[vulkan] Fix Vulkan graphics pipeline crash when image descriptor count exceeds 64 (#3785)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3785
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
This commit is contained in:
wildcard 2026-03-31 04:49:20 +02:00 committed by crueter
parent 7a8176f63f
commit 0b179517b3
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
2 changed files with 21 additions and 13 deletions

View file

@ -49,7 +49,7 @@ using VideoCore::Surface::PixelFormatFromDepthFormat;
using VideoCore::Surface::PixelFormatFromRenderTargetFormat; using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
constexpr size_t NUM_STAGES = Maxwell::MaxShaderStage; constexpr size_t NUM_STAGES = Maxwell::MaxShaderStage;
constexpr size_t MAX_IMAGE_ELEMENTS = 64; constexpr size_t INLINE_IMAGE_ELEMENTS = 64;
DescriptorLayoutBuilder MakeBuilder(const Device& device, std::span<const Shader::Info> infos) { DescriptorLayoutBuilder MakeBuilder(const Device& device, std::span<const Shader::Info> infos) {
DescriptorLayoutBuilder builder{device}; DescriptorLayoutBuilder builder{device};
@ -264,7 +264,11 @@ GraphicsPipeline::GraphicsPipeline(
stage_infos[stage] = *info; stage_infos[stage] = *info;
enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask; enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask;
std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin()); std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin());
num_image_elements += Shader::NumDescriptors(info->texture_buffer_descriptors);
num_image_elements += Shader::NumDescriptors(info->image_buffer_descriptors);
num_textures += Shader::NumDescriptors(info->texture_descriptors); num_textures += Shader::NumDescriptors(info->texture_descriptors);
num_image_elements += Shader::NumDescriptors(info->texture_descriptors);
num_image_elements += Shader::NumDescriptors(info->image_descriptors);
} }
fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0]; fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0];
auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] { auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] {
@ -310,10 +314,10 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) {
template <typename Spec> template <typename Spec>
bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
std::array<VideoCommon::ImageViewInOut, MAX_IMAGE_ELEMENTS> views; small_vector<VideoCommon::ImageViewInOut, INLINE_IMAGE_ELEMENTS> views;
std::array<VideoCommon::SamplerId, MAX_IMAGE_ELEMENTS> samplers; small_vector<VideoCommon::SamplerId, INLINE_IMAGE_ELEMENTS> samplers;
size_t sampler_index{}; views.reserve(num_image_elements);
size_t view_index{}; samplers.reserve(num_textures);
texture_cache.SynchronizeGraphicsDescriptors(); texture_cache.SynchronizeGraphicsDescriptors();
@ -358,11 +362,11 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE { const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE {
for (u32 index = 0; index < desc.count; ++index) { for (u32 index = 0; index < desc.count; ++index) {
const auto handle{read_handle(desc, index)}; const auto handle{read_handle(desc, index)};
views[view_index++] = { views.push_back({
.index = handle.first, .index = handle.first,
.blacklist = blacklist, .blacklist = blacklist,
.id = {} .id = {}
}; });
} }
}}; }};
if constexpr (Spec::has_texture_buffers) { if constexpr (Spec::has_texture_buffers) {
@ -378,10 +382,10 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
for (const auto& desc : info.texture_descriptors) { for (const auto& desc : info.texture_descriptors) {
for (u32 index = 0; index < desc.count; ++index) { for (u32 index = 0; index < desc.count; ++index) {
const auto handle{read_handle(desc, index)}; const auto handle{read_handle(desc, index)};
views[view_index++] = {handle.first}; views.push_back({handle.first});
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)}; VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
samplers[sampler_index++] = sampler; samplers.push_back(sampler);
} }
} }
if constexpr (Spec::has_images) { if constexpr (Spec::has_images) {
@ -407,7 +411,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
if constexpr (Spec::enabled_stages[4]) { if constexpr (Spec::enabled_stages[4]) {
config_stage(4); config_stage(4);
} }
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), view_index)); ASSERT(views.size() == num_image_elements);
ASSERT(samplers.size() == num_textures);
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), views.size()));
VideoCommon::ImageViewInOut* texture_buffer_it{views.data()}; VideoCommon::ImageViewInOut* texture_buffer_it{views.data()};
const auto bind_stage_info{[&](size_t stage) LAMBDA_FORCEINLINE { const auto bind_stage_info{[&](size_t stage) LAMBDA_FORCEINLINE {
@ -501,7 +507,8 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
buffer_cache.any_buffer_uploaded = false; buffer_cache.any_buffer_uploaded = false;
} }
texture_cache.UpdateRenderTargets(false); texture_cache.UpdateRenderTargets(false);
texture_cache.CheckFeedbackLoop(views); texture_cache.CheckFeedbackLoop(std::span<const VideoCommon::ImageViewInOut>{views.data(),
views.size()});
ConfigureDraw(rescaling, render_area); ConfigureDraw(rescaling, render_area);
return true; return true;
@ -987,7 +994,7 @@ void GraphicsPipeline::Validate() {
num_images += Shader::NumDescriptors(info.texture_descriptors); num_images += Shader::NumDescriptors(info.texture_descriptors);
num_images += Shader::NumDescriptors(info.image_descriptors); num_images += Shader::NumDescriptors(info.image_descriptors);
} }
ASSERT(num_images <= MAX_IMAGE_ELEMENTS); ASSERT(num_images == num_image_elements);
} }
} // namespace Vulkan } // namespace Vulkan

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@ -159,6 +159,7 @@ private:
std::array<Shader::Info, NUM_STAGES> stage_infos; std::array<Shader::Info, NUM_STAGES> stage_infos;
std::array<u32, 5> enabled_uniform_buffer_masks{}; std::array<u32, 5> enabled_uniform_buffer_masks{};
VideoCommon::UniformBufferSizes uniform_buffer_sizes{}; VideoCommon::UniformBufferSizes uniform_buffer_sizes{};
size_t num_image_elements{};
u32 num_textures{}; u32 num_textures{};
bool fragment_has_color0_output{}; bool fragment_has_color0_output{};