diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 97016dbb04..f5baa5f068 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -595,6 +595,7 @@ if(TARGET 3rdparty_vulkan) RSX/VK/VKAsyncScheduler.cpp RSX/VK/VKCommandStream.cpp RSX/VK/VKCommonDecompiler.cpp + RSX/VK/VKCommonPipelineLayout.cpp RSX/VK/VKCompute.cpp RSX/VK/VKDMA.cpp RSX/VK/VKDraw.cpp diff --git a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp new file mode 100644 index 0000000000..6773a4d78f --- /dev/null +++ b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp @@ -0,0 +1,160 @@ +#include "stdafx.h" +#include "vkutils/device.h" +#include "vkutils/descriptors.h" +#include "VKCommonPipelineLayout.h" +#include "VKHelpers.h" + +#include "Emu/RSX/Common/simple_array.hpp" + +namespace vk +{ + rsx::simple_array get_common_binding_table() + { + const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); + rsx::simple_array bindings(binding_table.instancing_constants_buffer_slot + 1); + + u32 idx = 0; + + // Vertex stream, one stream for cacheable data, one stream for transient data + for (int i = 0; i < 3; i++) + { + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[idx].binding = binding_table.vertex_buffers_first_bind_slot + i; + bindings[idx].pImmutableSamplers = nullptr; + idx++; + } + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings[idx].binding = binding_table.fragment_constant_buffers_bind_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings[idx].binding = binding_table.fragment_state_bind_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings[idx].binding = binding_table.fragment_texture_params_bind_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[idx].binding = binding_table.vertex_constant_buffers_bind_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; + bindings[idx].binding = binding_table.vertex_params_bind_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[idx].binding = binding_table.conditional_render_predicate_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings[idx].binding = binding_table.rasterizer_env_bind_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[idx].binding = binding_table.instancing_lookup_table_bind_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[idx].binding = binding_table.instancing_constants_buffer_slot; + bindings[idx].pImmutableSamplers = nullptr; + + idx++; + + return bindings; + } + + std::tuple get_common_pipeline_layout(VkDevice dev) + { + const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); + auto bindings = get_common_binding_table(); + u32 idx = ::size32(bindings); + + bindings.resize(binding_table.total_descriptor_bindings); + + for (auto binding = binding_table.textures_first_bind_slot; + binding < binding_table.vertex_textures_first_bind_slot; + binding++) + { + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings[idx].binding = binding; + bindings[idx].pImmutableSamplers = nullptr; + idx++; + } + + for (int i = 0; i < rsx::limits::vertex_textures_count; i++) + { + bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bindings[idx].descriptorCount = 1; + bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + bindings[idx].binding = binding_table.vertex_textures_first_bind_slot + i; + bindings[idx].pImmutableSamplers = nullptr; + idx++; + } + + ensure(idx == binding_table.total_descriptor_bindings); + + std::array push_constants; + push_constants[0].offset = 0; + push_constants[0].size = 16; + push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + if (vk::emulate_conditional_rendering()) + { + // Conditional render toggle + push_constants[0].size = 20; + } + + const auto set_layout = vk::descriptors::create_layout(bindings); + + VkPipelineLayoutCreateInfo layout_info = {}; + layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = &set_layout; + layout_info.pushConstantRangeCount = 1; + layout_info.pPushConstantRanges = push_constants.data(); + + VkPipelineLayout result; + CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); + return std::make_tuple(result, set_layout); + } +} diff --git a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h new file mode 100644 index 0000000000..7c64d67982 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h @@ -0,0 +1,14 @@ +#pragma once + +#include "vkutils/shared.h" +#include "Emu/RSX/Common/simple_array.hpp" + +namespace vk +{ + // Grab standard layout for decompiled RSX programs. Also used by the interpreter. + // FIXME: This generates a bloated monstrosity that needs to die. + std::tuple get_common_pipeline_layout(VkDevice dev); + + // Returns the standard binding layout without texture slots. Those have special handling depending on the consumer. + rsx::simple_array get_common_binding_table(); +} diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 8ebb41c099..4490ff54bf 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -5,6 +5,7 @@ #include "VKAsyncScheduler.h" #include "VKCommandStream.h" #include "VKCommonDecompiler.h" +#include "VKCommonPipelineLayout.h" #include "VKCompute.h" #include "VKGSRender.h" #include "VKHelpers.h" @@ -401,148 +402,6 @@ namespace vk } } -namespace -{ - std::tuple get_shared_pipeline_layout(VkDevice dev) - { - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); - rsx::simple_array bindings(binding_table.total_descriptor_bindings); - - u32 idx = 0; - - // Vertex stream, one stream for cacheable data, one stream for transient data - for (int i = 0; i < 3; i++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_buffers_first_bind_slot + i; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_constant_buffers_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_state_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_texture_params_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_constant_buffers_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; - bindings[idx].binding = binding_table.vertex_params_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.conditional_render_predicate_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.rasterizer_env_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.instancing_lookup_table_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.instancing_constants_buffer_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - for (auto binding = binding_table.textures_first_bind_slot; - binding < binding_table.vertex_textures_first_bind_slot; - binding++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - for (int i = 0; i < rsx::limits::vertex_textures_count; i++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_textures_first_bind_slot + i; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - ensure(idx == binding_table.total_descriptor_bindings); - - std::array push_constants; - push_constants[0].offset = 0; - push_constants[0].size = 16; - push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - if (vk::emulate_conditional_rendering()) - { - // Conditional render toggle - push_constants[0].size = 20; - } - - const auto set_layout = vk::descriptors::create_layout(bindings); - - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = &set_layout; - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = push_constants.data(); - - VkPipelineLayout result; - CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); - return std::make_tuple(result, set_layout); - } -} - u64 VKGSRender::get_cycles() { return thread_ctrl::get_cycles(static_cast&>(*this)); @@ -633,7 +492,7 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar) m_secondary_cb_list.create(m_secondary_command_buffer_pool, vk::command_buffer::access_type_hint::all); //Precalculated stuff - std::tie(m_pipeline_layout, m_descriptor_layouts) = get_shared_pipeline_layout(*m_device); + std::tie(m_pipeline_layout, m_descriptor_layouts) = vk::get_common_pipeline_layout(*m_device); //Occlusion m_occlusion_query_manager = std::make_unique(*m_device, VK_QUERY_TYPE_OCCLUSION, OCCLUSION_MAX_POOL_SIZE); diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp index 6b6882f616..930210f19d 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp @@ -63,7 +63,7 @@ namespace vk const std::vector& vs_inputs, const std::vector& fs_inputs) { VkPipeline pipeline; - CHECK_RESULT(vkCreateGraphicsPipelines(*m_device, nullptr, 1, &create_info, NULL, &pipeline)); + CHECK_RESULT(vkCreateGraphicsPipelines(*m_device, VK_NULL_HANDLE, 1, &create_info, nullptr, &pipeline)); auto result = std::make_unique(*m_device, pipeline, pipe_layout, vs_inputs, fs_inputs); result->link(); return result; diff --git a/rpcs3/VKGSRender.vcxproj b/rpcs3/VKGSRender.vcxproj index 435e11e423..868ff9ad66 100644 --- a/rpcs3/VKGSRender.vcxproj +++ b/rpcs3/VKGSRender.vcxproj @@ -36,6 +36,7 @@ + @@ -84,6 +85,7 @@ + diff --git a/rpcs3/VKGSRender.vcxproj.filters b/rpcs3/VKGSRender.vcxproj.filters index bc2791f16a..153a21a9b0 100644 --- a/rpcs3/VKGSRender.vcxproj.filters +++ b/rpcs3/VKGSRender.vcxproj.filters @@ -72,6 +72,7 @@ upscalers\fsr1 + @@ -173,6 +174,7 @@ vkutils +