Vulkan Implement Dynamic State 2 LogicOp and PatchVertices

master
Fernando Sahmkow 2022-12-05 17:14:34 +07:00
parent c897c55e3c
commit f800e485c9
12 changed files with 75 additions and 27 deletions

@ -124,6 +124,7 @@ void Maxwell3D::InitializeRegisterDefaults() {
regs.gl_front_face = Maxwell3D::Regs::FrontFace::ClockWise; regs.gl_front_face = Maxwell3D::Regs::FrontFace::ClockWise;
regs.polygon_mode_back = Maxwell3D::Regs::PolygonMode::Fill; regs.polygon_mode_back = Maxwell3D::Regs::PolygonMode::Fill;
regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill; regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill;
regs.logic_op.op = Maxwell3D::Regs::LogicOp::Op::Clear;
shadow_state = regs; shadow_state = regs;
} }

@ -55,6 +55,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
raw1 = 0; raw1 = 0;
extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 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.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); extended_dynamic_state_3.Assign(features.has_extended_dynamic_state_3 ? 1 : 0);
dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0); dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0);
xfb_enabled.Assign(regs.transform_feedback_enabled != 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); Maxwell::ViewportClipControl::GeometryClip::FrustumZ);
ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0); ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0);
polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front)); polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front));
patch_control_points_minus_one.Assign(regs.patch_vertices - 1);
tessellation_primitive.Assign(static_cast<u32>(regs.tessellation.params.domain_type.Value())); tessellation_primitive.Assign(static_cast<u32>(regs.tessellation.params.domain_type.Value()));
tessellation_spacing.Assign(static_cast<u32>(regs.tessellation.params.spacing.Value())); tessellation_spacing.Assign(static_cast<u32>(regs.tessellation.params.spacing.Value()));
tessellation_clockwise.Assign(regs.tessellation.params.output_primitives.Value() == tessellation_clockwise.Assign(regs.tessellation.params.output_primitives.Value() ==
Maxwell::Tessellation::OutputPrimitives::Triangles_CW); Maxwell::Tessellation::OutputPrimitives::Triangles_CW);
logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); 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_); topology.Assign(topology_);
msaa_mode.Assign(regs.anti_alias_samples_mode); msaa_mode.Assign(regs.anti_alias_samples_mode);
@ -156,8 +156,8 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
if (!extended_dynamic_state) { if (!extended_dynamic_state) {
dynamic_state.Refresh(regs); dynamic_state.Refresh(regs);
} }
if (!extended_dynamic_state_2) { if (!extended_dynamic_state_2_extra) {
dynamic_state.Refresh2(regs, topology); dynamic_state.Refresh2(regs, topology, extended_dynamic_state_2);
} }
if (!extended_dynamic_state_3) { if (!extended_dynamic_state_3) {
dynamic_state.Refresh3(regs); 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{ const std::array enabled_lut{
regs.polygon_offset_point_enable, regs.polygon_offset_point_enable,
regs.polygon_offset_line_enable, regs.polygon_offset_line_enable,

@ -146,6 +146,7 @@ struct FixedPipelineState {
BitField<3, 1, u32> primitive_restart_enable; BitField<3, 1, u32> primitive_restart_enable;
BitField<4, 1, u32> depth_bias_enable; BitField<4, 1, u32> depth_bias_enable;
BitField<5, 1, u32> rasterize_enable; BitField<5, 1, u32> rasterize_enable;
BitField<6, 4, u32> logic_op;
}; };
union { union {
u32 raw2; u32 raw2;
@ -162,7 +163,7 @@ struct FixedPipelineState {
std::array<u16, Maxwell::NumVertexArrays> vertex_strides; std::array<u16, Maxwell::NumVertexArrays> vertex_strides;
void Refresh(const Maxwell& regs); 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); void Refresh3(const Maxwell& regs);
Maxwell::ComparisonOp DepthTestFunc() const noexcept { Maxwell::ComparisonOp DepthTestFunc() const noexcept {
@ -182,18 +183,19 @@ struct FixedPipelineState {
u32 raw1; u32 raw1;
BitField<0, 1, u32> extended_dynamic_state; BitField<0, 1, u32> extended_dynamic_state;
BitField<1, 1, u32> extended_dynamic_state_2; BitField<1, 1, u32> extended_dynamic_state_2;
BitField<2, 1, u32> extended_dynamic_state_3; BitField<2, 1, u32> extended_dynamic_state_2_extra;
BitField<3, 1, u32> dynamic_vertex_input; BitField<3, 1, u32> extended_dynamic_state_3;
BitField<4, 1, u32> xfb_enabled; BitField<4, 1, u32> dynamic_vertex_input;
BitField<5, 1, u32> depth_clamp_disabled; BitField<5, 1, u32> xfb_enabled;
BitField<6, 1, u32> ndc_minus_one_to_one; BitField<6, 1, u32> depth_clamp_disabled;
BitField<7, 2, u32> polygon_mode; BitField<7, 1, u32> ndc_minus_one_to_one;
BitField<9, 5, u32> patch_control_points_minus_one; BitField<8, 2, u32> polygon_mode;
BitField<14, 2, u32> tessellation_primitive; BitField<10, 2, u32> tessellation_primitive;
BitField<16, 2, u32> tessellation_spacing; BitField<12, 2, u32> tessellation_spacing;
BitField<18, 1, u32> tessellation_clockwise; BitField<14, 1, u32> tessellation_clockwise;
BitField<19, 1, u32> logic_op_enable; BitField<15, 1, u32> logic_op_enable;
BitField<20, 4, u32> logic_op; BitField<16, 5, u32> patch_control_points_minus_one;
BitField<24, 4, Maxwell::PrimitiveTopology> topology; BitField<24, 4, Maxwell::PrimitiveTopology> topology;
BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode;
}; };
@ -246,7 +248,7 @@ struct FixedPipelineState {
// Exclude dynamic state and attributes // Exclude dynamic state and attributes
return offsetof(FixedPipelineState, attributes); return offsetof(FixedPipelineState, attributes);
} }
if (extended_dynamic_state_2) { if (extended_dynamic_state_2_extra) {
// Exclude dynamic state // Exclude dynamic state
return offsetof(FixedPipelineState, dynamic_state); return offsetof(FixedPipelineState, dynamic_state);
} }

@ -628,7 +628,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.topology = input_assembly_topology, .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 && ((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
device.IsTopologyListPrimitiveRestartSupported()) || device.IsTopologyListPrimitiveRestartSupported()) ||
SupportsPrimitiveRestart(input_assembly_topology) || SupportsPrimitiveRestart(input_assembly_topology) ||
@ -786,12 +786,12 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.logicOpEnable = key.state.logic_op_enable != 0, .logicOpEnable = key.state.logic_op_enable != 0,
.logicOp = static_cast<VkLogicOp>(key.state.logic_op.Value()), .logicOp = static_cast<VkLogicOp>(dynamic.logic_op.Value()),
.attachmentCount = static_cast<u32>(cb_attachments.size()), .attachmentCount = static_cast<u32>(cb_attachments.size()),
.pAttachments = cb_attachments.data(), .pAttachments = cb_attachments.data(),
.blendConstants = {}, .blendConstants = {},
}; };
static_vector<VkDynamicState, 22> dynamic_states{ static_vector<VkDynamicState, 23> dynamic_states{
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, 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()); 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{ const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,

@ -454,6 +454,8 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
dynamic_features.has_extended_dynamic_state || dynamic_features.has_extended_dynamic_state ||
(key.state.extended_dynamic_state_2 != 0) != (key.state.extended_dynamic_state_2 != 0) !=
dynamic_features.has_extended_dynamic_state_2 || 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) != (key.state.extended_dynamic_state_3 != 0) !=
dynamic_features.has_extended_dynamic_state_3 || dynamic_features.has_extended_dynamic_state_3 ||
(key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) { (key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) {

@ -680,7 +680,6 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateLineWidth(regs); UpdateLineWidth(regs);
if (device.IsExtExtendedDynamicStateSupported()) { if (device.IsExtExtendedDynamicStateSupported()) {
UpdateCullMode(regs); UpdateCullMode(regs);
UpdateDepthCompareOp(regs); UpdateDepthCompareOp(regs);
UpdateFrontFace(regs); UpdateFrontFace(regs);
UpdateStencilOp(regs); UpdateStencilOp(regs);
@ -700,6 +699,9 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateDepthBiasEnable(regs); 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<VkLogicOp>(static_cast<u32>(regs.logic_op.op) - 0x1500);
scheduler.Record([op](vk::CommandBuffer cmdbuf) { cmdbuf.SetLogicOpEXT(op); });
}
void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) { void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchStencilTestEnable()) { if (!state_tracker.TouchStencilTestEnable()) {
return; return;

@ -145,6 +145,7 @@ private:
void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateStencilTestEnable(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); void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs);

@ -48,6 +48,7 @@ Flags MakeInvalidationFlags() {
PrimitiveRestartEnable, PrimitiveRestartEnable,
RasterizerDiscardEnable, RasterizerDiscardEnable,
DepthBiasEnable, DepthBiasEnable,
LogicOp,
}; };
Flags flags{}; Flags flags{};
for (const int flag : INVALIDATION_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); 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) { void SetupDirtyViewportSwizzles(Tables& tables) {
static constexpr size_t swizzle_offset = 6; static constexpr size_t swizzle_offset = 6;
for (size_t index = 0; index < Regs::NumViewports; ++index) { for (size_t index = 0; index < Regs::NumViewports; ++index) {
@ -210,6 +215,7 @@ void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
SetupDirtyViewportSwizzles(tables); SetupDirtyViewportSwizzles(tables);
SetupDirtyVertexAttributes(tables); SetupDirtyVertexAttributes(tables);
SetupDirtyVertexBindings(tables); SetupDirtyVertexBindings(tables);
SetupDirtySpecialOps(tables);
} }
void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) { void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {

@ -49,6 +49,7 @@ enum : u8 {
RasterizerDiscardEnable, RasterizerDiscardEnable,
DepthBiasEnable, DepthBiasEnable,
StateEnable, StateEnable,
LogicOp,
Blending, Blending,
ViewportSwizzles, ViewportSwizzles,
@ -159,6 +160,10 @@ public:
return Exchange(Dirty::StencilTestEnable, false); return Exchange(Dirty::StencilTestEnable, false);
} }
bool TouchLogicOp() {
return Exchange(Dirty::LogicOp, false);
}
bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) { bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
const bool has_changed = current_topology != new_topology; const bool has_changed = current_topology != new_topology;
current_topology = new_topology; current_topology = new_topology;

@ -576,8 +576,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
.pNext = nullptr, .pNext = nullptr,
.extendedDynamicState2 = VK_TRUE, .extendedDynamicState2 = VK_TRUE,
.extendedDynamicState2LogicOp = ext_extended_dynamic_state2_extra ? VK_TRUE : VK_FALSE, .extendedDynamicState2LogicOp = ext_extended_dynamic_state2_extra ? VK_TRUE : VK_FALSE,
.extendedDynamicState2PatchControlPoints =
ext_extended_dynamic_state2_extra ? VK_TRUE : VK_FALSE,
}; };
SetNext(next, dynamic_state2); SetNext(next, dynamic_state2);
} else { } else {
@ -1330,8 +1328,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
ext_extended_dynamic_state2 = true; ext_extended_dynamic_state2 = true;
ext_extended_dynamic_state2_extra = ext_extended_dynamic_state2_extra =
extended_dynamic_state2.extendedDynamicState2LogicOp && extended_dynamic_state2.extendedDynamicState2LogicOp;
extended_dynamic_state2.extendedDynamicState2PatchControlPoints;
} }
} }
if (has_ext_extended_dynamic_state3) { if (has_ext_extended_dynamic_state3) {

@ -126,6 +126,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCmdSetRasterizerDiscardEnableEXT); X(vkCmdSetRasterizerDiscardEnableEXT);
X(vkCmdSetDepthBiasEnableEXT); X(vkCmdSetDepthBiasEnableEXT);
X(vkCmdSetFrontFaceEXT); X(vkCmdSetFrontFaceEXT);
X(vkCmdSetLogicOpEXT);
X(vkCmdSetPatchControlPointsEXT);
X(vkCmdSetLineWidth); X(vkCmdSetLineWidth);
X(vkCmdSetPrimitiveTopologyEXT); X(vkCmdSetPrimitiveTopologyEXT);
X(vkCmdSetStencilOpEXT); X(vkCmdSetStencilOpEXT);

@ -239,6 +239,8 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{}; PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{};
PFN_vkCmdSetEvent vkCmdSetEvent{}; PFN_vkCmdSetEvent vkCmdSetEvent{};
PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{}; PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{};
PFN_vkCmdSetPatchControlPointsEXT vkCmdSetPatchControlPointsEXT{};
PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT{};
PFN_vkCmdSetLineWidth vkCmdSetLineWidth{}; PFN_vkCmdSetLineWidth vkCmdSetLineWidth{};
PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{}; PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{};
PFN_vkCmdSetScissor vkCmdSetScissor{}; PFN_vkCmdSetScissor vkCmdSetScissor{};
@ -1238,6 +1240,14 @@ public:
dld->vkCmdSetFrontFaceEXT(handle, front_face); 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 { void SetLineWidth(float line_width) const noexcept {
dld->vkCmdSetLineWidth(handle, line_width); dld->vkCmdSetLineWidth(handle, line_width);
} }