Add fallback system for unsupported pixel formats.

This commit is contained in:
squidbus 2024-07-14 02:48:00 -07:00 committed by TheTurtle
parent 35d629a730
commit 175ffe8ce3
6 changed files with 154 additions and 4 deletions

View File

@ -281,6 +281,63 @@ vk::BorderColor BorderColor(AmdGpu::BorderColor color) {
} }
} }
const std::vector<vk::Format>& GetAllFormats() {
static const std::vector formats{
vk::Format::eR32G32B32A32Sfloat,
vk::Format::eR32G32B32Uint,
vk::Format::eR8G8B8A8Unorm,
vk::Format::eB8G8R8A8Unorm,
vk::Format::eR8G8B8A8Srgb,
vk::Format::eB8G8R8A8Srgb,
vk::Format::eR32G32B32Sfloat,
vk::Format::eR32G32Sfloat,
vk::Format::eB5G6R5UnormPack16,
vk::Format::eR5G6B5UnormPack16,
vk::Format::eR8Unorm,
vk::Format::eBc3SrgbBlock,
vk::Format::eBc3UnormBlock,
vk::Format::eBc4UnormBlock,
vk::Format::eBc5UnormBlock,
vk::Format::eR16G16B16A16Sint,
vk::Format::eR16G16Sfloat,
vk::Format::eB10G11R11UfloatPack32,
vk::Format::eA2B10G10R10UnormPack32,
vk::Format::eBc7SrgbBlock,
vk::Format::eBc1RgbaUnormBlock,
vk::Format::eR8G8B8A8Uint,
vk::Format::eR16Sfloat,
vk::Format::eR32Sfloat,
vk::Format::eR16G16B16A16Sfloat,
vk::Format::eR32Uint,
vk::Format::eR32Sint,
vk::Format::eR8G8Unorm,
vk::Format::eR8G8Snorm,
vk::Format::eBc7UnormBlock,
vk::Format::eBc2UnormBlock,
vk::Format::eR16G16Snorm,
vk::Format::eA2R10G10B10UnormPack32,
vk::Format::eA2R10G10B10SnormPack32,
vk::Format::eB10G11R11UfloatPack32,
vk::Format::eR16G16Sfloat,
vk::Format::eR16G16B16A16Snorm,
vk::Format::eR32G32Uint,
vk::Format::eR4G4B4A4UnormPack16,
vk::Format::eR16G16B16A16Uint,
vk::Format::eR32G32B32A32Uint,
vk::Format::eR8Sint,
vk::Format::eBc1RgbaSrgbBlock,
vk::Format::eR16G16Sint,
vk::Format::eR8G8B8A8Uscaled,
vk::Format::eR16Unorm,
vk::Format::eR16G16B16A16Unorm,
vk::Format::eD32SfloatS8Uint,
vk::Format::eD32Sfloat,
vk::Format::eD16Unorm,
vk::Format::eD16UnormS8Uint,
};
return formats;
}
vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format) { vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format) {
if (data_format == AmdGpu::DataFormat::Format32_32_32_32 && if (data_format == AmdGpu::DataFormat::Format32_32_32_32 &&

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <vector>
#include "video_core/amdgpu/liverpool.h" #include "video_core/amdgpu/liverpool.h"
#include "video_core/amdgpu/pixel_format.h" #include "video_core/amdgpu/pixel_format.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
@ -38,6 +39,8 @@ vk::SamplerMipmapMode MipFilter(AmdGpu::MipFilter filter);
vk::BorderColor BorderColor(AmdGpu::BorderColor color); vk::BorderColor BorderColor(AmdGpu::BorderColor color);
const std::vector<vk::Format>& GetAllFormats();
vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format); vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format);
vk::Format AdjustColorBufferFormat(vk::Format base_format, vk::Format AdjustColorBufferFormat(vk::Format base_format,

View File

@ -9,6 +9,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "sdl_window.h" #include "sdl_window.h"
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_platform.h" #include "video_core/renderer_vulkan/vk_platform.h"
@ -28,6 +29,15 @@ std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) {
return supported_extensions; return supported_extensions;
} }
std::unordered_map<vk::Format, vk::FormatProperties> GetFormatProperties(
vk::PhysicalDevice physical) {
std::unordered_map<vk::Format, vk::FormatProperties> format_properties;
for (const auto& format : LiverpoolToVK::GetAllFormats()) {
format_properties.emplace(format, physical.getFormatProperties(format));
}
return format_properties;
}
std::string GetReadableVersion(u32 version) { std::string GetReadableVersion(u32 version) {
return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
VK_VERSION_PATCH(version)); VK_VERSION_PATCH(version));
@ -93,6 +103,7 @@ Instance::Instance(Frontend::WindowSDL& window, s32 physical_device_index,
} }
available_extensions = GetSupportedExtensions(physical_device); available_extensions = GetSupportedExtensions(physical_device);
format_properties = GetFormatProperties(physical_device);
properties = physical_device.getProperties(); properties = physical_device.getProperties();
CollectDeviceParameters(); CollectDeviceParameters();
ASSERT_MSG(properties.apiVersion >= TargetVulkanApiVersion, ASSERT_MSG(properties.apiVersion >= TargetVulkanApiVersion,
@ -102,6 +113,22 @@ Instance::Instance(Frontend::WindowSDL& window, s32 physical_device_index,
CreateDevice(); CreateDevice();
CollectToolingInfo(); CollectToolingInfo();
// Check and log format support details.
for (const auto& key : format_properties | std::views::keys) {
const auto format = key;
if (!IsFormatSupported(format)) {
const auto alternative = GetAlternativeFormat(format);
if (IsFormatSupported(alternative)) {
LOG_WARNING(Render_Vulkan, "Format {} is not supported, falling back to {}",
vk::to_string(format), vk::to_string(alternative));
} else {
LOG_ERROR(Render_Vulkan,
"Format {} is not supported and no suitable alternative is supported.",
vk::to_string(format));
}
}
}
} }
Instance::~Instance() { Instance::~Instance() {
@ -303,7 +330,7 @@ bool Instance::CreateDevice() {
vk::TimeDomainEXT::eClockMonotonicRaw) != time_domains.cend(); vk::TimeDomainEXT::eClockMonotonicRaw) != time_domains.cend();
#else #else
// Tracy limitation means only Windows and Linux can use host time domain. // Tracy limitation means only Windows and Linux can use host time domain.
// See https://github.com/shadps4-emu/tracy/blob/c6d779d78508514102fbe1b8eb28bda10d95bb2a/public/tracy/TracyVulkan.hpp#L384-L389 // https://github.com/shadps4-emu/tracy/blob/c6d779d78508514102fbe1b8eb28bda10d95bb2a/public/tracy/TracyVulkan.hpp#L384-L389
const bool has_host_time_domain = false; const bool has_host_time_domain = false;
#endif #endif
if (has_host_time_domain) { if (has_host_time_domain) {
@ -377,4 +404,52 @@ void Instance::CollectToolingInfo() {
} }
} }
bool Instance::IsFormatSupported(const vk::Format format) const {
if (format == vk::Format::eUndefined) [[unlikely]] {
return true;
}
const auto it = format_properties.find(format);
if (it == format_properties.end()) {
UNIMPLEMENTED_MSG("Properties of format {} have not been queried.", vk::to_string(format));
}
constexpr vk::FormatFeatureFlags optimal_flags = vk::FormatFeatureFlagBits::eTransferSrc |
vk::FormatFeatureFlagBits::eTransferDst |
vk::FormatFeatureFlagBits::eSampledImage;
return (it->second.optimalTilingFeatures & optimal_flags) == optimal_flags;
}
vk::Format Instance::GetAlternativeFormat(const vk::Format format) const {
if (format == vk::Format::eB5G6R5UnormPack16) {
return vk::Format::eR5G6B5UnormPack16;
}
return format;
}
vk::Format Instance::GetSupportedFormat(const vk::Format format) const {
if (IsFormatSupported(format)) [[likely]] {
return format;
}
const vk::Format alternative = GetAlternativeFormat(format);
if (IsFormatSupported(alternative)) [[likely]] {
return alternative;
}
return format;
}
vk::ComponentMapping Instance::GetSupportedComponentSwizzle(vk::Format format,
vk::ComponentMapping swizzle) const {
if (IsFormatSupported(format)) [[likely]] {
return swizzle;
}
vk::ComponentMapping supported_swizzle = swizzle;
if (format == vk::Format::eB5G6R5UnormPack16) {
// B5G6R5 -> R5G6B5
std::swap(supported_swizzle.r, supported_swizzle.b);
}
return supported_swizzle;
}
} // namespace Vulkan } // namespace Vulkan

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <span> #include <span>
#include <unordered_map>
#include "video_core/renderer_vulkan/vk_platform.h" #include "video_core/renderer_vulkan/vk_platform.h"
@ -34,6 +35,13 @@ public:
/// Returns a formatted string for the driver version /// Returns a formatted string for the driver version
std::string GetDriverVersionName(); std::string GetDriverVersionName();
/// Gets a compatibility format if the format is not supported.
[[nodiscard]] vk::Format GetSupportedFormat(vk::Format format) const;
/// Re-orders a component swizzle for format compatibility, if needed.
[[nodiscard]] vk::ComponentMapping GetSupportedComponentSwizzle(
vk::Format format, vk::ComponentMapping swizzle) const;
/// Returns the Vulkan instance /// Returns the Vulkan instance
vk::Instance GetInstance() const { vk::Instance GetInstance() const {
return *instance; return *instance;
@ -211,6 +219,12 @@ private:
void CollectDeviceParameters(); void CollectDeviceParameters();
void CollectToolingInfo(); void CollectToolingInfo();
/// Determines if a format is supported.
[[nodiscard]] bool IsFormatSupported(vk::Format format) const;
/// Gets a commonly available alternative for an unsupported pixel format.
vk::Format GetAlternativeFormat(const vk::Format format) const;
private: private:
vk::DynamicLoader dl{VULKAN_LIBRARY_NAME}; vk::DynamicLoader dl{VULKAN_LIBRARY_NAME};
vk::UniqueInstance instance; vk::UniqueInstance instance;
@ -226,6 +240,7 @@ private:
vk::Queue graphics_queue; vk::Queue graphics_queue;
std::vector<vk::PhysicalDevice> physical_devices; std::vector<vk::PhysicalDevice> physical_devices;
std::vector<std::string> available_extensions; std::vector<std::string> available_extensions;
std::unordered_map<vk::Format, vk::FormatProperties> format_properties;
TracyVkCtx profiler_context{}; TracyVkCtx profiler_context{};
u32 queue_family_index{0}; u32 queue_family_index{0};
bool image_view_reinterpretation{true}; bool image_view_reinterpretation{true};

View File

@ -142,7 +142,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
const vk::ImageCreateInfo image_ci = { const vk::ImageCreateInfo image_ci = {
.flags = flags, .flags = flags,
.imageType = info.type, .imageType = info.type,
.format = info.pixel_format, .format = instance->GetSupportedFormat(info.pixel_format),
.extent{ .extent{
.width = info.size.width, .width = info.size.width,
.height = info.size.height, .height = info.size.height,

View File

@ -89,8 +89,8 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
.pNext = usage_override ? &usage_ci : nullptr, .pNext = usage_override ? &usage_ci : nullptr,
.image = image.image, .image = image.image,
.viewType = info.type, .viewType = info.type,
.format = format, .format = instance.GetSupportedFormat(format),
.components = info.mapping, .components = instance.GetSupportedComponentSwizzle(format, info.mapping),
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = aspect,
.baseMipLevel = 0U, .baseMipLevel = 0U,