|
|
|
@ -381,68 +381,65 @@ void BufferCacheRuntime::TryEnableUnifiedMemory(void* base, size_t size, |
|
|
|
device, base, size, hardware_buffers, hardware_buffer_window, hardware_buffer_base); |
|
|
|
if (!unified_memory->IsValid()) { |
|
|
|
unified_memory.reset(); |
|
|
|
return; |
|
|
|
} |
|
|
|
AcquireUnifiedWindowsFromForeign(); |
|
|
|
} |
|
|
|
|
|
|
|
void BufferCacheRuntime::CopyToUnifiedMemory( |
|
|
|
size_t window_index, VkBuffer src_buffer, |
|
|
|
std::span<const VideoCommon::BufferCopy> copies) { |
|
|
|
if (!unified_memory || src_buffer == VK_NULL_HANDLE || copies.empty() || |
|
|
|
window_index >= unified_memory->GetWindowCount()) { |
|
|
|
void BufferCacheRuntime::AcquireUnifiedWindowsFromForeign() { |
|
|
|
if (!unified_memory->NeedsForeignOwnershipTransfer()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const VkBuffer dst_buffer = unified_memory->GetWindowBuffer(window_index); |
|
|
|
if (dst_buffer == VK_NULL_HANDLE) { |
|
|
|
return; |
|
|
|
boost::container::small_vector<VkBuffer, 16> window_buffers; |
|
|
|
const size_t window_count = unified_memory->GetWindowCount(); |
|
|
|
for (size_t i = 0; i < window_count; ++i) { |
|
|
|
const VkBuffer buffer = unified_memory->GetWindowBuffer(i); |
|
|
|
if (buffer != VK_NULL_HANDLE) { |
|
|
|
window_buffers.push_back(buffer); |
|
|
|
} |
|
|
|
} |
|
|
|
VkDeviceSize covered_begin = std::numeric_limits<VkDeviceSize>::max(); |
|
|
|
VkDeviceSize covered_end = 0; |
|
|
|
for (const VideoCommon::BufferCopy& copy : copies) { |
|
|
|
covered_begin = (std::min)(covered_begin, static_cast<VkDeviceSize>(copy.dst_offset)); |
|
|
|
covered_end = (std::max)(covered_end, |
|
|
|
static_cast<VkDeviceSize>(copy.dst_offset + copy.size)); |
|
|
|
if (window_buffers.empty()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size()); |
|
|
|
std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); |
|
|
|
|
|
|
|
const bool foreign = unified_memory->NeedsForeignOwnershipTransfer(); |
|
|
|
const u32 queue_family = device.GetGraphicsFamily(); |
|
|
|
|
|
|
|
scheduler.RequestOutsideRenderPassOperationContext(); |
|
|
|
scheduler.Record([src_buffer, dst_buffer, vk_copies, foreign, queue_family, covered_begin, |
|
|
|
covered_end](vk::CommandBuffer cmdbuf) { |
|
|
|
if (foreign) { |
|
|
|
scheduler.Record([window_buffers = std::move(window_buffers), |
|
|
|
queue_family](vk::CommandBuffer cmdbuf) { |
|
|
|
for (const VkBuffer buffer : window_buffers) { |
|
|
|
const VkBufferMemoryBarrier acquire{ |
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
|
|
|
.pNext = nullptr, |
|
|
|
.srcAccessMask = 0, |
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
|
|
|
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, |
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT, |
|
|
|
.dstQueueFamilyIndex = queue_family, |
|
|
|
.buffer = dst_buffer, |
|
|
|
.offset = covered_begin, |
|
|
|
.size = covered_end - covered_begin, |
|
|
|
.buffer = buffer, |
|
|
|
.offset = 0, |
|
|
|
.size = VK_WHOLE_SIZE, |
|
|
|
}; |
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, acquire); |
|
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, acquire); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
void BufferCacheRuntime::CopyToUnifiedMemory( |
|
|
|
size_t window_index, VkBuffer src_buffer, |
|
|
|
std::span<const VideoCommon::BufferCopy> copies) { |
|
|
|
if (!unified_memory || src_buffer == VK_NULL_HANDLE || copies.empty() || |
|
|
|
window_index >= unified_memory->GetWindowCount()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const VkBuffer dst_buffer = unified_memory->GetWindowBuffer(window_index); |
|
|
|
if (dst_buffer == VK_NULL_HANDLE) { |
|
|
|
return; |
|
|
|
} |
|
|
|
boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size()); |
|
|
|
std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); |
|
|
|
|
|
|
|
scheduler.RequestOutsideRenderPassOperationContext(); |
|
|
|
scheduler.Record([src_buffer, dst_buffer, vk_copies](vk::CommandBuffer cmdbuf) { |
|
|
|
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies)); |
|
|
|
if (foreign) { |
|
|
|
const VkBufferMemoryBarrier release{ |
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
|
|
|
.pNext = nullptr, |
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
|
|
|
.dstAccessMask = 0, |
|
|
|
.srcQueueFamilyIndex = queue_family, |
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT, |
|
|
|
.buffer = dst_buffer, |
|
|
|
.offset = covered_begin, |
|
|
|
.size = covered_end - covered_begin, |
|
|
|
}; |
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, |
|
|
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, release); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -457,54 +454,12 @@ void BufferCacheRuntime::CopyFromUnifiedMemory( |
|
|
|
if (src_buffer == VK_NULL_HANDLE) { |
|
|
|
return; |
|
|
|
} |
|
|
|
VkDeviceSize covered_begin = std::numeric_limits<VkDeviceSize>::max(); |
|
|
|
VkDeviceSize covered_end = 0; |
|
|
|
for (const VideoCommon::BufferCopy& copy : copies) { |
|
|
|
covered_begin = (std::min)(covered_begin, static_cast<VkDeviceSize>(copy.dst_offset)); |
|
|
|
covered_end = (std::max)(covered_end, |
|
|
|
static_cast<VkDeviceSize>(copy.dst_offset + copy.size)); |
|
|
|
} |
|
|
|
|
|
|
|
boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size()); |
|
|
|
std::ranges::transform(copies, vk_copies.begin(), MakeUnifiedUploadCopy); |
|
|
|
|
|
|
|
const bool foreign = unified_memory->NeedsForeignOwnershipTransfer(); |
|
|
|
const u32 queue_family = device.GetGraphicsFamily(); |
|
|
|
|
|
|
|
scheduler.RequestOutsideRenderPassOperationContext(); |
|
|
|
scheduler.Record([src_buffer, dst_buffer, vk_copies, foreign, queue_family, covered_begin, |
|
|
|
covered_end](vk::CommandBuffer cmdbuf) { |
|
|
|
if (foreign) { |
|
|
|
const VkBufferMemoryBarrier acquire{ |
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
|
|
|
.pNext = nullptr, |
|
|
|
.srcAccessMask = 0, |
|
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, |
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT, |
|
|
|
.dstQueueFamilyIndex = queue_family, |
|
|
|
.buffer = src_buffer, |
|
|
|
.offset = covered_begin, |
|
|
|
.size = covered_end - covered_begin, |
|
|
|
}; |
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, acquire); |
|
|
|
} |
|
|
|
scheduler.Record([src_buffer, dst_buffer, vk_copies](vk::CommandBuffer cmdbuf) { |
|
|
|
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies)); |
|
|
|
if (foreign) { |
|
|
|
const VkBufferMemoryBarrier release{ |
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
|
|
|
.pNext = nullptr, |
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT, |
|
|
|
.dstAccessMask = 0, |
|
|
|
.srcQueueFamilyIndex = queue_family, |
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT, |
|
|
|
.buffer = src_buffer, |
|
|
|
.offset = covered_begin, |
|
|
|
.size = covered_end - covered_begin, |
|
|
|
}; |
|
|
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, |
|
|
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, release); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -536,6 +491,20 @@ void BufferCacheRuntime::UnifiedMemoryHostBarrier() { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
void BufferCacheRuntime::UnifiedMemoryShaderWriteBarrier() { |
|
|
|
static constexpr VkMemoryBarrier SHADER_WRITE_BARRIER{ |
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, |
|
|
|
.pNext = nullptr, |
|
|
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, |
|
|
|
.dstAccessMask = VK_ACCESS_HOST_READ_BIT, |
|
|
|
}; |
|
|
|
scheduler.RequestOutsideRenderPassOperationContext(); |
|
|
|
scheduler.Record([](vk::CommandBuffer cmdbuf) { |
|
|
|
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, VK_PIPELINE_STAGE_HOST_BIT, 0, |
|
|
|
SHADER_WRITE_BARRIER); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
StagingBufferRef BufferCacheRuntime::UploadStagingBuffer(size_t size) { |
|
|
|
return staging_pool.Request(size, MemoryUsage::Upload); |
|
|
|
} |
|
|
|
|