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