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 skgpu_GraphicsPipelineDesc_DEFINED
9 #define skgpu_GraphicsPipelineDesc_DEFINED
10
11 #include "include/core/SkTypes.h"
12
13 #include "experimental/graphite/src/DrawTypes.h"
14 #include "include/private/SkTArray.h"
15
16 namespace skgpu {
17
18 /**
19 * GraphicsPipelineDesc represents the state needed to create a backend specific GraphicsPipeline,
20 * minus the target-specific properties that can be inferred from the DrawPass and RenderPassTask.
21 */
22 class GraphicsPipelineDesc {
23 public:
24 GraphicsPipelineDesc();
25
26 /** Describes a vertex or instance attribute. */
27 class Attribute {
28 public:
29 constexpr Attribute() = default;
Attribute(const char * name,VertexAttribType cpuType,SLType gpuType)30 constexpr Attribute(const char* name,
31 VertexAttribType cpuType,
32 SLType gpuType)
33 : fName(name), fCPUType(cpuType), fGPUType(gpuType) {
34 SkASSERT(name && gpuType != SLType::kVoid);
35 }
36 constexpr Attribute(const Attribute&) = default;
37
38 Attribute& operator=(const Attribute&) = default;
39
isInitialized()40 constexpr bool isInitialized() const { return fGPUType != SLType::kVoid; }
41
name()42 constexpr const char* name() const { return fName; }
cpuType()43 constexpr VertexAttribType cpuType() const { return fCPUType; }
gpuType()44 constexpr SLType gpuType() const { return fGPUType; }
45
46 inline constexpr size_t size() const;
sizeAlign4()47 constexpr size_t sizeAlign4() const { return SkAlign4(this->size()); }
48
49 private:
50 const char* fName = nullptr;
51 VertexAttribType fCPUType = VertexAttribType::kFloat;
52 SLType fGPUType = SLType::kVoid;
53 };
54
55 class Iter {
56 public:
Iter()57 Iter() : fCurr(nullptr), fRemaining(0) {}
Iter(const Iter & iter)58 Iter(const Iter& iter) : fCurr(iter.fCurr), fRemaining(iter.fRemaining) {}
59 Iter& operator= (const Iter& iter) {
60 fCurr = iter.fCurr;
61 fRemaining = iter.fRemaining;
62 return *this;
63 }
Iter(const Attribute * attrs,int count)64 Iter(const Attribute* attrs, int count) : fCurr(attrs), fRemaining(count) {
65 this->skipUninitialized();
66 }
67
68 bool operator!=(const Iter& that) const { return fCurr != that.fCurr; }
69 const Attribute& operator*() const { return *fCurr; }
70 void operator++() {
71 if (fRemaining) {
72 fRemaining--;
73 fCurr++;
74 this->skipUninitialized();
75 }
76 }
77
78 private:
skipUninitialized()79 void skipUninitialized() {
80 if (!fRemaining) {
81 fCurr = nullptr;
82 } else {
83 while (!fCurr->isInitialized()) {
84 ++fCurr;
85 }
86 }
87 }
88
89 const Attribute* fCurr;
90 int fRemaining;
91 };
92
93 class AttributeSet {
94 public:
begin()95 Iter begin() const { return Iter(fAttributes, fCount); }
end()96 Iter end() const { return Iter(); }
97
count()98 int count() const { return fCount; }
stride()99 size_t stride() const { return fStride; }
100
101 private:
102 friend class GraphicsPipelineDesc;
init(const Attribute * attrs,int count)103 void init(const Attribute* attrs, int count) {
104 fAttributes = attrs;
105 fRawCount = count;
106 fCount = 0;
107 fStride = 0;
108 for (int i = 0; i < count; ++i) {
109 if (attrs[i].isInitialized()) {
110 fCount++;
111 fStride += attrs[i].sizeAlign4();
112 }
113 }
114 }
115
116 const Attribute* fAttributes = nullptr;
117 int fRawCount = 0;
118 int fCount = 0;
119 size_t fStride = 0;
120 };
121
122 // Returns this as a uint32_t array to be used as a key in the pipeline cache.
123 // TODO: Do we want to do anything here with a tuple or an SkSpan?
asKey()124 const uint32_t* asKey() const {
125 return fKey.data();
126 }
127
128 // Gets the number of bytes in asKey(). It will be a 4-byte aligned value.
keyLength()129 uint32_t keyLength() const {
130 return fKey.size() * sizeof(uint32_t);
131 }
132
133 bool operator==(const GraphicsPipelineDesc& that) const {
134 return this->fKey == that.fKey;
135 }
136
137 bool operator!=(const GraphicsPipelineDesc& other) const {
138 return !(*this == other);
139 }
140
141 // TODO: remove this once we have something real working
setTestingOnlyShaderIndex(int index)142 void setTestingOnlyShaderIndex(int index) {
143 fTestingOnlyShaderIndex = index;
144 if (fKey.count() >= 1) {
145 fKey[0] = index;
146 } else {
147 fKey.push_back(index);
148 }
149 }
testingOnlyShaderIndex()150 int testingOnlyShaderIndex() const {
151 return fTestingOnlyShaderIndex;
152 }
153
setVertexAttributes(const Attribute * attrs,int attrCount)154 void setVertexAttributes(const Attribute* attrs, int attrCount) {
155 fVertexAttributes.init(attrs, attrCount);
156 }
setInstanceAttributes(const Attribute * attrs,int attrCount)157 void setInstanceAttributes(const Attribute* attrs, int attrCount) {
158 SkASSERT(attrCount >= 0);
159 fInstanceAttributes.init(attrs, attrCount);
160 }
161
numVertexAttributes()162 int numVertexAttributes() const { return fVertexAttributes.fCount; }
vertexAttributes()163 const AttributeSet& vertexAttributes() const { return fVertexAttributes; }
numInstanceAttributes()164 int numInstanceAttributes() const { return fInstanceAttributes.fCount; }
instanceAttributes()165 const AttributeSet& instanceAttributes() const { return fInstanceAttributes; }
166
hasVertexAttributes()167 bool hasVertexAttributes() const { return SkToBool(fVertexAttributes.fCount); }
hasInstanceAttributes()168 bool hasInstanceAttributes() const { return SkToBool(fInstanceAttributes.fCount); }
169
170 /**
171 * A common practice is to populate the the vertex/instance's memory using an implicit array of
172 * structs. In this case, it is best to assert that:
173 * stride == sizeof(struct)
174 */
vertexStride()175 size_t vertexStride() const { return fVertexAttributes.fStride; }
instanceStride()176 size_t instanceStride() const { return fInstanceAttributes.fStride; }
177
178 private:
179 // Estimate of max expected key size
180 // TODO: flesh this out
181 inline static constexpr int kPreAllocSize = 1;
182
183 SkSTArray<kPreAllocSize, uint32_t, true> fKey;
184
185 int fTestingOnlyShaderIndex;
186
187 AttributeSet fVertexAttributes;
188 AttributeSet fInstanceAttributes;
189 };
190
191 //////////////////////////////////////////////////////////////////////////////
192
193 /**
194 * Returns the size of the attrib type in bytes.
195 * Placed here in service of Skia dependents that build with C++11.
196 */
VertexAttribTypeSize(VertexAttribType type)197 static constexpr inline size_t VertexAttribTypeSize(VertexAttribType type) {
198 switch (type) {
199 case VertexAttribType::kFloat:
200 return sizeof(float);
201 case VertexAttribType::kFloat2:
202 return 2 * sizeof(float);
203 case VertexAttribType::kFloat3:
204 return 3 * sizeof(float);
205 case VertexAttribType::kFloat4:
206 return 4 * sizeof(float);
207 case VertexAttribType::kHalf:
208 return sizeof(uint16_t);
209 case VertexAttribType::kHalf2:
210 return 2 * sizeof(uint16_t);
211 case VertexAttribType::kHalf4:
212 return 4 * sizeof(uint16_t);
213 case VertexAttribType::kInt2:
214 return 2 * sizeof(int32_t);
215 case VertexAttribType::kInt3:
216 return 3 * sizeof(int32_t);
217 case VertexAttribType::kInt4:
218 return 4 * sizeof(int32_t);
219 case VertexAttribType::kByte:
220 return 1 * sizeof(char);
221 case VertexAttribType::kByte2:
222 return 2 * sizeof(char);
223 case VertexAttribType::kByte4:
224 return 4 * sizeof(char);
225 case VertexAttribType::kUByte:
226 return 1 * sizeof(char);
227 case VertexAttribType::kUByte2:
228 return 2 * sizeof(char);
229 case VertexAttribType::kUByte4:
230 return 4 * sizeof(char);
231 case VertexAttribType::kUByte_norm:
232 return 1 * sizeof(char);
233 case VertexAttribType::kUByte4_norm:
234 return 4 * sizeof(char);
235 case VertexAttribType::kShort2:
236 return 2 * sizeof(int16_t);
237 case VertexAttribType::kShort4:
238 return 4 * sizeof(int16_t);
239 case VertexAttribType::kUShort2: // fall through
240 case VertexAttribType::kUShort2_norm:
241 return 2 * sizeof(uint16_t);
242 case VertexAttribType::kInt:
243 return sizeof(int32_t);
244 case VertexAttribType::kUInt:
245 return sizeof(uint32_t);
246 case VertexAttribType::kUShort_norm:
247 return sizeof(uint16_t);
248 case VertexAttribType::kUShort4_norm:
249 return 4 * sizeof(uint16_t);
250 }
251 // GCC fails because SK_ABORT evaluates to non constexpr. clang and cl.exe think this is
252 // unreachable and don't complain.
253 #if defined(__clang__) || !defined(__GNUC__)
254 SK_ABORT("Unsupported type conversion");
255 #endif
256 return 0;
257 }
258
size()259 constexpr size_t GraphicsPipelineDesc::Attribute::size() const {
260 return VertexAttribTypeSize(fCPUType);
261 }
262
263 } // namespace skgpu
264
265 #endif // skgpu_GraphicsPipelineDesc_DEFINED
266