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.
This commit is contained in:
parent
86345c126a
commit
8bba84a401
3 changed files with 42 additions and 36 deletions
|
@ -238,6 +238,12 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr u32 EncodeSwizzle(SwizzleSource x_source, SwizzleSource y_source, SwizzleSource z_source,
|
||||||
|
SwizzleSource w_source) {
|
||||||
|
return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) |
|
||||||
|
(static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source);
|
||||||
|
}
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params,
|
CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params,
|
||||||
|
@ -404,7 +410,8 @@ CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, const ViewParams& p
|
||||||
if (!is_proxy) {
|
if (!is_proxy) {
|
||||||
texture_view = CreateTextureView();
|
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;
|
CachedSurfaceView::~CachedSurfaceView() = default;
|
||||||
|
@ -449,25 +456,35 @@ void CachedSurfaceView::Attach(GLenum attachment, GLenum target) const {
|
||||||
|
|
||||||
void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_source,
|
void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_source,
|
||||||
SwizzleSource z_source, SwizzleSource w_source) {
|
SwizzleSource z_source, SwizzleSource w_source) {
|
||||||
u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source);
|
const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source);
|
||||||
if (new_swizzle == swizzle)
|
if (current_swizzle == new_swizzle) {
|
||||||
return;
|
return;
|
||||||
swizzle = new_swizzle;
|
}
|
||||||
const std::array gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source),
|
current_swizzle = new_swizzle;
|
||||||
GetSwizzleSource(z_source), GetSwizzleSource(w_source)};
|
|
||||||
|
std::array swizzle{x_source, y_source, z_source, w_source};
|
||||||
|
|
||||||
const GLuint handle = GetTexture();
|
const GLuint handle = GetTexture();
|
||||||
const PixelFormat format = surface.GetSurfaceParams().pixel_format;
|
switch (const PixelFormat format = surface.GetSurfaceParams().pixel_format) {
|
||||||
switch (format) {
|
case PixelFormat::S8Z24:
|
||||||
case PixelFormat::Z24S8:
|
case PixelFormat::Z24S8:
|
||||||
case PixelFormat::Z32FS8:
|
case PixelFormat::Z32FS8:
|
||||||
case PixelFormat::S8Z24:
|
UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G);
|
||||||
glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE,
|
glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE,
|
||||||
GetComponent(format, x_source == SwizzleSource::R));
|
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());
|
glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OGLTextureView CachedSurfaceView::CreateTextureView() const {
|
OGLTextureView CachedSurfaceView::CreateTextureView() const {
|
||||||
|
|
|
@ -110,14 +110,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) |
|
|
||||||
(static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
OGLTextureView CreateTextureView() const;
|
OGLTextureView CreateTextureView() const;
|
||||||
|
|
||||||
CachedSurface& surface;
|
CachedSurface& surface;
|
||||||
|
@ -125,7 +117,7 @@ private:
|
||||||
GLenum format{};
|
GLenum format{};
|
||||||
|
|
||||||
OGLTextureView texture_view;
|
OGLTextureView texture_view;
|
||||||
u32 swizzle{};
|
u32 current_swizzle{};
|
||||||
bool is_proxy{};
|
bool is_proxy{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -354,26 +354,23 @@ CachedSurfaceView::~CachedSurfaceView() = default;
|
||||||
|
|
||||||
VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y_source,
|
VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y_source,
|
||||||
SwizzleSource z_source, SwizzleSource w_source) {
|
SwizzleSource z_source, SwizzleSource w_source) {
|
||||||
const u32 swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source);
|
const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source);
|
||||||
if (last_image_view && last_swizzle == swizzle) {
|
if (last_image_view && last_swizzle == new_swizzle) {
|
||||||
return last_image_view;
|
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;
|
auto& image_view = entry->second;
|
||||||
if (!is_cache_miss) {
|
if (!is_cache_miss) {
|
||||||
return last_image_view = *image_view;
|
return last_image_view = *image_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto swizzle_x = MaxwellToVK::SwizzleSource(x_source);
|
std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source),
|
||||||
auto swizzle_y = MaxwellToVK::SwizzleSource(y_source);
|
MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)};
|
||||||
auto swizzle_z = MaxwellToVK::SwizzleSource(z_source);
|
|
||||||
auto swizzle_w = MaxwellToVK::SwizzleSource(w_source);
|
|
||||||
|
|
||||||
if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) {
|
if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) {
|
||||||
// A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here.
|
// 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
|
// 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();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vulkan doesn't seem to understand swizzling of a depth stencil image, use identity
|
// Make sure we sample the first component
|
||||||
swizzle_x = VK_COMPONENT_SWIZZLE_R;
|
std::transform(
|
||||||
swizzle_y = VK_COMPONENT_SWIZZLE_G;
|
swizzle.begin(), swizzle.end(), swizzle.begin(), [](VkComponentSwizzle component) {
|
||||||
swizzle_z = VK_COMPONENT_SWIZZLE_B;
|
return component == VK_COMPONENT_SWIZZLE_G ? VK_COMPONENT_SWIZZLE_R : component;
|
||||||
swizzle_w = VK_COMPONENT_SWIZZLE_A;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageViewCreateInfo ci;
|
VkImageViewCreateInfo ci;
|
||||||
|
@ -409,7 +406,7 @@ VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y
|
||||||
ci.image = surface.GetImageHandle();
|
ci.image = surface.GetImageHandle();
|
||||||
ci.viewType = image_view_type;
|
ci.viewType = image_view_type;
|
||||||
ci.format = surface.GetImage().GetFormat();
|
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.aspectMask = aspect;
|
||||||
ci.subresourceRange.baseMipLevel = base_level;
|
ci.subresourceRange.baseMipLevel = base_level;
|
||||||
ci.subresourceRange.levelCount = num_levels;
|
ci.subresourceRange.levelCount = num_levels;
|
||||||
|
|
Loading…
Reference in a new issue