1 /* 2 * Copyright 2021 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 #ifndef SkCustomMesh_DEFINED 9 #define SkCustomMesh_DEFINED 10 11 #include "include/core/SkTypes.h" 12 13 #ifdef SK_ENABLE_SKSL 14 #include "include/core/SkColorSpace.h" 15 #include "include/core/SkImageInfo.h" 16 #include "include/core/SkRect.h" 17 #include "include/core/SkRefCnt.h" 18 #include "include/core/SkSpan.h" 19 #include "include/core/SkString.h" 20 21 #include <vector> 22 23 namespace SkSL { struct Program; } 24 25 /** 26 * A specification for custom meshes. Specifies the vertex buffer attributes and stride, the 27 * vertex program that produces a user-defined set of varyings, a fragment program that ingests 28 * the interpolated varyings and produces local coordinates and optionally a color. 29 * 30 * The signature of the vertex program must be: 31 * float2 main(Attributes, out Varyings) 32 * where the return value is a local position that will be transformed by SkCanvas's matrix. 33 * 34 * The signature of the fragment program must be either: 35 * (float2|void) main(Varyings) 36 * or 37 * (float2|void) main(Varyings, out (half4|float4) color) 38 * 39 * where the return value is the local coordinates that will be used to access SkShader. If the 40 * return type is void then the interpolated position from vertex shader return is used as the local 41 * coordinate. If the color variant is used it will be blended with SkShader (or SkPaint color in 42 * absence of a shader) using the SkBlender provided to the SkCanvas draw call. 43 */ 44 class SkCustomMeshSpecification : public SkNVRefCnt<SkCustomMeshSpecification> { 45 public: 46 /** These values are enforced when creating a specification. */ 47 static constexpr size_t kMaxStride = 1024; 48 static constexpr size_t kMaxAttributes = 8; 49 static constexpr size_t kStrideAlignment = 4; 50 static constexpr size_t kOffsetAlignment = 4; 51 static constexpr size_t kMaxVaryings = 6; 52 53 struct Attribute { 54 enum class Type : uint32_t { // CPU representation Shader Type 55 kFloat, // float float 56 kFloat2, // two floats float2 57 kFloat3, // three floats float3 58 kFloat4, // four floats float4 59 kUByte4_unorm, // four bytes half4 60 61 kLast = kUByte4_unorm 62 }; 63 Type type; 64 size_t offset; 65 SkString name; 66 }; 67 68 struct Varying { 69 enum class Type : uint32_t { 70 kFloat, // "float" 71 kFloat2, // "float2" 72 kFloat3, // "float3" 73 kFloat4, // "float4" 74 kHalf, // "half" 75 kHalf2, // "half2" 76 kHalf3, // "half3" 77 kHalf4, // "half4" 78 79 kLast = kHalf4 80 }; 81 Type type; 82 SkString name; 83 }; 84 85 ~SkCustomMeshSpecification(); 86 87 struct Result { 88 sk_sp<SkCustomMeshSpecification> specification; 89 SkString error; 90 }; 91 92 /** 93 * If successful the return is a specification and an empty error string. Otherwise, it is a 94 * null specification a non-empty error string. 95 * 96 * @param attributes The vertex attributes that will be consumed by 'vs'. Attributes need 97 * not be tightly packed but attribute offsets must be aligned to 98 * kOffsetAlignment and offset + size may not be greater than 99 * 'vertexStride'. At least one attribute is required. 100 * @param vertexStride The offset between successive attribute values. This must be aligned to 101 * kStrideAlignment. 102 * @param varyings The varyings that will be written by 'vs' and read by 'fs'. This may 103 * be empty. 104 * @param vs The vertex shader code that computes a vertex position and the varyings 105 * from the attributes. 106 * @param fs The fragment code that computes a local coordinate and optionally a 107 * color from the varyings. The local coordinate is used to sample 108 * SkShader. 109 * @param cs The colorspace of the color produced by 'fs'. Ignored if 'fs's main() 110 * function does not have a color out param. 111 * @param at The alpha type of the color produced by 'fs'. Ignored if 'fs's main() 112 * function does not have a color out param. Cannot be kUnknown. 113 */ 114 static Result Make(SkSpan<const Attribute> attributes, 115 size_t vertexStride, 116 SkSpan<const Varying> varyings, 117 const SkString& vs, 118 const SkString& fs, 119 sk_sp<SkColorSpace> cs = SkColorSpace::MakeSRGB(), 120 SkAlphaType at = kPremul_SkAlphaType); 121 attributes()122 SkSpan<const Attribute> attributes() const { return SkMakeSpan(fAttributes); } 123 stride()124 size_t stride() const { return fStride; } 125 126 private: 127 friend struct SkCustomMeshSpecificationPriv; 128 129 enum class ColorType { 130 kNone, 131 kHalf4, 132 kFloat4, 133 }; 134 135 static Result MakeFromSourceWithStructs(SkSpan<const Attribute> attributes, 136 size_t stride, 137 SkSpan<const Varying> varyings, 138 const SkString& vs, 139 const SkString& fs, 140 sk_sp<SkColorSpace> cs, 141 SkAlphaType at); 142 143 SkCustomMeshSpecification(SkSpan<const Attribute>, 144 size_t, 145 SkSpan<const Varying>, 146 std::unique_ptr<SkSL::Program>, 147 std::unique_ptr<SkSL::Program>, 148 ColorType, 149 bool hasLocalCoords, 150 sk_sp<SkColorSpace>, 151 SkAlphaType); 152 153 SkCustomMeshSpecification(const SkCustomMeshSpecification&) = delete; 154 SkCustomMeshSpecification(SkCustomMeshSpecification&&) = delete; 155 156 SkCustomMeshSpecification& operator=(const SkCustomMeshSpecification&) = delete; 157 SkCustomMeshSpecification& operator=(SkCustomMeshSpecification&&) = delete; 158 159 const std::vector<Attribute> fAttributes; 160 const std::vector<Varying> fVaryings; 161 std::unique_ptr<SkSL::Program> fVS; 162 std::unique_ptr<SkSL::Program> fFS; 163 size_t fStride; 164 uint32_t fHash; 165 ColorType fColorType; 166 bool fHasLocalCoords; 167 sk_sp<SkColorSpace> fColorSpace; 168 SkAlphaType fAlphaType; 169 }; 170 171 /** 172 * This is a placeholder object. We will want something that allows the client to incrementally 173 * update the mesh that can be synchronized with the GPU backend without requiring extra copies. 174 * 175 * A buffer of vertices, a topology, optionally indices, and a compatible SkCustomMeshSpecification. 176 * The data in 'vb' is expected to contain the attributes described in 'spec' for 'vcount' vertices. 177 * The size of the buffer must be at least spec->stride()*vcount (even if vertex attributes contains 178 * pad at the end of the stride). If 'bounds' does not contain all points output by 'spec''s vertex 179 * program when applied to the vertices in 'vb' a draw of the custom mesh produces undefined 180 * results. 181 * 182 * If indices is null then then 'icount' must be <= 0. 'vcount' vertices will be selected from 'vb' 183 * to create the topology indicated by 'mode'. 184 * 185 * If indices is not null then icount must be >= 3. 'vb' will be indexed by 'icount' successive 186 * values in 'indices' to create the topology indicated by 'mode'. The values in 'indices' must be 187 * less than 'vcount' 188 */ 189 struct SkCustomMesh { 190 enum class Mode { kTriangles, kTriangleStrip }; 191 sk_sp<SkCustomMeshSpecification> spec; 192 Mode mode = Mode::kTriangles; 193 SkRect bounds = SkRect::MakeEmpty(); 194 const void* vb = nullptr; 195 int vcount = 0; 196 const uint16_t* indices = nullptr; 197 int icount = 0; 198 }; 199 200 #endif // SK_ENABLE_SKSL 201 202 #endif 203