diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index 6e698038c..8c297ff83 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -405,7 +405,9 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::spanpred_op.Value() == PredicateOperation::Zpass) { if (rasterizer) { - rasterizer->StartPredication(); + rasterizer->StartPredication(predication->Address(), + predication->action.Value() == Predication::DrawIfVisible, + predication->hint.Value() == PredicationHint::Wait); } } else { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 73022f639..12d187403 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -42,7 +42,9 @@ Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_, : instance{instance_}, scheduler{scheduler_}, page_manager{this}, buffer_cache{instance, scheduler, *this, liverpool_, texture_cache, page_manager}, texture_cache{instance, scheduler, buffer_cache, page_manager}, liverpool{liverpool_}, - memory{Core::Memory::Instance()}, pipeline_cache{instance, scheduler, liverpool} { + memory{Core::Memory::Instance()}, pipeline_cache{instance, scheduler, liverpool}, + occlusion_query_buffer{instance, scheduler, VideoCore::MemoryUsage::DeviceLocal, 0, + vk::BufferUsageFlagBits::eConditionalRenderingEXT | vk::BufferUsageFlagBits::eTransferDst, sizeof(u32)*OCCLUSION_QUERIES_COUNT} { if (!Config::nullGpu()) { liverpool->BindRasterizer(this); } @@ -52,6 +54,7 @@ Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_, .queryCount = OCCLUSION_QUERIES_COUNT, })); instance.GetDevice().resetQueryPool(occlusion_query_pool, 0, OCCLUSION_QUERIES_COUNT); + Vulkan::SetObjectName(instance.GetDevice(), occlusion_query_buffer.Handle(), "OcclusionQueryBuffer:{:#x}", sizeof(u32)*OCCLUSION_QUERIES_COUNT); } Rasterizer::~Rasterizer() = default; @@ -1272,12 +1275,63 @@ void Rasterizer::ScopedMarkerInsertColor(const std::string_view& str, const u32 (f32)(color & 0xff) / 255.0f, (f32)((color >> 24) & 0xff) / 255.0f})}); } -void Rasterizer::StartPredication() { +void Rasterizer::StartPredication(VAddr addr, bool draw_if_visible, bool wait_for_result) { + if (!instance.IsConditionalRenderingSupported()) { + return; + } + ASSERT(!active_predication); + ASSERT(occlusion_index_mapping.contains(addr)); + + auto index = occlusion_index_mapping[addr]; + LOG_DEBUG(Render_Vulkan, "addr = {:#x}, index = {}", addr, index); + + scheduler.EndRendering(); + const auto cmdbuf = scheduler.CommandBuffer(); + + cmdbuf.copyQueryPoolResults(occlusion_query_pool, index, 1, occlusion_query_buffer.Handle(), + index*sizeof(u32), sizeof(u32), wait_for_result ? vk::QueryResultFlagBits::eWait + : vk::QueryResultFlagBits::ePartial); + + const auto pre_barrier = vk::BufferMemoryBarrier2{ + .srcStageMask = vk::PipelineStageFlagBits2::eCopy, + .srcAccessMask = vk::AccessFlagBits2::eTransferWrite, + .dstStageMask = vk::PipelineStageFlagBits2::eCopy, + .dstAccessMask = vk::AccessFlagBits2::eTransferWrite, + .buffer = occlusion_query_buffer.Handle(), + .offset = index * sizeof(u32), + .size = sizeof(u32), + }; + cmdbuf.pipelineBarrier2(vk::DependencyInfo{ + .dependencyFlags = vk::DependencyFlagBits::eByRegion, + .bufferMemoryBarrierCount = 1, + .pBufferMemoryBarriers = &pre_barrier, + }); + + ScopeMarkerBegin("gfx:{}:predication", fmt::ptr(reinterpret_cast(addr))); + vk::ConditionalRenderingBeginInfoEXT conditional_rendering_info { + .buffer = occlusion_query_buffer.Handle(), + .offset = index * sizeof(u32), + .flags = draw_if_visible ? vk::ConditionalRenderingFlagBitsEXT::eInverted + : vk::ConditionalRenderingFlagsEXT(), + }; + cmdbuf.beginConditionalRenderingEXT(&conditional_rendering_info); + + active_predication = true; } void Rasterizer::EndPredication() { + if (!active_predication) { + return; + } + LOG_DEBUG(Render_Vulkan, ""); + + scheduler.EndRendering(); + const auto cmdbuf = scheduler.CommandBuffer(); + cmdbuf.endConditionalRenderingEXT(); + ScopeMarkerEnd(); + active_predication = false; } void Rasterizer::StartOcclusionQuery(VAddr addr) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 5be1748a8..9883a606f 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -55,7 +55,7 @@ public: void ScopedMarkerInsertColor(const std::string_view& str, const u32 color, bool from_guest = false); - void StartPredication(); + void StartPredication(VAddr addr, bool discard_if_zero, bool wait_for_result); void EndPredication(); void StartOcclusionQuery(VAddr addr); void EndOcclusionQuery(VAddr addr); @@ -130,6 +130,8 @@ private: vk::QueryPool occlusion_query_pool; u32 occlusion_current_index{}; std::map occlusion_index_mapping; + VideoCore::Buffer occlusion_query_buffer; + bool active_predication; boost::container::static_vector< std::pair, 8>