From 8bba84a4014e1bf204089ff7dbcaa73917f84738 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 24 May 2020 17:57:54 -0300 Subject: [PATCH] texture_cache: Implement depth stencil texture swizzles Stop ignoring image swizzles on depth and stencil images. This doesn't fix a known issue on Xenoblade Chronicles 2 where an OpenGL texture changes swizzles twice before being used. A proper fix would be having a small texture view cache for this like we do on Vulkan. --- .../renderer_opengl/gl_texture_cache.cpp | 39 +++++++++++++------ .../renderer_opengl/gl_texture_cache.h | 10 +---- .../renderer_vulkan/vk_texture_cache.cpp | 29 +++++++------- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 94fbd2a22..7e0ffe3cd 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -238,6 +238,12 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte return texture; } +constexpr u32 EncodeSwizzle(SwizzleSource x_source, SwizzleSource y_source, SwizzleSource z_source, + SwizzleSource w_source) { + return (static_cast(x_source) << 24) | (static_cast(y_source) << 16) | + (static_cast(z_source) << 8) | static_cast(w_source); +} + } // Anonymous namespace CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, @@ -404,7 +410,8 @@ CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, const ViewParams& p if (!is_proxy) { texture_view = CreateTextureView(); } - swizzle = EncodeSwizzle(SwizzleSource::R, SwizzleSource::G, SwizzleSource::B, SwizzleSource::A); + current_swizzle = + EncodeSwizzle(SwizzleSource::R, SwizzleSource::G, SwizzleSource::B, SwizzleSource::A); } CachedSurfaceView::~CachedSurfaceView() = default; @@ -449,25 +456,35 @@ void CachedSurfaceView::Attach(GLenum attachment, GLenum target) const { void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_source, SwizzleSource z_source, SwizzleSource w_source) { - u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); - if (new_swizzle == swizzle) + const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); + if (current_swizzle == new_swizzle) { return; - swizzle = new_swizzle; - const std::array gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source), - GetSwizzleSource(z_source), GetSwizzleSource(w_source)}; + } + current_swizzle = new_swizzle; + + std::array swizzle{x_source, y_source, z_source, w_source}; + const GLuint handle = GetTexture(); - const PixelFormat format = surface.GetSurfaceParams().pixel_format; - switch (format) { + switch (const PixelFormat format = surface.GetSurfaceParams().pixel_format) { + case PixelFormat::S8Z24: case PixelFormat::Z24S8: case PixelFormat::Z32FS8: - case PixelFormat::S8Z24: + UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE, GetComponent(format, x_source == SwizzleSource::R)); - break; - default: + + // Make sure we sample the first component + std::transform(swizzle.begin(), swizzle.end(), swizzle.begin(), [](SwizzleSource value) { + return value == SwizzleSource::G ? SwizzleSource::R : value; + }); + [[fallthrough]]; + default: { + const std::array gl_swizzle = {GetSwizzleSource(swizzle[0]), GetSwizzleSource(swizzle[1]), + GetSwizzleSource(swizzle[2]), GetSwizzleSource(swizzle[3])}; glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); break; } + } } OGLTextureView CachedSurfaceView::CreateTextureView() const { diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 02d9981a1..0d88d738f 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -110,14 +110,6 @@ public: } private: - u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, - Tegra::Texture::SwizzleSource y_source, - Tegra::Texture::SwizzleSource z_source, - Tegra::Texture::SwizzleSource w_source) const { - return (static_cast(x_source) << 24) | (static_cast(y_source) << 16) | - (static_cast(z_source) << 8) | static_cast(w_source); - } - OGLTextureView CreateTextureView() const; CachedSurface& surface; @@ -125,7 +117,7 @@ private: GLenum format{}; OGLTextureView texture_view; - u32 swizzle{}; + u32 current_swizzle{}; bool is_proxy{}; }; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 55f43e61b..2f1d5021d 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -354,26 +354,23 @@ CachedSurfaceView::~CachedSurfaceView() = default; VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y_source, SwizzleSource z_source, SwizzleSource w_source) { - const u32 swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); - if (last_image_view && last_swizzle == swizzle) { + const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); + if (last_image_view && last_swizzle == new_swizzle) { return last_image_view; } - last_swizzle = swizzle; + last_swizzle = new_swizzle; - const auto [entry, is_cache_miss] = view_cache.try_emplace(swizzle); + const auto [entry, is_cache_miss] = view_cache.try_emplace(new_swizzle); auto& image_view = entry->second; if (!is_cache_miss) { return last_image_view = *image_view; } - auto swizzle_x = MaxwellToVK::SwizzleSource(x_source); - auto swizzle_y = MaxwellToVK::SwizzleSource(y_source); - auto swizzle_z = MaxwellToVK::SwizzleSource(z_source); - auto swizzle_w = MaxwellToVK::SwizzleSource(w_source); - + std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), + MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)}; if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) { // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here. - std::swap(swizzle_x, swizzle_z); + std::swap(swizzle[0], swizzle[2]); } // Games can sample depth or stencil values on textures. This is decided by the swizzle value on @@ -395,11 +392,11 @@ VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y UNIMPLEMENTED(); } - // Vulkan doesn't seem to understand swizzling of a depth stencil image, use identity - swizzle_x = VK_COMPONENT_SWIZZLE_R; - swizzle_y = VK_COMPONENT_SWIZZLE_G; - swizzle_z = VK_COMPONENT_SWIZZLE_B; - swizzle_w = VK_COMPONENT_SWIZZLE_A; + // Make sure we sample the first component + std::transform( + swizzle.begin(), swizzle.end(), swizzle.begin(), [](VkComponentSwizzle component) { + return component == VK_COMPONENT_SWIZZLE_G ? VK_COMPONENT_SWIZZLE_R : component; + }); } VkImageViewCreateInfo ci; @@ -409,7 +406,7 @@ VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y ci.image = surface.GetImageHandle(); ci.viewType = image_view_type; ci.format = surface.GetImage().GetFormat(); - ci.components = {swizzle_x, swizzle_y, swizzle_z, swizzle_w}; + ci.components = {swizzle[0], swizzle[1], swizzle[2], swizzle[3]}; ci.subresourceRange.aspectMask = aspect; ci.subresourceRange.baseMipLevel = base_level; ci.subresourceRange.levelCount = num_levels;