Browse Source

[vulkan] Adjusted dynamic state handling + update state tracker for extended dynamic states

vkexperiments1
CamilleLaVey 5 days ago
parent
commit
6985aaf614
  1. 8
      src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
  2. 8
      src/video_core/renderer_vulkan/fixed_pipeline_state.h
  3. 21
      src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
  4. 67
      src/video_core/renderer_vulkan/vk_rasterizer.cpp
  5. 11
      src/video_core/renderer_vulkan/vk_scheduler.cpp
  6. 4
      src/video_core/renderer_vulkan/vk_state_tracker.h

8
src/video_core/renderer_vulkan/fixed_pipeline_state.cpp

@ -131,15 +131,11 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
} }
dynamic_state.raw1 = 0; dynamic_state.raw1 = 0;
dynamic_state.raw2 = 0; dynamic_state.raw2 = 0;
if (!extended_dynamic_state) {
dynamic_state.Refresh(regs);
}
dynamic_state.Refresh(regs);
std::ranges::transform(regs.vertex_streams, vertex_strides.begin(), [](const auto& array) { std::ranges::transform(regs.vertex_streams, vertex_strides.begin(), [](const auto& array) {
return static_cast<u16>(array.stride.Value()); return static_cast<u16>(array.stride.Value());
}); });
if (!extended_dynamic_state_2) {
dynamic_state.Refresh2(regs, topology_, extended_dynamic_state_2);
}
dynamic_state.Refresh2(regs, topology_, false);
if (maxwell3d.dirty.flags[Dirty::Blending]) { if (maxwell3d.dirty.flags[Dirty::Blending]) {
maxwell3d.dirty.flags[Dirty::Blending] = false; maxwell3d.dirty.flags[Dirty::Blending] = false;
for (size_t index = 0; index < attachments.size(); ++index) { for (size_t index = 0; index < attachments.size(); ++index) {

8
src/video_core/renderer_vulkan/fixed_pipeline_state.h

@ -254,11 +254,9 @@ struct FixedPipelineState {
// When transform feedback is enabled, use the whole struct // When transform feedback is enabled, use the whole struct
return sizeof(*this); return sizeof(*this);
} }
if (extended_dynamic_state) {
// Exclude dynamic state
return offsetof(FixedPipelineState, vertex_strides);
}
// Default
// Always include the cached dynamic-state payload in the key. Some members of
// `dynamic_state` still feed static pipeline state even when EDS is enabled,
// and excluding the whole block causes incorrect pipeline reuse.
return offsetof(FixedPipelineState, xfb_state); return offsetof(FixedPipelineState, xfb_state);
} }
}; };

21
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp

@ -531,12 +531,7 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
} }
const void* const descriptor_data{guest_descriptor_queue.UpdateData()}; const void* const descriptor_data{guest_descriptor_queue.UpdateData()};
FixedPipelineState::DynamicState dynamic_state{};
if (!key.state.extended_dynamic_state) {
dynamic_state = key.state.dynamic_state;
} else {
dynamic_state.raw1 = key.state.dynamic_state.raw1;
}
const FixedPipelineState::DynamicState dynamic_state{key.state.dynamic_state};
scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(), scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(),
is_rescaling, update_rescaling, is_rescaling, update_rescaling,
uses_render_area = render_area.uses_render_area, uses_render_area = render_area.uses_render_area,
@ -687,9 +682,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.viewportCount = num_viewports,
.viewportCount = key.state.extended_dynamic_state ? 0u : num_viewports,
.pViewports = nullptr, .pViewports = nullptr,
.scissorCount = num_viewports,
.scissorCount = key.state.extended_dynamic_state ? 0u : num_viewports,
.pScissors = nullptr, .pScissors = nullptr,
}; };
if (device.IsNvViewportSwizzleSupported()) { if (device.IsNvViewportSwizzleSupported()) {
@ -901,6 +896,11 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
} }
if (key.state.extended_dynamic_state) { if (key.state.extended_dynamic_state) {
static constexpr std::array extended{ static constexpr std::array extended{
VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT,
VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT,
VK_DYNAMIC_STATE_CULL_MODE_EXT,
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_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,
VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT, VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT,
@ -914,11 +914,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
} }
if (key.state.extended_dynamic_state) {
dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT);
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
}
// EDS2 - Core (3 states) // EDS2 - Core (3 states)
if (key.state.extended_dynamic_state_2) { if (key.state.extended_dynamic_state_2) {
static constexpr std::array extended2{ static constexpr std::array extended2{

67
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -277,8 +277,9 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
if (!pipeline->Configure(is_indexed)) if (!pipeline->Configure(is_indexed))
return; return;
if (pipeline->UsesExtendedDynamicState()) {
state_tracker.InvalidateStateEnableFlag();
if (pipeline->UsesExtendedDynamicState() || pipeline->UsesExtendedDynamicState2() ||
pipeline->UsesExtendedDynamicState2LogicOp()) {
state_tracker.InvalidateExtendedDynamicStates();
} }
HandleTransformFeedback(); HandleTransformFeedback();
@ -1078,16 +1079,18 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateLineWidth(regs); UpdateLineWidth(regs);
UpdateLineStipple(regs); UpdateLineStipple(regs);
// EDS1: DepthCompare, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest
// EDS1: CullMode, DepthCompare, FrontFace, PrimitiveTopology, StencilOp,
// DepthBoundsTest, DepthTest, DepthWrite, StencilTest
if (device.IsExtExtendedDynamicStateSupported() && pipeline && pipeline->UsesExtendedDynamicState()) { if (device.IsExtExtendedDynamicStateSupported() && pipeline && pipeline->UsesExtendedDynamicState()) {
UpdateCullMode(regs);
UpdateDepthCompareOp(regs); UpdateDepthCompareOp(regs);
UpdateFrontFace(regs);
UpdatePrimitiveTopology(regs);
UpdateStencilOp(regs); UpdateStencilOp(regs);
if (state_tracker.TouchStateEnable()) {
UpdateDepthBoundsTestEnable(regs);
UpdateDepthTestEnable(regs);
UpdateDepthWriteEnable(regs);
UpdateStencilTestEnable(regs);
}
UpdateDepthBoundsTestEnable(regs);
UpdateDepthTestEnable(regs);
UpdateDepthWriteEnable(regs);
UpdateStencilTestEnable(regs);
} }
UpdateStencilFaces(regs); UpdateStencilFaces(regs);
@ -1157,8 +1160,16 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
.minDepth = 0.0f, .minDepth = 0.0f,
.maxDepth = 1.0f, .maxDepth = 1.0f,
}; };
scheduler.Record([viewport](vk::CommandBuffer cmdbuf) {
cmdbuf.SetViewport(0, viewport);
GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline();
const bool use_viewport_with_count = device.IsExtExtendedDynamicStateSupported() &&
pipeline && pipeline->UsesExtendedDynamicState();
scheduler.Record([viewport, use_viewport_with_count](vk::CommandBuffer cmdbuf) {
if (use_viewport_with_count) {
std::array viewports{viewport};
cmdbuf.SetViewportWithCountEXT(viewports);
} else {
cmdbuf.SetViewport(0, viewport);
}
}); });
return; return;
} }
@ -1174,10 +1185,17 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
}; };
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline();
const bool use_viewport_with_count = device.IsExtExtendedDynamicStateSupported() &&
pipeline && pipeline->UsesExtendedDynamicState();
scheduler.Record([this, viewport_list, use_viewport_with_count](vk::CommandBuffer cmdbuf) {
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports); const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
cmdbuf.SetViewport(0, viewports);
if (use_viewport_with_count) {
cmdbuf.SetViewportWithCountEXT(viewports);
} else {
cmdbuf.SetViewport(0, viewports);
}
}); });
} }
@ -1198,8 +1216,16 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
scissor.offset.y = static_cast<int32_t>(y); scissor.offset.y = static_cast<int32_t>(y);
scissor.extent.width = width; scissor.extent.width = width;
scissor.extent.height = height; scissor.extent.height = height;
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) {
cmdbuf.SetScissor(0, scissor);
GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline();
const bool use_scissor_with_count = device.IsExtExtendedDynamicStateSupported() &&
pipeline && pipeline->UsesExtendedDynamicState();
scheduler.Record([scissor, use_scissor_with_count](vk::CommandBuffer cmdbuf) {
if (use_scissor_with_count) {
std::array scissors{scissor};
cmdbuf.SetScissorWithCountEXT(scissors);
} else {
cmdbuf.SetScissor(0, scissor);
}
}); });
return; return;
} }
@ -1227,10 +1253,17 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
GetScissorState(regs, 14, up_scale, down_shift), GetScissorState(regs, 14, up_scale, down_shift),
GetScissorState(regs, 15, up_scale, down_shift), GetScissorState(regs, 15, up_scale, down_shift),
}; };
scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline();
const bool use_scissor_with_count = device.IsExtExtendedDynamicStateSupported() &&
pipeline && pipeline->UsesExtendedDynamicState();
scheduler.Record([this, scissor_list, use_scissor_with_count](vk::CommandBuffer cmdbuf) {
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors); const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
cmdbuf.SetScissor(0, scissors);
if (use_scissor_with_count) {
cmdbuf.SetScissorWithCountEXT(scissors);
} else {
cmdbuf.SetScissor(0, scissors);
}
}); });
} }

11
src/video_core/renderer_vulkan/vk_scheduler.cpp

@ -154,9 +154,11 @@ void Scheduler::RequestOutsideRenderPassOperationContext() {
bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) {
if (state.graphics_pipeline == pipeline) { if (state.graphics_pipeline == pipeline) {
if (pipeline && pipeline->UsesExtendedDynamicState() &&
if (pipeline &&
(pipeline->UsesExtendedDynamicState() || pipeline->UsesExtendedDynamicState2() ||
pipeline->UsesExtendedDynamicState2LogicOp()) &&
state.needs_state_enable_refresh) { state.needs_state_enable_refresh) {
state_tracker.InvalidateStateEnableFlag();
state_tracker.InvalidateExtendedDynamicStates();
state.needs_state_enable_refresh = false; state.needs_state_enable_refresh = false;
} }
return false; return false;
@ -173,10 +175,11 @@ bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) {
state_tracker.InvalidateExtendedDynamicStates(); state_tracker.InvalidateExtendedDynamicStates();
} }
if (!pipeline->UsesExtendedDynamicState()) {
if (!pipeline->UsesExtendedDynamicState() && !pipeline->UsesExtendedDynamicState2() &&
!pipeline->UsesExtendedDynamicState2LogicOp()) {
state.needs_state_enable_refresh = true; state.needs_state_enable_refresh = true;
} else if (state.needs_state_enable_refresh) { } else if (state.needs_state_enable_refresh) {
state_tracker.InvalidateStateEnableFlag();
state_tracker.InvalidateExtendedDynamicStates();
state.needs_state_enable_refresh = false; state.needs_state_enable_refresh = false;
} }

4
src/video_core/renderer_vulkan/vk_state_tracker.h

@ -98,9 +98,13 @@ public:
(*flags)[Dirty::Viewports] = true; (*flags)[Dirty::Viewports] = true;
(*flags)[Dirty::Scissors] = true; (*flags)[Dirty::Scissors] = true;
(*flags)[Dirty::CullMode] = true; (*flags)[Dirty::CullMode] = true;
(*flags)[Dirty::DepthBoundsEnable] = true;
(*flags)[Dirty::DepthTestEnable] = true;
(*flags)[Dirty::DepthWriteEnable] = true;
(*flags)[Dirty::DepthCompareOp] = true; (*flags)[Dirty::DepthCompareOp] = true;
(*flags)[Dirty::FrontFace] = true; (*flags)[Dirty::FrontFace] = true;
(*flags)[Dirty::StencilOp] = true; (*flags)[Dirty::StencilOp] = true;
(*flags)[Dirty::StencilTestEnable] = true;
(*flags)[Dirty::StateEnable] = true; (*flags)[Dirty::StateEnable] = true;
(*flags)[Dirty::PrimitiveRestartEnable] = true; (*flags)[Dirty::PrimitiveRestartEnable] = true;
(*flags)[Dirty::RasterizerDiscardEnable] = true; (*flags)[Dirty::RasterizerDiscardEnable] = true;

Loading…
Cancel
Save