Loading...
Searching...
No Matches
SSBO.hpp
1#pragma once
2
3#include <isf.hpp>
4
5namespace score::gfx
6{
8{
9 int baseSize{}; // Size of the type itself (e.g., 12 for vec3)
10 int baseAlignment{}; // Alignment requirement (e.g., 16 for vec3)
11
12 bool isValid() const { return baseSize > 0 && baseAlignment > 0; }
13};
14
16{
17 int size{}; // The total size (stride) of the struct/type including padding
18 int alignment{}; // The alignment requirement of the struct/type
19
20 bool isValid() const { return size > 0 && alignment > 0; }
21};
22
24{
25 QString baseType;
26 int arrayCount{}; // 0 = not an array, -1 = flexible array [], >0 = fixed array [N]
27};
28
29static constexpr inline int64_t alignUp(int64_t value, int64_t alignment)
30{
31 if(alignment <= 0)
32 return value;
33 return (value + alignment - 1) & ~(alignment - 1);
34}
35
36static inline ArrayParseResult parseArrayType(const QString& typeStr)
37{
38 ArrayParseResult result;
39 result.baseType = typeStr;
40 result.arrayCount = 0; // Not an array
41
42 int bracketStart = typeStr.lastIndexOf('[');
43 int bracketEnd = typeStr.lastIndexOf(']');
44
45 if(bracketStart != -1 && bracketEnd > bracketStart)
46 {
47 QString content
48 = typeStr.mid(bracketStart + 1, bracketEnd - bracketStart - 1).trimmed();
49 result.baseType = typeStr.left(bracketStart).trimmed();
50
51 if(content.isEmpty())
52 {
53 // Flexible array: "type[]"
54 result.arrayCount = -1;
55 }
56 else
57 {
58 // Fixed array: "type[N]"
59 bool ok = false;
60 int count = content.toInt(&ok);
61 result.arrayCount = ok ? count : 1;
62 }
63 }
64
65 return result;
66}
67
68static inline Std430TypeInfo getStd430BaseTypeInfo(const QString& typeStr)
69{
70 if(typeStr == "float" || typeStr == "int" || typeStr == "uint" || typeStr == "bool")
71 return {4, 4};
72 if(typeStr == "double")
73 return {8, 8};
74
75 if(typeStr == "vec2" || typeStr == "ivec2" || typeStr == "uvec2" || typeStr == "bvec2")
76 return {8, 8};
77 if(typeStr == "vec3" || typeStr == "ivec3" || typeStr == "uvec3" || typeStr == "bvec3")
78 return {12, 16};
79 if(typeStr == "vec4" || typeStr == "ivec4" || typeStr == "uvec4" || typeStr == "bvec4")
80 return {16, 16};
81
82 if(typeStr == "dvec2")
83 return {16, 16};
84 if(typeStr == "dvec3")
85 return {24, 32};
86 if(typeStr == "dvec4")
87 return {32, 32};
88
89 // mat2: 2 columns of vec2, stride=8, total=16
90 if(typeStr == "mat2" || typeStr == "mat2x2")
91 return {16, 8};
92 // mat3: 3 columns of vec3, stride=16 (vec3 aligns to 16), total=48
93 if(typeStr == "mat3" || typeStr == "mat3x3")
94 return {48, 16};
95 // mat4: 4 columns of vec4, stride=16, total=64
96 if(typeStr == "mat4" || typeStr == "mat4x4")
97 return {64, 16};
98
99 // mat2x3: 2 columns of vec3, stride=16, total=32
100 if(typeStr == "mat2x3")
101 return {32, 16};
102 // mat2x4: 2 columns of vec4, stride=16, total=32
103 if(typeStr == "mat2x4")
104 return {32, 16};
105 // mat3x2: 3 columns of vec2, stride=8, total=24
106 if(typeStr == "mat3x2")
107 return {24, 8};
108 // mat3x4: 3 columns of vec4, stride=16, total=48
109 if(typeStr == "mat3x4")
110 return {48, 16};
111 // mat4x2: 4 columns of vec2, stride=8, total=32
112 if(typeStr == "mat4x2")
113 return {32, 8};
114 // mat4x3: 4 columns of vec3, stride=16, total=64
115 if(typeStr == "mat4x3")
116 return {64, 16};
117
118 // dmat2: 2 columns of dvec2, stride=16, total=32
119 if(typeStr == "dmat2" || typeStr == "dmat2x2")
120 return {32, 16};
121 // dmat3: 3 columns of dvec3, stride=32 (dvec3 aligns to 32), total=96
122 if(typeStr == "dmat3" || typeStr == "dmat3x3")
123 return {96, 32};
124 // dmat4: 4 columns of dvec4, stride=32, total=128
125 if(typeStr == "dmat4" || typeStr == "dmat4x4")
126 return {128, 32};
127
128 if(typeStr == "dmat2x3")
129 return {64, 32}; // 2 columns of dvec3
130 if(typeStr == "dmat2x4")
131 return {64, 32}; // 2 columns of dvec4
132 if(typeStr == "dmat3x2")
133 return {48, 16}; // 3 columns of dvec2
134 if(typeStr == "dmat3x4")
135 return {96, 32}; // 3 columns of dvec4
136 if(typeStr == "dmat4x2")
137 return {64, 16}; // 4 columns of dvec2
138 if(typeStr == "dmat4x3")
139 return {128, 32}; // 4 columns of dvec3
140
141 // Unknown type
142 return {0, 0};
143}
144
145static inline LayoutResult calculateStructLayout(
146 std::span<const isf::storage_input::layout_field> layout,
147 std::span<const isf::descriptor::type_definition> typeDefinitions)
148{
149 if(layout.empty())
150 return {0, 0};
151
152 int currentOffset = 0;
153 int maxAlignment = 0;
154
155 for(const auto& field : layout)
156 {
157 const ArrayParseResult parsed = parseArrayType(QString::fromStdString(field.type));
158 const QString baseType = parsed.baseType;
159
160 const bool isArray = (parsed.arrayCount != 0);
161 const bool isFlexibleArray = (parsed.arrayCount == -1);
162 const int arrayCount = (parsed.arrayCount > 0) ? parsed.arrayCount : 1;
163
164 if(isFlexibleArray)
165 {
166 qWarning() << "Flexible array found inside struct. Invalid GLSL, skipping:"
167 << QString::fromStdString(field.name);
168 continue;
169 }
170
171 int fieldSize = 0;
172 int fieldAlign = 0;
173
174 const Std430TypeInfo info = getStd430BaseTypeInfo(baseType);
175
176 if(info.isValid())
177 {
178 // Primitive or matrix type
179 fieldSize = info.baseSize;
180 fieldAlign = info.baseAlignment;
181 }
182 else
183 {
184 // Custom struct - search type definitions
185 bool found = false;
186 for(const auto& typeDef : typeDefinitions)
187 {
188 if(QString::fromStdString(typeDef.name) == baseType)
189 {
190 LayoutResult subStruct
191 = calculateStructLayout(typeDef.layout, typeDefinitions);
192 fieldSize = subStruct.size;
193 fieldAlign = subStruct.alignment;
194 found = true;
195 break;
196 }
197 }
198 if(!found)
199 {
200 qWarning() << "Unknown type, using fallback alignment:" << baseType;
201 fieldSize = 16;
202 fieldAlign = 16;
203 }
204 }
205
206 // --- Handle Array ---
207 int totalFieldSize = fieldSize;
208 if(isArray && arrayCount > 0)
209 {
210 // std430: Array element stride = element size rounded up to element alignment
211 int elementStride = alignUp(fieldSize, fieldAlign);
212 totalFieldSize = elementStride * arrayCount;
213 }
214
215 currentOffset = alignUp(currentOffset, fieldAlign);
216 currentOffset += totalFieldSize;
217 maxAlignment = std::max(maxAlignment, fieldAlign);
218 }
219
220 // Struct size must be a multiple of its largest member alignment
221 currentOffset = alignUp(currentOffset, maxAlignment);
222
223 return {currentOffset, maxAlignment};
224}
225
226static inline int64_t calculateStorageBufferSize(
227 std::span<const isf::storage_input::layout_field> layout, int arrayCount,
228 const isf::descriptor& d)
229{
230 if(layout.empty())
231 return 0;
232
233 if(arrayCount < 0)
234 arrayCount = 0;
235
236 // Get type definitions from the node descriptor
237 const auto& typeDefinitions = d.types;
238
239 int64_t currentOffset = 0;
240 int64_t maxBufferAlignment = 0;
241
242 for(const auto& field : layout)
243 {
244 const ArrayParseResult parsed = parseArrayType(QString::fromStdString(field.type));
245 const QString baseType = parsed.baseType;
246
247 const bool isFlexibleArray = (parsed.arrayCount == -1);
248 const bool isFixedArray = (parsed.arrayCount > 0);
249 const int fixedArrayCount = isFixedArray ? parsed.arrayCount : 1;
250
251 int fieldSize = 0;
252 int64_t fieldAlign = 0;
253
254 const Std430TypeInfo info = getStd430BaseTypeInfo(baseType);
255
256 if(info.isValid())
257 {
258 // Primitive or matrix type
259 fieldSize = info.baseSize;
260 fieldAlign = info.baseAlignment;
261 }
262 else
263 {
264 // Custom struct
265 bool found = false;
266 for(const auto& typeDef : typeDefinitions)
267 {
268 if(QString::fromStdString(typeDef.name) == baseType)
269 {
270 const LayoutResult subRes
271 = calculateStructLayout(typeDef.layout, typeDefinitions);
272 fieldSize = subRes.size;
273 fieldAlign = subRes.alignment;
274 found = true;
275 break;
276 }
277 }
278 if(!found)
279 {
280 qWarning() << "Unknown type in buffer layout:" << baseType;
281 fieldSize = 16;
282 fieldAlign = 16;
283 }
284 }
285
286 int elementStride = alignUp(fieldSize, fieldAlign);
287 currentOffset = alignUp(currentOffset, fieldAlign);
288 if(isFlexibleArray)
289 {
290 // Variable-length array: use provided arrayCount
291 currentOffset += elementStride * arrayCount;
292 }
293 else if(isFixedArray)
294 {
295 // Fixed-length array: use parsed count
296 currentOffset += elementStride * fixedArrayCount;
297 }
298 else
299 {
300 // Single field (not an array)
301 currentOffset += fieldSize;
302 }
303
304 maxBufferAlignment = std::max(maxBufferAlignment, fieldAlign);
305 }
306
307 currentOffset = alignUp(currentOffset, maxBufferAlignment);
308
309 return currentOffset;
310}
311}
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:12
Definition SSBO.hpp:24
Definition SSBO.hpp:16
Definition SSBO.hpp:8