diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp index 843bedb20..a6ae0c304 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp @@ -156,6 +156,18 @@ vk::CullModeFlags CullMode(Liverpool::CullMode mode) { } } +vk::FrontFace FrontFace(Liverpool::FrontFace face) { + switch (face) { + case Liverpool::FrontFace::Clockwise: + return vk::FrontFace::eClockwise; + case Liverpool::FrontFace::CounterClockwise: + return vk::FrontFace::eCounterClockwise; + default: + UNREACHABLE(); + return vk::FrontFace::eClockwise; + } +} + vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor) { using BlendFactor = Liverpool::BlendControl::BlendFactor; switch (factor) { diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.h b/src/video_core/renderer_vulkan/liverpool_to_vk.h index 42da7aa06..fca0a8378 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.h +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.h @@ -26,6 +26,8 @@ vk::PolygonMode PolygonMode(Liverpool::PolygonMode mode); vk::CullModeFlags CullMode(Liverpool::CullMode mode); +vk::FrontFace FrontFace(Liverpool::FrontFace mode); + vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor); vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 7cd4bd872..354e22331 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -28,6 +28,15 @@ static constexpr std::array LogicalStageToStageBit = { vk::ShaderStageFlagBits::eCompute, }; +static bool IsPrimitiveTopologyList(const vk::PrimitiveTopology topology) { + return topology == vk::PrimitiveTopology::ePointList || + topology == vk::PrimitiveTopology::eLineList || + topology == vk::PrimitiveTopology::eTriangleList || + topology == vk::PrimitiveTopology::eLineListWithAdjacency || + topology == vk::PrimitiveTopology::eTriangleListWithAdjacency || + topology == vk::PrimitiveTopology::ePatchList; +} + GraphicsPipeline::GraphicsPipeline( const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap, const Shader::Profile& profile, const GraphicsPipelineKey& key_, @@ -75,19 +84,15 @@ GraphicsPipeline::GraphicsPipeline( .pVertexAttributeDescriptions = vertex_attributes.data(), }; - auto prim_restart = key.enable_primitive_restart != 0; - if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) { - LOG_DEBUG(Render_Vulkan, - "Primitive restart is enabled for list topology but not supported by driver."); - prim_restart = false; - } + const auto topology = LiverpoolToVK::PrimitiveType(key.prim_type); const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { - .topology = LiverpoolToVK::PrimitiveType(key.prim_type), - .primitiveRestartEnable = prim_restart, + .topology = topology, + // Avoid warning spam on all pipelines about unsupported restart disable, if not supported. + // However, must be false for list topologies to avoid validation errors. + .primitiveRestartEnable = + !instance.IsPrimitiveRestartDisableSupported() && !IsPrimitiveTopologyList(topology), }; - ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF || - key.primitive_restart_index == 0xFFFFFFFF, - "Primitive restart index other than -1 is not supported yet"); + const bool is_rect_list = key.prim_type == AmdGpu::PrimitiveType::RectList; const bool is_quad_list = key.prim_type == AmdGpu::PrimitiveType::QuadList; const auto& fs_info = runtime_infos[u32(Shader::LogicalStage::Fragment)].fs_info; @@ -99,12 +104,6 @@ GraphicsPipeline::GraphicsPipeline( .depthClampEnable = false, .rasterizerDiscardEnable = false, .polygonMode = LiverpoolToVK::PolygonMode(key.polygon_mode), - .cullMode = LiverpoolToVK::IsPrimitiveCulled(key.prim_type) - ? LiverpoolToVK::CullMode(key.cull_mode) - : vk::CullModeFlagBits::eNone, - .frontFace = key.front_face == Liverpool::FrontFace::Clockwise - ? vk::FrontFace::eClockwise - : vk::FrontFace::eCounterClockwise, .lineWidth = 1.0f, }; @@ -122,16 +121,20 @@ GraphicsPipeline::GraphicsPipeline( .pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr, }; - boost::container::static_vector dynamic_states = { + boost::container::static_vector dynamic_states = { vk::DynamicState::eViewportWithCountEXT, vk::DynamicState::eScissorWithCountEXT, vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthTestEnableEXT, vk::DynamicState::eDepthWriteEnableEXT, vk::DynamicState::eDepthCompareOpEXT, vk::DynamicState::eDepthBiasEnableEXT, vk::DynamicState::eDepthBias, vk::DynamicState::eStencilTestEnableEXT, vk::DynamicState::eStencilReference, vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, - vk::DynamicState::eStencilOpEXT, + vk::DynamicState::eStencilOpEXT, vk::DynamicState::eCullModeEXT, + vk::DynamicState::eFrontFaceEXT, }; + if (instance.IsPrimitiveRestartDisableSupported()) { + dynamic_states.push_back(vk::DynamicState::ePrimitiveRestartEnableEXT); + } if (instance.IsDepthBoundsSupported()) { dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnableEXT); dynamic_states.push_back(vk::DynamicState::eDepthBounds); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 7ffd14064..59230ae46 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -42,11 +42,7 @@ struct GraphicsPipelineKey { u32 num_samples; u32 mrt_mask; AmdGpu::PrimitiveType prim_type; - u32 enable_primitive_restart; - u32 primitive_restart_index; Liverpool::PolygonMode polygon_mode; - Liverpool::CullMode cull_mode; - Liverpool::FrontFace front_face; Liverpool::ClipSpace clip_space; Liverpool::ColorBufferMask cb_shader_mask; std::array blend_controls; @@ -82,16 +78,6 @@ public: return key.mrt_mask; } - [[nodiscard]] bool IsPrimitiveListTopology() const { - return key.prim_type == AmdGpu::PrimitiveType::PointList || - key.prim_type == AmdGpu::PrimitiveType::LineList || - key.prim_type == AmdGpu::PrimitiveType::TriangleList || - key.prim_type == AmdGpu::PrimitiveType::AdjLineList || - key.prim_type == AmdGpu::PrimitiveType::AdjTriangleList || - key.prim_type == AmdGpu::PrimitiveType::RectList || - key.prim_type == AmdGpu::PrimitiveType::QuadList; - } - /// Gets the attributes and bindings for vertex inputs. template void GetVertexInputs(VertexInputs& attributes, VertexInputs& bindings, diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 04b68c1d0..6de419041 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -292,6 +292,11 @@ public: properties.limits.framebufferStencilSampleCounts; } + /// Returns whether disabling primitive restart is supported. + bool IsPrimitiveRestartDisableSupported() const { + return driver_id != vk::DriverId::eMoltenvk; + } + private: /// Creates the logical device opportunistically enabling extensions bool CreateDevice(); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 17a1fdec4..bad2a549c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -283,12 +283,8 @@ bool PipelineCache::RefreshGraphicsKey() { } key.prim_type = regs.primitive_type; - key.enable_primitive_restart = regs.enable_primitive_restart & 1; - key.primitive_restart_index = regs.primitive_restart_index; key.polygon_mode = regs.polygon_control.PolyMode(); - key.cull_mode = regs.polygon_control.CullingMode(); key.clip_space = regs.clipper_control.clip_space; - key.front_face = regs.polygon_control.front_face; key.num_samples = regs.NumSamples(); const bool skip_cb_binding = diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 5aae43cc8..30102960a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -949,6 +949,7 @@ void Rasterizer::UnmapMemory(VAddr addr, u64 size) { void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) const { UpdateViewportScissorState(); UpdateDepthStencilState(); + UpdatePrimitiveState(); auto& dynamic_state = scheduler.GetDynamicState(); dynamic_state.SetBlendConstants(&liverpool->regs.blend_constants.red); @@ -1132,6 +1133,25 @@ void Rasterizer::UpdateDepthStencilState() const { } } +void Rasterizer::UpdatePrimitiveState() const { + const auto& regs = liverpool->regs; + auto& dynamic_state = scheduler.GetDynamicState(); + + const auto prim_restart = (regs.enable_primitive_restart & 1) != 0; + ASSERT_MSG(!prim_restart || regs.primitive_restart_index == 0xFFFF || + regs.primitive_restart_index == 0xFFFFFFFF, + "Primitive restart index other than -1 is not supported yet"); + + const auto cull_mode = LiverpoolToVK::IsPrimitiveCulled(regs.primitive_type) + ? LiverpoolToVK::CullMode(regs.polygon_control.CullingMode()) + : vk::CullModeFlagBits::eNone; + const auto front_face = LiverpoolToVK::FrontFace(regs.polygon_control.front_face); + + dynamic_state.SetPrimitiveRestartEnabled(prim_restart); + dynamic_state.SetCullMode(cull_mode); + dynamic_state.SetFrontFace(front_face); +} + void Rasterizer::ScopeMarkerBegin(const std::string_view& str, bool from_guest) { if ((from_guest && !Config::getVkGuestMarkersEnabled()) || (!from_guest && !Config::getVkHostMarkersEnabled())) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 02c24c7ec..54bf3d253 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -78,6 +78,7 @@ private: void UpdateDynamicState(const GraphicsPipeline& pipeline) const; void UpdateViewportScissorState() const; void UpdateDepthStencilState() const; + void UpdatePrimitiveState() const; bool FilterDraw(); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 6b872bdaa..a48d93dee 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -288,6 +288,20 @@ void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmd } } } + if (dirty_state.primitive_restart_enable) { + dirty_state.primitive_restart_enable = false; + if (instance.IsPrimitiveRestartDisableSupported()) { + cmdbuf.setPrimitiveRestartEnableEXT(primitive_restart_enable); + } + } + if (dirty_state.cull_mode) { + dirty_state.cull_mode = false; + cmdbuf.setCullModeEXT(cull_mode); + } + if (dirty_state.front_face) { + dirty_state.front_face = false; + cmdbuf.setFrontFaceEXT(front_face); + } if (dirty_state.blend_constants) { dirty_state.blend_constants = false; cmdbuf.setBlendConstants(blend_constants); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 880bd4b04..7709e1d41 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -95,6 +95,10 @@ struct DynamicState { bool stencil_back_write_mask : 1; bool stencil_back_compare_mask : 1; + bool primitive_restart_enable : 1; + bool cull_mode : 1; + bool front_face : 1; + bool blend_constants : 1; bool color_write_masks : 1; } dirty_state{}; @@ -125,6 +129,10 @@ struct DynamicState { u32 stencil_back_write_mask{}; u32 stencil_back_compare_mask{}; + bool primitive_restart_enable{}; + vk::CullModeFlags cull_mode{}; + vk::FrontFace front_face{}; + float blend_constants[4]{}; ColorWriteMasks color_write_masks{}; @@ -254,6 +262,27 @@ struct DynamicState { } } + void SetPrimitiveRestartEnabled(const bool enabled) { + if (primitive_restart_enable != enabled) { + primitive_restart_enable = enabled; + dirty_state.primitive_restart_enable = true; + } + } + + void SetCullMode(const vk::CullModeFlags cull_mode_) { + if (cull_mode != cull_mode_) { + cull_mode = cull_mode_; + dirty_state.cull_mode = true; + } + } + + void SetFrontFace(const vk::FrontFace front_face_) { + if (front_face != front_face_) { + front_face = front_face_; + dirty_state.front_face = true; + } + } + void SetBlendConstants(const float blend_constants_[4]) { if (!std::equal(blend_constants, std::end(blend_constants), blend_constants_)) { std::memcpy(blend_constants, blend_constants_, sizeof(blend_constants));