diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index d44a5cabfc..7f406e1714 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -124,6 +124,7 @@ void Maxwell3D::InitializeRegisterDefaults() { regs.gl_front_face = Maxwell3D::Regs::FrontFace::ClockWise; regs.polygon_mode_back = Maxwell3D::Regs::PolygonMode::Fill; regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill; + regs.logic_op.op = Maxwell3D::Regs::LogicOp::Op::Clear; shadow_state = regs; } diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index f13ff09c69..b1623b882e 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -55,6 +55,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe raw1 = 0; extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 0); extended_dynamic_state_2.Assign(features.has_extended_dynamic_state_2 ? 1 : 0); + extended_dynamic_state_2_extra.Assign(features.has_extended_dynamic_state_2_extra ? 1 : 0); extended_dynamic_state_3.Assign(features.has_extended_dynamic_state_3 ? 1 : 0); dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0); xfb_enabled.Assign(regs.transform_feedback_enabled != 0); @@ -66,13 +67,12 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe Maxwell::ViewportClipControl::GeometryClip::FrustumZ); ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0); polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front)); - patch_control_points_minus_one.Assign(regs.patch_vertices - 1); tessellation_primitive.Assign(static_cast(regs.tessellation.params.domain_type.Value())); tessellation_spacing.Assign(static_cast(regs.tessellation.params.spacing.Value())); tessellation_clockwise.Assign(regs.tessellation.params.output_primitives.Value() == Maxwell::Tessellation::OutputPrimitives::Triangles_CW); logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); - logic_op.Assign(PackLogicOp(regs.logic_op.op)); + patch_control_points_minus_one.Assign(regs.patch_vertices - 1); topology.Assign(topology_); msaa_mode.Assign(regs.anti_alias_samples_mode); @@ -156,8 +156,8 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe if (!extended_dynamic_state) { dynamic_state.Refresh(regs); } - if (!extended_dynamic_state_2) { - dynamic_state.Refresh2(regs, topology); + if (!extended_dynamic_state_2_extra) { + dynamic_state.Refresh2(regs, topology, extended_dynamic_state_2); } if (!extended_dynamic_state_3) { dynamic_state.Refresh3(regs); @@ -241,7 +241,13 @@ void FixedPipelineState::DynamicState::Refresh(const Maxwell& regs) { }); } -void FixedPipelineState::DynamicState::Refresh2(const Maxwell& regs, Maxwell::PrimitiveTopology topology_) { +void FixedPipelineState::DynamicState::Refresh2(const Maxwell& regs, Maxwell::PrimitiveTopology topology_, bool base_feautures_supported) { + logic_op.Assign(PackLogicOp(regs.logic_op.op)); + + if (base_feautures_supported) { + return; + } + const std::array enabled_lut{ regs.polygon_offset_point_enable, regs.polygon_offset_line_enable, diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index ac2ec3edc0..88680e4482 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -146,6 +146,7 @@ struct FixedPipelineState { BitField<3, 1, u32> primitive_restart_enable; BitField<4, 1, u32> depth_bias_enable; BitField<5, 1, u32> rasterize_enable; + BitField<6, 4, u32> logic_op; }; union { u32 raw2; @@ -162,7 +163,7 @@ struct FixedPipelineState { std::array vertex_strides; void Refresh(const Maxwell& regs); - void Refresh2(const Maxwell& regs, Maxwell::PrimitiveTopology topology); + void Refresh2(const Maxwell& regs, Maxwell::PrimitiveTopology topology, bool base_feautures_supported); void Refresh3(const Maxwell& regs); Maxwell::ComparisonOp DepthTestFunc() const noexcept { @@ -182,18 +183,19 @@ struct FixedPipelineState { u32 raw1; BitField<0, 1, u32> extended_dynamic_state; BitField<1, 1, u32> extended_dynamic_state_2; - BitField<2, 1, u32> extended_dynamic_state_3; - BitField<3, 1, u32> dynamic_vertex_input; - BitField<4, 1, u32> xfb_enabled; - BitField<5, 1, u32> depth_clamp_disabled; - BitField<6, 1, u32> ndc_minus_one_to_one; - BitField<7, 2, u32> polygon_mode; - BitField<9, 5, u32> patch_control_points_minus_one; - BitField<14, 2, u32> tessellation_primitive; - BitField<16, 2, u32> tessellation_spacing; - BitField<18, 1, u32> tessellation_clockwise; - BitField<19, 1, u32> logic_op_enable; - BitField<20, 4, u32> logic_op; + BitField<2, 1, u32> extended_dynamic_state_2_extra; + BitField<3, 1, u32> extended_dynamic_state_3; + BitField<4, 1, u32> dynamic_vertex_input; + BitField<5, 1, u32> xfb_enabled; + BitField<6, 1, u32> depth_clamp_disabled; + BitField<7, 1, u32> ndc_minus_one_to_one; + BitField<8, 2, u32> polygon_mode; + BitField<10, 2, u32> tessellation_primitive; + BitField<12, 2, u32> tessellation_spacing; + BitField<14, 1, u32> tessellation_clockwise; + BitField<15, 1, u32> logic_op_enable; + BitField<16, 5, u32> patch_control_points_minus_one; + BitField<24, 4, Maxwell::PrimitiveTopology> topology; BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; }; @@ -246,7 +248,7 @@ struct FixedPipelineState { // Exclude dynamic state and attributes return offsetof(FixedPipelineState, attributes); } - if (extended_dynamic_state_2) { + if (extended_dynamic_state_2_extra) { // Exclude dynamic state return offsetof(FixedPipelineState, dynamic_state); } diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index d21d5aaf4c..ce82a9c65c 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -628,7 +628,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pNext = nullptr, .flags = 0, .topology = input_assembly_topology, - .primitiveRestartEnable = key.state.dynamic_state.primitive_restart_enable != 0 && + .primitiveRestartEnable = dynamic.primitive_restart_enable != 0 && ((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && device.IsTopologyListPrimitiveRestartSupported()) || SupportsPrimitiveRestart(input_assembly_topology) || @@ -786,12 +786,12 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pNext = nullptr, .flags = 0, .logicOpEnable = key.state.logic_op_enable != 0, - .logicOp = static_cast(key.state.logic_op.Value()), + .logicOp = static_cast(dynamic.logic_op.Value()), .attachmentCount = static_cast(cb_attachments.size()), .pAttachments = cb_attachments.data(), .blendConstants = {}, }; - static_vector dynamic_states{ + static_vector dynamic_states{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, @@ -822,6 +822,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { }; dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end()); } + if (key.state.extended_dynamic_state_2_extra) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_EXT); + } } const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 1292b6bdff..ee1ad744f9 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -454,6 +454,8 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading dynamic_features.has_extended_dynamic_state || (key.state.extended_dynamic_state_2 != 0) != dynamic_features.has_extended_dynamic_state_2 || + (key.state.extended_dynamic_state_2_extra != 0) != + dynamic_features.has_extended_dynamic_state_2_extra || (key.state.extended_dynamic_state_3 != 0) != dynamic_features.has_extended_dynamic_state_3 || (key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f52cebc222..3cf6b796b3 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -680,7 +680,6 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateLineWidth(regs); if (device.IsExtExtendedDynamicStateSupported()) { UpdateCullMode(regs); - UpdateDepthCompareOp(regs); UpdateFrontFace(regs); UpdateStencilOp(regs); @@ -700,6 +699,9 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateDepthBiasEnable(regs); } } + if (device.IsExtExtendedDynamicState2ExtrasSupported()) { + UpdateLogicOp(regs); + } } } @@ -1028,6 +1030,17 @@ void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { } } +void RasterizerVulkan::UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs) { + if (!regs.logic_op.enable) { + return; + } + if (!state_tracker.TouchLogicOp()) { + return; + } + auto op = static_cast(static_cast(regs.logic_op.op) - 0x1500); + scheduler.Record([op](vk::CommandBuffer cmdbuf) { cmdbuf.SetLogicOpEXT(op); }); +} + void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) { if (!state_tracker.TouchStencilTestEnable()) { return; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index c09415a6ad..67d35eff7a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -145,6 +145,7 @@ private: void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); + void UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index 339679ff92..1f8528e3eb 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp @@ -48,6 +48,7 @@ Flags MakeInvalidationFlags() { PrimitiveRestartEnable, RasterizerDiscardEnable, DepthBiasEnable, + LogicOp, }; Flags flags{}; for (const int flag : INVALIDATION_FLAGS) { @@ -162,6 +163,10 @@ void SetupDirtyBlending(Tables& tables) { FillBlock(tables[0], OFF(blend_per_target), NUM(blend_per_target), Blending); } +void SetupDirtySpecialOps(Tables& tables) { + tables[0][OFF(logic_op.op)] = LogicOp; +} + void SetupDirtyViewportSwizzles(Tables& tables) { static constexpr size_t swizzle_offset = 6; for (size_t index = 0; index < Regs::NumViewports; ++index) { @@ -210,6 +215,7 @@ void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) { SetupDirtyViewportSwizzles(tables); SetupDirtyVertexAttributes(tables); SetupDirtyVertexBindings(tables); + SetupDirtySpecialOps(tables); } void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) { diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index 583bfe1350..6050f5d268 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h @@ -49,6 +49,7 @@ enum : u8 { RasterizerDiscardEnable, DepthBiasEnable, StateEnable, + LogicOp, Blending, ViewportSwizzles, @@ -159,6 +160,10 @@ public: return Exchange(Dirty::StencilTestEnable, false); } + bool TouchLogicOp() { + return Exchange(Dirty::LogicOp, false); + } + bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) { const bool has_changed = current_topology != new_topology; current_topology = new_topology; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 9a420a2934..7294fcfe37 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -576,8 +576,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR .pNext = nullptr, .extendedDynamicState2 = VK_TRUE, .extendedDynamicState2LogicOp = ext_extended_dynamic_state2_extra ? VK_TRUE : VK_FALSE, - .extendedDynamicState2PatchControlPoints = - ext_extended_dynamic_state2_extra ? VK_TRUE : VK_FALSE, }; SetNext(next, dynamic_state2); } else { @@ -1330,8 +1328,7 @@ std::vector Device::LoadExtensions(bool requires_surface) { extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); ext_extended_dynamic_state2 = true; ext_extended_dynamic_state2_extra = - extended_dynamic_state2.extendedDynamicState2LogicOp && - extended_dynamic_state2.extendedDynamicState2PatchControlPoints; + extended_dynamic_state2.extendedDynamicState2LogicOp; } } if (has_ext_extended_dynamic_state3) { diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 4dde325ffb..8745cf80fc 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -126,6 +126,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { X(vkCmdSetRasterizerDiscardEnableEXT); X(vkCmdSetDepthBiasEnableEXT); X(vkCmdSetFrontFaceEXT); + X(vkCmdSetLogicOpEXT); + X(vkCmdSetPatchControlPointsEXT); X(vkCmdSetLineWidth); X(vkCmdSetPrimitiveTopologyEXT); X(vkCmdSetStencilOpEXT); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 0d3f71460a..c4b7051fca 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -239,6 +239,8 @@ struct DeviceDispatch : InstanceDispatch { PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{}; PFN_vkCmdSetEvent vkCmdSetEvent{}; PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{}; + PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT{}; + PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT{}; PFN_vkCmdSetLineWidth vkCmdSetLineWidth{}; PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{}; PFN_vkCmdSetScissor vkCmdSetScissor{}; @@ -1238,6 +1240,14 @@ public: dld->vkCmdSetFrontFaceEXT(handle, front_face); } + void SetLogicOpEXT(VkLogicOp logic_op) const noexcept { + dld->vkCmdSetLogicOpEXT(handle, logic_op); + } + + void SetPatchControlPointsEXT(uint32_t patch_control_points) const noexcept { + dld->vkCmdSetPatchControlPointsEXT(handle, patch_control_points); + } + void SetLineWidth(float line_width) const noexcept { dld->vkCmdSetLineWidth(handle, line_width); }