Add fallback system for unsupported pixel formats.
This commit is contained in:
parent
35d629a730
commit
175ffe8ce3
|
@ -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 &&
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue