载入中...
搜索中...
未找到
VulkanSequence.cpp
浏览该文件的文档.
5
6#include "common/Exception.h"
8
9#include <algorithm>
10
11namespace eve::gpgpu {
12
13bool VulkanSequence::ready() const { return vkg && static_cast<VkDevice>(vkg->getDevice().instance); }
14
15namespace {
16
17using buf = vk::BufferUsageFlagBits;
18using pfb = vk::MemoryPropertyFlagBits;
19
21void fullMemoryBarrier(VulkanSequence *seq) {
22 vk::MemoryBarrier mb{vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead,
23 vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite};
24 seq->commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
25 vk::PipelineStageFlagBits::eAllCommands,
26 vk::DependencyFlags{}, 1, &mb, 0, nullptr, 0, nullptr);
27}
28
29} // namespace
30
32
34 if (ready()) return;
35 auto *g = requireVulkanGraphics();
36 vkg = g;
39 if (!queue) throw Exception("Gpgpu.Sequence: no compute/graphics queue");
40}
41
43 if (recording && commandBuffer) return;
45 throw Exception("Gpgpu.Sequence.begin: previous async submission is still pending");
47 auto &device = vkg->getDevice();
48 if (!fenceReady) {
49 fence = device->createFence(vk::FenceCreateInfo{});
50 fenceReady = true;
51 }
52 vk::CommandBufferAllocateInfo cbai{pool, vk::CommandBufferLevel::ePrimary, 1};
53 commandBuffer = device->allocateCommandBuffers(cbai)[0];
54 commandBuffer.begin(vk::CommandBufferBeginInfo{});
55 recording = true;
57 stagingUsed = 0;
58 usedShaders.clear();
59}
60
63 try {
64 (void)vulkanSequenceWait(this);
65 } catch (...) {
66 }
67 }
68 auto *dev = vkg ? &vkg->getDevice() : nullptr;
69 if (dev && static_cast<VkDevice>(dev->instance)) {
70 if (commandBuffer) {
71 (*dev)->freeCommandBuffers(pool, commandBuffer);
72 commandBuffer = vk::CommandBuffer{};
73 }
75 (*dev)->freeCommandBuffers(pool, submittedCommandBuffer);
76 submittedCommandBuffer = vk::CommandBuffer{};
77 }
78 // Abandoning an unsubmitted recording must retire its descriptor leases too.
79 // The caller keeps shaders alive until the Sequence has been destroyed.
81 auto *vs = dynamic_cast<VulkanComputeShader *>(shader);
82 if (vs) {
83 vs->endSequence();
84 vs->releasePendingDescriptors(*dev);
85 }
86 }
87 usedShaders.clear();
88 if (fenceReady) {
89 (*dev)->destroyFence(fence, dev->allocation_callbacks);
90 fence = nullptr;
91 fenceReady = false;
92 }
93 }
94 recording = false;
96 stagingPool.clear();
97 vkg = nullptr;
98 queue = vk::Queue{};
99 pool = vk::CommandPool{};
100}
101
103 if (!seq) return;
104 seq->destroy();
105 delete seq;
106}
107
109 if (!seq) throw Exception("Gpgpu.Sequence: null sequence");
110 seq->ensureReady();
111 seq->ensureCommandBuffer();
112 seq->stagingUsed = 0;
113}
114
116 const void *src, uint64_t nbytes,
117 uint64_t dstOffset) {
118 if (!seq || !dst || !src || nbytes == 0) return;
119 seq->ensureCommandBuffer();
120 auto *vkbDst = dynamic_cast<VulkanGpuBuffer *>(dst);
121 if (!vkbDst || !vkbDst->buffer_)
122 throw Exception("Gpgpu.Sequence.recordUpload: destination is not a Vulkan storage buffer");
123 if (dstOffset + nbytes > uint64_t(vkbDst->size_))
124 throw Exception("Gpgpu.Sequence.recordUpload: out of range");
125
126 auto &device = seq->vkg->getDevice();
127 vkb::GenericBuffer *staging = nullptr;
128 for (size_t i = seq->stagingUsed; i < seq->stagingPool.size(); ++i) {
129 if (seq->stagingPool[i].capacity >= vk::DeviceSize(nbytes)) {
130 std::swap(seq->stagingPool[seq->stagingUsed], seq->stagingPool[i]);
131 staging = &seq->stagingPool[seq->stagingUsed];
132 break;
133 }
134 }
135 if (!staging) {
136 seq->stagingPool.emplace_back(device, buf::eTransferSrc, vk::DeviceSize(nbytes),
137 pfb::eHostVisible | pfb::eHostCoherent);
138 std::swap(seq->stagingPool[seq->stagingUsed], seq->stagingPool.back());
139 staging = &seq->stagingPool[seq->stagingUsed];
140 }
141 ++seq->stagingUsed;
142 staging->updateLocal(vkb::FrameSlot::gpuIdle(), src, vk::DeviceSize(nbytes));
143
144 vk::BufferCopy bc{0, vk::DeviceSize(dstOffset), vk::DeviceSize(nbytes)};
145 seq->commandBuffer.copyBuffer(staging->buffer, vkbDst->buffer_, bc);
146 fullMemoryBarrier(seq);
147}
148
150 GpuBuffer *staging, uint64_t nbytes,
151 uint64_t srcOffset) {
152 if (!seq || !src || !staging || nbytes == 0) return;
153 seq->ensureCommandBuffer();
154 auto *vkbSrc = dynamic_cast<VulkanGpuBuffer *>(src);
155 auto *vkbStaging = dynamic_cast<VulkanGpuBuffer *>(staging);
156 if (!vkbSrc || !vkbSrc->buffer_)
157 throw Exception("Gpgpu.Sequence.recordDownload: source is not a Vulkan storage buffer");
158 if (!vkbStaging || !vkbStaging->buffer_ || !vkbStaging->hostVisible_)
159 throw Exception("Gpgpu.Sequence.recordDownload: target must be a \"staging\" buffer");
160 if (srcOffset + nbytes > uint64_t(vkbSrc->size_))
161 throw Exception("Gpgpu.Sequence.recordDownload: out of range");
162 if (nbytes > uint64_t(vkbStaging->size_))
163 throw Exception("Gpgpu.Sequence.recordDownload: staging buffer too small");
164
165 vk::BufferCopy bc{vk::DeviceSize(srcOffset), 0, vk::DeviceSize(nbytes)};
166 seq->commandBuffer.copyBuffer(vkbSrc->buffer_, vkbStaging->buffer_, bc);
167 fullMemoryBarrier(seq);
168}
169
171 int groupsX, int groupsY, int groupsZ) {
172 if (!seq || !shader) return;
173 seq->ensureCommandBuffer();
174 auto *vs = dynamic_cast<VulkanComputeShader *>(shader);
175 if (!vs || !vs->pipeline_) return;
176 if (groupsX <= 0) groupsX = 1;
177 if (groupsY <= 0) groupsY = 1;
178 if (groupsZ <= 0) groupsZ = 1;
179
180 auto &device = seq->vkg->getDevice();
181 vs->flushDescriptors(device);
182 if (std::find(seq->usedShaders.begin(), seq->usedShaders.end(), vs) == seq->usedShaders.end()) {
183 vs->beginSequence();
184 seq->usedShaders.push_back(vs);
185 }
186
187 seq->commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, vs->pipeline_);
188 if (vs->descriptorSet_) {
189 seq->commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
190 vs->pipelineLayout_, 0, vs->descriptorSet_,
191 nullptr);
192 }
193 seq->commandBuffer.pushConstants(vs->pipelineLayout_, vk::ShaderStageFlagBits::eCompute,
195 vs->pushConstantData());
196 seq->commandBuffer.dispatch(uint32_t(groupsX), uint32_t(groupsY), uint32_t(groupsZ));
197 fullMemoryBarrier(seq);
198}
199
201 const SequenceStatus submitted = vulkanSequenceSubmitAsync(seq);
203 throw Exception("Gpgpu.Sequence.submit: GPU submission failed");
204}
205
207 if (!seq) return SequenceStatus::Failed;
208 seq->ensureReady();
209 if (!seq->recording || !seq->commandBuffer)
210 throw Exception("Gpgpu.Sequence.submit: nothing recorded");
211 auto &device = seq->vkg->getDevice();
212
213 vk::CommandBuffer cb = seq->commandBuffer;
214 seq->commandBuffer = vk::CommandBuffer{};
215 seq->recording = false;
216 cb.end();
217
218 device->resetFences(seq->fence);
219 vk::SubmitInfo submit;
220 submit.commandBufferCount = 1;
221 submit.pCommandBuffers = &cb;
222 seq->queue.submit(submit, seq->fence);
223 seq->submittedCommandBuffer = cb;
225 return seq->status;
226}
227
228namespace {
229
230SequenceStatus retireSubmission(VulkanSequence *seq, SequenceStatus terminal) {
231 auto &device = seq->vkg->getDevice();
232 for (ComputeShader *shader : seq->usedShaders) {
233 auto *vs = dynamic_cast<VulkanComputeShader *>(shader);
234 if (vs) {
235 vs->endSequence();
236 vs->releasePendingDescriptors(device);
237 }
238 }
239 seq->usedShaders.clear();
240 if (seq->submittedCommandBuffer) {
241 device->freeCommandBuffers(seq->pool, seq->submittedCommandBuffer);
242 seq->submittedCommandBuffer = vk::CommandBuffer{};
243 }
244 seq->status = terminal;
245 return terminal;
246}
247
248} // namespace
249
251 if (!seq) return SequenceStatus::Failed;
252 if (seq->status != SequenceStatus::Submitted) return seq->status;
253 const vk::Result result = seq->vkg->getDevice()->getFenceStatus(seq->fence);
254 if (result == vk::Result::eNotReady) return SequenceStatus::Submitted;
255 return retireSubmission(seq, result == vk::Result::eSuccess ? SequenceStatus::Complete : SequenceStatus::Failed);
256}
257
259 if (!seq) return SequenceStatus::Failed;
260 if (seq->status != SequenceStatus::Submitted) return seq->status;
261 const vk::Result result = seq->vkg->getDevice()->waitForFences(1, &seq->fence, VK_TRUE, UINT64_MAX);
262 return retireSubmission(seq, result == vk::Result::eSuccess ? SequenceStatus::Complete : SequenceStatus::Failed);
263}
264
266
267} // namespace eve::gpgpu
tensor::Graph g
Definition GpuGraph.cpp:7
vkb::Device & device
Shader * shader
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Backend-agnostic compute program. Bind storage buffers then dispatch via Gpgpu::dispatch....
static constexpr uint32_t kPushConstantBytes
Backend-agnostic GPU buffer for compute (storage) or CPU staging transfers. Squirrel-owned; derived c...
Definition GpuBuffer.h:18
Vulkan 计算着色器(SPIR-V pipeline + descriptor 管理)。
Vulkan 计算缓冲区实现(storage/vertex buffer + device memory)。
vkb::Device & getDevice()
Returns the device.
Definition Graphics.h:1014
Fluids module — interactive surface fluid simulation.
Definition Fluids.h:34
void vulkanSequenceSubmit(VulkanSequence *seq)
Vulkan sequence submit.
SequenceStatus
Observable lifecycle state of a reusable GPU command sequence.
Definition Sequence.h:14
void vulkanSequenceBegin(VulkanSequence *seq)
Vulkan sequence begin.
SequenceStatus vulkanSequenceWait(VulkanSequence *seq)
Vulkan sequence wait.
void vulkanSequenceDestroy(VulkanSequence *seq)
Vulkan sequence destroy.
vk::Queue computeQueue(graphics::vulkan::Graphics *vkg)
Computes queue.
SequenceStatus vulkanSequenceStatus(const VulkanSequence *seq)
Vulkan sequence status.
void vulkanSequenceRecordDownload(VulkanSequence *seq, GpuBuffer *src, GpuBuffer *staging, uint64_t nbytes, uint64_t srcOffset)
Vulkan sequence record download.
void vulkanSequenceRecordDispatch(VulkanSequence *seq, ComputeShader *shader, int groupsX, int groupsY, int groupsZ)
Vulkan sequence record dispatch.
graphics::vulkan::Graphics * requireVulkanGraphics()
Resolve live Vulkan Graphics (throws if missing / not initialized).
vk::CommandPool computeCommandPool(graphics::vulkan::Graphics *vkg)
Computes command pool.
SequenceStatus vulkanSequencePoll(VulkanSequence *seq)
Vulkan sequence poll.
void vulkanSequenceRecordUpload(VulkanSequence *seq, GpuBuffer *dst, const void *src, uint64_t nbytes, uint64_t dstOffset)
Vulkan sequence record upload.
VulkanSequence * vulkanSequenceCreate()
Vulkan sequence create.
SequenceStatus vulkanSequenceSubmitAsync(VulkanSequence *seq)
Vulkan sequence submit async.
VulkanSequence public API.
std::vector< ComputeShader * > usedShaders
vk::CommandBuffer submittedCommandBuffer
std::vector< vkb::GenericBuffer > stagingPool
void ensureReady()
Ensure ready.
graphics::vulkan::Graphics * vkg
void destroy()
Destroys destroy.
vk::CommandBuffer commandBuffer
void ensureCommandBuffer()
Ensure command buffer.