| /* | |
| * 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/VerticesRenderStep.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkVertices.h" | |
| #include "include/private/base/SkAssert.h" | |
| #include "include/private/base/SkDebug.h" | |
| #include "include/private/base/SkPoint_impl.h" | |
| #include "include/private/base/SkSpan_impl.h" | |
| #include "include/private/base/SkTo.h" | |
| #include "src/base/SkEnumBitMask.h" | |
| #include "src/core/SkSLTypeShared.h" | |
| #include "src/core/SkVertState.h" | |
| #include "src/core/SkVerticesPriv.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/Transform.h" | |
| #include "src/gpu/graphite/render/CommonDepthStencilSettings.h" | |
| #include <cstdint> | |
| namespace skgpu::graphite { | |
| namespace { | |
| static constexpr Attribute kPositionAttr = | |
| {"position", VertexAttribType::kFloat2, SkSLType::kFloat2}; | |
| static constexpr Attribute kTexCoordAttr = | |
| {"texCoords", VertexAttribType::kFloat2, SkSLType::kFloat2}; | |
| static constexpr Attribute kColorAttr = | |
| {"vertColor", VertexAttribType::kUByte4_norm, SkSLType::kHalf4}; | |
| static constexpr Attribute kSsboIndexAttr = | |
| {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2}; | |
| static constexpr Attribute kAttributePositionOnly[] = | |
| {kPositionAttr, kSsboIndexAttr}; | |
| static constexpr Attribute kAttributeColor[] = | |
| {kPositionAttr, kColorAttr, kSsboIndexAttr}; | |
| static constexpr Attribute kAttributeTexCoords[] = | |
| {kPositionAttr, kTexCoordAttr, kSsboIndexAttr}; | |
| static constexpr Attribute kAttributeColorAndTexCoords[] = | |
| {kPositionAttr, kColorAttr, kTexCoordAttr, kSsboIndexAttr}; | |
| static constexpr SkSpan<const Attribute> kAttributes[4] = { | |
| kAttributePositionOnly, | |
| kAttributeColor, | |
| kAttributeTexCoords, | |
| kAttributeColorAndTexCoords, | |
| }; | |
| static constexpr Varying kVaryingColor[] = | |
| {{"color", SkSLType::kHalf4}}; | |
| static constexpr SkSpan<const Varying> kVaryings[2] = { | |
| /*none*/ {}, | |
| /*color*/ kVaryingColor | |
| }; | |
| RenderStep::RenderStepID variant_id(PrimitiveType type, bool hasColor, bool hasTexCoords) { | |
| if (type == PrimitiveType::kTriangles) { | |
| if (hasColor) { | |
| if (hasTexCoords) { | |
| return RenderStep::RenderStepID::kVertices_TrisColorTexCoords; | |
| } else { | |
| return RenderStep::RenderStepID::kVertices_TrisColor; | |
| } | |
| } else { | |
| if (hasTexCoords) { | |
| return RenderStep::RenderStepID::kVertices_TrisTexCoords; | |
| } else { | |
| return RenderStep::RenderStepID::kVertices_Tris; | |
| } | |
| } | |
| } else { | |
| SkASSERT(type == PrimitiveType::kTriangleStrip); | |
| if (hasColor) { | |
| if (hasTexCoords) { | |
| return RenderStep::RenderStepID::kVertices_TristripsColorTexCoords; | |
| } else { | |
| return RenderStep::RenderStepID::kVertices_TristripsColor; | |
| } | |
| } else { | |
| if (hasTexCoords) { | |
| return RenderStep::RenderStepID::kVertices_TristripsTexCoords; | |
| } else { | |
| return RenderStep::RenderStepID::kVertices_Tristrips; | |
| } | |
| } | |
| } | |
| } | |
| } // namespace | |
| VerticesRenderStep::VerticesRenderStep(PrimitiveType type, bool hasColor, bool hasTexCoords) | |
| : RenderStep(variant_id(type, hasColor, hasTexCoords), | |
| (hasColor ? Flags::kEmitsPrimitiveColor : Flags::kNone) | | |
| Flags::kPerformsShading | Flags::kAppendVertices, | |
| /*uniforms=*/{{"localToDevice", SkSLType::kFloat4x4}, | |
| {"depth", SkSLType::kFloat}}, | |
| type, | |
| kDirectDepthLEqualPass, | |
| /*staticAttrs=*/ {}, | |
| /*appendAttrs=*/kAttributes[2*hasTexCoords + hasColor], | |
| /*varyings=*/ kVaryings[hasColor]) | |
| , fHasColor(hasColor) | |
| , fHasTexCoords(hasTexCoords) {} | |
| VerticesRenderStep::~VerticesRenderStep() {} | |
| std::string VerticesRenderStep::vertexSkSL() const { | |
| if (fHasColor && fHasTexCoords) { | |
| return | |
| "color = half4(vertColor.bgr * vertColor.a, vertColor.a);\n" | |
| "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n" | |
| "devPosition.z = depth;\n" | |
| "stepLocalCoords = texCoords;\n"; | |
| } else if (fHasTexCoords) { | |
| return | |
| "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n" | |
| "devPosition.z = depth;\n" | |
| "stepLocalCoords = texCoords;\n"; | |
| } else if (fHasColor) { | |
| return | |
| "color = half4(vertColor.bgr * vertColor.a, vertColor.a);\n" | |
| "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n" | |
| "devPosition.z = depth;\n" | |
| "stepLocalCoords = position;\n"; | |
| } else { | |
| return | |
| "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n" | |
| "devPosition.z = depth;\n" | |
| "stepLocalCoords = position;\n"; | |
| } | |
| } | |
| const char* VerticesRenderStep::fragmentColorSkSL() const { | |
| if (fHasColor) { | |
| return "primitiveColor = color;\n"; | |
| } else { | |
| return ""; | |
| } | |
| } | |
| void VerticesRenderStep::writeVertices(DrawWriter* writer, | |
| const DrawParams& params, | |
| skvx::uint2 ssboIndices) const { | |
| SkVerticesPriv info(params.geometry().vertices()->priv()); | |
| const int vertexCount = info.vertexCount(); | |
| const int indexCount = info.indexCount(); | |
| const SkPoint* positions = info.positions(); | |
| const uint16_t* indices = info.indices(); | |
| const SkColor* colors = info.colors(); | |
| const SkPoint* texCoords = info.texCoords(); | |
| // This should always be the case if the Renderer was chosen appropriately, but the vertex | |
| // writing loop is set up in such a way that if the shader expects color or tex coords and they | |
| // are missing, it will just read 0s, so release builds are safe. | |
| SkASSERT(fHasColor == SkToBool(colors)); | |
| SkASSERT(fHasTexCoords == SkToBool(texCoords)); | |
| // TODO: We could access the writer's DrawBufferManager and upload the SkVertices index buffer | |
| // but that would require we manually manage the VertexWriter for interleaving the position, | |
| // color, and tex coord arrays together. This wouldn't be so bad if we let ::Vertices() take | |
| // a CPU index buffer that indexes into the accumulated vertex data (and handles offsetting for | |
| // merged drawIndexed calls), or if we could bind multiple attribute sources and copy the | |
| // position/color/texCoord data separately in bulk w/o using an Appender. | |
| DrawWriter::Vertices verts{*writer}; | |
| verts.reserve(indices ? indexCount : vertexCount); | |
| VertState state(vertexCount, indices, indexCount); | |
| VertState::Proc vertProc = state.chooseProc(info.mode()); | |
| while (vertProc(&state)) { | |
| verts.append(3) << positions[state.f0] | |
| << VertexWriter::If(fHasColor, colors ? colors[state.f0] | |
| : SK_ColorTRANSPARENT) | |
| << VertexWriter::If(fHasTexCoords, texCoords ? texCoords[state.f0] | |
| : SkPoint{0.f, 0.f}) | |
| << ssboIndices | |
| << positions[state.f1] | |
| << VertexWriter::If(fHasColor, colors ? colors[state.f1] | |
| : SK_ColorTRANSPARENT) | |
| << VertexWriter::If(fHasTexCoords, texCoords ? texCoords[state.f1] | |
| : SkPoint{0.f, 0.f}) | |
| << ssboIndices | |
| << positions[state.f2] | |
| << VertexWriter::If(fHasColor, colors ? colors[state.f2] | |
| : SK_ColorTRANSPARENT) | |
| << VertexWriter::If(fHasTexCoords, texCoords ? texCoords[state.f2] | |
| : SkPoint{0.f, 0.f}) | |
| << ssboIndices; | |
| } | |
| } | |
| void VerticesRenderStep::writeUniformsAndTextures(const DrawParams& params, | |
| PipelineDataGatherer* gatherer) const { | |
| // Vertices are transformed on the GPU. Store PaintDepth as a uniform to avoid copying the | |
| // same depth for each vertex. | |
| SkDEBUGCODE(gatherer->checkRewind()); | |
| SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, this->uniforms());) | |
| gatherer->write(params.transform().matrix()); | |
| gatherer->write(params.order().depthAsFloat()); | |
| } | |
| } // namespace skgpu::graphite |