mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-01-16 20:05:13 +00:00
vulkan: Use dynamic vertex buffer strides when dynamic bindings unavailable. (#1164)
This commit is contained in:
parent
82c7c6aed1
commit
bf3e43b016
|
@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
enable_language(OBJC)
|
enable_language(OBJC)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 11)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 14)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT CMAKE_BUILD_TYPE)
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
|
|
|
@ -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).
|
Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md).
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!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
|
# Debugging and reporting issues
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,8 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) {
|
||||||
|
|
||||||
std::array<vk::Buffer, NumVertexBuffers> host_buffers;
|
std::array<vk::Buffer, NumVertexBuffers> host_buffers;
|
||||||
std::array<vk::DeviceSize, NumVertexBuffers> host_offsets;
|
std::array<vk::DeviceSize, NumVertexBuffers> host_offsets;
|
||||||
|
std::array<vk::DeviceSize, NumVertexBuffers> host_sizes;
|
||||||
|
std::array<vk::DeviceSize, NumVertexBuffers> host_strides;
|
||||||
boost::container::static_vector<AmdGpu::Buffer, NumVertexBuffers> guest_buffers;
|
boost::container::static_vector<AmdGpu::Buffer, NumVertexBuffers> guest_buffers;
|
||||||
|
|
||||||
struct BufferRange {
|
struct BufferRange {
|
||||||
|
@ -193,11 +195,18 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) {
|
||||||
|
|
||||||
host_buffers[i] = host_buffer->vk_buffer;
|
host_buffers[i] = host_buffer->vk_buffer;
|
||||||
host_offsets[i] = host_buffer->offset + buffer.base_address - host_buffer->base_address;
|
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) {
|
if (num_buffers > 0) {
|
||||||
const auto cmdbuf = scheduler.CommandBuffer();
|
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;
|
return has_step_rate;
|
||||||
|
|
|
@ -46,28 +46,34 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||||
|
|
||||||
boost::container::static_vector<vk::VertexInputBindingDescription, 32> vertex_bindings;
|
boost::container::static_vector<vk::VertexInputBindingDescription, 32> vertex_bindings;
|
||||||
boost::container::static_vector<vk::VertexInputAttributeDescription, 32> vertex_attributes;
|
boost::container::static_vector<vk::VertexInputAttributeDescription, 32> vertex_attributes;
|
||||||
const auto& vs_info = stages[u32(Shader::Stage::Vertex)];
|
if (!instance.IsVertexInputDynamicState()) {
|
||||||
for (const auto& input : vs_info->vs_inputs) {
|
const auto& vs_info = stages[u32(Shader::Stage::Vertex)];
|
||||||
if (input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate0 ||
|
for (const auto& input : vs_info->vs_inputs) {
|
||||||
input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate1) {
|
if (input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate0 ||
|
||||||
// Skip attribute binding as the data will be pulled by shader
|
input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate1) {
|
||||||
continue;
|
// Skip attribute binding as the data will be pulled by shader
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const auto buffer = vs_info->ReadUd<AmdGpu::Buffer>(input.sgpr_base, input.dword_offset);
|
const auto buffer =
|
||||||
vertex_attributes.push_back({
|
vs_info->ReadUd<AmdGpu::Buffer>(input.sgpr_base, input.dword_offset);
|
||||||
.location = input.binding,
|
if (buffer.GetSize() == 0) {
|
||||||
.binding = input.binding,
|
continue;
|
||||||
.format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()),
|
}
|
||||||
.offset = 0,
|
vertex_attributes.push_back({
|
||||||
});
|
.location = input.binding,
|
||||||
vertex_bindings.push_back({
|
.binding = input.binding,
|
||||||
.binding = input.binding,
|
.format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()),
|
||||||
.stride = buffer.GetStride(),
|
.offset = 0,
|
||||||
.inputRate = input.instance_step_rate == Shader::Info::VsInput::None
|
});
|
||||||
? vk::VertexInputRate::eVertex
|
vertex_bindings.push_back({
|
||||||
: vk::VertexInputRate::eInstance,
|
.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 = {
|
const vk::PipelineVertexInputStateCreateInfo vertex_input_info = {
|
||||||
|
@ -147,6 +153,8 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||||
}
|
}
|
||||||
if (instance.IsVertexInputDynamicState()) {
|
if (instance.IsVertexInputDynamicState()) {
|
||||||
dynamic_states.push_back(vk::DynamicState::eVertexInputEXT);
|
dynamic_states.push_back(vk::DynamicState::eVertexInputEXT);
|
||||||
|
} else {
|
||||||
|
dynamic_states.push_back(vk::DynamicState::eVertexInputBindingStrideEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
const vk::PipelineDynamicStateCreateInfo dynamic_info = {
|
const vk::PipelineDynamicStateCreateInfo dynamic_info = {
|
||||||
|
@ -273,7 +281,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||||
.pNext = &pipeline_rendering_ci,
|
.pNext = &pipeline_rendering_ci,
|
||||||
.stageCount = static_cast<u32>(shader_stages.size()),
|
.stageCount = static_cast<u32>(shader_stages.size()),
|
||||||
.pStages = shader_stages.data(),
|
.pStages = shader_stages.data(),
|
||||||
.pVertexInputState = &vertex_input_info,
|
.pVertexInputState = !instance.IsVertexInputDynamicState() ? &vertex_input_info : nullptr,
|
||||||
.pInputAssemblyState = &input_assembly,
|
.pInputAssemblyState = &input_assembly,
|
||||||
.pViewportState = &viewport_info,
|
.pViewportState = &viewport_info,
|
||||||
.pRasterizationState = &raster_state,
|
.pRasterizationState = &raster_state,
|
||||||
|
|
|
@ -45,6 +45,7 @@ struct GraphicsPipelineKey {
|
||||||
Liverpool::ColorBufferMask cb_shader_mask;
|
Liverpool::ColorBufferMask cb_shader_mask;
|
||||||
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
|
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
|
||||||
std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;
|
std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;
|
||||||
|
std::array<vk::Format, MaxVertexBufferCount> vertex_buffer_formats;
|
||||||
|
|
||||||
bool operator==(const GraphicsPipelineKey& key) const noexcept {
|
bool operator==(const GraphicsPipelineKey& key) const noexcept {
|
||||||
return std::memcmp(this, &key, sizeof(key)) == 0;
|
return std::memcmp(this, &key, sizeof(key)) == 0;
|
||||||
|
|
|
@ -272,6 +272,7 @@ bool Instance::CreateDevice() {
|
||||||
add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
||||||
add_extension(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
|
add_extension(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
|
||||||
add_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
|
add_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
|
||||||
|
add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// Required by Vulkan spec if supported.
|
// Required by Vulkan spec if supported.
|
||||||
|
|
|
@ -247,6 +247,7 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||||
key.blend_controls.fill({});
|
key.blend_controls.fill({});
|
||||||
key.write_masks.fill({});
|
key.write_masks.fill({});
|
||||||
key.mrt_swizzles.fill(Liverpool::ColorBuffer::SwapMode::Standard);
|
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
|
// First pass of bindings check to idenitfy formats and swizzles and pass them to rhe shader
|
||||||
// recompiler.
|
// recompiler.
|
||||||
|
@ -310,7 +311,26 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||||
std::tie(infos[i], modules[i], key.stage_hashes[i]) = GetProgram(stage, params, binding);
|
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<u32>(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<AmdGpu::Buffer>(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<u32>(Shader::Stage::Fragment)];
|
||||||
key.mrt_mask = fs_info ? fs_info->mrt_mask : 0u;
|
key.mrt_mask = fs_info ? fs_info->mrt_mask : 0u;
|
||||||
|
|
||||||
// Second pass to fill remain CB pipeline key data
|
// Second pass to fill remain CB pipeline key data
|
||||||
|
|
Loading…
Reference in a new issue