From e29cd4cc9311ec8c7f4eafe962f4ebef75ed7eba Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Feb 2026 20:57:16 +0300 Subject: [PATCH] gl: Implement SNORM and SRGB format overrides --- rpcs3/Emu/RSX/GL/GLDraw.cpp | 47 +++++++++++++++++++++++++++++----- rpcs3/Emu/RSX/GL/GLTexture.cpp | 38 +++++++++++++++++++++++++++ rpcs3/Emu/RSX/GL/GLTexture.h | 2 ++ 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLDraw.cpp b/rpcs3/Emu/RSX/GL/GLDraw.cpp index b167ab24c2..c564adfa20 100644 --- a/rpcs3/Emu/RSX/GL/GLDraw.cpp +++ b/rpcs3/Emu/RSX/GL/GLDraw.cpp @@ -334,17 +334,52 @@ void GLGSRender::load_texture_env() continue; } + if (!is_sampler_dirty) + { + if (sampler_state->format_class != previous_format_class) + { + // Host details changed but RSX is not aware + m_graphics_state |= rsx::fragment_program_state_dirty; + } + + if (m_fs_sampler_states[i]) + { + // Nothing to change, use cached sampler + continue; + } + } + sampler_state->format_ex = tex.format_ex(); - if (is_sampler_dirty) + if (sampler_state->format_ex.texel_remap_control && + sampler_state->image_handle && + sampler_state->upload_context == rsx::texture_upload_context::shader_read) [[ unlikely ]] { - m_fs_sampler_states[i].apply(tex, fs_sampler_state[i].get()); - } - else if (sampler_state->format_class != previous_format_class) - { - m_graphics_state |= rsx::fragment_program_state_dirty; + // Check if we need to override the view format + const auto gl_format = sampler_state->image_handle->view_format(); + GLenum format_override = gl_format; + rsx::flags32_t flags_to_erase = 0u; + + if (sampler_state->format_ex.hw_SNORM_possible()) + { + format_override = gl::get_compatible_snorm_format(gl_format); + flags_to_erase = rsx::texture_control_bits::SEXT_MASK; + } + else if (sampler_state->format_ex.hw_SRGB_possible()) + { + format_override = gl::get_compatible_srgb_format(gl_format); + flags_to_erase = rsx::texture_control_bits::GAMMA_CTRL_MASK; + } + + if (format_override != GL_NONE && format_override != gl_format) + { + sampler_state->image_handle = sampler_state->image_handle->as(format_override); + sampler_state->format_ex.texel_remap_control &= (~flags_to_erase); + } } + m_fs_sampler_states[i].apply(tex, fs_sampler_state[i].get()); + const auto texture_format = sampler_state->format_ex.format(); // Depth format redirected to BGRA8 resample stage. Do not filter to avoid bits leaking. // If accurate graphics are desired, force a bitcast to COLOR as a workaround. diff --git a/rpcs3/Emu/RSX/GL/GLTexture.cpp b/rpcs3/Emu/RSX/GL/GLTexture.cpp index 9a439177f4..181e5058c8 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.cpp +++ b/rpcs3/Emu/RSX/GL/GLTexture.cpp @@ -266,6 +266,44 @@ namespace gl fmt::throw_exception("Unknown format 0x%x", texture_format); } + GLenum get_compatible_snorm_format(GLenum base_format) + { + switch (base_format) + { + case GL_R8: + return GL_R8_SNORM; + case GL_RG8: + return GL_RG8_SNORM; + case GL_RGBA8: + return GL_RGBA8_SNORM; + case GL_R16: + return GL_R16_SNORM; + case GL_RG16: + return GL_RG16_SNORM; + case GL_RGBA16: + return GL_RGBA16_SNORM; + default: + return GL_NONE; + } + } + + GLenum get_compatible_srgb_format(GLenum base_format) + { + switch (base_format) + { + case GL_RGBA8: + return GL_SRGB8_ALPHA8_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + default: + return GL_NONE; + } + } + cs_shuffle_base* get_trivial_transform_job(const pixel_buffer_layout& pack_info) { if (!pack_info.swap_bytes) diff --git a/rpcs3/Emu/RSX/GL/GLTexture.h b/rpcs3/Emu/RSX/GL/GLTexture.h index dc6d90098a..10c26dc536 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.h +++ b/rpcs3/Emu/RSX/GL/GLTexture.h @@ -62,6 +62,8 @@ namespace gl std::tuple get_format_type(u32 texture_format); pixel_buffer_layout get_format_type(texture::internal_format format); std::array get_swizzle_remap(u32 texture_format); + GLenum get_compatible_snorm_format(GLenum base_format); + GLenum get_compatible_srgb_format(GLenum base_format); viewable_image* create_texture(u32 gcm_format, u16 width, u16 height, u16 depth, u16 mipmaps, rsx::texture_dimension_extended type);