1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/graphite/render/CoverBoundsRenderStep.h"
9
10 #include "src/base/SkVx.h"
11 #include "src/gpu/graphite/DrawParams.h"
12 #include "src/gpu/graphite/DrawWriter.h"
13 #include "src/gpu/graphite/render/CommonDepthStencilSettings.h"
14
15 namespace skgpu::graphite {
16
CoverBoundsRenderStep(bool inverseFill)17 CoverBoundsRenderStep::CoverBoundsRenderStep(bool inverseFill)
18 : RenderStep("CoverBoundsRenderStep",
19 inverseFill ? "inverse" : "regular",
20 Flags::kPerformsShading,
21 /*uniforms=*/{},
22 PrimitiveType::kTriangleStrip,
23 inverseFill ? kInverseCoverPass : kRegularCoverPass,
24 /*vertexAttrs=*/{{"position",
25 VertexAttribType::kFloat4,
26 SkSLType::kFloat4}},
27 /*instanceAttrs=*/{{"bounds", VertexAttribType::kFloat4, SkSLType::kFloat4},
28 {"depth", VertexAttribType::kFloat, SkSLType::kFloat},
29 {"ssboIndex", VertexAttribType::kInt, SkSLType::kInt},
30 {"mat0", VertexAttribType::kFloat3, SkSLType::kFloat3},
31 {"mat1", VertexAttribType::kFloat3, SkSLType::kFloat3},
32 {"mat2", VertexAttribType::kFloat3, SkSLType::kFloat3}})
33 , fInverseFill(inverseFill) {}
34
~CoverBoundsRenderStep()35 CoverBoundsRenderStep::~CoverBoundsRenderStep() {}
36
vertexSkSL() const37 std::string CoverBoundsRenderStep::vertexSkSL() const {
38 return R"(
39 float3x3 matrix = float3x3(mat0, mat1, mat2);
40 float2 corner = float2(float(sk_VertexID / 2), float(sk_VertexID % 2));
41
42 float4 devPosition;
43 if (bounds.L <= bounds.R && bounds.T <= bounds.B) {
44 // A regular fill
45 corner = (1.0 - corner) * bounds.LT + corner * bounds.RB;
46 float3 devCorner = matrix * corner.xy1;
47 devPosition = float4(devCorner.xy, depth, devCorner.z);
48 stepLocalCoords = corner;
49 } else {
50 // An inverse fill
51 corner = corner * bounds.LT + (1.0 - corner) * bounds.RB;
52 devPosition = float4(corner, depth, 1.0);
53 // TODO: Support float3 local coordinates if the matrix has perspective so that W
54 // is interpolated correctly to the fragment shader.
55 float3 localCoords = matrix * corner.xy1;
56 stepLocalCoords = localCoords.xy / localCoords.z;
57 }
58 )";
59 }
60
writeVertices(DrawWriter * writer,const DrawParams & params,int ssboIndex) const61 void CoverBoundsRenderStep::writeVertices(DrawWriter* writer,
62 const DrawParams& params,
63 int ssboIndex) const {
64 // Each instance is 4 vertices, forming 2 triangles from a single triangle strip, so no indices
65 // are needed. sk_VertexID is used to place vertex positions, so no vertex buffer is needed.
66 DrawWriter::Instances instances{*writer, {}, {}, 4};
67
68 skvx::float4 bounds;
69 const SkM44* m;
70 if (fInverseFill) {
71 // Normally all bounding boxes are sorted such that l<r and t<b. We upload an inverted
72 // rectangle [r,b,l,t] when it's an inverse fill to encode that the bounds are already in
73 // device space and then use the inverse of the transform to compute local coordinates.
74 bounds = skvx::shuffle</*R*/2, /*B*/3, /*L*/0, /*T*/1>(
75 skvx::cast<float>(skvx::int4::Load(¶ms.clip().scissor())));
76 m = ¶ms.transform().inverse();
77 } else {
78 bounds = params.geometry().bounds().ltrb();
79 m = ¶ms.transform().matrix();
80 }
81
82 // Since the local coords always have Z=0, we can discard the 3rd row and column of the matrix.
83 instances.append(1) << bounds << params.order().depthAsFloat() << ssboIndex
84 << m->rc(0,0) << m->rc(1,0) << m->rc(3,0)
85 << m->rc(0,1) << m->rc(1,1) << m->rc(3,1)
86 << m->rc(0,3) << m->rc(1,3) << m->rc(3,3);
87 }
88
writeUniformsAndTextures(const DrawParams &,PipelineDataGatherer *) const89 void CoverBoundsRenderStep::writeUniformsAndTextures(const DrawParams&,
90 PipelineDataGatherer*) const {
91 // All data is uploaded as instance attributes, so no uniforms are needed.
92 }
93
94 } // namespace skgpu::graphite
95