mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-05-31 23:07:06 +02:00
[vulkan] [eds] implement VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT
This commit is contained in:
parent
8678cb06eb
commit
bfb85c1385
6 changed files with 89 additions and 12 deletions
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
bool ChangePrimitiveTopology(u32 new_topology) {
|
||||||
const bool has_changed = current_topology != new_topology;
|
const bool has_changed = current_primitive_topology != new_topology;
|
||||||
current_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…
Add table
Add a link
Reference in a new issue