From ac86076b8347b2a3a3477ef6cc661f55adf13c21 Mon Sep 17 00:00:00 2001 From: Lolothepro <68275908+Lolothepro@users.noreply.github.com> Date: Thu, 14 May 2026 11:31:56 +0200 Subject: [PATCH] Use SSBOs instead of UBOs to workaround corruption issues with certain drivers. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 13 ++++++++----- src/video_core/renderer_opengl/gl_rasterizer.h | 1 + src/video_core/renderer_vulkan/vk_instance.h | 4 ++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 13 +++++++++---- src/video_core/shader/generator/glsl_shader_gen.cpp | 4 ++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 2f15dec9c..688dc455d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -101,12 +101,14 @@ RasterizerOpenGL::RasterizerOpenGL(Memory::MemorySystem& memory, Pica::PicaCore& hw_vao.Create(); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); + glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &ssbo_buffer_alignment); + const GLint max_alignment = std::max(uniform_buffer_alignment, ssbo_buffer_alignment); uniform_size_aligned_vs_pica = - Common::AlignUp(sizeof(VSPicaUniformData), uniform_buffer_alignment); + Common::AlignUp(sizeof(VSPicaUniformData), max_alignment); uniform_size_aligned_vs = - Common::AlignUp(sizeof(VSUniformData), uniform_buffer_alignment); + Common::AlignUp(sizeof(VSUniformData), max_alignment); uniform_size_aligned_fs = - Common::AlignUp(sizeof(FSUniformData), uniform_buffer_alignment); + Common::AlignUp(sizeof(FSUniformData), max_alignment); // Set vertex attributes for software shader path state.draw.vertex_array = sw_vao.handle; @@ -1005,8 +1007,9 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw) { uniform_size_aligned_vs_pica + uniform_size_aligned_vs + uniform_size_aligned_fs; std::size_t used_bytes = 0; + const GLint max_alignment = std::max(uniform_buffer_alignment, ssbo_buffer_alignment); const auto [uniforms, offset, invalidate] = - uniform_buffer.Map(uniform_size, uniform_buffer_alignment); + uniform_buffer.Map(uniform_size, max_alignment); if (vs_data_dirty || invalidate) { std::memcpy(uniforms + used_bytes, &vs_data, sizeof(vs_data)); @@ -1028,7 +1031,7 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw) { VSPicaUniformData vs_uniforms; vs_uniforms.SetFromRegs(pica.vs_setup); std::memcpy(uniforms + used_bytes, &vs_uniforms, sizeof(vs_uniforms)); - glBindBufferRange(GL_UNIFORM_BUFFER, UniformBindings::VSPicaData, + glBindBufferRange(GL_SHADER_STORAGE_BUFFER, UniformBindings::VSPicaData, uniform_buffer.GetHandle(), offset + used_bytes, sizeof(vs_uniforms)); pica.vs_setup.uniforms_dirty = false; used_bytes += uniform_size_aligned_vs_pica; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b529a56b2..f45cc2665 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -121,6 +121,7 @@ private: OGLStreamBuffer texture_buffer; OGLStreamBuffer texture_lf_buffer; GLint uniform_buffer_alignment; + GLint ssbo_buffer_alignment; std::size_t uniform_size_aligned_vs_pica; std::size_t uniform_size_aligned_vs; std::size_t uniform_size_aligned_fs; diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index f6fbc28fb..da9cfa51c 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -231,6 +231,10 @@ public: return properties.limits.minUniformBufferOffsetAlignment; } + vk::DeviceSize StorageMinAlignment() const { + return properties.limits.minStorageBufferOffsetAlignment; + } + /// Returns the minimum alignemt required for accessing host-mapped device memory vk::DeviceSize NonCoherentAtomSize() const { return properties.limits.nonCoherentAtomSize; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index e61359acf..a6121ea6d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -57,7 +57,7 @@ AttribLoadFlags MakeAttribLoadFlag(Pica::PipelineRegs::VertexAttributeFormat for } constexpr std::array BUFFER_BINDINGS = {{ - {0, vk::DescriptorType::eUniformBufferDynamic, 1, vk::ShaderStageFlagBits::eVertex}, + {0, vk::DescriptorType::eStorageBufferDynamic, 1, vk::ShaderStageFlagBits::eVertex}, {1, vk::DescriptorType::eUniformBufferDynamic, 1, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eGeometry}, {2, vk::DescriptorType::eUniformBufferDynamic, 1, vk::ShaderStageFlagBits::eFragment}, diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 0f997d5e9..d275594cb 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -68,7 +68,9 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory, Pica::PicaCore& runtime{instance, scheduler, renderpass_cache, update_queue, image_count}, res_cache{memory, custom_tex_manager, runtime, regs, renderer}, stream_buffer{instance, scheduler, BUFFER_USAGE, STREAM_BUFFER_SIZE}, - uniform_buffer{instance, scheduler, vk::BufferUsageFlagBits::eUniformBuffer, + uniform_buffer{instance, scheduler, + vk::BufferUsageFlagBits::eUniformBuffer | + vk::BufferUsageFlagBits::eStorageBuffer, UNIFORM_BUFFER_SIZE}, texture_buffer{instance, scheduler, vk::BufferUsageFlagBits::eUniformTexelBuffer, TextureBufferSize(instance)}, @@ -78,10 +80,12 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory, Pica::PicaCore& vertex_buffers.fill(stream_buffer.Handle()); - // Query uniform buffer alignment. + // Query buffer alignments. + const vk::DeviceSize vs_pica_alignment = + std::max(instance.UniformMinAlignment(), instance.StorageMinAlignment()); uniform_buffer_alignment = instance.UniformMinAlignment(); uniform_size_aligned_vs_pica = - Common::AlignUp(sizeof(VSPicaUniformData), uniform_buffer_alignment); + Common::AlignUp(sizeof(VSPicaUniformData), vs_pica_alignment); uniform_size_aligned_vs = Common::AlignUp(sizeof(VSUniformData), uniform_buffer_alignment); uniform_size_aligned_fs = Common::AlignUp(sizeof(FSUniformData), uniform_buffer_alignment); @@ -113,7 +117,8 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory, Pica::PicaCore& // Prepare the static buffer descriptor set. const auto buffer_set = pipeline_cache.Acquire(DescriptorHeapType::Buffer); - update_queue.AddBuffer(buffer_set, 0, uniform_buffer.Handle(), 0, sizeof(VSPicaUniformData)); + update_queue.AddBuffer(buffer_set, 0, uniform_buffer.Handle(), 0, sizeof(VSPicaUniformData), + vk::DescriptorType::eStorageBufferDynamic); update_queue.AddBuffer(buffer_set, 1, uniform_buffer.Handle(), 0, sizeof(VSUniformData)); update_queue.AddBuffer(buffer_set, 2, uniform_buffer.Handle(), 0, sizeof(FSUniformData)); update_queue.AddTexelBuffer(buffer_set, 3, *texture_lf_view); diff --git a/src/video_core/shader/generator/glsl_shader_gen.cpp b/src/video_core/shader/generator/glsl_shader_gen.cpp index b537df375..703c2e396 100644 --- a/src/video_core/shader/generator/glsl_shader_gen.cpp +++ b/src/video_core/shader/generator/glsl_shader_gen.cpp @@ -16,9 +16,9 @@ namespace Pica::Shader::Generator::GLSL { constexpr std::string_view VSPicaUniformBlockDef = R"( #ifdef VULKAN -layout (set = 0, binding = 0, std140) uniform vs_pica_data { +layout (set = 0, binding = 0, std430) readonly buffer vs_pica_data { #else -layout (binding = 0, std140) uniform vs_pica_data { +layout (binding = 0, std430) readonly buffer vs_pica_data { #endif uint b; uvec4 i[4];