buffer_cache: Move buffer barriers and copy outside of lock range

This commit is contained in:
IndecisiveTurtle 2025-07-08 10:05:23 +03:00
parent 4abffb2489
commit faee44a820
2 changed files with 43 additions and 35 deletions

View file

@ -818,48 +818,22 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
boost::container::small_vector<vk::BufferCopy, 4> copies; boost::container::small_vector<vk::BufferCopy, 4> copies;
size_t total_size_bytes = 0; size_t total_size_bytes = 0;
VAddr buffer_start = buffer.CpuAddr(); VAddr buffer_start = buffer.CpuAddr();
vk::Buffer src_buffer = VK_NULL_HANDLE;
memory_tracker->ForEachUploadRange( memory_tracker->ForEachUploadRange(
device_addr, size, is_written, device_addr, size, is_written,
[&](u64 device_addr_out, u64 range_size) { [&](u64 device_addr_out, u64 range_size) {
copies.emplace_back(total_size_bytes, device_addr_out - buffer_start, range_size); copies.emplace_back(total_size_bytes, device_addr_out - buffer_start, range_size);
total_size_bytes += range_size; total_size_bytes += range_size;
}, },
[&] { UploadCopies(buffer, copies, total_size_bytes); }); [&] { src_buffer = UploadCopies(buffer, copies, total_size_bytes); });
if (is_texel_buffer) { SCOPE_EXIT {
SynchronizeBufferFromImage(buffer, device_addr, size); if (is_texel_buffer) {
} SynchronizeBufferFromImage(buffer, device_addr, size);
} }
};
void BufferCache::UploadCopies(Buffer& buffer, std::span<vk::BufferCopy> copies, if (!src_buffer) {
size_t total_size_bytes) {
if (copies.empty()) {
return; return;
} }
vk::Buffer src_buffer = staging_buffer.Handle();
const auto [staging, offset] = staging_buffer.Map(total_size_bytes);
if (staging) {
for (auto& copy : copies) {
u8* const src_pointer = staging + copy.srcOffset;
const VAddr device_addr = buffer.CpuAddr() + copy.dstOffset;
std::memcpy(src_pointer, std::bit_cast<const u8*>(device_addr), copy.size);
// Apply the staging offset
copy.srcOffset += offset;
}
staging_buffer.Commit();
} else {
// For large one time transfers use a temporary host buffer.
auto temp_buffer =
std::make_unique<Buffer>(instance, scheduler, MemoryUsage::Upload, 0,
vk::BufferUsageFlagBits::eTransferSrc, total_size_bytes);
src_buffer = temp_buffer->Handle();
u8* const staging = temp_buffer->mapped_data.data();
for (const auto& copy : copies) {
u8* const src_pointer = staging + copy.srcOffset;
const VAddr device_addr = buffer.CpuAddr() + copy.dstOffset;
std::memcpy(src_pointer, std::bit_cast<const u8*>(device_addr), copy.size);
}
scheduler.DeferOperation([buffer = std::move(temp_buffer)]() mutable { buffer.reset(); });
}
scheduler.EndRendering(); scheduler.EndRendering();
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
const vk::BufferMemoryBarrier2 pre_barrier = { const vk::BufferMemoryBarrier2 pre_barrier = {
@ -894,6 +868,39 @@ void BufferCache::UploadCopies(Buffer& buffer, std::span<vk::BufferCopy> copies,
}); });
} }
vk::Buffer BufferCache::UploadCopies(Buffer& buffer, std::span<vk::BufferCopy> copies,
size_t total_size_bytes) {
if (copies.empty()) {
return VK_NULL_HANDLE;
}
const auto [staging, offset] = staging_buffer.Map(total_size_bytes);
if (staging) {
for (auto& copy : copies) {
u8* const src_pointer = staging + copy.srcOffset;
const VAddr device_addr = buffer.CpuAddr() + copy.dstOffset;
std::memcpy(src_pointer, std::bit_cast<const u8*>(device_addr), copy.size);
// Apply the staging offset
copy.srcOffset += offset;
}
staging_buffer.Commit();
return staging_buffer.Handle();
} else {
// For large one time transfers use a temporary host buffer.
auto temp_buffer =
std::make_unique<Buffer>(instance, scheduler, MemoryUsage::Upload, 0,
vk::BufferUsageFlagBits::eTransferSrc, total_size_bytes);
const vk::Buffer src_buffer = temp_buffer->Handle();
u8* const staging = temp_buffer->mapped_data.data();
for (const auto& copy : copies) {
u8* const src_pointer = staging + copy.srcOffset;
const VAddr device_addr = buffer.CpuAddr() + copy.dstOffset;
std::memcpy(src_pointer, std::bit_cast<const u8*>(device_addr), copy.size);
}
scheduler.DeferOperation([buffer = std::move(temp_buffer)]() mutable { buffer.reset(); });
return src_buffer;
}
}
bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size) { bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size) {
boost::container::small_vector<ImageId, 6> image_ids; boost::container::small_vector<ImageId, 6> image_ids;
texture_cache.ForEachImageInRegion(device_addr, size, [&](ImageId image_id, Image& image) { texture_cache.ForEachImageInRegion(device_addr, size, [&](ImageId image_id, Image& image) {

View file

@ -194,7 +194,8 @@ private:
void SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, bool is_written, void SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, bool is_written,
bool is_texel_buffer); bool is_texel_buffer);
void UploadCopies(Buffer& buffer, std::span<vk::BufferCopy> copies, size_t total_size_bytes); vk::Buffer UploadCopies(Buffer& buffer, std::span<vk::BufferCopy> copies,
size_t total_size_bytes);
bool SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size); bool SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size);