载入中...
搜索中...
未找到
VulkanComputeShader.cpp
浏览该文件的文档.
3
4#include "common/Exception.h"
5
6#include <array>
7
8namespace eve::gpgpu {
9
11 if (!device_ || !static_cast<VkDevice>(device_->instance)) return;
12 auto &dev = *device_;
13 if (pipeline_) {
14 dev->destroyPipeline(pipeline_, device_->allocation_callbacks);
15 pipeline_ = vk::Pipeline{};
16 }
17 if (pipelineLayout_) {
18 dev->destroyPipelineLayout(pipelineLayout_, device_->allocation_callbacks);
19 pipelineLayout_ = vk::PipelineLayout{};
20 }
21 if (setLayout_) {
22 dev->destroyDescriptorSetLayout(setLayout_, device_->allocation_callbacks);
23 setLayout_ = vk::DescriptorSetLayout{};
24 }
25 if (descriptorPool_) {
26 // Sets allocated from the pool are freed with it.
27 dev->destroyDescriptorPool(descriptorPool_, device_->allocation_callbacks);
28 descriptorPool_ = vk::DescriptorPool{};
29 descriptorSet_ = vk::DescriptorSet{};
30 }
31 if (module_) {
32 dev->destroyShaderModule(module_, device_->allocation_callbacks);
33 module_ = vk::ShaderModule{};
34 }
35 if (dummyBuffer_) {
36 dev->destroyBuffer(dummyBuffer_, device_->allocation_callbacks);
37 dummyBuffer_ = vk::Buffer{};
38 }
39 if (dummyMemory_) {
40 dev->freeMemory(dummyMemory_, device_->allocation_callbacks);
41 dummyMemory_ = vk::DeviceMemory{};
42 }
43 device_ = nullptr;
44}
45
46void VulkanComputeShader::bindBuffer(int binding, GpuBuffer *buffer) {
47 if (binding < 0 || binding >= kMaxBindings) return;
48 bindings_[size_t(binding)] = buffer;
49 descriptorsDirty_ = true;
50}
51
53 if (binding < 0 || binding >= kMaxBindings) return nullptr;
54 return bindings_[size_t(binding)];
55}
56
57void VulkanComputeShader::setFloat(int index, float value) {
58 if (index < 0 || index >= kMaxFloats) return;
59 push_[size_t(index)] = value;
60}
61
62float VulkanComputeShader::getFloat(int index) const {
63 if (index < 0 || index >= kMaxFloats) return 0.f;
64 return push_[size_t(index)];
65}
66
68 bindings_.fill(nullptr);
69 descriptorsDirty_ = true;
70}
71
73 if (!descriptorsDirty_ && descriptorSet_) return;
74
75 if (!descriptorPool_) {
76 // maxSets sets x kMaxBindings storage-buffer descriptors per set: the
77 // pool must hold the deferred backlog from multi-dispatch Sequences.
78 vk::DescriptorPoolSize poolSize{vk::DescriptorType::eStorageBuffer,
79 uint32_t(kMaxBindings) * 64};
80 vk::DescriptorPoolCreateInfo poolInfo{};
81 poolInfo.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet;
82 poolInfo.maxSets = 64;
83 poolInfo.poolSizeCount = 1;
84 poolInfo.pPoolSizes = &poolSize;
85 descriptorPool_ = device->createDescriptorPool(poolInfo, device.allocation_callbacks);
86 }
87
88 if (descriptorSet_) {
89 if (deferSetFree_) {
90 // A previously recorded command buffer in the open Sequence may
91 // still reference this set. Defer the free until that Sequence
92 // submits and waits; the pool is sized for the deferred backlog.
94 } else {
95 device->freeDescriptorSets(descriptorPool_, descriptorSet_);
96 }
97 descriptorSet_ = vk::DescriptorSet{};
98 }
99
100 vk::DescriptorSetAllocateInfo alloc{};
101 alloc.descriptorPool = descriptorPool_;
102 alloc.descriptorSetCount = 1;
103 alloc.pSetLayouts = &setLayout_;
104 auto sets = device->allocateDescriptorSets(alloc);
105 descriptorSet_ = sets[0];
106
107 // Dummy 4-byte SSBO for unused bindings (validation requires all layout slots valid).
108 if (!dummyBuffer_) {
109 using buf = vk::BufferUsageFlagBits;
110 using pfb = vk::MemoryPropertyFlagBits;
111 vkb::GenericBuffer tmp(device, buf::eStorageBuffer | buf::eTransferDst, 4, pfb::eDeviceLocal);
112 dummyBuffer_ = tmp.buffer;
113 dummyMemory_ = tmp.memory;
114 // Without detach(), tmp's destructor frees the handles, leaving the
115 // dummy SSBO dangling: descriptor writes reference a destroyed buffer
116 // (crashes MoltenVK) and ~VulkanComputeShader double-frees it.
117 tmp.detach();
118 }
119
120 std::array<vk::DescriptorBufferInfo, kMaxBindings> infos{};
121 std::array<vk::WriteDescriptorSet, kMaxBindings> writes{};
122 for (int i = 0; i < kMaxBindings; ++i) {
123 auto *vb = dynamic_cast<VulkanGpuBuffer *>(bindings_[size_t(i)]);
124 infos[size_t(i)].buffer = (vb && vb->buffer_) ? vb->buffer_ : dummyBuffer_;
125 infos[size_t(i)].offset = 0;
126 infos[size_t(i)].range = (vb && vb->buffer_) ? vb->size_ : vk::DeviceSize(4);
127 writes[size_t(i)].dstSet = descriptorSet_;
128 writes[size_t(i)].dstBinding = uint32_t(i);
129 writes[size_t(i)].dstArrayElement = 0;
130 writes[size_t(i)].descriptorCount = 1;
131 writes[size_t(i)].descriptorType = vk::DescriptorType::eStorageBuffer;
132 writes[size_t(i)].pBufferInfo = &infos[size_t(i)];
133 }
134 device->updateDescriptorSets(kMaxBindings, writes.data(), 0, nullptr);
135
136 descriptorsDirty_ = false;
137}
138
140
142
144 if (pendingSets_.empty()) return;
145 for (vk::DescriptorSet set : pendingSets_)
146 device->freeDescriptorSets(descriptorPool_, set);
147 pendingSets_.clear();
148}
149
150} // namespace eve::gpgpu
std::string value
vkb::Device & device
static constexpr int kMaxBindings
static constexpr int kMaxFloats
std::array< float, kMaxFloats > push_
Backend-agnostic GPU buffer for compute (storage) or CPU staging transfers. Squirrel-owned; derived c...
Definition GpuBuffer.h:16
float getFloat(int index) const override
void releasePendingDescriptors(vkb::Device &device)
void clearBindings() override
清空全部绑定。
void bindBuffer(int binding, GpuBuffer *buffer) override
绑定/解绑 GpuBuffer 到指定 binding。
vk::DescriptorSetLayout setLayout_
std::array< GpuBuffer *, kMaxBindings > bindings_
void flushDescriptors(vkb::Device &device)
内部:把脏绑定刷成 descriptor set。
GpuBuffer * getBoundBuffer(int binding) const override
std::vector< vk::DescriptorSet > pendingSets_
void setFloat(int index, float value) override
标量 uniform 读写。
Vulkan 计算缓冲区实现(storage/vertex buffer + device memory)。