diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index 628504929f..e5aadb09bf 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -1572,4 +1572,25 @@ namespace rsx return true; } } + + bool is_border_clamped_texture( + rsx::texture_wrap_mode wrap_s, + rsx::texture_wrap_mode wrap_t, + rsx::texture_wrap_mode wrap_r, + rsx::texture_dimension dimension) + { + // Technically we should check border and mirror_once_border + // However, the latter is not implemented in any modern API, so we can just ignore it (emulated with mirror_once_clamp). + switch (dimension) + { + case rsx::texture_dimension::dimension1d: + return wrap_s == rsx::texture_wrap_mode::border; + case rsx::texture_dimension::dimension2d: + return wrap_s == rsx::texture_wrap_mode::border || wrap_t == rsx::texture_wrap_mode::border; + case rsx::texture_dimension::dimension3d: + return wrap_s == rsx::texture_wrap_mode::border || wrap_t == rsx::texture_wrap_mode::border || wrap_r == rsx::texture_wrap_mode::border; + default: + return false; + } + } } diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.h b/rpcs3/Emu/RSX/Common/TextureUtils.h index 718d4e2d34..0481ded4f2 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.h +++ b/rpcs3/Emu/RSX/Common/TextureUtils.h @@ -289,4 +289,11 @@ namespace rsx format_class classify_format(u32 gcm_format); bool is_texcoord_wrapping_mode(rsx::texture_wrap_mode mode); + bool is_border_clamped_texture(rsx::texture_wrap_mode wrap_s, rsx::texture_wrap_mode wrap_t, rsx::texture_wrap_mode wrap_r, rsx::texture_dimension dimension); + + template + bool is_border_clamped_texture(const TextureType& tex) + { + return is_border_clamped_texture(tex.wrap_s(), tex.wrap_t(), tex.wrap_r(), tex.dimension()); + } } diff --git a/rpcs3/Emu/RSX/GL/glutils/sampler.cpp b/rpcs3/Emu/RSX/GL/glutils/sampler.cpp index 57f505a89d..6ff60b6f95 100644 --- a/rpcs3/Emu/RSX/GL/glutils/sampler.cpp +++ b/rpcs3/Emu/RSX/GL/glutils/sampler.cpp @@ -79,13 +79,15 @@ namespace gl set_parameteri(GL_TEXTURE_WRAP_T, wrap_mode(tex.wrap_t())); set_parameteri(GL_TEXTURE_WRAP_R, wrap_mode(tex.wrap_r())); - if (const auto color = tex.border_color(); - get_parameteri(GL_TEXTURE_BORDER_COLOR) != color) + if (rsx::is_border_clamped_texture(tex)) { - m_propertiesi[GL_TEXTURE_BORDER_COLOR] = color; - - const color4f border_color = rsx::decode_border_color(color); - glSamplerParameterfv(sampler_handle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); + const auto border_color = tex.remapped_border_color(); + const auto encoded_color = rsx::encode_color_to_storage_key(border_color); + if (get_parameteri(GL_TEXTURE_BORDER_COLOR) != encoded_color) + { + m_propertiesi[GL_TEXTURE_BORDER_COLOR] = encoded_color; + glSamplerParameterfv(sampler_handle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); + } } if (sampled_image->upload_context != rsx::texture_upload_context::shader_read || @@ -150,13 +152,15 @@ namespace gl void sampler_state::apply(const rsx::vertex_texture& tex, const rsx::sampled_image_descriptor_base* /*sampled_image*/) { - if (const auto color = tex.border_color(); - get_parameteri(GL_TEXTURE_BORDER_COLOR) != color) + if (rsx::is_border_clamped_texture(tex)) { - m_propertiesi[GL_TEXTURE_BORDER_COLOR] = color; - - const color4f border_color = rsx::decode_border_color(color); - glSamplerParameterfv(sampler_handle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); + const auto border_color = tex.remapped_border_color(); + const auto encoded_color = rsx::encode_color_to_storage_key(border_color); + if (get_parameteri(GL_TEXTURE_BORDER_COLOR) != encoded_color) + { + m_propertiesi[GL_TEXTURE_BORDER_COLOR] = encoded_color; + glSamplerParameterfv(sampler_handle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); + } } set_parameteri(GL_TEXTURE_WRAP_S, wrap_mode(tex.wrap_s())); diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 8bb11d3fb2..fd23d0fb8d 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -303,7 +303,9 @@ void VKGSRender::load_texture_env() const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s()); const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t()); const auto wrap_r = vk::vk_wrap_mode(tex.wrap_r()); - const auto border_color = vk::border_color_t(tex.border_color()); + const auto border_color = rsx::is_border_clamped_texture(tex) + ? vk::border_color_t(tex.remapped_border_color()) + : vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); // Check if non-point filtering can even be used on this format bool can_sample_linear; @@ -441,11 +443,16 @@ void VKGSRender::load_texture_env() const VkBool32 unnormalized_coords = !!(tex.format() & CELL_GCM_TEXTURE_UN); const auto min_lod = tex.min_lod(); const auto max_lod = tex.max_lod(); - const auto border_color = vk::border_color_t(tex.border_color()); + const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s()); + const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t()); + + const auto border_color = is_border_clamped_texture(tex) + ? vk::border_color_t(tex.remapped_border_color()) + : vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); if (vs_sampler_handles[i]) { - if (!vs_sampler_handles[i]->matches(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, + if (!vs_sampler_handles[i]->matches(wrap_s, wrap_t, VK_SAMPLER_ADDRESS_MODE_REPEAT, unnormalized_coords, 0.f, 1.f, min_lod, max_lod, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, border_color)) { replace = true; @@ -457,7 +464,7 @@ void VKGSRender::load_texture_env() vs_sampler_handles[i] = vk::get_resource_manager()->get_sampler( *m_device, vs_sampler_handles[i], - VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, + wrap_s, wrap_t, VK_SAMPLER_ADDRESS_MODE_REPEAT, unnormalized_coords, 0.f, 1.f, min_lod, max_lod, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, border_color); diff --git a/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp b/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp index c6bf83cdec..9127afcc4e 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp @@ -1,5 +1,6 @@ #include "memory.h" #include "sampler.h" +#include "../../color_utils.h" #include "../../rsx_utils.h" namespace vk @@ -20,9 +21,10 @@ namespace vk return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; } - border_color_t::border_color_t(u32 encoded_color, VkFormat fmt, VkImageAspectFlags aspect) - : storage_key(0), format(fmt), aspect(aspect) + border_color_t::border_color_t(const color4f& color, VkFormat fmt, VkImageAspectFlags aspect) + : format(fmt), aspect(aspect), color_value(color) { + const auto encoded_color = rsx::encode_color_to_storage_key(color); value = vk::get_border_color(encoded_color); if (value != VK_BORDER_COLOR_FLOAT_CUSTOM_EXT) @@ -31,7 +33,6 @@ namespace vk return; } - color_value = rsx::decode_border_color(encoded_color); if (!g_render_device->get_custom_border_color_support()) { value = get_closest_border_color_enum(color_value); diff --git a/rpcs3/Emu/RSX/VK/vkutils/sampler.h b/rpcs3/Emu/RSX/VK/vkutils/sampler.h index 182fdb0b27..f1d81d542f 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/sampler.h +++ b/rpcs3/Emu/RSX/VK/vkutils/sampler.h @@ -13,7 +13,7 @@ namespace vk VkImageCreateFlags aspect; color4f color_value; - border_color_t(u32 encoded_color, VkFormat fmt = VK_FORMAT_UNDEFINED, VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT); + border_color_t(const color4f& color, VkFormat fmt = VK_FORMAT_UNDEFINED, VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT); border_color_t(VkBorderColor color); diff --git a/rpcs3/Emu/RSX/color_utils.h b/rpcs3/Emu/RSX/color_utils.h index c052c2aacc..389c6b7d4b 100644 --- a/rpcs3/Emu/RSX/color_utils.h +++ b/rpcs3/Emu/RSX/color_utils.h @@ -201,6 +201,16 @@ namespace rsx return result; } + static inline u32 encode_color_to_storage_key(color4f color) + { + const u32 r = static_cast(color.r * 255); + const u32 g = static_cast(color.g * 255); + const u32 b = static_cast(color.b * 255); + const u32 a = static_cast(color.a * 255); + + return (a << 24) | (b << 16) | (g << 8) | r; + } + static inline const std::array get_write_output_mask(rsx::surface_color_format format) { constexpr std::array rgba = { true, true, true, true };