diff --git a/src/graphics/host_gpu/renderer/cache/bufferCache.cpp b/src/graphics/host_gpu/renderer/cache/bufferCache.cpp index cddaa0bb1..3d4da6bcb 100644 --- a/src/graphics/host_gpu/renderer/cache/bufferCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/bufferCache.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -432,21 +433,79 @@ BufferId BufferCache::FindBuffer(uint64_t vaddr, uint64_t size) { bool BufferCache::SynchronizeBuffer(Buffer& buffer, uint64_t vaddr, uint64_t size, bool is_written, bool is_texel_buffer) { - std::vector> uploads; + std::vector copies; + uint64_t total_size = 0; + vk::Buffer source; m_memory_tracker.ForEachUploadRange( vaddr, size, is_written, - [&](uint64_t address, uint64_t bytes) noexcept { uploads.emplace_back(address, bytes); }, - [&]() noexcept { - for (const auto& [address, bytes]: uploads) { - WriteDataBuffer(buffer, address, reinterpret_cast(address), bytes); - } - }); + [&](uint64_t address, uint64_t bytes) noexcept { + copies.emplace_back(total_size, buffer.Offset(address), bytes); + total_size += bytes; + }, + [&]() noexcept { source = UploadCopies(buffer, copies, total_size); }); + if (source) { + auto& command = m_scheduler.Current(); + command.EndRendering(); + const auto native = command.Handle(); + vk::BufferMemoryBarrier before {}; + before.sType = vk::StructureType::eBufferMemoryBarrier; + before.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite | + vk::AccessFlagBits::eTransferRead | + vk::AccessFlagBits::eTransferWrite; + before.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + before.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + before.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + before.buffer = buffer.Handle(); + before.offset = 0; + before.size = buffer.Size(); + native.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, + vk::PipelineStageFlagBits::eTransfer, + vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &before, 0, nullptr); + native.copyBuffer(source, buffer.Handle(), static_cast(copies.size()), + copies.data()); + auto after = before; + after.srcAccessMask = vk::AccessFlagBits::eTransferWrite; + after.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; + native.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eAllCommands, + vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr); + } if (is_texel_buffer && !is_written) { return SynchronizeBufferFromImage(buffer, vaddr, size); } return false; } +vk::Buffer BufferCache::UploadCopies(Buffer& buffer, std::span copies, + uint64_t total_size) { + if (copies.empty()) { + return nullptr; + } + + auto [mapped, base_offset] = m_staging_buffer.Map(total_size, 4); + if (mapped != nullptr) { + for (auto& copy: copies) { + const auto address = buffer.CpuAddress() + copy.dstOffset; + std::memcpy(mapped + copy.srcOffset, reinterpret_cast(address), copy.size); + copy.srcOffset += base_offset; + } + m_staging_buffer.Commit(); + return m_staging_buffer.Handle(); + } + + auto temporary = std::make_unique(m_graphics, m_scheduler, MemoryUsage::Upload, 0, + vk::BufferUsageFlagBits::eTransferSrc, total_size); + for (const auto& copy: copies) { + const auto address = buffer.CpuAddress() + copy.dstOffset; + std::memcpy(temporary->Mapped().data() + copy.srcOffset, + reinterpret_cast(address), copy.size); + } + temporary->Flush(0, total_size); + const auto handle = temporary->Handle(); + m_scheduler.DeferOperation([owner = std::move(temporary)]() mutable { owner.reset(); }); + return handle; +} + std::pair BufferCache::ObtainBuffer(uint64_t vaddr, uint64_t size, bool is_written, bool is_texel_buffer, BufferId id) { diff --git a/src/graphics/host_gpu/renderer/cache/bufferCache.h b/src/graphics/host_gpu/renderer/cache/bufferCache.h index 2a8882915..5e0e43ef0 100644 --- a/src/graphics/host_gpu/renderer/cache/bufferCache.h +++ b/src/graphics/host_gpu/renderer/cache/bufferCache.h @@ -76,6 +76,8 @@ private: void DeleteBuffer(BufferId id); [[nodiscard]] bool SynchronizeBuffer(Buffer& buffer, uint64_t vaddr, uint64_t size, bool is_written, bool is_texel_buffer); + [[nodiscard]] vk::Buffer UploadCopies(Buffer& buffer, std::span copies, + uint64_t total_size); [[nodiscard]] bool SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uint64_t size); [[nodiscard]] std::vector RecordDownloads(std::span copies); void PublishDownloads(std::span downloads);