diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 7833de54a5..695ca9833b 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -1,4 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index a7a878f18c..24da3591ec 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -214,7 +214,7 @@ struct FormatTuple { {VK_FORMAT_ASTC_8x6_SRGB_BLOCK}, // ASTC_2D_8X6_SRGB {VK_FORMAT_ASTC_6x5_UNORM_BLOCK}, // ASTC_2D_6X5_UNORM {VK_FORMAT_ASTC_6x5_SRGB_BLOCK}, // ASTC_2D_6X5_SRGB - {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32}, // E5B9G9R9_FLOAT + {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, Attachable | Storage}, // E5B9G9R9_FLOAT // Depth formats {VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 136a11f78d..1b0619afad 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1549,6 +1549,24 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu MakeStorageView(device, level, *original_image, VK_FORMAT_A8B8G8R8_UNORM_PACK32); } } + + // Proactive warning for problematic HDR format + MSAA combinations on Android + // These combinations commonly cause texture flickering/black screens across multiple game engines + // Note: MSAA is native Switch rendering technique, cannot be disabled by emulator + if (info.num_samples > 1) { + const auto vk_format = MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, + false, info.format).format; + const bool is_hdr_format = vk_format == VK_FORMAT_B10G11R11_UFLOAT_PACK32 || + vk_format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + + if (is_hdr_format) { + LOG_WARNING(Render_Vulkan, + "Creating MSAA image ({}x samples) with HDR format {} (Maxwell: {}). " + "Driver support may be limited on Android (Qualcomm < 800, Mali pre-maintenance5). " + "Format fallback to RGBA16F should prevent issues.", + info.num_samples, vk_format, info.format); + } + } } Image::Image(const VideoCommon::NullImageParams& params) : VideoCommon::ImageBase{params} {} diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 437d082c4c..be4b246b79 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -1,4 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index ddaca2669c..f73365fd97 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -90,6 +90,31 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{ VK_FORMAT_UNDEFINED, }; +// B10G11R11_UFLOAT (R11G11B10 float) is used by Unreal Engine 5 for HDR textures +// Some Android drivers (Qualcomm pre-800, Mali pre-maintenance5) have issues with this format +// when used with MSAA or certain tiling modes, causing texture flickering/black screens +constexpr std::array B10G11R11_UFLOAT_PACK32{ + VK_FORMAT_R16G16B16A16_SFLOAT, // Fallback: RGBA16F (more memory, but widely supported) + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, // Alternative: E5B9G9R9 shared exponent format + VK_FORMAT_UNDEFINED, +}; + +// E5B9G9R9_UFLOAT (shared exponent RGB9E5) used by various engines (Unity, custom engines) +// Also problematic on some Android drivers, especially with MSAA and as render target +constexpr std::array E5B9G9R9_UFLOAT_PACK32{ + VK_FORMAT_R16G16B16A16_SFLOAT, // Fallback: RGBA16F (safest option) + VK_FORMAT_B10G11R11_UFLOAT_PACK32, // Alternative: might work if E5B9G9R9 fails + VK_FORMAT_UNDEFINED, +}; + +/// Helper function to detect HDR formats that commonly fail with MSAA on some Android drivers +[[nodiscard]] constexpr bool IsProblematicHDRFormat(VkFormat format) { + // These formats are known to cause texture flickering/black screens across multiple game engines + // when combined with MSAA on certain Android drivers (Qualcomm < 800, Mali pre-maintenance5) + return format == VK_FORMAT_B10G11R11_UFLOAT_PACK32 || // UE5, custom engines + format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; // Unity, RE Engine, others +} + } // namespace Alternatives template @@ -122,6 +147,10 @@ constexpr const VkFormat* GetFormatAlternatives(VkFormat format) { return Alternatives::VK_FORMAT_R32G32B32_SFLOAT.data(); case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: return Alternatives::VK_FORMAT_A4B4G4R4_UNORM_PACK16.data(); + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + return Alternatives::B10G11R11_UFLOAT_PACK32.data(); + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + return Alternatives::E5B9G9R9_UFLOAT_PACK32.data(); default: return nullptr; } @@ -844,15 +873,33 @@ Device::~Device() { VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, FormatType format_type) const { if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { - return wanted_format; + // CRITICAL FIX: Even if format is "supported", check for STORAGE + HDR + no MSAA support + // Driver may report STORAGE_IMAGE_BIT but shaderStorageImageMultisample=false means + // it will fail at runtime when used with MSAA (CopyImageMSAA silently fails) + const bool requests_storage = (wanted_usage & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0; + const bool is_hdr_format = wanted_format == VK_FORMAT_B10G11R11_UFLOAT_PACK32 || + wanted_format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + + // If driver doesn't support shader storage image with MSAA, and we're requesting storage + // for an HDR format (which will likely be used with MSAA), force fallback + if (requests_storage && is_hdr_format && !features.features.shaderStorageImageMultisample) { + LOG_WARNING(Render_Vulkan, + "Format {} reports STORAGE_IMAGE_BIT but driver doesn't support " + "shaderStorageImageMultisample. Forcing fallback for MSAA compatibility.", + wanted_format); + // Continue to alternatives search below + } else { + return wanted_format; + } } // The wanted format is not supported by hardware, search for alternatives const VkFormat* alternatives = GetFormatAlternatives(wanted_format); if (alternatives == nullptr) { LOG_ERROR(Render_Vulkan, - "Format={} with usage={} and type={} has no defined alternatives and host " - "hardware does not support it", - wanted_format, wanted_usage, format_type); + "Format={} (0x{:X}) with usage={} and type={} has no defined alternatives and host " + "hardware does not support it. Driver: {} Device: {}", + wanted_format, static_cast(wanted_format), wanted_usage, format_type, + GetDriverName(), properties.properties.deviceName); return wanted_format; } @@ -861,9 +908,22 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags if (!IsFormatSupported(alternative, wanted_usage, format_type)) { continue; } - LOG_DEBUG(Render_Vulkan, + // Special logging for HDR formats (common across multiple engines) on problematic drivers + if (wanted_format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) { + LOG_WARNING(Render_Vulkan, + "Emulating B10G11R11_UFLOAT (HDR format: UE5, custom engines) with {} on {}. " + "Native format not supported by driver, using fallback.", + alternative, properties.properties.deviceName); + } else if (wanted_format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) { + LOG_WARNING(Render_Vulkan, + "Emulating E5B9G9R9_UFLOAT (HDR format: Unity, RE Engine) with {} on {}. " + "Native format not supported by driver, using fallback.", + alternative, properties.properties.deviceName); + } else { + LOG_DEBUG(Render_Vulkan, "Emulating format={} with alternative format={} with usage={} and type={}", wanted_format, alternative, wanted_usage, format_type); + } return alternative; }