mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-11 13:36:24 +02:00
Vulkan: Add support for listing all the available surface formats in system info.
Enabling the EXT_swapchain_colorspace extension lets the driver expose all the formats it really supports. Used this to discover that my Galaxy S21 supports Display-P3 which is a wider gamut than sRGB. Might be able to do some color boosting mode for fun. Or, use this stuff to play around with HDR?
This commit is contained in:
1 parent
0e2f5d66b6
commit
8dc8fae16d
5 files changed
+108
-24
No files matched your search
@@ -151,12 +151,15 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
// Temporary hack for libretro. For some reason, when we try to load the functions from this extension,
|
||||
// we get null pointers when running libretro. Quite strange.
|
||||
#if !defined(__LIBRETRO__)
|
||||
if (IsInstanceExtensionAvailable(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
|
||||
instance_extensions_enabled_.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||
if (EnableInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
|
||||
extensionsLookup_.KHR_get_physical_device_properties2 = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (EnableInstanceExtension(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME)) {
|
||||
extensionsLookup_.EXT_swapchain_colorspace = true;
|
||||
}
|
||||
|
||||
// Validate that all the instance extensions we ask for are actually available.
|
||||
for (auto ext : instance_extensions_enabled_) {
|
||||
if (!IsInstanceExtensionAvailable(ext))
|
||||
@@ -615,6 +618,16 @@ bool VulkanContext::EnableDeviceExtension(const char *extension) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VulkanContext::EnableInstanceExtension(const char *extension) {
|
||||
for (auto &iter : instance_extension_properties_) {
|
||||
if (!strcmp(iter.extensionName, extension)) {
|
||||
instance_extensions_enabled_.push_back(extension);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VkResult VulkanContext::CreateDevice() {
|
||||
if (!init_error_.empty() || physical_device_ < 0) {
|
||||
ERROR_LOG(G3D, "Vulkan init failed: %s", init_error_.c_str());
|
||||
@@ -923,8 +936,8 @@ bool VulkanContext::ChooseQueue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> surfFormats(formatCount);
|
||||
res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, surfFormats.data());
|
||||
surfFormats_.resize(formatCount);
|
||||
res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, surfFormats_.data());
|
||||
_dbg_assert_(res == VK_SUCCESS);
|
||||
if (res != VK_SUCCESS) {
|
||||
return false;
|
||||
@@ -932,24 +945,23 @@ bool VulkanContext::ChooseQueue() {
|
||||
// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
|
||||
// the surface has no preferred format. Otherwise, at least one
|
||||
// supported format will be returned.
|
||||
if (formatCount == 0 || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) {
|
||||
if (formatCount == 0 || (formatCount == 1 && surfFormats_[0].format == VK_FORMAT_UNDEFINED)) {
|
||||
INFO_LOG(G3D, "swapchain_format: Falling back to B8G8R8A8_UNORM");
|
||||
swapchainFormat_ = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
} else {
|
||||
swapchainFormat_ = VK_FORMAT_UNDEFINED;
|
||||
for (uint32_t i = 0; i < formatCount; ++i) {
|
||||
if (surfFormats[i].colorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR) {
|
||||
if (surfFormats_[i].colorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (surfFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM || surfFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) {
|
||||
swapchainFormat_ = surfFormats[i].format;
|
||||
if (surfFormats_[i].format == VK_FORMAT_B8G8R8A8_UNORM || surfFormats_[i].format == VK_FORMAT_R8G8B8A8_UNORM) {
|
||||
swapchainFormat_ = surfFormats_[i].format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (swapchainFormat_ == VK_FORMAT_UNDEFINED) {
|
||||
// Okay, take the first one then.
|
||||
swapchainFormat_ = surfFormats[0].format;
|
||||
swapchainFormat_ = surfFormats_[0].format;
|
||||
}
|
||||
INFO_LOG(G3D, "swapchain_format: %d (/%d)", swapchainFormat_, formatCount);
|
||||
}
|
||||
@@ -1537,3 +1549,65 @@ std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props) {
|
||||
uint32_t branch = VK_VERSION_PATCH(props.driverVersion);
|
||||
return StringFromFormat("%d.%d.%d (%08x)", major, minor, branch, props.driverVersion);
|
||||
}
|
||||
|
||||
// Mainly just the formats seen on gpuinfo.org for swapchains, as this function is only used for listing
|
||||
// those in the UI. Also depth buffers that we used in one place.
|
||||
// Might add more in the future if we find more uses for this.
|
||||
const char *VulkanFormatToString(VkFormat format) {
|
||||
switch (format) {
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: return "A1R5G5B5_UNORM_PACK16";
|
||||
case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return "A2B10G10R10_UNORM_PACK32";
|
||||
case VK_FORMAT_A8B8G8R8_SNORM_PACK32: return "A8B8G8R8_SNORM_PACK32";
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32: return "A8B8G8R8_SRGB_PACK32";
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: return "A8B8G8R8_UNORM_PACK32";
|
||||
case VK_FORMAT_B10G11R11_UFLOAT_PACK32: return "B10G11R11_UFLOAT_PACK32";
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: return "B4G4R4A4_UNORM_PACK16";
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: return "B5G5R5A1_UNORM_PACK16";
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16: return "B5G6R5_UNORM_PACK16";
|
||||
case VK_FORMAT_B8G8R8A8_SNORM: return "B8G8R8A8_SNORM";
|
||||
case VK_FORMAT_B8G8R8A8_SRGB: return "B8G8R8A8_SRGB";
|
||||
case VK_FORMAT_B8G8R8A8_UNORM: return "B8G8R8A8_UNORM";
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT: return "R16G16B16A16_SFLOAT";
|
||||
case VK_FORMAT_R16G16B16A16_SNORM: return "R16G16B16A16_SNORM";
|
||||
case VK_FORMAT_R16G16B16A16_UNORM: return "R16G16B16A16_UNORM";
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: return "R4G4B4A4_UNORM_PACK16";
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: return "R5G5B5A1_UNORM_PACK16";
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16: return "R5G6B5_UNORM_PACK16";
|
||||
case VK_FORMAT_R8G8B8A8_SNORM: return "R8G8B8A8_SNORM";
|
||||
case VK_FORMAT_R8G8B8A8_SRGB: return "R8G8B8A8_SRGB";
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: return "R8G8B8A8_UNORM";
|
||||
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT: return "D24S8";
|
||||
case VK_FORMAT_D16_UNORM: return "D16";
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT: return "D16S8";
|
||||
case VK_FORMAT_D32_SFLOAT: return "D32f";
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT: return "D32fS8";
|
||||
case VK_FORMAT_S8_UINT: return "S8";
|
||||
case VK_FORMAT_UNDEFINED: return "UNDEFINED (BAD!)";
|
||||
|
||||
default: return "(format not added to string list)";
|
||||
}
|
||||
}
|
||||
|
||||
// I miss Rust where this is automatic :(
|
||||
const char *VulkanColorSpaceToString(VkColorSpaceKHR colorSpace) {
|
||||
switch (colorSpace) {
|
||||
case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: return "SRGB_NONLINEAR";
|
||||
case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT: return "DISPLAY_P3_NONLINEAR";
|
||||
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT: return "EXTENDED_SRGB_LINEAR";
|
||||
case VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT: return "DISPLAY_P3_LINEAR";
|
||||
case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT: return "DCI_P3_NONLINEAR";
|
||||
case VK_COLOR_SPACE_BT709_LINEAR_EXT: return "BT709_LINEAR";
|
||||
case VK_COLOR_SPACE_BT709_NONLINEAR_EXT: return "BT709_NONLINEAR";
|
||||
case VK_COLOR_SPACE_BT2020_LINEAR_EXT: return "BT2020_LINEAR";
|
||||
case VK_COLOR_SPACE_HDR10_ST2084_EXT: return "HDR10_ST2084";
|
||||
case VK_COLOR_SPACE_DOLBYVISION_EXT: return "DOLBYVISION";
|
||||
case VK_COLOR_SPACE_HDR10_HLG_EXT: return "HDR10_HLG";
|
||||
case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT: return "ADOBERGB_LINEAR";
|
||||
case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT: return "ADOBERGB_NONLINEAR";
|
||||
case VK_COLOR_SPACE_PASS_THROUGH_EXT: return "PASS_THROUGH";
|
||||
case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT: return "EXTENDED_SRGB_NONLINEAR";
|
||||
case VK_COLOR_SPACE_DISPLAY_NATIVE_AMD: return "DISPLAY_NATIVE_AMD";
|
||||
default: return "(unknown)";
|
||||
}
|
||||
}
|
||||
@@ -171,6 +171,7 @@ public:
|
||||
int GetBestPhysicalDevice();
|
||||
int GetPhysicalDeviceByName(std::string name);
|
||||
void ChooseDevice(int physical_device);
|
||||
bool EnableInstanceExtension(const char *extension);
|
||||
bool EnableDeviceExtension(const char *extension);
|
||||
VkResult CreateDevice();
|
||||
|
||||
@@ -338,6 +339,10 @@ public:
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
const std::vector<VkSurfaceFormatKHR> &SurfaceFormats() {
|
||||
return surfFormats_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool ChooseQueue();
|
||||
|
||||
@@ -420,6 +425,7 @@ private:
|
||||
PhysicalDeviceFeatures deviceFeatures_;
|
||||
|
||||
VkSurfaceCapabilitiesKHR surfCapabilities_{};
|
||||
std::vector<VkSurfaceFormatKHR> surfFormats_{};
|
||||
|
||||
std::vector<VkCommandBuffer> cmdQueue_;
|
||||
|
||||
@@ -445,6 +451,9 @@ enum class GLSLVariant {
|
||||
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *sourceCode, GLSLVariant variant, std::vector<uint32_t> &spirv, std::string *errorMessage);
|
||||
|
||||
const char *VulkanResultToString(VkResult res);
|
||||
const char *VulkanColorSpaceToString(VkColorSpaceKHR colorSpace);
|
||||
const char *VulkanFormatToString(VkFormat format);
|
||||
|
||||
std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props);
|
||||
|
||||
// Simple heuristic.
|
||||
|
||||
@@ -238,6 +238,7 @@ struct VulkanExtensions {
|
||||
bool KHR_get_physical_device_properties2;
|
||||
bool KHR_depth_stencil_resolve;
|
||||
bool EXT_shader_stencil_export;
|
||||
bool EXT_swapchain_colorspace;
|
||||
// bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers.
|
||||
};
|
||||
|
||||
|
||||
@@ -1395,20 +1395,6 @@ void AddFeature(std::vector<std::string> &features, const char *name, VkBool32 a
|
||||
features.push_back(buf);
|
||||
}
|
||||
|
||||
// Limited to depth buffer formats as that's what we need right now.
|
||||
static const char *VulkanFormatToString(VkFormat fmt) {
|
||||
switch (fmt) {
|
||||
case VkFormat::VK_FORMAT_D24_UNORM_S8_UINT: return "D24S8";
|
||||
case VkFormat::VK_FORMAT_D16_UNORM: return "D16";
|
||||
case VkFormat::VK_FORMAT_D16_UNORM_S8_UINT: return "D16S8";
|
||||
case VkFormat::VK_FORMAT_D32_SFLOAT: return "D32f";
|
||||
case VkFormat::VK_FORMAT_D32_SFLOAT_S8_UINT: return "D32fS8";
|
||||
case VkFormat::VK_FORMAT_S8_UINT: return "S8";
|
||||
case VkFormat::VK_FORMAT_UNDEFINED: return "UNDEFINED (BAD!)";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> VKContext::GetFeatureList() const {
|
||||
const VkPhysicalDeviceFeatures &available = vulkan_->GetDeviceFeatures().available;
|
||||
const VkPhysicalDeviceFeatures &enabled = vulkan_->GetDeviceFeatures().enabled;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "Common/System/NativeApp.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/GPU/OpenGL/GLFeatures.h"
|
||||
#include "Common/GPU/Vulkan/VulkanContext.h"
|
||||
#include "Common/File/AndroidStorage.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Net/HTTPClient.h"
|
||||
@@ -55,6 +56,7 @@
|
||||
#include "UI/ControlMappingScreen.h"
|
||||
#include "UI/GameSettingsScreen.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Common/CommonWindows.h"
|
||||
// Want to avoid including the full header here as it includes d3dx.h
|
||||
@@ -720,6 +722,18 @@ void SystemInfoScreen::CreateViews() {
|
||||
for (auto &feature : features) {
|
||||
gpuExtensions->Add(new TextView(feature, new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true);
|
||||
}
|
||||
|
||||
// Vulkan specific code here, can't be bothered to abstract.
|
||||
gpuExtensions->Add(new ItemHeader(si->T("Display Color Formats")));
|
||||
VulkanContext *vk = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
|
||||
if (vk) {
|
||||
for (auto &format : vk->SurfaceFormats()) {
|
||||
std::string line = StringFromFormat("%s : %s", VulkanFormatToString(format.format), VulkanColorSpaceToString(format.colorSpace));
|
||||
gpuExtensions->Add(new TextView(line,
|
||||
new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true);
|
||||
}
|
||||
}
|
||||
|
||||
gpuExtensions->Add(new ItemHeader(si->T("Vulkan Extensions")));
|
||||
std::vector<std::string> extensions = draw->GetExtensionList();
|
||||
for (auto &extension : extensions) {
|
||||
|
||||
Reference in new issue
Block a user