diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index b7d372e8bd..82613c12ff 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -577,6 +577,7 @@ if(TARGET 3rdparty_vulkan) RSX/VK/vkutils/buffer_object.cpp RSX/VK/vkutils/chip_class.cpp RSX/VK/vkutils/commands.cpp + RSX/VK/vkutils/ex.cpp RSX/VK/vkutils/data_heap.cpp RSX/VK/vkutils/descriptors.cpp RSX/VK/vkutils/image.cpp diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index ff233e3a04..345103264e 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -553,7 +553,7 @@ bool VKGSRender::bind_texture_env() if (view) [[likely]] { - m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout }, + m_program->bind_uniform({ *view, *fs_sampler_handles[i] }, vk::glsl::binding_set_index_fragment, m_fs_binding_table->ftex_location[i]); @@ -574,7 +574,7 @@ bool VKGSRender::bind_texture_env() VK_BORDER_COLOR_INT_OPAQUE_BLACK); } - m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout }, + m_program->bind_uniform({ *stencil_view, *m_stencil_mirror_sampler }, vk::glsl::binding_set_index_fragment, m_fs_binding_table->ftex_stencil_location[i]); } @@ -582,13 +582,14 @@ bool VKGSRender::bind_texture_env() else { const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i)); - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + const VkDescriptorImageInfoEx desc = { *vk::null_image_view(*m_current_command_buffer, view_type), vk::null_sampler() }; + m_program->bind_uniform(desc, vk::glsl::binding_set_index_fragment, m_fs_binding_table->ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + m_program->bind_uniform(desc, vk::glsl::binding_set_index_fragment, m_fs_binding_table->ftex_stencil_location[i]); } @@ -603,7 +604,7 @@ bool VKGSRender::bind_texture_env() if (!rsx::method_registers.vertex_textures[i].enabled()) { const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + m_program->bind_uniform({ *vk::null_image_view(*m_current_command_buffer, view_type), vk::null_sampler() }, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vtex_location[i]); @@ -626,7 +627,7 @@ bool VKGSRender::bind_texture_env() rsx_log.error("Texture upload failed to vtexture index %d. Binding null sampler.", i); const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + m_program->bind_uniform({ *vk::null_image_view(*m_current_command_buffer, view_type), vk::null_sampler() }, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vtex_location[i]); @@ -635,7 +636,7 @@ bool VKGSRender::bind_texture_env() validate_image_layout_for_read_access(*m_current_command_buffer, image_ptr, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, sampler_state); - m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout }, + m_program->bind_uniform({ *image_ptr, *vs_sampler_handles[i] }, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vtex_location[i]); } @@ -651,8 +652,12 @@ bool VKGSRender::bind_interpreter_texture_env() return false; } - std::array texture_env; - VkDescriptorImageInfo fallback = { vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, VK_IMAGE_VIEW_TYPE_1D)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + std::array texture_env; + VkDescriptorImageInfoEx fallback = + { + *vk::null_image_view(*m_current_command_buffer, VK_IMAGE_VIEW_TYPE_1D), + vk::null_sampler() + }; auto start = texture_env.begin(); auto end = start; @@ -708,7 +713,7 @@ bool VKGSRender::bind_interpreter_texture_env() { const int offsets[] = { 0, 16, 48, 32 }; auto& sampled_image_info = texture_env[offsets[static_cast(sampler_state->image_type)] + i]; - sampled_image_info = { fs_sampler_handles[i]->value, view->value, view->image()->current_layout }; + sampled_image_info = { *view, *fs_sampler_handles[i] }; } } diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index d0abe33485..9ca5a16aaa 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -188,9 +188,8 @@ namespace vk for (uint n = 0; n < src.size(); ++n) { - VkDescriptorImageInfo info = { m_sampler->value, src[n]->value, src[n]->image()->current_layout }; const auto [set, location] = program->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "fs" + std::to_string(n)); - program->bind_uniform(info, set, location); + program->bind_uniform({ *src[n], *m_sampler }, set, location); } program->bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS); diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 446d4f0063..588c7a5a58 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -3,22 +3,23 @@ #include "VKResourceManager.h" #include "vkutils/descriptors.h" #include "vkutils/device.h" +#include "vkutils/image.h" +#include "vkutils/sampler.h" #include "../Program/SPIRVCommon.h" namespace vk { - extern const vk::render_device* get_current_renderer(); - namespace glsl { using namespace ::glsl; - bool operator == (const descriptor_slot_t& a, const VkDescriptorImageInfo& b) + bool operator == (const descriptor_slot_t& a, const VkDescriptorImageInfoEx& b) { - const auto ptr = std::get_if(&a); + const auto ptr = std::get_if(&a); return !!ptr && ptr->imageView == b.imageView && + ptr->resourceId == b.resourceId && ptr->sampler == b.sampler && ptr->imageLayout == b.imageLayout; } @@ -38,7 +39,7 @@ namespace vk return !!ptr && *ptr == b; } - bool operator == (const descriptor_slot_t& a, const std::span& b) + bool operator == (const descriptor_slot_t& a, const std::span& b) { const auto ptr = std::get_if(&a); return !!ptr && ptr->size() == b.size() && !std::memcmp(ptr->data(), b.data(), b.size_bytes()); @@ -313,7 +314,7 @@ namespace vk return { umax, umax }; } - void program::bind_uniform(const VkDescriptorImageInfo& image_descriptor, u32 set_id, u32 binding_point) + void program::bind_uniform(const VkDescriptorImageInfoEx& image_descriptor, u32 set_id, u32 binding_point) { if (m_sets[set_id].m_descriptor_slots[binding_point] == image_descriptor) { @@ -343,7 +344,7 @@ namespace vk m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_view); } - void program::bind_uniform_array(const std::span& image_descriptors, u32 set_id, u32 binding_point) + void program::bind_uniform_array(const std::span& image_descriptors, u32 set_id, u32 binding_point) { if (m_sets[set_id].m_descriptor_slots[binding_point] == image_descriptors) { @@ -479,7 +480,7 @@ namespace vk writer.descriptorCount = 1; writer.descriptorType = type; - if (auto ptr = std::get_if(&slot)) + if (auto ptr = std::get_if(&slot)) { m_descriptor_set.push(*ptr, type, idx); return; @@ -530,7 +531,7 @@ namespace vk { const auto& slot = m_descriptor_slots[idx]; const VkDescriptorType type = m_descriptor_types[idx]; - if (auto ptr = std::get_if(&slot)) + if (auto ptr = std::get_if(&slot)) { m_descriptor_template[idx].pImageInfo = m_descriptor_set.store(*ptr); return; @@ -690,7 +691,7 @@ namespace vk void descriptor_table_t::create_descriptor_pool() { m_descriptor_pool = std::make_unique(); - m_descriptor_pool->create(*vk::get_current_renderer(), m_descriptor_pool_sizes); + m_descriptor_pool->create(*vk::g_render_device, m_descriptor_pool_sizes); } void descriptor_table_t::validate() const diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index f4c5784cfb..425069a0c4 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -4,6 +4,7 @@ #include "Emu/RSX/Program/GLSLTypes.h" #include "vkutils/descriptors.h" +#include "vkutils/ex.h" #include #include @@ -113,8 +114,8 @@ namespace vk VkShaderModule get_handle() const; }; - using descriptor_image_array_t = rsx::simple_array; - using descriptor_slot_t = std::variant; + using descriptor_image_array_t = rsx::simple_array; + using descriptor_slot_t = std::variant; struct descriptor_table_t { @@ -200,12 +201,12 @@ namespace vk bool has_uniform(program_input_type type, const std::string &uniform_name); std::pair get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name); - void bind_uniform(const VkDescriptorImageInfo &image_descriptor, u32 set_id, u32 binding_point); + void bind_uniform(const VkDescriptorImageInfoEx& image_descriptor, u32 set_id, u32 binding_point); void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point); void bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point); void bind_uniform(const VkBufferView &buffer_view, ::glsl::program_domain domain, program_input_type type, const std::string &binding_name); - void bind_uniform_array(const std::span& image_descriptors,u32 set_id, u32 binding_point); + void bind_uniform_array(const std::span& image_descriptors,u32 set_id, u32 binding_point); inline VkPipelineLayout layout() const { return m_pipeline_layout; } inline VkPipeline value() const { return m_pipeline; } diff --git a/rpcs3/Emu/RSX/VK/VKResolveHelper.h b/rpcs3/Emu/RSX/VK/VKResolveHelper.h index 23d243b032..550c52da2a 100644 --- a/rpcs3/Emu/RSX/VK/VKResolveHelper.h +++ b/rpcs3/Emu/RSX/VK/VKResolveHelper.h @@ -55,8 +55,8 @@ namespace vk { auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED)); auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY)); - m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, 0, 0); - m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, 0, 1); + m_program->bind_uniform({ *msaa_view }, 0, 0); + m_program->bind_uniform({ *resolved_view }, 0, 1); } void run(const vk::command_buffer& cmd, vk::viewable_image* msaa_image, vk::viewable_image* resolve_image) diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index e37e7745b5..083c3f8c7f 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -433,7 +433,7 @@ namespace vk return program.release(); } - void shader_interpreter::update_fragment_textures(const std::array& sampled_images) + void shader_interpreter::update_fragment_textures(const std::array& sampled_images) { // FIXME: Cannot use m_fragment_textures.start now since each interpreter has its own binding layout auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "sampler1D_array[16]"); @@ -442,7 +442,7 @@ namespace vk return; } - const VkDescriptorImageInfo* texture_ptr = sampled_images.data(); + const VkDescriptorImageInfoEx* texture_ptr = sampled_images.data(); for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16) { m_current_interpreter->bind_uniform_array({ texture_ptr, 16 }, set, binding); diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h index ff83be6245..840ae9b969 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h @@ -85,6 +85,6 @@ namespace vk u32 get_vertex_instruction_location() const; u32 get_fragment_instruction_location() const; - void update_fragment_textures(const std::array& sampled_images); + void update_fragment_textures(const std::array& sampled_images); }; } diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp index dc6562289e..869dba6fa9 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp @@ -108,8 +108,8 @@ namespace vk VK_FALSE, 0.f, 1.f, 0.f, 0.f, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); } - m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, 0, 0); - m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, 0, 1); + m_program->bind_uniform({ *m_input_image, *m_sampler }, 0, 0); + m_program->bind_uniform({ *m_output_image }, 0, 1); } void fsr_pass::run(const vk::command_buffer& cmd, vk::viewable_image* src, vk::viewable_image* dst, const size2u& input_size, const size2u& output_size) diff --git a/rpcs3/Emu/RSX/VK/vkutils/ex.cpp b/rpcs3/Emu/RSX/VK/vkutils/ex.cpp new file mode 100644 index 0000000000..1e4b68c904 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/ex.cpp @@ -0,0 +1,26 @@ +#include "ex.h" +#include "image.h" +#include "sampler.h" + +namespace vk +{ + VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view, const vk::sampler& sampler, VkImageLayout layout) + : VkDescriptorImageInfo(sampler.value, view.value, layout) + , resourceId(view.image()->id()) + {} + + VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view, const vk::sampler& sampler) + : VkDescriptorImageInfo(sampler.value, view.value, view.image()->current_layout) + , resourceId(view.image()->id()) + {} + + VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view, VkSampler sampler) + : VkDescriptorImageInfo(sampler, view.value, view.image()->current_layout) + , resourceId(view.image()->id()) + {} + + VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view) + : VkDescriptorImageInfo(VK_NULL_HANDLE, view.value, view.image()->current_layout) + , resourceId(view.image()->id()) + {} +} diff --git a/rpcs3/Emu/RSX/VK/vkutils/ex.h b/rpcs3/Emu/RSX/VK/vkutils/ex.h new file mode 100644 index 0000000000..ee49e7bc55 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/ex.h @@ -0,0 +1,27 @@ +#pragma once + +#include "../VulkanAPI.h" + +// Custom extensions to vulkan core +namespace vk +{ + struct image_view; + struct sampler; + + // VkImage and VkImageView can be reused by drivers and are not safe for identity checking. + // NVIDIA driver will crash horribly if such a thing happens, so we use our own resourceId field to uniquely identify an image and its descendants such as image views. + struct VkDescriptorImageInfoEx : public VkDescriptorImageInfo + { + u64 resourceId = 0ull; + + VkDescriptorImageInfoEx() = default; + VkDescriptorImageInfoEx(const vk::image_view& view, const vk::sampler& sampler, VkImageLayout layout); + VkDescriptorImageInfoEx(const vk::image_view& view, const vk::sampler& sampler); + VkDescriptorImageInfoEx(const vk::image_view& view, VkSampler sampler); + VkDescriptorImageInfoEx(const vk::image_view& view); + }; +} + +// Re-export +using VkDescriptorImageInfoEx = vk::VkDescriptorImageInfoEx; + diff --git a/rpcs3/Emu/RSX/VK/vkutils/image.cpp b/rpcs3/Emu/RSX/VK/vkutils/image.cpp index 1aa90648ce..65ab7f9f16 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/image.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/image.cpp @@ -3,12 +3,15 @@ #include "device.h" #include "image.h" #include "image_helpers.h" +#include "sampler.h" #include "../VKResourceManager.h" #include namespace vk { + static atomic_t s_image_uid_counter = 0; + void image::validate(const vk::render_device& dev, const VkImageCreateInfo& info) const { const auto& gpu_limits = dev.gpu().get_limits(); @@ -118,6 +121,8 @@ namespace vk CHECK_RESULT(vkCreateImage(m_device, &info, nullptr, &value)); + m_uid = s_image_uid_counter++; + VkMemoryRequirements memory_req; vkGetImageMemoryRequirements(m_device, value, &memory_req); diff --git a/rpcs3/Emu/RSX/VK/vkutils/image.h b/rpcs3/Emu/RSX/VK/vkutils/image.h index a37c7676b4..d7ec263f17 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/image.h +++ b/rpcs3/Emu/RSX/VK/vkutils/image.h @@ -67,6 +67,10 @@ namespace vk image(const image&) = delete; image(image&&) = delete; + // Identifiers + u64 id() const { return m_uid; } + VkImage handle() const { return value; } + // Properties u32 width() const; u32 height() const; @@ -94,7 +98,8 @@ namespace vk void set_debug_name(const std::string& name); protected: - VkDevice m_device; + VkDevice m_device = VK_NULL_HANDLE; + u64 m_uid = 0ull; }; struct image_view diff --git a/rpcs3/VKGSRender.vcxproj b/rpcs3/VKGSRender.vcxproj index 65420231f3..b964e282c1 100644 --- a/rpcs3/VKGSRender.vcxproj +++ b/rpcs3/VKGSRender.vcxproj @@ -46,6 +46,7 @@ + @@ -100,6 +101,7 @@ + @@ -163,4 +165,4 @@ - + \ No newline at end of file diff --git a/rpcs3/VKGSRender.vcxproj.filters b/rpcs3/VKGSRender.vcxproj.filters index 0d4db62e53..143da9a07b 100644 --- a/rpcs3/VKGSRender.vcxproj.filters +++ b/rpcs3/VKGSRender.vcxproj.filters @@ -81,6 +81,9 @@ vkutils + + vkutils + @@ -200,6 +203,9 @@ vkutils + + vkutils +