vk: Uniquely identify images using a monotonic incrementing counter
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.6, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.6, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.6, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.6, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, .ci/build-mac.sh, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, .ci/build-mac-arm64.sh, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang (win64, clang, clang64) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run

This commit is contained in:
kd-11 2025-10-12 03:52:49 +03:00 committed by kd-11
parent 878bb12a72
commit 1cae72c872
15 changed files with 113 additions and 35 deletions

View file

@ -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

View file

@ -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<VkDescriptorImageInfo, 68> 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<VkDescriptorImageInfoEx, 68> 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<u32>(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] };
}
}

View file

@ -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);

View file

@ -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<VkDescriptorImageInfo>(&a);
const auto ptr = std::get_if<VkDescriptorImageInfoEx>(&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<const VkDescriptorImageInfo>& b)
bool operator == (const descriptor_slot_t& a, const std::span<const VkDescriptorImageInfoEx>& b)
{
const auto ptr = std::get_if<descriptor_image_array_t>(&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<const VkDescriptorImageInfo>& image_descriptors, u32 set_id, u32 binding_point)
void program::bind_uniform_array(const std::span<const VkDescriptorImageInfoEx>& 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<VkDescriptorImageInfo>(&slot))
if (auto ptr = std::get_if<VkDescriptorImageInfoEx>(&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<VkDescriptorImageInfo>(&slot))
if (auto ptr = std::get_if<VkDescriptorImageInfoEx>(&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<descriptor_pool>();
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

View file

@ -4,6 +4,7 @@
#include "Emu/RSX/Program/GLSLTypes.h"
#include "vkutils/descriptors.h"
#include "vkutils/ex.h"
#include <string>
#include <vector>
@ -113,8 +114,8 @@ namespace vk
VkShaderModule get_handle() const;
};
using descriptor_image_array_t = rsx::simple_array<VkDescriptorImageInfo>;
using descriptor_slot_t = std::variant<VkDescriptorImageInfo, VkDescriptorBufferInfo, VkBufferView, descriptor_image_array_t>;
using descriptor_image_array_t = rsx::simple_array<VkDescriptorImageInfoEx>;
using descriptor_slot_t = std::variant<VkDescriptorImageInfoEx, VkDescriptorBufferInfo, VkBufferView, descriptor_image_array_t>;
struct descriptor_table_t
{
@ -200,12 +201,12 @@ namespace vk
bool has_uniform(program_input_type type, const std::string &uniform_name);
std::pair<u32, u32> 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<const VkDescriptorImageInfo>& image_descriptors,u32 set_id, u32 binding_point);
void bind_uniform_array(const std::span<const VkDescriptorImageInfoEx>& image_descriptors,u32 set_id, u32 binding_point);
inline VkPipelineLayout layout() const { return m_pipeline_layout; }
inline VkPipeline value() const { return m_pipeline; }

View file

@ -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)

View file

@ -433,7 +433,7 @@ namespace vk
return program.release();
}
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images)
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfoEx, 68>& 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);

View file

@ -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<VkDescriptorImageInfo, 68>& sampled_images);
void update_fragment_textures(const std::array<VkDescriptorImageInfoEx, 68>& sampled_images);
};
}

View file

@ -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)

View file

@ -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())
{}
}

View file

@ -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;

View file

@ -3,12 +3,15 @@
#include "device.h"
#include "image.h"
#include "image_helpers.h"
#include "sampler.h"
#include "../VKResourceManager.h"
#include <memory>
namespace vk
{
static atomic_t<u64> 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);

View file

@ -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

View file

@ -46,6 +46,7 @@
<ClInclude Include="Emu\RSX\VK\vkutils\data_heap.h" />
<ClInclude Include="Emu\RSX\VK\vkutils\descriptors.h" />
<ClInclude Include="Emu\RSX\VK\vkutils\barriers.h" />
<ClInclude Include="Emu\RSX\VK\vkutils\ex.h" />
<ClInclude Include="Emu\RSX\VK\vkutils\framebuffer_object.hpp" />
<ClInclude Include="Emu\RSX\VK\vkutils\garbage_collector.h" />
<ClInclude Include="Emu\RSX\VK\vkutils\image.h" />
@ -100,6 +101,7 @@
<ClCompile Include="Emu\RSX\VK\vkutils\chip_class.cpp" />
<ClCompile Include="Emu\RSX\VK\vkutils\commands.cpp" />
<ClCompile Include="Emu\RSX\VK\vkutils\data_heap.cpp" />
<ClCompile Include="Emu\RSX\VK\vkutils\ex.cpp" />
<ClCompile Include="Emu\RSX\VK\vkutils\image.cpp" />
<ClCompile Include="Emu\RSX\VK\vkutils\image_helpers.cpp" />
<ClCompile Include="Emu\RSX\VK\vkutils\instance.cpp" />

View file

@ -81,6 +81,9 @@
<ClCompile Include="Emu\RSX\VK\vkutils\swapchain.cpp">
<Filter>vkutils</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\VK\vkutils\ex.cpp">
<Filter>vkutils</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\RSX\VK\VKCommonDecompiler.h" />
@ -200,6 +203,9 @@
<Filter>vkutils</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\VK\VKProcTable.h" />
<ClInclude Include="Emu\RSX\VK\vkutils\ex.h">
<Filter>vkutils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="vkutils">