1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/GrRenderTargetContext.h"
9
10 #include "include/core/SkDrawable.h"
11 #include "include/gpu/GrBackendSemaphore.h"
12 #include "include/private/GrRecordingContext.h"
13 #include "include/private/SkShadowFlags.h"
14 #include "include/utils/SkShadowUtils.h"
15 #include "src/core/SkAutoPixmapStorage.h"
16 #include "src/core/SkConvertPixels.h"
17 #include "src/core/SkDrawShadowInfo.h"
18 #include "src/core/SkGlyphRunPainter.h"
19 #include "src/core/SkLatticeIter.h"
20 #include "src/core/SkMatrixPriv.h"
21 #include "src/core/SkRRectPriv.h"
22 #include "src/core/SkSurfacePriv.h"
23 #include "src/core/SkYUVMath.h"
24 #include "src/gpu/GrAppliedClip.h"
25 #include "src/gpu/GrAuditTrail.h"
26 #include "src/gpu/GrBlurUtils.h"
27 #include "src/gpu/GrCaps.h"
28 #include "src/gpu/GrClientMappedBufferManager.h"
29 #include "src/gpu/GrColor.h"
30 #include "src/gpu/GrContextPriv.h"
31 #include "src/gpu/GrDataUtils.h"
32 #include "src/gpu/GrDrawingManager.h"
33 #include "src/gpu/GrFixedClip.h"
34 #include "src/gpu/GrGpuResourcePriv.h"
35 #include "src/gpu/GrImageInfo.h"
36 #include "src/gpu/GrMemoryPool.h"
37 #include "src/gpu/GrPathRenderer.h"
38 #include "src/gpu/GrRecordingContextPriv.h"
39 #include "src/gpu/GrRenderTarget.h"
40 #include "src/gpu/GrRenderTargetContextPriv.h"
41 #include "src/gpu/GrResourceProvider.h"
42 #include "src/gpu/GrStencilAttachment.h"
43 #include "src/gpu/GrStyle.h"
44 #include "src/gpu/GrTracing.h"
45 #include "src/gpu/SkGr.h"
46 #include "src/gpu/effects/GrBicubicEffect.h"
47 #include "src/gpu/effects/GrRRectEffect.h"
48 #include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
49 #include "src/gpu/geometry/GrQuad.h"
50 #include "src/gpu/geometry/GrQuadUtils.h"
51 #include "src/gpu/geometry/GrShape.h"
52 #include "src/gpu/ops/GrAtlasTextOp.h"
53 #include "src/gpu/ops/GrClearOp.h"
54 #include "src/gpu/ops/GrClearStencilClipOp.h"
55 #include "src/gpu/ops/GrDrawAtlasOp.h"
56 #include "src/gpu/ops/GrDrawOp.h"
57 #include "src/gpu/ops/GrDrawVerticesOp.h"
58 #include "src/gpu/ops/GrDrawableOp.h"
59 #include "src/gpu/ops/GrFillRRectOp.h"
60 #include "src/gpu/ops/GrFillRectOp.h"
61 #include "src/gpu/ops/GrLatticeOp.h"
62 #include "src/gpu/ops/GrOp.h"
63 #include "src/gpu/ops/GrOvalOpFactory.h"
64 #include "src/gpu/ops/GrRegionOp.h"
65 #include "src/gpu/ops/GrShadowRRectOp.h"
66 #include "src/gpu/ops/GrStencilPathOp.h"
67 #include "src/gpu/ops/GrStrokeRectOp.h"
68 #include "src/gpu/ops/GrTextureOp.h"
69 #include "src/gpu/text/GrTextContext.h"
70 #include "src/gpu/text/GrTextTarget.h"
71
72 class GrRenderTargetContext::TextTarget : public GrTextTarget {
73 public:
TextTarget(GrRenderTargetContext * renderTargetContext)74 TextTarget(GrRenderTargetContext* renderTargetContext)
75 : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
76 renderTargetContext->colorInfo())
77 , fRenderTargetContext(renderTargetContext)
78 , fGlyphPainter{*renderTargetContext} {}
79
addDrawOp(const GrClip & clip,std::unique_ptr<GrAtlasTextOp> op)80 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
81 fRenderTargetContext->addDrawOp(clip, std::move(op));
82 }
83
drawShape(const GrClip & clip,const SkPaint & paint,const SkMatrix & viewMatrix,const GrShape & shape)84 void drawShape(const GrClip& clip, const SkPaint& paint,
85 const SkMatrix& viewMatrix, const GrShape& shape) override {
86 GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
87 clip, paint, viewMatrix, shape);
88 }
89
makeGrPaint(GrMaskFormat maskFormat,const SkPaint & skPaint,const SkMatrix & viewMatrix,GrPaint * grPaint)90 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
91 GrPaint* grPaint) override {
92 auto context = fRenderTargetContext->fContext;
93 const GrColorInfo& colorInfo = fRenderTargetContext->colorInfo();
94 if (kARGB_GrMaskFormat == maskFormat) {
95 SkPaintToGrPaintWithPrimitiveColor(context, colorInfo, skPaint, grPaint);
96 } else {
97 SkPaintToGrPaint(context, colorInfo, skPaint, viewMatrix, grPaint);
98 }
99 }
100
getContext()101 GrRecordingContext* getContext() override {
102 return fRenderTargetContext->fContext;
103 }
104
glyphPainter()105 SkGlyphRunListPainter* glyphPainter() override {
106 return &fGlyphPainter;
107 }
108
109 private:
110 GrRenderTargetContext* fRenderTargetContext;
111 SkGlyphRunListPainter fGlyphPainter;
112
113 };
114
115 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
116 #define ASSERT_SINGLE_OWNER \
117 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
118 #define ASSERT_SINGLE_OWNER_PRIV \
119 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
120 #define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; }
121 #define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
122 #define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; }
123 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
124 #define RETURN_NULL_IF_ABANDONED if (fContext->priv().abandoned()) { return nullptr; }
125
126 //////////////////////////////////////////////////////////////////////////////
127
128 class AutoCheckFlush {
129 public:
AutoCheckFlush(GrDrawingManager * drawingManager)130 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
131 SkASSERT(fDrawingManager);
132 }
~AutoCheckFlush()133 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
134
135 private:
136 GrDrawingManager* fDrawingManager;
137 };
138
Make(GrRecordingContext * context,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,sk_sp<GrSurfaceProxy> proxy,GrSurfaceOrigin origin,const SkSurfaceProps * surfaceProps,bool managedOps)139 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::Make(
140 GrRecordingContext* context,
141 GrColorType colorType,
142 sk_sp<SkColorSpace> colorSpace,
143 sk_sp<GrSurfaceProxy> proxy,
144 GrSurfaceOrigin origin,
145 const SkSurfaceProps* surfaceProps,
146 bool managedOps) {
147 if (!proxy) {
148 return nullptr;
149 }
150
151 const GrBackendFormat& format = proxy->backendFormat();
152 GrSwizzle readSwizzle = context->priv().caps()->getReadSwizzle(format, colorType);
153 GrSwizzle outSwizzle = context->priv().caps()->getOutputSwizzle(format, colorType);
154
155 GrSurfaceProxyView readView(proxy, origin, readSwizzle);
156 GrSurfaceProxyView outputView(std::move(proxy), origin, outSwizzle);
157
158 return std::make_unique<GrRenderTargetContext>(context, std::move(readView),
159 std::move(outputView), colorType,
160 std::move(colorSpace), surfaceProps, managedOps);
161 }
162
Make(GrRecordingContext * context,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,SkBackingFit fit,SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrMipMapped mipMapped,GrProtected isProtected,GrSurfaceOrigin origin,SkBudgeted budgeted,const SkSurfaceProps * surfaceProps)163 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::Make(
164 GrRecordingContext* context,
165 GrColorType colorType,
166 sk_sp<SkColorSpace> colorSpace,
167 SkBackingFit fit,
168 SkISize dimensions,
169 const GrBackendFormat& format,
170 int sampleCnt,
171 GrMipMapped mipMapped,
172 GrProtected isProtected,
173 GrSurfaceOrigin origin,
174 SkBudgeted budgeted,
175 const SkSurfaceProps* surfaceProps) {
176 // It is probably not necessary to check if the context is abandoned here since uses of the
177 // GrRenderTargetContext which need the context will mostly likely fail later on without an
178 // issue. However having this hear adds some reassurance in case there is a path doesn't handle
179 // an abandoned context correctly. It also lets us early out of some extra work.
180 if (context->priv().abandoned()) {
181 return nullptr;
182 }
183
184 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(format, colorType);
185
186 sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(
187 format, dimensions, swizzle, GrRenderable::kYes, sampleCnt, mipMapped, fit, budgeted,
188 isProtected);
189 if (!proxy) {
190 return nullptr;
191 }
192
193 auto rtc = GrRenderTargetContext::Make(context, colorType, std::move(colorSpace),
194 std::move(proxy), origin, surfaceProps, true);
195 if (!rtc) {
196 return nullptr;
197 }
198 rtc->discard();
199 return rtc;
200 }
201
Make(GrRecordingContext * context,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,SkBackingFit fit,SkISize dimensions,int sampleCnt,GrMipMapped mipMapped,GrProtected isProtected,GrSurfaceOrigin origin,SkBudgeted budgeted,const SkSurfaceProps * surfaceProps)202 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::Make(
203 GrRecordingContext* context,
204 GrColorType colorType,
205 sk_sp<SkColorSpace> colorSpace,
206 SkBackingFit fit,
207 SkISize dimensions,
208 int sampleCnt,
209 GrMipMapped mipMapped,
210 GrProtected isProtected,
211 GrSurfaceOrigin origin,
212 SkBudgeted budgeted,
213 const SkSurfaceProps* surfaceProps) {
214 auto format = context->priv().caps()->getDefaultBackendFormat(colorType, GrRenderable::kYes);
215 if (!format.isValid()) {
216 return nullptr;
217 }
218
219 return GrRenderTargetContext::Make(context, colorType, std::move(colorSpace), fit, dimensions,
220 format, sampleCnt, mipMapped, isProtected, origin, budgeted,
221 surfaceProps);
222 }
223
color_type_fallback(GrColorType ct)224 static inline GrColorType color_type_fallback(GrColorType ct) {
225 switch (ct) {
226 // kRGBA_8888 is our default fallback for many color types that may not have renderable
227 // backend formats.
228 case GrColorType::kAlpha_8:
229 case GrColorType::kBGR_565:
230 case GrColorType::kABGR_4444:
231 case GrColorType::kBGRA_8888:
232 case GrColorType::kRGBA_1010102:
233 case GrColorType::kRGBA_F16:
234 case GrColorType::kRGBA_F16_Clamped:
235 return GrColorType::kRGBA_8888;
236 case GrColorType::kAlpha_F16:
237 return GrColorType::kRGBA_F16;
238 case GrColorType::kGray_8:
239 return GrColorType::kRGB_888x;
240 default:
241 return GrColorType::kUnknown;
242 }
243 }
244
MakeWithFallback(GrRecordingContext * context,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,SkBackingFit fit,SkISize dimensions,int sampleCnt,GrMipMapped mipMapped,GrProtected isProtected,GrSurfaceOrigin origin,SkBudgeted budgeted,const SkSurfaceProps * surfaceProps)245 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::MakeWithFallback(
246 GrRecordingContext* context,
247 GrColorType colorType,
248 sk_sp<SkColorSpace> colorSpace,
249 SkBackingFit fit,
250 SkISize dimensions,
251 int sampleCnt,
252 GrMipMapped mipMapped,
253 GrProtected isProtected,
254 GrSurfaceOrigin origin,
255 SkBudgeted budgeted,
256 const SkSurfaceProps* surfaceProps) {
257 std::unique_ptr<GrRenderTargetContext> rtc;
258 do {
259 rtc = GrRenderTargetContext::Make(context, colorType, colorSpace, fit, dimensions,
260 sampleCnt, mipMapped, isProtected, origin, budgeted,
261 surfaceProps);
262 colorType = color_type_fallback(colorType);
263 } while (!rtc && colorType != GrColorType::kUnknown);
264 return rtc;
265 }
266
MakeFromBackendTexture(GrRecordingContext * context,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,const GrBackendTexture & tex,int sampleCnt,GrSurfaceOrigin origin,const SkSurfaceProps * surfaceProps,ReleaseProc releaseProc,ReleaseContext releaseCtx)267 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::MakeFromBackendTexture(
268 GrRecordingContext* context,
269 GrColorType colorType,
270 sk_sp<SkColorSpace> colorSpace,
271 const GrBackendTexture& tex,
272 int sampleCnt,
273 GrSurfaceOrigin origin,
274 const SkSurfaceProps* surfaceProps,
275 ReleaseProc releaseProc,
276 ReleaseContext releaseCtx) {
277 SkASSERT(sampleCnt > 0);
278 sk_sp<GrTextureProxy> proxy(context->priv().proxyProvider()->wrapRenderableBackendTexture(
279 tex, sampleCnt, colorType, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, releaseProc,
280 releaseCtx));
281 if (!proxy) {
282 return nullptr;
283 }
284
285 return GrRenderTargetContext::Make(context, colorType, std::move(colorSpace), std::move(proxy),
286 origin, surfaceProps);
287 }
288
MakeFromBackendTextureAsRenderTarget(GrRecordingContext * context,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,const GrBackendTexture & tex,int sampleCnt,GrSurfaceOrigin origin,const SkSurfaceProps * surfaceProps)289 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::MakeFromBackendTextureAsRenderTarget(
290 GrRecordingContext* context,
291 GrColorType colorType,
292 sk_sp<SkColorSpace> colorSpace,
293 const GrBackendTexture& tex,
294 int sampleCnt,
295 GrSurfaceOrigin origin,
296 const SkSurfaceProps* surfaceProps) {
297 SkASSERT(sampleCnt > 0);
298 sk_sp<GrSurfaceProxy> proxy(context->priv().proxyProvider()->wrapBackendTextureAsRenderTarget(
299 tex, colorType, sampleCnt));
300 if (!proxy) {
301 return nullptr;
302 }
303
304 return GrRenderTargetContext::Make(context, colorType, std::move(colorSpace), std::move(proxy),
305 origin, surfaceProps);
306 }
307
MakeFromBackendRenderTarget(GrRecordingContext * context,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,const SkSurfaceProps * surfaceProps,ReleaseProc releaseProc,ReleaseContext releaseCtx)308 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::MakeFromBackendRenderTarget(
309 GrRecordingContext* context,
310 GrColorType colorType,
311 sk_sp<SkColorSpace> colorSpace,
312 const GrBackendRenderTarget& rt,
313 GrSurfaceOrigin origin,
314 const SkSurfaceProps* surfaceProps,
315 ReleaseProc releaseProc,
316 ReleaseContext releaseCtx) {
317 sk_sp<GrSurfaceProxy> proxy(context->priv().proxyProvider()->wrapBackendRenderTarget(
318 rt, colorType, releaseProc, releaseCtx));
319 if (!proxy) {
320 return nullptr;
321 }
322
323 return GrRenderTargetContext::Make(context, colorType, std::move(colorSpace), std::move(proxy),
324 origin, surfaceProps);
325 }
326
MakeFromVulkanSecondaryCB(GrRecordingContext * context,const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo,const SkSurfaceProps * props)327 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::MakeFromVulkanSecondaryCB(
328 GrRecordingContext* context,
329 const SkImageInfo& imageInfo,
330 const GrVkDrawableInfo& vkInfo,
331 const SkSurfaceProps* props) {
332 sk_sp<GrSurfaceProxy> proxy(
333 context->priv().proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
334 vkInfo));
335 if (!proxy) {
336 return nullptr;
337 }
338
339 return GrRenderTargetContext::Make(context, SkColorTypeToGrColorType(imageInfo.colorType()),
340 imageInfo.refColorSpace(), std::move(proxy),
341 kTopLeft_GrSurfaceOrigin, props);
342 }
343
344 // In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
345 // GrOpsTask to be picked up and added to by renderTargetContexts lower in the call
346 // stack. When this occurs with a closed GrOpsTask, a new one will be allocated
347 // when the renderTargetContext attempts to use it (via getOpsTask).
GrRenderTargetContext(GrRecordingContext * context,GrSurfaceProxyView readView,GrSurfaceProxyView outputView,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,bool managedOpsTask)348 GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
349 GrSurfaceProxyView readView,
350 GrSurfaceProxyView outputView,
351 GrColorType colorType,
352 sk_sp<SkColorSpace> colorSpace,
353 const SkSurfaceProps* surfaceProps,
354 bool managedOpsTask)
355 : GrSurfaceContext(context, std::move(readView), colorType, kPremul_SkAlphaType,
356 std::move(colorSpace))
357 , fOutputView(std::move(outputView))
358 , fOpsTask(sk_ref_sp(this->asSurfaceProxy()->getLastOpsTask()))
359 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
360 , fManagedOpsTask(managedOpsTask) {
361 SkASSERT(this->asSurfaceProxy() == fOutputView.proxy());
362 SkASSERT(this->origin() == fOutputView.origin());
363
364 fTextTarget.reset(new TextTarget(this));
365 SkDEBUGCODE(this->validate();)
366 }
367
368 #ifdef SK_DEBUG
onValidate() const369 void GrRenderTargetContext::onValidate() const {
370 if (fOpsTask && !fOpsTask->isClosed()) {
371 SkASSERT(fOutputView.proxy()->getLastRenderTask() == fOpsTask.get());
372 }
373 }
374 #endif
375
~GrRenderTargetContext()376 GrRenderTargetContext::~GrRenderTargetContext() {
377 ASSERT_SINGLE_OWNER
378 }
379
chooseAAType(GrAA aa)380 inline GrAAType GrRenderTargetContext::chooseAAType(GrAA aa) {
381 if (GrAA::kNo == aa) {
382 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
383 // that.
384 if (this->numSamples() > 1 && !this->caps()->multisampleDisableSupport()) {
385 return GrAAType::kMSAA;
386 }
387 return GrAAType::kNone;
388 }
389 return (this->numSamples() > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
390 }
391
mipMapped() const392 GrMipMapped GrRenderTargetContext::mipMapped() const {
393 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
394 return proxy->mipMapped();
395 }
396 return GrMipMapped::kNo;
397 }
398
getOpsTask()399 GrOpsTask* GrRenderTargetContext::getOpsTask() {
400 ASSERT_SINGLE_OWNER
401 SkDEBUGCODE(this->validate();)
402
403 if (!fOpsTask || fOpsTask->isClosed()) {
404 sk_sp<GrOpsTask> newOpsTask =
405 this->drawingManager()->newOpsTask(this->outputSurfaceView(), fManagedOpsTask);
406 if (fOpsTask && fNumStencilSamples > 0) {
407 // Store the stencil values in memory upon completion of fOpsTask.
408 fOpsTask->setMustPreserveStencil();
409 // Reload the stencil buffer content at the beginning of newOpsTask.
410 // FIXME: Could the topo sort insert a task between these two that modifies the stencil
411 // values?
412 newOpsTask->setInitialStencilContent(GrOpsTask::StencilContent::kPreserved);
413 }
414 fOpsTask = std::move(newOpsTask);
415 }
416
417 return fOpsTask.get();
418 }
419
drawGlyphRunList(const GrClip & clip,const SkMatrix & viewMatrix,const SkGlyphRunList & blob)420 void GrRenderTargetContext::drawGlyphRunList(
421 const GrClip& clip, const SkMatrix& viewMatrix,
422 const SkGlyphRunList& blob) {
423 ASSERT_SINGLE_OWNER
424 RETURN_IF_ABANDONED
425 SkDEBUGCODE(this->validate();)
426 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
427
428 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
429 // secondary command buffers because it would require stopping and starting a render pass which
430 // we don't have access to.
431 if (this->wrapsVkSecondaryCB()) {
432 return;
433 }
434
435 GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
436 atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
437 fSurfaceProps, blob);
438 }
439
discard()440 void GrRenderTargetContext::discard() {
441 ASSERT_SINGLE_OWNER
442 RETURN_IF_ABANDONED
443 SkDEBUGCODE(this->validate();)
444 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
445
446 AutoCheckFlush acf(this->drawingManager());
447
448 this->getOpsTask()->discard();
449 }
450
clear(const SkIRect * rect,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)451 void GrRenderTargetContext::clear(const SkIRect* rect,
452 const SkPMColor4f& color,
453 CanClearFullscreen canClearFullscreen) {
454 ASSERT_SINGLE_OWNER
455 RETURN_IF_ABANDONED
456 SkDEBUGCODE(this->validate();)
457 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
458
459 AutoCheckFlush acf(this->drawingManager());
460 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
461 canClearFullscreen);
462 }
463
clear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)464 void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
465 const SkPMColor4f& color,
466 CanClearFullscreen canClearFullscreen) {
467 ASSERT_SINGLE_OWNER_PRIV
468 RETURN_IF_ABANDONED_PRIV
469 SkDEBUGCODE(fRenderTargetContext->validate();)
470 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
471 fRenderTargetContext->fContext);
472
473 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
474 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
475 }
476
clear_to_grpaint(const SkPMColor4f & color,GrPaint * paint)477 static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
478 paint->setColor4f(color);
479 if (color.isOpaque()) {
480 // Can just rely on the src-over blend mode to do the right thing
481 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
482 } else {
483 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
484 // were src blended
485 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
486 }
487 }
488
internalClear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)489 void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
490 const SkPMColor4f& color,
491 CanClearFullscreen canClearFullscreen) {
492 bool isFull = false;
493 if (!clip.hasWindowRectangles()) {
494 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
495 // only clear the entire target if we knew it had not been cleared before. As
496 // is this could end up doing a lot of redundant clears.
497 isFull = !clip.scissorEnabled() ||
498 (CanClearFullscreen::kYes == canClearFullscreen &&
499 (this->caps()->preferFullscreenClears() || this->caps()->shouldInitializeTextures())) ||
500 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
501 }
502
503 if (isFull) {
504 GrOpsTask* opsTask = this->getOpsTask();
505 if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
506 !this->caps()->performColorClearsAsDraws()) {
507 // The op list was emptied and native clears are allowed, so just use the load op
508 opsTask->setColorLoadOp(GrLoadOp::kClear, color);
509 return;
510 } else {
511 // Will use an op for the clear, reset the load op to discard since the op will
512 // blow away the color buffer contents
513 opsTask->setColorLoadOp(GrLoadOp::kDiscard);
514 }
515
516 // Must add an op to the list (either because we couldn't use a load op, or because the
517 // clear load op isn't supported)
518 if (this->caps()->performColorClearsAsDraws()) {
519 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
520 GrPaint paint;
521 clear_to_grpaint(color, &paint);
522 this->addDrawOp(GrFixedClip::Disabled(),
523 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
524 rtRect));
525 } else {
526 this->addOp(GrClearOp::Make(
527 fContext, SkIRect::MakeEmpty(), color, /* fullscreen */ true));
528 }
529 } else {
530 if (this->caps()->performPartialClearsAsDraws()) {
531 // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
532 GrPaint paint;
533 clear_to_grpaint(color, &paint);
534
535 this->addDrawOp(clip,
536 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
537 SkRect::Make(clip.scissorRect())));
538 } else {
539 std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
540 this->asSurfaceProxy()));
541 // This version of the clear op factory can return null if the clip doesn't intersect
542 // with the surface proxy's boundary
543 if (!op) {
544 return;
545 }
546 this->addOp(std::move(op));
547 }
548 }
549 }
550
drawPaint(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix)551 void GrRenderTargetContext::drawPaint(const GrClip& clip,
552 GrPaint&& paint,
553 const SkMatrix& viewMatrix) {
554 // Start with the render target, since that is the maximum content we could possibly fill.
555 // drawFilledQuad() will automatically restrict it to clip bounds for us if possible.
556 SkRect r = this->asSurfaceProxy()->getBoundsRect();
557 if (!paint.numTotalFragmentProcessors()) {
558 // The paint is trivial so we won't need to use local coordinates, so skip calculating the
559 // inverse view matrix.
560 this->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r, r);
561 } else {
562 // Use the inverse view matrix to arrive at appropriate local coordinates for the paint.
563 SkMatrix localMatrix;
564 if (!viewMatrix.invert(&localMatrix)) {
565 return;
566 }
567 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r,
568 localMatrix);
569 }
570 }
571
572 enum class GrRenderTargetContext::QuadOptimization {
573 // The rect to draw doesn't intersect clip or render target, so no draw op should be added
574 kDiscarded,
575 // The rect to draw was converted to some other op and appended to the oplist, so no additional
576 // op is necessary. Currently this can convert it to a clear op or a rrect op. Only valid if
577 // a constColor is provided.
578 kSubmitted,
579 // The clip was folded into the device quad, with updated edge flags and local coords, and
580 // caller is responsible for adding an appropriate op.
581 kClipApplied,
582 // No change to clip, but quad updated to better fit clip/render target, and caller is
583 // responsible for adding an appropriate op.
584 kCropped
585 };
586
make_vertex_finite(float * value)587 static bool make_vertex_finite(float* value) {
588 if (SkScalarIsNaN(*value)) {
589 return false;
590 }
591
592 if (!SkScalarIsFinite(*value)) {
593 // +/- infinity at this point. Don't use exactly SK_ScalarMax so that we have some precision
594 // left when calculating crops.
595 static constexpr float kNearInfinity = SK_ScalarMax / 4.f;
596 *value = *value < 0.f ? -kNearInfinity : kNearInfinity;
597 }
598
599 return true;
600 }
601
attemptQuadOptimization(const GrClip & clip,const SkPMColor4f * constColor,const GrUserStencilSettings * stencilSettings,GrAA * aa,DrawQuad * quad)602 GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimization(
603 const GrClip& clip, const SkPMColor4f* constColor,
604 const GrUserStencilSettings* stencilSettings, GrAA* aa, DrawQuad* quad) {
605 // Optimization requirements:
606 // 1. kDiscard applies when clip bounds and quad bounds do not intersect
607 // 2a. kSubmitted applies when constColor and final geom is pixel aligned rect;
608 // pixel aligned rect requires rect clip and (rect quad or quad covers clip) OR
609 // 2b. kSubmitted applies when constColor and rrect clip and quad covers clip
610 // 4. kClipApplied applies when rect clip and (rect quad or quad covers clip)
611 // 5. kCropped in all other scenarios (although a crop may be a no-op)
612
613 // Save the old AA flags since CropToRect will modify 'quad' and if kCropped is returned, it's
614 // better to just keep the old flags instead of introducing mixed edge flags.
615 GrQuadAAFlags oldFlags = quad->fEdgeFlags;
616
617 SkRect rtRect;
618 if (stencilSettings) {
619 // Must use size at which the rendertarget will ultimately be allocated so that stencil
620 // buffer updates on approximately sized render targets don't get corrupted.
621 rtRect = this->asSurfaceProxy()->backingStoreBoundsRect();
622 } else {
623 // Use the logical size of the render target, which allows for "fullscreen" clears even if
624 // the render target has an approximate backing fit
625 rtRect = SkRect::MakeWH(this->width(), this->height());
626 }
627
628 SkRect drawBounds = quad->fDevice.bounds();
629 if (constColor) {
630 // If the device quad is not finite, coerce into a finite quad. This is acceptable since it
631 // will be cropped to the finite 'clip' or render target and there is no local space mapping
632 if (!quad->fDevice.isFinite()) {
633 for (int i = 0; i < 4; ++i) {
634 if (!make_vertex_finite(quad->fDevice.xs() + i) ||
635 !make_vertex_finite(quad->fDevice.ys() + i) ||
636 !make_vertex_finite(quad->fDevice.ws() + i)) {
637 // Discard if we see a nan
638 return QuadOptimization::kDiscarded;
639 }
640 }
641 SkASSERT(quad->fDevice.isFinite());
642 }
643 } else {
644 // CropToRect requires the quads to be finite. If they are not finite and we have local
645 // coordinates, the mapping from local space to device space is poorly defined so drop it
646 if (!quad->fDevice.isFinite()) {
647 return QuadOptimization::kDiscarded;
648 }
649 }
650
651 // If the quad is entirely off screen, it doesn't matter what the clip does
652 if (!rtRect.intersects(drawBounds)) {
653 return QuadOptimization::kDiscarded;
654 }
655
656 // Check if clip can be represented as a rounded rect (initialize as if clip fully contained
657 // the render target).
658 SkRRect clipRRect = SkRRect::MakeRect(rtRect);
659 // We initialize clipAA to *aa when there are stencil settings so that we don't artificially
660 // encounter mixed-aa edges (not allowed for stencil), but we want to start as non-AA for
661 // regular draws so that if we fully cover the render target, that can stop being anti-aliased.
662 GrAA clipAA = stencilSettings ? *aa : GrAA::kNo;
663 bool axisAlignedClip = true;
664 if (!clip.quickContains(rtRect)) {
665 if (!clip.isRRect(rtRect, &clipRRect, &clipAA)) {
666 axisAlignedClip = false;
667 }
668 }
669
670 // If the clip rrect is valid (i.e. axis-aligned), we can potentially combine it with the
671 // draw geometry so that no clip is needed when drawing.
672 if (axisAlignedClip && (!stencilSettings || clipAA == *aa)) {
673 // Tighten clip bounds (if clipRRect.isRect() is true, clipBounds now holds the intersection
674 // of the render target and the clip rect)
675 SkRect clipBounds = rtRect;
676 if (!clipBounds.intersect(clipRRect.rect()) || !clipBounds.intersects(drawBounds)) {
677 return QuadOptimization::kDiscarded;
678 }
679
680 if (clipRRect.isRect()) {
681 // No rounded corners, so the kClear and kExplicitClip optimizations are possible
682 if (GrQuadUtils::CropToRect(clipBounds, clipAA, quad, /*compute local*/ !constColor)) {
683 if (!stencilSettings && constColor &&
684 quad->fDevice.quadType() == GrQuad::Type::kAxisAligned) {
685 // Clear optimization is possible
686 drawBounds = quad->fDevice.bounds();
687 if (drawBounds.contains(rtRect)) {
688 // Fullscreen clear
689 this->clear(nullptr, *constColor, CanClearFullscreen::kYes);
690 return QuadOptimization::kSubmitted;
691 } else if (GrClip::IsPixelAligned(drawBounds) &&
692 drawBounds.width() > 256 && drawBounds.height() > 256) {
693 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
694 SkIRect scissorRect;
695 drawBounds.round(&scissorRect);
696 this->clear(&scissorRect, *constColor, CanClearFullscreen::kNo);
697 return QuadOptimization::kSubmitted;
698 }
699 }
700
701 // Update overall AA setting.
702 if (*aa == GrAA::kNo && clipAA == GrAA::kYes &&
703 quad->fEdgeFlags != GrQuadAAFlags::kNone) {
704 // The clip was anti-aliased and now the draw needs to be upgraded to AA to
705 // properly reflect the smooth edge of the clip.
706 *aa = GrAA::kYes;
707 }
708 // We intentionally do not downgrade AA here because we don't know if we need to
709 // preserve MSAA (see GrQuadAAFlags docs). But later in the pipeline, the ops can
710 // use GrResolveAATypeForQuad() to turn off coverage AA when all flags are off.
711
712 // deviceQuad is exactly the intersection of original quad and clip, so it can be
713 // drawn with no clip (submitted by caller)
714 return QuadOptimization::kClipApplied;
715 } else {
716 // The quads have been updated to better fit the clip bounds, but can't get rid of
717 // the clip entirely
718 quad->fEdgeFlags = oldFlags;
719 return QuadOptimization::kCropped;
720 }
721 } else if (!stencilSettings && constColor) {
722 // Rounded corners and constant filled color (limit ourselves to solid colors because
723 // there is no way to use custom local coordinates with drawRRect).
724 if (GrQuadUtils::CropToRect(clipBounds, clipAA, quad, /* compute local */ false) &&
725 quad->fDevice.quadType() == GrQuad::Type::kAxisAligned &&
726 quad->fDevice.bounds().contains(clipBounds)) {
727 // Since the cropped quad became a rectangle which covered the bounds of the rrect,
728 // we can draw the rrect directly and ignore the edge flags
729 GrPaint paint;
730 clear_to_grpaint(*constColor, &paint);
731 this->drawRRect(GrFixedClip::Disabled(), std::move(paint), clipAA, SkMatrix::I(),
732 clipRRect, GrStyle::SimpleFill());
733 return QuadOptimization::kSubmitted;
734 } else {
735 // The quad has been updated to better fit clip bounds, but can't remove the clip
736 quad->fEdgeFlags = oldFlags;
737 return QuadOptimization::kCropped;
738 }
739 }
740 }
741
742 // Crop the quad to the conservative bounds of the clip.
743 SkIRect clipDevBounds;
744 clip.getConservativeBounds(rtRect.width(), rtRect.height(), &clipDevBounds);
745 SkRect clipBounds = SkRect::Make(clipDevBounds);
746
747 // One final check for discarding, since we may have gone here directly due to a complex clip
748 if (!clipBounds.intersects(drawBounds)) {
749 return QuadOptimization::kDiscarded;
750 }
751
752 // Even if this were to return true, the crop rect does not exactly match the clip, so can not
753 // report explicit-clip. Since these edges aren't visible, don't update the final edge flags.
754 GrQuadUtils::CropToRect(clipBounds, clipAA, quad, /* compute local */ !constColor);
755 quad->fEdgeFlags = oldFlags;
756
757 return QuadOptimization::kCropped;
758 }
759
drawFilledQuad(const GrClip & clip,GrPaint && paint,GrAA aa,DrawQuad * quad,const GrUserStencilSettings * ss)760 void GrRenderTargetContext::drawFilledQuad(const GrClip& clip,
761 GrPaint&& paint,
762 GrAA aa,
763 DrawQuad* quad,
764 const GrUserStencilSettings* ss) {
765 ASSERT_SINGLE_OWNER
766 RETURN_IF_ABANDONED
767 SkDEBUGCODE(this->validate();)
768 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFilledQuad", fContext);
769
770 AutoCheckFlush acf(this->drawingManager());
771
772 SkPMColor4f* constColor = nullptr;
773 SkPMColor4f paintColor;
774 if (!ss && !paint.numCoverageFragmentProcessors() &&
775 paint.isConstantBlendedColor(&paintColor)) {
776 // Only consider clears/rrects when it's easy to guarantee 100% fill with single color
777 constColor = &paintColor;
778 }
779
780 QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, ss, &aa, quad);
781 if (opt >= QuadOptimization::kClipApplied) {
782 // These optimizations require caller to add an op themselves
783 const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
784 : clip;
785 GrAAType aaType = ss ? (aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone)
786 : this->chooseAAType(aa);
787 this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType,
788 quad, ss));
789 }
790 // All other optimization levels were completely handled inside attempt(), so no extra op needed
791 }
792
drawTexturedQuad(const GrClip & clip,GrSurfaceProxyView proxyView,SkAlphaType srcAlphaType,sk_sp<GrColorSpaceXform> textureXform,GrSamplerState::Filter filter,const SkPMColor4f & color,SkBlendMode blendMode,GrAA aa,DrawQuad * quad,const SkRect * domain)793 void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip,
794 GrSurfaceProxyView proxyView,
795 SkAlphaType srcAlphaType,
796 sk_sp<GrColorSpaceXform> textureXform,
797 GrSamplerState::Filter filter,
798 const SkPMColor4f& color,
799 SkBlendMode blendMode,
800 GrAA aa,
801 DrawQuad* quad,
802 const SkRect* domain) {
803 ASSERT_SINGLE_OWNER
804 RETURN_IF_ABANDONED
805 SkDEBUGCODE(this->validate();)
806 SkASSERT(proxyView.asTextureProxy());
807 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexturedQuad", fContext);
808
809 AutoCheckFlush acf(this->drawingManager());
810
811 // Functionally this is very similar to drawFilledQuad except that there's no constColor to
812 // enable the kSubmitted optimizations, no stencil settings support, and its a GrTextureOp.
813 QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr, nullptr, &aa, quad);
814
815 SkASSERT(opt != QuadOptimization::kSubmitted);
816 if (opt != QuadOptimization::kDiscarded) {
817 // And the texture op if not discarded
818 const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
819 : clip;
820 GrAAType aaType = this->chooseAAType(aa);
821 auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
822 auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
823 : GrTextureOp::Saturate::kNo;
824 // Use the provided domain, although hypothetically we could detect that the cropped local
825 // quad is sufficiently inside the domain and the constraint could be dropped.
826 this->addDrawOp(finalClip,
827 GrTextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
828 std::move(textureXform), filter, color, saturate,
829 blendMode, aaType, quad, domain));
830 }
831 }
832
drawRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrStyle * style)833 void GrRenderTargetContext::drawRect(const GrClip& clip,
834 GrPaint&& paint,
835 GrAA aa,
836 const SkMatrix& viewMatrix,
837 const SkRect& rect,
838 const GrStyle* style) {
839 if (!style) {
840 style = &GrStyle::SimpleFill();
841 }
842 ASSERT_SINGLE_OWNER
843 RETURN_IF_ABANDONED
844 SkDEBUGCODE(this->validate();)
845 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
846
847 // Path effects should've been devolved to a path in SkGpuDevice
848 SkASSERT(!style->pathEffect());
849
850 AutoCheckFlush acf(this->drawingManager());
851
852 const SkStrokeRec& stroke = style->strokeRec();
853 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
854 // Fills the rect, using rect as its own local coordinates
855 this->fillRectToRect(clip, std::move(paint), aa, viewMatrix, rect, rect);
856 return;
857 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
858 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
859 if ((!rect.width() || !rect.height()) &&
860 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
861 SkScalar r = stroke.getWidth() / 2;
862 // TODO: Move these stroke->fill fallbacks to GrShape?
863 switch (stroke.getJoin()) {
864 case SkPaint::kMiter_Join:
865 this->drawRect(
866 clip, std::move(paint), aa, viewMatrix,
867 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
868 &GrStyle::SimpleFill());
869 return;
870 case SkPaint::kRound_Join:
871 // Raster draws nothing when both dimensions are empty.
872 if (rect.width() || rect.height()){
873 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
874 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
875 GrStyle::SimpleFill());
876 return;
877 }
878 case SkPaint::kBevel_Join:
879 if (!rect.width()) {
880 this->drawRect(clip, std::move(paint), aa, viewMatrix,
881 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
882 &GrStyle::SimpleFill());
883 } else {
884 this->drawRect(clip, std::move(paint), aa, viewMatrix,
885 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
886 &GrStyle::SimpleFill());
887 }
888 return;
889 }
890 }
891
892 std::unique_ptr<GrDrawOp> op;
893
894 GrAAType aaType = this->chooseAAType(aa);
895 op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
896 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
897 // does not preserve rectangles.
898 if (op) {
899 this->addDrawOp(clip, std::move(op));
900 return;
901 }
902 }
903 assert_alive(paint);
904 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
905 }
906
drawQuadSet(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const QuadSetEntry quads[],int cnt)907 void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
908 const SkMatrix& viewMatrix, const QuadSetEntry quads[],
909 int cnt) {
910 GrAAType aaType = this->chooseAAType(aa);
911
912 GrFillRectOp::AddFillRectOps(this, clip, fContext, std::move(paint), aaType, viewMatrix,
913 quads, cnt);
914 }
915
maxWindowRectangles() const916 int GrRenderTargetContextPriv::maxWindowRectangles() const {
917 return fRenderTargetContext->asRenderTargetProxy()->maxWindowRectangles(
918 *fRenderTargetContext->caps());
919 }
920
canDiscardPreviousOpsOnFullClear() const921 GrOpsTask::CanDiscardPreviousOps GrRenderTargetContext::canDiscardPreviousOpsOnFullClear(
922 ) const {
923 #if GR_TEST_UTILS
924 if (fPreserveOpsOnFullClear_TestingOnly) {
925 return GrOpsTask::CanDiscardPreviousOps::kNo;
926 }
927 #endif
928 // Regardless of how the clear is implemented (native clear or a fullscreen quad), all prior ops
929 // would normally be overwritten. The one exception is if the render target context is marked as
930 // needing a stencil buffer then there may be a prior op that writes to the stencil buffer.
931 // Although the clear will ignore the stencil buffer, following draw ops may not so we can't get
932 // rid of all the preceding ops. Beware! If we ever add any ops that have a side effect beyond
933 // modifying the stencil buffer we will need a more elaborate tracking system (skbug.com/7002).
934 return GrOpsTask::CanDiscardPreviousOps(!fNumStencilSamples);
935 }
936
setNeedsStencil(bool useMixedSamplesIfNotMSAA)937 void GrRenderTargetContext::setNeedsStencil(bool useMixedSamplesIfNotMSAA) {
938 // Don't clear stencil until after we've changed fNumStencilSamples. This ensures we don't loop
939 // forever in the event that there are driver bugs and we need to clear as a draw.
940 bool hasInitializedStencil = fNumStencilSamples > 0;
941
942 int numRequiredSamples = this->numSamples();
943 if (useMixedSamplesIfNotMSAA && 1 == numRequiredSamples) {
944 SkASSERT(this->asRenderTargetProxy()->canUseMixedSamples(*this->caps()));
945 numRequiredSamples = this->caps()->internalMultisampleCount(
946 this->asSurfaceProxy()->backendFormat());
947 }
948 SkASSERT(numRequiredSamples > 0);
949
950 if (numRequiredSamples > fNumStencilSamples) {
951 fNumStencilSamples = numRequiredSamples;
952 this->asRenderTargetProxy()->setNeedsStencil(fNumStencilSamples);
953 }
954
955 if (!hasInitializedStencil) {
956 if (this->caps()->performStencilClearsAsDraws()) {
957 // There is a driver bug with clearing stencil. We must use an op to manually clear the
958 // stencil buffer before the op that required 'setNeedsStencil'.
959 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
960 } else {
961 this->getOpsTask()->setInitialStencilContent(
962 GrOpsTask::StencilContent::kUserBitsCleared);
963 }
964 }
965 }
966
clearStencilClip(const GrFixedClip & clip,bool insideStencilMask)967 void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
968 ASSERT_SINGLE_OWNER_PRIV
969 RETURN_IF_ABANDONED_PRIV
970 SkDEBUGCODE(fRenderTargetContext->validate();)
971 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
972 fRenderTargetContext->fContext);
973
974 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
975
976 fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
977 }
978
internalStencilClear(const GrFixedClip & clip,bool insideStencilMask)979 void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
980 this->setNeedsStencil(/* useMixedSamplesIfNotMSAA = */ false);
981
982 if (this->caps()->performStencilClearsAsDraws()) {
983 const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
984 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
985
986 // Configure the paint to have no impact on the color buffer
987 GrPaint paint;
988 paint.setXPFactory(GrDisableColorXPFactory::Get());
989 this->addDrawOp(clip, GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
990 rtRect, ss));
991 } else {
992 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask,
993 this->asRenderTargetProxy()));
994 if (!op) {
995 return;
996 }
997 this->addOp(std::move(op));
998 }
999 }
1000
stencilPath(const GrHardClip & clip,GrAA doStencilMSAA,const SkMatrix & viewMatrix,sk_sp<const GrPath> path)1001 void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
1002 GrAA doStencilMSAA,
1003 const SkMatrix& viewMatrix,
1004 sk_sp<const GrPath> path) {
1005 ASSERT_SINGLE_OWNER_PRIV
1006 RETURN_IF_ABANDONED_PRIV
1007 SkDEBUGCODE(fRenderTargetContext->validate();)
1008 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
1009 fRenderTargetContext->fContext);
1010
1011 // TODO: extract portions of checkDraw that are relevant to path stenciling.
1012 SkASSERT(path);
1013 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
1014
1015 // FIXME: Use path bounds instead of this WAR once
1016 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
1017 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
1018
1019 // Setup clip
1020 GrAppliedHardClip appliedClip;
1021 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
1022 &bounds)) {
1023 return;
1024 }
1025
1026 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
1027 viewMatrix,
1028 GrAA::kYes == doStencilMSAA,
1029 appliedClip.hasStencilClip(),
1030 appliedClip.scissorState(),
1031 std::move(path));
1032 if (!op) {
1033 return;
1034 }
1035 op->setClippedBounds(bounds);
1036
1037 fRenderTargetContext->setNeedsStencil(GrAA::kYes == doStencilMSAA);
1038 fRenderTargetContext->addOp(std::move(op));
1039 }
1040
drawTextureSet(const GrClip & clip,TextureSetEntry set[],int cnt,int proxyRunCnt,GrSamplerState::Filter filter,SkBlendMode mode,GrAA aa,SkCanvas::SrcRectConstraint constraint,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> texXform)1041 void GrRenderTargetContext::drawTextureSet(const GrClip& clip, TextureSetEntry set[],
1042 int cnt, int proxyRunCnt,
1043 GrSamplerState::Filter filter, SkBlendMode mode,
1044 GrAA aa, SkCanvas::SrcRectConstraint constraint,
1045 const SkMatrix& viewMatrix,
1046 sk_sp<GrColorSpaceXform> texXform) {
1047 ASSERT_SINGLE_OWNER
1048 RETURN_IF_ABANDONED
1049 SkDEBUGCODE(this->validate();)
1050 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
1051
1052 // Create the minimum number of GrTextureOps needed to draw this set. Individual
1053 // GrTextureOps can rebind the texture between draws thus avoiding GrPaint (re)creation.
1054 AutoCheckFlush acf(this->drawingManager());
1055 GrAAType aaType = this->chooseAAType(aa);
1056 auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
1057 auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
1058 : GrTextureOp::Saturate::kNo;
1059 GrTextureOp::AddTextureSetOps(this, clip, fContext, set, cnt, proxyRunCnt, filter, saturate,
1060 mode, aaType, constraint, viewMatrix, std::move(texXform));
1061 }
1062
drawVertices(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<SkVertices> vertices,const SkVertices::Bone bones[],int boneCount,GrPrimitiveType * overridePrimType)1063 void GrRenderTargetContext::drawVertices(const GrClip& clip,
1064 GrPaint&& paint,
1065 const SkMatrix& viewMatrix,
1066 sk_sp<SkVertices> vertices,
1067 const SkVertices::Bone bones[],
1068 int boneCount,
1069 GrPrimitiveType* overridePrimType) {
1070 ASSERT_SINGLE_OWNER
1071 RETURN_IF_ABANDONED
1072 SkDEBUGCODE(this->validate();)
1073 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
1074
1075 AutoCheckFlush acf(this->drawingManager());
1076
1077 SkASSERT(vertices);
1078 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1079 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
1080 fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
1081 this->colorInfo().refColorSpaceXformFromSRGB(), overridePrimType);
1082 this->addDrawOp(clip, std::move(op));
1083 }
1084
1085 ///////////////////////////////////////////////////////////////////////////////
1086
drawAtlas(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,int spriteCount,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[])1087 void GrRenderTargetContext::drawAtlas(const GrClip& clip,
1088 GrPaint&& paint,
1089 const SkMatrix& viewMatrix,
1090 int spriteCount,
1091 const SkRSXform xform[],
1092 const SkRect texRect[],
1093 const SkColor colors[]) {
1094 ASSERT_SINGLE_OWNER
1095 RETURN_IF_ABANDONED
1096 SkDEBUGCODE(this->validate();)
1097 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
1098
1099 AutoCheckFlush acf(this->drawingManager());
1100
1101 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1102 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1103 aaType, spriteCount, xform, texRect, colors);
1104 this->addDrawOp(clip, std::move(op));
1105 }
1106
1107 ///////////////////////////////////////////////////////////////////////////////
1108
drawRRect(const GrClip & origClip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStyle & style)1109 void GrRenderTargetContext::drawRRect(const GrClip& origClip,
1110 GrPaint&& paint,
1111 GrAA aa,
1112 const SkMatrix& viewMatrix,
1113 const SkRRect& rrect,
1114 const GrStyle& style) {
1115 ASSERT_SINGLE_OWNER
1116 RETURN_IF_ABANDONED
1117 SkDEBUGCODE(this->validate();)
1118 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
1119
1120 const SkStrokeRec& stroke = style.strokeRec();
1121 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
1122 return;
1123 }
1124
1125 GrNoClip noclip;
1126 const GrClip* clip = &origClip;
1127 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1128 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
1129 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
1130 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
1131 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
1132 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
1133 // only works for filled rrects since the stroke width outsets beyond the rrect itself.
1134 SkRRect devRRect;
1135 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
1136 clip->quickContains(devRRect)) {
1137 clip = &noclip;
1138 }
1139 #endif
1140 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1141
1142 AutoCheckFlush acf(this->drawingManager());
1143
1144 GrAAType aaType = this->chooseAAType(aa);
1145
1146 std::unique_ptr<GrDrawOp> op;
1147 if (GrAAType::kCoverage == aaType && rrect.isSimple() &&
1148 rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY &&
1149 viewMatrix.rectStaysRect() && viewMatrix.isSimilarity()) {
1150 // In coverage mode, we draw axis-aligned circular roundrects with the GrOvalOpFactory
1151 // to avoid perf regressions on some platforms.
1152 assert_alive(paint);
1153 op = GrOvalOpFactory::MakeCircularRRectOp(
1154 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1155 }
1156 if (!op && style.isSimpleFill()) {
1157 assert_alive(paint);
1158 op = GrFillRRectOp::Make(
1159 fContext, aaType, viewMatrix, rrect, *this->caps(), std::move(paint));
1160 }
1161 if (!op && GrAAType::kCoverage == aaType) {
1162 assert_alive(paint);
1163 op = GrOvalOpFactory::MakeRRectOp(
1164 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1165 }
1166 if (op) {
1167 this->addDrawOp(*clip, std::move(op));
1168 return;
1169 }
1170
1171 assert_alive(paint);
1172 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1173 GrShape(rrect, style));
1174 }
1175
1176 ///////////////////////////////////////////////////////////////////////////////
1177
map(const SkMatrix & m,const SkPoint3 & pt)1178 static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1179 SkPoint3 result;
1180 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1181 result.fZ = pt.fZ;
1182 return result;
1183 }
1184
drawFastShadow(const GrClip & clip,const SkMatrix & viewMatrix,const SkPath & path,const SkDrawShadowRec & rec)1185 bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
1186 const SkMatrix& viewMatrix,
1187 const SkPath& path,
1188 const SkDrawShadowRec& rec) {
1189 ASSERT_SINGLE_OWNER
1190 if (fContext->priv().abandoned()) {
1191 return true;
1192 }
1193 SkDEBUGCODE(this->validate();)
1194 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
1195
1196 // check z plane
1197 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1198 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1199 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1200 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1201 return false;
1202 }
1203
1204 SkRRect rrect;
1205 SkRect rect;
1206 // we can only handle rects, circles, and rrects with circular corners
1207 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
1208 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1209 if (!isRRect &&
1210 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1211 rect.width() > SK_ScalarNearlyZero) {
1212 rrect.setOval(rect);
1213 isRRect = true;
1214 }
1215 if (!isRRect && path.isRect(&rect)) {
1216 rrect.setRect(rect);
1217 isRRect = true;
1218 }
1219
1220 if (!isRRect) {
1221 return false;
1222 }
1223
1224 if (rrect.isEmpty()) {
1225 return true;
1226 }
1227
1228 AutoCheckFlush acf(this->drawingManager());
1229
1230 // transform light
1231 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1232
1233 // 1/scale
1234 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1235 SkScalarInvert(SkScalarAbs(viewMatrix[SkMatrix::kMScaleX])) :
1236 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1237 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1238
1239 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1240 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1241
1242 if (SkColorGetA(rec.fAmbientColor) > 0) {
1243 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1244 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1245 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1246
1247 // Outset the shadow rrect to the border of the penumbra
1248 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1249 SkRRect ambientRRect;
1250 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1251 // If the rrect was an oval then its outset will also be one.
1252 // We set it explicitly to avoid errors.
1253 if (rrect.isOval()) {
1254 ambientRRect = SkRRect::MakeOval(outsetRect);
1255 } else {
1256 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
1257 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1258 }
1259
1260 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
1261 if (transparent) {
1262 // set a large inset to force a fill
1263 devSpaceInsetWidth = ambientRRect.width();
1264 }
1265
1266 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1267 ambientColor,
1268 viewMatrix,
1269 ambientRRect,
1270 devSpaceAmbientBlur,
1271 devSpaceInsetWidth);
1272 if (op) {
1273 this->addDrawOp(clip, std::move(op));
1274 }
1275 }
1276
1277 if (SkColorGetA(rec.fSpotColor) > 0) {
1278 SkScalar devSpaceSpotBlur;
1279 SkScalar spotScale;
1280 SkVector spotOffset;
1281 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1282 devLightPos.fZ, rec.fLightRadius,
1283 &devSpaceSpotBlur, &spotScale, &spotOffset);
1284 // handle scale of radius due to CTM
1285 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1286
1287 // Adjust translate for the effect of the scale.
1288 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1289 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1290 // This offset is in dev space, need to transform it into source space.
1291 SkMatrix ctmInverse;
1292 if (viewMatrix.invert(&ctmInverse)) {
1293 ctmInverse.mapPoints(&spotOffset, 1);
1294 } else {
1295 // Since the matrix is a similarity, this should never happen, but just in case...
1296 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1297 SkASSERT(false);
1298 }
1299
1300 // Compute the transformed shadow rrect
1301 SkRRect spotShadowRRect;
1302 SkMatrix shadowTransform;
1303 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1304 rrect.transform(shadowTransform, &spotShadowRRect);
1305 SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
1306
1307 // Compute the insetWidth
1308 SkScalar blurOutset = srcSpaceSpotBlur;
1309 SkScalar insetWidth = blurOutset;
1310 if (transparent) {
1311 // If transparent, just do a fill
1312 insetWidth += spotShadowRRect.width();
1313 } else {
1314 // For shadows, instead of using a stroke we specify an inset from the penumbra
1315 // border. We want to extend this inset area so that it meets up with the caster
1316 // geometry. The inset geometry will by default already be inset by the blur width.
1317 //
1318 // We compare the min and max corners inset by the radius between the original
1319 // rrect and the shadow rrect. The distance between the two plus the difference
1320 // between the scaled radius and the original radius gives the distance from the
1321 // transformed shadow shape to the original shape in that corner. The max
1322 // of these gives the maximum distance we need to cover.
1323 //
1324 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1325 // that to get the full insetWidth.
1326 SkScalar maxOffset;
1327 if (rrect.isRect()) {
1328 // Manhattan distance works better for rects
1329 maxOffset = std::max(std::max(SkTAbs(spotShadowRRect.rect().fLeft -
1330 rrect.rect().fLeft),
1331 SkTAbs(spotShadowRRect.rect().fTop -
1332 rrect.rect().fTop)),
1333 std::max(SkTAbs(spotShadowRRect.rect().fRight -
1334 rrect.rect().fRight),
1335 SkTAbs(spotShadowRRect.rect().fBottom -
1336 rrect.rect().fBottom)));
1337 } else {
1338 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
1339 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1340 rrect.rect().fLeft + dr,
1341 spotShadowRRect.rect().fTop -
1342 rrect.rect().fTop + dr);
1343 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1344 rrect.rect().fRight - dr,
1345 spotShadowRRect.rect().fBottom -
1346 rrect.rect().fBottom - dr);
1347 maxOffset = SkScalarSqrt(std::max(SkPointPriv::LengthSqd(upperLeftOffset),
1348 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1349 }
1350 insetWidth += std::max(blurOutset, maxOffset);
1351 }
1352
1353 // Outset the shadow rrect to the border of the penumbra
1354 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1355 if (spotShadowRRect.isOval()) {
1356 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1357 } else {
1358 SkScalar outsetRad = spotRadius + blurOutset;
1359 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1360 }
1361
1362 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
1363
1364 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1365 spotColor,
1366 viewMatrix,
1367 spotShadowRRect,
1368 2.0f * devSpaceSpotBlur,
1369 insetWidth);
1370 if (op) {
1371 this->addDrawOp(clip, std::move(op));
1372 }
1373 }
1374
1375 return true;
1376 }
1377
1378 ///////////////////////////////////////////////////////////////////////////////
1379
drawFilledDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & origOuter,const SkRRect & origInner)1380 bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
1381 GrPaint&& paint,
1382 GrAA aa,
1383 const SkMatrix& viewMatrix,
1384 const SkRRect& origOuter,
1385 const SkRRect& origInner) {
1386 SkASSERT(!origInner.isEmpty());
1387 SkASSERT(!origOuter.isEmpty());
1388
1389 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1390
1391 GrAAType aaType = this->chooseAAType(aa);
1392
1393 if (GrAAType::kMSAA == aaType) {
1394 return false;
1395 }
1396
1397 if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1398 && SkRRectPriv::IsCircle(*outer)) {
1399 auto outerR = outer->width() / 2.f;
1400 auto innerR = inner->width() / 2.f;
1401 auto cx = outer->getBounds().fLeft + outerR;
1402 auto cy = outer->getBounds().fTop + outerR;
1403 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1404 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1405 auto avgR = (innerR + outerR) / 2.f;
1406 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1407 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1408 stroke.setStrokeStyle(outerR - innerR);
1409 auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
1410 circleBounds, GrStyle(stroke, nullptr),
1411 this->caps()->shaderCaps());
1412 if (op) {
1413 this->addDrawOp(clip, std::move(op));
1414 return true;
1415 }
1416 assert_alive(paint);
1417 }
1418 }
1419
1420 GrClipEdgeType innerEdgeType, outerEdgeType;
1421 if (GrAAType::kCoverage == aaType) {
1422 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1423 outerEdgeType = GrClipEdgeType::kFillAA;
1424 } else {
1425 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1426 outerEdgeType = GrClipEdgeType::kFillBW;
1427 }
1428
1429 SkMatrix inverseVM;
1430 if (!viewMatrix.isIdentity()) {
1431 if (!origInner.transform(viewMatrix, inner.writable())) {
1432 return false;
1433 }
1434 if (!origOuter.transform(viewMatrix, outer.writable())) {
1435 return false;
1436 }
1437 if (!viewMatrix.invert(&inverseVM)) {
1438 return false;
1439 }
1440 } else {
1441 inverseVM.reset();
1442 }
1443
1444 const auto& caps = *this->caps()->shaderCaps();
1445 // TODO these need to be a geometry processors
1446 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
1447 if (!innerEffect) {
1448 return false;
1449 }
1450
1451 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
1452 if (!outerEffect) {
1453 return false;
1454 }
1455
1456 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1457 paint.addCoverageFragmentProcessor(std::move(outerEffect));
1458
1459 SkRect bounds = outer->getBounds();
1460 if (GrAAType::kCoverage == aaType) {
1461 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1462 }
1463
1464 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1465 inverseVM);
1466 return true;
1467 }
1468
drawDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & outer,const SkRRect & inner)1469 void GrRenderTargetContext::drawDRRect(const GrClip& clip,
1470 GrPaint&& paint,
1471 GrAA aa,
1472 const SkMatrix& viewMatrix,
1473 const SkRRect& outer,
1474 const SkRRect& inner) {
1475 ASSERT_SINGLE_OWNER
1476 RETURN_IF_ABANDONED
1477 SkDEBUGCODE(this->validate();)
1478 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
1479
1480 SkASSERT(!outer.isEmpty());
1481 SkASSERT(!inner.isEmpty());
1482
1483 AutoCheckFlush acf(this->drawingManager());
1484
1485 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
1486 return;
1487 }
1488 assert_alive(paint);
1489
1490 SkPath path;
1491 path.setIsVolatile(true);
1492 path.addRRect(inner);
1493 path.addRRect(outer);
1494 path.setFillType(SkPathFillType::kEvenOdd);
1495 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
1496 }
1497
1498 ///////////////////////////////////////////////////////////////////////////////
1499
drawRegion(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRegion & region,const GrStyle & style,const GrUserStencilSettings * ss)1500 void GrRenderTargetContext::drawRegion(const GrClip& clip,
1501 GrPaint&& paint,
1502 GrAA aa,
1503 const SkMatrix& viewMatrix,
1504 const SkRegion& region,
1505 const GrStyle& style,
1506 const GrUserStencilSettings* ss) {
1507 ASSERT_SINGLE_OWNER
1508 RETURN_IF_ABANDONED
1509 SkDEBUGCODE(this->validate();)
1510 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
1511
1512 if (GrAA::kYes == aa) {
1513 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1514 // to see whether aa is really required.
1515 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1516 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1517 SkScalarIsInt(viewMatrix.getTranslateY())) {
1518 aa = GrAA::kNo;
1519 }
1520 }
1521 bool complexStyle = !style.isSimpleFill();
1522 if (complexStyle || GrAA::kYes == aa) {
1523 SkPath path;
1524 region.getBoundaryPath(&path);
1525 path.setIsVolatile(true);
1526
1527 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1528 }
1529
1530 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1531 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1532 aaType, ss);
1533 this->addDrawOp(clip, std::move(op));
1534 }
1535
drawOval(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,const GrStyle & style)1536 void GrRenderTargetContext::drawOval(const GrClip& clip,
1537 GrPaint&& paint,
1538 GrAA aa,
1539 const SkMatrix& viewMatrix,
1540 const SkRect& oval,
1541 const GrStyle& style) {
1542 ASSERT_SINGLE_OWNER
1543 RETURN_IF_ABANDONED
1544 SkDEBUGCODE(this->validate();)
1545 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
1546
1547 const SkStrokeRec& stroke = style.strokeRec();
1548
1549 if (oval.isEmpty() && !style.pathEffect()) {
1550 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1551 return;
1552 }
1553
1554 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1555 return;
1556 }
1557
1558 AutoCheckFlush acf(this->drawingManager());
1559
1560 GrAAType aaType = this->chooseAAType(aa);
1561
1562 std::unique_ptr<GrDrawOp> op;
1563 if (GrAAType::kCoverage == aaType && oval.width() > SK_ScalarNearlyZero &&
1564 oval.width() == oval.height() && viewMatrix.isSimilarity()) {
1565 // We don't draw true circles as round rects in coverage mode, because it can
1566 // cause perf regressions on some platforms as compared to the dedicated circle Op.
1567 assert_alive(paint);
1568 op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1569 this->caps()->shaderCaps());
1570 }
1571 if (!op && style.isSimpleFill()) {
1572 // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1573 // the arc equation. This same special geometry and fragment branch also turn out to be a
1574 // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1575 // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1576 // ovals the exact same way we do round rects.
1577 assert_alive(paint);
1578 op = GrFillRRectOp::Make(fContext, aaType, viewMatrix, SkRRect::MakeOval(oval),
1579 *this->caps(), std::move(paint));
1580 }
1581 if (!op && GrAAType::kCoverage == aaType) {
1582 assert_alive(paint);
1583 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1584 this->caps()->shaderCaps());
1585 }
1586 if (op) {
1587 this->addDrawOp(clip, std::move(op));
1588 return;
1589 }
1590
1591 assert_alive(paint);
1592 this->drawShapeUsingPathRenderer(
1593 clip, std::move(paint), aa, viewMatrix,
1594 GrShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2, false, style));
1595 }
1596
drawArc(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const GrStyle & style)1597 void GrRenderTargetContext::drawArc(const GrClip& clip,
1598 GrPaint&& paint,
1599 GrAA aa,
1600 const SkMatrix& viewMatrix,
1601 const SkRect& oval,
1602 SkScalar startAngle,
1603 SkScalar sweepAngle,
1604 bool useCenter,
1605 const GrStyle& style) {
1606 ASSERT_SINGLE_OWNER
1607 RETURN_IF_ABANDONED
1608 SkDEBUGCODE(this->validate();)
1609 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
1610
1611 AutoCheckFlush acf(this->drawingManager());
1612
1613 GrAAType aaType = this->chooseAAType(aa);
1614 if (GrAAType::kCoverage == aaType) {
1615 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1616 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1617 std::move(paint),
1618 viewMatrix,
1619 oval,
1620 startAngle,
1621 sweepAngle,
1622 useCenter,
1623 style,
1624 shaderCaps);
1625 if (op) {
1626 this->addDrawOp(clip, std::move(op));
1627 return;
1628 }
1629 assert_alive(paint);
1630 }
1631 this->drawShapeUsingPathRenderer(
1632 clip, std::move(paint), aa, viewMatrix,
1633 GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
1634 }
1635
drawImageLattice(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,GrSurfaceProxyView view,SkAlphaType alphaType,sk_sp<GrColorSpaceXform> csxf,GrSamplerState::Filter filter,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst)1636 void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
1637 GrPaint&& paint,
1638 const SkMatrix& viewMatrix,
1639 GrSurfaceProxyView view,
1640 SkAlphaType alphaType,
1641 sk_sp<GrColorSpaceXform> csxf,
1642 GrSamplerState::Filter filter,
1643 std::unique_ptr<SkLatticeIter> iter,
1644 const SkRect& dst) {
1645 ASSERT_SINGLE_OWNER
1646 RETURN_IF_ABANDONED
1647 SkDEBUGCODE(this->validate();)
1648 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
1649
1650 AutoCheckFlush acf(this->drawingManager());
1651
1652 std::unique_ptr<GrDrawOp> op =
1653 GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(view),
1654 alphaType, std::move(csxf), filter, std::move(iter), dst);
1655 this->addDrawOp(clip, std::move(op));
1656 }
1657
drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,const SkRect & bounds)1658 void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1659 const SkRect& bounds) {
1660 std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1661 SkASSERT(op);
1662 this->addOp(std::move(op));
1663 }
1664
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,SkSurface::RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)1665 void GrRenderTargetContext::asyncRescaleAndReadPixels(
1666 const SkImageInfo& info, const SkIRect& srcRect, SkSurface::RescaleGamma rescaleGamma,
1667 SkFilterQuality rescaleQuality, ReadPixelsCallback callback, ReadPixelsContext context) {
1668 auto direct = fContext->priv().asDirectContext();
1669 if (!direct) {
1670 callback(context, nullptr);
1671 return;
1672 }
1673 if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
1674 callback(context, nullptr);
1675 return;
1676 }
1677 if (this->asRenderTargetProxy()->framebufferOnly()) {
1678 callback(context, nullptr);
1679 return;
1680 }
1681 auto dstCT = SkColorTypeToGrColorType(info.colorType());
1682 if (dstCT == GrColorType::kUnknown) {
1683 callback(context, nullptr);
1684 return;
1685 }
1686 bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
1687 auto colorTypeOfFinalContext = this->colorInfo().colorType();
1688 auto backendFormatOfFinalContext = this->asSurfaceProxy()->backendFormat();
1689 if (needsRescale) {
1690 colorTypeOfFinalContext = dstCT;
1691 backendFormatOfFinalContext = this->caps()->getDefaultBackendFormat(dstCT,
1692 GrRenderable::kYes);
1693 }
1694 auto readInfo = this->caps()->supportedReadPixelsColorType(colorTypeOfFinalContext,
1695 backendFormatOfFinalContext, dstCT);
1696 // Fail if we can't read from the source surface's color type.
1697 if (readInfo.fColorType == GrColorType::kUnknown) {
1698 callback(context, nullptr);
1699 return;
1700 }
1701 // Fail if read color type does not have all of dstCT's color channels and those missing color
1702 // channels are in the src.
1703 uint32_t dstComponents = GrColorTypeComponentFlags(dstCT);
1704 uint32_t legalReadComponents = GrColorTypeComponentFlags(readInfo.fColorType);
1705 uint32_t srcComponents = GrColorTypeComponentFlags(this->colorInfo().colorType());
1706 if ((~legalReadComponents & dstComponents) & srcComponents) {
1707 callback(context, nullptr);
1708 return;
1709 }
1710
1711 std::unique_ptr<GrRenderTargetContext> tempRTC;
1712 int x = srcRect.fLeft;
1713 int y = srcRect.fTop;
1714 if (needsRescale) {
1715 tempRTC = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
1716 if (!tempRTC) {
1717 callback(context, nullptr);
1718 return;
1719 }
1720 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
1721 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
1722 x = y = 0;
1723 } else {
1724 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(),
1725 this->colorInfo().alphaType(),
1726 info.colorSpace(),
1727 info.alphaType());
1728 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
1729 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
1730 // We flip or color convert by drawing and we don't currently support drawing to
1731 // kPremul.
1732 if (info.alphaType() == kUnpremul_SkAlphaType) {
1733 callback(context, nullptr);
1734 return;
1735 }
1736 GrSurfaceProxyView texProxyView = this->readSurfaceView();
1737 SkRect srcRectToDraw = SkRect::Make(srcRect);
1738 // If the src is not texturable first try to make a copy to a texture.
1739 if (!texProxyView.asTextureProxy()) {
1740 texProxyView = GrSurfaceProxy::Copy(fContext, this->asSurfaceProxy(),
1741 this->origin(), this->colorInfo().colorType(),
1742 GrMipMapped::kNo, srcRect,
1743 SkBackingFit::kApprox, SkBudgeted::kNo);
1744 if (!texProxyView.asTextureProxy()) {
1745 callback(context, nullptr);
1746 return;
1747 }
1748 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
1749 }
1750 tempRTC = GrRenderTargetContext::Make(
1751 direct, this->colorInfo().colorType(), info.refColorSpace(),
1752 SkBackingFit::kApprox, srcRect.size(), 1, GrMipMapped::kNo, GrProtected::kNo,
1753 kTopLeft_GrSurfaceOrigin);
1754 if (!tempRTC) {
1755 callback(context, nullptr);
1756 return;
1757 }
1758 tempRTC->drawTexture(GrNoClip(), std::move(texProxyView), this->colorInfo().alphaType(),
1759 GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
1760 SK_PMColor4fWHITE, srcRectToDraw,
1761 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
1762 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
1763 SkMatrix::I(), std::move(xform));
1764 x = y = 0;
1765 }
1766 }
1767 auto rtc = tempRTC ? tempRTC.get() : this;
1768 return rtc->asyncReadPixels(SkIRect::MakeXYWH(x, y, info.width(), info.height()),
1769 info.colorType(), callback, context);
1770 }
1771
1772 class GrRenderTargetContext::AsyncReadResult : public SkSurface::AsyncReadResult {
1773 public:
AsyncReadResult(uint32_t inboxID)1774 AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
~AsyncReadResult()1775 ~AsyncReadResult() override {
1776 for (int i = 0; i < fPlanes.count(); ++i) {
1777 if (!fPlanes[i].fMappedBuffer) {
1778 delete[] static_cast<const char*>(fPlanes[i].fData);
1779 } else {
1780 GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
1781 {std::move(fPlanes[i].fMappedBuffer), fInboxID});
1782 }
1783 }
1784 }
1785
count() const1786 int count() const override { return fPlanes.count(); }
data(int i) const1787 const void* data(int i) const override { return fPlanes[i].fData; }
rowBytes(int i) const1788 size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
1789
addTransferResult(const PixelTransferResult & result,SkISize dimensions,size_t rowBytes,GrClientMappedBufferManager * manager)1790 bool addTransferResult(const PixelTransferResult& result,
1791 SkISize dimensions,
1792 size_t rowBytes,
1793 GrClientMappedBufferManager* manager) {
1794 SkASSERT(!result.fTransferBuffer->isMapped());
1795 const void* mappedData = result.fTransferBuffer->map();
1796 if (!mappedData) {
1797 return false;
1798 }
1799 if (result.fPixelConverter) {
1800 std::unique_ptr<char[]> convertedData(new char[rowBytes * dimensions.height()]);
1801 result.fPixelConverter(convertedData.get(), mappedData);
1802 this->addCpuPlane(std::move(convertedData), rowBytes);
1803 result.fTransferBuffer->unmap();
1804 } else {
1805 manager->insert(result.fTransferBuffer);
1806 this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
1807 }
1808 return true;
1809 }
1810
addCpuPlane(std::unique_ptr<const char[]> data,size_t rowBytes)1811 void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
1812 SkASSERT(data);
1813 SkASSERT(rowBytes > 0);
1814 fPlanes.emplace_back(data.release(), rowBytes, nullptr);
1815 }
1816
1817 private:
addMappedPlane(const void * data,size_t rowBytes,sk_sp<GrGpuBuffer> mappedBuffer)1818 void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
1819 SkASSERT(data);
1820 SkASSERT(rowBytes > 0);
1821 SkASSERT(mappedBuffer);
1822 SkASSERT(mappedBuffer->isMapped());
1823 fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
1824 }
1825
1826 struct Plane {
PlaneGrRenderTargetContext::AsyncReadResult::Plane1827 Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
1828 : fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
1829 const void* fData;
1830 size_t fRowBytes;
1831 // If this is null then fData is heap alloc and must be delete[]ed as const char[].
1832 sk_sp<GrGpuBuffer> fMappedBuffer;
1833 };
1834 SkSTArray<3, Plane> fPlanes;
1835 uint32_t fInboxID;
1836 };
1837
asyncReadPixels(const SkIRect & rect,SkColorType colorType,ReadPixelsCallback callback,ReadPixelsContext context)1838 void GrRenderTargetContext::asyncReadPixels(const SkIRect& rect, SkColorType colorType,
1839 ReadPixelsCallback callback,
1840 ReadPixelsContext context) {
1841 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1842 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
1843
1844 if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
1845 callback(context, nullptr);
1846 return;
1847 }
1848
1849 auto directContext = fContext->priv().asDirectContext();
1850 SkASSERT(directContext);
1851 auto mappedBufferManager = directContext->priv().clientMappedBufferManager();
1852
1853 auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
1854
1855 if (!transferResult.fTransferBuffer) {
1856 auto ii = SkImageInfo::Make(rect.size(), colorType,
1857 this->colorInfo().alphaType(),
1858 this->colorInfo().refColorSpace());
1859 auto result = std::make_unique<AsyncReadResult>(0);
1860 std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
1861 SkPixmap pm(ii, data.get(), ii.minRowBytes());
1862 result->addCpuPlane(std::move(data), pm.rowBytes());
1863
1864 if (!this->readPixels(ii, pm.writable_addr(), pm.rowBytes(), {rect.fLeft, rect.fTop})) {
1865 callback(context, nullptr);
1866 return;
1867 }
1868 callback(context, std::move(result));
1869 return;
1870 }
1871
1872 struct FinishContext {
1873 ReadPixelsCallback* fClientCallback;
1874 ReadPixelsContext fClientContext;
1875 SkISize fSize;
1876 SkColorType fColorType;
1877 GrClientMappedBufferManager* fMappedBufferManager;
1878 PixelTransferResult fTransferResult;
1879 };
1880 // Assumption is that the caller would like to flush. We could take a parameter or require an
1881 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
1882 // callback to GrGpu until after the next flush that flushes our op list, though.
1883 auto* finishContext = new FinishContext{callback,
1884 context,
1885 rect.size(),
1886 colorType,
1887 mappedBufferManager,
1888 std::move(transferResult)};
1889 auto finishCallback = [](GrGpuFinishedContext c) {
1890 const auto* context = reinterpret_cast<const FinishContext*>(c);
1891 auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
1892 size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
1893 if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
1894 context->fMappedBufferManager)) {
1895 result.reset();
1896 }
1897 (*context->fClientCallback)(context->fClientContext, std::move(result));
1898 delete context;
1899 };
1900 GrFlushInfo flushInfo;
1901 flushInfo.fFinishedContext = finishContext;
1902 flushInfo.fFinishedProc = finishCallback;
1903 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
1904 }
1905
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,SkISize dstSize,RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)1906 void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
1907 sk_sp<SkColorSpace> dstColorSpace,
1908 const SkIRect& srcRect,
1909 SkISize dstSize,
1910 RescaleGamma rescaleGamma,
1911 SkFilterQuality rescaleQuality,
1912 ReadPixelsCallback callback,
1913 ReadPixelsContext context) {
1914 SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
1915 SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
1916 SkASSERT(!dstSize.isZero());
1917 SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
1918
1919 auto direct = fContext->priv().asDirectContext();
1920 if (!direct) {
1921 callback(context, nullptr);
1922 return;
1923 }
1924 if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
1925 callback(context, nullptr);
1926 return;
1927 }
1928 if (this->asRenderTargetProxy()->framebufferOnly()) {
1929 callback(context, nullptr);
1930 return;
1931 }
1932 if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
1933 callback(context, nullptr);
1934 return;
1935 }
1936 int x = srcRect.fLeft;
1937 int y = srcRect.fTop;
1938 bool needsRescale = srcRect.size() != dstSize;
1939 GrSurfaceProxyView srcView;
1940 if (needsRescale) {
1941 // We assume the caller wants kPremul. There is no way to indicate a preference.
1942 auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
1943 dstColorSpace);
1944 // TODO: Incorporate the YUV conversion into last pass of rescaling.
1945 auto tempRTC = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
1946 if (!tempRTC) {
1947 callback(context, nullptr);
1948 return;
1949 }
1950 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
1951 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
1952 x = y = 0;
1953 srcView = tempRTC->readSurfaceView();
1954 } else {
1955 srcView = this->readSurfaceView();
1956 if (!srcView.asTextureProxy()) {
1957 srcView = GrSurfaceProxy::Copy(fContext, fReadView.proxy(), this->origin(),
1958 this->colorInfo().colorType(), GrMipMapped::kNo,
1959 srcRect, SkBackingFit::kApprox, SkBudgeted::kYes);
1960 if (!srcView.asTextureProxy()) {
1961 // If we can't get a texture copy of the contents then give up.
1962 callback(context, nullptr);
1963 return;
1964 }
1965 x = y = 0;
1966 }
1967 // We assume the caller wants kPremul. There is no way to indicate a preference.
1968 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(
1969 this->colorInfo().colorSpace(), this->colorInfo().alphaType(), dstColorSpace.get(),
1970 kPremul_SkAlphaType);
1971 if (xform) {
1972 SkRect srcRectToDraw = SkRect::MakeXYWH(x, y, srcRect.width(), srcRect.height());
1973 auto tempRTC = GrRenderTargetContext::Make(
1974 direct, this->colorInfo().colorType(), dstColorSpace, SkBackingFit::kApprox,
1975 dstSize, 1, GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
1976 if (!tempRTC) {
1977 callback(context, nullptr);
1978 return;
1979 }
1980 tempRTC->drawTexture(GrNoClip(), std::move(srcView), this->colorInfo().alphaType(),
1981 GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
1982 SK_PMColor4fWHITE, srcRectToDraw, SkRect::Make(srcRect.size()),
1983 GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
1984 SkMatrix::I(), std::move(xform));
1985 srcView = tempRTC->readSurfaceView();
1986 SkASSERT(srcView.asTextureProxy());
1987 x = y = 0;
1988 }
1989 }
1990
1991 auto yRTC = GrRenderTargetContext::MakeWithFallback(
1992 direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, dstSize, 1,
1993 GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
1994 int halfW = dstSize.width()/2;
1995 int halfH = dstSize.height()/2;
1996 auto uRTC = GrRenderTargetContext::MakeWithFallback(
1997 direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH}, 1,
1998 GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
1999 auto vRTC = GrRenderTargetContext::MakeWithFallback(
2000 direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH}, 1,
2001 GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
2002 if (!yRTC || !uRTC || !vRTC) {
2003 callback(context, nullptr);
2004 return;
2005 }
2006
2007 float baseM[20];
2008 SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
2009
2010 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
2011
2012 auto texMatrix = SkMatrix::MakeTrans(x, y);
2013
2014 SkRect dstRectY = SkRect::Make(dstSize);
2015 SkRect dstRectUV = SkRect::MakeWH(halfW, halfH);
2016
2017 bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
2018 PixelTransferResult yTransfer, uTransfer, vTransfer;
2019
2020 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
2021 float yM[20];
2022 std::fill_n(yM, 15, 0.f);
2023 std::copy_n(baseM + 0, 5, yM + 15);
2024 GrPaint yPaint;
2025 yPaint.addColorFragmentProcessor(
2026 GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix));
2027 auto yFP = GrColorMatrixFragmentProcessor::Make(yM, false, true, false);
2028 yPaint.addColorFragmentProcessor(std::move(yFP));
2029 yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2030 yRTC->fillRectToRect(GrNoClip(), std::move(yPaint), GrAA::kNo, SkMatrix::I(),
2031 dstRectY, dstRectY);
2032 if (!doSynchronousRead) {
2033 yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
2034 SkIRect::MakeWH(yRTC->width(), yRTC->height()));
2035 if (!yTransfer.fTransferBuffer) {
2036 callback(context, nullptr);
2037 return;
2038 }
2039 }
2040
2041 texMatrix.preScale(2.f, 2.f);
2042 // This matrix generates (r,g,b,a) = (0, 0, 0, u)
2043 float uM[20];
2044 std::fill_n(uM, 15, 0.f);
2045 std::copy_n(baseM + 5, 5, uM + 15);
2046 GrPaint uPaint;
2047 uPaint.addColorFragmentProcessor(GrTextureEffect::Make(
2048 srcView, this->colorInfo().alphaType(), texMatrix, GrSamplerState::Filter::kBilerp));
2049 auto uFP = GrColorMatrixFragmentProcessor::Make(uM, false, true, false);
2050 uPaint.addColorFragmentProcessor(std::move(uFP));
2051 uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2052 uRTC->fillRectToRect(GrNoClip(), std::move(uPaint), GrAA::kNo, SkMatrix::I(),
2053 dstRectUV, dstRectUV);
2054 if (!doSynchronousRead) {
2055 uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
2056 SkIRect::MakeWH(uRTC->width(), uRTC->height()));
2057 if (!uTransfer.fTransferBuffer) {
2058 callback(context, nullptr);
2059 return;
2060 }
2061 }
2062
2063 // This matrix generates (r,g,b,a) = (0, 0, 0, v)
2064 float vM[20];
2065 std::fill_n(vM, 15, 0.f);
2066 std::copy_n(baseM + 10, 5, vM + 15);
2067 GrPaint vPaint;
2068 vPaint.addColorFragmentProcessor(GrTextureEffect::Make(std::move(srcView),
2069 this->colorInfo().alphaType(), texMatrix,
2070 GrSamplerState::Filter::kBilerp));
2071 auto vFP = GrColorMatrixFragmentProcessor::Make(vM, false, true, false);
2072 vPaint.addColorFragmentProcessor(std::move(vFP));
2073 vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2074 vRTC->fillRectToRect(GrNoClip(), std::move(vPaint), GrAA::kNo, SkMatrix::I(),
2075 dstRectUV, dstRectUV);
2076 if (!doSynchronousRead) {
2077 vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
2078 SkIRect::MakeWH(vRTC->width(), vRTC->height()));
2079 if (!vTransfer.fTransferBuffer) {
2080 callback(context, nullptr);
2081 return;
2082 }
2083 }
2084
2085 if (doSynchronousRead) {
2086 GrImageInfo yInfo(GrColorType::kAlpha_8, kPremul_SkAlphaType, nullptr, dstSize);
2087 GrImageInfo uvInfo = yInfo.makeWH(halfW, halfH);
2088 size_t yRB = yInfo.minRowBytes();
2089 size_t uvRB = uvInfo.minRowBytes();
2090 std::unique_ptr<char[]> y(new char[yRB * yInfo.height()]);
2091 std::unique_ptr<char[]> u(new char[uvRB*uvInfo.height()]);
2092 std::unique_ptr<char[]> v(new char[uvRB*uvInfo.height()]);
2093 if (!yRTC->readPixels(yInfo, y.get(), yRB, {0, 0}, direct) ||
2094 !uRTC->readPixels(uvInfo, u.get(), uvRB, {0, 0}, direct) ||
2095 !vRTC->readPixels(uvInfo, v.get(), uvRB, {0, 0}, direct)) {
2096 callback(context, nullptr);
2097 return;
2098 }
2099 auto result = std::make_unique<AsyncReadResult>(direct->priv().contextID());
2100 result->addCpuPlane(std::move(y), yRB );
2101 result->addCpuPlane(std::move(u), uvRB);
2102 result->addCpuPlane(std::move(v), uvRB);
2103 callback(context, std::move(result));
2104 return;
2105 }
2106
2107 struct FinishContext {
2108 ReadPixelsCallback* fClientCallback;
2109 ReadPixelsContext fClientContext;
2110 GrClientMappedBufferManager* fMappedBufferManager;
2111 SkISize fSize;
2112 PixelTransferResult fYTransfer;
2113 PixelTransferResult fUTransfer;
2114 PixelTransferResult fVTransfer;
2115 };
2116 // Assumption is that the caller would like to flush. We could take a parameter or require an
2117 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
2118 // callback to GrGpu until after the next flush that flushes our op list, though.
2119 auto* finishContext = new FinishContext{callback,
2120 context,
2121 direct->priv().clientMappedBufferManager(),
2122 dstSize,
2123 std::move(yTransfer),
2124 std::move(uTransfer),
2125 std::move(vTransfer)};
2126 auto finishCallback = [](GrGpuFinishedContext c) {
2127 const auto* context = reinterpret_cast<const FinishContext*>(c);
2128 auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
2129 auto manager = context->fMappedBufferManager;
2130 size_t rowBytes = SkToSizeT(context->fSize.width());
2131 if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
2132 (*context->fClientCallback)(context->fClientContext, nullptr);
2133 delete context;
2134 return;
2135 }
2136 rowBytes /= 2;
2137 SkISize uvSize = {context->fSize.width()/2, context->fSize.height()/2};
2138 if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
2139 (*context->fClientCallback)(context->fClientContext, nullptr);
2140 delete context;
2141 return;
2142 }
2143 if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
2144 (*context->fClientCallback)(context->fClientContext, nullptr);
2145 delete context;
2146 return;
2147 }
2148 (*context->fClientCallback)(context->fClientContext, std::move(result));
2149 delete context;
2150 };
2151 GrFlushInfo flushInfo;
2152 flushInfo.fFinishedContext = finishContext;
2153 flushInfo.fFinishedProc = finishCallback;
2154 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
2155 }
2156
flush(SkSurface::BackendSurfaceAccess access,const GrFlushInfo & info)2157 GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,
2158 const GrFlushInfo& info) {
2159 ASSERT_SINGLE_OWNER
2160 if (fContext->priv().abandoned()) {
2161 return GrSemaphoresSubmitted::kNo;
2162 }
2163 SkDEBUGCODE(this->validate();)
2164 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
2165
2166 return this->drawingManager()->flushSurface(this->asSurfaceProxy(), access, info);
2167 }
2168
waitOnSemaphores(int numSemaphores,const GrBackendSemaphore waitSemaphores[])2169 bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
2170 const GrBackendSemaphore waitSemaphores[]) {
2171 ASSERT_SINGLE_OWNER
2172 RETURN_FALSE_IF_ABANDONED
2173 SkDEBUGCODE(this->validate();)
2174 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
2175
2176 AutoCheckFlush acf(this->drawingManager());
2177
2178 if (numSemaphores && !this->caps()->semaphoreSupport()) {
2179 return false;
2180 }
2181
2182 auto direct = fContext->priv().asDirectContext();
2183 if (!direct) {
2184 return false;
2185 }
2186
2187 auto resourceProvider = direct->priv().resourceProvider();
2188
2189 std::unique_ptr<std::unique_ptr<GrSemaphore>[]> grSemaphores(
2190 new std::unique_ptr<GrSemaphore>[numSemaphores]);
2191 for (int i = 0; i < numSemaphores; ++i) {
2192 grSemaphores[i] = resourceProvider->wrapBackendSemaphore(
2193 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
2194 kAdopt_GrWrapOwnership);
2195 }
2196 this->drawingManager()->newWaitRenderTask(this->asSurfaceProxyRef(), std::move(grSemaphores),
2197 numSemaphores);
2198 return true;
2199 }
2200
drawPath(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path,const GrStyle & style)2201 void GrRenderTargetContext::drawPath(const GrClip& clip,
2202 GrPaint&& paint,
2203 GrAA aa,
2204 const SkMatrix& viewMatrix,
2205 const SkPath& path,
2206 const GrStyle& style) {
2207 ASSERT_SINGLE_OWNER
2208 RETURN_IF_ABANDONED
2209 SkDEBUGCODE(this->validate();)
2210 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
2211
2212 GrShape shape(path, style);
2213
2214 this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
2215 }
2216
drawShape(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & shape)2217 void GrRenderTargetContext::drawShape(const GrClip& clip,
2218 GrPaint&& paint,
2219 GrAA aa,
2220 const SkMatrix& viewMatrix,
2221 const GrShape& shape) {
2222 ASSERT_SINGLE_OWNER
2223 RETURN_IF_ABANDONED
2224 SkDEBUGCODE(this->validate();)
2225 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
2226
2227 if (shape.isEmpty()) {
2228 if (shape.inverseFilled()) {
2229 this->drawPaint(clip, std::move(paint), viewMatrix);
2230 }
2231 return;
2232 }
2233
2234 AutoCheckFlush acf(this->drawingManager());
2235
2236 if (!shape.style().hasPathEffect()) {
2237 GrAAType aaType = this->chooseAAType(aa);
2238 SkRRect rrect;
2239 // We can ignore the starting point and direction since there is no path effect.
2240 bool inverted;
2241 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
2242 if (rrect.isRect()) {
2243 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
2244 &shape.style());
2245 return;
2246 } else if (rrect.isOval()) {
2247 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
2248 return;
2249 }
2250 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
2251 return;
2252 } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
2253 viewMatrix.rectStaysRect()) {
2254 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
2255 // the matrix to all the points individually rather than just to the rect
2256 SkRect rects[2];
2257 if (shape.asNestedRects(rects)) {
2258 // Concave AA paths are expensive - try to avoid them for special cases
2259 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
2260 fContext, std::move(paint), viewMatrix, rects);
2261 if (op) {
2262 this->addDrawOp(clip, std::move(op));
2263 }
2264 // Returning here indicates that there is nothing to draw in this case.
2265 return;
2266 }
2267 }
2268 }
2269
2270 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
2271 }
2272
drawAndStencilPath(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path)2273 bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
2274 const GrUserStencilSettings* ss,
2275 SkRegion::Op op,
2276 bool invert,
2277 GrAA aa,
2278 const SkMatrix& viewMatrix,
2279 const SkPath& path) {
2280 ASSERT_SINGLE_OWNER_PRIV
2281 RETURN_FALSE_IF_ABANDONED_PRIV
2282 SkDEBUGCODE(fRenderTargetContext->validate();)
2283 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
2284 fRenderTargetContext->fContext);
2285
2286 if (path.isEmpty() && path.isInverseFillType()) {
2287 GrPaint paint;
2288 paint.setCoverageSetOpXPFactory(op, invert);
2289 this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
2290 SkRect::MakeIWH(fRenderTargetContext->width(),
2291 fRenderTargetContext->height()));
2292 return true;
2293 }
2294
2295 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
2296
2297 // An Assumption here is that path renderer would use some form of tweaking
2298 // the src color (either the input alpha or in the frag shader) to implement
2299 // aa. If we have some future driver-mojo path AA that can do the right
2300 // thing WRT to the blend then we'll need some query on the PR.
2301 GrAAType aaType = fRenderTargetContext->chooseAAType(aa);
2302 bool hasUserStencilSettings = !ss->isUnused();
2303
2304 SkIRect clipConservativeBounds;
2305 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
2306 &clipConservativeBounds, nullptr);
2307
2308 GrShape shape(path, GrStyle::SimpleFill());
2309 GrPathRenderer::CanDrawPathArgs canDrawArgs;
2310 canDrawArgs.fCaps = fRenderTargetContext->caps();
2311 canDrawArgs.fProxy = fRenderTargetContext->asRenderTargetProxy();
2312 canDrawArgs.fViewMatrix = &viewMatrix;
2313 canDrawArgs.fShape = &shape;
2314 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
2315 canDrawArgs.fAAType = aaType;
2316 SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
2317 canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
2318 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
2319
2320 // Don't allow the SW renderer
2321 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
2322 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
2323 if (!pr) {
2324 return false;
2325 }
2326
2327 GrPaint paint;
2328 paint.setCoverageSetOpXPFactory(op, invert);
2329
2330 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
2331 std::move(paint),
2332 ss,
2333 fRenderTargetContext,
2334 &clip,
2335 &clipConservativeBounds,
2336 &viewMatrix,
2337 &shape,
2338 aaType,
2339 fRenderTargetContext->colorInfo().isLinearlyBlended()};
2340 pr->drawPath(args);
2341 return true;
2342 }
2343
isBudgeted() const2344 SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
2345 ASSERT_SINGLE_OWNER_PRIV
2346
2347 if (fRenderTargetContext->fContext->priv().abandoned()) {
2348 return SkBudgeted::kNo;
2349 }
2350
2351 SkDEBUGCODE(fRenderTargetContext->validate();)
2352
2353 return fRenderTargetContext->asSurfaceProxy()->isBudgeted();
2354 }
2355
drawShapeUsingPathRenderer(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & originalShape)2356 void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
2357 GrPaint&& paint,
2358 GrAA aa,
2359 const SkMatrix& viewMatrix,
2360 const GrShape& originalShape) {
2361 ASSERT_SINGLE_OWNER
2362 RETURN_IF_ABANDONED
2363 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
2364
2365 if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
2366 return;
2367 }
2368
2369 SkIRect clipConservativeBounds;
2370 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
2371
2372 GrShape tempShape;
2373 GrAAType aaType = this->chooseAAType(aa);
2374
2375 GrPathRenderer::CanDrawPathArgs canDrawArgs;
2376 canDrawArgs.fCaps = this->caps();
2377 canDrawArgs.fProxy = this->asRenderTargetProxy();
2378 canDrawArgs.fViewMatrix = &viewMatrix;
2379 canDrawArgs.fShape = &originalShape;
2380 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
2381 canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
2382 canDrawArgs.fHasUserStencilSettings = false;
2383
2384 GrPathRenderer* pr;
2385 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
2386 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
2387 return;
2388 }
2389
2390 canDrawArgs.fAAType = aaType;
2391
2392 // Try a 1st time without applying any of the style to the geometry (and barring sw)
2393 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2394 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
2395
2396 if (!pr && originalShape.style().pathEffect()) {
2397 // It didn't work above, so try again with the path effect applied.
2398 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
2399 if (tempShape.isEmpty()) {
2400 return;
2401 }
2402 canDrawArgs.fShape = &tempShape;
2403 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2404 }
2405 if (!pr) {
2406 if (canDrawArgs.fShape->style().applies()) {
2407 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
2408 styleScale);
2409 if (tempShape.isEmpty()) {
2410 return;
2411 }
2412 canDrawArgs.fShape = &tempShape;
2413 // This time, allow SW renderer
2414 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
2415 } else {
2416 pr = this->drawingManager()->getSoftwarePathRenderer();
2417 }
2418 }
2419
2420 if (!pr) {
2421 #ifdef SK_DEBUG
2422 SkDebugf("Unable to find path renderer compatible with path.\n");
2423 #endif
2424 return;
2425 }
2426
2427 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
2428 std::move(paint),
2429 &GrUserStencilSettings::kUnused,
2430 this,
2431 &clip,
2432 &clipConservativeBounds,
2433 &viewMatrix,
2434 canDrawArgs.fShape,
2435 aaType,
2436 this->colorInfo().isLinearlyBlended()};
2437 pr->drawPath(args);
2438 }
2439
op_bounds(SkRect * bounds,const GrOp * op)2440 static void op_bounds(SkRect* bounds, const GrOp* op) {
2441 *bounds = op->bounds();
2442 if (op->hasZeroArea()) {
2443 if (op->hasAABloat()) {
2444 bounds->outset(0.5f, 0.5f);
2445 } else {
2446 // We don't know which way the particular GPU will snap lines or points at integer
2447 // coords. So we ensure that the bounds is large enough for either snap.
2448 SkRect before = *bounds;
2449 bounds->roundOut(bounds);
2450 if (bounds->fLeft == before.fLeft) {
2451 bounds->fLeft -= 1;
2452 }
2453 if (bounds->fTop == before.fTop) {
2454 bounds->fTop -= 1;
2455 }
2456 if (bounds->fRight == before.fRight) {
2457 bounds->fRight += 1;
2458 }
2459 if (bounds->fBottom == before.fBottom) {
2460 bounds->fBottom += 1;
2461 }
2462 }
2463 }
2464 }
2465
addOp(std::unique_ptr<GrOp> op)2466 void GrRenderTargetContext::addOp(std::unique_ptr<GrOp> op) {
2467 this->getOpsTask()->addOp(
2468 std::move(op), GrTextureResolveManager(this->drawingManager()), *this->caps());
2469 }
2470
addDrawOp(const GrClip & clip,std::unique_ptr<GrDrawOp> op,const std::function<WillAddOpFn> & willAddFn)2471 void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2472 const std::function<WillAddOpFn>& willAddFn) {
2473 ASSERT_SINGLE_OWNER
2474 if (fContext->priv().abandoned()) {
2475 fContext->priv().opMemoryPool()->release(std::move(op));
2476 return;
2477 }
2478 SkDEBUGCODE(this->validate();)
2479 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
2480 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
2481
2482 // Setup clip
2483 SkRect bounds;
2484 op_bounds(&bounds, op.get());
2485 GrAppliedClip appliedClip;
2486 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
2487 bool usesHWAA = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA;
2488 bool usesUserStencilBits = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil;
2489
2490 if (usesUserStencilBits) { // Stencil clipping will call setNeedsStencil on its own, if needed.
2491 this->setNeedsStencil(usesHWAA);
2492 }
2493
2494 if (!clip.apply(fContext, this, usesHWAA, usesUserStencilBits, &appliedClip, &bounds)) {
2495 fContext->priv().opMemoryPool()->release(std::move(op));
2496 return;
2497 }
2498
2499 bool willUseStencil = usesUserStencilBits || appliedClip.hasStencilClip();
2500 SkASSERT(!willUseStencil || fNumStencilSamples > 0);
2501
2502 // If stencil is enabled and the framebuffer is mixed sampled, then the graphics pipeline will
2503 // have mixed sampled coverage, regardless of whether HWAA is enabled. (e.g., a non-aa draw
2504 // that uses a stencil test when the stencil buffer is multisampled.)
2505 bool hasMixedSampledCoverage = (
2506 willUseStencil && fNumStencilSamples > this->numSamples());
2507 SkASSERT(!hasMixedSampledCoverage ||
2508 this->asRenderTargetProxy()->canUseMixedSamples(*this->caps()));
2509
2510 GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
2511 GrProcessorSet::Analysis analysis = op->finalize(
2512 *this->caps(), &appliedClip, hasMixedSampledCoverage, clampType);
2513
2514 GrXferProcessor::DstProxyView dstProxyView;
2515 if (analysis.requiresDstTexture()) {
2516 if (!this->setupDstProxyView(clip, *op, &dstProxyView)) {
2517 fContext->priv().opMemoryPool()->release(std::move(op));
2518 return;
2519 }
2520 }
2521
2522 op->setClippedBounds(bounds);
2523 auto opsTask = this->getOpsTask();
2524 if (willAddFn) {
2525 willAddFn(op.get(), opsTask->uniqueID());
2526 }
2527 opsTask->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxyView,
2528 GrTextureResolveManager(this->drawingManager()), *this->caps());
2529 }
2530
setupDstProxyView(const GrClip & clip,const GrOp & op,GrXferProcessor::DstProxyView * dstProxyView)2531 bool GrRenderTargetContext::setupDstProxyView(const GrClip& clip, const GrOp& op,
2532 GrXferProcessor::DstProxyView* dstProxyView) {
2533 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2534 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2535 // start and stop the render pass in order to make the copy.
2536 if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
2537 return false;
2538 }
2539
2540 if (this->caps()->textureBarrierSupport() &&
2541 !this->asSurfaceProxy()->requiresManualMSAAResolve()) {
2542 if (this->asTextureProxy()) {
2543 // The render target is a texture, so we can read from it directly in the shader. The XP
2544 // will be responsible to detect this situation and request a texture barrier.
2545 dstProxyView->setProxyView(this->readSurfaceView());
2546 dstProxyView->setOffset(0, 0);
2547 return true;
2548 }
2549 }
2550
2551 SkIRect copyRect = SkIRect::MakeSize(this->asSurfaceProxy()->dimensions());
2552
2553 SkIRect clippedRect;
2554 clip.getConservativeBounds(
2555 this->width(), this->height(), &clippedRect);
2556 SkRect opBounds = op.bounds();
2557 // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2558 // 0.5 pixels.
2559 if (op.hasAABloat() || op.hasZeroArea()) {
2560 opBounds.outset(0.5f, 0.5f);
2561 // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2562 // performance we may ignore the clip when the draw is entirely inside the clip is float
2563 // space but will hit pixels just outside the clip when actually rasterizing.
2564 clippedRect.outset(1, 1);
2565 clippedRect.intersect(SkIRect::MakeSize(this->asSurfaceProxy()->dimensions()));
2566 }
2567 SkIRect opIBounds;
2568 opBounds.roundOut(&opIBounds);
2569 if (!clippedRect.intersect(opIBounds)) {
2570 #ifdef SK_DEBUG
2571 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
2572 #endif
2573 return false;
2574 }
2575
2576 GrColorType colorType = this->colorInfo().colorType();
2577 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2578 // have per-sample dst values by making the copy multisampled.
2579 GrCaps::DstCopyRestrictions restrictions = this->caps()->getDstCopyRestrictions(
2580 this->asRenderTargetProxy(), colorType);
2581
2582 if (!restrictions.fMustCopyWholeSrc) {
2583 copyRect = clippedRect;
2584 }
2585
2586 SkIPoint dstOffset;
2587 SkBackingFit fit;
2588 if (restrictions.fRectsMustMatch == GrSurfaceProxy::RectsMustMatch::kYes) {
2589 dstOffset = {0, 0};
2590 fit = SkBackingFit::kExact;
2591 } else {
2592 dstOffset = {copyRect.fLeft, copyRect.fTop};
2593 fit = SkBackingFit::kApprox;
2594 }
2595 GrSurfaceProxyView newProxyView =
2596 GrSurfaceProxy::Copy(fContext, this->asSurfaceProxy(), this->origin(), colorType,
2597 GrMipMapped::kNo, copyRect, fit, SkBudgeted::kYes,
2598 restrictions.fRectsMustMatch);
2599 SkASSERT(newProxyView.proxy());
2600
2601 dstProxyView->setProxyView(std::move(newProxyView));
2602 dstProxyView->setOffset(dstOffset);
2603 return true;
2604 }
2605
blitTexture(GrSurfaceProxyView view,const SkIRect & srcRect,const SkIPoint & dstPoint)2606 bool GrRenderTargetContext::blitTexture(GrSurfaceProxyView view, const SkIRect& srcRect,
2607 const SkIPoint& dstPoint) {
2608 SkASSERT(view.asTextureProxy());
2609 SkIRect clippedSrcRect;
2610 SkIPoint clippedDstPoint;
2611 if (!GrClipSrcRectAndDstPoint(this->asSurfaceProxy()->dimensions(), view.proxy()->dimensions(),
2612 srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) {
2613 return false;
2614 }
2615
2616 GrPaint paint;
2617 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2618
2619 auto fp = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
2620 if (!fp) {
2621 return false;
2622 }
2623 paint.addColorFragmentProcessor(std::move(fp));
2624
2625 this->fillRectToRect(
2626 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
2627 SkRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(),
2628 clippedSrcRect.height()),
2629 SkRect::Make(clippedSrcRect));
2630 return true;
2631 }
2632