Browse Source

[vulkan] [eds] implement VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT

eds_changes_phasewise
wildcard 2 days ago
parent
commit
bfb85c1385
  1. 3
      src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
  2. 4
      src/video_core/renderer_vulkan/vk_graphics_pipeline.h
  3. 77
      src/video_core/renderer_vulkan/vk_rasterizer.cpp
  4. 1
      src/video_core/renderer_vulkan/vk_rasterizer.h
  5. 2
      src/video_core/renderer_vulkan/vk_state_tracker.cpp
  6. 14
      src/video_core/renderer_vulkan/vk_state_tracker.h

3
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp

@ -830,7 +830,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pAttachments = cb_attachments.data(), .pAttachments = cb_attachments.data(),
.blendConstants = {} .blendConstants = {}
}; };
static_vector<VkDynamicState, 34> dynamic_states{
static_vector<VkDynamicState, 35> 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,
@ -847,6 +847,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT, VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT, VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_STENCIL_OP_EXT, VK_DYNAMIC_STATE_STENCIL_OP_EXT,
VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
}; };
dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end()); dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end());

4
src/video_core/renderer_vulkan/vk_graphics_pipeline.h

@ -90,6 +90,10 @@ public:
return fragment_has_color0_output; return fragment_has_color0_output;
} }
bool HasTessellationStages() const noexcept {
return spv_modules[1] || spv_modules[2];
}
bool UsesExtendedDynamicState() const noexcept { bool UsesExtendedDynamicState() const noexcept {
return key.state.extended_dynamic_state != 0; return key.state.extended_dynamic_state != 0;
} }

77
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -61,6 +61,33 @@ struct DrawParams {
bool is_indexed; bool is_indexed;
}; };
bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) {
static constexpr std::array unsupported_topologies{
VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
// VK_PRIMITIVE_TOPOLOGY_QUAD_LIST_EXT,
};
return std::ranges::find(unsupported_topologies, topology) == unsupported_topologies.end();
}
VkPrimitiveTopology DynamicInputAssemblyTopology(const Device& device,
const MaxwellDrawState& draw_state,
const GraphicsPipeline& pipeline) {
auto topology = MaxwellToVK::PrimitiveTopology(device, draw_state.topology);
if (topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
if (!pipeline.HasTessellationStages()) {
topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
}
} else if (pipeline.HasTessellationStages()) {
topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
}
return topology;
}
VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) {
const auto& src = regs.viewport_transform[index]; const auto& src = regs.viewport_transform[index];
const auto conv = [scale](float value) { const auto conv = [scale](float value) {
@ -1018,8 +1045,10 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateStencilFaces(regs); UpdateStencilFaces(regs);
UpdateLineWidth(regs); UpdateLineWidth(regs);
// EDS1: CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest
// EDS1: PrimitiveTopology, CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest,
// DepthTest, DepthWrite, StencilTest
if (device.IsExtExtendedDynamicStateSupported()) { if (device.IsExtExtendedDynamicStateSupported()) {
UpdatePrimitiveTopology();
UpdateCullMode(regs); UpdateCullMode(regs);
UpdateDepthCompareOp(regs); UpdateDepthCompareOp(regs);
UpdateFrontFace(regs); UpdateFrontFace(regs);
@ -1384,6 +1413,28 @@ void RasterizerVulkan::UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs) {
}); });
} }
void RasterizerVulkan::UpdatePrimitiveTopology() {
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
if (pipeline == nullptr) {
return;
}
const MaxwellDrawState& draw_state = maxwell3d->draw_manager->GetDrawState();
const VkPrimitiveTopology topology = DynamicInputAssemblyTopology(device, draw_state, *pipeline);
if (!state_tracker.ChangePrimitiveTopology(static_cast<u32>(topology))) {
return;
}
// Primitive restart support depends on topology, so force re-evaluation on topology changes
if (device.IsExtExtendedDynamicState2Supported()) {
maxwell3d->dirty.flags[Dirty::PrimitiveRestartEnable] = true;
}
scheduler.Record([topology](vk::CommandBuffer cmdbuf) {
cmdbuf.SetPrimitiveTopologyEXT(topology);
});
}
void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) { void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchDepthBoundsTestEnable()) { if (!state_tracker.TouchDepthBoundsTestEnable()) {
return; return;
@ -1420,7 +1471,29 @@ void RasterizerVulkan::UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::R
if (!state_tracker.TouchPrimitiveRestartEnable()) { if (!state_tracker.TouchPrimitiveRestartEnable()) {
return; return;
} }
scheduler.Record([enable = regs.primitive_restart.enabled](vk::CommandBuffer cmdbuf) {
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
if (pipeline == nullptr) {
// No graphics pipeline is currently available so repeat when available
maxwell3d->dirty.flags[Dirty::PrimitiveRestartEnable] = true;
return;
}
const MaxwellDrawState& draw_state = maxwell3d->draw_manager->GetDrawState();
const VkPrimitiveTopology topology = DynamicInputAssemblyTopology(device, draw_state, *pipeline);
bool enable = regs.primitive_restart.enabled != 0;
if (device.IsMoltenVK()) {
// MoltenVK/Metal
enable = true;
} else if (enable) {
enable = ((topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
device.IsTopologyListPrimitiveRestartSupported()) ||
SupportsPrimitiveRestart(topology) ||
(topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
device.IsPatchListPrimitiveRestartSupported()));
}
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetPrimitiveRestartEnableEXT(enable); cmdbuf.SetPrimitiveRestartEnableEXT(enable);
}); });
} }

1
src/video_core/renderer_vulkan/vk_rasterizer.h

@ -170,6 +170,7 @@ private:
void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdatePrimitiveTopology();
void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);

2
src/video_core/renderer_vulkan/vk_state_tracker.cpp

@ -265,7 +265,7 @@ void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {
void StateTracker::InvalidateState() { void StateTracker::InvalidateState() {
flags->set(); flags->set();
current_topology = INVALID_TOPOLOGY;
current_primitive_topology = INVALID_PRIMITIVE_TOPOLOGY;
stencil_reset = true; stencil_reset = true;
} }

14
src/video_core/renderer_vulkan/vk_state_tracker.h

@ -78,14 +78,12 @@ static_assert(Last <= (std::numeric_limits<u8>::max)());
} // namespace Dirty } // namespace Dirty
class StateTracker { class StateTracker {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
public: public:
explicit StateTracker(); explicit StateTracker();
void InvalidateCommandBufferState() { void InvalidateCommandBufferState() {
(*flags) |= invalidation_flags; (*flags) |= invalidation_flags;
current_topology = INVALID_TOPOLOGY;
current_primitive_topology = INVALID_PRIMITIVE_TOPOLOGY;
stencil_reset = true; stencil_reset = true;
} }
@ -280,9 +278,9 @@ public:
return Exchange(Dirty::LineRasterizationMode, false); return Exchange(Dirty::LineRasterizationMode, false);
} }
bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
const bool has_changed = current_topology != new_topology;
current_topology = new_topology;
bool ChangePrimitiveTopology(u32 new_topology) {
const bool has_changed = current_primitive_topology != new_topology;
current_primitive_topology = new_topology;
return has_changed; return has_changed;
} }
@ -293,7 +291,7 @@ public:
void InvalidateState(); void InvalidateState();
private: private:
static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u);
static constexpr u32 INVALID_PRIMITIVE_TOPOLOGY = ~0u;
bool Exchange(std::size_t id, bool new_value) const noexcept { bool Exchange(std::size_t id, bool new_value) const noexcept {
const bool is_dirty = (*flags)[id]; const bool is_dirty = (*flags)[id];
@ -310,7 +308,7 @@ private:
Tegra::Engines::Maxwell3D::DirtyState::Flags* flags; Tegra::Engines::Maxwell3D::DirtyState::Flags* flags;
Tegra::Engines::Maxwell3D::DirtyState::Flags default_flags; Tegra::Engines::Maxwell3D::DirtyState::Flags default_flags;
Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags; Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY;
u32 current_primitive_topology = INVALID_PRIMITIVE_TOPOLOGY;
bool two_sided_stencil = false; bool two_sided_stencil = false;
StencilProperties front{}; StencilProperties front{};
StencilProperties back{}; StencilProperties back{};

Loading…
Cancel
Save