mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-09 22:58:54 +02:00
[vulkan] Adjusted VK_EXT_vertex_input_dynamic_state
This commit is contained in:
parent
415a62c37b
commit
3ca8bdce0d
4 changed files with 58 additions and 51 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
#include "video_core/buffer_cache/buffer_cache_base.h"
|
#include "video_core/buffer_cache/buffer_cache_base.h"
|
||||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||||
|
|
||||||
|
|
@ -334,6 +335,9 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m
|
||||||
staging_pool{staging_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
|
staging_pool{staging_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
|
||||||
quad_index_pass(device, scheduler, descriptor_pool, staging_pool,
|
quad_index_pass(device, scheduler, descriptor_pool, staging_pool,
|
||||||
compute_pass_descriptor_queue) {
|
compute_pass_descriptor_queue) {
|
||||||
|
use_vertex_input_dynamic_state = device.IsExtVertexInputDynamicStateSupported() &&
|
||||||
|
Settings::values.vertex_input_dynamic_state.GetValue();
|
||||||
|
|
||||||
const VkDriverIdKHR driver_id = device.GetDriverID();
|
const VkDriverIdKHR driver_id = device.GetDriverID();
|
||||||
limit_dynamic_storage_buffers = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
limit_dynamic_storage_buffers = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
|
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
|
||||||
|
|
@ -556,7 +560,10 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset
|
||||||
if (index >= device.GetMaxVertexInputBindings()) {
|
if (index >= device.GetMaxVertexInputBindings()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
const bool use_bind_vertex_buffers2_stride =
|
||||||
|
device.IsExtExtendedDynamicStateSupported() && !use_vertex_input_dynamic_state;
|
||||||
|
|
||||||
|
if (use_bind_vertex_buffers2_stride) {
|
||||||
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
||||||
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
|
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
|
||||||
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
|
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
|
||||||
|
|
@ -596,7 +603,10 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
|
||||||
if (binding_count == 0) {
|
if (binding_count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
const bool use_bind_vertex_buffers2_stride =
|
||||||
|
device.IsExtExtendedDynamicStateSupported() && !use_vertex_input_dynamic_state;
|
||||||
|
|
||||||
|
if (use_bind_vertex_buffers2_stride) {
|
||||||
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data());
|
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data());
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,7 @@ private:
|
||||||
std::unique_ptr<Uint8Pass> uint8_pass;
|
std::unique_ptr<Uint8Pass> uint8_pass;
|
||||||
QuadIndexedPass quad_index_pass;
|
QuadIndexedPass quad_index_pass;
|
||||||
|
|
||||||
|
bool use_vertex_input_dynamic_state = 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)();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1732,39 +1732,54 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||||
}
|
}
|
||||||
dirty[Dirty::VertexInput] = false;
|
dirty[Dirty::VertexInput] = false;
|
||||||
|
|
||||||
|
const size_t max_vertex_attributes =
|
||||||
|
(std::min)(Maxwell::NumVertexAttributes,
|
||||||
|
static_cast<size_t>(device.GetMaxVertexInputAttributes()));
|
||||||
|
const size_t max_vertex_bindings =
|
||||||
|
(std::min)(Maxwell::NumVertexArrays,
|
||||||
|
static_cast<size_t>(device.GetMaxVertexInputBindings()));
|
||||||
|
|
||||||
|
// Dynamic state path must respect device limits, same as static pipeline creation.
|
||||||
|
for (size_t index = max_vertex_attributes; index < Maxwell::NumVertexAttributes; ++index) {
|
||||||
|
dirty[Dirty::VertexAttribute0 + index] = false;
|
||||||
|
}
|
||||||
|
for (size_t index = max_vertex_bindings; index < Maxwell::NumVertexArrays; ++index) {
|
||||||
|
dirty[Dirty::VertexBinding0 + index] = false;
|
||||||
|
}
|
||||||
|
|
||||||
boost::container::static_vector<VkVertexInputBindingDescription2EXT, 32> bindings;
|
boost::container::static_vector<VkVertexInputBindingDescription2EXT, 32> bindings;
|
||||||
boost::container::static_vector<VkVertexInputAttributeDescription2EXT, 32> attributes;
|
boost::container::static_vector<VkVertexInputAttributeDescription2EXT, 32> attributes;
|
||||||
|
|
||||||
// There seems to be a bug on Nvidia's driver where updating only higher attributes ends up
|
std::array<bool, Maxwell::NumVertexArrays> used_bindings{};
|
||||||
// generating dirty state. Track the highest dirty attribute and update all attributes until
|
for (size_t index = 0; index < max_vertex_attributes; ++index) {
|
||||||
// that one.
|
|
||||||
size_t highest_dirty_attr{};
|
|
||||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
|
||||||
if (dirty[Dirty::VertexAttribute0 + index]) {
|
|
||||||
highest_dirty_attr = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t index = 0; index < highest_dirty_attr; ++index) {
|
|
||||||
const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]};
|
|
||||||
const u32 binding{attribute.buffer};
|
|
||||||
dirty[Dirty::VertexAttribute0 + index] = false;
|
dirty[Dirty::VertexAttribute0 + index] = false;
|
||||||
dirty[Dirty::VertexBinding0 + static_cast<size_t>(binding)] = true;
|
|
||||||
if (!attribute.constant) {
|
const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]};
|
||||||
attributes.push_back({
|
if (attribute.constant) {
|
||||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.location = static_cast<u32>(index),
|
|
||||||
.binding = binding,
|
|
||||||
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
|
|
||||||
.offset = attribute.offset,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
|
||||||
if (!dirty[Dirty::VertexBinding0 + index]) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const size_t binding{attribute.buffer};
|
||||||
|
if (binding >= max_vertex_bindings) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
used_bindings[binding] = true;
|
||||||
|
attributes.push_back({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.location = static_cast<u32>(index),
|
||||||
|
.binding = static_cast<u32>(binding),
|
||||||
|
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
|
||||||
|
.offset = attribute.offset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t index = 0; index < max_vertex_bindings; ++index) {
|
||||||
dirty[Dirty::VertexBinding0 + index] = false;
|
dirty[Dirty::VertexBinding0 + index] = false;
|
||||||
|
if (!used_bindings[index]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const u32 binding{static_cast<u32>(index)};
|
const u32 binding{static_cast<u32>(index)};
|
||||||
const auto& input_binding{regs.vertex_streams[binding]};
|
const auto& input_binding{regs.vertex_streams[binding]};
|
||||||
|
|
@ -1778,6 +1793,10 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||||
.divisor = is_instanced ? input_binding.frequency : 1,
|
.divisor = is_instanced ? input_binding.frequency : 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT(attributes.size() <= max_vertex_attributes);
|
||||||
|
ASSERT(bindings.size() <= max_vertex_bindings);
|
||||||
|
|
||||||
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.SetVertexInputEXT(bindings, attributes);
|
cmdbuf.SetVertexInputEXT(bindings, attributes);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1112,34 +1112,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||||
// VK_DYNAMIC_STATE
|
// VK_DYNAMIC_STATE
|
||||||
|
|
||||||
// Driver detection variables for workarounds in GetSuitability
|
// Driver detection variables for workarounds in GetSuitability
|
||||||
const VkDriverId driver_id = properties.driver.driverID;
|
|
||||||
|
|
||||||
// VK_EXT_extended_dynamic_state2 below this will appear drivers that need workarounds.
|
// VK_EXT_extended_dynamic_state2 below this will appear drivers that need workarounds.
|
||||||
|
|
||||||
// VK_EXT_extended_dynamic_state3 below this will appear drivers that need workarounds.
|
// VK_EXT_extended_dynamic_state3 below this will appear drivers that need workarounds.
|
||||||
|
|
||||||
// Samsung: Broken extendedDynamicState3ColorBlendEquation
|
|
||||||
// Disable blend equation dynamic state, force static pipeline state
|
|
||||||
if (extensions.extended_dynamic_state3 &&
|
|
||||||
(driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY)) {
|
|
||||||
LOG_WARNING(Render_Vulkan,
|
|
||||||
"Samsung: Disabling broken extendedDynamicState3ColorBlendEquation");
|
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
|
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intel Windows < 27.20.100.0: Broken VertexInputDynamicState
|
|
||||||
// Same for NVIDIA Proprietary < 580.119.02, unknown when VIDS was first NOT broken
|
|
||||||
// Disable VertexInputDynamicState on old Intel Windows drivers
|
|
||||||
if (extensions.vertex_input_dynamic_state) {
|
|
||||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
|
||||||
if ((driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS && version < VK_MAKE_API_VERSION(27, 20, 100, 0))
|
|
||||||
|| (driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY && version < VK_MAKE_API_VERSION(580, 119, 02, 0))) {
|
|
||||||
LOG_WARNING(Render_Vulkan, "Disabling broken VK_EXT_vertex_input_dynamic_state");
|
|
||||||
RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u32(Settings::values.dyna_state.GetValue()) == 0) {
|
if (u32(Settings::values.dyna_state.GetValue()) == 0) {
|
||||||
LOG_INFO(Render_Vulkan, "Extended Dynamic State disabled by user setting, clearing all EDS features");
|
LOG_INFO(Render_Vulkan, "Extended Dynamic State disabled by user setting, clearing all EDS features");
|
||||||
features.extended_dynamic_state.extendedDynamicState = false;
|
features.extended_dynamic_state.extendedDynamicState = false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue