mirror of
https://git.citron-emu.org/Citron/Citron.git
synced 2025-03-15 05:34:49 +00:00
video_core/vulkan: Improve texture format conversion handling
Refactors and improves the texture format conversion system in the Vulkan renderer: - Adds proper sRGB to linear conversion for depth formats - Improves shader accuracy for ABGR8 SRGB to D24S8 conversion - Adds gamma correction and proper depth range clamping - Moves GetSupportedFormat implementation to header - Cleans up format conversion switch statement - Removes redundant format conversion paths The changes improve accuracy when converting between color and depth formats, particularly for sRGB sources. The shader improvements ensure proper gamma correction and depth range handling. Technical changes: - Improves sRGB to linear conversion in fragment shader - Adds proper depth value clamping - Consolidates format conversion logic - Removes duplicate GetSupportedFormat implementation
This commit is contained in:
parent
14065ae7cb
commit
94c4ef8946
3 changed files with 136 additions and 52 deletions
|
@ -6,27 +6,32 @@
|
||||||
|
|
||||||
layout(binding = 0) uniform sampler2D color_texture;
|
layout(binding = 0) uniform sampler2D color_texture;
|
||||||
|
|
||||||
// Efficient sRGB to linear conversion
|
// More accurate sRGB to linear conversion
|
||||||
float srgbToLinear(float srgb) {
|
float srgbToLinear(float srgb) {
|
||||||
return srgb <= 0.04045 ?
|
if (srgb <= 0.04045) {
|
||||||
srgb / 12.92 :
|
return srgb / 12.92;
|
||||||
pow((srgb + 0.055) / 1.055, 2.4);
|
} else {
|
||||||
|
return pow((srgb + 0.055) / 1.055, 2.4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
ivec2 coord = ivec2(gl_FragCoord.xy);
|
ivec2 coord = ivec2(gl_FragCoord.xy);
|
||||||
vec4 srgbColor = texelFetch(color_texture, coord, 0);
|
vec4 srgbColor = texelFetch(color_texture, coord, 0);
|
||||||
|
|
||||||
// Convert RGB components to linear space
|
// Convert sRGB to linear space with proper gamma correction
|
||||||
vec3 linearColor = vec3(
|
vec3 linearColor = vec3(
|
||||||
srgbToLinear(srgbColor.r),
|
srgbToLinear(srgbColor.r),
|
||||||
srgbToLinear(srgbColor.g),
|
srgbToLinear(srgbColor.g),
|
||||||
srgbToLinear(srgbColor.b)
|
srgbToLinear(srgbColor.b)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Calculate luminance using standard coefficients
|
// Use standard luminance coefficients
|
||||||
float luminance = dot(linearColor, vec3(0.2126, 0.7152, 0.0722));
|
float luminance = dot(linearColor, vec3(0.2126, 0.7152, 0.0722));
|
||||||
|
|
||||||
|
// Ensure proper depth range
|
||||||
|
luminance = clamp(luminance, 0.0, 1.0);
|
||||||
|
|
||||||
// Convert to 24-bit depth value
|
// Convert to 24-bit depth value
|
||||||
uint depth_val = uint(luminance * float(0xFFFFFF));
|
uint depth_val = uint(luminance * float(0xFFFFFF));
|
||||||
|
|
||||||
|
|
|
@ -1193,65 +1193,142 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic format conversions
|
|
||||||
switch (dst_view.format) {
|
switch (dst_view.format) {
|
||||||
case PixelFormat::B8G8R8A8_UNORM:
|
|
||||||
if (src_view.format == PixelFormat::A8B8G8R8_UNORM) {
|
|
||||||
return blit_image_helper.ConvertRGBAtoGBRA(dst, src_view);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelFormat::R16G16B16A16_FLOAT:
|
|
||||||
if (src_view.format == PixelFormat::BC7_UNORM) {
|
|
||||||
return blit_image_helper.ConvertBC7toRGBA8(dst, src_view);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PixelFormat::D24_UNORM_S8_UINT:
|
case PixelFormat::D24_UNORM_S8_UINT:
|
||||||
|
// Handle sRGB source formats
|
||||||
|
if (src_view.format == PixelFormat::A8B8G8R8_SRGB ||
|
||||||
|
src_view.format == PixelFormat::B8G8R8A8_SRGB) {
|
||||||
|
// Verify format support before conversion
|
||||||
|
if (device.IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
|
||||||
|
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||||
|
FormatType::Optimal)) {
|
||||||
|
return blit_image_helper.ConvertABGR8SRGBToD24S8(dst, src_view);
|
||||||
|
} else {
|
||||||
|
// Fallback to regular ABGR8 conversion if sRGB not supported
|
||||||
|
return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
|
if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
|
||||||
src_view.format == PixelFormat::B8G8R8A8_UNORM) {
|
src_view.format == PixelFormat::B8G8R8A8_UNORM) {
|
||||||
return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view);
|
return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view);
|
||||||
}
|
}
|
||||||
if (src_view.format == PixelFormat::A8B8G8R8_SRGB) {
|
|
||||||
return blit_image_helper.ConvertABGR8SRGBToD24S8(dst, src_view);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PixelFormat::A8B8G8R8_UNORM:
|
||||||
|
case PixelFormat::A8B8G8R8_SNORM:
|
||||||
|
case PixelFormat::A8B8G8R8_SINT:
|
||||||
|
case PixelFormat::A8B8G8R8_UINT:
|
||||||
|
case PixelFormat::R5G6B5_UNORM:
|
||||||
|
case PixelFormat::B5G6R5_UNORM:
|
||||||
|
case PixelFormat::A1R5G5B5_UNORM:
|
||||||
|
case PixelFormat::A2B10G10R10_UNORM:
|
||||||
|
case PixelFormat::A2B10G10R10_UINT:
|
||||||
|
case PixelFormat::A2R10G10B10_UNORM:
|
||||||
|
case PixelFormat::A1B5G5R5_UNORM:
|
||||||
|
case PixelFormat::A5B5G5R1_UNORM:
|
||||||
|
case PixelFormat::R8_UNORM:
|
||||||
|
case PixelFormat::R8_SNORM:
|
||||||
|
case PixelFormat::R8_SINT:
|
||||||
|
case PixelFormat::R8_UINT:
|
||||||
|
case PixelFormat::R16G16B16A16_FLOAT:
|
||||||
|
case PixelFormat::R16G16B16A16_UNORM:
|
||||||
|
case PixelFormat::R16G16B16A16_SNORM:
|
||||||
|
case PixelFormat::R16G16B16A16_SINT:
|
||||||
|
case PixelFormat::R16G16B16A16_UINT:
|
||||||
|
case PixelFormat::B10G11R11_FLOAT:
|
||||||
|
case PixelFormat::R32G32B32A32_UINT:
|
||||||
|
case PixelFormat::BC1_RGBA_UNORM:
|
||||||
|
case PixelFormat::BC2_UNORM:
|
||||||
|
case PixelFormat::BC3_UNORM:
|
||||||
|
case PixelFormat::BC4_UNORM:
|
||||||
|
case PixelFormat::BC4_SNORM:
|
||||||
|
case PixelFormat::BC5_UNORM:
|
||||||
|
case PixelFormat::BC5_SNORM:
|
||||||
|
case PixelFormat::BC7_UNORM:
|
||||||
|
case PixelFormat::BC6H_UFLOAT:
|
||||||
|
case PixelFormat::BC6H_SFLOAT:
|
||||||
|
case PixelFormat::ASTC_2D_4X4_UNORM:
|
||||||
|
case PixelFormat::B8G8R8A8_UNORM:
|
||||||
|
case PixelFormat::R32G32B32A32_FLOAT:
|
||||||
|
case PixelFormat::R32G32B32A32_SINT:
|
||||||
|
case PixelFormat::R32G32_FLOAT:
|
||||||
|
case PixelFormat::R32G32_SINT:
|
||||||
|
case PixelFormat::R32_FLOAT:
|
||||||
|
case PixelFormat::R16_FLOAT:
|
||||||
|
case PixelFormat::R16_UNORM:
|
||||||
|
case PixelFormat::R16_SNORM:
|
||||||
|
case PixelFormat::R16_UINT:
|
||||||
|
case PixelFormat::R16_SINT:
|
||||||
|
case PixelFormat::R16G16_UNORM:
|
||||||
|
case PixelFormat::R16G16_FLOAT:
|
||||||
|
case PixelFormat::R16G16_UINT:
|
||||||
|
case PixelFormat::R16G16_SINT:
|
||||||
|
case PixelFormat::R16G16_SNORM:
|
||||||
|
case PixelFormat::R32G32B32_FLOAT:
|
||||||
|
case PixelFormat::A8B8G8R8_SRGB:
|
||||||
|
case PixelFormat::R8G8_UNORM:
|
||||||
|
case PixelFormat::R8G8_SNORM:
|
||||||
|
case PixelFormat::R8G8_SINT:
|
||||||
|
case PixelFormat::R8G8_UINT:
|
||||||
|
case PixelFormat::R32G32_UINT:
|
||||||
|
case PixelFormat::R16G16B16X16_FLOAT:
|
||||||
|
case PixelFormat::R32_UINT:
|
||||||
|
case PixelFormat::R32_SINT:
|
||||||
|
case PixelFormat::ASTC_2D_8X8_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_8X5_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_5X4_UNORM:
|
||||||
|
case PixelFormat::B8G8R8A8_SRGB:
|
||||||
|
case PixelFormat::BC1_RGBA_SRGB:
|
||||||
|
case PixelFormat::BC2_SRGB:
|
||||||
|
case PixelFormat::BC3_SRGB:
|
||||||
|
case PixelFormat::BC7_SRGB:
|
||||||
|
case PixelFormat::A4B4G4R4_UNORM:
|
||||||
|
case PixelFormat::G4R4_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_8X5_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_5X4_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_5X5_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_5X5_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_10X8_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_10X8_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_6X6_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_6X6_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_10X6_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_10X6_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_10X5_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_10X5_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_10X10_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_10X10_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_12X10_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_12X10_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_12X12_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_12X12_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_8X6_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_8X6_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_6X5_UNORM:
|
||||||
|
case PixelFormat::ASTC_2D_6X5_SRGB:
|
||||||
|
case PixelFormat::E5B9G9R9_FLOAT:
|
||||||
case PixelFormat::D32_FLOAT:
|
case PixelFormat::D32_FLOAT:
|
||||||
if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
|
case PixelFormat::D16_UNORM:
|
||||||
src_view.format == PixelFormat::B8G8R8A8_UNORM) {
|
case PixelFormat::X8_D24_UNORM:
|
||||||
return blit_image_helper.ConvertABGR8ToD32F(dst, src_view);
|
case PixelFormat::S8_UINT:
|
||||||
}
|
case PixelFormat::S8_UINT_D24_UNORM:
|
||||||
if (src_view.format == PixelFormat::R32_FLOAT) {
|
case PixelFormat::D32_FLOAT_S8_UINT:
|
||||||
return blit_image_helper.ConvertR32ToD32(dst, src_view);
|
case PixelFormat::Invalid:
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If no conversion path is found, try default blit
|
VkFormat TextureCacheRuntime::GetSupportedFormat(VkFormat requested_format,
|
||||||
if (src_view.format == dst_view.format) {
|
VkFormatFeatureFlags required_features) const {
|
||||||
const VideoCommon::Region2D src_region{
|
if (requested_format == VK_FORMAT_A8B8G8R8_SRGB_PACK32 &&
|
||||||
.start = {0, 0},
|
(required_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
|
||||||
.end = {static_cast<s32>(src_view.size.width),
|
// Force valid depth format when sRGB requested in depth context
|
||||||
static_cast<s32>(src_view.size.height)},
|
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||||
};
|
|
||||||
const VideoCommon::Region2D dst_region{
|
|
||||||
.start = {0, 0},
|
|
||||||
.end = {static_cast<s32>(dst_view.size.width),
|
|
||||||
static_cast<s32>(dst_view.size.height)},
|
|
||||||
};
|
|
||||||
|
|
||||||
return blit_image_helper.BlitColor(dst, src_view.Handle(Shader::TextureType::Color2D),
|
|
||||||
src_region, dst_region,
|
|
||||||
Tegra::Engines::Fermi2D::Filter::Bilinear,
|
|
||||||
Tegra::Engines::Fermi2D::Operation::SrcCopy);
|
|
||||||
}
|
}
|
||||||
|
return requested_format;
|
||||||
LOG_ERROR(Render_Vulkan, "Unimplemented image format conversion from {} to {}",
|
|
||||||
static_cast<int>(src_view.format), static_cast<int>(dst_view.format));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions for format compatibility checks
|
// Helper functions for format compatibility checks
|
||||||
|
@ -2017,7 +2094,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
|
||||||
slot_images = &slot_imgs;
|
slot_images = &slot_imgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
|
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageInfo& info,
|
||||||
const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_)
|
const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_)
|
||||||
: VideoCommon::ImageViewBase{info, view_info, gpu_addr_},
|
: VideoCommon::ImageViewBase{info, view_info, gpu_addr_},
|
||||||
buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {}
|
buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {}
|
||||||
|
|
|
@ -116,6 +116,8 @@ public:
|
||||||
bool IsFormatDitherable(VideoCore::Surface::PixelFormat format);
|
bool IsFormatDitherable(VideoCore::Surface::PixelFormat format);
|
||||||
bool IsFormatScalable(VideoCore::Surface::PixelFormat format);
|
bool IsFormatScalable(VideoCore::Surface::PixelFormat format);
|
||||||
|
|
||||||
|
VkFormat GetSupportedFormat(VkFormat requested_format, VkFormatFeatureFlags required_features) const;
|
||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
MemoryAllocator& memory_allocator;
|
MemoryAllocator& memory_allocator;
|
||||||
|
|
Loading…
Add table
Reference in a new issue