MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GpuDataFormat.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <glm/glm.hpp>
4
5namespace MayaFlux::Kakshya {
6
7/**
8 * @enum GpuDataFormat
9 * @brief GPU data formats with explicit precision levels
10 */
11enum class GpuDataFormat : uint8_t {
12 FLOAT32, ///< 32-bit float (standard GPU)
13 VEC2_F32, ///< glm::vec2 (32-bit components)
14 VEC3_F32, ///< glm::vec3 (32-bit components), not a sampled image format
15 VEC4_F32, ///< glm::vec4 (32-bit components)
16
17 FLOAT64, ///< 64-bit double (audio precision)
18 VEC2_F64, ///< glm::dvec2 (64-bit components)
19 VEC3_F64, ///< glm::dvec3 (64-bit components)
20 VEC4_F64, ///< glm::dvec4 (64-bit components)
21
22 INT32,
23 UINT32,
24
25 UINT8, ///< uint8_t, R8 / RGBA8 texel data
26 UINT16, ///< uint16_t, R16F raw half-float storage, packed formats
27
28 MAT4_F32, ///< glm::mat4 (column-major), not a sampled image format
29};
30
31/**
32 * @brief Byte size of one element of a GpuDataFormat.
33 *
34 * Single authoritative source for format sizing. Used by TextureAccess,
35 * ShaderSpec, and any other system that needs to derive byte counts from
36 * GpuDataFormat without duplicating the switch.
37 *
38 * @param fmt GpuDataFormat value.
39 * @return Byte size of one element, or 0 for unrecognised formats.
40 */
41MAYAFLUX_API size_t gpu_data_format_bytes(GpuDataFormat fmt) noexcept;
42
43/**
44 * @brief Base alignment in bytes of one element, following std430 rules.
45 *
46 * Differs from gpu_data_format_bytes for three-component vectors, which
47 * align as four.
48 *
49 * @param fmt GpuDataFormat value.
50 * @return Alignment in bytes, or 0 for unrecognised formats.
51 */
52MAYAFLUX_API size_t gpu_data_format_align(GpuDataFormat fmt) noexcept;
53
54/**
55 * @brief Number of scalar components in one element of a GpuDataFormat.
56 *
57 * @param fmt GpuDataFormat value.
58 * @return 1 for scalars, 2 to 4 for vectors, 16 for MAT4_F32, 0 for unrecognised formats.
59 */
60MAYAFLUX_API size_t gpu_data_format_components(GpuDataFormat fmt) noexcept;
61
62/**
63 * @struct GpuBlockLayout
64 * @brief Member offsets and total size of a block of GpuDataFormat fields.
65 */
67 std::vector<uint32_t> offsets;
68 uint32_t size {};
69};
70
71/**
72 * @brief Lay out fields in declaration order under std430 rules.
73 *
74 * Each offset is the running end rounded up to the field's alignment, and the
75 * size is the end rounded up to the widest alignment, never less than four.
76 * This is the layout Vulkan applies to push constant blocks, which the GLSL
77 * path leaves to the compiler and the SPIR-V path must state itself.
78 *
79 * @param fields Field formats in declaration order.
80 * @return One offset per field. Unrecognised formats take no space and
81 * report the current end as their offset.
82 */
83MAYAFLUX_API GpuBlockLayout gpu_block_layout(std::span<const GpuDataFormat> fields);
84
85/**
86 * @brief Maps a C++ type to its GpuDataFormat.
87 *
88 * Specialised for float, double, int32_t, uint32_t, uint8_t, uint16_t,
89 * glm::vec2/3/4, glm::dvec2/3/4 and glm::mat4. Unspecialised types have no
90 * `value` member.
91 */
92template <typename T>
94
95template <>
96struct gpu_data_format_of<float> {
98};
99
100template <>
101struct gpu_data_format_of<glm::vec2> {
103};
104
105template <>
106struct gpu_data_format_of<glm::vec3> {
108};
109
110template <>
111struct gpu_data_format_of<glm::vec4> {
113};
114
115template <>
116struct gpu_data_format_of<double> {
118};
119
120template <>
121struct gpu_data_format_of<glm::dvec2> {
123};
124
125template <>
126struct gpu_data_format_of<glm::dvec3> {
128};
129
130template <>
131struct gpu_data_format_of<glm::dvec4> {
133};
134
135template <>
136struct gpu_data_format_of<int32_t> {
138};
139
140template <>
141struct gpu_data_format_of<uint32_t> {
143};
144
145template <>
146struct gpu_data_format_of<uint8_t> {
148};
149
150template <>
151struct gpu_data_format_of<uint16_t> {
153};
154
155template <>
156struct gpu_data_format_of<glm::mat4> {
158};
159
160/**
161 * @concept GpuFormatElement
162 * @brief A type with a GpuDataFormat mapping.
163 *
164 * Wider than DataVariantElement: includes int32_t and the double precision
165 * glm types, which DataVariant cannot hold.
166 */
167template <typename T>
168concept GpuFormatElement = requires {
169 { gpu_data_format_of<std::remove_cvref_t<T>>::value } -> std::convertible_to<GpuDataFormat>;
170};
171
172/**
173 * @brief The GpuDataFormat of a GpuFormatElement type.
174 */
175template <GpuFormatElement T>
177
178/**
179 * @brief One value of any GpuDataFormat.
180 *
181 * Alternatives follow GpuDataFormat order, so the active index is the
182 * format. Construct with the exact type; an untyped literal is ambiguous.
183 */
184using GpuValue = std::variant<
185 float, glm::vec2, glm::vec3, glm::vec4,
186 double, glm::dvec2, glm::dvec3, glm::dvec4,
187 int32_t, uint32_t,
188 uint8_t, uint16_t,
189 glm::mat4>;
190
191namespace detail {
192
193 template <size_t... I>
194 constexpr bool gpu_value_follows_format_order(std::index_sequence<I...>)
195 {
196 return ((gpu_data_format_of<std::variant_alternative_t<I, GpuValue>>::value == static_cast<GpuDataFormat>(I)) && ...);
197 }
198
199} // namespace detail
200
201static_assert(detail::gpu_value_follows_format_order(std::make_index_sequence<std::variant_size_v<GpuValue>> {}));
202
203/**
204 * @brief The GpuDataFormat of the value held.
205 */
206[[nodiscard]] inline GpuDataFormat gpu_value_format(const GpuValue& value) noexcept
207{
208 return static_cast<GpuDataFormat>(value.index());
209}
210
211/**
212 * @brief Copies the held value's bytes into out, unconverted.
213 *
214 * @param value Source value.
215 * @param out Destination, at least gpu_data_format_bytes(gpu_value_format(value)).
216 * @return Bytes written, or 0 if out is too small.
217 */
218MAYAFLUX_API size_t gpu_value_write(const GpuValue& value, std::span<std::byte> out) noexcept;
219
220/**
221 * @brief Writes scalar components into out as one element of dst.
222 *
223 * Each component is converted to the component type of dst. Integer
224 * destinations saturate and map NaN to zero.
225 *
226 * @param dst Destination format.
227 * @param components Source components, in element order (column-major for MAT4_F32).
228 * @param out Destination bytes, at least gpu_data_format_bytes(dst).
229 * @return False, with out untouched, if the component count does not equal
230 * gpu_data_format_components(dst) or out is too small.
231 */
232MAYAFLUX_API bool pack_gpu_components(
234 std::span<const double> components,
235 std::span<std::byte> out) noexcept;
236
237/**
238 * @brief Writes a typed value into out as one element of dst.
239 *
240 * The value's component count must equal that of dst, so a glm::vec3 packs
241 * into VEC3_F32 or VEC3_F64 but not into FLOAT32.
242 *
243 * @param dst Destination format.
244 * @param value Source value.
245 * @param out Destination bytes, at least gpu_data_format_bytes(dst).
246 * @return False if the component counts differ or out is too small.
247 */
248template <GpuFormatElement T>
249[[nodiscard]] bool pack_gpu_value(
251 const T& value,
252 std::span<std::byte> out) noexcept
253{
254 using V = std::remove_cvref_t<T>;
255
256 std::array<double, 16> components {};
257 size_t count = 0;
258
259 if constexpr (ArithmeticData<V>) {
260 components[count++] = static_cast<double>(value);
261 } else if constexpr (GlmMatrixType<V>) {
262 for (int c = 0; c < 4; ++c) {
263 for (int r = 0; r < 4; ++r) {
264 components[count++] = static_cast<double>(value[c][r]);
265 }
266 }
267 } else {
268 for (int i = 0; i < static_cast<int>(glm_component_count<V>()); ++i) {
269 components[count++] = static_cast<double>(value[i]);
270 }
271 }
272
273 return pack_gpu_components(dst, std::span<const double>(components.data(), count), out);
274}
275
276} // namespace MayaFlux::Kakshya
uint32_t * dst
std::vector< float > * out
glm::vec3 value
size_t count
A type with a GpuDataFormat mapping.
constexpr bool gpu_value_follows_format_order(std::index_sequence< I... >)
std::variant< float, glm::vec2, glm::vec3, glm::vec4, double, glm::dvec2, glm::dvec3, glm::dvec4, int32_t, uint32_t, uint8_t, uint16_t, glm::mat4 > GpuValue
One value of any GpuDataFormat.
bool pack_gpu_components(GpuDataFormat dst, std::span< const double > components, std::span< std::byte > out) noexcept
Writes scalar components into out as one element of dst.
size_t gpu_data_format_bytes(GpuDataFormat fmt) noexcept
Byte size of one element of a GpuDataFormat.
size_t gpu_data_format_align(GpuDataFormat fmt) noexcept
Base alignment in bytes of one element, following std430 rules.
size_t gpu_data_format_components(GpuDataFormat fmt) noexcept
Number of scalar components in one element of a GpuDataFormat.
GpuBlockLayout gpu_block_layout(std::span< const GpuDataFormat > fields)
Lay out fields in declaration order under std430 rules.
GpuDataFormat gpu_value_format(const GpuValue &value) noexcept
The GpuDataFormat of the value held.
size_t gpu_value_write(const GpuValue &value, std::span< std::byte > out) noexcept
Copies the held value's bytes into out, unconverted.
constexpr GpuDataFormat gpu_data_format_v
The GpuDataFormat of a GpuFormatElement type.
bool pack_gpu_value(GpuDataFormat dst, const T &value, std::span< std::byte > out) noexcept
Writes a typed value into out as one element of dst.
GpuDataFormat
GPU data formats with explicit precision levels.
@ VEC3_F64
glm::dvec3 (64-bit components)
@ FLOAT64
64-bit double (audio precision)
@ UINT16
uint16_t, R16F raw half-float storage, packed formats
@ VEC2_F64
glm::dvec2 (64-bit components)
@ VEC2_F32
glm::vec2 (32-bit components)
@ VEC4_F32
glm::vec4 (32-bit components)
@ VEC4_F64
glm::dvec4 (64-bit components)
@ FLOAT32
32-bit float (standard GPU)
@ MAT4_F32
glm::mat4 (column-major), not a sampled image format
@ VEC3_F32
glm::vec3 (32-bit components), not a sampled image format
@ UINT8
uint8_t, R8 / RGBA8 texel data
std::vector< uint32_t > offsets
Member offsets and total size of a block of GpuDataFormat fields.
Maps a C++ type to its GpuDataFormat.