diff options
| author | 2020-05-24 17:57:54 -0300 | |
|---|---|---|
| committer | 2020-05-26 17:44:50 -0300 | |
| commit | 8bba84a4014e1bf204089ff7dbcaa73917f84738 (patch) | |
| tree | 2775c6a219a18ff4ceed45e4954f6707d7fafd8b | |
| parent | Merge pull request #3978 from ReinUsesLisp/write-rz (diff) | |
| download | yuzu-8bba84a4014e1bf204089ff7dbcaa73917f84738.tar.gz yuzu-8bba84a4014e1bf204089ff7dbcaa73917f84738.tar.xz yuzu-8bba84a4014e1bf204089ff7dbcaa73917f84738.zip | |
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.
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 39 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 10 | ||||
| -rw-r--r-- | src/video_core/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 | |||
| 238 | return texture; | 238 | return texture; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | constexpr u32 EncodeSwizzle(SwizzleSource x_source, SwizzleSource y_source, SwizzleSource z_source, | ||
| 242 | SwizzleSource w_source) { | ||
| 243 | return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) | | ||
| 244 | (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source); | ||
| 245 | } | ||
| 246 | |||
| 241 | } // Anonymous namespace | 247 | } // Anonymous namespace |
| 242 | 248 | ||
| 243 | CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, | 249 | CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, |
| @@ -404,7 +410,8 @@ CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, const ViewParams& p | |||
| 404 | if (!is_proxy) { | 410 | if (!is_proxy) { |
| 405 | texture_view = CreateTextureView(); | 411 | texture_view = CreateTextureView(); |
| 406 | } | 412 | } |
| 407 | swizzle = EncodeSwizzle(SwizzleSource::R, SwizzleSource::G, SwizzleSource::B, SwizzleSource::A); | 413 | current_swizzle = |
| 414 | EncodeSwizzle(SwizzleSource::R, SwizzleSource::G, SwizzleSource::B, SwizzleSource::A); | ||
| 408 | } | 415 | } |
| 409 | 416 | ||
| 410 | CachedSurfaceView::~CachedSurfaceView() = default; | 417 | CachedSurfaceView::~CachedSurfaceView() = default; |
| @@ -449,25 +456,35 @@ void CachedSurfaceView::Attach(GLenum attachment, GLenum target) const { | |||
| 449 | 456 | ||
| 450 | void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_source, | 457 | void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_source, |
| 451 | SwizzleSource z_source, SwizzleSource w_source) { | 458 | SwizzleSource z_source, SwizzleSource w_source) { |
| 452 | u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); | 459 | const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); |
| 453 | if (new_swizzle == swizzle) | 460 | if (current_swizzle == new_swizzle) { |
| 454 | return; | 461 | return; |
| 455 | swizzle = new_swizzle; | 462 | } |
| 456 | const std::array gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source), | 463 | current_swizzle = new_swizzle; |
| 457 | GetSwizzleSource(z_source), GetSwizzleSource(w_source)}; | 464 | |
| 465 | std::array swizzle{x_source, y_source, z_source, w_source}; | ||
| 466 | |||
| 458 | const GLuint handle = GetTexture(); | 467 | const GLuint handle = GetTexture(); |
| 459 | const PixelFormat format = surface.GetSurfaceParams().pixel_format; | 468 | switch (const PixelFormat format = surface.GetSurfaceParams().pixel_format) { |
| 460 | switch (format) { | 469 | case PixelFormat::S8Z24: |
| 461 | case PixelFormat::Z24S8: | 470 | case PixelFormat::Z24S8: |
| 462 | case PixelFormat::Z32FS8: | 471 | case PixelFormat::Z32FS8: |
| 463 | case PixelFormat::S8Z24: | 472 | UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); |
| 464 | glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE, | 473 | glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE, |
| 465 | GetComponent(format, x_source == SwizzleSource::R)); | 474 | GetComponent(format, x_source == SwizzleSource::R)); |
| 466 | break; | 475 | |
| 467 | default: | 476 | // Make sure we sample the first component |
| 477 | std::transform(swizzle.begin(), swizzle.end(), swizzle.begin(), [](SwizzleSource value) { | ||
| 478 | return value == SwizzleSource::G ? SwizzleSource::R : value; | ||
| 479 | }); | ||
| 480 | [[fallthrough]]; | ||
| 481 | default: { | ||
| 482 | const std::array gl_swizzle = {GetSwizzleSource(swizzle[0]), GetSwizzleSource(swizzle[1]), | ||
| 483 | GetSwizzleSource(swizzle[2]), GetSwizzleSource(swizzle[3])}; | ||
| 468 | glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); | 484 | glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); |
| 469 | break; | 485 | break; |
| 470 | } | 486 | } |
| 487 | } | ||
| 471 | } | 488 | } |
| 472 | 489 | ||
| 473 | OGLTextureView CachedSurfaceView::CreateTextureView() const { | 490 | 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: | |||
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | private: | 112 | private: |
| 113 | u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, | ||
| 114 | Tegra::Texture::SwizzleSource y_source, | ||
| 115 | Tegra::Texture::SwizzleSource z_source, | ||
| 116 | Tegra::Texture::SwizzleSource w_source) const { | ||
| 117 | return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) | | ||
| 118 | (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source); | ||
| 119 | } | ||
| 120 | |||
| 121 | OGLTextureView CreateTextureView() const; | 113 | OGLTextureView CreateTextureView() const; |
| 122 | 114 | ||
| 123 | CachedSurface& surface; | 115 | CachedSurface& surface; |
| @@ -125,7 +117,7 @@ private: | |||
| 125 | GLenum format{}; | 117 | GLenum format{}; |
| 126 | 118 | ||
| 127 | OGLTextureView texture_view; | 119 | OGLTextureView texture_view; |
| 128 | u32 swizzle{}; | 120 | u32 current_swizzle{}; |
| 129 | bool is_proxy{}; | 121 | bool is_proxy{}; |
| 130 | }; | 122 | }; |
| 131 | 123 | ||
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; | |||
| 354 | 354 | ||
| 355 | VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y_source, | 355 | VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y_source, |
| 356 | SwizzleSource z_source, SwizzleSource w_source) { | 356 | SwizzleSource z_source, SwizzleSource w_source) { |
| 357 | const u32 swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); | 357 | const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); |
| 358 | if (last_image_view && last_swizzle == swizzle) { | 358 | if (last_image_view && last_swizzle == new_swizzle) { |
| 359 | return last_image_view; | 359 | return last_image_view; |
| 360 | } | 360 | } |
| 361 | last_swizzle = swizzle; | 361 | last_swizzle = new_swizzle; |
| 362 | 362 | ||
| 363 | const auto [entry, is_cache_miss] = view_cache.try_emplace(swizzle); | 363 | const auto [entry, is_cache_miss] = view_cache.try_emplace(new_swizzle); |
| 364 | auto& image_view = entry->second; | 364 | auto& image_view = entry->second; |
| 365 | if (!is_cache_miss) { | 365 | if (!is_cache_miss) { |
| 366 | return last_image_view = *image_view; | 366 | return last_image_view = *image_view; |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | auto swizzle_x = MaxwellToVK::SwizzleSource(x_source); | 369 | std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), |
| 370 | auto swizzle_y = MaxwellToVK::SwizzleSource(y_source); | 370 | MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)}; |
| 371 | auto swizzle_z = MaxwellToVK::SwizzleSource(z_source); | ||
| 372 | auto swizzle_w = MaxwellToVK::SwizzleSource(w_source); | ||
| 373 | |||
| 374 | if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) { | 371 | if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) { |
| 375 | // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here. | 372 | // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here. |
| 376 | std::swap(swizzle_x, swizzle_z); | 373 | std::swap(swizzle[0], swizzle[2]); |
| 377 | } | 374 | } |
| 378 | 375 | ||
| 379 | // Games can sample depth or stencil values on textures. This is decided by the swizzle value on | 376 | // 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 | |||
| 395 | UNIMPLEMENTED(); | 392 | UNIMPLEMENTED(); |
| 396 | } | 393 | } |
| 397 | 394 | ||
| 398 | // Vulkan doesn't seem to understand swizzling of a depth stencil image, use identity | 395 | // Make sure we sample the first component |
| 399 | swizzle_x = VK_COMPONENT_SWIZZLE_R; | 396 | std::transform( |
| 400 | swizzle_y = VK_COMPONENT_SWIZZLE_G; | 397 | swizzle.begin(), swizzle.end(), swizzle.begin(), [](VkComponentSwizzle component) { |
| 401 | swizzle_z = VK_COMPONENT_SWIZZLE_B; | 398 | return component == VK_COMPONENT_SWIZZLE_G ? VK_COMPONENT_SWIZZLE_R : component; |
| 402 | swizzle_w = VK_COMPONENT_SWIZZLE_A; | 399 | }); |
| 403 | } | 400 | } |
| 404 | 401 | ||
| 405 | VkImageViewCreateInfo ci; | 402 | VkImageViewCreateInfo ci; |
| @@ -409,7 +406,7 @@ VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y | |||
| 409 | ci.image = surface.GetImageHandle(); | 406 | ci.image = surface.GetImageHandle(); |
| 410 | ci.viewType = image_view_type; | 407 | ci.viewType = image_view_type; |
| 411 | ci.format = surface.GetImage().GetFormat(); | 408 | ci.format = surface.GetImage().GetFormat(); |
| 412 | ci.components = {swizzle_x, swizzle_y, swizzle_z, swizzle_w}; | 409 | ci.components = {swizzle[0], swizzle[1], swizzle[2], swizzle[3]}; |
| 413 | ci.subresourceRange.aspectMask = aspect; | 410 | ci.subresourceRange.aspectMask = aspect; |
| 414 | ci.subresourceRange.baseMipLevel = base_level; | 411 | ci.subresourceRange.baseMipLevel = base_level; |
| 415 | ci.subresourceRange.levelCount = num_levels; | 412 | ci.subresourceRange.levelCount = num_levels; |