From bf3e43b01683bd783323e12237027103fae28d54 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Mon, 30 Sep 2024 23:54:06 -0700 Subject: [PATCH] vulkan: Use dynamic vertex buffer strides when dynamic bindings unavailable. (#1164) --- CMakeLists.txt | 2 +- README.md | 2 +- src/video_core/buffer_cache/buffer_cache.cpp | 11 +++- .../renderer_vulkan/vk_graphics_pipeline.cpp | 52 +++++++++++-------- .../renderer_vulkan/vk_graphics_pipeline.h | 1 + .../renderer_vulkan/vk_instance.cpp | 1 + .../renderer_vulkan/vk_pipeline_cache.cpp | 22 +++++++- 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9ea1591..598f59e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) if(APPLE) enable_language(OBJC) - set(CMAKE_OSX_DEPLOYMENT_TARGET 11) + set(CMAKE_OSX_DEPLOYMENT_TARGET 14) endif() if (NOT CMAKE_BUILD_TYPE) diff --git a/README.md b/README.md index 6d6e2d82..da01833e 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shad Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md). > [!IMPORTANT] -> macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 11 on Intel-based Mac devices. +> macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 14 on Intel-based Mac devices. # Debugging and reporting issues diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index caffee6b..607543a5 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -114,6 +114,8 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { std::array host_buffers; std::array host_offsets; + std::array host_sizes; + std::array host_strides; boost::container::static_vector guest_buffers; struct BufferRange { @@ -193,11 +195,18 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { host_buffers[i] = host_buffer->vk_buffer; host_offsets[i] = host_buffer->offset + buffer.base_address - host_buffer->base_address; + host_sizes[i] = buffer.GetSize(); + host_strides[i] = buffer.GetStride(); } if (num_buffers > 0) { const auto cmdbuf = scheduler.CommandBuffer(); - cmdbuf.bindVertexBuffers(0, num_buffers, host_buffers.data(), host_offsets.data()); + if (instance.IsVertexInputDynamicState()) { + cmdbuf.bindVertexBuffers(0, num_buffers, host_buffers.data(), host_offsets.data()); + } else { + cmdbuf.bindVertexBuffers2EXT(0, num_buffers, host_buffers.data(), host_offsets.data(), + host_sizes.data(), host_strides.data()); + } } return has_step_rate; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 3c191c4a..ce79d423 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -46,28 +46,34 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul boost::container::static_vector vertex_bindings; boost::container::static_vector vertex_attributes; - const auto& vs_info = stages[u32(Shader::Stage::Vertex)]; - for (const auto& input : vs_info->vs_inputs) { - if (input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate0 || - input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate1) { - // Skip attribute binding as the data will be pulled by shader - continue; - } + if (!instance.IsVertexInputDynamicState()) { + const auto& vs_info = stages[u32(Shader::Stage::Vertex)]; + for (const auto& input : vs_info->vs_inputs) { + if (input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate0 || + input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate1) { + // Skip attribute binding as the data will be pulled by shader + continue; + } - const auto buffer = vs_info->ReadUd(input.sgpr_base, input.dword_offset); - vertex_attributes.push_back({ - .location = input.binding, - .binding = input.binding, - .format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()), - .offset = 0, - }); - vertex_bindings.push_back({ - .binding = input.binding, - .stride = buffer.GetStride(), - .inputRate = input.instance_step_rate == Shader::Info::VsInput::None - ? vk::VertexInputRate::eVertex - : vk::VertexInputRate::eInstance, - }); + const auto buffer = + vs_info->ReadUd(input.sgpr_base, input.dword_offset); + if (buffer.GetSize() == 0) { + continue; + } + vertex_attributes.push_back({ + .location = input.binding, + .binding = input.binding, + .format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()), + .offset = 0, + }); + vertex_bindings.push_back({ + .binding = input.binding, + .stride = buffer.GetStride(), + .inputRate = input.instance_step_rate == Shader::Info::VsInput::None + ? vk::VertexInputRate::eVertex + : vk::VertexInputRate::eInstance, + }); + } } const vk::PipelineVertexInputStateCreateInfo vertex_input_info = { @@ -147,6 +153,8 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul } if (instance.IsVertexInputDynamicState()) { dynamic_states.push_back(vk::DynamicState::eVertexInputEXT); + } else { + dynamic_states.push_back(vk::DynamicState::eVertexInputBindingStrideEXT); } const vk::PipelineDynamicStateCreateInfo dynamic_info = { @@ -273,7 +281,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul .pNext = &pipeline_rendering_ci, .stageCount = static_cast(shader_stages.size()), .pStages = shader_stages.data(), - .pVertexInputState = &vertex_input_info, + .pVertexInputState = !instance.IsVertexInputDynamicState() ? &vertex_input_info : nullptr, .pInputAssemblyState = &input_assembly, .pViewportState = &viewport_info, .pRasterizationState = &raster_state, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 74817656..dda9183a 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -45,6 +45,7 @@ struct GraphicsPipelineKey { Liverpool::ColorBufferMask cb_shader_mask; std::array blend_controls; std::array write_masks; + std::array vertex_buffer_formats; bool operator==(const GraphicsPipelineKey& key) const noexcept { return std::memcmp(this, &key, sizeof(key)) == 0; diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index c09414a1..2aeb77ec 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -272,6 +272,7 @@ bool Instance::CreateDevice() { add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); add_extension(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME); add_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME); + add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); #ifdef __APPLE__ // Required by Vulkan spec if supported. diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 4aca0073..7a66fc0a 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -247,6 +247,7 @@ bool PipelineCache::RefreshGraphicsKey() { key.blend_controls.fill({}); key.write_masks.fill({}); key.mrt_swizzles.fill(Liverpool::ColorBuffer::SwapMode::Standard); + key.vertex_buffer_formats.fill(vk::Format::eUndefined); // First pass of bindings check to idenitfy formats and swizzles and pass them to rhe shader // recompiler. @@ -310,7 +311,26 @@ bool PipelineCache::RefreshGraphicsKey() { std::tie(infos[i], modules[i], key.stage_hashes[i]) = GetProgram(stage, params, binding); } - const auto* fs_info = infos[u32(Shader::Stage::Fragment)]; + const auto* vs_info = infos[static_cast(Shader::Stage::Vertex)]; + if (vs_info && !instance.IsVertexInputDynamicState()) { + u32 vertex_binding = 0; + for (const auto& input : vs_info->vs_inputs) { + if (input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate0 || + input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate1) { + continue; + } + const auto& buffer = + vs_info->ReadUd(input.sgpr_base, input.dword_offset); + if (buffer.GetSize() == 0) { + continue; + } + ASSERT(vertex_binding < MaxVertexBufferCount); + key.vertex_buffer_formats[vertex_binding++] = + Vulkan::LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()); + } + } + + const auto* fs_info = infos[static_cast(Shader::Stage::Fragment)]; key.mrt_mask = fs_info ? fs_info->mrt_mask : 0u; // Second pass to fill remain CB pipeline key data