37bool skews_are_relevant(
const SkMatrix& m) {
51 float norm = std::max(absScaleX + absSkewY, absSkewX + absScaleY);
53 return absSkewX > kTol * norm || absSkewY > kTol * norm;
65 LocalCoords(
const SkRect& localRect)
68 LocalCoords(
const SkMatrix& localMatrix)
69 : fType(Type::kMatrix)
70 , fMatrix(localMatrix) {}
86 const char*
name()
const override {
return "FillRRectOp"; }
88 FixedFunctionFlags fixedFunctionFlags()
const override {
return fHelper.
fixedFunctionFlags(); }
99#if defined(GR_TEST_UTILS)
100 SkString onDumpInfo()
const override;
116 friend class ::GrSimpleMeshDrawOpHelper;
119 enum class ProcessorFlags {
121 kUseHWDerivatives = 1 << 0,
122 kHasLocalCoords = 1 << 1,
124 kMSAAEnabled = 1 << 3,
127 constexpr static int kNumProcessorFlags = 5;
141 GrProgramInfo* programInfo()
override {
return fProgramInfo; }
144 void onCreateProgramInfo(
const GrCaps*,
147 bool usesMSAASurface,
154 ProcessorFlags fProcessorFlags;
157 Instance(
const SkMatrix& viewMatrix,
159 const LocalCoords& localCoords,
170 Instance* fHeadInstance;
171 Instance** fTailInstance;
172 int fInstanceCount = 1;
177 int fBaseInstance = 0;
188bool can_use_hw_derivatives_with_coverage(
const GrShaderCaps&,
197 const LocalCoords& localCoords,
211 ProcessorFlags
flags = ProcessorFlags::kNone;
218 if (can_use_hw_derivatives_with_coverage(*caps->
shaderCaps(), viewMatrix, rrect)) {
221 flags |= ProcessorFlags::kUseHWDerivatives;
224 flags |= ProcessorFlags::kFakeNonAA;
227 return Helper::FactoryHelper<FillRRectOpImpl>(ctx, std::move(
paint), arena, viewMatrix, rrect,
236 const LocalCoords& localCoords,
237 ProcessorFlags processorFlags)
239 , fHelper(processorSet,
240 (processorFlags & ProcessorFlags::kFakeNonAA)
243 , fProcessorFlags(processorFlags & ~(ProcessorFlags::kHasLocalCoords |
244 ProcessorFlags::kWideColor |
245 ProcessorFlags::kMSAAEnabled))
246 , fHeadInstance(arena->
make<Instance>(viewMatrix,
rrect, localCoords, paintColor))
247 , fTailInstance(&fHeadInstance->
fNext) {
261 SkASSERT(fHeadInstance->fNext ==
nullptr);
265 (aa ==
GrAA::kNo) == (fProcessorFlags & ProcessorFlags::kFakeNonAA)) {
268 if (clipMatrix == fHeadInstance->fViewMatrix) {
276 SkASSERT(!fHeadInstance->fViewMatrix.hasPerspective());
278 return ClipResult::kFail;
281 if (!fHeadInstance->fViewMatrix.invert(&clipToView)) {
282 return ClipResult::kClippedOut;
287 if (skews_are_relevant(clipToView)) {
289 return ClipResult::kFail;
301 return ClipResult::kFail;
308 if (fHeadInstance->fRRect.isRect() &&
clipRRect.isRect()) {
311 return ClipResult::kClippedOut;
319 return ClipResult::kFail;
325 SkRect devISectBounds = fHeadInstance->fViewMatrix.mapRect(isectRRect.
rect());
326 if (devISectBounds.
width() < 1.f || devISectBounds.
height() < 1.f) {
327 return ClipResult::kFail;
330 if (fHeadInstance->fLocalCoords.fType == LocalCoords::Type::kRect) {
332 auto rect = sk_bit_cast<skvx::float4>(fHeadInstance->fRRect.rect());
333 auto local = sk_bit_cast<skvx::float4>(fHeadInstance->fLocalCoords.fRect);
334 auto isect = sk_bit_cast<skvx::float4>(isectRRect.
rect());
335 auto rectToLocalSize = (
local - skvx::shuffle<2,3,0,1>(local)) /
336 (rect - skvx::shuffle<2,3,0,1>(rect));
337 auto localCoordsRect = (isect -
rect) * rectToLocalSize + local;
338 fHeadInstance->fLocalCoords.fRect.setLTRB(localCoordsRect.x(),
341 localCoordsRect.w());
345 fHeadInstance->fRRect = isectRRect;
346 return ClipResult::kClippedGeometrically;
349 return ClipResult::kFail;
355 SkASSERT(fHeadInstance->fNext ==
nullptr);
358 auto analysis = fHelper.finalizeProcessors(caps,
clip, clampType,
360 &fHeadInstance->fColor, &isWideColor);
362 fProcessorFlags |= ProcessorFlags::kWideColor;
364 if (analysis.usesLocalCoords()) {
365 fProcessorFlags |= ProcessorFlags::kHasLocalCoords;
373 auto that = op->
cast<FillRRectOpImpl>();
374 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds()) ||
375 fProcessorFlags != that->fProcessorFlags) {
376 return CombineResult::kCannotCombine;
379 *fTailInstance = that->fHeadInstance;
380 fTailInstance = that->fTailInstance;
381 fInstanceCount += that->fInstanceCount;
382 return CombineResult::kMerged;
385#if defined(GR_TEST_UTILS)
386SkString FillRRectOpImpl::onDumpInfo()
const {
388 str += fHelper.dumpInfo();
390 for (Instance* tmp = fHeadInstance; tmp; tmp = tmp->fNext, ++i) {
391 str.
appendf(
"%d: Color: [%.2f, %.2f, %.2f, %.2f] ",
392 i, tmp->fColor.fR, tmp->fColor.fG, tmp->fColor.fB, tmp->fColor.fA);
394 str.
appendf(
"ViewMatrix: [%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f] ",
395 m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
396 SkRect r = tmp->fRRect.rect();
406 return arena->
make([&](
void* ptr) {
407 return new (ptr) Processor(aaType,
flags);
411 const char*
name()
const override {
return "FillRRectOp::Processor"; }
414 b->addBits(kNumProcessorFlags, (uint32_t)
fFlags,
"flags");
430 if (
fFlags & ProcessorFlags::kHasLocalCoords) {
431 fInstanceAttribs.emplace_back(
"translate_and_localrotate",
434 fInstanceAttribs.emplace_back(
437 fInstanceAttribs.emplace_back(
"translate_and_localrotate",
441 fColorAttrib = &fInstanceAttribs.push_back(
443 SkASSERT(fInstanceAttribs.size() <= kMaxInstanceAttribs);
445 fInstanceAttribs.size());
448 inline static constexpr Attribute kVertexAttribs[] = {
454 const ProcessorFlags
fFlags;
456 constexpr static int kMaxInstanceAttribs = 6;
465struct CoverageVertex {
479static constexpr CoverageVertex kVertexData[] = {
481 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1},
482 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1},
485 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,+1}}, 1, 1},
486 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,+1}}, 1, 1},
489 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{-1,0}}, 1, 1},
490 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{-1,0}}, 1, 1},
493 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,-1}}, 1, 1},
494 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,-1}}, 1, 1},
498 {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{-1,0}}, 0, 1},
499 {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{-1,0}}, 0, 1},
502 {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}, {{0,-1}}, 0, 1},
503 {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}, {{0,-1}}, 0, 1},
506 {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}, {{+1,0}}, 0, 1},
507 {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}, {{+1,0}}, 0, 1},
510 {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}, {{0,+1}}, 0, 1},
511 {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}, {{0,+1}}, 0, 1},
515 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{-1, 0}}, 0, 0},
516 {{{1,0,0,0}}, {{-1,-1}}, {{ 0,+1}}, {{+1, 0}}, 1, 0},
517 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,+1}}, 1, 0},
518 {{{1,0,0,0}}, {{-1,-1}}, {{+1, 0}}, {{ 0,-1}}, 0, 0},
519 {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}, {{-1,-1}}, 0, 0},
520 {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}, {{-1,-1}}, 0, 0},
523 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,-1}}, 0, 0},
524 {{{0,1,0,0}}, {{+1,-1}}, {{-1, 0}}, {{ 0,+1}}, 1, 0},
525 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{-1, 0}}, 1, 0},
526 {{{0,1,0,0}}, {{+1,-1}}, {{ 0,+1}}, {{+1, 0}}, 0, 0},
527 {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}, {{+1,-1}}, 0, 0},
528 {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}, {{+1,-1}}, 0, 0},
531 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{+1, 0}}, 0, 0},
532 {{{0,0,1,0}}, {{+1,+1}}, {{ 0,-1}}, {{-1, 0}}, 1, 0},
533 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,-1}}, 1, 0},
534 {{{0,0,1,0}}, {{+1,+1}}, {{-1, 0}}, {{ 0,+1}}, 0, 0},
535 {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}, {{+1,+1}}, 0, 0},
536 {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}, {{+1,+1}}, 0, 0},
539 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,+1}}, 0, 0},
540 {{{0,0,0,1}}, {{-1,+1}}, {{+1, 0}}, {{ 0,-1}}, 1, 0},
541 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{+1, 0}}, 1, 0},
542 {{{0,0,0,1}}, {{-1,+1}}, {{ 0,-1}}, {{-1, 0}}, 0, 0},
543 {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0},
544 {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}};
548static constexpr uint16_t kIndexData[] = {
591 this->createProgramInfo(
target);
596 if (VertexWriter instanceWriter =
target->makeVertexWriter(instanceStride, fInstanceCount,
597 &fInstanceBuffer, &fBaseInstance)) {
598 SkDEBUGCODE(
auto end = instanceWriter.mark(instanceStride * fInstanceCount));
599 for (Instance* i = fHeadInstance; i; i = i->fNext) {
600 auto [l, t, r,
b] = i->fRRect.rect();
605 m.setScaleTranslate((r - l)/2, (
b - t)/2, (l + r)/2, (t +
b)/2);
607 m.postConcat(i->fViewMatrix);
612 radiiX *= 2 / (r - l);
613 radiiY *= 2 / (
b - t);
615 instanceWriter << radiiX << radiiY
616 <<
m.getScaleX() <<
m.getSkewX() <<
m.getSkewY() <<
m.getScaleY()
617 <<
m.getTranslateX() <<
m.getTranslateY();
619 if (fProcessorFlags & ProcessorFlags::kHasLocalCoords) {
620 if (i->fLocalCoords.fType == LocalCoords::Type::kRect) {
621 instanceWriter << 0.f << 0.f
622 << i->fLocalCoords.fRect;
624 SkASSERT(i->fLocalCoords.fType == LocalCoords::Type::kMatrix);
626 const SkMatrix& localMatrix = i->fLocalCoords.fMatrix;
630 instanceWriter << v.
x() << u.
y()
631 << l0 << (l0.
x() + u.
x()) << (l0.
y() + v.
y());
635 instanceWriter << VertexColor(i->fColor, fProcessorFlags & ProcessorFlags::kWideColor);
644 kIndexData, gIndexBufferKey);
654class FillRRectOpImpl::Processor::Impl :
public ProgramImpl {
661 void onEmitCode(EmitArgs&
args, GrGPArgs* gpArgs)
override {
665 const auto& proc =
args.fGeomProc.cast<Processor>();
666 bool useHWDerivatives = (proc.fFlags & ProcessorFlags::kUseHWDerivatives);
668 SkASSERT(proc.vertexStride() ==
sizeof(CoverageVertex));
672 f->codeAppendf(
"half4 %s;",
args.fOutputColor);
681 (proc.fFlags & ProcessorFlags::kMSAAEnabled)
683 : (!(proc.
fFlags & ProcessorFlags::kFakeNonAA))
688 v->
codeAppend(
"float2 corner = corner_and_radius_outsets.xy;");
689 v->
codeAppend(
"float2 radius_outset = corner_and_radius_outsets.zw;");
690 v->
codeAppend(
"float2 aa_bloat_direction = aa_bloat_and_coverage.xy;");
691 v->
codeAppend(
"float is_linear_coverage = aa_bloat_and_coverage.w;");
694 v->
codeAppend(
"float2 pixellength = inversesqrt("
695 "float2(dot(skew.xz, skew.xz), dot(skew.yw, skew.yw)));");
696 v->
codeAppend(
"float4 normalized_axis_dirs = skew * pixellength.xyxy;");
697 v->
codeAppend(
"float2 axiswidths = (abs(normalized_axis_dirs.xy) + "
698 "abs(normalized_axis_dirs.zw));");
699 v->
codeAppend(
"float2 aa_bloatradius = axiswidths * pixellength * .5;");
702 v->
codeAppend(
"float4 radii_and_neighbors = radii_selector"
703 "* float4x4(radii_x, radii_y, radii_x.yxwz, radii_y.wzyx);");
704 v->
codeAppend(
"float2 radii = radii_and_neighbors.xy;");
705 v->
codeAppend(
"float2 neighbor_radii = radii_and_neighbors.zw;");
707 v->
codeAppend(
"float coverage_multiplier = 1;");
708 v->
codeAppend(
"if (any(greaterThan(aa_bloatradius, float2(1)))) {");
713 v->
codeAppend(
"corner = max(abs(corner), aa_bloatradius) * sign(corner);");
714 v->
codeAppend(
"coverage_multiplier = 1 / (max(aa_bloatradius.x, 1) * "
715 "max(aa_bloatradius.y, 1));");
722 v->
codeAppend(
"float coverage = aa_bloat_and_coverage.z;");
723 if (proc.fFlags & ProcessorFlags::kMSAAEnabled) {
725 v->
codeAppendf(
"coverage = (coverage - .5) * aa_bloat_multiplier + .5;");
728 v->
codeAppend(
"if (any(lessThan(radii, aa_bloatradius * 1.5))) {");
733 v->
codeAppend(
"aa_bloat_direction = sign(corner);");
735 v->
codeAppend(
"aa_bloat_direction = -aa_bloat_direction;");
742 v->
codeAppend(
"radii = clamp(radii, pixellength * 1.5, 2 - pixellength * 1.5);");
743 v->
codeAppend(
"neighbor_radii = clamp(neighbor_radii, pixellength * 1.5, "
744 "2 - pixellength * 1.5);");
746 v->
codeAppend(
"float2 spacing = 2 - radii - neighbor_radii;");
747 v->
codeAppend(
"float2 extra_pad = max(pixellength * .0625 - spacing, float2(0));");
754 "aa_bloat_direction * aa_bloatradius * aa_bloat_multiplier;");
755 v->
codeAppend(
"float2 vertexpos = corner + radius_outset * radii + aa_outset;");
762 v->
codeAppend(
"if (aa_bloat_direction.x != 0 && vertexpos.x * corner.x < 0) {");
763 v->
codeAppend(
"float backset = abs(vertexpos.x);");
766 "backset * sign(corner.y) * pixellength.y/pixellength.x;");
767 v->
codeAppend(
"coverage = (coverage - .5) * abs(corner.x) / "
768 "(abs(corner.x) + backset) + .5;");
770 v->
codeAppend(
"if (aa_bloat_direction.y != 0 && vertexpos.y * corner.y < 0) {");
771 v->
codeAppend(
"float backset = abs(vertexpos.y);");
774 "backset * sign(corner.x) * pixellength.x/pixellength.y;");
775 v->
codeAppend(
"coverage = (coverage - .5) * abs(corner.y) / "
776 "(abs(corner.y) + backset) + .5;");
781 v->
codeAppend(
"float2x2 skewmatrix = float2x2(skew.xy, skew.zw);");
782 v->
codeAppend(
"float2 devcoord = vertexpos * skewmatrix + translate_and_localrotate.xy;");
786 if (proc.fFlags & ProcessorFlags::kHasLocalCoords) {
789 v->
codeAppend(
"float2 T = vertexpos * .5 + .5;");
790 v->
codeAppend(
"float2 localcoord = localrect.xy * (1 - T) + "
791 "localrect.zw * T + "
792 "translate_and_localrotate.zw * T.yx;");
799 v->
codeAppend(
"if (0 != is_linear_coverage) {");
802 v->
codeAppendf(
"%s.xy = float2(0, coverage * coverage_multiplier);",
807 v->
codeAppend(
"float2 arccoord = 1 - abs(radius_outset) + aa_outset/radii * corner;");
811 v->
codeAppendf(
"%s.xy = float2(arccoord.x+1, arccoord.y);", arcCoord.
vsOut());
812 if (!useHWDerivatives) {
814 v->
codeAppendf(
"float2x2 derivatives = inverse(skewmatrix);");
815 v->
codeAppendf(
"%s.zw = derivatives * (arccoord/radii * 2);", arcCoord.
vsOut());
820 f->codeAppendf(
"float x_plus_1=%s.x, y=%s.y;", arcCoord.
fsIn(), arcCoord.
fsIn());
821 f->codeAppendf(
"half coverage;");
822 f->codeAppendf(
"if (0 == x_plus_1) {");
823 f->codeAppendf(
"coverage = half(y);");
824 f->codeAppendf(
"} else {");
825 f->codeAppendf(
"float fn = x_plus_1 * (x_plus_1 - 2);");
826 f->codeAppendf(
"fn = fma(y,y, fn);");
827 if (useHWDerivatives) {
828 f->codeAppendf(
"float fnwidth = fwidth(fn);");
831 f->codeAppendf(
"float gx=%s.z, gy=%s.w;", arcCoord.
fsIn(), arcCoord.
fsIn());
832 f->codeAppendf(
"float fnwidth = abs(gx) + abs(gy);");
834 f->codeAppendf(
"coverage = .5 - half(fn/fnwidth);");
835 if (proc.fFlags & ProcessorFlags::kMSAAEnabled) {
839 f->codeAppendf(
"coverage = clamp(coverage, 0, 1);");
840 if (!(proc.fFlags & ProcessorFlags::kMSAAEnabled)) {
844 if (proc.fFlags & ProcessorFlags::kFakeNonAA) {
845 f->codeAppendf(
"coverage = (coverage >= .5) ? 1 : 0;");
847 f->codeAppendf(
"half4 %s = half4(coverage);",
args.fOutputCoverage);
851std::unique_ptr<GrGeometryProcessor::ProgramImpl> FillRRectOpImpl::Processor::makeProgramImpl(
853 return std::make_unique<Impl>();
856void FillRRectOpImpl::onCreateProgramInfo(
const GrCaps* caps,
859 bool usesMSAASurface,
864 if (usesMSAASurface) {
865 fProcessorFlags |= ProcessorFlags::kMSAAEnabled;
868 fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, usesMSAASurface,
869 std::move(appliedClip), dstProxyView, gp,
875 if (!fInstanceBuffer || !fIndexBuffer || !fVertexBuffer) {
881 flushState->
bindBuffers(std::move(fIndexBuffer), std::move(fInstanceBuffer),
882 std::move(fVertexBuffer));
887bool can_use_hw_derivatives_with_coverage(
const skvx::float2& devScale,
890 if (devRadii[1] < devRadii[0]) {
891 devRadii = skvx::shuffle<1,0>(devRadii);
893 float minDevRadius = std::max(devRadii[0], 1.f);
896 return minDevRadius * minDevRadius * 5 > devRadii[1];
899bool can_use_hw_derivatives_with_coverage(
const skvx::float2& devScale,
901 return can_use_hw_derivatives_with_coverage(devScale,
skvx::float2::Load(&cornerRadii));
905bool can_use_hw_derivatives_with_coverage(
const GrShaderCaps& shaderCaps,
929 return can_use_hw_derivatives_with_coverage(devScale,
931 can_use_hw_derivatives_with_coverage(devScale,
936 for (
int i = 0; i < 4; ++i) {
938 if (!can_use_hw_derivatives_with_coverage(devScale,
rrect.
radii(corner))) {
945 SK_ABORT(
"Invalid round rect type.");
957 return FillRRectOpImpl::Make(ctx, arena, std::move(
paint), viewMatrix, rrect, localRect, aa);
967 return FillRRectOpImpl::Make(ctx, arena, std::move(
paint), viewMatrix, rrect, localMatrix, aa);