FCT
载入中...
搜索中...
未找到
Uniform.h
浏览该文件的文档.
1#pragma once
2
3#include <vector>
4#include <string>
5#include <unordered_map>
6#include <memory>
7#include <cstring>
8#include "DataTypes.h"
9#include "../Base/Flags.h"
10#include "../Base/string.h"
11#include "./ShaderStage.h"
12
13namespace FCT
14{
15 // Uniform类型枚举
16 enum class ConstType {
17 // 矩阵类型
24
25 // 向量类型
29
30 // 标量类型
34
35 // 纹理类型
38
39 // 自定义类型
41 };
42
43
44#ifdef FCT_USE_VULKAN
45#include <vulkan/vulkan.hpp>
46
47 inline vk::ShaderStageFlags ConvertToVkShaderStageFlags(ShaderStages stages)
48 {
49 vk::ShaderStageFlags flags;
50
51 if (stages & ShaderStage::Vertex)
52 flags |= vk::ShaderStageFlagBits::eVertex;
53
54 if (stages & ShaderStage::Fragment)
55 flags |= vk::ShaderStageFlagBits::eFragment;
56
57 if (stages & ShaderStage::Compute)
58 flags |= vk::ShaderStageFlagBits::eCompute;
59
60 if (stages & ShaderStage::Geometry)
61 flags |= vk::ShaderStageFlagBits::eGeometry;
62
63 if (stages & ShaderStage::TessControl)
64 flags |= vk::ShaderStageFlagBits::eTessellationControl;
65
66 if (stages & ShaderStage::TessEvaluation)
67 flags |= vk::ShaderStageFlagBits::eTessellationEvaluation;
68
69 if (stages & ShaderStage::Task)
70 flags |= vk::ShaderStageFlagBits::eTaskEXT;
71
72 if (stages & ShaderStage::Mesh)
73 flags |= vk::ShaderStageFlagBits::eMeshEXT;
74
75 if (stages & ShaderStage::RayGen)
76 flags |= vk::ShaderStageFlagBits::eRaygenKHR;
77
78 if (stages & ShaderStage::AnyHit)
79 flags |= vk::ShaderStageFlagBits::eAnyHitKHR;
80
81 if (stages & ShaderStage::ClosestHit)
82 flags |= vk::ShaderStageFlagBits::eClosestHitKHR;
83
84 if (stages & ShaderStage::Miss)
85 flags |= vk::ShaderStageFlagBits::eMissKHR;
86
87 if (stages & ShaderStage::Intersection)
88 flags |= vk::ShaderStageFlagBits::eIntersectionKHR;
89
90 if (stages & ShaderStage::Callable)
91 flags |= vk::ShaderStageFlagBits::eCallableKHR;
92
93 if (!flags)
94 flags = vk::ShaderStageFlagBits::eAll;
95
96 return flags;
97 }
98#endif
99
100 // 获取Uniform类型的大小
101 constexpr size_t GetUniformSize(ConstType type) {
102 switch (type) {
107 case ConstType::Mat4:
108 return sizeof(Mat4);
109 case ConstType::Mat3:
110 return sizeof(Mat3);
111 case ConstType::Vec4:
112 return sizeof(Vec4);
113 case ConstType::Vec3:
114 return sizeof(Vec3);
115 case ConstType::Vec2:
116 return sizeof(Vec2);
117 case ConstType::Float:
118 return sizeof(float);
119 case ConstType::Int:
120 case ConstType::Bool:
121 return sizeof(int);
124 return sizeof(int); // 纹理句柄
126 default:
127 return 0;
128 }
129 }
130
131 // 获取Uniform类型的对齐要求
132 constexpr size_t GetUniformAlignment(ConstType type)
133 {
134 switch (type) {
139 case ConstType::Mat4:
140 case ConstType::Mat3:
141 return 16; // 矩阵对齐到16字节
142 case ConstType::Vec4:
143 case ConstType::Vec3:
144 return 16; // 向量对齐到16字节
145 case ConstType::Vec2:
146 return 8; // Vec2对齐到8字节
147 case ConstType::Float:
148 case ConstType::Int:
149 case ConstType::Bool:
152 return 4; // 标量和纹理句柄对齐到4字节
154 default:
155 return 16; // 默认对齐到16字节
156 }
157 }
158
159 constexpr size_t GetHLSLArrayElementSize(ConstType type) {
160 switch (type) {
161 case ConstType::Float:
162 case ConstType::Int:
163 case ConstType::Bool:
164 case ConstType::Vec2:
165 case ConstType::Vec3:
166 return 16; // 16字节
167
168 case ConstType::Vec4:
169 return 16;
170
171 case ConstType::Mat3:
172 return 48; // 3x3矩阵:3个寄存器,每行按 float4 对齐
173
174 case ConstType::Mat4:
179 return 64; // 4x4矩阵:4个寄存器
180
181 default:
182 return 16;
183 }
184 }
185
186 inline constexpr const char* GetUniformDefaultName(ConstType type)
187 {
188 switch (type)
189 {
190 // 标准类型 - 不生成警告
192 return "modelMatrix";
194 return "viewMatrix";
196 return "projectionMatrix";
198 return "mvpMatrix";
199 case ConstType::Mat4:
200 return "u_Mat4";
201 case ConstType::Mat3:
202 return "u_Mat3";
203 case ConstType::Vec4:
204 return "u_Vec4";
205 case ConstType::Vec3:
206 return "u_Vec3";
207 case ConstType::Vec2:
208 return "u_Vec2";
209 case ConstType::Float:
210 return "u_Float";
211
212 case ConstType::Int:
213 return "u_Int";
214
215 case ConstType::Bool:
216 return "u_Bool";
217
219 return "u_Texture2D";
220
222 return "u_TextureCube";
223
225 default:
226 return "u_Custom";
227 }
228 }
229
230
232 public:
233 constexpr ConstElement() noexcept
234 : m_type(ConstType::Custom), m_name("") {}
235
236 constexpr ConstElement(ConstType type) noexcept
237 : m_type(type), m_name(GetUniformDefaultName(type)) {}
238
239 constexpr ConstElement(ConstType type, const char* name) noexcept
240 : m_type(type), m_name(name) {}
241
242 constexpr ConstElement(ConstType type, const char* name, size_t arraySize) noexcept
243 : m_type(type), m_name(name), m_arraySize(arraySize) {}
244
245 constexpr size_t getElementCount() const noexcept {
246 return isArray() ? m_arraySize : 1;
247 }
248 constexpr bool isArray() const noexcept { return m_arraySize > 0; }
249
250 constexpr ConstType getType() const noexcept { return m_type; }
251 constexpr const char* getName() const noexcept { return m_name; }
252 constexpr size_t getSize() const noexcept {
253 if (isArray()) {
255 }
256 return GetUniformSize(m_type);
257 }
258 constexpr size_t getAlignment() const noexcept { return GetUniformAlignment(m_type); }
259 constexpr explicit operator bool() const noexcept {
260 return (m_name && m_name[0] != '\0');
261 }
262 private:
264 const char* m_name;
265 size_t m_arraySize = 0;
266 };
267
269 public:
270 constexpr ConstLayout() noexcept
273 {
274 for (size_t i = 0; i < MaxElements; ++i) {
276 m_offsets[i] = 0;
277 }
278 }
279 template<typename... Args>
280 constexpr ConstLayout(const char* layoutName, Args&&... args) noexcept
282 {
283 processArgs(std::forward<Args>(args)...);
284 }
285
286 constexpr const char* getName() const noexcept { return m_name; }
287
288 constexpr UpdateFrequency getUpdateFrequency() const noexcept { return m_updateFrequency; }
289
290 constexpr ShaderStages getShaderStages() const noexcept { return m_shaderStages; }
291#ifdef FCT_UNUSE
292
293 constexpr void addElement(const ConstElement& element) noexcept {
295 size_t alignment = element.getAlignment();
296 m_size = (m_size + alignment - 1) & ~(alignment - 1);
297
299 m_elements[m_elementCount++] = element;
300 m_size += element.getSize();
301 }
302 }
303#endif
304 constexpr void addElement(const ConstElement& element) noexcept {
306 size_t size = element.getSize();
307 m_size = (m_size + size <= ((m_size + 15) & ~15)) ?
308 m_size : (m_size + 15) & ~15;
310 m_elements[m_elementCount++] = element;
311 m_size += element.getSize();
312 }
313 }
314 bool operator==(const ConstLayout& other) const noexcept {
315
316 if (!StringEquals(m_name, other.m_name)) {
317 return false;
318 }
319 if (m_elementCount != other.m_elementCount) {
320 return false;
321 }
322
323 for (size_t i = 0; i < m_elementCount; ++i) {
324 if (m_elements[i].getType() != other.m_elements[i].getType()) {
325 return false;
326 }
327 }
328 return true;
329 }
330
331 constexpr size_t getElementCount() const noexcept { return m_elementCount; }
332
333 constexpr const ConstElement& getElement(size_t index) const noexcept {
334 return (index < m_elementCount) ? m_elements[index] : m_elements[0];
335 }
336
337 constexpr const ConstElement& getElement(ConstType type) const noexcept {
338 auto index = findElementIndex(type);
339 return (index >= 0) ? m_elements[index] : ConstElement();
340 }
341
342 constexpr size_t getTotalSize() const noexcept {
343 //return (m_size + 15) & ~15;
344 return m_size;
345 }
346
347 constexpr int findElementIndex(const char* name) const noexcept {
348 for (size_t i = 0; i < m_elementCount; ++i) {
349 if (strcmp(m_elements[i].getName(), name) == 0) {
350 return static_cast<int>(i);
351 }
352 }
353 return -1;
354 }
355
356 constexpr int findElementIndex(ConstType type) const noexcept {
357 for (size_t i = 0; i < m_elementCount; ++i) {
358 if (m_elements[i].getType() == type) {
359 return static_cast<int>(i);
360 }
361 }
362 return -1;
363 }
364
365 constexpr size_t getElementOffset(size_t index) const noexcept {
366 return (index < m_elementCount) ? m_offsets[index] : 0;
367 }
368
369 constexpr size_t getElementOffset(const char* name) const noexcept {
370 int index = findElementIndex(name);
371 return (index >= 0) ? m_offsets[index] : 0;
372 }
373
374 constexpr size_t getElementOffset(ConstType type) const noexcept {
375 int index = findElementIndex(type);
376 return (index >= 0) ? m_offsets[index] : 0;
377 }
378
379 private:
380 constexpr void processArgs() noexcept {
381
382 }
383
384 template<typename... Rest>
385 constexpr void processArgs(UpdateFrequency frequency, Rest&&... rest) noexcept {
386 m_updateFrequency = frequency;
387 processArgs(std::forward<Rest>(rest)...);
388 }
389
390 template<typename... Rest>
391 constexpr void processArgs(const ConstElement& element, Rest&&... rest) noexcept {
392 addElement(element);
393 processArgs(std::forward<Rest>(rest)...);
394 }
395
396 template<typename... Rest>
397 constexpr void processArgs(ShaderStages stages, Rest&&... rest) noexcept {
398 m_shaderStages = stages;
399 processArgs(std::forward<Rest>(rest)...);
400 }
401
402 static constexpr size_t MaxElements = 16;
403 const char* m_name = "";
408 size_t m_elementCount = 0;
409 size_t m_size = 0;
410 };
411
420
421 static constexpr ConstLayout SingleMVP = {
422 "mvpTransform",
425 };
426
433
434 static constexpr ConstLayout BasicPBRMaterial = {
435 "pbrMaterial",
437 ConstElement(ConstType::Vec4, "baseColorFactor"),
438 ConstElement(ConstType::Float, "metallicFactor"),
439 ConstElement(ConstType::Float, "roughnessFactor"),
440 ConstElement(ConstType::Vec3, "emissiveFactor")
441 };
442 }
443
445 public:
446 explicit UniformBuffer(const ConstLayout& layout)
447 : m_layout(layout), m_size(layout.getTotalSize()), m_dirty(true) {
448 m_data.resize(m_size, 0);
449 }
450
451 UpdateFrequency getUpdateFrequency() const { return m_layout.getUpdateFrequency(); }
452
453 template<typename T>
454 void setValue(const char* name, const T& value) {
455 int index = m_layout.findElementIndex(name);
456 if (index >= 0) {
457 const auto& element = m_layout.getElement(index);
458 size_t offset = m_layout.getElementOffset(index);
459 if (element.isArray())
460 {
461 setArrayValueDispatch(name, value, element, offset);
462 }
463 else
464 {
465 setSingleValue(name, value, element, offset);
466 }
467 }
468 }
469
470 template<typename T>
471 void setValue(ConstType type, const T& value) {
472 int index = m_layout.findElementIndex(type);
473 if (index >= 0) {
474 size_t offset = m_layout.getElementOffset(index);
475 size_t elementSize = m_layout.getElement(index).getSize();
476
477 if (sizeof(T) <= elementSize) {
478 std::memcpy(m_data.data() + offset, &value, sizeof(T));
479 m_dirty = true;
480 }
481 }
482 }
483
484 template<typename T>
485 T getValue(const char* name) const {
486 T result{};
487 int index = m_layout.findElementIndex(name);
488 if (index >= 0) {
489 size_t offset = m_layout.getElementOffset(index);
490 size_t elementSize = m_layout.getElement(index).getSize();
491
492 if (sizeof(T) <= elementSize) {
493 std::memcpy(&result, m_data.data() + offset, sizeof(T));
494 }
495 }
496 return result;
497 }
498
499 const void* getData() const { return m_data.data(); }
500
501 size_t getSize() const { return m_size; }
502
503 const ConstLayout& getLayout() const { return m_layout; }
504
505 bool isDirty() const { return m_dirty; }
506
507 void clearDirty() { m_dirty = false; }
508 private:
509 template<typename T>
510 void setArrayValueDispatch(const char* name, const T& value, const ConstElement& element, size_t offset) {
511 if constexpr (std::is_pointer_v<T>) {
512 setArrayFromPointer(value, element, offset);
513 } else if constexpr (std::ranges::range<T>) {
514 setArrayFromContainer(value, element, offset);
515 } else
516 {
517
518 }
519 }
520
521 template<typename T>
522 void setArrayFromPointer(T value, const ConstElement& element, size_t offset) {
523 static_assert(std::is_pointer_v<T>, "Expected pointer type");
524
525 size_t baseElementSize = GetUniformSize(element.getType());
526 size_t elementCount = element.getElementCount();
527
528 for (uint32_t i = 0; i < elementCount; ++i) {
529 size_t currentOffset = offset + i * GetHLSLArrayElementSize(element.getType());
530 if (currentOffset + baseElementSize <= m_data.size()) {
531 std::memcpy(m_data.data() + currentOffset, &value[i], baseElementSize);
532 }
533 }
534 m_dirty = true;
535 }
536
537 template<typename T>
538 void setArrayFromContainer(const T& value, const ConstElement& element, size_t offset) {
539 size_t baseElementSize = GetUniformSize(element.getType());
540 size_t maxElements = element.getElementCount();
541 uint32_t arrayIndex = 0;
542
543 for (const auto& it : value) {
544 if (arrayIndex >= maxElements) break;
545
546 size_t currentOffset = offset + arrayIndex * GetHLSLArrayElementSize(element.getType());
547 if (currentOffset + baseElementSize <= m_data.size()) {
548 std::memcpy(m_data.data() + currentOffset, &it, baseElementSize);
549 }
550 arrayIndex++;
551 }
552 m_dirty = true;
553 }
554 template<typename T>
555 void setSingleValue(const char* name, const T& value, const ConstElement& element, size_t offset) {
556 size_t elementSize = element.getSize();
557 if (sizeof(T) <= elementSize) {
558 std::memcpy(m_data.data() + offset, &value, sizeof(T));
559 m_dirty = true;
560 }
561 }
563 std::vector<uint8_t> m_data;
564 size_t m_size;
566 };
567}
constexpr ConstElement(ConstType type, const char *name) noexcept
constexpr size_t getSize() const noexcept
constexpr ConstElement() noexcept
const char * m_name
constexpr bool isArray() const noexcept
constexpr ConstElement(ConstType type, const char *name, size_t arraySize) noexcept
constexpr size_t getAlignment() const noexcept
constexpr size_t getElementCount() const noexcept
constexpr ConstType getType() const noexcept
constexpr ConstElement(ConstType type) noexcept
constexpr const char * getName() const noexcept
constexpr const ConstElement & getElement(ConstType type) const noexcept
constexpr size_t getElementOffset(size_t index) const noexcept
constexpr ConstLayout() noexcept
constexpr void processArgs(const ConstElement &element, Rest &&... rest) noexcept
size_t m_offsets[MaxElements]
constexpr ShaderStages getShaderStages() const noexcept
constexpr int findElementIndex(ConstType type) const noexcept
ShaderStages m_shaderStages
constexpr size_t getTotalSize() const noexcept
constexpr int findElementIndex(const char *name) const noexcept
constexpr void processArgs(UpdateFrequency frequency, Rest &&... rest) noexcept
constexpr void addElement(const ConstElement &element) noexcept
constexpr size_t getElementOffset(ConstType type) const noexcept
const char * m_name
ConstElement m_elements[MaxElements]
static constexpr size_t MaxElements
constexpr UpdateFrequency getUpdateFrequency() const noexcept
constexpr void processArgs(ShaderStages stages, Rest &&... rest) noexcept
constexpr void processArgs() noexcept
constexpr const char * getName() const noexcept
bool operator==(const ConstLayout &other) const noexcept
constexpr size_t getElementOffset(const char *name) const noexcept
constexpr const ConstElement & getElement(size_t index) const noexcept
constexpr size_t getElementCount() const noexcept
UpdateFrequency m_updateFrequency
constexpr ConstLayout(const char *layoutName, Args &&... args) noexcept
bool isDirty() const
UpdateFrequency getUpdateFrequency() const
T getValue(const char *name) const
void setValue(const char *name, const T &value)
void setValue(ConstType type, const T &value)
void setArrayValueDispatch(const char *name, const T &value, const ConstElement &element, size_t offset)
const void * getData() const
void setArrayFromPointer(T value, const ConstElement &element, size_t offset)
const ConstLayout & getLayout() const
std::vector< uint8_t > m_data
void setArrayFromContainer(const T &value, const ConstElement &element, size_t offset)
void setSingleValue(const char *name, const T &value, const ConstElement &element, size_t offset)
UniformBuffer(const ConstLayout &layout)
size_t getSize() const
static constexpr ConstLayout ModelViewProj
static constexpr ConstLayout MVP
static constexpr ConstLayout BasicPBRMaterial
static constexpr ConstLayout SingleMVP
UpdateFrequency
constexpr bool StringEquals(const char *a, const char *b) noexcept
定义 string.h:8
constexpr size_t GetUniformAlignment(ConstType type)
vk::ShaderStageFlags ConvertToVkShaderStageFlags(ShaderStages stages)
constexpr size_t GetUniformSize(ConstType type)
constexpr size_t GetHLSLArrayElementSize(ConstType type)
constexpr const char * GetUniformDefaultName(ConstType type)