mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-10-11 22:49:56 +00:00
GS:Vk: Use vkCmdPipelineBarrier2KHR
Co-Authored-By: TJnotJT <[email protected]>
This commit is contained in:
committed by
lightningterror
co-authored by
TJnotJT
parent
4463fe4e7b
commit
cf8633fe50
@@ -52,6 +52,67 @@ enum : u32
|
||||
static u32 s_debug_scope_depth = 0;
|
||||
#endif
|
||||
|
||||
namespace ReplaceVK
|
||||
{
|
||||
static VkPipelineStageFlags TranslateStageFlags(VkPipelineStageFlags2 flags2)
|
||||
{
|
||||
VkPipelineStageFlags flags = static_cast<VkPipelineStageFlags>(flags2);
|
||||
static constexpr VkPipelineStageFlags2 transfer = VK_PIPELINE_STAGE_2_COPY_BIT | VK_PIPELINE_STAGE_2_RESOLVE_BIT | VK_PIPELINE_STAGE_2_BLIT_BIT | VK_PIPELINE_STAGE_2_CLEAR_BIT;
|
||||
if (flags2 & transfer)
|
||||
flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
assert(!(flags2 & ~transfer & ~static_cast<VkPipelineStageFlags2>(VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM)));
|
||||
return flags;
|
||||
}
|
||||
|
||||
static VkAccessFlags TranslateAccessFlags(VkAccessFlags2 flags2)
|
||||
{
|
||||
VkAccessFlags flags = static_cast<VkAccessFlags>(flags2);
|
||||
assert(!(flags2 & ~static_cast<VkAccessFlags2>(VK_ACCESS_FLAG_BITS_MAX_ENUM)));
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void VKAPI_CALL CmdPipelineBarrier2(VkCommandBuffer commandBuffer, const VkDependencyInfo* RESTRICT pDependencyInfo)
|
||||
{
|
||||
assert(!pDependencyInfo->pNext);
|
||||
VkDependencyFlags dependencyFlags = pDependencyInfo->dependencyFlags;
|
||||
for (const VkMemoryBarrier2& barrier2 : std::span(pDependencyInfo->pMemoryBarriers, pDependencyInfo->memoryBarrierCount))
|
||||
{
|
||||
VkMemoryBarrier barrier = {VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
barrier.srcAccessMask = TranslateAccessFlags(barrier2.srcAccessMask);
|
||||
barrier.dstAccessMask = TranslateAccessFlags(barrier2.dstAccessMask);
|
||||
vkCmdPipelineBarrier(commandBuffer, TranslateStageFlags(barrier2.srcStageMask), TranslateStageFlags(barrier2.dstStageMask),
|
||||
dependencyFlags, 1, &barrier, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
for (const VkBufferMemoryBarrier2& barrier2 : std::span(pDependencyInfo->pBufferMemoryBarriers, pDependencyInfo->bufferMemoryBarrierCount))
|
||||
{
|
||||
VkBufferMemoryBarrier barrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
barrier.srcAccessMask = TranslateAccessFlags(barrier2.srcAccessMask);
|
||||
barrier.dstAccessMask = TranslateAccessFlags(barrier2.dstAccessMask);
|
||||
barrier.srcQueueFamilyIndex = barrier2.srcQueueFamilyIndex;
|
||||
barrier.dstQueueFamilyIndex = barrier2.dstQueueFamilyIndex;
|
||||
barrier.buffer = barrier2.buffer;
|
||||
barrier.offset = barrier2.offset;
|
||||
barrier.size = barrier2.size;
|
||||
vkCmdPipelineBarrier(commandBuffer, TranslateStageFlags(barrier2.srcStageMask), TranslateStageFlags(barrier2.dstStageMask),
|
||||
dependencyFlags, 0, nullptr, 1, &barrier, 0, nullptr);
|
||||
}
|
||||
for (const VkImageMemoryBarrier2& barrier2 : std::span(pDependencyInfo->pImageMemoryBarriers, pDependencyInfo->imageMemoryBarrierCount))
|
||||
{
|
||||
VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
barrier.srcAccessMask = TranslateAccessFlags(barrier2.srcAccessMask);
|
||||
barrier.dstAccessMask = TranslateAccessFlags(barrier2.dstAccessMask);
|
||||
barrier.oldLayout = barrier2.oldLayout;
|
||||
barrier.newLayout = barrier2.newLayout;
|
||||
barrier.srcQueueFamilyIndex = barrier2.srcQueueFamilyIndex;
|
||||
barrier.dstQueueFamilyIndex = barrier2.dstQueueFamilyIndex;
|
||||
barrier.image = barrier2.image;
|
||||
barrier.subresourceRange = barrier2.subresourceRange;
|
||||
vkCmdPipelineBarrier(commandBuffer, TranslateStageFlags(barrier2.srcStageMask), TranslateStageFlags(barrier2.dstStageMask),
|
||||
dependencyFlags, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
}
|
||||
} // namespace ReplaceVK
|
||||
|
||||
static bool IsDATEModePrimIDInit(u32 flag)
|
||||
{
|
||||
return flag == 1 || flag == 2;
|
||||
@@ -423,6 +484,7 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab
|
||||
m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps =
|
||||
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_synchronization2 = SupportsExtension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, false);
|
||||
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1)
|
||||
{
|
||||
@@ -619,6 +681,8 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
device_info.ppEnabledLayerNames = layer_names;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceSynchronization2Features sync2_features = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES};
|
||||
// provoking vertex
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
@@ -634,6 +698,11 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_ext_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT};
|
||||
|
||||
if (m_optional_extensions.vk_khr_synchronization2)
|
||||
{
|
||||
sync2_features.synchronization2 = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &sync2_features);
|
||||
}
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
{
|
||||
provoking_vertex_feature.provokingVertexLast = VK_TRUE;
|
||||
@@ -703,6 +772,12 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
if (!ProcessDeviceExtensions())
|
||||
return false;
|
||||
|
||||
// Add replacements for unsupported functions
|
||||
if (!m_optional_extensions.vk_khr_synchronization2)
|
||||
{
|
||||
vkCmdPipelineBarrier2KHR = ReplaceVK::CmdPipelineBarrier2;
|
||||
}
|
||||
|
||||
if (m_spinning_supported)
|
||||
{
|
||||
vkGetDeviceQueue(m_device, m_spin_queue_family_index, spin_queue_index, &m_spin_queue);
|
||||
@@ -726,6 +801,8 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
{
|
||||
// advanced feature checks
|
||||
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
|
||||
VkPhysicalDeviceSynchronization2Features sync2_features = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES};
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
@@ -741,6 +818,8 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT };
|
||||
|
||||
// add in optional feature structs
|
||||
if (m_optional_extensions.vk_khr_synchronization2)
|
||||
Vulkan::AddPointerToChain(&features2, &sync2_features);
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
Vulkan::AddPointerToChain(&features2, &provoking_vertex_features);
|
||||
if (m_optional_extensions.vk_ext_line_rasterization)
|
||||
@@ -758,6 +837,7 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
vkGetPhysicalDeviceFeatures2(m_physical_device, &features2);
|
||||
|
||||
// confirm we actually support it
|
||||
m_optional_extensions.vk_khr_synchronization2 &= (sync2_features.synchronization2 == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access &=
|
||||
(rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
@@ -838,6 +918,8 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
m_optional_extensions.vk_swapchain_maintenance1 ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_full_screen_exclusive is %s",
|
||||
m_optional_extensions.vk_ext_full_screen_exclusive ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_KHR_synchronization2 is %s",
|
||||
m_optional_extensions.vk_khr_synchronization2 ? "supported" : "NOT supported");
|
||||
Console.WriteLn(
|
||||
"VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_line_rasterization is %s",
|
||||
@@ -1667,11 +1749,8 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key)
|
||||
subpass_dependency[num_subpass_dependencies].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].srcAccessMask =
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].dstAccessMask =
|
||||
UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].dependencyFlags =
|
||||
UseFeedbackLoopLayout() ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) :
|
||||
VK_DEPENDENCY_BY_REGION_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].dstAccessMask = static_cast<VkAccessFlags>(GetFeedbackLoopInputAccessFlags());
|
||||
subpass_dependency[num_subpass_dependencies].dependencyFlags = GetFeedbackBarrierDependencyFlags();
|
||||
num_subpass_dependencies++;
|
||||
}
|
||||
}
|
||||
@@ -1713,11 +1792,8 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key)
|
||||
subpass_dependency[num_subpass_dependencies].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].srcAccessMask =
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].dstAccessMask =
|
||||
UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].dependencyFlags =
|
||||
UseFeedbackLoopLayout() ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) :
|
||||
VK_DEPENDENCY_BY_REGION_BIT;
|
||||
subpass_dependency[num_subpass_dependencies].dstAccessMask = static_cast<VkAccessFlags>(GetFeedbackLoopInputAccessFlags());
|
||||
subpass_dependency[num_subpass_dependencies].dependencyFlags = GetFeedbackBarrierDependencyFlags();
|
||||
num_subpass_dependencies++;
|
||||
}
|
||||
}
|
||||
@@ -1999,7 +2075,9 @@ void GSDeviceVK::SubmitSpinCommand(u32 index, u32 cycles)
|
||||
{
|
||||
m_spin_buffer_initialized = true;
|
||||
vkCmdFillBuffer(resources.command_buffer, m_spin_buffer, 0, VK_WHOLE_SIZE, 0);
|
||||
VkBufferMemoryBarrier barrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
VkBufferMemoryBarrier2 barrier = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2};
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
barrier.srcQueueFamilyIndex = m_spin_queue_family_index;
|
||||
@@ -2007,13 +2085,22 @@ void GSDeviceVK::SubmitSpinCommand(u32 index, u32 cycles)
|
||||
barrier.buffer = m_spin_buffer;
|
||||
barrier.offset = 0;
|
||||
barrier.size = VK_WHOLE_SIZE;
|
||||
vkCmdPipelineBarrier(resources.command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 1, &barrier, 0, nullptr);
|
||||
VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
|
||||
dependency.bufferMemoryBarrierCount = 1;
|
||||
dependency.pBufferMemoryBarriers = &barrier;
|
||||
vkCmdPipelineBarrier2KHR(resources.command_buffer, &dependency);
|
||||
}
|
||||
|
||||
if (m_spin_queue_is_graphics_queue)
|
||||
vkCmdPipelineBarrier(resources.command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 0, nullptr);
|
||||
{
|
||||
VkMemoryBarrier2 barrier = {VK_STRUCTURE_TYPE_MEMORY_BARRIER_2};
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
|
||||
VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
|
||||
dependency.memoryBarrierCount = 1;
|
||||
dependency.pMemoryBarriers = &barrier;
|
||||
vkCmdPipelineBarrier2KHR(resources.command_buffer, &dependency);
|
||||
}
|
||||
|
||||
const u32 timestamp_base = (index + NUM_COMMAND_BUFFERS) * 2;
|
||||
vkCmdResetQueryPool(resources.command_buffer, m_timestamp_query_pool, timestamp_base, 2);
|
||||
@@ -3052,9 +3139,9 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
sTexVK->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
dTexVK->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
sTexVK->TransitionToLayout(
|
||||
(dTexVK == sTexVK) ? GSTextureVK::Layout::TransferSelf : GSTextureVK::Layout::TransferSrc);
|
||||
(dTexVK == sTexVK) ? GSTextureVK::Layout::CopySelf : GSTextureVK::Layout::CopySrc);
|
||||
dTexVK->TransitionToLayout(
|
||||
(dTexVK == sTexVK) ? GSTextureVK::Layout::TransferSelf : GSTextureVK::Layout::TransferDst);
|
||||
(dTexVK == sTexVK) ? GSTextureVK::Layout::CopySelf : GSTextureVK::Layout::CopyDst);
|
||||
|
||||
vkCmdCopyImage(GetCurrentCommandBuffer(), sTexVK->GetImage(), sTexVK->GetVkLayout(), dTexVK->GetImage(),
|
||||
dTexVK->GetVkLayout(), 1, &ic);
|
||||
@@ -3322,8 +3409,8 @@ void GSDeviceVK::BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel,
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
sTexVK->TransitionToLayout(GSTextureVK::Layout::TransferSrc);
|
||||
dTexVK->TransitionToLayout(GSTextureVK::Layout::TransferDst);
|
||||
sTexVK->TransitionToLayout(GSTextureVK::Layout::BlitSrc);
|
||||
dTexVK->TransitionToLayout(GSTextureVK::Layout::BlitDst);
|
||||
|
||||
// ensure we don't leave this bound later on
|
||||
if (m_tfx_textures[0] == sTexVK)
|
||||
@@ -4768,7 +4855,7 @@ void GSDeviceVK::RenderBlankFrame()
|
||||
|
||||
VkCommandBuffer cmdbuffer = GetCurrentCommandBuffer();
|
||||
GSTextureVK* sctex = m_swap_chain->GetCurrentTexture();
|
||||
sctex->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::TransferDst);
|
||||
sctex->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::ClearDst);
|
||||
|
||||
constexpr VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
vkCmdClearColorImage(
|
||||
@@ -6543,27 +6630,9 @@ void GSDeviceVK::UploadHWDrawVerticesAndIndices(GSHWDrawConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier GSDeviceVK::GetColorBufferFeedbackBarrier(GSTextureVK* rt) const
|
||||
VkImageLayout GSDeviceVK::GetFeedbackLoopLayout() const
|
||||
{
|
||||
const VkImageLayout layout =
|
||||
UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL;
|
||||
const VkAccessFlags dst_access =
|
||||
UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
return {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, dst_access, layout, layout,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, rt->GetImage(), {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier GSDeviceVK::GetDepthStencilBufferFeedbackBarrier(GSTextureVK* ds) const
|
||||
{
|
||||
const VkImageLayout layout =
|
||||
UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL;
|
||||
const VkAccessFlags dst_access =
|
||||
UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
return {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, dst_access, layout, layout,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, ds->GetImage(),
|
||||
{VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u}};
|
||||
return UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
|
||||
VkDependencyFlags GSDeviceVK::GetFeedbackBarrierDependencyFlags() const
|
||||
@@ -6572,6 +6641,50 @@ VkDependencyFlags GSDeviceVK::GetFeedbackBarrierDependencyFlags() const
|
||||
VK_DEPENDENCY_BY_REGION_BIT;
|
||||
}
|
||||
|
||||
VkAccessFlags2 GSDeviceVK::GetFeedbackLoopInputAccessFlags() const
|
||||
{
|
||||
return UseFeedbackLoopLayout() ? VK_ACCESS_2_SHADER_READ_BIT : VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT;
|
||||
}
|
||||
|
||||
void GSDeviceVK::FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds)
|
||||
{
|
||||
VkImageMemoryBarrier2 barrier_template = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2};
|
||||
barrier_template.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
|
||||
barrier_template.dstAccessMask = GetFeedbackLoopInputAccessFlags();
|
||||
barrier_template.oldLayout = GetFeedbackLoopLayout();
|
||||
barrier_template.newLayout = GetFeedbackLoopLayout();
|
||||
barrier_template.subresourceRange.levelCount = 1;
|
||||
barrier_template.subresourceRange.layerCount = 1;
|
||||
|
||||
std::array<VkImageMemoryBarrier2, 2> barriers;
|
||||
u32 num_barriers = 0;
|
||||
|
||||
if (rt)
|
||||
{
|
||||
VkImageMemoryBarrier2& barrier = barriers[num_barriers++] = barrier_template;
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
barrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.image = rt->GetImage();
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
|
||||
if (ds)
|
||||
{
|
||||
VkImageMemoryBarrier2& barrier = barriers[num_barriers++] = barrier_template;
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
|
||||
barrier.srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
barrier.image = ds->GetImage();
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
|
||||
VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
|
||||
dependency.dependencyFlags = GetFeedbackBarrierDependencyFlags();
|
||||
dependency.imageMemoryBarrierCount = num_barriers;
|
||||
dependency.pImageMemoryBarriers = barriers.data();
|
||||
|
||||
vkCmdPipelineBarrier2KHR(GetCurrentCommandBuffer(), &dependency);
|
||||
}
|
||||
|
||||
void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, GSTextureVK* draw_ds,
|
||||
bool one_barrier, bool full_barrier)
|
||||
{
|
||||
@@ -6585,38 +6698,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
if ((one_barrier || full_barrier) && !(config.IsFeedbackLoopRT(m_pipeline_selector.ps) || config.IsFeedbackLoopDepth(m_pipeline_selector.ps))) [[unlikely]]
|
||||
Console.Warning("VK: Possible unnecessary barrier detected.");
|
||||
#endif
|
||||
VkDependencyFlags barrier_flags = GetFeedbackBarrierDependencyFlags();
|
||||
|
||||
std::array<VkImageMemoryBarrier, 2> barriers;
|
||||
u32 n_barriers = 0;
|
||||
if (full_barrier || one_barrier)
|
||||
{
|
||||
if (draw_rt)
|
||||
{
|
||||
barriers[0] = GetColorBufferFeedbackBarrier(draw_rt);
|
||||
n_barriers++;
|
||||
}
|
||||
if (draw_ds)
|
||||
{
|
||||
barriers[1] = GetDepthStencilBufferFeedbackBarrier(draw_ds);
|
||||
n_barriers++;
|
||||
}
|
||||
}
|
||||
|
||||
const auto IssueBarriers = [&]() {
|
||||
if (draw_rt)
|
||||
{
|
||||
vkCmdPipelineBarrier(GetCurrentCommandBuffer(),
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags, 0, nullptr, 0, nullptr, 1, &barriers[0]);
|
||||
}
|
||||
if (draw_ds)
|
||||
{
|
||||
vkCmdPipelineBarrier(GetCurrentCommandBuffer(),
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags, 0, nullptr, 0, nullptr, 1, &barriers[1]);
|
||||
}
|
||||
};
|
||||
const int n_barriers = (draw_rt ? 1 : 0) + (draw_ds ? 1 : 0);
|
||||
|
||||
if (full_barrier)
|
||||
{
|
||||
@@ -6630,7 +6712,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
|
||||
for (u32 n = 0, p = 0; n < draw_list_size; n++)
|
||||
{
|
||||
IssueBarriers();
|
||||
FeedbackBarrier(draw_rt, draw_ds);
|
||||
|
||||
const u32 count = config.drawlist->at(n) * indices_per_prim;
|
||||
Draw(config, p, count);
|
||||
@@ -6643,7 +6725,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
if (one_barrier)
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, n_barriers);
|
||||
IssueBarriers();
|
||||
FeedbackBarrier(draw_rt, draw_ds);
|
||||
}
|
||||
|
||||
Draw(config);
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
bool vk_swapchain_maintenance1_is_khr : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_khr_shader_non_semantic_info : 1;
|
||||
bool vk_khr_synchronization2 : 1;
|
||||
bool vk_ext_attachment_feedback_loop_layout : 1;
|
||||
bool vk_ext_fragment_shader_interlock : 1;
|
||||
};
|
||||
@@ -640,9 +641,10 @@ public:
|
||||
void RenderHW(GSHWDrawConfig& config) override;
|
||||
void UpdateHWPipelineSelector(GSHWDrawConfig& config, PipelineSelector& pipe);
|
||||
void UploadHWDrawVerticesAndIndices(GSHWDrawConfig& config);
|
||||
VkImageMemoryBarrier GetColorBufferFeedbackBarrier(GSTextureVK* rt) const;
|
||||
VkImageMemoryBarrier GetDepthStencilBufferFeedbackBarrier(GSTextureVK* ds) const;
|
||||
VkImageLayout GetFeedbackLoopLayout() const;
|
||||
VkDependencyFlags GetFeedbackBarrierDependencyFlags() const;
|
||||
VkAccessFlags2 GetFeedbackLoopInputAccessFlags() const;
|
||||
void FeedbackBarrier(GSTextureVK* rt, GSTextureVK* ds);
|
||||
void SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt, GSTextureVK* draw_ds,
|
||||
bool one_barrier, bool full_barrier);
|
||||
|
||||
|
||||
@@ -34,31 +34,105 @@ static constexpr const VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZL
|
||||
|
||||
static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout)
|
||||
{
|
||||
static constexpr std::array<VkImageLayout, static_cast<u32>(GSTextureVK::Layout::Count)> s_vk_layout_mapping = {{
|
||||
static constexpr VkImageLayout s_vk_layout_mapping[] = {
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, // Undefined
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED, // Preinitialized
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // ColorAttachment
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // DepthStencilAttachment
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // ShaderReadOnly
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // ClearDst
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TransferSrc
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TransferDst
|
||||
VK_IMAGE_LAYOUT_GENERAL, // TransferSelf
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // CopySrc
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // CopyDst
|
||||
VK_IMAGE_LAYOUT_GENERAL, // CopySelf
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // BlitSrc
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // BlitDst
|
||||
VK_IMAGE_LAYOUT_GENERAL, // BlitSelf
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // PresentSrc
|
||||
VK_IMAGE_LAYOUT_GENERAL, // FeedbackLoop
|
||||
VK_IMAGE_LAYOUT_GENERAL, // ReadWriteImage
|
||||
VK_IMAGE_LAYOUT_GENERAL, // ComputeReadWriteImage
|
||||
VK_IMAGE_LAYOUT_GENERAL, // General
|
||||
}};
|
||||
return (layout == GSTextureVK::Layout::FeedbackLoop && GSDeviceVK::GetInstance()->UseFeedbackLoopLayout()) ?
|
||||
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
|
||||
s_vk_layout_mapping[static_cast<u32>(layout)];
|
||||
};
|
||||
static_assert(std::size(s_vk_layout_mapping) == static_cast<u32>(GSTextureVK::Layout::Count));
|
||||
if (layout == GSTextureVK::Layout::FeedbackLoop)
|
||||
return GSDeviceVK::GetInstance()->GetFeedbackLoopLayout();
|
||||
else
|
||||
return s_vk_layout_mapping[static_cast<u32>(layout)];
|
||||
}
|
||||
|
||||
static VkAccessFlagBits GetFeedbackLoopInputAccessBits()
|
||||
static VkPipelineStageFlags2 GetPipelineStageFlags(GSTextureVK::Layout layout, bool color)
|
||||
{
|
||||
return GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT :
|
||||
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
static constexpr VkPipelineStageFlags2 s_vk_stage_mapping[] = {
|
||||
VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, // Undefined
|
||||
VK_PIPELINE_STAGE_2_HOST_BIT, // Preinitialized
|
||||
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, // ColorAttachment
|
||||
VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, // DepthStencilAttachment
|
||||
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, // ShaderReadOnly
|
||||
VK_PIPELINE_STAGE_2_CLEAR_BIT, // ClearDst
|
||||
VK_PIPELINE_STAGE_2_COPY_BIT, // CopySrc
|
||||
VK_PIPELINE_STAGE_2_COPY_BIT, // CopyDst
|
||||
VK_PIPELINE_STAGE_2_COPY_BIT, // CopySelf
|
||||
VK_PIPELINE_STAGE_2_BLIT_BIT, // BlitSrc
|
||||
VK_PIPELINE_STAGE_2_BLIT_BIT, // BlitDst
|
||||
VK_PIPELINE_STAGE_2_BLIT_BIT, // BlitSelf
|
||||
VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, // PresentSrc
|
||||
VK_PIPELINE_STAGE_2_NONE, // FeedbackLoop (overridden)
|
||||
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, // ReadWriteImage
|
||||
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, // ComputeReadWriteImage
|
||||
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, // General
|
||||
};
|
||||
static_assert(std::size(s_vk_stage_mapping) == static_cast<u32>(GSTextureVK::Layout::Count));
|
||||
if (layout == GSTextureVK::Layout::FeedbackLoop)
|
||||
{
|
||||
VkPipelineStageFlags2 flags = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
|
||||
if (color)
|
||||
flags |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
else
|
||||
flags |= VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
|
||||
return flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
return s_vk_stage_mapping[static_cast<u32>(layout)];
|
||||
}
|
||||
}
|
||||
|
||||
static VkAccessFlags2 GetAccessFlags(GSTextureVK::Layout layout, bool color)
|
||||
{
|
||||
static constexpr VkPipelineStageFlags2 s_vk_access_mapping[] = {
|
||||
VK_ACCESS_2_NONE, // Undefined
|
||||
VK_ACCESS_2_HOST_WRITE_BIT, // Preinitialized
|
||||
VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, // ColorAttachment
|
||||
VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // DepthStencilAttachment
|
||||
VK_ACCESS_2_SHADER_READ_BIT, // ShaderReadOnly
|
||||
VK_ACCESS_2_TRANSFER_WRITE_BIT, // ClearDst
|
||||
VK_ACCESS_2_TRANSFER_READ_BIT, // CopySrc
|
||||
VK_ACCESS_2_TRANSFER_WRITE_BIT, // CopyDst
|
||||
VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, // CopySelf
|
||||
VK_ACCESS_2_TRANSFER_READ_BIT, // BlitSrc
|
||||
VK_ACCESS_2_TRANSFER_WRITE_BIT, // BlitDst
|
||||
VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, // BlitSelf
|
||||
VK_ACCESS_2_NONE, // PresentSrc
|
||||
VK_ACCESS_2_NONE, // FeedbackLoop (overridden)
|
||||
VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, // ReadWriteImage
|
||||
VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, // ComputeReadWriteImage
|
||||
VK_ACCESS_2_NONE, // General
|
||||
};
|
||||
static_assert(std::size(s_vk_access_mapping) == static_cast<u32>(GSTextureVK::Layout::Count));
|
||||
|
||||
if (layout == GSTextureVK::Layout::FeedbackLoop)
|
||||
{
|
||||
VkAccessFlags2 flags;
|
||||
if (color)
|
||||
flags = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
else
|
||||
flags = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
return flags | GSDeviceVK::GetInstance()->GetFeedbackLoopInputAccessFlags();
|
||||
}
|
||||
else
|
||||
{
|
||||
return s_vk_access_mapping[static_cast<u32>(layout)];
|
||||
}
|
||||
}
|
||||
|
||||
GSTextureVK::GSTextureVK(Usage usage, Format format, int width, int height, int levels, VkImage image,
|
||||
@@ -315,9 +389,9 @@ void GSTextureVK::UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32
|
||||
{
|
||||
const Layout old_layout = m_layout;
|
||||
if (old_layout == Layout::Undefined)
|
||||
TransitionToLayout(cmdbuf, Layout::TransferDst);
|
||||
else if (old_layout != Layout::TransferDst)
|
||||
TransitionSubresourcesToLayout(cmdbuf, level, 1, old_layout, Layout::TransferDst);
|
||||
TransitionToLayout(cmdbuf, Layout::CopyDst);
|
||||
else if (old_layout != Layout::CopyDst)
|
||||
TransitionSubresourcesToLayout(cmdbuf, level, 1, old_layout, Layout::CopyDst);
|
||||
|
||||
const VkBufferImageCopy bic = {static_cast<VkDeviceSize>(buffer_offset), row_length, buffer_height,
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, static_cast<u32>(level), 0u, 1u}, {static_cast<s32>(x), static_cast<s32>(y), 0},
|
||||
@@ -325,8 +399,8 @@ void GSTextureVK::UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32
|
||||
|
||||
vkCmdCopyBufferToImage(cmdbuf, buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bic);
|
||||
|
||||
if (old_layout != Layout::TransferDst && old_layout != Layout::Undefined)
|
||||
TransitionSubresourcesToLayout(cmdbuf, level, 1, Layout::TransferDst, old_layout);
|
||||
if (old_layout != Layout::CopyDst && old_layout != Layout::Undefined)
|
||||
TransitionSubresourcesToLayout(cmdbuf, level, 1, Layout::CopyDst, old_layout);
|
||||
}
|
||||
|
||||
bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int layer)
|
||||
@@ -387,7 +461,7 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
|
||||
// first time the texture is used? don't leave it undefined
|
||||
if (m_layout == Layout::Undefined)
|
||||
TransitionToLayout(cmdbuf, Layout::TransferDst);
|
||||
TransitionToLayout(cmdbuf, Layout::CopyDst);
|
||||
|
||||
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
|
||||
if (IsRenderTarget())
|
||||
@@ -469,7 +543,7 @@ void GSTextureVK::Unmap()
|
||||
|
||||
// first time the texture is used? don't leave it undefined
|
||||
if (m_layout == Layout::Undefined)
|
||||
TransitionToLayout(cmdbuf, Layout::TransferDst);
|
||||
TransitionToLayout(cmdbuf, Layout::CopyDst);
|
||||
|
||||
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
|
||||
if (IsRenderTarget())
|
||||
@@ -494,7 +568,7 @@ void GSTextureVK::GenerateMipmap()
|
||||
const VkCommandBuffer cmdbuf = GetCommandBufferForUpdate();
|
||||
|
||||
if (m_layout == Layout::Undefined)
|
||||
TransitionToLayout(cmdbuf, Layout::TransferSrc);
|
||||
TransitionToLayout(cmdbuf, Layout::BlitSrc);
|
||||
|
||||
for (int dst_level = 1; dst_level < m_mipmap_levels; dst_level++)
|
||||
{
|
||||
@@ -504,8 +578,8 @@ void GSTextureVK::GenerateMipmap()
|
||||
const int dst_width = std::max<int>(m_size.x >> dst_level, 1);
|
||||
const int dst_height = std::max<int>(m_size.y >> dst_level, 1);
|
||||
|
||||
TransitionSubresourcesToLayout(cmdbuf, src_level, 1, m_layout, Layout::TransferSrc);
|
||||
TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, m_layout, Layout::TransferDst);
|
||||
TransitionSubresourcesToLayout(cmdbuf, src_level, 1, m_layout, Layout::BlitSrc);
|
||||
TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, m_layout, Layout::BlitDst);
|
||||
|
||||
const VkImageBlit blit = {
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, static_cast<u32>(src_level), 0u, 1u}, // srcSubresource
|
||||
@@ -517,8 +591,8 @@ void GSTextureVK::GenerateMipmap()
|
||||
vkCmdBlitImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
||||
|
||||
TransitionSubresourcesToLayout(cmdbuf, src_level, 1, Layout::TransferSrc, m_layout);
|
||||
TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, Layout::TransferDst, m_layout);
|
||||
TransitionSubresourcesToLayout(cmdbuf, src_level, 1, Layout::BlitSrc, m_layout);
|
||||
TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, Layout::BlitDst, m_layout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,168 +694,29 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
||||
aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, 0, 0, GetVkImageLayout(old_layout),
|
||||
GetVkImageLayout(new_layout), VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, m_image,
|
||||
{aspect, static_cast<u32>(start_level), static_cast<u32>(num_levels), 0u, 1u}};
|
||||
// These layouts should only be used on one side of the barrier
|
||||
pxAssert(old_layout != Layout::PresentSrc);
|
||||
pxAssert(new_layout != Layout::Undefined);
|
||||
pxAssert(new_layout != Layout::Preinitialized);
|
||||
|
||||
// srcStageMask -> Stages that must complete before the barrier
|
||||
// dstStageMask -> Stages that must wait for after the barrier before beginning
|
||||
VkPipelineStageFlags srcStageMask, dstStageMask;
|
||||
switch (old_layout)
|
||||
{
|
||||
case Layout::Undefined:
|
||||
// Layout undefined therefore contents undefined, and we don't care what happens to it.
|
||||
barrier.srcAccessMask = 0;
|
||||
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
VkImageMemoryBarrier2 barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2};
|
||||
barrier.srcStageMask = GetPipelineStageFlags(old_layout, !IsDepthStencil());
|
||||
barrier.dstStageMask = GetPipelineStageFlags(new_layout, !IsDepthStencil());
|
||||
barrier.srcAccessMask = GetAccessFlags(old_layout, !IsDepthStencil());
|
||||
barrier.dstAccessMask = GetAccessFlags(new_layout, !IsDepthStencil());
|
||||
barrier.oldLayout = GetVkImageLayout(old_layout);
|
||||
barrier.newLayout = GetVkImageLayout(new_layout);
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = m_image;
|
||||
barrier.subresourceRange = {aspect, static_cast<u32>(start_level), static_cast<u32>(num_levels), 0u, 1u};
|
||||
|
||||
case Layout::Preinitialized:
|
||||
// Image has been pre-initialized by the host, so ensure all writes have completed.
|
||||
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_HOST_BIT;
|
||||
break;
|
||||
VkDependencyInfo dependency = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
|
||||
dependency.dependencyFlags = GSDeviceVK::GetInstance()->GetFeedbackBarrierDependencyFlags();
|
||||
dependency.imageMemoryBarrierCount = 1;
|
||||
dependency.pImageMemoryBarriers = &barrier;
|
||||
|
||||
case Layout::ColorAttachment:
|
||||
// Image was being used as a color attachment, so ensure all writes have completed.
|
||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
|
||||
case Layout::DepthStencilAttachment:
|
||||
// Image was being used as a depthstencil attachment, so ensure all writes have completed.
|
||||
barrier.srcAccessMask =
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
|
||||
case Layout::ShaderReadOnly:
|
||||
// Image was being used as a shader resource, make sure all reads have finished.
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::ClearDst:
|
||||
// Image was being used as a clear destination, ensure all writes have finished.
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::TransferSrc:
|
||||
// Image was being used as a copy source, ensure all reads have finished.
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::TransferDst:
|
||||
// Image was being used as a copy destination, ensure all writes have finished.
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::TransferSelf:
|
||||
// Image was being used as a copy source and destination, ensure all reads and writes have finished.
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::FeedbackLoop:
|
||||
barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits())
|
||||
: (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits());
|
||||
srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
|
||||
: (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
break;
|
||||
|
||||
case Layout::ReadWriteImage:
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::ComputeReadWriteImage:
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::General:
|
||||
default:
|
||||
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (new_layout)
|
||||
{
|
||||
case Layout::Undefined:
|
||||
barrier.dstAccessMask = 0;
|
||||
dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
|
||||
case Layout::ColorAttachment:
|
||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
|
||||
case Layout::DepthStencilAttachment:
|
||||
barrier.dstAccessMask =
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
|
||||
case Layout::ShaderReadOnly:
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::ClearDst:
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::TransferSrc:
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::TransferDst:
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::TransferSelf:
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::PresentSrc:
|
||||
srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
|
||||
case Layout::FeedbackLoop:
|
||||
barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits())
|
||||
: (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits());
|
||||
dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
|
||||
: (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
break;
|
||||
|
||||
case Layout::ReadWriteImage:
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::ComputeReadWriteImage:
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case Layout::General:
|
||||
default:
|
||||
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
break;
|
||||
}
|
||||
vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
vkCmdPipelineBarrier2KHR(command_buffer, &dependency);
|
||||
|
||||
// Count as a UAV barrier if we transition to/from UAV.
|
||||
if (IsRenderTargetOrDepthStencil() &&
|
||||
@@ -902,9 +837,9 @@ void GSDownloadTextureVK::CopyFromTexture(
|
||||
|
||||
GSTextureVK::Layout old_layout = vkTex->GetLayout();
|
||||
if (old_layout == GSTextureVK::Layout::Undefined)
|
||||
vkTex->TransitionToLayout(cmdbuf, GSTextureVK::Layout::TransferSrc);
|
||||
else if (old_layout != GSTextureVK::Layout::TransferSrc)
|
||||
vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, old_layout, GSTextureVK::Layout::TransferSrc);
|
||||
vkTex->TransitionToLayout(cmdbuf, GSTextureVK::Layout::CopySrc);
|
||||
else if (old_layout != GSTextureVK::Layout::CopySrc)
|
||||
vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, old_layout, GSTextureVK::Layout::CopySrc);
|
||||
|
||||
VkBufferImageCopy image_copy = {};
|
||||
const VkImageAspectFlags aspect = vkTex->IsDepthStencil() ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
@@ -919,22 +854,24 @@ void GSDownloadTextureVK::CopyFromTexture(
|
||||
vkCmdCopyImageToBuffer(cmdbuf, vkTex->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer, 1, &image_copy);
|
||||
|
||||
// flush gpu cache
|
||||
const VkBufferMemoryBarrier buffer_info = {
|
||||
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask
|
||||
VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask
|
||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
|
||||
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
|
||||
m_buffer, // VkBuffer buffer
|
||||
0, // VkDeviceSize offset
|
||||
copy_size // VkDeviceSize size
|
||||
};
|
||||
vkCmdPipelineBarrier(
|
||||
cmdbuf, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, 1, &buffer_info, 0, nullptr);
|
||||
VkBufferMemoryBarrier2 buffer_info = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2};
|
||||
buffer_info.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
|
||||
buffer_info.dstStageMask = VK_PIPELINE_STAGE_2_HOST_BIT;
|
||||
buffer_info.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
|
||||
buffer_info.dstAccessMask = VK_ACCESS_2_HOST_READ_BIT;
|
||||
buffer_info.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
buffer_info.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
buffer_info.buffer = m_buffer;
|
||||
buffer_info.size = copy_size;
|
||||
|
||||
if (old_layout != GSTextureVK::Layout::TransferSrc && old_layout != GSTextureVK::Layout::Undefined)
|
||||
vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, GSTextureVK::Layout::TransferSrc, old_layout);
|
||||
VkDependencyInfo barrier_info = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
|
||||
barrier_info.bufferMemoryBarrierCount = 1;
|
||||
barrier_info.pBufferMemoryBarriers = &buffer_info;
|
||||
|
||||
vkCmdPipelineBarrier2KHR(cmdbuf, &barrier_info);
|
||||
|
||||
if (old_layout != GSTextureVK::Layout::CopySrc && old_layout != GSTextureVK::Layout::Undefined)
|
||||
vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, GSTextureVK::Layout::CopySrc, old_layout);
|
||||
|
||||
m_copy_fence_counter = GSDeviceVK::GetInstance()->GetCurrentFenceCounter();
|
||||
m_needs_cache_invalidate = true;
|
||||
|
||||
@@ -20,9 +20,12 @@ public:
|
||||
DepthStencilAttachment,
|
||||
ShaderReadOnly,
|
||||
ClearDst,
|
||||
TransferSrc,
|
||||
TransferDst,
|
||||
TransferSelf,
|
||||
CopySrc,
|
||||
CopyDst,
|
||||
CopySelf,
|
||||
BlitSrc,
|
||||
BlitDst,
|
||||
BlitSelf,
|
||||
PresentSrc,
|
||||
FeedbackLoop,
|
||||
ReadWriteImage,
|
||||
|
||||
@@ -201,6 +201,7 @@ VULKAN_DEVICE_ENTRY_POINT(vkCmdSetEvent, true)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdResetEvent, true)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdWaitEvents, true)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdPipelineBarrier, true)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdPipelineBarrier2KHR, false)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdBeginQuery, true)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdEndQuery, true)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdResetQueryPool, true)
|
||||
|
||||
Reference in New Issue
Block a user