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 SkMeshPriv_DEFINED
9 #define SkMeshPriv_DEFINED
10
11 #include "include/core/SkMesh.h"
12
13 #ifdef SK_ENABLE_SKSL
14 #include "include/core/SkData.h"
15 #include "src/core/SkSLTypeShared.h"
16
17 #if defined(SK_GANESH)
18 #include "include/gpu/GrDirectContext.h"
19 #include "include/private/gpu/ganesh/GrTypesPriv.h"
20 #include "src/gpu/ganesh/GrDirectContextPriv.h"
21 #include "src/gpu/ganesh/GrDrawingManager.h"
22 #include "src/gpu/ganesh/GrGpuBuffer.h"
23 #include "src/gpu/ganesh/GrResourceCache.h"
24 #include "src/gpu/ganesh/GrResourceProvider.h"
25 #endif
26
27 struct SkMeshSpecificationPriv {
28 using Varying = SkMeshSpecification::Varying;
29 using Attribute = SkMeshSpecification::Attribute;
30 using ColorType = SkMeshSpecification::ColorType;
31
VaryingsSkMeshSpecificationPriv32 static SkSpan<const Varying> Varyings(const SkMeshSpecification& spec) {
33 return SkSpan(spec.fVaryings);
34 }
35
VSSkMeshSpecificationPriv36 static const SkSL::Program* VS(const SkMeshSpecification& spec) { return spec.fVS.get(); }
FSSkMeshSpecificationPriv37 static const SkSL::Program* FS(const SkMeshSpecification& spec) { return spec.fFS.get(); }
38
HashSkMeshSpecificationPriv39 static int Hash(const SkMeshSpecification& spec) { return spec.fHash; }
40
GetColorTypeSkMeshSpecificationPriv41 static ColorType GetColorType(const SkMeshSpecification& spec) { return spec.fColorType; }
HasColorsSkMeshSpecificationPriv42 static bool HasColors(const SkMeshSpecification& spec) {
43 return GetColorType(spec) != ColorType::kNone;
44 }
45
ColorSpaceSkMeshSpecificationPriv46 static SkColorSpace* ColorSpace(const SkMeshSpecification& spec) {
47 return spec.fColorSpace.get();
48 }
49
AlphaTypeSkMeshSpecificationPriv50 static SkAlphaType AlphaType(const SkMeshSpecification& spec) { return spec.fAlphaType; }
51
VaryingTypeAsSLTypeSkMeshSpecificationPriv52 static SkSLType VaryingTypeAsSLType(Varying::Type type) {
53 switch (type) {
54 case Varying::Type::kFloat: return SkSLType::kFloat;
55 case Varying::Type::kFloat2: return SkSLType::kFloat2;
56 case Varying::Type::kFloat3: return SkSLType::kFloat3;
57 case Varying::Type::kFloat4: return SkSLType::kFloat4;
58 case Varying::Type::kHalf: return SkSLType::kHalf;
59 case Varying::Type::kHalf2: return SkSLType::kHalf2;
60 case Varying::Type::kHalf3: return SkSLType::kHalf3;
61 case Varying::Type::kHalf4: return SkSLType::kHalf4;
62 }
63 SkUNREACHABLE;
64 }
65
66 #if defined(SK_GANESH)
AttrTypeAsVertexAttribTypeSkMeshSpecificationPriv67 static GrVertexAttribType AttrTypeAsVertexAttribType(Attribute::Type type) {
68 switch (type) {
69 case Attribute::Type::kFloat: return kFloat_GrVertexAttribType;
70 case Attribute::Type::kFloat2: return kFloat2_GrVertexAttribType;
71 case Attribute::Type::kFloat3: return kFloat3_GrVertexAttribType;
72 case Attribute::Type::kFloat4: return kFloat4_GrVertexAttribType;
73 case Attribute::Type::kUByte4_unorm: return kUByte4_norm_GrVertexAttribType;
74 }
75 SkUNREACHABLE;
76 }
77 #endif
78
AttrTypeAsSLTypeSkMeshSpecificationPriv79 static SkSLType AttrTypeAsSLType(Attribute::Type type) {
80 switch (type) {
81 case Attribute::Type::kFloat: return SkSLType::kFloat;
82 case Attribute::Type::kFloat2: return SkSLType::kFloat2;
83 case Attribute::Type::kFloat3: return SkSLType::kFloat3;
84 case Attribute::Type::kFloat4: return SkSLType::kFloat4;
85 case Attribute::Type::kUByte4_unorm: return SkSLType::kHalf4;
86 }
87 SkUNREACHABLE;
88 }
89
PassthroughLocalCoordsVaryingIndexSkMeshSpecificationPriv90 static int PassthroughLocalCoordsVaryingIndex(const SkMeshSpecification& spec) {
91 return spec.fPassthroughLocalCoordsVaryingIndex;
92 }
93
94 /**
95 * A varying is dead if it is never referenced OR it is only referenced as a passthrough for
96 * local coordinates. In the latter case it's index will returned as
97 * PassthroughLocalCoordsVaryingIndex. Our analysis is not very sophisticated so this is
98 * determined conservatively.
99 */
VaryingIsDeadSkMeshSpecificationPriv100 static bool VaryingIsDead(const SkMeshSpecification& spec, int v) {
101 SkASSERT(v >= 0 && SkToSizeT(v) < spec.fVaryings.size());
102 return (1 << v) & spec.fDeadVaryingMask;
103 }
104 };
105
106 struct SkMeshPriv {
107 class Buffer {
108 public:
109 virtual ~Buffer() = 0;
110
111 Buffer() = default;
112 Buffer(const Buffer&) = delete;
113
114 Buffer& operator=(const Buffer&) = delete;
115
peekSkMeshPriv116 virtual const void* peek() const { return nullptr; }
117
118 #if defined(SK_GANESH)
asGpuBufferSkMeshPriv119 virtual sk_sp<const GrGpuBuffer> asGpuBuffer() const { return nullptr; }
120 #endif
121 };
122
123 class IB : public Buffer, public SkMesh::IndexBuffer {};
124 class VB : public Buffer, public SkMesh::VertexBuffer {};
125
126 template <typename Base> class CpuBuffer final : public Base {
127 public:
128 ~CpuBuffer() override = default;
129
130 static sk_sp<Base> Make(const void* data, size_t size);
131
peekSkMeshPriv132 const void* peek() const override { return fData->data(); }
133
sizeSkMeshPriv134 size_t size() const override { return fData->size(); }
135
136 private:
CpuBufferSkMeshPriv137 CpuBuffer(sk_sp<SkData> data) : fData(std::move(data)) {}
138
139 bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) override;
140
141 sk_sp<SkData> fData;
142 };
143
144 using CpuIndexBuffer = CpuBuffer<IB>;
145 using CpuVertexBuffer = CpuBuffer<VB>;
146
147 #if defined(SK_GANESH)
148 template <typename Base, GrGpuBufferType> class GpuBuffer final : public Base {
149 public:
150 GpuBuffer() = default;
151
152 ~GpuBuffer() override;
153
154 static sk_sp<Base> Make(GrDirectContext*, const void* data, size_t size);
155
asGpuBufferSkMeshPriv156 sk_sp<const GrGpuBuffer> asGpuBuffer() const override { return fBuffer; }
157
sizeSkMeshPriv158 size_t size() const override { return fBuffer->size(); }
159
160 private:
161 bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) override;
162
163 sk_sp<GrGpuBuffer> fBuffer;
164 GrDirectContext::DirectContextID fContextID;
165 };
166
167 using GpuIndexBuffer = GpuBuffer<IB, GrGpuBufferType::kIndex >;
168 using GpuVertexBuffer = GpuBuffer<VB, GrGpuBufferType::kVertex>;
169 #endif // defined(SK_GANESH)
170
171 private:
172 #if defined(SK_GANESH)
173 static bool UpdateGpuBuffer(GrDirectContext*,
174 sk_sp<GrGpuBuffer>,
175 const void*,
176 size_t offset,
177 size_t size);
178 #endif
179 };
180
181 inline SkMeshPriv::Buffer::~Buffer() = default;
182
Make(const void * data,size_t size)183 template <typename Base> sk_sp<Base> SkMeshPriv::CpuBuffer<Base>::Make(const void* data,
184 size_t size) {
185 SkASSERT(size);
186 sk_sp<SkData> storage;
187 if (data) {
188 storage = SkData::MakeWithCopy(data, size);
189 } else {
190 storage = SkData::MakeZeroInitialized(size);
191 }
192 return sk_sp<Base>(new CpuBuffer<Base>(std::move(storage)));
193 }
194
onUpdate(GrDirectContext * dc,const void * data,size_t offset,size_t size)195 template <typename Base> bool SkMeshPriv::CpuBuffer<Base>::onUpdate(GrDirectContext* dc,
196 const void* data,
197 size_t offset,
198 size_t size) {
199 if (dc) {
200 return false;
201 }
202 std::memcpy(SkTAddOffset<void>(fData->writable_data(), offset), data, size);
203 return true;
204 }
205
206 #if defined(SK_GANESH)
207
~GpuBuffer()208 template <typename Base, GrGpuBufferType Type> SkMeshPriv::GpuBuffer<Base, Type>::~GpuBuffer() {
209 GrResourceCache::ReturnResourceFromThread(std::move(fBuffer), fContextID);
210 }
211
212 template <typename Base, GrGpuBufferType Type>
Make(GrDirectContext * dc,const void * data,size_t size)213 sk_sp<Base> SkMeshPriv::GpuBuffer<Base, Type>::Make(GrDirectContext* dc,
214 const void* data,
215 size_t size) {
216 SkASSERT(dc);
217
218 sk_sp<GrGpuBuffer> buffer = dc->priv().resourceProvider()->createBuffer(
219 size,
220 Type,
221 kStatic_GrAccessPattern,
222 data ? GrResourceProvider::ZeroInit::kNo : GrResourceProvider::ZeroInit::kYes);
223 if (!buffer) {
224 return nullptr;
225 }
226
227 if (data && !buffer->updateData(data, 0, size, /*preserve=*/false)) {
228 return nullptr;
229 }
230
231 auto result = new GpuBuffer;
232 result->fBuffer = std::move(buffer);
233 result->fContextID = dc->directContextID();
234 return sk_sp<Base>(result);
235 }
236
237
238 template <typename Base, GrGpuBufferType Type>
onUpdate(GrDirectContext * dc,const void * data,size_t offset,size_t size)239 bool SkMeshPriv::GpuBuffer<Base, Type>::onUpdate(GrDirectContext* dc,
240 const void* data,
241 size_t offset,
242 size_t size) {
243 return UpdateGpuBuffer(dc, fBuffer, data, offset, size);
244 }
245
246 #endif // defined(SK_GANESH)
247
248 #endif // SK_ENABLE_SKSL
249
250 #endif
251