| /* | |
| * Copyright 2022 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "src/gpu/graphite/render/CoverBoundsRenderStep.h" | |
| #include "include/core/SkM44.h" | |
| #include "include/private/SkDebug.h" | |
| #include "include/private/SkEnumBitMask.h" | |
| #include "src/core/SkSLTypeShared.h" | |
| #include "src/core/SkVx.h" | |
| #include "src/gpu/BufferWriter.h" | |
| #include "src/gpu/graphite/Attribute.h" | |
| #include "src/gpu/graphite/DrawOrder.h" | |
| #include "src/gpu/graphite/DrawParams.h" | |
| #include "src/gpu/graphite/DrawTypes.h" | |
| #include "src/gpu/graphite/DrawWriter.h" | |
| #include "src/gpu/graphite/PipelineData.h" | |
| #include "src/gpu/graphite/geom/Geometry.h" | |
| #include "src/gpu/graphite/geom/Rect.h" | |
| #include "src/gpu/graphite/geom/Shape.h" | |
| #include "src/gpu/graphite/geom/Transform.h" | |
| #include "src/gpu/graphite/render/CommonDepthStencilSettings.h" | |
| namespace skgpu::graphite { | |
| CoverBoundsRenderStep::CoverBoundsRenderStep(Layout layout, | |
| RenderStep::RenderStepID renderStepID, | |
| StencilSettings stencilSettings) | |
| : RenderStep(layout, | |
| renderStepID, | |
| Flags::kPerformsShading | Flags::kNoSelfIntersections | |
| | Flags::kAppendInstances | |
| | Flags::kInverseFillsScissor, | |
| /*uniforms=*/{}, | |
| PrimitiveType::kTriangleStrip, | |
| stencilSettings, | |
| /*staticAttrs=*/ {}, | |
| /*appendAttrs=*/{{{"bounds", VertexAttribType::kFloat4, SkSLType::kFloat4}, | |
| {"depth", VertexAttribType::kFloat, SkSLType::kFloat}, | |
| {"ssboIndex", VertexAttribType::kUInt, SkSLType::kUInt}, | |
| {"mat0", VertexAttribType::kFloat3, SkSLType::kFloat3}, | |
| {"mat1", VertexAttribType::kFloat3, SkSLType::kFloat3}, | |
| {"mat2", VertexAttribType::kFloat3, SkSLType::kFloat3}}}, | |
| /*storageUniforms=*/{}) {} | |
| CoverBoundsRenderStep::~CoverBoundsRenderStep() {} | |
| std::unique_ptr<CoverBoundsRenderStep> CoverBoundsRenderStep::NonAAInnerFill(Layout layout) { | |
| return std::unique_ptr<CoverBoundsRenderStep>(new CoverBoundsRenderStep( | |
| layout, RenderStepID::kCoverBounds_NonAAFill, /*stencilSettings=*/{})); | |
| } | |
| std::unique_ptr<CoverBoundsRenderStep> CoverBoundsRenderStep::StencilCover( | |
| Layout layout, bool inverseFill) { | |
| RenderStepID id = inverseFill ? RenderStepID::kCoverBounds_InverseCover | |
| : RenderStepID::kCoverBounds_RegularCover; | |
| StencilSettings stencil = inverseFill ? kInverseCoverPass : kRegularCoverPass; | |
| return std::unique_ptr<CoverBoundsRenderStep>(new CoverBoundsRenderStep(layout, id, stencil)); | |
| } | |
| std::string CoverBoundsRenderStep::vertexSkSL(const RootNodesInfo&) const { | |
| // Returns the body of a vertex function, which must define a float4 devPosition variable and | |
| // must write to an already-defined float2 stepLocalCoords variable. | |
| return "float4 devPosition = cover_bounds_vertex_fn(" | |
| "float2(sk_VertexID / 2, sk_VertexID % 2), " | |
| "bounds, depth, float3x3(mat0, mat1, mat2), " | |
| "stepLocalCoords);\n"; | |
| } | |
| void CoverBoundsRenderStep::writeVertices(DrawWriter* writer, | |
| StorageContext* /*storageContext*/, | |
| const DrawParams& params, | |
| uint32_t ssboIndex) const { | |
| // Each instance is 4 vertices, forming 2 triangles from a single triangle strip, so no indices | |
| // are needed. sk_VertexID is used to place vertex positions, so no vertex buffer is needed. | |
| DrawWriter::Instances instances{*writer, {}, {}, 4}; | |
| skvx::float4 bounds; | |
| if (params.geometry().isShape() && params.geometry().shape().inverted()) { | |
| // Normally all bounding boxes are sorted such that l<r and t<b. We upload an inverted | |
| // rectangle [r,b,l,t] when it's an inverse fill to encode that the bounds are already in | |
| // device space and then the VS will use the inverse of the transform to compute local | |
| // coordinates. | |
| bounds = skvx::shuffle</*R*/2, /*B*/3, /*L*/0, /*T*/1>( | |
| skvx::cast<float>(skvx::int4::Load(¶ms.scissor()))); | |
| } else { | |
| // If there's a stroke style, the bounding box needs to increase by the stroke radius. | |
| // This is not necessary for inverted fills since that maximally covers the clip. | |
| bounds = params.styledBounds().ltrb(); | |
| } | |
| // Since the local coords always have Z=0, we can discard the 3rd row and column of the matrix. | |
| const SkM44& m = params.transform().matrix(); | |
| instances.append(1) << bounds << params.order().depthAsFloat() << ssboIndex | |
| << m.rc(0,0) << m.rc(1,0) << m.rc(3,0) | |
| << m.rc(0,1) << m.rc(1,1) << m.rc(3,1) | |
| << m.rc(0,3) << m.rc(1,3) << m.rc(3,3); | |
| } | |
| void CoverBoundsRenderStep::writeUniformsAndTextures(const DrawParams&, | |
| PipelineDataGatherer* gatherer) const { | |
| // All data is uploaded as instance attributes, so no uniforms are needed. | |
| SkDEBUGCODE(gatherer->checkRewind()); | |
| } | |
| } // namespace skgpu::graphite |