[Vulkan] Float controls properties

This commit is contained in:
Triang3l 2020-11-15 15:08:50 +03:00
parent 8febf02a39
commit 715d614f5e
4 changed files with 149 additions and 11 deletions

View File

@ -28,7 +28,8 @@ SpirvShaderTranslator::Features::Features(bool all)
max_storage_buffer_range(all ? UINT32_MAX : (128 * 1024 * 1024)), max_storage_buffer_range(all ? UINT32_MAX : (128 * 1024 * 1024)),
clip_distance(all), clip_distance(all),
cull_distance(all), cull_distance(all),
float_controls(all) {} signed_zero_inf_nan_preserve_float32(all),
denorm_flush_to_zero_float32(all) {}
SpirvShaderTranslator::Features::Features( SpirvShaderTranslator::Features::Features(
const ui::vulkan::VulkanProvider& provider) const ui::vulkan::VulkanProvider& provider)
@ -48,8 +49,18 @@ SpirvShaderTranslator::Features::Features(
} else { } else {
spirv_version = spv::Spv_1_0; spirv_version = spv::Spv_1_0;
} }
float_controls = spirv_version >= spv::Spv_1_4 || if (spirv_version >= spv::Spv_1_4 ||
device_extensions.khr_shader_float_controls; device_extensions.khr_shader_float_controls) {
const VkPhysicalDeviceFloatControlsPropertiesKHR&
float_controls_properties = provider.device_float_controls_properties();
signed_zero_inf_nan_preserve_float32 =
bool(float_controls_properties.shaderSignedZeroInfNanPreserveFloat32);
denorm_flush_to_zero_float32 =
bool(float_controls_properties.shaderDenormFlushToZeroFloat32);
} else {
signed_zero_inf_nan_preserve_float32 = false;
denorm_flush_to_zero_float32 = false;
}
} }
SpirvShaderTranslator::SpirvShaderTranslator(const Features& features) SpirvShaderTranslator::SpirvShaderTranslator(const Features& features)
@ -82,7 +93,8 @@ void SpirvShaderTranslator::StartTranslation() {
builder_->addCapability(IsSpirvTessEvalShader() ? spv::CapabilityTessellation builder_->addCapability(IsSpirvTessEvalShader() ? spv::CapabilityTessellation
: spv::CapabilityShader); : spv::CapabilityShader);
if (features_.spirv_version < spv::Spv_1_4) { if (features_.spirv_version < spv::Spv_1_4) {
if (features_.float_controls) { if (features_.signed_zero_inf_nan_preserve_float32 ||
features_.denorm_flush_to_zero_float32) {
builder_->addExtension("SPV_KHR_float_controls"); builder_->addExtension("SPV_KHR_float_controls");
} }
} }
@ -511,21 +523,21 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
? spv::ExecutionModelTessellationEvaluation ? spv::ExecutionModelTessellationEvaluation
: spv::ExecutionModelVertex; : spv::ExecutionModelVertex;
} }
// TODO(Triang3l): Re-enable float controls when if (features_.denorm_flush_to_zero_float32) {
// VkPhysicalDeviceFloatControlsPropertiesKHR are handled.
/* if (features_.float_controls) {
// Flush to zero, similar to the real hardware, also for things like Shader // Flush to zero, similar to the real hardware, also for things like Shader
// Model 3 multiplication emulation. // Model 3 multiplication emulation.
builder_->addCapability(spv::CapabilityDenormFlushToZero); builder_->addCapability(spv::CapabilityDenormFlushToZero);
builder_->addExecutionMode(function_main_, builder_->addExecutionMode(function_main_,
spv::ExecutionModeDenormFlushToZero, 32); spv::ExecutionModeDenormFlushToZero, 32);
}
if (features_.signed_zero_inf_nan_preserve_float32) {
// Signed zero used to get VFACE from ps_param_gen, also special behavior // Signed zero used to get VFACE from ps_param_gen, also special behavior
// for infinity in certain instructions (such as logarithm, reciprocal, // for infinity in certain instructions (such as logarithm, reciprocal,
// muls_prev2). // muls_prev2).
builder_->addCapability(spv::CapabilitySignedZeroInfNanPreserve); builder_->addCapability(spv::CapabilitySignedZeroInfNanPreserve);
builder_->addExecutionMode(function_main_, builder_->addExecutionMode(function_main_,
spv::ExecutionModeSignedZeroInfNanPreserve, 32); spv::ExecutionModeSignedZeroInfNanPreserve, 32);
} */ }
spv::Instruction* entry_point = spv::Instruction* entry_point =
builder_->addEntryPoint(execution_model, function_main_, "main"); builder_->addEntryPoint(execution_model, function_main_, "main");
for (spv::Id interface_id : main_interface_) { for (spv::Id interface_id : main_interface_) {

View File

@ -92,7 +92,8 @@ class SpirvShaderTranslator : public ShaderTranslator {
uint32_t max_storage_buffer_range; uint32_t max_storage_buffer_range;
bool clip_distance; bool clip_distance;
bool cull_distance; bool cull_distance;
bool float_controls; bool signed_zero_inf_nan_preserve_float32;
bool denorm_flush_to_zero_float32;
}; };
SpirvShaderTranslator(const Features& features); SpirvShaderTranslator(const Features& features);

View File

@ -125,6 +125,12 @@ bool VulkanProvider::Initialize() {
library_functions_loaded &= library_functions_loaded &=
(lfn_.vkCreateInstance = PFN_vkCreateInstance(lfn_.vkGetInstanceProcAddr( (lfn_.vkCreateInstance = PFN_vkCreateInstance(lfn_.vkGetInstanceProcAddr(
VK_NULL_HANDLE, "vkCreateInstance"))) != nullptr; VK_NULL_HANDLE, "vkCreateInstance"))) != nullptr;
library_functions_loaded &=
(lfn_.vkEnumerateInstanceExtensionProperties =
PFN_vkEnumerateInstanceExtensionProperties(
lfn_.vkGetInstanceProcAddr(
VK_NULL_HANDLE,
"vkEnumerateInstanceExtensionProperties"))) != nullptr;
if (!library_functions_loaded) { if (!library_functions_loaded) {
XELOGE( XELOGE(
"Failed to get Vulkan library function pointers via " "Failed to get Vulkan library function pointers via "
@ -144,11 +150,58 @@ bool VulkanProvider::Initialize() {
VK_SUCCESS) { VK_SUCCESS) {
instance_api_version = VK_API_VERSION_1_0; instance_api_version = VK_API_VERSION_1_0;
} }
XELOGVK("Vulkan instance version {}.{}.{}", XELOGVK("Vulkan instance version: {}.{}.{}",
VK_VERSION_MAJOR(instance_api_version), VK_VERSION_MAJOR(instance_api_version),
VK_VERSION_MINOR(instance_api_version), VK_VERSION_MINOR(instance_api_version),
VK_VERSION_PATCH(instance_api_version)); VK_VERSION_PATCH(instance_api_version));
// Get the instance extensions.
std::vector<VkExtensionProperties> instance_extension_properties;
VkResult instance_extensions_enumerate_result;
for (;;) {
uint32_t instance_extension_count =
uint32_t(instance_extension_properties.size());
bool instance_extensions_was_empty = !instance_extension_count;
instance_extensions_enumerate_result =
lfn_.vkEnumerateInstanceExtensionProperties(
nullptr, &instance_extension_count,
instance_extensions_was_empty
? nullptr
: instance_extension_properties.data());
// If the original extension count was 0 (first call), SUCCESS is
// returned, not INCOMPLETE.
if (instance_extensions_enumerate_result == VK_SUCCESS ||
instance_extensions_enumerate_result == VK_INCOMPLETE) {
instance_extension_properties.resize(instance_extension_count);
if (instance_extensions_enumerate_result == VK_SUCCESS &&
(!instance_extensions_was_empty || !instance_extension_count)) {
break;
}
} else {
break;
}
}
if (instance_extensions_enumerate_result != VK_SUCCESS) {
instance_extension_properties.clear();
}
std::memset(&instance_extensions_, 0, sizeof(instance_extensions_));
if (instance_api_version >= VK_MAKE_VERSION(1, 1, 0)) {
instance_extensions_.khr_get_physical_device_properties2 = true;
}
for (const VkExtensionProperties& instance_extension :
instance_extension_properties) {
const char* instance_extension_name = instance_extension.extensionName;
if (!instance_extensions_.khr_get_physical_device_properties2 &&
!std::strcmp(instance_extension_name,
"VK_KHR_get_physical_device_properties2")) {
instance_extensions_.khr_get_physical_device_properties2 = true;
}
}
XELOGVK("Vulkan instance extensions:");
XELOGVK(
"* VK_KHR_get_physical_device_properties2: {}",
instance_extensions_.khr_get_physical_device_properties2 ? "yes" : "no");
// Create the instance. // Create the instance.
std::vector<const char*> instance_extensions_enabled; std::vector<const char*> instance_extensions_enabled;
instance_extensions_enabled.push_back("VK_KHR_surface"); instance_extensions_enabled.push_back("VK_KHR_surface");
@ -157,6 +210,12 @@ bool VulkanProvider::Initialize() {
#elif XE_PLATFORM_WIN32 #elif XE_PLATFORM_WIN32
instance_extensions_enabled.push_back("VK_KHR_win32_surface"); instance_extensions_enabled.push_back("VK_KHR_win32_surface");
#endif #endif
if (instance_api_version < VK_MAKE_VERSION(1, 1, 0)) {
if (instance_extensions_.khr_get_physical_device_properties2) {
instance_extensions_enabled.push_back(
"VK_KHR_get_physical_device_properties2");
}
}
VkApplicationInfo application_info; VkApplicationInfo application_info;
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
application_info.pNext = nullptr; application_info.pNext = nullptr;
@ -205,11 +264,16 @@ bool VulkanProvider::Initialize() {
} }
// Get instance functions. // Get instance functions.
std::memset(&ifn_, 0, sizeof(ifn_));
bool instance_functions_loaded = true; bool instance_functions_loaded = true;
#define XE_VULKAN_LOAD_IFN(name) \ #define XE_VULKAN_LOAD_IFN(name) \
instance_functions_loaded &= \ instance_functions_loaded &= \
(ifn_.name = PFN_##name( \ (ifn_.name = PFN_##name( \
lfn_.vkGetInstanceProcAddr(instance_, #name))) != nullptr; lfn_.vkGetInstanceProcAddr(instance_, #name))) != nullptr;
#define XE_VULKAN_LOAD_IFN_SYMBOL(name, symbol) \
instance_functions_loaded &= \
(ifn_.name = PFN_##name( \
lfn_.vkGetInstanceProcAddr(instance_, symbol))) != nullptr;
XE_VULKAN_LOAD_IFN(vkCreateDevice); XE_VULKAN_LOAD_IFN(vkCreateDevice);
XE_VULKAN_LOAD_IFN(vkDestroyDevice); XE_VULKAN_LOAD_IFN(vkDestroyDevice);
XE_VULKAN_LOAD_IFN(vkDestroySurfaceKHR); XE_VULKAN_LOAD_IFN(vkDestroySurfaceKHR);
@ -229,6 +293,13 @@ bool VulkanProvider::Initialize() {
#elif XE_PLATFORM_WIN32 #elif XE_PLATFORM_WIN32
XE_VULKAN_LOAD_IFN(vkCreateWin32SurfaceKHR); XE_VULKAN_LOAD_IFN(vkCreateWin32SurfaceKHR);
#endif #endif
if (instance_extensions_.khr_get_physical_device_properties2) {
XE_VULKAN_LOAD_IFN_SYMBOL(vkGetPhysicalDeviceProperties2KHR,
(instance_api_version >= VK_MAKE_VERSION(1, 1, 0))
? "vkGetPhysicalDeviceProperties2"
: "vkGetPhysicalDeviceProperties2KHR");
}
#undef XE_VULKAN_LOAD_IFN_SYMBOL
#undef XE_VULKAN_LOAD_IFN #undef XE_VULKAN_LOAD_IFN
if (!instance_functions_loaded) { if (!instance_functions_loaded) {
XELOGE("Failed to get Vulkan instance function pointers"); XELOGE("Failed to get Vulkan instance function pointers");
@ -470,6 +541,32 @@ bool VulkanProvider::Initialize() {
"support"); "support");
return false; return false;
} }
// Get additional device properties.
std::memset(&device_float_controls_properties_, 0,
sizeof(device_float_controls_properties_));
if (instance_extensions_.khr_get_physical_device_properties2) {
VkPhysicalDeviceProperties2KHR device_properties_2;
device_properties_2.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
device_properties_2.pNext = nullptr;
VkPhysicalDeviceProperties2KHR* device_properties_2_last =
&device_properties_2;
if (device_extensions_.khr_shader_float_controls) {
device_float_controls_properties_.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR;
device_float_controls_properties_.pNext = nullptr;
device_properties_2_last->pNext = &device_float_controls_properties_;
device_properties_2_last =
reinterpret_cast<VkPhysicalDeviceProperties2KHR*>(
&device_float_controls_properties_);
}
if (device_properties_2_last != &device_properties_2) {
ifn_.vkGetPhysicalDeviceProperties2KHR(physical_device_,
&device_properties_2);
}
}
XELOGVK( XELOGVK(
"Vulkan device: {} (vendor {:04X}, device {:04X}, driver {:08X}, API " "Vulkan device: {} (vendor {:04X}, device {:04X}, driver {:08X}, API "
"{}.{}.{})", "{}.{}.{})",
@ -487,6 +584,17 @@ bool VulkanProvider::Initialize() {
device_extensions_.khr_shader_float_controls ? "yes" : "no"); device_extensions_.khr_shader_float_controls ? "yes" : "no");
XELOGVK("* VK_KHR_spirv_1_4: {}", XELOGVK("* VK_KHR_spirv_1_4: {}",
device_extensions_.khr_spirv_1_4 ? "yes" : "no"); device_extensions_.khr_spirv_1_4 ? "yes" : "no");
if (device_extensions_.khr_shader_float_controls) {
XELOGVK(
"* Signed zero, inf, nan preserve for float32: {}",
device_float_controls_properties_.shaderSignedZeroInfNanPreserveFloat32
? "yes"
: "no");
XELOGVK("* Denorm flush to zero for float32: {}",
device_float_controls_properties_.shaderDenormFlushToZeroFloat32
? "yes"
: "no");
}
// TODO(Triang3l): Report properties, features. // TODO(Triang3l): Report properties, features.
// Create the device. // Create the device.

View File

@ -57,12 +57,21 @@ class VulkanProvider : public GraphicsProvider {
PFN_vkDestroyInstance vkDestroyInstance; PFN_vkDestroyInstance vkDestroyInstance;
// From vkGetInstanceProcAddr. // From vkGetInstanceProcAddr.
PFN_vkCreateInstance vkCreateInstance; PFN_vkCreateInstance vkCreateInstance;
PFN_vkEnumerateInstanceExtensionProperties
vkEnumerateInstanceExtensionProperties;
struct { struct {
PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
} v_1_1; } v_1_1;
}; };
const LibraryFunctions& lfn() const { return lfn_; } const LibraryFunctions& lfn() const { return lfn_; }
struct InstanceExtensions {
// Core since 1.1.0.
bool khr_get_physical_device_properties2;
};
const InstanceExtensions& instance_extensions() const {
return instance_extensions_;
}
VkInstance instance() const { return instance_; } VkInstance instance() const { return instance_; }
struct InstanceFunctions { struct InstanceFunctions {
PFN_vkCreateDevice vkCreateDevice; PFN_vkCreateDevice vkCreateDevice;
@ -75,6 +84,8 @@ class VulkanProvider : public GraphicsProvider {
PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
// VK_KHR_get_physical_device_properties2 or 1.1.0.
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
PFN_vkGetPhysicalDeviceQueueFamilyProperties PFN_vkGetPhysicalDeviceQueueFamilyProperties
vkGetPhysicalDeviceQueueFamilyProperties; vkGetPhysicalDeviceQueueFamilyProperties;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
@ -129,6 +140,10 @@ class VulkanProvider : public GraphicsProvider {
uint32_t queue_family_graphics_compute() const { uint32_t queue_family_graphics_compute() const {
return queue_family_graphics_compute_; return queue_family_graphics_compute_;
} }
const VkPhysicalDeviceFloatControlsPropertiesKHR&
device_float_controls_properties() const {
return device_float_controls_properties_;
}
VkDevice device() const { return device_; } VkDevice device() const { return device_; }
struct DeviceFunctions { struct DeviceFunctions {
@ -262,8 +277,9 @@ class VulkanProvider : public GraphicsProvider {
LibraryFunctions lfn_ = {}; LibraryFunctions lfn_ = {};
InstanceExtensions instance_extensions_;
VkInstance instance_ = VK_NULL_HANDLE; VkInstance instance_ = VK_NULL_HANDLE;
InstanceFunctions ifn_ = {}; InstanceFunctions ifn_;
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
VkPhysicalDeviceProperties device_properties_; VkPhysicalDeviceProperties device_properties_;
@ -274,6 +290,7 @@ class VulkanProvider : public GraphicsProvider {
uint32_t memory_types_host_coherent_; uint32_t memory_types_host_coherent_;
uint32_t memory_types_host_cached_; uint32_t memory_types_host_cached_;
uint32_t queue_family_graphics_compute_; uint32_t queue_family_graphics_compute_;
VkPhysicalDeviceFloatControlsPropertiesKHR device_float_controls_properties_;
VkDevice device_ = VK_NULL_HANDLE; VkDevice device_ = VK_NULL_HANDLE;
DeviceFunctions dfn_ = {}; DeviceFunctions dfn_ = {};