Compare commits

...

2 Commits

Author SHA1 Message Date
ReinUsesLisp
84bac2a53b vk_memory_manager,vk_stream_buffer: Use persistent memory maps
yuzu originally mapped and unmapped when memory had to be used from the
host. This was originally used to reduce overhead on debugging tools
(renderdoc and Nsight), but at the same time it broke compatibility with
Nsight because this is not handled properly.

After measuring recently, there isn't much of a difference in capture
and replay performance on renderdoc by avoiding persistent memory maps.

This commit replaces previous memory maps with a persistent memory map,
but the API is kept intact to be able to rollback in case it's needed.
2020-10-15 02:03:56 -03:00
ReinUsesLisp
b9d827b1c8 vk_staging_buffer_pool: Minor style changes to support generic staging buffers
This is intended to be able to support staging buffers at a generic
buffer cache level instead of having an extra explicit memcpy on Vulkan
and implicit memcpy (NamedBufferSubData) on OpenGL.

While we are at it, make some minor style changes to buffer management
on Vulkan.
2020-10-15 02:03:56 -03:00
9 changed files with 147 additions and 110 deletions

View File

@@ -37,8 +37,9 @@ std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKSch
} // Anonymous namespace
Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler_,
VKStagingBufferPool& staging_pool_, VAddr cpu_addr, std::size_t size)
CachedBuffer::CachedBuffer(const VKDevice& device, VKMemoryManager& memory_manager,
VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_,
VAddr cpu_addr, std::size_t size)
: BufferBlock{cpu_addr, size}, scheduler{scheduler_}, staging_pool{staging_pool_} {
const VkBufferCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
@@ -55,16 +56,16 @@ Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKSchedu
buffer.commit = memory_manager.Commit(buffer.handle, false);
}
Buffer::~Buffer() = default;
CachedBuffer::~CachedBuffer() = default;
void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) {
const auto& staging = staging_pool.GetUnusedBuffer(size, true);
std::memcpy(staging.commit->Map(size), data, size);
void CachedBuffer::Upload(std::size_t offset, std::size_t size, const u8* data) {
const Buffer& staging = staging_pool.GetUnusedBuffer(size, true);
std::memcpy(staging.Map(size), data, size);
scheduler.RequestOutsideRenderPassOperationContext();
const VkBuffer handle = Handle();
scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) {
scheduler.Record([staging = staging.Handle(), handle, offset, size](vk::CommandBuffer cmdbuf) {
cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, size});
const VkBufferMemoryBarrier barrier{
@@ -83,8 +84,8 @@ void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) {
});
}
void Buffer::Download(std::size_t offset, std::size_t size, u8* data) {
const auto& staging = staging_pool.GetUnusedBuffer(size, true);
void CachedBuffer::Download(std::size_t offset, std::size_t size, u8* data) {
const Buffer& staging = staging_pool.GetUnusedBuffer(size, true);
scheduler.RequestOutsideRenderPassOperationContext();
const VkBuffer handle = Handle();
@@ -109,11 +110,11 @@ void Buffer::Download(std::size_t offset, std::size_t size, u8* data) {
});
scheduler.Finish();
std::memcpy(data, staging.commit->Map(size), size);
std::memcpy(data, staging.Map(size), size);
}
void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
std::size_t size) {
void CachedBuffer::CopyFrom(const CachedBuffer& src, std::size_t src_offset, std::size_t dst_offset,
std::size_t size) {
scheduler.RequestOutsideRenderPassOperationContext();
const VkBuffer dst_buffer = Handle();
@@ -121,25 +122,30 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
size](vk::CommandBuffer cmdbuf) {
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, size});
std::array<VkBufferMemoryBarrier, 2> barriers;
barriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barriers[0].pNext = nullptr;
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barriers[0].dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barriers[0].buffer = src_buffer;
barriers[0].offset = src_offset;
barriers[0].size = size;
barriers[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barriers[1].pNext = nullptr;
barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barriers[1].dstAccessMask = UPLOAD_ACCESS_BARRIERS;
barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barriers[1].buffer = dst_buffer;
barriers[1].offset = dst_offset;
barriers[1].size = size;
const std::array barriers{
VkBufferMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = src_buffer,
.offset = src_offset,
.size = size,
},
VkBufferMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = UPLOAD_ACCESS_BARRIERS,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = dst_buffer,
.offset = dst_offset,
.size = size,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {},
barriers, {});
});
@@ -149,27 +155,28 @@ VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer,
Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
const VKDevice& device_, VKMemoryManager& memory_manager_,
VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_)
: VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, gpu_memory, cpu_memory,
CreateStreamBuffer(device_,
scheduler_)},
: VideoCommon::BufferCache<CachedBuffer, VkBuffer, VKStreamBuffer>{rasterizer, gpu_memory,
cpu_memory,
CreateStreamBuffer(
device_, scheduler_)},
device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{
staging_pool_} {}
VKBufferCache::~VKBufferCache() = default;
std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
return std::make_shared<Buffer>(device, memory_manager, scheduler, staging_pool, cpu_addr,
size);
std::shared_ptr<CachedBuffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
return std::make_shared<CachedBuffer>(device, memory_manager, scheduler, staging_pool, cpu_addr,
size);
}
VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) {
size = std::max(size, std::size_t(4));
const auto& empty = staging_pool.GetUnusedBuffer(size, false);
const Buffer& empty = staging_pool.GetUnusedBuffer(size, false);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf) {
scheduler.Record([size, buffer = empty.Handle()](vk::CommandBuffer cmdbuf) {
cmdbuf.FillBuffer(buffer, 0, size, 0);
});
return {*empty.handle, 0, 0};
return {empty.Handle(), 0, 0};
}
} // namespace Vulkan

View File

@@ -19,21 +19,22 @@ class VKDevice;
class VKMemoryManager;
class VKScheduler;
class Buffer final : public VideoCommon::BufferBlock {
class CachedBuffer final : public VideoCommon::BufferBlock {
public:
explicit Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler,
VKStagingBufferPool& staging_pool, VAddr cpu_addr, std::size_t size);
~Buffer();
explicit CachedBuffer(const VKDevice& device, VKMemoryManager& memory_manager,
VKScheduler& scheduler, VKStagingBufferPool& staging_pool, VAddr cpu_addr,
std::size_t size);
~CachedBuffer();
void Upload(std::size_t offset, std::size_t size, const u8* data);
void Download(std::size_t offset, std::size_t size, u8* data);
void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
void CopyFrom(const CachedBuffer& src, std::size_t src_offset, std::size_t dst_offset,
std::size_t size);
VkBuffer Handle() const {
return *buffer.handle;
return buffer.Handle();
}
u64 Address() const {
@@ -44,10 +45,11 @@ private:
VKScheduler& scheduler;
VKStagingBufferPool& staging_pool;
VKBuffer buffer;
Buffer buffer;
};
class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> {
class VKBufferCache final
: public VideoCommon::BufferCache<CachedBuffer, VkBuffer, VKStreamBuffer> {
public:
explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer,
Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
@@ -58,7 +60,7 @@ public:
BufferInfo GetEmptyBuffer(std::size_t size) override;
protected:
std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override;
std::shared_ptr<CachedBuffer> CreateBlock(VAddr cpu_addr, std::size_t size) override;
private:
const VKDevice& device;

View File

@@ -29,10 +29,21 @@ u64 GetAllocationChunkSize(u64 required_size) {
class VKMemoryAllocation final {
public:
explicit VKMemoryAllocation(const VKDevice& device, vk::DeviceMemory memory,
VkMemoryPropertyFlags properties, u64 allocation_size, u32 type)
: device{device}, memory{std::move(memory)}, properties{properties},
allocation_size{allocation_size}, shifted_type{ShiftType(type)} {}
explicit VKMemoryAllocation(const VKDevice& device_, vk::DeviceMemory memory_,
VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type)
: device{device_}, memory{std::move(memory_)}, properties{properties_},
allocation_size{allocation_size_}, shifted_type{ShiftType(type)} {
if ((properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) {
// Only map memory when it's host visible
persistent_map = memory.Map(0, allocation_size);
}
}
~VKMemoryAllocation() {
if (persistent_map) {
memory.Unmap();
}
}
VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) {
auto found = TryFindFreeSection(free_iterator, allocation_size,
@@ -71,6 +82,12 @@ public:
return (wanted_properties & properties) && (type_mask & shifted_type) != 0;
}
/// Returns the base pointer to a persistently mapped pointer
/// @note It will be nullptr when the memory allocation is not host visible
u8* PersistentMap() const noexcept {
return persistent_map;
}
private:
static constexpr u32 ShiftType(u32 type) {
return 1U << type;
@@ -109,6 +126,7 @@ private:
const VkMemoryPropertyFlags properties; ///< Vulkan properties.
const u64 allocation_size; ///< Size of this allocation.
const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted.
u8* persistent_map{}; ///< Persistently mapped pointer.
/// Hints where the next free region is likely going to be.
u64 free_iterator{};
@@ -153,13 +171,13 @@ VKMemoryCommit VKMemoryManager::Commit(const VkMemoryRequirements& requirements,
VKMemoryCommit VKMemoryManager::Commit(const vk::Buffer& buffer, bool host_visible) {
auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible);
buffer.BindMemory(commit->GetMemory(), commit->GetOffset());
buffer.BindMemory(commit->Memory(), commit->Offset());
return commit;
}
VKMemoryCommit VKMemoryManager::Commit(const vk::Image& image, bool host_visible) {
auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible);
image.BindMemory(commit->GetMemory(), commit->GetOffset());
image.BindMemory(commit->Memory(), commit->Offset());
return commit;
}
@@ -209,18 +227,15 @@ VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requi
VKMemoryCommitImpl::VKMemoryCommitImpl(const VKDevice& device, VKMemoryAllocation* allocation,
const vk::DeviceMemory& memory, u64 begin, u64 end)
: device{device}, memory{memory}, interval{begin, end}, allocation{allocation} {}
: device{device}, memory{memory}, interval{begin, end}, allocation{allocation},
persistent_map{allocation->PersistentMap() + interval.first} {}
VKMemoryCommitImpl::~VKMemoryCommitImpl() {
allocation->Free(this);
}
MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const {
return MemoryMap{this, memory.Map(interval.first + offset_, size)};
}
void VKMemoryCommitImpl::Unmap() const {
memory.Unmap();
MemoryMap VKMemoryCommitImpl::Map([[maybe_unused]] u64 size, u64 offset) const {
return MemoryMap{this, persistent_map + offset};
}
MemoryMap VKMemoryCommitImpl::Map() const {

View File

@@ -63,31 +63,33 @@ public:
~VKMemoryCommitImpl();
/// Maps a memory region and returns a pointer to it.
/// It's illegal to have more than one memory map at the same time.
/// @note It's illegal to have more than one memory map at the same time.
MemoryMap Map(u64 size, u64 offset = 0) const;
/// Maps the whole commit and returns a pointer to it.
/// It's illegal to have more than one memory map at the same time.
/// @note It's illegal to have more than one memory map at the same time.
MemoryMap Map() const;
/// Returns the Vulkan memory handler.
VkDeviceMemory GetMemory() const {
VkDeviceMemory Memory() const {
return *memory;
}
/// Returns the start position of the commit relative to the allocation.
VkDeviceSize GetOffset() const {
VkDeviceSize Offset() const {
return static_cast<VkDeviceSize>(interval.first);
}
private:
/// Unmaps memory.
void Unmap() const;
/// @note Currently a no-op because all memory maps are persistent
void Unmap() const {}
const VKDevice& device; ///< Vulkan device.
const vk::DeviceMemory& memory; ///< Vulkan device memory handler.
std::pair<u64, u64> interval{}; ///< Interval where the commit exists.
VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation.
u8* persistent_map{}; ///< Pointer to a persistently mapped address.
};
/// Holds ownership of a memory map.

View File

@@ -16,17 +16,14 @@
namespace Vulkan {
VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_)
: buffer{std::move(buffer_)} {}
VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device_, VKMemoryManager& memory_manager_,
VKScheduler& scheduler_)
: device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {}
VKStagingBufferPool::~VKStagingBufferPool() = default;
VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visible) {
if (const auto buffer = TryGetReservedBuffer(size, host_visible)) {
Buffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visible) {
if (Buffer* const buffer = TryGetReservedBuffer(size, host_visible)) {
return *buffer;
}
return CreateStagingBuffer(size, host_visible);
@@ -39,22 +36,22 @@ void VKStagingBufferPool::TickFrame() {
ReleaseCache(false);
}
VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) {
Buffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) {
for (StagingBuffer& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) {
if (!scheduler.IsFree(entry.tick)) {
continue;
}
entry.tick = scheduler.CurrentTick();
return &*entry.buffer;
return &entry.buffer;
}
return nullptr;
}
VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) {
Buffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) {
const u32 log2 = Common::Log2Ceil64(size);
auto buffer = std::make_unique<VKBuffer>();
buffer->handle = device.GetLogical().CreateBuffer({
Buffer buffer;
buffer.handle = device.GetLogical().CreateBuffer({
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -65,13 +62,15 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
buffer->commit = memory_manager.Commit(buffer->handle, host_visible);
}),
buffer.commit = memory_manager.Commit(buffer.handle, host_visible);
std::vector<StagingBuffer>& entries = GetCache(host_visible)[log2].entries;
StagingBuffer& entry = entries.emplace_back(std::move(buffer));
entry.tick = scheduler.CurrentTick();
return *entry.buffer;
StagingBuffer& entry = entries.emplace_back(StagingBuffer{
.buffer = std::move(buffer),
.tick = scheduler.CurrentTick(),
});
return entry.buffer;
}
VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) {

View File

@@ -17,9 +17,17 @@ namespace Vulkan {
class VKDevice;
class VKScheduler;
struct VKBuffer final {
struct Buffer {
vk::Buffer handle;
VKMemoryCommit commit;
VkBuffer Handle() const noexcept {
return *handle;
}
MemoryMap Map(u64 size, u64 offset = 0) const {
return commit->Map(size, offset);
}
};
class VKStagingBufferPool final {
@@ -28,19 +36,17 @@ public:
VKScheduler& scheduler);
~VKStagingBufferPool();
VKBuffer& GetUnusedBuffer(std::size_t size, bool host_visible);
Buffer& GetUnusedBuffer(std::size_t size, bool host_visible);
void TickFrame();
private:
struct StagingBuffer final {
explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer);
std::unique_ptr<VKBuffer> buffer;
u64 tick = 0;
struct StagingBuffer {
Buffer buffer;
u64 tick;
};
struct StagingBuffers final {
struct StagingBuffers {
std::vector<StagingBuffer> entries;
std::size_t delete_index = 0;
};
@@ -48,9 +54,9 @@ private:
static constexpr std::size_t NumLevels = sizeof(std::size_t) * CHAR_BIT;
using StagingBuffersCache = std::array<StagingBuffers, NumLevels>;
VKBuffer* TryGetReservedBuffer(std::size_t size, bool host_visible);
Buffer* TryGetReservedBuffer(std::size_t size, bool host_visible);
VKBuffer& CreateStagingBuffer(std::size_t size, bool host_visible);
Buffer& CreateStagingBuffer(std::size_t size, bool host_visible);
StagingBuffersCache& GetCache(bool host_visible);

View File

@@ -64,7 +64,11 @@ VKStreamBuffer::VKStreamBuffer(const VKDevice& device_, VKScheduler& scheduler_,
ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
}
VKStreamBuffer::~VKStreamBuffer() = default;
VKStreamBuffer::~VKStreamBuffer() {
if (persistent_map) {
memory.Unmap();
}
}
std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) {
ASSERT(size <= stream_buffer_size);
@@ -94,14 +98,12 @@ std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) {
invalidated = true;
}
return {memory.Map(offset, size), offset, invalidated};
return {persistent_map + offset, offset, invalidated};
}
void VKStreamBuffer::Unmap(u64 size) {
ASSERT_MSG(size <= mapped_size, "Reserved size is too small");
memory.Unmap();
offset += size;
if (current_watch_cursor + 1 >= current_watches.size()) {
@@ -137,13 +139,16 @@ void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) {
const u32 required_flags = requirements.memoryTypeBits;
stream_buffer_size = static_cast<u64>(requirements.size);
memory = device.GetLogical().AllocateMemory({
const VkMemoryAllocateInfo memory_ai{
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = nullptr,
.allocationSize = requirements.size,
.memoryTypeIndex = GetMemoryType(memory_properties, required_flags),
});
};
memory = device.GetLogical().AllocateMemory(memory_ai);
buffer.BindMemory(*memory, 0);
persistent_map = memory.Map(0, memory_ai.allocationSize);
}
void VKStreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {

View File

@@ -63,8 +63,9 @@ private:
vk::DeviceMemory memory; ///< Memory allocation.
u64 stream_buffer_size{}; ///< Stream buffer size.
u64 offset{}; ///< Buffer iterator.
u64 mapped_size{}; ///< Size reserved for the current copy.
u8* persistent_map{}; ///< Address of the persistently mapped pointer.
u64 offset{}; ///< Buffer iterator.
u64 mapped_size{}; ///< Size reserved for the current copy.
std::vector<Watch> current_watches; ///< Watches recorded in the current iteration.
std::size_t current_watch_cursor{}; ///< Count of watches, reset on invalidation.

View File

@@ -244,10 +244,10 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
const auto& buffer = staging_pool.GetUnusedBuffer(host_memory_size, true);
const Buffer& buffer = staging_pool.GetUnusedBuffer(host_memory_size, true);
// TODO(Rodrigo): Do this in a single copy
for (u32 level = 0; level < params.num_levels; ++level) {
scheduler.Record([image = *image->GetHandle(), buffer = *buffer.handle,
scheduler.Record([image = *image->GetHandle(), buffer = buffer.Handle(),
copy = GetBufferImageCopy(level)](vk::CommandBuffer cmdbuf) {
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy);
});
@@ -255,7 +255,7 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
scheduler.Finish();
// TODO(Rodrigo): Use an intern buffer for staging buffers and avoid this unnecessary memcpy.
std::memcpy(staging_buffer.data(), buffer.commit->Map(host_memory_size), host_memory_size);
std::memcpy(staging_buffer.data(), buffer.Map(host_memory_size), host_memory_size);
}
void CachedSurface::DecorateSurfaceName() {
@@ -268,10 +268,10 @@ View CachedSurface::CreateView(const ViewParams& params) {
}
void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) {
const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true);
std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size);
const Buffer& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true);
std::memcpy(src_buffer.Map(host_memory_size), staging_buffer.data(), host_memory_size);
scheduler.Record([src_buffer = *src_buffer.handle, dst_buffer = *buffer,
scheduler.Record([src_buffer = src_buffer.Handle(), dst_buffer = *buffer,
size = host_memory_size](vk::CommandBuffer cmdbuf) {
VkBufferCopy copy;
copy.srcOffset = 0;
@@ -295,8 +295,8 @@ void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) {
}
void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) {
const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true);
std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size);
const Buffer& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true);
std::memcpy(src_buffer.Map(host_memory_size), staging_buffer.data(), host_memory_size);
FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
@@ -304,7 +304,7 @@ void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) {
for (u32 level = 0; level < params.num_levels; ++level) {
const VkBufferImageCopy copy = GetBufferImageCopy(level);
if (image->GetAspectMask() == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(),
scheduler.Record([buffer = src_buffer.Handle(), image = *image->GetHandle(),
copy](vk::CommandBuffer cmdbuf) {
std::array<VkBufferImageCopy, 2> copies = {copy, copy};
copies[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
@@ -313,7 +313,7 @@ void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) {
copies);
});
} else {
scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(),
scheduler.Record([buffer = src_buffer.Handle(), image = *image->GetHandle(),
copy](vk::CommandBuffer cmdbuf) {
cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy);
});