[video_core] Improve texture rendering (#2830)

This fixes some edge cases and improves texture rendering, bringing it closer to specifications. This fixes many assertions that occur in some games, such as EOW.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2830
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
This commit is contained in:
MaranBr 2025-10-26 02:14:45 +02:00 committed by crueter
parent 53bfd56b70
commit 73ebf59af7
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
2 changed files with 140 additions and 110 deletions

View file

@ -54,65 +54,81 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
TextureType tex_type = config.texture_type; TextureType tex_type = config.texture_type;
if (tex_type == TextureType::Texture1D && (config.Depth() > 1 || config.BaseLayer() != 0)) { if (tex_type == TextureType::Texture1D && (config.Depth() > 1 || config.BaseLayer() != 0)) {
tex_type = TextureType::Texture1DArray; tex_type = TextureType::Texture1DArray;
} else if (tex_type == TextureType::Texture2D && (config.Depth() > 1 || config.BaseLayer() != 0)) {
tex_type = TextureType::Texture2DArray;
} }
switch (tex_type) { switch (tex_type) {
case TextureType::Texture1D: case TextureType::Texture1D:
ASSERT(config.BaseLayer() == 0); ASSERT(config.BaseLayer() == 0);
type = ImageType::e1D; ASSERT(config.Depth() == 1);
size.width = config.Width(); type = ImageType::e1D;
resources.layers = 1; size.width = config.Width();
break; size.depth = 1;
case TextureType::Texture1DArray: resources.layers = 1;
type = ImageType::e1D; break;
size.width = config.Width(); case TextureType::Texture1DArray:
resources.layers = config.BaseLayer() + config.Depth(); ASSERT(config.Depth() > 0);
break; ASSERT(config.BaseLayer() < config.Depth());
case TextureType::Texture2D: type = ImageType::e1D;
case TextureType::Texture2DNoMipmap: size.width = config.Width();
ASSERT(config.Depth() == 1); size.depth = 1;
type = config.IsPitchLinear() ? ImageType::Linear : ImageType::e2D; resources.layers = config.Depth() - config.BaseLayer();
rescaleable = !config.IsPitchLinear(); break;
size.width = config.Width(); case TextureType::Texture2D:
size.height = config.Height(); case TextureType::Texture2DNoMipmap:
resources.layers = config.BaseLayer() + 1; ASSERT(config.BaseLayer() == 0);
break; ASSERT(config.Depth() == 1);
case TextureType::Texture2DArray: type = config.IsPitchLinear() ? ImageType::Linear : ImageType::e2D;
type = ImageType::e2D; rescaleable = !config.IsPitchLinear();
rescaleable = true; size.width = config.Width();
size.width = config.Width(); size.height = config.Height();
size.height = config.Height(); size.depth = 1;
resources.layers = config.BaseLayer() + config.Depth(); resources.layers = 1;
break; break;
case TextureType::TextureCubemap: case TextureType::Texture2DArray:
ASSERT(config.Depth() == 1); ASSERT(config.Depth() > 0);
type = ImageType::e2D; ASSERT(config.BaseLayer() < config.Depth());
size.width = config.Width(); type = ImageType::e2D;
size.height = config.Height(); rescaleable = true;
resources.layers = config.BaseLayer() + 6; size.width = config.Width();
break; size.height = config.Height();
case TextureType::TextureCubeArray: size.depth = 1;
UNIMPLEMENTED_IF(config.load_store_hint != 0); resources.layers = config.Depth() - config.BaseLayer();
type = ImageType::e2D; break;
size.width = config.Width(); case TextureType::TextureCubemap:
size.height = config.Height(); ASSERT(config.Depth() == 1);
resources.layers = config.BaseLayer() + config.Depth() * 6; type = ImageType::e2D;
break; size.width = config.Width();
case TextureType::Texture3D: size.height = config.Height();
ASSERT(config.BaseLayer() == 0); size.depth = 1;
type = ImageType::e3D; resources.layers = 6;
size.width = config.Width(); break;
size.height = config.Height(); case TextureType::TextureCubeArray:
size.depth = config.Depth(); UNIMPLEMENTED_IF(config.load_store_hint != 0);
resources.layers = 1; ASSERT(config.Depth() > 0);
break; type = ImageType::e2D;
case TextureType::Texture1DBuffer: size.width = config.Width();
type = ImageType::Buffer; size.height = config.Height();
size.width = config.Width(); size.depth = 1;
resources.layers = 1; resources.layers = (config.Depth() - config.BaseLayer()) * 6;
break; break;
default: case TextureType::Texture3D:
ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(tex_type)); ASSERT(config.BaseLayer() == 0);
break; type = ImageType::e3D;
size.width = config.Width();
size.height = config.Height();
size.depth = config.Depth();
resources.layers = 1;
break;
case TextureType::Texture1DBuffer:
type = ImageType::Buffer;
size.width = config.Width();
size.depth = 1;
resources.layers = 1;
break;
default:
ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(tex_type));
break;
} }
if (num_samples > 1) { if (num_samples > 1) {
size.width *= NumSamplesX(config.msaa_mode); size.width *= NumSamplesX(config.msaa_mode);

View file

@ -30,59 +30,73 @@ constexpr u8 RENDER_TARGET_SWIZZLE = (std::numeric_limits<u8>::max)();
} // Anonymous namespace } // Anonymous namespace
ImageViewInfo::ImageViewInfo(const TICEntry& config, s32 base_layer) noexcept ImageViewInfo::ImageViewInfo(const TICEntry& config, s32 base_layer) noexcept
: format{PixelFormatFromTIC(config)}, : format{PixelFormatFromTIC(config)},
x_source{CastSwizzle(config.x_source)}, x_source{CastSwizzle(config.x_source)},
y_source{CastSwizzle(config.y_source)}, y_source{CastSwizzle(config.y_source)},
z_source{CastSwizzle(config.z_source)}, z_source{CastSwizzle(config.z_source)},
w_source{CastSwizzle(config.w_source)} { w_source{CastSwizzle(config.w_source)} {
range.base = SubresourceBase{ range.base = SubresourceBase{
.level = static_cast<s32>(config.res_min_mip_level), .level = static_cast<s32>(config.res_min_mip_level),
.layer = base_layer, .layer = base_layer,
}; };
range.extent.levels = config.res_max_mip_level - config.res_min_mip_level + 1; range.extent.levels = config.res_max_mip_level - config.res_min_mip_level + 1;
TextureType tex_type = config.texture_type; TextureType tex_type = config.texture_type;
if (tex_type == TextureType::Texture1D && (config.Depth() > 1 || base_layer != 0)) { if (tex_type == TextureType::Texture1D && (config.Depth() > 1 || base_layer != 0)) {
tex_type = TextureType::Texture1DArray; tex_type = TextureType::Texture1DArray;
} } else if (tex_type == TextureType::Texture2D && (config.Depth() > 1 || base_layer != 0)) {
switch (tex_type) { tex_type = TextureType::Texture2DArray;
case TextureType::Texture1D: }
ASSERT(config.Height() == 1); switch (tex_type) {
ASSERT(config.Depth() == 1); case TextureType::Texture1D:
type = ImageViewType::e1D; ASSERT(config.Height() == 1);
break; ASSERT(config.Depth() == 1);
case TextureType::Texture1DArray: ASSERT(base_layer == 0);
ASSERT(config.Height() == 1); type = ImageViewType::e1D;
type = ImageViewType::e1DArray; range.extent.layers = 1;
range.extent.layers = config.Depth(); break;
break; case TextureType::Texture1DArray:
case TextureType::Texture2D: ASSERT(config.Depth() > 0);
case TextureType::Texture2DNoMipmap: ASSERT(static_cast<u32>(base_layer) < config.Depth());
ASSERT(config.Depth() == 1); type = ImageViewType::e1DArray;
type = config.normalized_coords ? ImageViewType::e2D : ImageViewType::Rect; range.extent.layers = config.Depth() - base_layer;
break; break;
case TextureType::Texture2DArray: case TextureType::Texture2D:
type = ImageViewType::e2DArray; case TextureType::Texture2DNoMipmap:
range.extent.layers = config.Depth(); ASSERT(config.Depth() == 1);
break; ASSERT(base_layer == 0);
case TextureType::Texture3D: type = config.normalized_coords ? ImageViewType::e2D : ImageViewType::Rect;
type = ImageViewType::e3D; range.extent.layers = 1;
break; break;
case TextureType::TextureCubemap: case TextureType::Texture2DArray:
ASSERT(config.Depth() == 1); ASSERT(config.Depth() > 0);
type = ImageViewType::Cube; ASSERT(static_cast<u32>(base_layer) < config.Depth());
range.extent.layers = 6; type = ImageViewType::e2DArray;
break; range.extent.layers = config.Depth() - base_layer;
case TextureType::TextureCubeArray: break;
type = ImageViewType::CubeArray; case TextureType::TextureCubemap:
range.extent.layers = config.Depth() * 6; ASSERT(config.Depth() == 1);
break; type = ImageViewType::Cube;
case TextureType::Texture1DBuffer: range.extent.layers = 6;
type = ImageViewType::Buffer; break;
break; case TextureType::TextureCubeArray:
default: ASSERT(config.Depth() > 0);
ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(tex_type)); ASSERT(static_cast<u32>(base_layer) < config.Depth());
break; type = ImageViewType::CubeArray;
} range.extent.layers = (config.Depth() - base_layer) * 6;
break;
case TextureType::Texture3D:
ASSERT(base_layer == 0);
type = ImageViewType::e3D;
range.extent.layers = 1;
break;
case TextureType::Texture1DBuffer:
type = ImageViewType::Buffer;
range.extent.layers = 1;
break;
default:
ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(tex_type));
break;
}
} }
ImageViewInfo::ImageViewInfo(ImageViewType type_, PixelFormat format_, ImageViewInfo::ImageViewInfo(ImageViewType type_, PixelFormat format_,