[vulkan] Adjustment ExtendedDynamicState System Nª1

This commit is contained in:
CamilleLaVey 2026-04-09 02:11:13 -04:00
parent 3ca8bdce0d
commit a8f4fe55cb
8 changed files with 147 additions and 29 deletions

View file

@ -806,6 +806,58 @@ void BufferCache<P>::UpdateVertexBufferSlot(u32 index, const Binding& binding) {
template <class P> template <class P>
void BufferCache<P>::BindHostVertexBuffers() { void BufferCache<P>::BindHostVertexBuffers() {
bool needs_vertex_input_refresh = false;
bool use_vertex_input_dynamic_state = false;
bool use_dynamic_stride = false;
u32 max_dynamic_stride = 0;
std::array<u32, NUM_VERTEX_BUFFERS> min_dynamic_stride{};
if constexpr (!IS_OPENGL) {
use_vertex_input_dynamic_state = runtime.UsesVertexInputDynamicState();
if (use_vertex_input_dynamic_state) {
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
if (maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) {
needs_vertex_input_refresh = true;
break;
}
}
}
use_dynamic_stride = runtime.UsesDynamicVertexBindingStride();
if (use_dynamic_stride) {
max_dynamic_stride = runtime.GetMaxVertexInputBindingStride();
for (const auto& attribute : maxwell3d->regs.vertex_attrib_format) {
if (attribute.constant != 0) {
continue;
}
const u32 binding = attribute.buffer;
if (binding >= NUM_VERTEX_BUFFERS) {
continue;
}
const u32 extent = attribute.offset + attribute.SizeInBytes();
min_dynamic_stride[binding] = (std::max)(min_dynamic_stride[binding], extent);
}
}
}
const auto sanitize_stride = [&](u32 binding, u32 stride) -> u32 {
if constexpr (IS_OPENGL) {
return stride;
} else {
if (!use_dynamic_stride || stride == 0) {
return stride;
}
const u32 min_stride = min_dynamic_stride[binding];
const u32 required_stride = (std::max)(stride, min_stride);
if (required_stride <= max_dynamic_stride) {
return required_stride;
}
if (min_stride > max_dynamic_stride) {
return 0;
}
return max_dynamic_stride;
}
};
#ifdef ANDROID #ifdef ANDROID
const bool use_optimized_vertex_buffers = Settings::values.use_optimized_vertex_buffers.GetValue(); const bool use_optimized_vertex_buffers = Settings::values.use_optimized_vertex_buffers.GetValue();
#else #else
@ -838,7 +890,8 @@ void BufferCache<P>::BindHostVertexBuffers() {
continue; continue;
} }
flags[Dirty::VertexBuffer0 + index] = false; flags[Dirty::VertexBuffer0 + index] = false;
const u32 stride = maxwell3d->regs.vertex_streams[index].stride; const u32 stride =
sanitize_stride(index, maxwell3d->regs.vertex_streams[index].stride);
const u32 offset = buffer.Offset(binding.device_addr); const u32 offset = buffer.Offset(binding.device_addr);
buffer.MarkUsage(offset, binding.size); buffer.MarkUsage(offset, binding.size);
if (!bindings.buffers.empty() && index != last_index + 1) { if (!bindings.buffers.empty() && index != last_index + 1) {
@ -881,7 +934,8 @@ void BufferCache<P>::BindHostVertexBuffers() {
const Binding& binding = channel_state->vertex_buffers[index]; const Binding& binding = channel_state->vertex_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id]; Buffer& buffer = slot_buffers[binding.buffer_id];
const u32 stride = maxwell3d->regs.vertex_streams[index].stride; const u32 stride =
sanitize_stride(index, maxwell3d->regs.vertex_streams[index].stride);
const u32 offset = buffer.Offset(binding.device_addr); const u32 offset = buffer.Offset(binding.device_addr);
buffer.MarkUsage(offset, binding.size); buffer.MarkUsage(offset, binding.size);
@ -893,6 +947,12 @@ void BufferCache<P>::BindHostVertexBuffers() {
runtime.BindVertexBuffers(host_bindings); runtime.BindVertexBuffers(host_bindings);
} }
} }
if constexpr (!IS_OPENGL) {
if (needs_vertex_input_refresh) {
runtime.NotifyVertexInputBindingChange();
}
}
} }
template <class P> template <class P>

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
@ -161,6 +161,28 @@ public:
return max_dynamic_storage_buffers; return max_dynamic_storage_buffers;
} }
bool UsesDynamicVertexBindingStride() const {
return device.IsExtExtendedDynamicStateSupported() && !use_vertex_input_dynamic_state;
}
bool UsesVertexInputDynamicState() const {
return use_vertex_input_dynamic_state;
}
void NotifyVertexInputBindingChange() {
needs_vertex_input_refresh = true;
}
bool ConsumeVertexInputBindingChange() {
const bool refresh = needs_vertex_input_refresh;
needs_vertex_input_refresh = false;
return refresh;
}
u32 GetMaxVertexInputBindingStride() const {
return device.GetMaxVertexInputBindingStride();
}
private: private:
void BindBuffer(VkBuffer buffer, u32 offset, u32 size) { void BindBuffer(VkBuffer buffer, u32 offset, u32 size) {
guest_descriptor_queue.AddBuffer(buffer, offset, size); guest_descriptor_queue.AddBuffer(buffer, offset, size);
@ -184,6 +206,7 @@ private:
QuadIndexedPass quad_index_pass; QuadIndexedPass quad_index_pass;
bool use_vertex_input_dynamic_state = false; bool use_vertex_input_dynamic_state = false;
bool needs_vertex_input_refresh = false;
bool limit_dynamic_storage_buffers = false; bool limit_dynamic_storage_buffers = false;
u32 max_dynamic_storage_buffers = (std::numeric_limits<u32>::max)(); u32 max_dynamic_storage_buffers = (std::numeric_limits<u32>::max)();
}; };

View file

@ -82,6 +82,9 @@ public:
const std::array<const Shader::Info*, NUM_STAGES>& infos); const std::array<const Shader::Info*, NUM_STAGES>& infos);
bool HasDynamicVertexInput() const noexcept { return key.state.dynamic_vertex_input; } bool HasDynamicVertexInput() const noexcept { return key.state.dynamic_vertex_input; }
bool UsesVertexAttribute(size_t index) const noexcept {
return index < Maxwell::NumVertexAttributes && stage_infos[0].loads.Generic(index);
}
bool SupportsAlphaToCoverage() const noexcept { bool SupportsAlphaToCoverage() const noexcept {
return fragment_has_color0_output; return fragment_has_color0_output;
} }

View file

@ -1014,20 +1014,6 @@ void RasterizerVulkan::UpdateDynamicStates() {
// EDS3 Enables: LogicOpEnable, DepthClamp, LineStipple, ConservativeRaster // EDS3 Enables: LogicOpEnable, DepthClamp, LineStipple, ConservativeRaster
if (device.IsExtExtendedDynamicState3EnablesSupported()) { if (device.IsExtExtendedDynamicState3EnablesSupported()) {
using namespace Tegra::Engines;
// AMD Workaround: LogicOp incompatible with float render targets
if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE ||
device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) {
const auto has_float = std::any_of(
regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(),
[](const auto& attrib) {
return attrib.type == Maxwell3D::Regs::VertexAttribute::Type::Float;
}
);
if (regs.logic_op.enable) {
regs.logic_op.enable = static_cast<u32>(!has_float);
}
}
UpdateLogicOpEnable(regs); UpdateLogicOpEnable(regs);
UpdateDepthClampEnable(regs); UpdateDepthClampEnable(regs);
UpdateLineRasterizationMode(regs); UpdateLineRasterizationMode(regs);
@ -1045,7 +1031,7 @@ void RasterizerVulkan::UpdateDynamicStates() {
// Vertex Input Dynamic State: Independent from EDS levels // Vertex Input Dynamic State: Independent from EDS levels
if (device.IsExtVertexInputDynamicStateSupported()) { if (device.IsExtVertexInputDynamicStateSupported()) {
if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) { if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) {
UpdateVertexInput(regs); UpdateVertexInput(regs, *gp);
} }
} }
} }
@ -1725,9 +1711,11 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs&
}); });
} }
void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) { void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs,
const GraphicsPipeline& pipeline) {
auto& dirty{maxwell3d->dirty.flags}; auto& dirty{maxwell3d->dirty.flags};
if (!dirty[Dirty::VertexInput]) { const bool force_vertex_input_refresh = buffer_cache_runtime.ConsumeVertexInputBindingChange();
if (!dirty[Dirty::VertexInput] && !force_vertex_input_refresh) {
return; return;
} }
dirty[Dirty::VertexInput] = false; dirty[Dirty::VertexInput] = false;
@ -1758,6 +1746,9 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
if (attribute.constant) { if (attribute.constant) {
continue; continue;
} }
if (!pipeline.UsesVertexAttribute(index)) {
continue;
}
const size_t binding{attribute.buffer}; const size_t binding{attribute.buffer};
if (binding >= max_vertex_bindings) { if (binding >= max_vertex_bindings) {

View file

@ -191,7 +191,8 @@ private:
void UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs,
const GraphicsPipeline& pipeline);
Tegra::GPU& gpu; Tegra::GPU& gpu;
Tegra::MaxwellDeviceMemoryManager& device_memory; Tegra::MaxwellDeviceMemoryManager& device_memory;

View file

@ -153,11 +153,17 @@ void Scheduler::RequestOutsideRenderPassOperationContext() {
} }
bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) {
const auto consume_eds_refresh = [this] {
if (!state.needs_state_enable_refresh) {
return;
}
state_tracker.InvalidateExtendedDynamicStateFlags();
state.needs_state_enable_refresh = false;
};
if (state.graphics_pipeline == pipeline) { if (state.graphics_pipeline == pipeline) {
if (pipeline && pipeline->UsesExtendedDynamicState() && if (pipeline && pipeline->UsesExtendedDynamicState()) {
state.needs_state_enable_refresh) { consume_eds_refresh();
state_tracker.InvalidateStateEnableFlag();
state.needs_state_enable_refresh = false;
} }
return false; return false;
} }
@ -170,9 +176,8 @@ bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) {
if (!pipeline->UsesExtendedDynamicState()) { if (!pipeline->UsesExtendedDynamicState()) {
state.needs_state_enable_refresh = true; state.needs_state_enable_refresh = true;
} else if (state.needs_state_enable_refresh) { } else {
state_tracker.InvalidateStateEnableFlag(); consume_eds_refresh();
state.needs_state_enable_refresh = false;
} }
return true; return true;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@ -101,6 +101,37 @@ public:
(*flags)[Dirty::StateEnable] = true; (*flags)[Dirty::StateEnable] = true;
} }
void InvalidateExtendedDynamicStateFlags() {
InvalidateStateEnableFlag();
(*flags)[Dirty::CullMode] = true;
(*flags)[Dirty::DepthCompareOp] = true;
(*flags)[Dirty::FrontFace] = true;
(*flags)[Dirty::StencilOp] = true;
(*flags)[Dirty::DepthBoundsEnable] = true;
(*flags)[Dirty::DepthTestEnable] = true;
(*flags)[Dirty::DepthWriteEnable] = true;
(*flags)[Dirty::StencilTestEnable] = true;
(*flags)[Dirty::PrimitiveRestartEnable] = true;
(*flags)[Dirty::RasterizerDiscardEnable] = true;
(*flags)[Dirty::DepthBiasEnable] = true;
(*flags)[Dirty::LogicOp] = true;
(*flags)[Dirty::LogicOpEnable] = true;
(*flags)[Dirty::DepthClampEnable] = true;
(*flags)[Dirty::LineRasterizationMode] = true;
(*flags)[Dirty::LineStippleEnable] = true;
(*flags)[Dirty::ConservativeRasterizationMode] = true;
(*flags)[Dirty::AlphaToCoverageEnable] = true;
(*flags)[Dirty::AlphaToOneEnable] = true;
(*flags)[Dirty::Blending] = true;
(*flags)[Dirty::ColorMask] = true;
(*flags)[Dirty::BlendEnable] = true;
(*flags)[Dirty::BlendEquations] = true;
}
bool TouchViewports() { bool TouchViewports() {
const bool dirty_viewports = Exchange(Dirty::Viewports, false); const bool dirty_viewports = Exchange(Dirty::Viewports, false);
const bool rescale_viewports = Exchange(VideoCommon::Dirty::RescaleViewports, false); const bool rescale_viewports = Exchange(VideoCommon::Dirty::RescaleViewports, false);

View file

@ -783,6 +783,10 @@ public:
return properties.properties.limits.maxVertexInputBindings; return properties.properties.limits.maxVertexInputBindings;
} }
u32 GetMaxVertexInputBindingStride() const {
return properties.properties.limits.maxVertexInputBindingStride;
}
u32 GetMaxViewports() const { u32 GetMaxViewports() const {
return properties.properties.limits.maxViewports; return properties.properties.limits.maxViewports;
} }