Flutter Engine
The Flutter Engine
SurfaceDrawContext.cpp
Go to the documentation of this file.
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
9
10#include "include/core/SkArc.h"
20#include "src/base/SkVx.h"
28#include "src/core/SkMeshPriv.h"
54#include "src/gpu/ganesh/SkGr.h"
77
78#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
79#define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(this->singleOwner())
80#define RETURN_IF_ABANDONED if (fContext->abandoned()) { return; }
81#define RETURN_FALSE_IF_ABANDONED if (fContext->abandoned()) { return false; }
82
83using namespace skia_private;
84
85//////////////////////////////////////////////////////////////////////////////
86
87namespace {
88
89void op_bounds(SkRect* bounds, const GrOp* op) {
90 *bounds = op->bounds();
91 if (op->hasZeroArea()) {
92 if (op->hasAABloat()) {
93 bounds->outset(0.5f, 0.5f);
94 } else {
95 // We don't know which way the particular GPU will snap lines or points at integer
96 // coords. So we ensure that the bounds is large enough for either snap.
97 SkRect before = *bounds;
98 bounds->roundOut(bounds);
99 if (bounds->fLeft == before.fLeft) {
100 bounds->fLeft -= 1;
101 }
102 if (bounds->fTop == before.fTop) {
103 bounds->fTop -= 1;
104 }
105 if (bounds->fRight == before.fRight) {
106 bounds->fRight += 1;
107 }
108 if (bounds->fBottom == before.fBottom) {
109 bounds->fBottom += 1;
110 }
111 }
112 }
113}
114
115} // anonymous namespace
116
117namespace skgpu::ganesh {
118
120
122public:
123 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
124 SkASSERT(fDrawingManager);
125 }
126 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
127
128private:
129 GrDrawingManager* fDrawingManager;
130};
131
132std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(GrRecordingContext* rContext,
135 sk_sp<SkColorSpace> colorSpace,
136 GrSurfaceOrigin origin,
137 const SkSurfaceProps& surfaceProps) {
138 if (!rContext || !proxy || colorType == GrColorType::kUnknown) {
139 return nullptr;
140 }
141
142 const GrBackendFormat& format = proxy->backendFormat();
144 skgpu::Swizzle writeSwizzle = rContext->priv().caps()->getWriteSwizzle(format, colorType);
145
146 GrSurfaceProxyView readView ( proxy, origin, readSwizzle);
147 GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
148
149 return std::make_unique<SurfaceDrawContext>(rContext,
150 std::move(readView),
151 std::move(writeView),
152 colorType,
153 std::move(colorSpace),
155}
156
157std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(GrRecordingContext* rContext,
158 sk_sp<SkColorSpace> colorSpace,
159 SkBackingFit fit,
160 SkISize dimensions,
161 const GrBackendFormat& format,
162 int sampleCnt,
163 skgpu::Mipmapped mipmapped,
164 GrProtected isProtected,
165 skgpu::Swizzle readSwizzle,
166 skgpu::Swizzle writeSwizzle,
167 GrSurfaceOrigin origin,
168 skgpu::Budgeted budgeted,
169 const SkSurfaceProps& surfaceProps,
170 std::string_view label) {
171 // It is probably not necessary to check if the context is abandoned here since uses of the
172 // SurfaceDrawContext which need the context will mostly likely fail later on without an
173 // issue. However having this hear adds some reassurance in case there is a path doesn't handle
174 // an abandoned context correctly. It also lets us early out of some extra work.
175 if (rContext->abandoned()) {
176 return nullptr;
177 }
178
180 format,
183 sampleCnt,
184 mipmapped,
185 fit,
186 budgeted,
187 isProtected,
188 label);
189 if (!proxy) {
190 return nullptr;
191 }
192
193 GrSurfaceProxyView readView ( proxy, origin, readSwizzle);
194 GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
195
196 auto sdc = std::make_unique<SurfaceDrawContext>(rContext,
197 std::move(readView),
198 std::move(writeView),
200 std::move(colorSpace),
202 sdc->discard();
203 return sdc;
204}
205
206std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(GrRecordingContext* rContext,
208 sk_sp<SkColorSpace> colorSpace,
209 SkBackingFit fit,
210 SkISize dimensions,
211 const SkSurfaceProps& surfaceProps,
212 std::string_view label,
213 int sampleCnt,
214 skgpu::Mipmapped mipmapped,
215 GrProtected isProtected,
216 GrSurfaceOrigin origin,
217 skgpu::Budgeted budgeted) {
218 if (!rContext) {
219 return nullptr;
220 }
221
223 if (!format.isValid()) {
224 return nullptr;
225 }
227 format,
230 sampleCnt,
231 mipmapped,
232 fit,
233 budgeted,
234 isProtected,
235 label);
236 if (!proxy) {
237 return nullptr;
238 }
239
240 return SurfaceDrawContext::Make(rContext,
241 colorType,
242 std::move(proxy),
243 std::move(colorSpace),
244 origin,
246}
247
248std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::MakeWithFallback(
249 GrRecordingContext* rContext,
251 sk_sp<SkColorSpace> colorSpace,
252 SkBackingFit fit,
253 SkISize dimensions,
254 const SkSurfaceProps& surfaceProps,
255 int sampleCnt,
256 skgpu::Mipmapped mipmapped,
257 GrProtected isProtected,
258 GrSurfaceOrigin origin,
259 skgpu::Budgeted budgeted) {
260 const GrCaps* caps = rContext->priv().caps();
261 auto [ct, _] = caps->getFallbackColorTypeAndFormat(colorType, sampleCnt);
262 if (ct == GrColorType::kUnknown) {
263 return nullptr;
264 }
265 return SurfaceDrawContext::Make(rContext, ct, colorSpace, fit, dimensions, surfaceProps,
266 /*label=*/"MakeSurfaceDrawContextWithFallback", sampleCnt,
267 mipmapped, isProtected, origin, budgeted);
268}
269
270std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::MakeFromBackendTexture(
271 GrRecordingContext* rContext,
273 sk_sp<SkColorSpace> colorSpace,
274 const GrBackendTexture& tex,
275 int sampleCnt,
276 GrSurfaceOrigin origin,
277 const SkSurfaceProps& surfaceProps,
278 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
279 SkASSERT(sampleCnt > 0);
282 std::move(releaseHelper)));
283 if (!proxy) {
284 return nullptr;
285 }
286
287 return SurfaceDrawContext::Make(rContext, colorType, std::move(proxy), std::move(colorSpace),
289}
290
291// In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
292// OpsTask to be picked up and added to by SurfaceDrawContexts lower in the call
293// stack. When this occurs with a closed OpsTask, a new one will be allocated
294// when the surfaceDrawContext attempts to use it (via getOpsTask).
296 GrSurfaceProxyView readView,
297 GrSurfaceProxyView writeView,
299 sk_sp<SkColorSpace> colorSpace,
300 const SkSurfaceProps& surfaceProps)
301 : SurfaceFillContext(rContext,
302 std::move(readView),
303 std::move(writeView),
304 {colorType, kPremul_SkAlphaType, std::move(colorSpace)})
305 , fSurfaceProps(surfaceProps)
306 , fCanUseDynamicMSAA(
307 (fSurfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag) &&
308 rContext->priv().caps()->supportsDynamicMSAA(this->asRenderTargetProxy())) {
309 SkDEBUGCODE(this->validate();)
310}
311
314}
315
316void SurfaceDrawContext::willReplaceOpsTask(OpsTask* prevTask, OpsTask* nextTask) {
317 if (prevTask && fNeedsStencil) {
318 // Store the stencil values in memory upon completion of fOpsTask.
319 prevTask->setMustPreserveStencil();
320 // Reload the stencil buffer content at the beginning of newOpsTask.
321 // FIXME: Could the topo sort insert a task between these two that modifies the stencil
322 // values?
324 }
325#if GR_GPU_STATS && defined(GR_TEST_UTILS)
326 if (fCanUseDynamicMSAA) {
327 fContext->priv().dmsaaStats().fNumRenderPasses++;
328 }
329#endif
330}
331
333 const GrClip* clip,
334 const SkMatrix& viewMatrix,
335 const sktext::GlyphRunList& glyphRunList,
336 SkStrikeDeviceInfo strikeDeviceInfo,
337 const SkPaint& paint) {
340 SkDEBUGCODE(this->validate();)
341 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawGlyphRunList", fContext);
342
343 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
344 // secondary command buffers because it would require stopping and starting a render pass which
345 // we don't have access to.
346 if (this->wrapsVkSecondaryCB()) {
347 return;
348 }
349
351
352 auto atlasDelegate = [&](const sktext::gpu::AtlasSubRun* subRun,
353 SkPoint drawOrigin,
354 const SkPaint& paint,
355 sk_sp<SkRefCnt> subRunStorage,
357 auto [drawingClip, op] = subRun->makeAtlasTextOp(
358 clip, viewMatrix, drawOrigin, paint, std::move(subRunStorage), this);
359 if (op != nullptr) {
360 this->addDrawOp(drawingClip, std::move(op));
361 }
362 };
363
364 textBlobCache->drawGlyphRunList(
365 canvas, viewMatrix, glyphRunList, paint, strikeDeviceInfo, atlasDelegate);
366}
367
369 GrPaint&& paint,
370 const SkMatrix& viewMatrix) {
371 // Start with the render target, since that is the maximum content we could possibly fill.
372 // drawFilledQuad() will automatically restrict it to clip bounds for us if possible.
373 if (!paint.numTotalFragmentProcessors()) {
374 // The paint is trivial so we won't need to use local coordinates, so skip calculating the
375 // inverse view matrix.
376 SkRect r = this->asSurfaceProxy()->getBoundsRect();
377 this->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r, r);
378 } else {
379 // Use the inverse view matrix to arrive at appropriate local coordinates for the paint.
380 SkMatrix localMatrix;
381 if (!viewMatrix.invert(&localMatrix)) {
382 return;
383 }
385 this->fillPixelsWithLocalMatrix(clip, std::move(paint), bounds, localMatrix);
386 }
387}
388
390 // The rect to draw doesn't intersect clip or render target, so no draw op should be added
391 kDiscarded,
392 // The rect to draw was converted to some other op and appended to the oplist, so no additional
393 // op is necessary. Currently this can convert it to a clear op or a rrect op. Only valid if
394 // a constColor is provided.
395 kSubmitted,
396 // The clip was folded into the device quad, with updated edge flags and local coords, and
397 // caller is responsible for adding an appropriate op.
398 kClipApplied,
399 // No change to clip, but quad updated to better fit clip/render target, and caller is
400 // responsible for adding an appropriate op.
401 kCropped
402};
403
404SurfaceDrawContext::QuadOptimization SurfaceDrawContext::attemptQuadOptimization(
405 const GrClip* clip,
406 const GrUserStencilSettings* stencilSettings,
407 DrawQuad* quad,
408 GrPaint* paint) {
409 // Optimization requirements:
410 // 1. kDiscard applies when clip bounds and quad bounds do not intersect
411 // 2a. kSubmitted applies when constColor and final geom is pixel aligned rect;
412 // pixel aligned rect requires rect clip and (rect quad or quad covers clip) OR
413 // 2b. kSubmitted applies when constColor and rrect clip and quad covers clip
414 // 4. kClipApplied applies when rect clip and (rect quad or quad covers clip)
415 // 5. kCropped in all other scenarios (although a crop may be a no-op)
416 const SkPMColor4f* constColor = nullptr;
417 SkPMColor4f paintColor;
418 if (!stencilSettings && paint && !paint->hasCoverageFragmentProcessor() &&
419 paint->isConstantBlendedColor(&paintColor)) {
420 // Only consider clears/rrects when it's easy to guarantee 100% fill with single color
421 constColor = &paintColor;
422 }
423
424 // Save the old AA flags since CropToRect will modify 'quad' and if kCropped is returned, it's
425 // better to just keep the old flags instead of introducing mixed edge flags.
426 GrQuadAAFlags oldFlags = quad->fEdgeFlags;
427
428 // Use the logical size of the render target, which allows for "fullscreen" clears even if
429 // the render target has an approximate backing fit
430 SkRect rtRect = this->asSurfaceProxy()->getBoundsRect();
431
432 // For historical reasons, we assume AA for exact bounds checking in IsOutsideClip.
433 // TODO(michaelludwig) - Hopefully that can be revisited when the clipping optimizations are
434 // refactored to work better with round rects and dmsaa.
435 SkRect drawBounds = quad->fDevice.bounds();
436 if (!quad->fDevice.isFinite() || drawBounds.isEmpty() ||
437 GrClip::IsOutsideClip(SkIRect::MakeSize(this->dimensions()), drawBounds, GrAA::kYes)) {
440 // Don't try to apply the clip early if we know rendering will use hairline methods, as this
441 // has an effect on the op bounds not otherwise taken into account in this function.
443 }
444
445 GrAA drawUsesAA{quad->fEdgeFlags != GrQuadAAFlags::kNone};
446 auto conservativeCrop = [&]() {
447 static constexpr int kLargeDrawLimit = 15000;
448 // Crop the quad to the render target. This doesn't change the visual results of drawing but
449 // is meant to help numerical stability for excessively large draws.
450 if (drawBounds.width() > kLargeDrawLimit || drawBounds.height() > kLargeDrawLimit) {
451 GrQuadUtils::CropToRect(rtRect, drawUsesAA, quad, /* compute local */ !constColor);
452 }
453 };
454
455 bool simpleColor = !stencilSettings && constColor;
456 GrClip::PreClipResult result = clip ? clip->preApply(drawBounds, drawUsesAA)
458 switch(result.fEffect) {
462 if (!simpleColor) {
463 conservativeCrop();
465 } else {
466 // Update result to store the render target bounds in order and then fall
467 // through to attempt the draw->native clear optimization. Pick an AA value such
468 // that any geometric clipping doesn't need to change aa or edge flags (since we
469 // know this is on pixel boundaries, it will draw the same regardless).
470 // See skbug.com/13114 for more details.
471 result = GrClip::PreClipResult(SkRRect::MakeRect(rtRect), drawUsesAA);
472 }
473 break;
475 if (!result.fIsRRect || (stencilSettings && result.fAA != drawUsesAA) ||
476 (!result.fRRect.isRect() && !simpleColor)) {
477 // The clip and draw state are too complicated to try and reduce
478 conservativeCrop();
480 } // Else fall through to attempt to combine the draw and clip geometry together
481 break;
482 default:
484 }
485
486 // If we reached here, we know we're an axis-aligned clip that is either a rect or a round rect,
487 // so we can potentially combine it with the draw geometry so that no clipping is needed.
488 SkASSERT(result.fEffect == GrClip::Effect::kClipped && result.fIsRRect);
489 SkRect clippedBounds = result.fRRect.getBounds();
490 clippedBounds.intersect(rtRect);
491 if (!drawBounds.intersect(clippedBounds)) {
492 // Our fractional bounds aren't actually inside the clip. GrClip::preApply() can sometimes
493 // think in terms of rounded-out bounds. Discard the draw.
495 }
496 // Guard against the clipped draw turning into a hairline draw after intersection
497 if (drawBounds.width() < 1.f || drawBounds.height() < 1.f) {
499 }
500
501 if (result.fRRect.isRect()) {
502 // No rounded corners, so we might be able to become a native clear or we might be able to
503 // modify geometry and edge flags to represent intersected shape of clip and draw.
504 if (GrQuadUtils::CropToRect(clippedBounds, result.fAA, quad,
505 /*compute local*/ !constColor)) {
506 if (simpleColor && quad->fDevice.quadType() == GrQuad::Type::kAxisAligned) {
507 // Clear optimization is possible
508 drawBounds = quad->fDevice.bounds();
509 if (drawBounds.contains(rtRect)) {
510 // Fullscreen clear
511 this->clear(*constColor);
513 } else if (GrClip::IsPixelAligned(drawBounds) &&
514 drawBounds.width() > 256 && drawBounds.height() > 256) {
515 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
516 SkIRect scissorRect;
517 drawBounds.round(&scissorRect);
518 this->clear(scissorRect, *constColor);
520 }
521 }
522
524 }
525 } else {
526 // Rounded corners and constant filled color (limit ourselves to solid colors because
527 // there is no way to use custom local coordinates with drawRRect).
528 SkASSERT(simpleColor);
529 if (GrQuadUtils::CropToRect(clippedBounds, result.fAA, quad,
530 /* compute local */ false) &&
532 quad->fDevice.bounds().contains(clippedBounds)) {
533 // Since the cropped quad became a rectangle which covered the bounds of the rrect,
534 // we can draw the rrect directly and ignore the edge flags
535 this->drawRRect(nullptr, std::move(*paint), result.fAA, SkMatrix::I(), result.fRRect,
538 }
539 }
540
541 // The quads have been updated to better fit the clip bounds, but can't get rid of
542 // the clip entirely
543 quad->fEdgeFlags = oldFlags;
545}
546
547void SurfaceDrawContext::drawFilledQuad(const GrClip* clip,
548 GrPaint&& paint,
549 DrawQuad* quad,
550 const GrUserStencilSettings* ss) {
553 SkDEBUGCODE(this->validate();)
554 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFilledQuad", fContext);
555
556 AutoCheckFlush acf(this->drawingManager());
557
558 QuadOptimization opt = this->attemptQuadOptimization(clip, ss, quad, &paint);
560 // These optimizations require caller to add an op themselves
561 const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
562 // The quad being drawn requires AA if any of its edges requires AA
564 GrAAType aaType;
565 if (ss) {
566 aaType = (aa == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
567 } else if (fCanUseDynamicMSAA && aa == GrAA::kNo) {
568 // The SkGpuDevice ensures GrAA is always kYes when using dmsaa. If the caller calls
569 // into here with GrAA::kNo, trust that they know what they're doing and that the
570 // rendering will be equal with or without msaa.
571 aaType = GrAAType::kNone;
572 } else {
573 aaType = this->chooseAAType(aa);
574 }
575 this->addDrawOp(finalClip, FillRectOp::Make(fContext, std::move(paint), aaType,
576 quad, ss));
577 }
578 // All other optimization levels were completely handled inside attempt(), so no extra op needed
579}
580
583 SkAlphaType srcAlphaType,
586 SkBlendMode blendMode,
587 const SkPMColor4f& color,
588 const SkRect& srcRect,
589 const SkRect& dstRect,
590 GrQuadAAFlags edgeAA,
592 const SkMatrix& viewMatrix,
593 sk_sp<GrColorSpaceXform> colorSpaceXform) {
594 // If we are using dmsaa then go through FillRRectOp (via fillRectToRect).
595 if ((this->alwaysAntialias() || this->caps()->reducedShaderMode()) &&
596 edgeAA != GrQuadAAFlags::kNone) {
597 auto [mustFilter, mustMM] = FilterAndMipmapHaveNoEffect(
598 GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect));
599 if (!mustFilter) {
600 // Chromeos-jacuzzi devices (ARM Mali-G72 MP3) have issues with blitting with linear
601 // filtering. Likely some optimization or quantization causes fragments to be produced
602 // with small offset/error. This will result in a slight blending of pixels when
603 // sampling. Normally in most application this would be completely unnoticeable but when
604 // trying to use the gpu as a per pixel blit we will end up with slightly blurry
605 // results.
606 // See https://crbug.com/326980863
608 }
609
611 paint.setColor4f(color);
612 std::unique_ptr<GrFragmentProcessor> fp;
613 if (constraint == SkCanvas::kStrict_SrcRectConstraint) {
614 fp = GrTextureEffect::MakeSubset(view, srcAlphaType, SkMatrix::I(),
615 GrSamplerState(filter, mm), srcRect,
616 *this->caps());
617 } else {
618 fp = GrTextureEffect::Make(view, srcAlphaType, SkMatrix::I(), filter, mm);
619 }
620 if (colorSpaceXform) {
621 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(colorSpaceXform));
622 }
623 fp = GrBlendFragmentProcessor::Make<SkBlendMode::kModulate>(std::move(fp), nullptr);
624 paint.setColorFragmentProcessor(std::move(fp));
625 if (blendMode != SkBlendMode::kSrcOver) {
626 paint.setXPFactory(GrXPFactory::FromBlendMode(blendMode));
627 }
628 this->fillRectToRect(clip, std::move(paint), GrAA::kYes, viewMatrix, dstRect, srcRect);
629 return;
630 }
631
632 const SkRect* subset = constraint == SkCanvas::kStrict_SrcRectConstraint ?
633 &srcRect : nullptr;
634 DrawQuad quad{GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), edgeAA};
635
636 this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(colorSpaceXform), filter,
637 mm, color, blendMode, &quad, subset);
638}
639
640void SurfaceDrawContext::drawTexturedQuad(const GrClip* clip,
641 GrSurfaceProxyView proxyView,
642 SkAlphaType srcAlphaType,
643 sk_sp<GrColorSpaceXform> textureXform,
646 const SkPMColor4f& color,
647 SkBlendMode blendMode,
648 DrawQuad* quad,
649 const SkRect* subset) {
652 SkDEBUGCODE(this->validate();)
653 SkASSERT(proxyView.asTextureProxy());
654 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawTexturedQuad", fContext);
655
656 AutoCheckFlush acf(this->drawingManager());
657
658 // Functionally this is very similar to drawFilledQuad except that there's no constColor to
659 // enable the kSubmitted optimizations, no stencil settings support, and its a TextureOp.
660 QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr/*stencil*/, quad,
661 nullptr/*paint*/);
662
664 if (opt != QuadOptimization::kDiscarded) {
665 // Add the texture op if not discarded
666 const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
667 GrAAType aaType = this->chooseAAType(GrAA{quad->fEdgeFlags != GrQuadAAFlags::kNone});
668 auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
669 auto saturate = clampType == GrClampType::kManual ? ganesh::TextureOp::Saturate::kYes
671 // Use the provided subset, although hypothetically we could detect that the cropped local
672 // quad is sufficiently inside the subset and the constraint could be dropped.
673 this->addDrawOp(finalClip,
674 ganesh::TextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
675 std::move(textureXform), filter, mm, color,
676 saturate, blendMode, aaType, quad, subset));
677 }
678}
679
681 GrPaint&& paint,
682 GrAA aa,
683 const SkMatrix& viewMatrix,
684 const SkRect& rect,
685 const GrStyle* style) {
686 if (!style) {
687 style = &GrStyle::SimpleFill();
688 }
691 SkDEBUGCODE(this->validate();)
692 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRect", fContext);
693
694 // Path effects should've been devolved to a path in SkGpuDevice
695 SkASSERT(!style->pathEffect());
696
697 AutoCheckFlush acf(this->drawingManager());
698
699 const SkStrokeRec& stroke = style->strokeRec();
700 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
701 // Fills the rect, using rect as its own local coordinates
702 this->fillRectToRect(clip, std::move(paint), aa, viewMatrix, rect, rect);
703 return;
704 } else if ((stroke.getStyle() == SkStrokeRec::kStroke_Style ||
705 stroke.getStyle() == SkStrokeRec::kHairline_Style) &&
706 rect.width() &&
707 rect.height() &&
708 !this->caps()->reducedShaderMode()) {
709 // Only use the StrokeRectOp for non-empty rectangles. Empty rectangles will be processed by
710 // GrStyledShape to handle stroke caps and dashing properly.
711 //
712 // http://skbug.com/12206 -- there is a double-blend issue with the bevel version of
713 // AAStrokeRectOp, and if we increase the AA bloat for MSAA it becomes more pronounced.
714 // Don't use the bevel version with DMSAA.
715 GrAAType aaType = (fCanUseDynamicMSAA &&
716 stroke.getJoin() == SkPaint::kMiter_Join &&
718 : this->chooseAAType(aa);
719 GrOp::Owner op = ganesh::StrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix,
720 rect, stroke);
721 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
722 // does not preserve rectangles.
723 if (op) {
724 this->addDrawOp(clip, std::move(op));
725 return;
726 }
727 }
728 assert_alive(paint);
729 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
731}
732
734 GrPaint&& paint,
735 GrAA aa,
736 const SkMatrix& viewMatrix,
737 const SkRect& rectToDraw,
738 const SkRect& localRect) {
739 DrawQuad quad{GrQuad::MakeFromRect(rectToDraw, viewMatrix), GrQuad(localRect),
741
742 // If we are using dmsaa then attempt to draw the rect with FillRRectOp.
743 if ((fContext->priv().caps()->reducedShaderMode() || this->alwaysAntialias()) &&
744 this->caps()->drawInstancedSupport() &&
745 aa == GrAA::kYes) { // If aa is kNo when using dmsaa, the rect is axis aligned. Don't use
746 // FillRRectOp because it might require dual source blending.
747 // http://skbug.com/11756
748 QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr/*stencil*/, &quad,
749 &paint);
751 // The optimization was completely handled inside attempt().
752 return;
753 }
754
755 SkRect croppedRect, croppedLocal{};
756 const GrClip* optimizedClip = clip;
757 if (clip && viewMatrix.isScaleTranslate() && quad.fDevice.asRect(&croppedRect) &&
758 (!paint.usesLocalCoords() || quad.fLocal.asRect(&croppedLocal))) {
759 // The cropped quad is still a rect, and our view matrix preserves rects. Map it back
760 // to pre-matrix space.
761 SkMatrix inverse;
762 if (!viewMatrix.invert(&inverse)) {
763 return;
764 }
765 SkASSERT(inverse.rectStaysRect());
766 inverse.mapRect(&croppedRect);
768 optimizedClip = nullptr;
769 }
770 } else {
771 // Even if attemptQuadOptimization gave us an optimized quad, FillRRectOp needs a rect
772 // in pre-matrix space, so use the original rect. Also preserve the original clip.
773 croppedRect = rectToDraw;
774 croppedLocal = localRect;
775 }
776
777 if (auto op = FillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint),
778 viewMatrix, SkRRect::MakeRect(croppedRect), croppedLocal,
779 GrAA::kYes)) {
780 this->addDrawOp(optimizedClip, std::move(op));
781 return;
782 }
783 }
784
785 assert_alive(paint);
786 this->drawFilledQuad(clip, std::move(paint), &quad);
787}
788
790 GrPaint&& paint,
791 const SkMatrix& viewMatrix,
792 const GrQuadSetEntry quads[],
793 int cnt) {
794 GrAAType aaType = this->chooseAAType(GrAA::kYes);
795
796 FillRectOp::AddFillRectOps(this, clip, fContext, std::move(paint), aaType, viewMatrix,
797 quads, cnt);
798}
799
801 return this->asRenderTargetProxy()->maxWindowRectangles(*this->caps());
802}
803
804OpsTask::CanDiscardPreviousOps SurfaceDrawContext::canDiscardPreviousOpsOnFullClear() const {
805#if defined(GR_TEST_UTILS)
806 if (fPreserveOpsOnFullClear_TestingOnly) {
808 }
809#endif
810 // Regardless of how the clear is implemented (native clear or a fullscreen quad), all prior ops
811 // would normally be overwritten. The one exception is if the render target context is marked as
812 // needing a stencil buffer then there may be a prior op that writes to the stencil buffer.
813 // Although the clear will ignore the stencil buffer, following draw ops may not so we can't get
814 // rid of all the preceding ops. Beware! If we ever add any ops that have a side effect beyond
815 // modifying the stencil buffer we will need a more elaborate tracking system (skbug.com/7002).
816 return OpsTask::CanDiscardPreviousOps(!fNeedsStencil);
817}
818
819void SurfaceDrawContext::setNeedsStencil() {
820 // Don't clear stencil until after we've set fNeedsStencil. This ensures we don't loop forever
821 // in the event that there are driver bugs and we need to clear as a draw.
822 bool hasInitializedStencil = fNeedsStencil;
823 fNeedsStencil = true;
824 if (!hasInitializedStencil) {
826 if (this->caps()->performStencilClearsAsDraws()) {
827 // There is a driver bug with clearing stencil. We must use an op to manually clear the
828 // stencil buffer before the op that required 'setNeedsStencil'.
829 this->internalStencilClear(nullptr, /* inside mask */ false);
830 } else {
833 }
834 }
835}
836
837void SurfaceDrawContext::internalStencilClear(const SkIRect* scissor, bool insideStencilMask) {
838 this->setNeedsStencil();
839
840 GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
841 if (scissor && !scissorState.set(*scissor)) {
842 // The requested clear region is off screen, so nothing to do.
843 return;
844 }
845
846 bool clearWithDraw = this->caps()->performStencilClearsAsDraws() ||
847 (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
848 if (clearWithDraw) {
850
851 // Configure the paint to have no impact on the color buffer
853 paint.setXPFactory(GrDisableColorXPFactory::Get());
854 this->addDrawOp(nullptr,
856 SkRect::Make(scissorState.rect()), ss));
857 } else {
858 this->addOp(ClearOp::MakeStencilClip(fContext, scissorState, insideStencilMask));
859 }
860}
861
863 GrAA doStencilMSAA,
864 const SkMatrix& viewMatrix,
865 const SkPath& path) {
866 SkIRect clipBounds = clip ? clip->getConservativeBounds()
867 : SkIRect::MakeSize(this->dimensions());
869
871 canDrawArgs.fCaps = fContext->priv().caps();
872 canDrawArgs.fProxy = this->asRenderTargetProxy();
873 canDrawArgs.fClipConservativeBounds = &clipBounds;
874 canDrawArgs.fViewMatrix = &viewMatrix;
875 canDrawArgs.fShape = &shape;
876 canDrawArgs.fPaint = nullptr;
877 canDrawArgs.fSurfaceProps = &fSurfaceProps;
878 canDrawArgs.fAAType = (doStencilMSAA == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
879 canDrawArgs.fHasUserStencilSettings = false;
880 auto pr = this->drawingManager()->getPathRenderer(canDrawArgs,
881 false,
883 if (!pr) {
884 SkDebugf("WARNING: No path renderer to stencil path.\n");
885 return false;
886 }
887
889 args.fContext = fContext;
890 args.fSurfaceDrawContext = this;
891 args.fClip = clip;
892 args.fClipConservativeBounds = &clipBounds;
893 args.fViewMatrix = &viewMatrix;
894 args.fShape = &shape;
895 args.fDoStencilMSAA = doStencilMSAA;
896 pr->stencilPath(args);
897 return true;
898}
899
902 int cnt,
903 int proxyRunCnt,
908 const SkMatrix& viewMatrix,
909 sk_sp<GrColorSpaceXform> texXform) {
912 SkDEBUGCODE(this->validate();)
913 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawTextureSet", fContext);
914
915 // Create the minimum number of GrTextureOps needed to draw this set. Individual
916 // GrTextureOps can rebind the texture between draws thus avoiding GrPaint (re)creation.
917 AutoCheckFlush acf(this->drawingManager());
918 GrAAType aaType = this->chooseAAType(GrAA::kYes);
919 auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
920 auto saturate = clampType == GrClampType::kManual ? ganesh::TextureOp::Saturate::kYes
922 ganesh::TextureOp::AddTextureSetOps(this, clip, fContext, set, cnt, proxyRunCnt, filter, mm,
923 saturate, mode, aaType, constraint, viewMatrix,
924 std::move(texXform));
925}
926
928 GrPaint&& paint,
929 const SkMatrix& viewMatrix,
930 sk_sp<SkVertices> vertices,
931 GrPrimitiveType* overridePrimType,
932 bool skipColorXform) {
935 SkDEBUGCODE(this->validate();)
936 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawVertices", fContext);
937
938 AutoCheckFlush acf(this->drawingManager());
939
940 SkASSERT(vertices);
941 auto xform = skipColorXform ? nullptr : this->colorInfo().refColorSpaceXformFromSRGB();
942 GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(GrAA::kNo);
944 std::move(paint),
945 std::move(vertices),
946 overridePrimType,
947 viewMatrix,
948 aaType,
949 std::move(xform));
950 this->addDrawOp(clip, std::move(op));
951}
952
954 GrPaint&& paint,
955 const SkMatrix& viewMatrix,
956 const SkMesh& mesh,
957 TArray<std::unique_ptr<GrFragmentProcessor>> children) {
960 SkDEBUGCODE(this->validate();)
961 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawMesh", fContext);
962
963 AutoCheckFlush acf(this->drawingManager());
964
965 SkASSERT(mesh.isValid());
966
969 this->colorInfo().colorSpace(),
970 this->colorInfo().alphaType());
971 GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(GrAA::kNo);
973 std::move(paint),
974 mesh,
975 std::move(children),
976 viewMatrix,
977 aaType,
978 std::move(xform));
979 this->addDrawOp(clip, std::move(op));
980}
981
982///////////////////////////////////////////////////////////////////////////////
983
985 GrPaint&& paint,
986 const SkMatrix& viewMatrix,
987 int spriteCount,
988 const SkRSXform xform[],
989 const SkRect texRect[],
990 const SkColor colors[]) {
993 SkDEBUGCODE(this->validate();)
994 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawAtlas", fContext);
995
996 AutoCheckFlush acf(this->drawingManager());
997
998 GrAAType aaType = this->chooseAAType(GrAA::kNo);
999 GrOp::Owner op = DrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1000 aaType, spriteCount, xform, texRect, colors);
1001 this->addDrawOp(clip, std::move(op));
1002}
1003
1004///////////////////////////////////////////////////////////////////////////////
1005
1007 GrPaint&& paint,
1008 GrAA aa,
1009 const SkMatrix& viewMatrix,
1010 const SkRRect& rrect,
1011 const GrStyle& style) {
1014 SkDEBUGCODE(this->validate();)
1015 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRRect", fContext);
1016
1017 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1018
1019 const SkStrokeRec& stroke = style.strokeRec();
1020 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
1021 return;
1022 }
1023
1024 const GrClip* clip = origClip;
1025 // It is not uncommon to clip to a round rect and then draw that same round rect. Since our
1026 // lower level clip code works from op bounds, which are SkRects, it doesn't detect that the
1027 // clip can be ignored. The following test attempts to mitigate the stencil clip cost but only
1028 // works for axis-aligned round rects. This also only works for filled rrects since the stroke
1029 // width outsets beyond the rrect itself.
1030 // TODO: skbug.com/10462 - There was mixed performance wins and regressions when this
1031 // optimization was turned on outside of Android Framework. I (michaelludwig) believe this is
1032 // do to the overhead in determining if an SkClipStack is just a rrect. Once that is improved,
1033 // re-enable this and see if we avoid the regressions.
1034#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1035 SkRRect devRRect;
1036 if (clip && stroke.getStyle() == SkStrokeRec::kFill_Style &&
1037 rrect.transform(viewMatrix, &devRRect)) {
1038 GrClip::PreClipResult result = clip->preApply(devRRect.getBounds(), aa);
1039 switch(result.fEffect) {
1041 return;
1043 clip = nullptr;
1044 break;
1046 // Currently there's no general-purpose rrect-to-rrect contains function, and if we
1047 // got here, we know the devRRect's bounds aren't fully contained by the clip.
1048 // Testing for equality between the two is a reasonable stop-gap for now.
1049 if (result.fIsRRect && result.fRRect == devRRect) {
1050 // NOTE: On the android framework, we allow this optimization even when the clip
1051 // is non-AA and the draw is AA.
1052 if (result.fAA == aa || (result.fAA == GrAA::kNo && aa == GrAA::kYes)) {
1053 clip = nullptr;
1054 }
1055 }
1056 break;
1057 default:
1059 }
1060 }
1061#endif
1062
1063 AutoCheckFlush acf(this->drawingManager());
1064
1065 GrAAType aaType = this->chooseAAType(aa);
1066
1067 GrOp::Owner op;
1068#ifndef SK_ENABLE_OPTIMIZE_SIZE
1069 if (aaType == GrAAType::kCoverage &&
1070 !fCanUseDynamicMSAA &&
1071 !this->caps()->reducedShaderMode() &&
1072 rrect.isSimple() &&
1074 viewMatrix.rectStaysRect() && viewMatrix.isSimilarity()) {
1075 // In specific cases we use a dedicated circular round rect op to try and get better perf.
1076 assert_alive(paint);
1077 op = GrOvalOpFactory::MakeCircularRRectOp(fContext, std::move(paint), viewMatrix, rrect,
1078 stroke, this->caps()->shaderCaps());
1079 }
1080#endif
1081 if (!op && style.isSimpleFill()) {
1082 assert_alive(paint);
1083 op = FillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix, rrect,
1084 rrect.rect(), GrAA(aaType != GrAAType::kNone));
1085 }
1086#ifndef SK_ENABLE_OPTIMIZE_SIZE
1087 if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1088 assert_alive(paint);
1090 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1091 }
1092#endif
1093 if (op) {
1094 this->addDrawOp(clip, std::move(op));
1095 return;
1096 }
1097
1098 assert_alive(paint);
1099 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1101}
1102
1103///////////////////////////////////////////////////////////////////////////////
1104
1106 const SkMatrix& viewMatrix,
1107 const SkPath& path,
1108 const SkDrawShadowRec& rec) {
1110 if (fContext->abandoned()) {
1111 return true;
1112 }
1113 SkDEBUGCODE(this->validate();)
1114 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFastShadow", fContext);
1115
1116 // check z plane
1117 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1119 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1120 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1121 return false;
1122 }
1123
1124 SkRRect rrect;
1125 SkRect rect;
1126 // we can only handle rects, circles, and simple rrects with circular corners
1127 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsNearlySimpleCircular(rrect) &&
1129 if (!isRRect &&
1130 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1131 rect.width() > SK_ScalarNearlyZero) {
1133 isRRect = true;
1134 }
1135 if (!isRRect && path.isRect(&rect)) {
1137 isRRect = true;
1138 }
1139
1140 if (!isRRect) {
1141 return false;
1142 }
1143
1144 if (rrect.isEmpty()) {
1145 return true;
1146 }
1147
1148 AutoCheckFlush acf(this->drawingManager());
1149
1150 SkPoint3 devLightPos = rec.fLightPos;
1151 bool directional = SkToBool(rec.fFlags & kDirectionalLight_ShadowFlag);
1152 if (!directional) {
1153 // transform light
1154 viewMatrix.mapPoints((SkPoint*)&devLightPos.fX, 1);
1155 }
1156
1157 // 1/scale
1158 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1160 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1161 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1162
1163 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1165
1166 if (SkColorGetA(rec.fAmbientColor) > 0) {
1167 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1168 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1169 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1170
1171 // Outset the shadow rrect to the border of the penumbra
1172 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1173 SkRRect ambientRRect;
1174 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1175 // If the rrect was an oval then its outset will also be one.
1176 // We set it explicitly to avoid errors.
1177 if (rrect.isOval()) {
1178 ambientRRect = SkRRect::MakeOval(outsetRect);
1179 } else {
1180 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
1181 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1182 }
1183
1184 // The ShadowRRectOp still uses 8888 colors, so it might get clamped if the shadow color
1185 // does not fit in bytes after being transformed to the destination color space. This can
1186 // happen if the destination color space is smaller than sRGB, which is highly unlikely.
1188 if (transparent) {
1189 // set a large inset to force a fill
1190 devSpaceInsetWidth = ambientRRect.width();
1191 }
1192
1194 ambientColor,
1195 viewMatrix,
1196 ambientRRect,
1197 devSpaceAmbientBlur,
1198 devSpaceInsetWidth);
1199 if (op) {
1200 this->addDrawOp(clip, std::move(op));
1201 }
1202 }
1203
1204 if (SkColorGetA(rec.fSpotColor) > 0) {
1205 SkScalar devSpaceSpotBlur;
1206 SkScalar spotScale;
1207 SkVector spotOffset;
1208 if (directional) {
1209 SkDrawShadowMetrics::GetDirectionalParams(occluderHeight, devLightPos.fX,
1210 devLightPos.fY, devLightPos.fZ,
1211 rec.fLightRadius, &devSpaceSpotBlur,
1212 &spotScale, &spotOffset);
1213 } else {
1214 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1215 devLightPos.fZ, rec.fLightRadius,
1216 &devSpaceSpotBlur, &spotScale, &spotOffset);
1217 }
1218 // handle scale of radius due to CTM
1219 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1220
1221 // Adjust translate for the effect of the scale.
1222 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1223 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1224 // This offset is in dev space, need to transform it into source space.
1225 SkMatrix ctmInverse;
1226 if (viewMatrix.invert(&ctmInverse)) {
1227 ctmInverse.mapPoints(&spotOffset, 1);
1228 } else {
1229 // Since the matrix is a similarity, this should never happen, but just in case...
1230 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1231 SkASSERT(false);
1232 }
1233
1234 // Compute the transformed shadow rrect
1235 SkRRect spotShadowRRect;
1236 SkMatrix shadowTransform;
1237 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1238 rrect.transform(shadowTransform, &spotShadowRRect);
1239 SkScalar spotRadius = spotShadowRRect.getSimpleRadii().fX;
1240
1241 // Compute the insetWidth
1242 SkScalar blurOutset = srcSpaceSpotBlur;
1243 SkScalar insetWidth = blurOutset;
1244 if (transparent) {
1245 // If transparent, just do a fill
1246 insetWidth += spotShadowRRect.width();
1247 } else {
1248 // For shadows, instead of using a stroke we specify an inset from the penumbra
1249 // border. We want to extend this inset area so that it meets up with the caster
1250 // geometry. The inset geometry will by default already be inset by the blur width.
1251 //
1252 // We compare the min and max corners inset by the radius between the original
1253 // rrect and the shadow rrect. The distance between the two plus the difference
1254 // between the scaled radius and the original radius gives the distance from the
1255 // transformed shadow shape to the original shape in that corner. The max
1256 // of these gives the maximum distance we need to cover.
1257 //
1258 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1259 // that to get the full insetWidth.
1260 SkScalar maxOffset;
1261 if (rrect.isRect()) {
1262 // Manhattan distance works better for rects
1263 maxOffset = std::max(std::max(SkTAbs(spotShadowRRect.rect().fLeft -
1264 rrect.rect().fLeft),
1265 SkTAbs(spotShadowRRect.rect().fTop -
1266 rrect.rect().fTop)),
1267 std::max(SkTAbs(spotShadowRRect.rect().fRight -
1268 rrect.rect().fRight),
1269 SkTAbs(spotShadowRRect.rect().fBottom -
1270 rrect.rect().fBottom)));
1271 } else {
1273 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1274 rrect.rect().fLeft + dr,
1275 spotShadowRRect.rect().fTop -
1276 rrect.rect().fTop + dr);
1277 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1278 rrect.rect().fRight - dr,
1279 spotShadowRRect.rect().fBottom -
1280 rrect.rect().fBottom - dr);
1281 maxOffset = SkScalarSqrt(std::max(SkPointPriv::LengthSqd(upperLeftOffset),
1282 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1283 }
1284 insetWidth += std::max(blurOutset, maxOffset);
1285 }
1286
1287 // Outset the shadow rrect to the border of the penumbra
1288 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1289 if (spotShadowRRect.isOval()) {
1290 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1291 } else {
1292 SkScalar outsetRad = spotRadius + blurOutset;
1293 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1294 }
1295
1296 // The ShadowRRectOp still uses 8888 colors, so it might get clamped if the shadow color
1297 // does not fit in bytes after being transformed to the destination color space. This can
1298 // happen if the destination color space is smaller than sRGB, which is highly unlikely.
1301 spotColor,
1302 viewMatrix,
1303 spotShadowRRect,
1304 2.0f * devSpaceSpotBlur,
1305 insetWidth);
1306 if (op) {
1307 this->addDrawOp(clip, std::move(op));
1308 }
1309 }
1310
1311 return true;
1312}
1313
1314///////////////////////////////////////////////////////////////////////////////
1315
1317 GrPaint&& paint,
1318 GrAA aa,
1319 const SkMatrix& viewMatrix,
1320 const SkRegion& region,
1321 const GrStyle& style,
1322 const GrUserStencilSettings* ss) {
1325 SkDEBUGCODE(this->validate();)
1326 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRegion", fContext);
1327
1328 if (GrAA::kYes == aa) {
1329 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1330 // to see whether aa is really required.
1331 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1332 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1333 SkScalarIsInt(viewMatrix.getTranslateY())) {
1334 aa = GrAA::kNo;
1335 }
1336 }
1337 bool complexStyle = !style.isSimpleFill();
1338 if (complexStyle || GrAA::kYes == aa) {
1339 SkPath path;
1341 path.setIsVolatile(true);
1342
1343 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1344 }
1345
1346 GrAAType aaType = (this->numSamples() > 1) ? GrAAType::kMSAA : GrAAType::kNone;
1347 GrOp::Owner op = RegionOp::Make(fContext, std::move(paint), viewMatrix, region, aaType, ss);
1348 this->addDrawOp(clip, std::move(op));
1349}
1350
1352 GrPaint&& paint,
1353 GrAA aa,
1354 const SkMatrix& viewMatrix,
1355 const SkRect& oval,
1356 const GrStyle& style) {
1359 SkDEBUGCODE(this->validate();)
1360 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawOval", fContext);
1361
1362 const SkStrokeRec& stroke = style.strokeRec();
1363
1364 if (oval.isEmpty() && !style.pathEffect()) {
1365 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1366 return;
1367 }
1368
1369 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1370 return;
1371 }
1372
1373 AutoCheckFlush acf(this->drawingManager());
1374
1375 GrAAType aaType = this->chooseAAType(aa);
1376
1377 GrOp::Owner op;
1378#ifndef SK_ENABLE_OPTIMIZE_SIZE
1379 if (aaType == GrAAType::kCoverage &&
1380 !fCanUseDynamicMSAA &&
1381 !this->caps()->reducedShaderMode() &&
1383 oval.width() == oval.height() &&
1384 viewMatrix.isSimilarity()) {
1385 // In specific cases we use a dedicated circle op to try and get better perf.
1386 assert_alive(paint);
1387 op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1388 this->caps()->shaderCaps());
1389 }
1390#endif
1391 if (!op && style.isSimpleFill()) {
1392 // FillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1393 // the arc equation. This same special geometry and fragment branch also turn out to be a
1394 // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1395 // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1396 // ovals the exact same way we do round rects.
1397 assert_alive(paint);
1398 op = FillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix,
1400 }
1401#ifndef SK_ENABLE_OPTIMIZE_SIZE
1402 if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1403 assert_alive(paint);
1404 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1405 this->caps()->shaderCaps());
1406 }
1407#endif
1408 if (op) {
1409 this->addDrawOp(clip, std::move(op));
1410 return;
1411 }
1412
1413 assert_alive(paint);
1414 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1416 false, style, DoSimplify::kNo));
1417}
1418
1420 GrPaint&& paint,
1421 GrAA aa,
1422 const SkMatrix& viewMatrix,
1423 const SkArc& arc,
1424 const GrStyle& style) {
1427 SkDEBUGCODE(this->validate();)
1428 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawArc", fContext);
1429
1430 AutoCheckFlush acf(this->drawingManager());
1431
1432#ifndef SK_ENABLE_OPTIMIZE_SIZE
1433 GrAAType aaType = this->chooseAAType(aa);
1434 if (aaType == GrAAType::kCoverage) {
1435 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1437 std::move(paint),
1438 viewMatrix,
1439 arc.fOval,
1440 arc.fStartAngle,
1441 arc.fSweepAngle,
1442 arc.isWedge(),
1443 style,
1444 shaderCaps);
1445 if (op) {
1446 this->addDrawOp(clip, std::move(op));
1447 return;
1448 }
1449 assert_alive(paint);
1450 }
1451#endif
1452 this->drawShapeUsingPathRenderer(clip,
1453 std::move(paint),
1454 aa,
1455 viewMatrix,
1457}
1458
1460 GrPaint&& paint,
1461 const SkMatrix& viewMatrix,
1462 GrSurfaceProxyView view,
1463 SkAlphaType alphaType,
1466 std::unique_ptr<SkLatticeIter> iter,
1467 const SkRect& dst) {
1470 SkDEBUGCODE(this->validate();)
1471 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawImageLattice", fContext);
1472
1473 AutoCheckFlush acf(this->drawingManager());
1474
1475 GrOp::Owner op =
1476 LatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(view),
1477 alphaType, std::move(csxf), filter, std::move(iter), dst);
1478 this->addDrawOp(clip, std::move(op));
1479}
1480
1481void SurfaceDrawContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1482 const SkRect& bounds) {
1485 SkDEBUGCODE(this->validate();)
1486 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawDrawable", fContext);
1487 GrOp::Owner op(DrawableOp::Make(fContext, std::move(drawable), bounds));
1488 SkASSERT(op);
1489 this->addOp(std::move(op));
1490}
1491
1492void SurfaceDrawContext::setLastClip(uint32_t clipStackGenID,
1493 const SkIRect& devClipBounds,
1494 int numClipAnalyticElements) {
1495 auto opsTask = this->getOpsTask();
1496 opsTask->fLastClipStackGenID = clipStackGenID;
1497 opsTask->fLastDevClipBounds = devClipBounds;
1498 opsTask->fLastClipNumAnalyticElements = numClipAnalyticElements;
1499}
1500
1501bool SurfaceDrawContext::mustRenderClip(uint32_t clipStackGenID,
1502 const SkIRect& devClipBounds,
1503 int numClipAnalyticElements) {
1504 auto opsTask = this->getOpsTask();
1505 return opsTask->fLastClipStackGenID != clipStackGenID ||
1506 !opsTask->fLastDevClipBounds.contains(devClipBounds) ||
1507 opsTask->fLastClipNumAnalyticElements != numClipAnalyticElements;
1508}
1509
1511 const GrBackendSemaphore waitSemaphores[],
1512 bool deleteSemaphoresAfterWait) {
1515 SkDEBUGCODE(this->validate();)
1516 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "waitOnSemaphores", fContext);
1517
1518 AutoCheckFlush acf(this->drawingManager());
1519
1520 if (numSemaphores && !this->caps()->backendSemaphoreSupport()) {
1521 return false;
1522 }
1523
1524 auto direct = fContext->asDirectContext();
1525 if (!direct) {
1526 return false;
1527 }
1528
1529 auto resourceProvider = direct->priv().resourceProvider();
1530
1531 GrWrapOwnership ownership =
1532 deleteSemaphoresAfterWait ? kAdopt_GrWrapOwnership : kBorrow_GrWrapOwnership;
1533
1534 std::unique_ptr<std::unique_ptr<GrSemaphore>[]> grSemaphores(
1535 new std::unique_ptr<GrSemaphore>[numSemaphores]);
1536 for (int i = 0; i < numSemaphores; ++i) {
1537 grSemaphores[i] = resourceProvider->wrapBackendSemaphore(waitSemaphores[i],
1539 ownership);
1540 }
1541 this->drawingManager()->newWaitRenderTask(this->asSurfaceProxyRef(), std::move(grSemaphores),
1542 numSemaphores);
1543 return true;
1544}
1545
1547 GrPaint&& paint,
1548 GrAA aa,
1549 const SkMatrix& viewMatrix,
1550 const SkPath& path,
1551 const GrStyle& style) {
1554 SkDEBUGCODE(this->validate();)
1555 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawPath", fContext);
1556
1557 GrStyledShape shape(path, style, DoSimplify::kNo);
1558 this->drawShape(clip, std::move(paint), aa, viewMatrix, std::move(shape));
1559}
1560
1562 GrPaint&& paint,
1563 GrAA aa,
1564 const SkMatrix& viewMatrix,
1565 GrStyledShape&& shape) {
1568 SkDEBUGCODE(this->validate();)
1569 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawShape", fContext);
1570
1571 if (shape.isEmpty()) {
1572 if (shape.inverseFilled()) {
1573 this->drawPaint(clip, std::move(paint), viewMatrix);
1574 }
1575 return;
1576 }
1577
1578 AutoCheckFlush acf(this->drawingManager());
1579
1580 // If we get here in drawShape(), we definitely need to use path rendering
1581 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, std::move(shape),
1582 /* attemptDrawSimple */ true);
1583}
1584
1586 return clip ? clip->getConservativeBounds() : SkIRect::MakeWH(sdc->width(), sdc->height());
1587}
1588
1590 const GrUserStencilSettings* ss,
1591 SkRegion::Op op,
1592 bool invert,
1593 GrAA aa,
1594 const SkMatrix& viewMatrix,
1595 const SkPath& path) {
1598 SkDEBUGCODE(this->validate();)
1599 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawAndStencilPath", fContext);
1600
1601 if (path.isEmpty() && path.isInverseFillType()) {
1602 GrPaint paint;
1603 paint.setCoverageSetOpXPFactory(op, invert);
1604 this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
1605 SkRect::Make(this->dimensions()));
1606 return true;
1607 }
1608
1609 AutoCheckFlush acf(this->drawingManager());
1610
1611 // An Assumption here is that path renderer would use some form of tweaking
1612 // the src color (either the input alpha or in the frag shader) to implement
1613 // aa. If we have some future driver-mojo path AA that can do the right
1614 // thing WRT to the blend then we'll need some query on the PR.
1615 GrAAType aaType = this->chooseAAType(aa);
1616 bool hasUserStencilSettings = !ss->isUnused();
1617
1618 SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1619
1620 GrPaint paint;
1621 paint.setCoverageSetOpXPFactory(op, invert);
1622
1625 canDrawArgs.fCaps = this->caps();
1626 canDrawArgs.fProxy = this->asRenderTargetProxy();
1627 canDrawArgs.fViewMatrix = &viewMatrix;
1628 canDrawArgs.fShape = &shape;
1629 canDrawArgs.fPaint = &paint;
1630 canDrawArgs.fSurfaceProps = &fSurfaceProps;
1631 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1632 canDrawArgs.fAAType = aaType;
1633 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1634
1636
1637 // Don't allow the SW renderer
1638 auto pr = this->drawingManager()->getPathRenderer(canDrawArgs,
1639 false,
1640 DrawType::kStencilAndColor);
1641 if (!pr) {
1642 return false;
1643 }
1644
1646 std::move(paint),
1647 ss,
1648 this,
1649 clip,
1650 &clipConservativeBounds,
1651 &viewMatrix,
1652 &shape,
1653 aaType,
1654 this->colorInfo().isLinearlyBlended()};
1655 pr->drawPath(args);
1656 return true;
1657}
1658
1661
1662 if (fContext->abandoned()) {
1663 return skgpu::Budgeted::kNo;
1664 }
1665
1666 SkDEBUGCODE(this->validate();)
1667
1668 return this->asSurfaceProxy()->isBudgeted();
1669}
1670
1672 GrPaint&& paint,
1673 GrAA aa,
1674 const SkMatrix& viewMatrix,
1675 const SkPoint points[2],
1676 const SkStrokeRec& stroke) {
1678
1680 SkASSERT(stroke.getWidth() > 0);
1681 // Adding support for round capping would require a
1682 // SurfaceDrawContext::fillRRectWithLocalMatrix entry point
1683 SkASSERT(SkPaint::kRound_Cap != stroke.getCap());
1684
1685 const SkScalar halfWidth = 0.5f * stroke.getWidth();
1686 if (halfWidth <= 0.f) {
1687 // Prevents underflow when stroke width is epsilon > 0 (so technically not a hairline).
1688 // The CTM would need to have a scale near 1/epsilon in order for this to have meaningful
1689 // coverage (although that would likely overflow elsewhere and cause the draw to drop due
1690 // to non-finite bounds). At any other scale, this line is so thin, it's coverage is
1691 // negligible, so discarding the draw is visually equivalent.
1692 return;
1693 }
1694
1695 SkVector parallel = points[1] - points[0];
1696
1697 if (!SkPoint::Normalize(&parallel)) {
1698 parallel.fX = 1.0f;
1699 parallel.fY = 0.0f;
1700 }
1701 parallel *= halfWidth;
1702
1703 SkVector ortho = { parallel.fY, -parallel.fX };
1704 SkPoint p0 = points[0], p1 = points[1];
1705 if (stroke.getCap() == SkPaint::kSquare_Cap) {
1706 // Extra extension for square caps
1707 p0 -= parallel;
1708 p1 += parallel;
1709 }
1710
1711 // If we are using dmsaa or reduced shader mode then attempt to draw with FillRRectOp.
1712 if (this->caps()->drawInstancedSupport() &&
1713 (this->alwaysAntialias() ||
1714 (fContext->priv().caps()->reducedShaderMode() && aa == GrAA::kYes))) {
1715 SkMatrix localMatrix = SkMatrix::MakeAll(p1.fX - p0.fX, ortho.fX, p0.fX,
1716 p1.fY - p0.fY, ortho.fY, p0.fY,
1717 0, 0, 1);
1718 if (auto op = FillRRectOp::Make(fContext,
1719 this->arenaAlloc(),
1720 std::move(paint),
1721 SkMatrix::Concat(viewMatrix, localMatrix),
1722 SkRRect::MakeRect({0,-1,1,1}),
1723 localMatrix,
1724 GrAA::kYes)) {
1725 this->addDrawOp(clip, std::move(op));
1726 return;
1727 }
1728 }
1729
1730 // Order is TL, TR, BR, BL where arbitrarily "down" is p0 to p1 and "right" is positive
1731 SkPoint corners[4] = { p0 - ortho,
1732 p0 + ortho,
1733 p1 + ortho,
1734 p1 - ortho };
1735
1737
1738 assert_alive(paint);
1739 this->fillQuadWithEdgeAA(clip, std::move(paint), edgeAA, viewMatrix, corners, nullptr);
1740}
1741
1742bool SurfaceDrawContext::drawSimpleShape(const GrClip* clip,
1743 GrPaint* paint,
1744 GrAA aa,
1745 const SkMatrix& viewMatrix,
1746 const GrStyledShape& shape) {
1747 if (!shape.style().hasPathEffect()) {
1748 GrAAType aaType = this->chooseAAType(aa);
1749 SkPoint linePts[2];
1750 SkRRect rrect;
1751 // We can ignore the starting point and direction since there is no path effect.
1752 bool inverted;
1753 if (shape.asLine(linePts, &inverted) && !inverted &&
1755 shape.style().strokeRec().getCap() != SkPaint::kRound_Cap) {
1756 // The stroked line is an oriented rectangle, which looks the same or better (if
1757 // perspective) compared to path rendering. The exception is subpixel/hairline lines
1758 // that are non-AA or MSAA, in which case the default path renderer achieves higher
1759 // quality.
1760 // FIXME(michaelludwig): If the fill rect op could take an external coverage, or checks
1761 // for and outsets thin non-aa rects to 1px, the path renderer could be skipped.
1763 if (aaType == GrAAType::kCoverage ||
1764 !SkDrawTreatAAStrokeAsHairline(shape.style().strokeRec().getWidth(), viewMatrix,
1765 &coverage)) {
1766 this->drawStrokedLine(clip, std::move(*paint), aa, viewMatrix, linePts,
1767 shape.style().strokeRec());
1768 return true;
1769 }
1770 } else if (shape.asRRect(&rrect, &inverted) && !inverted) {
1771 if (rrect.isRect()) {
1772 this->drawRect(clip, std::move(*paint), aa, viewMatrix, rrect.rect(),
1773 &shape.style());
1774 return true;
1775 } else if (rrect.isOval()) {
1776 this->drawOval(clip, std::move(*paint), aa, viewMatrix, rrect.rect(),
1777 shape.style());
1778 return true;
1779 }
1780 this->drawRRect(clip, std::move(*paint), aa, viewMatrix, rrect, shape.style());
1781 return true;
1782 } else if (GrAAType::kCoverage == aaType &&
1783 shape.style().isSimpleFill() &&
1784 viewMatrix.rectStaysRect() &&
1785 !this->caps()->reducedShaderMode()) {
1786 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply the
1787 // matrix to all the points individually rather than just to the rect
1788 SkRect rects[2];
1789 if (shape.asNestedRects(rects)) {
1790 // Concave AA paths are expensive - try to avoid them for special cases
1792 viewMatrix, rects);
1793 if (op) {
1794 this->addDrawOp(clip, std::move(op));
1795 return true;
1796 }
1797 // Fall through to let path renderer handle subpixel nested rects with unequal
1798 // stroke widths along X/Y.
1799 }
1800 }
1801 }
1802 return false;
1803}
1804
1805void SurfaceDrawContext::drawShapeUsingPathRenderer(const GrClip* clip,
1806 GrPaint&& paint,
1807 GrAA aa,
1808 const SkMatrix& viewMatrix,
1809 GrStyledShape&& shape,
1810 bool attemptDrawSimple) {
1813 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "internalDrawPath", fContext);
1814
1815 if (!viewMatrix.isFinite() || !shape.bounds().isFinite()) {
1816 return;
1817 }
1818
1819 SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1820
1821 // Always allow paths to trigger DMSAA.
1822 GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(aa);
1823
1824 PathRenderer::CanDrawPathArgs canDrawArgs;
1825 canDrawArgs.fCaps = this->caps();
1826 canDrawArgs.fProxy = this->asRenderTargetProxy();
1827 canDrawArgs.fViewMatrix = &viewMatrix;
1828 canDrawArgs.fShape = &shape;
1829 canDrawArgs.fPaint = &paint;
1830 canDrawArgs.fSurfaceProps = &fSurfaceProps;
1831 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1832 canDrawArgs.fHasUserStencilSettings = false;
1833 canDrawArgs.fAAType = aaType;
1834
1835 constexpr static bool kDisallowSWPathRenderer = false;
1837
1838 PathRenderer* pr = nullptr;
1839
1840 if (!shape.style().strokeRec().isFillStyle() && !shape.isEmpty()) {
1841 // Give the tessellation path renderer a chance to claim this stroke before we simplify it.
1842 PathRenderer* tess = this->drawingManager()->getTessellationPathRenderer();
1843 if (tess && tess->canDrawPath(canDrawArgs) == PathRenderer::CanDrawPath::kYes) {
1844 pr = tess;
1845 }
1846 }
1847
1848 if (!pr) {
1849 // The shape isn't a stroke that can be drawn directly. Simplify if possible.
1850 shape.simplify();
1851
1852 if (shape.isEmpty() && !shape.inverseFilled()) {
1853 return;
1854 }
1855
1856 if (attemptDrawSimple || shape.simplified()) {
1857 // Usually we enter drawShapeUsingPathRenderer() because the shape+style was too complex
1858 // for dedicated draw ops. However, if GrStyledShape was able to reduce something we
1859 // ought to try again instead of going right to path rendering.
1860 if (this->drawSimpleShape(clip, &paint, aa, viewMatrix, shape)) {
1861 return;
1862 }
1863 }
1864
1865 // Try a 1st time without applying any of the style to the geometry (and barring sw)
1866 pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1868 }
1869
1870 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
1871 if (styleScale == 0.0f) {
1872 return;
1873 }
1874
1875 if (!pr && shape.style().pathEffect()) {
1876 // It didn't work above, so try again with the path effect applied.
1877 shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1878 if (shape.isEmpty()) {
1879 return;
1880 }
1881 pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1883 }
1884 if (!pr && shape.style().applies()) {
1885 shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1886 if (shape.isEmpty()) {
1887 return;
1888 }
1889 pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1891 }
1892
1893 if (!pr) {
1894 // Fall back on SW renderer as a last resort.
1895 if (GrAATypeIsHW(aaType)) {
1896 // No point in trying SW renderer with MSAA.
1897 aaType = GrAAType::kCoverage;
1898 canDrawArgs.fAAType = aaType;
1899 }
1900 // This can only fail if a) AA type is MSAA or the style is not applied (already checked),
1901 // or b) the SW renderer's proxy provider is null, which should never happen.
1903 SkASSERT(pr->canDrawPath(canDrawArgs) != PathRenderer::CanDrawPath::kNo);
1904#if GR_PATH_RENDERER_SPEW
1905 SkDebugf("falling back to: %s\n", pr->name());
1906#endif
1907 }
1908
1909 PathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1910 std::move(paint),
1912 this,
1913 clip,
1914 &clipConservativeBounds,
1915 &viewMatrix,
1916 canDrawArgs.fShape,
1917 aaType,
1918 this->colorInfo().isLinearlyBlended()};
1919 pr->drawPath(args);
1920}
1921
1923 GrOp::Owner op,
1924 const std::function<WillAddOpFn>& willAddFn) {
1926 if (fContext->abandoned()) {
1927 return;
1928 }
1929 GrDrawOp* drawOp = (GrDrawOp*)op.get();
1930 SkDEBUGCODE(this->validate();)
1931 SkDEBUGCODE(drawOp->fAddDrawOpCalled = true;)
1932 GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "addDrawOp", fContext);
1933
1934 // Setup clip
1935 SkRect bounds;
1936 op_bounds(&bounds, op.get());
1937 GrAppliedClip appliedClip(this->dimensions(), this->asSurfaceProxy()->backingStoreDimensions());
1938 const bool opUsesMSAA = drawOp->usesMSAA();
1939 bool skipDraw = false;
1940 if (clip) {
1941 // Have a complex clip, so defer to its early clip culling
1942 GrAAType aaType;
1943 if (opUsesMSAA) {
1944 aaType = GrAAType::kMSAA;
1945 } else {
1946 aaType = op->hasAABloat() ? GrAAType::kCoverage : GrAAType::kNone;
1947 }
1948 skipDraw = clip->apply(fContext, this, drawOp, aaType,
1949 &appliedClip, &bounds) == GrClip::Effect::kClippedOut;
1950 } else {
1951 // No clipping, so just clip the bounds against the logical render target dimensions
1952 skipDraw = !bounds.intersect(this->asSurfaceProxy()->getBoundsRect());
1953 }
1954
1955 if (skipDraw) {
1956 return;
1957 }
1958
1959 GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
1960 GrProcessorSet::Analysis analysis = drawOp->finalize(*this->caps(), &appliedClip, clampType);
1961
1962 const bool opUsesStencil = drawOp->usesStencil();
1963
1964 // Always trigger DMSAA when there is stencil. This ensures stencil contents get properly
1965 // preserved between render passes, if needed.
1966 const bool drawNeedsMSAA = opUsesMSAA || (fCanUseDynamicMSAA && opUsesStencil);
1967
1968 // Must be called before setDstProxyView so that it sees the final bounds of the op.
1969 op->setClippedBounds(bounds);
1970
1971 // Determine if the Op will trigger the use of a separate DMSAA attachment that requires manual
1972 // resolves.
1973 // TODO: Currently usesAttachmentIfDMSAA checks if this is a textureProxy or not. This check is
1974 // really only for GL which uses a normal texture sampling when using barriers. For Vulkan it
1975 // is possible to use the msaa buffer as an input attachment even if this is not a texture.
1976 // However, support for that is not fully implemented yet in Vulkan. Once it is, this check
1977 // should change to a virtual caps check that returns whether we need to break up an OpsTask
1978 // if it has barriers and we are about to promote to MSAA.
1979 bool usesAttachmentIfDMSAA =
1980 fCanUseDynamicMSAA &&
1981 (!this->caps()->msaaResolvesAutomatically() || !this->asTextureProxy());
1982 bool opRequiresDMSAAAttachment = usesAttachmentIfDMSAA && drawNeedsMSAA;
1983 bool opTriggersDMSAAAttachment =
1984 opRequiresDMSAAAttachment && !this->getOpsTask()->usesMSAASurface();
1985 if (opTriggersDMSAAAttachment) {
1986 // This will be the op that actually triggers use of a DMSAA attachment. Texture barriers
1987 // can't be moved to a DMSAA attachment, so if there already are any on the current opsTask
1988 // then we need to split.
1989 if (this->getOpsTask()->renderPassXferBarriers() & GrXferBarrierFlags::kTexture) {
1990 SkASSERT(!this->getOpsTask()->isColorNoOp());
1991 this->replaceOpsTask()->setCannotMergeBackward();
1992 }
1993 }
1994
1995 GrDstProxyView dstProxyView;
1996 if (analysis.requiresDstTexture()) {
1997 if (!this->setupDstProxyView(drawOp->bounds(), drawNeedsMSAA, &dstProxyView)) {
1998 return;
1999 }
2000#ifdef SK_DEBUG
2001 if (fCanUseDynamicMSAA && drawNeedsMSAA && !this->caps()->msaaResolvesAutomatically()) {
2002 // Since we aren't literally writing to the render target texture while using a DMSAA
2003 // attachment, we need to resolve that texture before sampling it. Ensure the current
2004 // opsTask got closed off in order to initiate an implicit resolve.
2005 SkASSERT(this->getOpsTask()->isEmpty());
2006 }
2007#endif
2008 }
2009
2010 auto opsTask = this->getOpsTask();
2011 if (willAddFn) {
2012 willAddFn(op.get(), opsTask->uniqueID());
2013 }
2014
2015 // Note if the op needs stencil. Stencil clipping already called setNeedsStencil for itself, if
2016 // needed.
2017 if (opUsesStencil) {
2018 this->setNeedsStencil();
2019 }
2020
2021#if GR_GPU_STATS && defined(GR_TEST_UTILS)
2022 if (fCanUseDynamicMSAA && drawNeedsMSAA) {
2023 if (!opsTask->usesMSAASurface()) {
2024 fContext->priv().dmsaaStats().fNumMultisampleRenderPasses++;
2025 }
2026 fContext->priv().dmsaaStats().fTriggerCounts[op->name()]++;
2027 }
2028#endif
2029
2030 opsTask->addDrawOp(this->drawingManager(), std::move(op), drawNeedsMSAA, analysis,
2031 std::move(appliedClip), dstProxyView,
2032 GrTextureResolveManager(this->drawingManager()), *this->caps());
2033
2034#ifdef SK_DEBUG
2035 if (fCanUseDynamicMSAA && drawNeedsMSAA) {
2036 SkASSERT(opsTask->usesMSAASurface());
2037 }
2038#endif
2039}
2040
2041bool SurfaceDrawContext::setupDstProxyView(const SkRect& opBounds,
2042 bool opRequiresMSAA,
2043 GrDstProxyView* dstProxyView) {
2044 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2045 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2046 // start and stop the render pass in order to make the copy.
2047 if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
2048 return false;
2049 }
2050
2051 // First get the dstSampleFlags as if we will put the draw into the current OpsTask
2052 auto dstSampleFlags = this->caps()->getDstSampleFlagsForProxy(
2053 this->asRenderTargetProxy(), this->getOpsTask()->usesMSAASurface() || opRequiresMSAA);
2054
2055 // If we don't have barriers for this draw then we will definitely be breaking up the OpsTask.
2056 // However, if using dynamic MSAA, the new OpsTask will not have MSAA already enabled on it
2057 // and that may allow us to use texture barriers. So we check if we can use barriers on the new
2058 // ops task and then break it up if so.
2059 if (!(dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) &&
2060 fCanUseDynamicMSAA && this->getOpsTask()->usesMSAASurface() && !opRequiresMSAA) {
2061 auto newFlags =
2063 false/*=opRequiresMSAA*/);
2065 // We can't have an empty ops task if we are in DMSAA and the ops task already returns
2066 // true for usesMSAASurface.
2067 SkASSERT(!this->getOpsTask()->isColorNoOp());
2068 this->replaceOpsTask()->setCannotMergeBackward();
2069 dstSampleFlags = newFlags;
2070 }
2071 }
2072
2073 if (dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) {
2074 // If we require a barrier to sample the dst it means we are sampling the RT itself
2075 // either as a texture or input attachment. In this case we don't need to break up the
2076 // OpsTask.
2077 dstProxyView->setProxyView(this->readSurfaceView());
2078 dstProxyView->setOffset(0, 0);
2079 dstProxyView->setDstSampleFlags(dstSampleFlags);
2080 return true;
2081 }
2082 SkASSERT(dstSampleFlags == GrDstSampleFlags::kNone);
2083
2084 // We are using a different surface from the main color attachment to sample the dst from. If we
2085 // are in DMSAA we can just use the single sampled RT texture itself. Otherwise, we must do a
2086 // copy.
2087 // We do have to check if we ended up here becasue we don't have texture barriers but do have
2088 // msaaResolvesAutomatically (i.e. render-to-msaa-texture). In that case there will be no op or
2089 // barrier between draws to flush the render target before being used as a texture in the next
2090 // draw. So in that case we just fall through to doing a copy.
2091 if (fCanUseDynamicMSAA && opRequiresMSAA && this->asTextureProxy() &&
2092 !this->caps()->msaaResolvesAutomatically() &&
2093 this->caps()->dmsaaResolveCanBeUsedAsTextureInSameRenderPass()) {
2094 this->replaceOpsTaskIfModifiesColor()->setCannotMergeBackward();
2095 dstProxyView->setProxyView(this->readSurfaceView());
2096 dstProxyView->setOffset(0, 0);
2097 dstProxyView->setDstSampleFlags(dstSampleFlags);
2098 return true;
2099 }
2100
2101 // Now we fallback to doing a copy.
2102
2104 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2105 // have per-sample dst values by making the copy multisampled.
2107 this->asRenderTargetProxy(), colorType);
2108
2109 SkIRect copyRect = SkIRect::MakeSize(this->asSurfaceProxy()->backingStoreDimensions());
2110 if (!restrictions.fMustCopyWholeSrc) {
2111 // If we don't need the whole source, restrict to the op's bounds. We add an extra pixel
2112 // of padding to account for AA bloat and the unpredictable rounding of coords near pixel
2113 // centers during rasterization.
2114 SkIRect conservativeDrawBounds = opBounds.roundOut();
2115 conservativeDrawBounds.outset(1, 1);
2116 SkAssertResult(copyRect.intersect(conservativeDrawBounds));
2117 }
2118
2119 SkIPoint dstOffset;
2120 SkBackingFit fit;
2122 dstOffset = {0, 0};
2124 } else {
2125 dstOffset = {copyRect.fLeft, copyRect.fTop};
2127 }
2129 this->asSurfaceProxyRef(),
2130 this->origin(),
2132 copyRect,
2133 fit,
2135 /*label=*/{},
2136 restrictions.fRectsMustMatch);
2137 SkASSERT(copy);
2138
2139 dstProxyView->setProxyView({std::move(copy), this->origin(), this->readSwizzle()});
2140 dstProxyView->setOffset(dstOffset);
2141 dstProxyView->setDstSampleFlags(dstSampleFlags);
2142 return true;
2143}
2144
2145OpsTask* SurfaceDrawContext::replaceOpsTaskIfModifiesColor() {
2146 if (!this->getOpsTask()->isColorNoOp()) {
2147 this->replaceOpsTask();
2148 }
2149 return this->getOpsTask();
2150}
2151
2152} // namespace skgpu::ganesh
static constexpr SkColor kColor
Definition: CanvasTest.cpp:265
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
uint32_t GrColor
Definition: GrColor.h:25
#define GR_CREATE_TRACE_MARKER_CONTEXT(classname, op, context)
Definition: GrTracing.h:18
GrClampType
Definition: GrTypesPriv.h:228
GrQuadAAFlags
Definition: GrTypesPriv.h:247
GrWrapOwnership
Definition: GrTypesPriv.h:77
@ kAdopt_GrWrapOwnership
Definition: GrTypesPriv.h:82
@ kBorrow_GrWrapOwnership
Definition: GrTypesPriv.h:79
GrPrimitiveType
Definition: GrTypesPriv.h:43
static constexpr bool GrAATypeIsHW(GrAAType type)
Definition: GrTypesPriv.h:212
GrAAType
Definition: GrTypesPriv.h:200
GrAA
Definition: GrTypesPriv.h:173
GrColorType
Definition: GrTypesPriv.h:540
static constexpr GrClampType GrColorTypeClampType(GrColorType colorType)
Definition: GrTypesPriv.h:868
GrSurfaceOrigin
Definition: GrTypes.h:147
static const int points[]
SkAlphaType
Definition: SkAlphaType.h:26
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBackingFit
Definition: SkBackingFit.h:16
SkBlendMode
Definition: SkBlendMode.h:38
@ kSrcOver
r = s + (1-sa)*d
uint32_t SkColor
Definition: SkColor.h:37
#define SkColorGetA(color)
Definition: SkColor.h:61
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkDEBUGCODE(...)
Definition: SkDebug.h:23
bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix &matrix, SkScalar *coverage)
Definition: SkDrawBase.cpp:262
static float sk_float_rsqrt(float x)
SkPMColor4f SkColorToPMColor4f(SkColor c, const GrColorInfo &colorInfo)
Definition: SkGr.cpp:275
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
SkFilterMode
SkMipmapMode
#define SkScalarInvert(x)
Definition: SkScalar.h:73
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:101
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
#define SK_ScalarNearlyZero
Definition: SkScalar.h:99
#define SK_ScalarSqrt2
Definition: SkScalar.h:20
static bool SkScalarIsInt(SkScalar x)
Definition: SkScalar.h:80
#define SkScalarSqrt(x)
Definition: SkScalar.h:42
#define SkScalarAbs(x)
Definition: SkScalar.h:39
@ kDirectionalLight_ShadowFlag
Definition: SkShadowUtils.h:31
@ kGeometricOnly_ShadowFlag
Definition: SkShadowUtils.h:29
@ kTransparentOccluder_ShadowFlag
Definition: SkShadowUtils.h:27
static T SkTAbs(T value)
Definition: SkTemplates.h:43
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define RETURN_IF_ABANDONED
#define RETURN_FALSE_IF_ABANDONED
#define ASSERT_SINGLE_OWNER
const GrCaps * caps() const
Definition: GrCaps.h:57
bool reducedShaderMode() const
Definition: GrCaps.h:190
std::tuple< GrColorType, GrBackendFormat > getFallbackColorTypeAndFormat(GrColorType, int sampleCount) const
Definition: GrCaps.cpp:499
bool performPartialClearsAsDraws() const
Definition: GrCaps.h:426
GrDstSampleFlags getDstSampleFlagsForProxy(const GrRenderTargetProxy *, bool drawUsesMSAA) const
Definition: GrCaps.cpp:461
const GrShaderCaps * shaderCaps() const
Definition: GrCaps.h:63
virtual skgpu::Swizzle getWriteSwizzle(const GrBackendFormat &, GrColorType) const =0
virtual DstCopyRestrictions getDstCopyRestrictions(const GrRenderTargetProxy *src, GrColorType ct) const
Definition: GrCaps.h:461
GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const
Definition: GrCaps.cpp:400
bool msaaResolvesAutomatically() const
Definition: GrCaps.h:100
bool performStencilClearsAsDraws() const
Definition: GrCaps.h:438
skgpu::Swizzle getReadSwizzle(const GrBackendFormat &format, GrColorType colorType) const
Definition: GrCaps.cpp:443
Definition: GrClip.h:29
static bool IsPixelAligned(const SkRect &rect)
Definition: GrClip.h:202
static bool IsOutsideClip(const SkIRect &outerClipBounds, const SkRect &drawBounds, GrAA aa)
Definition: GrClip.h:139
bool isLinearlyBlended() const
Definition: GrColorInfo.cpp:44
sk_sp< GrColorSpaceXform > refColorSpaceXformFromSRGB() const
Definition: GrColorInfo.h:41
GrColorType colorType() const
Definition: GrColorInfo.h:43
static std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > child, SkColorSpace *src, SkAlphaType srcAT, SkColorSpace *dst, SkAlphaType dstAT)
static sk_sp< GrColorSpaceXform > Make(SkColorSpace *src, SkAlphaType srcAT, SkColorSpace *dst, SkAlphaType dstAT)
virtual GrDirectContext * asDirectContext()
GrResourceProvider * resourceProvider()
GrDirectContextPriv priv()
static const GrDisableColorXPFactory * Get()
virtual bool usesMSAA() const
Definition: GrDrawOp.h:37
virtual GrProcessorSet::Analysis finalize(const GrCaps &, const GrAppliedClip *, GrClampType)=0
virtual bool usesStencil() const
Definition: GrDrawOp.h:82
GrRecordingContext * getContext()
void newWaitRenderTask(const sk_sp< GrSurfaceProxy > &proxy, std::unique_ptr< std::unique_ptr< GrSemaphore >[]>, int numSemaphores)
PathRenderer * getTessellationPathRenderer()
PathRenderer * getSoftwarePathRenderer()
PathRenderer * getPathRenderer(const PathRenderer::CanDrawPathArgs &, bool allowSW, PathRendererChain::DrawType, PathRenderer::StencilSupport *=nullptr)
void setOffset(const SkIPoint &offset)
void setDstSampleFlags(GrDstSampleFlags dstSampleFlags)
void setProxyView(GrSurfaceProxyView view)
Definition: GrOp.h:70
std::unique_ptr< GrOp > Owner
Definition: GrOp.h:72
const SkRect & bounds() const
Definition: GrOp.h:122
bool hasAABloat() const
Definition: GrOp.h:133
bool hasZeroArea() const
Definition: GrOp.h:138
static GrOp::Owner MakeArcOp(GrRecordingContext *, GrPaint &&, const SkMatrix &, const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const GrStyle &, const GrShaderCaps *)
static GrOp::Owner MakeOvalOp(GrRecordingContext *, GrPaint &&, const SkMatrix &, const SkRect &oval, const GrStyle &style, const GrShaderCaps *)
static GrOp::Owner MakeCircularRRectOp(GrRecordingContext *, GrPaint &&, const SkMatrix &, const SkRRect &, const SkStrokeRec &, const GrShaderCaps *)
static GrOp::Owner MakeCircleOp(GrRecordingContext *, GrPaint &&, const SkMatrix &, const SkRect &oval, const GrStyle &style, const GrShaderCaps *)
static GrOp::Owner MakeRRectOp(GrRecordingContext *, GrPaint &&, const SkMatrix &, const SkRRect &, const SkStrokeRec &, const GrShaderCaps *)
bool requiresDstTexture() const
sk_sp< GrTextureProxy > createProxy(const GrBackendFormat &, SkISize dimensions, GrRenderable, int renderTargetSampleCnt, skgpu::Mipmapped, SkBackingFit, skgpu::Budgeted, GrProtected, std::string_view label, GrInternalSurfaceFlags=GrInternalSurfaceFlags::kNone, UseAllocator useAllocator=UseAllocator::kYes)
sk_sp< GrTextureProxy > wrapRenderableBackendTexture(const GrBackendTexture &, int sampleCnt, GrWrapOwnership, GrWrapCacheable, sk_sp< skgpu::RefCntedCallback > releaseHelper)
Definition: GrQuad.h:30
Type quadType() const
Definition: GrQuad.h:118
static GrQuad MakeFromRect(const SkRect &, const SkMatrix &)
Definition: GrQuad.cpp:107
bool asRect(SkRect *rect) const
Definition: GrQuad.cpp:141
bool isFinite() const
Definition: GrQuad.h:95
SkRect bounds() const
Definition: GrQuad.h:81
GrProxyProvider * proxyProvider()
sktext::gpu::TextBlobRedrawCoordinator * getTextBlobCache()
GrRecordingContextPriv priv()
bool abandoned() override
int maxWindowRectangles(const GrCaps &caps) const
static const GrUserStencilSettings * SetClipBitSettings(bool setToInside)
SkPathEffect * pathEffect() const
Definition: GrStyle.h:119
bool hasPathEffect() const
Definition: GrStyle.h:122
static const GrStyle & SimpleFill()
Definition: GrStyle.h:30
bool applies() const
Definition: GrStyle.h:143
static SkScalar MatrixToScaleFactor(const SkMatrix &matrix)
Definition: GrStyle.h:147
bool isSimpleFill() const
Definition: GrStyle.h:114
const SkStrokeRec & strokeRec() const
Definition: GrStyle.h:140
bool isEmpty() const
static GrStyledShape MakeArc(const SkArc &arc, const GrStyle &style, DoSimplify=DoSimplify::kYes)
bool asLine(SkPoint pts[2], bool *inverted) const
bool asRRect(SkRRect *rrect, bool *inverted) const
bool simplified() const
bool inverseFilled() const
const GrStyle & style() const
SkRect bounds() const
bool asNestedRects(SkRect rects[2]) const
GrStyledShape applyStyle(GrStyle::Apply apply, SkScalar scale) const
GrTextureProxy * asTextureProxy() const
const GrBackendFormat & backendFormat() const
SkRect getBoundsRect() const
skgpu::Budgeted isBudgeted() const
static sk_sp< GrSurfaceProxy > Copy(GrRecordingContext *, sk_sp< GrSurfaceProxy > src, GrSurfaceOrigin, skgpu::Mipmapped, SkIRect srcRect, SkBackingFit, skgpu::Budgeted, std::string_view label, RectsMustMatch=RectsMustMatch::kNo, sk_sp< GrRenderTask > *outTask=nullptr)
static std::unique_ptr< GrFragmentProcessor > MakeSubset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState, const SkRect &subset, const GrCaps &caps, const float border[4]=kDefaultBorder, bool alwaysUseShaderTileMode=false)
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
static const GrXPFactory * FromBlendMode(SkBlendMode)
SrcRectConstraint
Definition: SkCanvas.h:1541
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition: SkCanvas.h:1542
static constexpr int kMScaleX
horizontal scale factor
Definition: SkMatrix.h:353
static constexpr int kMTransY
vertical translation
Definition: SkMatrix.h:358
SkScalar getTranslateY() const
Definition: SkMatrix.h:452
void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty)
Definition: SkMatrix.h:1803
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Definition: SkMatrix.cpp:770
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition: SkMatrix.h:179
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
bool invert(SkMatrix *inverse) const
Definition: SkMatrix.h:1206
bool rectStaysRect() const
Definition: SkMatrix.h:271
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
bool isScaleTranslate() const
Definition: SkMatrix.h:236
static constexpr int kMTransX
horizontal translation
Definition: SkMatrix.h:355
bool isFinite() const
Definition: SkMatrix.h:1834
bool isSimilarity(SkScalar tol=SK_ScalarNearlyZero) const
Definition: SkMatrix.cpp:180
static constexpr int kMSkewX
horizontal skew factor
Definition: SkMatrix.h:354
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
SkScalar getTranslateX() const
Definition: SkMatrix.h:445
@ kTranslate_Mask
translation SkMatrix
Definition: SkMatrix.h:193
TypeMask getType() const
Definition: SkMatrix.h:207
Definition: SkMesh.h:263
bool isValid() const
Definition: SkMesh.cpp:753
SkMeshSpecification * spec() const
Definition: SkMesh.h:348
@ kRound_Cap
adds circle
Definition: SkPaint.h:335
@ kSquare_Cap
adds square
Definition: SkPaint.h:336
@ kMiter_Join
extends to miter limit
Definition: SkPaint.h:359
Definition: SkPath.h:59
static SkScalar LengthSqd(const SkPoint &pt)
Definition: SkPointPriv.h:63
static SkVector GetSimpleRadii(const SkRRect &rr)
Definition: SkRRectPriv.h:22
static bool IsNearlySimpleCircular(const SkRRect &rr, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkRRect.cpp:342
SkVector getSimpleRadii() const
Definition: SkRRect.h:111
bool isOval() const
Definition: SkRRect.h:85
const SkRect & rect() const
Definition: SkRRect.h:264
static SkRRect MakeOval(const SkRect &oval)
Definition: SkRRect.h:162
bool transform(const SkMatrix &matrix, SkRRect *dst) const
Definition: SkRRect.cpp:436
static SkRRect MakeRect(const SkRect &r)
Definition: SkRRect.h:149
void setOval(const SkRect &oval)
Definition: SkRRect.cpp:30
SkScalar width() const
Definition: SkRRect.h:95
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.h:180
bool isRect() const
Definition: SkRRect.h:84
bool isEmpty() const
Definition: SkRRect.h:83
const SkRect & getBounds() const
Definition: SkRRect.h:279
bool isSimple() const
Definition: SkRRect.h:86
void setRect(const SkRect &rect)
Definition: SkRRect.h:126
bool getBoundaryPath(SkPath *path) const
Style getStyle() const
Definition: SkStrokeRec.cpp:71
SkScalar getWidth() const
Definition: SkStrokeRec.h:42
SkPaint::Cap getCap() const
Definition: SkStrokeRec.h:44
bool isFillStyle() const
Definition: SkStrokeRec.h:51
AutoCheckFlush(GrDrawingManager *drawingManager)
static GrOp::Owner MakeStencilClip(GrRecordingContext *context, const GrScissorState &scissor, bool insideMask)
Definition: ClearOp.cpp:33
static DEFINE_OP_CLASS_ID GrOp::Owner Make(GrRecordingContext *, std::unique_ptr< SkDrawable::GpuDrawHandler > drawable, const SkRect &bounds)
Definition: DrawableOp.cpp:19
static GrOp::Owner Make(GrRecordingContext *, GrPaint &&, GrAAType, DrawQuad *, const GrUserStencilSettings *=nullptr, InputFlags=InputFlags::kNone)
Definition: FillRectOp.cpp:470
static void AddFillRectOps(SurfaceDrawContext *, const GrClip *, GrRecordingContext *, GrPaint &&, GrAAType, const SkMatrix &viewMatrix, const GrQuadSetEntry quads[], int quadCount, const GrUserStencilSettings *=nullptr)
Definition: FillRectOp.cpp:530
static GrOp::Owner MakeNonAARect(GrRecordingContext *, GrPaint &&, const SkMatrix &view, const SkRect &, const GrUserStencilSettings *=nullptr)
Definition: FillRectOp.cpp:480
void setInitialStencilContent(StencilContent initialContent)
Definition: OpsTask.h:136
bool usesMSAASurface() const
Definition: OpsTask.h:51
GrSurfaceProxy * asSurfaceProxy()
GrDrawingManager * drawingManager()
SkDEBUGCODE(void validate() const ;) SkDEBUGCODE(skgpu GrRecordingContext * fContext
GrRenderTargetProxy * asRenderTargetProxy()
const GrCaps * caps() const
const GrColorInfo & colorInfo() const
GrTextureProxy * asTextureProxy()
skgpu::Mipmapped mipmapped() const
GrSurfaceProxyView readSurfaceView()
skgpu::Swizzle readSwizzle() const
sk_sp< GrSurfaceProxy > asSurfaceProxyRef()
GrSurfaceOrigin origin() const
bool stencilPath(const GrHardClip *, GrAA doStencilMSAA, const SkMatrix &viewMatrix, const SkPath &)
void drawArc(const GrClip *, GrPaint &&paint, GrAA, const SkMatrix &viewMatrix, const SkArc &arc, const GrStyle &style)
bool drawFastShadow(const GrClip *, const SkMatrix &viewMatrix, const SkPath &path, const SkDrawShadowRec &rec)
void drawOval(const GrClip *, GrPaint &&paint, GrAA, const SkMatrix &viewMatrix, const SkRect &oval, const GrStyle &style)
void fillQuadWithEdgeAA(const GrClip *clip, GrPaint &&paint, GrQuadAAFlags edgeAA, const SkMatrix &viewMatrix, const SkPoint points[4], const SkPoint optionalLocalPoints[4])
SurfaceDrawContext(GrRecordingContext *, GrSurfaceProxyView readView, GrSurfaceProxyView writeView, GrColorType, sk_sp< SkColorSpace >, const SkSurfaceProps &)
void fillPixelsWithLocalMatrix(const GrClip *clip, GrPaint &&paint, const SkIRect &bounds, const SkMatrix &localMatrix)
void drawShape(const GrClip *, GrPaint &&, GrAA, const SkMatrix &viewMatrix, GrStyledShape &&)
void drawDrawable(std::unique_ptr< SkDrawable::GpuDrawHandler >, const SkRect &bounds)
void drawAtlas(const GrClip *, GrPaint &&paint, const SkMatrix &viewMatrix, int spriteCount, const SkRSXform xform[], const SkRect texRect[], const SkColor colors[])
void drawTextureSet(const GrClip *, GrTextureSetEntry[], int cnt, int proxyRunCnt, GrSamplerState::Filter, GrSamplerState::MipmapMode, SkBlendMode mode, SkCanvas::SrcRectConstraint, const SkMatrix &viewMatrix, sk_sp< GrColorSpaceXform > texXform)
void setLastClip(uint32_t clipStackGenID, const SkIRect &devClipBounds, int numClipAnalyticElements)
void drawMesh(const GrClip *, GrPaint &&paint, const SkMatrix &viewMatrix, const SkMesh &mesh, skia_private::TArray< std::unique_ptr< GrFragmentProcessor > > children)
void addDrawOp(const GrClip *, GrOp::Owner, const std::function< WillAddOpFn > &=std::function< WillAddOpFn >())
bool waitOnSemaphores(int numSemaphores, const GrBackendSemaphore waitSemaphores[], bool deleteSemaphoresAfterWait)
void drawQuadSet(const GrClip *clip, GrPaint &&paint, const SkMatrix &viewMatrix, const GrQuadSetEntry[], int cnt)
void drawImageLattice(const GrClip *, GrPaint &&, const SkMatrix &viewMatrix, GrSurfaceProxyView, SkAlphaType alphaType, sk_sp< GrColorSpaceXform >, GrSamplerState::Filter, std::unique_ptr< SkLatticeIter >, const SkRect &dst)
void drawPath(const GrClip *, GrPaint &&, GrAA, const SkMatrix &viewMatrix, const SkPath &, const GrStyle &)
bool drawAndStencilPath(const GrHardClip *, const GrUserStencilSettings *, SkRegion::Op op, bool invert, GrAA doStencilMSAA, const SkMatrix &viewMatrix, const SkPath &)
bool mustRenderClip(uint32_t clipStackGenID, const SkIRect &devClipBounds, int numClipAnalyticElements)
void drawRRect(const GrClip *, GrPaint &&, GrAA, const SkMatrix &viewMatrix, const SkRRect &rrect, const GrStyle &style)
void drawPaint(const GrClip *, GrPaint &&, const SkMatrix &viewMatrix)
void drawRegion(const GrClip *, GrPaint &&paint, GrAA aa, const SkMatrix &viewMatrix, const SkRegion &region, const GrStyle &style, const GrUserStencilSettings *ss=nullptr)
static std::unique_ptr< SurfaceDrawContext > MakeFromBackendTexture(GrRecordingContext *, GrColorType, sk_sp< SkColorSpace >, const GrBackendTexture &, int sampleCnt, GrSurfaceOrigin, const SkSurfaceProps &, sk_sp< skgpu::RefCntedCallback > releaseHelper)
void stencilRect(const GrClip *clip, const GrUserStencilSettings *ss, GrPaint &&paint, GrAA doStencilMSAA, const SkMatrix &viewMatrix, const SkRect &rect, const SkMatrix *localMatrix=nullptr)
const SkSurfaceProps & surfaceProps() const
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
void drawRect(const GrClip *, GrPaint &&paint, GrAA, const SkMatrix &viewMatrix, const SkRect &, const GrStyle *style=nullptr)
static std::unique_ptr< SurfaceDrawContext > MakeWithFallback(GrRecordingContext *, GrColorType, sk_sp< SkColorSpace >, SkBackingFit, SkISize dimensions, const SkSurfaceProps &, int sampleCnt, skgpu::Mipmapped, skgpu::Protected, GrSurfaceOrigin=kBottomLeft_GrSurfaceOrigin, skgpu::Budgeted=skgpu::Budgeted::kYes)
void drawGlyphRunList(SkCanvas *, const GrClip *, const SkMatrix &viewMatrix, const sktext::GlyphRunList &glyphRunList, SkStrikeDeviceInfo strikeDeviceInfo, const SkPaint &paint)
void fillRectToRect(const GrClip *, GrPaint &&, GrAA, const SkMatrix &, const SkRect &rectToDraw, const SkRect &localRect)
void drawVertices(const GrClip *, GrPaint &&paint, const SkMatrix &viewMatrix, sk_sp< SkVertices > vertices, GrPrimitiveType *overridePrimType=nullptr, bool skipColorXform=false)
void drawTexture(const GrClip *, GrSurfaceProxyView, SkAlphaType, GrSamplerState::Filter, GrSamplerState::MipmapMode, SkBlendMode, const SkPMColor4f &, const SkRect &srcRect, const SkRect &dstRect, GrQuadAAFlags, SkCanvas::SrcRectConstraint, const SkMatrix &, sk_sp< GrColorSpaceXform >)
void drawStrokedLine(const GrClip *, GrPaint &&, GrAA, const SkMatrix &, const SkPoint[2], const SkStrokeRec &)
void clear(const SkIRect &rect, const SkRGBA4f< AlphaType > &color)
static void AddTextureSetOps(skgpu::ganesh::SurfaceDrawContext *, const GrClip *, GrRecordingContext *, GrTextureSetEntry[], int cnt, int proxyRunCnt, GrSamplerState::Filter, GrSamplerState::MipmapMode, Saturate, SkBlendMode, GrAAType, SkCanvas::SrcRectConstraint, const SkMatrix &viewMatrix, sk_sp< GrColorSpaceXform > textureXform)
Definition: TextureOp.cpp:1275
static GrOp::Owner Make(GrRecordingContext *, GrSurfaceProxyView, SkAlphaType srcAlphaType, sk_sp< GrColorSpaceXform >, GrSamplerState::Filter, GrSamplerState::MipmapMode, const SkPMColor4f &, Saturate, SkBlendMode, GrAAType, DrawQuad *, const SkRect *subset=nullptr)
Definition: TextureOp.cpp:1149
void drawGlyphRunList(SkCanvas *canvas, const SkMatrix &viewMatrix, const GlyphRunList &glyphRunList, const SkPaint &paint, SkStrikeDeviceInfo strikeDeviceInfo, const AtlasDrawDelegate &)
const Paint & paint
Definition: color_source.cc:38
DlColor color
float SkScalar
Definition: extension.cpp:12
gboolean invert
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
uint32_t uint32_t * format
static float max(float r, float g, float b)
Definition: hsl.cpp:49
bool WillUseHairline(const GrQuad &quad, GrAAType aaType, GrQuadAAFlags edgeFlags)
bool CropToRect(const SkRect &cropRect, GrAA cropAA, DrawQuad *quad, bool computeLocal)
SkScalar AmbientRecipAlpha(SkScalar height)
void GetDirectionalParams(SkScalar occluderZ, SkScalar lightX, SkScalar lightY, SkScalar lightZ, SkScalar lightRadius, SkScalar *blurRadius, SkScalar *scale, SkVector *translate)
SkScalar AmbientBlurRadius(SkScalar height)
void GetSpotParams(SkScalar occluderZ, SkScalar lightX, SkScalar lightY, SkScalar lightZ, SkScalar lightRadius, SkScalar *blurRadius, SkScalar *scale, SkVector *translate)
Optional< SkRect > bounds
Definition: SkRecords.h:189
ClipOpAndAA opAA SkRegion region
Definition: SkRecords.h:238
SkRRect rrect
Definition: SkRecords.h:232
SkRect oval
Definition: SkRecords.h:249
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
SkMesh mesh
Definition: SkRecords.h:345
PODArray< SkColor > colors
Definition: SkRecords.h:276
Definition: copy.py:1
const uint32_t fp
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
dst
Definition: cp.py:12
static TessellatorLibtess tess
GrOp::Owner Make(GrRecordingContext *context, GrPaint &&paint, const SkMatrix &viewMatrix, GrAAType aaType, int spriteCount, const SkRSXform *xforms, const SkRect *rects, const SkColor *colors)
GrOp::Owner Make(GrRecordingContext *context, GrPaint &&paint, const SkMesh &mesh, TArray< std::unique_ptr< GrFragmentProcessor > > children, const SkMatrix &viewMatrix, GrAAType aaType, sk_sp< GrColorSpaceXform > colorSpaceXform)
GrOp::Owner Make(GrRecordingContext *ctx, SkArenaAlloc *arena, GrPaint &&paint, const SkMatrix &viewMatrix, const SkRRect &rrect, const SkRect &localRect, GrAA aa)
GrOp::Owner MakeNonAA(GrRecordingContext *context, GrPaint &&paint, const SkMatrix &viewMatrix, GrSurfaceProxyView view, SkAlphaType alphaType, sk_sp< GrColorSpaceXform > colorSpaceXform, GrSamplerState::Filter filter, std::unique_ptr< SkLatticeIter > iter, const SkRect &dst)
Definition: LatticeOp.cpp:401
GrOp::Owner Make(GrRecordingContext *context, GrPaint &&paint, const SkMatrix &viewMatrix, const SkRegion &region, GrAAType aaType, const GrUserStencilSettings *stencilSettings)
Definition: RegionOp.cpp:204
GrOp::Owner Make(GrRecordingContext *context, GrColor color, const SkMatrix &viewMatrix, const SkRRect &rrect, SkScalar blurWidth, SkScalar insetWidth)
GrOp::Owner Make(GrRecordingContext *context, GrPaint &&paint, GrAAType aaType, const SkMatrix &viewMatrix, const SkRect &rect, const SkStrokeRec &stroke)
GrOp::Owner MakeNested(GrRecordingContext *context, GrPaint &&paint, const SkMatrix &viewMatrix, const SkRect rects[2])
static SkIRect get_clip_bounds(const SurfaceDrawContext *sdc, const GrClip *clip)
std::tuple< bool, bool > FilterAndMipmapHaveNoEffect(const GrQuad &srcQuad, const GrQuad &dstQuad)
Definition: TextureOp.cpp:1114
Budgeted
Definition: GpuTypes.h:35
Mipmapped
Definition: GpuTypes.h:53
Protected
Definition: GpuTypes.h:61
Definition: ref_ptr.h:256
GrQuad fLocal
Definition: GrQuad.h:186
GrQuad fDevice
Definition: GrQuad.h:185
GrQuadAAFlags fEdgeFlags
Definition: GrQuad.h:187
GrSurfaceProxy::RectsMustMatch fRectsMustMatch
Definition: GrCaps.h:458
static const GrUserStencilSettings & kUnused
Definition: SkArc.h:15
SkScalar fSweepAngle
Definition: SkArc.h:60
SkScalar fStartAngle
Definition: SkArc.h:58
SkRect fOval
Definition: SkArc.h:55
bool isWedge() const
Definition: SkArc.h:28
SkPoint3 fZPlaneParams
Definition: SkRect.h:32
bool intersect(const SkIRect &r)
Definition: SkRect.h:513
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
void outset(int32_t dx, int32_t dy)
Definition: SkRect.h:428
Definition: SkSize.h:16
static SkAlphaType AlphaType(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:38
static SkColorSpace * ColorSpace(const SkMeshSpecification &spec)
Definition: SkMeshPriv.h:34
SkScalar fX
Definition: SkPoint3.h:16
SkScalar fZ
Definition: SkPoint3.h:16
SkScalar fY
Definition: SkPoint3.h:16
float fX
x-axis value
Definition: SkPoint_impl.h:164
static float Normalize(SkVector *vec)
Definition: SkPoint.cpp:71
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
float fY
y-axis value
Definition: SkPoint_impl.h:165
uint32_t toBytes_RGBA() const
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
bool isFinite() const
Definition: SkRect.h:711
bool intersect(const SkRect &r)
Definition: SkRect.cpp:114
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
SkRect makeOutset(float dx, float dy) const
Definition: SkRect.h:1002
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
bool contains(SkScalar x, SkScalar y) const
Definition: extension.cpp:19
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
void round(SkIRect *dst) const
Definition: SkRect.h:1228
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762
bool isEmpty() const
Definition: SkRect.h:693
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15
const GrRenderTargetProxy * fProxy
Definition: PathRenderer.h:85