载入中...
搜索中...
未找到
VulkanGpuBuffer.cpp
浏览该文件的文档.
3
5
6#include "common/Exception.h"
7#include "data/ByteData.h"
8
9#include <cstring>
10#include <vector>
11
12namespace eve::gpgpu {
13
15 if (!device_ || !static_cast<VkDevice>(device_->instance)) return;
16 if (buffer_) {
17 (*device_)->destroyBuffer(buffer_, device_->allocation_callbacks);
18 buffer_ = vk::Buffer{};
19 }
20 if (memory_) {
21 (*device_)->freeMemory(memory_, device_->allocation_callbacks);
22 memory_ = vk::DeviceMemory{};
23 }
24 device_ = nullptr;
25}
26
27void VulkanGpuBuffer::uploadBytes(const void *src, uint64_t nbytes, uint64_t dstOffset) {
28 if (!device_ || !buffer_ || !src || nbytes == 0) return;
29 if (dstOffset + nbytes > size_)
30 throw Exception("GpuBuffer.write: out of range (offset=%llu size=%llu capacity=%llu)",
31 (unsigned long long)dstOffset, (unsigned long long)nbytes,
32 (unsigned long long)size_);
33
34 auto *vkg = requireVulkanGraphics();
35 auto queue = computeQueue(vkg);
36 auto pool = computeCommandPool(vkg);
37
38 if (hostVisible_) {
39 void *ptr = (*device_)->mapMemory(memory_, dstOffset, nbytes, vk::MemoryMapFlags{});
40 std::memcpy(ptr, src, size_t(nbytes));
41 (*device_)->unmapMemory(memory_);
42 return;
43 }
44
45 using buf = vk::BufferUsageFlagBits;
46 using pfb = vk::MemoryPropertyFlagBits;
47 vkb::GenericBuffer staging(*device_, buf::eTransferSrc, nbytes,
48 pfb::eHostVisible | pfb::eHostCoherent);
49 staging.updateLocal(vkb::FrameSlot::gpuIdle(), src, nbytes);
50 vkb::executeImmediately(device_->instance, pool, queue, [&](vk::CommandBuffer cb) {
51 vk::BufferCopy bc{0, vk::DeviceSize(dstOffset), vk::DeviceSize(nbytes)};
52 cb.copyBuffer(staging.buffer, buffer_, bc);
53 });
54}
55
56void VulkanGpuBuffer::downloadBytes(void *dst, uint64_t nbytes, uint64_t srcOffset) const {
57 if (!device_ || !buffer_ || !dst || nbytes == 0) return;
58 if (srcOffset + nbytes > size_)
59 throw Exception("GpuBuffer.read: out of range (offset=%llu size=%llu capacity=%llu)",
60 (unsigned long long)srcOffset, (unsigned long long)nbytes,
61 (unsigned long long)size_);
62
63 auto *vkg = requireVulkanGraphics();
64 auto queue = computeQueue(vkg);
65 auto pool = computeCommandPool(vkg);
66
67 if (hostVisible_) {
68 void *ptr = (*device_)->mapMemory(memory_, srcOffset, nbytes, vk::MemoryMapFlags{});
69 std::memcpy(dst, ptr, size_t(nbytes));
70 (*device_)->unmapMemory(memory_);
71 return;
72 }
73
74 using buf = vk::BufferUsageFlagBits;
75 using pfb = vk::MemoryPropertyFlagBits;
76 vkb::GenericBuffer staging(*device_, buf::eTransferDst, nbytes,
77 pfb::eHostVisible | pfb::eHostCoherent);
78 vkb::executeImmediately(device_->instance, pool, queue, [&](vk::CommandBuffer cb) {
79 vk::BufferCopy bc{vk::DeviceSize(srcOffset), 0, vk::DeviceSize(nbytes)};
80 cb.copyBuffer(buffer_, staging.buffer, bc);
81 });
82 void *ptr = (*device_)->mapMemory(staging.memory, 0, nbytes, vk::MemoryMapFlags{});
83 std::memcpy(dst, ptr, size_t(nbytes));
84 (*device_)->unmapMemory(staging.memory);
85}
86
87void VulkanGpuBuffer::writeData(data::ByteData *data, int dstOffset) {
88 if (!data) return;
89 uploadBytes(data->getData(), data->getSize(), uint64_t(dstOffset < 0 ? 0 : dstOffset));
90}
91
92data::ByteData *VulkanGpuBuffer::readData(int srcOffset, int size) {
93 const int off = srcOffset < 0 ? 0 : srcOffset;
94 int nbytes = size;
95 if (nbytes < 0) nbytes = int(size_) - off;
96 if (nbytes <= 0) return new data::ByteData(size_t(0));
97 auto *out = new data::ByteData(size_t(nbytes));
98 downloadBytes(out->getData(), uint64_t(nbytes), uint64_t(off));
99 return out;
100}
101
102void VulkanGpuBuffer::writeFloat32(int floatIndex, float value) {
103 if (floatIndex < 0) return;
104 uploadBytes(&value, sizeof(float), uint64_t(floatIndex) * sizeof(float));
105}
106
107float VulkanGpuBuffer::readFloat32(int floatIndex) {
108 if (floatIndex < 0) return 0.f;
109 float v = 0.f;
110 downloadBytes(&v, sizeof(float), uint64_t(floatIndex) * sizeof(float));
111 return v;
112}
113
114void VulkanGpuBuffer::writeFloat32s(const float *data, int count, int startIndex) {
115 if (!data || count <= 0 || startIndex < 0) return;
116 uploadBytes(data, uint64_t(count) * sizeof(float),
117 uint64_t(startIndex) * sizeof(float));
118}
119
120void VulkanGpuBuffer::readFloat32s(float *out, int count, int startIndex) const {
121 if (!out || count <= 0 || startIndex < 0) return;
122 downloadBytes(out, uint64_t(count) * sizeof(float),
123 uint64_t(startIndex) * sizeof(float));
124}
125
126void VulkanGpuBuffer::fillFloat32(float value) {
127 if (size_ < sizeof(float)) return;
128 const size_t count = size_t(size_ / sizeof(float));
129 std::vector<float> tmp(count, value);
130 uploadBytes(tmp.data(), count * sizeof(float), 0);
131}
132
133} // namespace eve::gpgpu
std::string value
void * ptr
Light2D::Data * data
int v
In-memory byte buffer implementing eve::Data (ref-counted).
Definition ByteData.h:11
void uploadBytes(const void *src, uint64_t nbytes, uint64_t dstOffset=0) override
vk::Queue computeQueue(graphics::vulkan::Graphics *vkg)
graphics::vulkan::Graphics * requireVulkanGraphics()
Resolve live Vulkan Graphics (throws if missing / not initialized).
vk::CommandPool computeCommandPool(graphics::vulkan::Graphics *vkg)