载入中...
搜索中...
未找到
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 auto &device = vkg->getDevice();
46 if (!fenceReady) {
47 fence = device->createFence(vk::FenceCreateInfo{});
48 fenceReady = true;
49 }
50 vk::CommandBufferAllocateInfo cbai{pool, vk::CommandBufferLevel::ePrimary, 1};
51 commandBuffer = device->allocateCommandBuffers(cbai)[0];
52 commandBuffer.begin(vk::CommandBufferBeginInfo{});
53 recording = true;
54 stagingUsed = 0;
55 usedShaders.clear();
56}
57
59 auto *dev = vkg ? &vkg->getDevice() : nullptr;
60 if (dev && static_cast<VkDevice>(dev->instance)) {
61 if (commandBuffer) {
62 (*dev)->freeCommandBuffers(pool, commandBuffer);
63 commandBuffer = vk::CommandBuffer{};
64 }
65 if (fenceReady) {
66 (*dev)->destroyFence(fence, dev->allocation_callbacks);
67 fence = nullptr;
68 fenceReady = false;
69 }
70 }
71 recording = false;
72 stagingPool.clear();
73 vkg = nullptr;
74 queue = vk::Queue{};
75 pool = vk::CommandPool{};
76}
77
79 if (!seq) return;
80 seq->destroy();
81 delete seq;
82}
83
85 if (!seq) throw Exception("Gpgpu.Sequence: null sequence");
86 seq->ensureReady();
88 seq->stagingUsed = 0;
89}
90
92 const void *src, uint64_t nbytes,
93 uint64_t dstOffset) {
94 if (!seq || !dst || !src || nbytes == 0) return;
96 auto *vkbDst = dynamic_cast<VulkanGpuBuffer *>(dst);
97 if (!vkbDst || !vkbDst->buffer_)
98 throw Exception("Gpgpu.Sequence.recordUpload: destination is not a Vulkan storage buffer");
99 if (dstOffset + nbytes > uint64_t(vkbDst->size_))
100 throw Exception("Gpgpu.Sequence.recordUpload: out of range");
101
102 auto &device = seq->vkg->getDevice();
103 vkb::GenericBuffer *staging = nullptr;
104 for (size_t i = seq->stagingUsed; i < seq->stagingPool.size(); ++i) {
105 if (seq->stagingPool[i].capacity >= vk::DeviceSize(nbytes)) {
106 staging = &seq->stagingPool[i];
107 std::swap(seq->stagingPool[seq->stagingUsed], seq->stagingPool[i]);
108 break;
109 }
110 }
111 if (!staging) {
112 seq->stagingPool.emplace_back(device, buf::eTransferSrc, vk::DeviceSize(nbytes),
113 pfb::eHostVisible | pfb::eHostCoherent);
114 staging = &seq->stagingPool.back();
115 }
116 ++seq->stagingUsed;
117 staging->updateLocal(vkb::FrameSlot::gpuIdle(), src, vk::DeviceSize(nbytes));
118
119 vk::BufferCopy bc{0, vk::DeviceSize(dstOffset), vk::DeviceSize(nbytes)};
120 seq->commandBuffer.copyBuffer(staging->buffer, vkbDst->buffer_, bc);
121 fullMemoryBarrier(seq);
122}
123
125 GpuBuffer *staging, uint64_t nbytes,
126 uint64_t srcOffset) {
127 if (!seq || !src || !staging || nbytes == 0) return;
128 seq->ensureCommandBuffer();
129 auto *vkbSrc = dynamic_cast<VulkanGpuBuffer *>(src);
130 auto *vkbStaging = dynamic_cast<VulkanGpuBuffer *>(staging);
131 if (!vkbSrc || !vkbSrc->buffer_)
132 throw Exception("Gpgpu.Sequence.recordDownload: source is not a Vulkan storage buffer");
133 if (!vkbStaging || !vkbStaging->buffer_ || !vkbStaging->hostVisible_)
134 throw Exception("Gpgpu.Sequence.recordDownload: target must be a \"staging\" buffer");
135 if (srcOffset + nbytes > uint64_t(vkbSrc->size_))
136 throw Exception("Gpgpu.Sequence.recordDownload: out of range");
137 if (nbytes > uint64_t(vkbStaging->size_))
138 throw Exception("Gpgpu.Sequence.recordDownload: staging buffer too small");
139
140 vk::BufferCopy bc{vk::DeviceSize(srcOffset), 0, vk::DeviceSize(nbytes)};
141 seq->commandBuffer.copyBuffer(vkbSrc->buffer_, vkbStaging->buffer_, bc);
142 fullMemoryBarrier(seq);
143}
144
146 int groupsX, int groupsY, int groupsZ) {
147 if (!seq || !shader) return;
148 seq->ensureCommandBuffer();
149 auto *vs = dynamic_cast<VulkanComputeShader *>(shader);
150 if (!vs || !vs->pipeline_) return;
151 if (groupsX <= 0) groupsX = 1;
152 if (groupsY <= 0) groupsY = 1;
153 if (groupsZ <= 0) groupsZ = 1;
154
155 auto &device = seq->vkg->getDevice();
156 vs->beginSequence();
157 vs->flushDescriptors(device);
158 if (std::find(seq->usedShaders.begin(), seq->usedShaders.end(), vs) ==
159 seq->usedShaders.end())
160 seq->usedShaders.push_back(vs);
161
162 seq->commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, vs->pipeline_);
163 if (vs->descriptorSet_) {
164 seq->commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
165 vs->pipelineLayout_, 0, vs->descriptorSet_,
166 nullptr);
167 }
168 seq->commandBuffer.pushConstants(vs->pipelineLayout_, vk::ShaderStageFlagBits::eCompute,
170 vs->pushConstantData());
171 seq->commandBuffer.dispatch(uint32_t(groupsX), uint32_t(groupsY), uint32_t(groupsZ));
172 fullMemoryBarrier(seq);
173}
174
176 if (!seq) return;
177 seq->ensureReady();
178 if (!seq->recording || !seq->commandBuffer)
179 throw Exception("Gpgpu.Sequence.submit: nothing recorded");
180 auto &device = seq->vkg->getDevice();
181
182 vk::CommandBuffer cb = seq->commandBuffer;
183 seq->commandBuffer = vk::CommandBuffer{};
184 seq->recording = false;
185 cb.end();
186
187 device->resetFences(seq->fence);
188 vk::SubmitInfo submit;
189 submit.commandBufferCount = 1;
190 submit.pCommandBuffers = &cb;
191 seq->queue.submit(submit, seq->fence);
192 (void)device->waitForFences(1, &seq->fence, VK_TRUE, UINT64_MAX);
193 for (ComputeShader *shader : seq->usedShaders) {
194 auto *vs = dynamic_cast<VulkanComputeShader *>(shader);
195 if (vs) {
196 vs->endSequence();
197 vs->releasePendingDescriptors(device);
198 }
199 }
200 device->freeCommandBuffers(seq->pool, cb);
201}
202
203} // namespace eve::gpgpu
vkb::Device & device
Shader * shader
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:16
Vulkan 计算着色器(SPIR-V pipeline + descriptor 管理)。
Vulkan 计算缓冲区实现(storage/vertex buffer + device memory)。
void vulkanSequenceSubmit(VulkanSequence *seq)
void vulkanSequenceBegin(VulkanSequence *seq)
void vulkanSequenceDestroy(VulkanSequence *seq)
vk::Queue computeQueue(graphics::vulkan::Graphics *vkg)
void vulkanSequenceRecordDownload(VulkanSequence *seq, GpuBuffer *src, GpuBuffer *staging, uint64_t nbytes, uint64_t srcOffset)
void vulkanSequenceRecordDispatch(VulkanSequence *seq, ComputeShader *shader, int groupsX, int groupsY, int groupsZ)
graphics::vulkan::Graphics * requireVulkanGraphics()
Resolve live Vulkan Graphics (throws if missing / not initialized).
vk::CommandPool computeCommandPool(graphics::vulkan::Graphics *vkg)
void vulkanSequenceRecordUpload(VulkanSequence *seq, GpuBuffer *dst, const void *src, uint64_t nbytes, uint64_t dstOffset)
VulkanSequence * vulkanSequenceCreate()
std::vector< ComputeShader * > usedShaders
std::vector< vkb::GenericBuffer > stagingPool
graphics::vulkan::Graphics * vkg
vk::CommandBuffer commandBuffer