vk_graphics_pipeline: Manage primitive topology as fixed state

Vulkan has requirements for primitive topologies that don't play nicely
with yuzu's. Since it's only 4 bits, we can move it to fixed state
without changing the size of the pipeline key.

- Fixes a regression on recent Nvidia drivers on Fire Emblem: Three
  Houses.
This commit is contained in:
ReinUsesLisp 2020-10-12 21:33:27 -03:00
parent 4c348f4069
commit e4e0abc418
6 changed files with 7 additions and 26 deletions

View file

@ -58,6 +58,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
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.operation)); logic_op.Assign(PackLogicOp(regs.logic_op.operation));
rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0);
topology.Assign(regs.draw.topology);
std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
@ -131,7 +132,6 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size
} }
void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
u32 packed_front_face = PackFrontFace(regs.front_face); u32 packed_front_face = PackFrontFace(regs.front_face);
if (regs.screen_y_control.triangle_rast_flip != 0) { if (regs.screen_y_control.triangle_rast_flip != 0) {
// Flip front face // Flip front face
@ -161,7 +161,6 @@ void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
depth_test_enable.Assign(regs.depth_test_enable); depth_test_enable.Assign(regs.depth_test_enable);
front_face.Assign(packed_front_face); front_face.Assign(packed_front_face);
depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); depth_test_func.Assign(PackComparisonOp(regs.depth_test_func));
topology.Assign(topology_index);
cull_face.Assign(PackCullFace(regs.cull_face)); cull_face.Assign(PackCullFace(regs.cull_face));
cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0);

View file

@ -150,9 +150,8 @@ struct FixedPipelineState {
}; };
union { union {
u32 raw2; u32 raw2;
BitField<0, 4, u32> topology; BitField<0, 2, u32> cull_face;
BitField<4, 2, u32> cull_face; BitField<2, 1, u32> cull_enable;
BitField<6, 1, u32> cull_enable;
}; };
std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings; std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings;
@ -169,10 +168,6 @@ struct FixedPipelineState {
Maxwell::FrontFace FrontFace() const noexcept { Maxwell::FrontFace FrontFace() const noexcept {
return UnpackFrontFace(front_face.Value()); return UnpackFrontFace(front_face.Value());
} }
constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
}
}; };
union { union {
@ -190,6 +185,7 @@ struct FixedPipelineState {
BitField<18, 1, u32> logic_op_enable; BitField<18, 1, u32> logic_op_enable;
BitField<19, 4, u32> logic_op; BitField<19, 4, u32> logic_op;
BitField<23, 1, u32> rasterize_enable; BitField<23, 1, u32> rasterize_enable;
BitField<24, 4, Maxwell::PrimitiveTopology> topology;
}; };
u32 point_size; u32 point_size;
std::array<u32, Maxwell::NumVertexArrays> binding_divisors; std::array<u32, Maxwell::NumVertexArrays> binding_divisors;

View file

@ -261,12 +261,12 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
vertex_input_ci.pNext = &input_divisor_ci; vertex_input_ci.pNext = &input_divisor_ci;
} }
const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), .topology = MaxwellToVK::PrimitiveTopology(device, state.topology),
.primitiveRestartEnable = state.primitive_restart_enable != 0 && .primitiveRestartEnable = state.primitive_restart_enable != 0 &&
SupportsPrimitiveRestart(input_assembly_topology), SupportsPrimitiveRestart(input_assembly_topology),
}; };
@ -400,7 +400,6 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
static constexpr std::array extended{ static constexpr std::array extended{
VK_DYNAMIC_STATE_CULL_MODE_EXT, VK_DYNAMIC_STATE_CULL_MODE_EXT,
VK_DYNAMIC_STATE_FRONT_FACE_EXT, VK_DYNAMIC_STATE_FRONT_FACE_EXT,
VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,

View file

@ -331,8 +331,7 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) {
std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
Specialization specialization; Specialization specialization;
if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points || if (fixed_state.topology == Maxwell::PrimitiveTopology::Points) {
device.IsExtExtendedDynamicStateSupported()) {
float point_size; float point_size;
std::memcpy(&point_size, &fixed_state.point_size, sizeof(float)); std::memcpy(&point_size, &fixed_state.point_size, sizeof(float));
specialization.point_size = point_size; specialization.point_size = point_size;

View file

@ -948,7 +948,6 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateDepthWriteEnable(regs); UpdateDepthWriteEnable(regs);
UpdateDepthCompareOp(regs); UpdateDepthCompareOp(regs);
UpdateFrontFace(regs); UpdateFrontFace(regs);
UpdatePrimitiveTopology(regs);
UpdateStencilOp(regs); UpdateStencilOp(regs);
UpdateStencilTestEnable(regs); UpdateStencilTestEnable(regs);
} }
@ -1418,16 +1417,6 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
[front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); }); [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
} }
void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) {
const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value();
if (!state_tracker.ChangePrimitiveTopology(primitive_topology)) {
return;
}
scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) {
cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology));
});
}
void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchStencilOp()) { if (!state_tracker.TouchStencilOp()) {
return; return;

View file

@ -259,7 +259,6 @@ private:
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdatePrimitiveTopology(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);