From 2f344b7eb5527b2449f1ad0dc2a9e42ac2542b76 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 2 Oct 2020 21:14:03 -0700 Subject: Added device features to indicate support of 16-bit types --- .../VulkanUtilities/VulkanPhysicalDevice.hpp | 4 +- .../GraphicsEngineVulkan/src/EngineFactoryVk.cpp | 156 +++++++++++++++------ .../src/RenderDeviceVkImpl.cpp | 58 +++----- .../src/VulkanUtilities/VulkanPhysicalDevice.cpp | 23 ++- 4 files changed, 157 insertions(+), 84 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp index 215feb1a..848055eb 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp @@ -39,7 +39,9 @@ class VulkanPhysicalDevice public: struct ExtensionFeatures { - VkPhysicalDeviceMeshShaderFeaturesNV MeshShader = {}; + VkPhysicalDeviceMeshShaderFeaturesNV MeshShader = {}; + VkPhysicalDevice16BitStorageFeaturesKHR Storage16Bit = {}; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR ShaderFloat16Int8 = {}; }; public: diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index 5261235a..04bc3a1f 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -174,37 +174,49 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E VkPhysicalDeviceFeatures EnabledFeatures = {}; EnabledFeatures.fullDrawIndexUint32 = PhysicalDeviceFeatures.fullDrawIndexUint32; -#define ENABLE_FEATURE(Feature, RequestedState, FeatureName) \ - do \ - { \ - switch (RequestedState) \ - { \ - case DEVICE_FEATURE_STATE_DISABLED: \ - EnabledFeatures.Feature = VK_FALSE; \ - break; \ - case DEVICE_FEATURE_STATE_ENABLED: \ - { \ - if (PhysicalDeviceFeatures.Feature == VK_FALSE) \ - LOG_ERROR_AND_THROW(FeatureName, " not supported by this device"); \ - else \ - EnabledFeatures.Feature = VK_TRUE; \ - } \ - break; \ - case DEVICE_FEATURE_STATE_OPTIONAL: \ - EnabledFeatures.Feature = PhysicalDeviceFeatures.Feature; \ - break; \ - default: UNEXPECTED("Unexpected feature state"); \ - } \ + auto GetFeatureState = [&](DEVICE_FEATURE_STATE RequestedState, bool IsFeatureSupported, const char* FeatureName) // + { + switch (RequestedState) + { + case DEVICE_FEATURE_STATE_DISABLED: + return DEVICE_FEATURE_STATE_DISABLED; + + case DEVICE_FEATURE_STATE_ENABLED: + { + if (IsFeatureSupported) + return DEVICE_FEATURE_STATE_ENABLED; + else + LOG_ERROR_AND_THROW(FeatureName, " not supported by this device"); + } + + case DEVICE_FEATURE_STATE_OPTIONAL: + return IsFeatureSupported ? DEVICE_FEATURE_STATE_ENABLED : DEVICE_FEATURE_STATE_DISABLED; + + default: + UNEXPECTED("Unexpected feature state"); + return DEVICE_FEATURE_STATE_DISABLED; + } + }; + +#define ENABLE_FEATURE(vkFeature, State, FeatureName) \ + do \ + { \ + State = \ + GetFeatureState(State, PhysicalDeviceFeatures.vkFeature != VK_FALSE, FeatureName); \ + EnabledFeatures.vkFeature = \ + State == DEVICE_FEATURE_STATE_ENABLED ? VK_TRUE : VK_FALSE; \ } while (false) + auto ImageCubeArrayFeature = DEVICE_FEATURE_STATE_OPTIONAL; + auto SamplerAnisotropyFeature = DEVICE_FEATURE_STATE_OPTIONAL; // clang-format off ENABLE_FEATURE(geometryShader, EngineCI.Features.GeometryShaders, "Geometry shaders are"); ENABLE_FEATURE(tessellationShader, EngineCI.Features.Tessellation, "Tessellation is"); ENABLE_FEATURE(pipelineStatisticsQuery, EngineCI.Features.PipelineStatisticsQueries, "Pipeline statistics queries are"); ENABLE_FEATURE(occlusionQueryPrecise, EngineCI.Features.OcclusionQueries, "Occlusion queries are"); - ENABLE_FEATURE(imageCubeArray, DEVICE_FEATURE_STATE_OPTIONAL, "Image cube arrays"); + ENABLE_FEATURE(imageCubeArray, ImageCubeArrayFeature, "Image cube arrays are"); ENABLE_FEATURE(fillModeNonSolid, EngineCI.Features.WireframeFill, "Wireframe fill is"); - ENABLE_FEATURE(samplerAnisotropy, DEVICE_FEATURE_STATE_OPTIONAL, "Anisotropic texture filtering is"); + ENABLE_FEATURE(samplerAnisotropy, SamplerAnisotropyFeature, "Anisotropic texture filtering is"); ENABLE_FEATURE(depthBiasClamp, EngineCI.Features.DepthBiasClamp, "Depth bias clamp is"); ENABLE_FEATURE(depthClamp, EngineCI.Features.DepthClamp, "Depth clamp is"); ENABLE_FEATURE(independentBlend, EngineCI.Features.IndependentBlend, "Independent blend is"); @@ -226,37 +238,103 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E VK_KHR_MAINTENANCE1_EXTENSION_NAME // To allow negative viewport height }; + const auto& DeiceExtFeatures = PhysicalDevice->GetExtFeatures(); + +#define ENABLE_FEATURE(IsFeatureSupported, Feature, FeatureName) \ + do \ + { \ + EngineCI.Features.Feature = \ + GetFeatureState(EngineCI.Features.Feature, IsFeatureSupported, FeatureName); \ + } while (false) + + + auto MeshShaderFeats = DeiceExtFeatures.MeshShader; + ENABLE_FEATURE(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE, MeshShaders, "Mesh shaders are"); + + auto ShaderFloat16Int8 = DeiceExtFeatures.ShaderFloat16Int8; + ENABLE_FEATURE(ShaderFloat16Int8.shaderFloat16 != VK_FALSE, ShaderFloat16, "16-bit float shader operations are"); + + auto Storage16BitFeats = DeiceExtFeatures.Storage16Bit; + // clang-format off + ENABLE_FEATURE(Storage16BitFeats.storageBuffer16BitAccess != VK_FALSE, ResourceBuffer16BitAccess, "16-bit resoure buffer access is"); + ENABLE_FEATURE(Storage16BitFeats.uniformAndStorageBuffer16BitAccess != VK_FALSE, UniformBuffer16BitAccess, "16-bit uniform buffer access is"); + ENABLE_FEATURE(Storage16BitFeats.storageInputOutput16 != VK_FALSE, ShaderInputOutput16, "16-bit shader inputs/outputs are"); + // clang-format on +#undef FeatureSupport + + // To enable some device extensions you must enable instance extension VK_KHR_get_physical_device_properties2 // and add feature description to DeviceCreateInfo.pNext. const auto SupportsFeatures2 = Instance->IsExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - - // Enable mesh shader extension. - bool MeshShadersSupported = false; - VkPhysicalDeviceMeshShaderFeaturesNV MeshShaderFeats = {}; if (SupportsFeatures2) { void** NextExt = const_cast(&DeviceCreateInfo.pNext); if (EngineCI.Features.MeshShaders != DEVICE_FEATURE_STATE_DISABLED) { - MeshShaderFeats = PhysicalDevice->GetExtFeatures().MeshShader; - MeshShadersSupported = MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE; - if (PhysicalDevice->IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME) && MeshShadersSupported) - { - DeviceExtensions.push_back(VK_NV_MESH_SHADER_EXTENSION_NAME); - *NextExt = &MeshShaderFeats; - NextExt = &MeshShaderFeats.pNext; - } + VERIFY_EXPR(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE); + VERIFY(PhysicalDevice->IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME), + "VK_NV_mesh_shader extension must be supported as it has already been checked by VulkanPhysicalDevice and " + "both taskShader and meshShader features are TRUE"); + DeviceExtensions.push_back(VK_NV_MESH_SHADER_EXTENSION_NAME); + *NextExt = &MeshShaderFeats; + NextExt = &MeshShaderFeats.pNext; } + + if (EngineCI.Features.ShaderFloat16 != DEVICE_FEATURE_STATE_DISABLED) + { + VERIFY_EXPR(ShaderFloat16Int8.shaderFloat16 != VK_FALSE); + VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME), + "VK_KHR_shader_float16_int8 extension must be supported as it has already been checked by VulkanPhysicalDevice " + "and shaderFloat16 feature is TRUE"); + DeviceExtensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); + + *NextExt = &ShaderFloat16Int8; + NextExt = &ShaderFloat16Int8.pNext; + } + + // clang-format off + if (EngineCI.Features.ResourceBuffer16BitAccess != DEVICE_FEATURE_STATE_DISABLED || + EngineCI.Features.UniformBuffer16BitAccess != DEVICE_FEATURE_STATE_DISABLED || + EngineCI.Features.ShaderInputOutput16 != DEVICE_FEATURE_STATE_DISABLED) + // clang-format on + { + // clang-format off + VERIFY_EXPR(EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.storageBuffer16BitAccess != VK_FALSE); + VERIFY_EXPR(EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.uniformAndStorageBuffer16BitAccess != VK_FALSE); + VERIFY_EXPR(EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.storageInputOutput16 != VK_FALSE); + // clang-format on + + VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_16BIT_STORAGE_EXTENSION_NAME), + "VK_KHR_16bit_storage must be supported as it has already been checked by VulkanPhysicalDevice and at least one of " + "storageBuffer16BitAccess, uniformAndStorageBuffer16BitAccess, or storagePushConstant16 features is TRUE"); + DeviceExtensions.push_back(VK_KHR_16BIT_STORAGE_EXTENSION_NAME); + + // VK_KHR_16bit_storage extension requires VK_KHR_storage_buffer_storage_class extension. + // All required extensions for each extension in the VkDeviceCreateInfo::ppEnabledExtensionNames + // list must also be present in that list. + VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME), + "VK_KHR_storage_buffer_storage_class must be supported as it has already been checked by VulkanPhysicalDevice and at least one of " + "storageBuffer16BitAccess, uniformAndStorageBuffer16BitAccess, or storagePushConstant16 features is TRUE"); + DeviceExtensions.push_back(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME); + + if (EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED) + Storage16BitFeats.storageBuffer16BitAccess = VK_FALSE; + if (EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED) + Storage16BitFeats.uniformAndStorageBuffer16BitAccess = VK_FALSE; + if (EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED) + Storage16BitFeats.storageInputOutput16 = VK_FALSE; + + *NextExt = &Storage16BitFeats; + NextExt = &Storage16BitFeats.pNext; + } + *NextExt = nullptr; } - if (EngineCI.Features.MeshShaders == DEVICE_FEATURE_STATE_ENABLED && !MeshShadersSupported) - LOG_ERROR_AND_THROW("Mesh shaders are not supported by this device"); - // The actual state of Features.MeshShaders in device caps is set by RenderDeviceVkImpl #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 23, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 27, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data(); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 2d679e21..204aaa74 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -206,51 +206,27 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* for (Uint32 fmt = 1; fmt < m_TextureFormatsInfo.size(); ++fmt) m_TextureFormatsInfo[fmt].Supported = true; // We will test every format on a specific hardware device - auto& Features = m_DeviceCaps.Features; - const auto& vkExtFeatures = m_PhysicalDevice->GetExtFeatures(); - - // May be unused if extensions are disabled. - (void)(vkExtFeatures); - - const auto& vkEnabledFeatures = m_LogicalVkDevice->GetEnabledFeatures(); - - auto GetFeatureState = [](VkBool32 vkFeatureState) // - { - return vkFeatureState != VK_FALSE ? DEVICE_FEATURE_STATE_ENABLED : DEVICE_FEATURE_STATE_DISABLED; - }; - - Features.SeparablePrograms = DEVICE_FEATURE_STATE_ENABLED; - Features.IndirectRendering = DEVICE_FEATURE_STATE_ENABLED; - Features.WireframeFill = GetFeatureState(vkEnabledFeatures.fillModeNonSolid); - Features.MultithreadedResourceCreation = DEVICE_FEATURE_STATE_ENABLED; - Features.ComputeShaders = DEVICE_FEATURE_STATE_ENABLED; - Features.GeometryShaders = GetFeatureState(vkEnabledFeatures.geometryShader); - Features.Tessellation = GetFeatureState(vkEnabledFeatures.tessellationShader); - Features.BindlessResources = DEVICE_FEATURE_STATE_ENABLED; - Features.OcclusionQueries = GetFeatureState(vkEnabledFeatures.occlusionQueryPrecise); - Features.BinaryOcclusionQueries = DEVICE_FEATURE_STATE_ENABLED; - Features.TimestampQueries = DEVICE_FEATURE_STATE_ENABLED; - Features.DurationQueries = DEVICE_FEATURE_STATE_ENABLED; - Features.PipelineStatisticsQueries = GetFeatureState(vkEnabledFeatures.pipelineStatisticsQuery); - Features.DepthBiasClamp = GetFeatureState(vkEnabledFeatures.depthBiasClamp); - Features.DepthClamp = GetFeatureState(vkEnabledFeatures.depthClamp); - Features.IndependentBlend = GetFeatureState(vkEnabledFeatures.independentBlend); - Features.DualSourceBlend = GetFeatureState(vkEnabledFeatures.dualSrcBlend); - Features.MultiViewport = GetFeatureState(vkEnabledFeatures.multiViewport); - Features.TextureCompressionBC = GetFeatureState(vkEnabledFeatures.textureCompressionBC); - Features.VertexPipelineUAVWritesAndAtomics = GetFeatureState(vkEnabledFeatures.vertexPipelineStoresAndAtomics); - Features.PixelUAVWritesAndAtomics = GetFeatureState(vkEnabledFeatures.fragmentStoresAndAtomics); - Features.TextureUAVExtendedFormats = GetFeatureState(vkEnabledFeatures.shaderStorageImageExtendedFormats); - - // All devices that support mesh shaders also support task shaders, so it is not necessary to use two separate features. - Features.MeshShaders = GetFeatureState(EngineCI.Features.MeshShaders != DEVICE_FEATURE_STATE_DISABLED && vkExtFeatures.MeshShader.meshShader != VK_FALSE && vkExtFeatures.MeshShader.taskShader != VK_FALSE); + auto& Features = m_DeviceCaps.Features; + Features = EngineCI.Features; + + // The following features are always enabled + Features.SeparablePrograms = DEVICE_FEATURE_STATE_ENABLED; + Features.IndirectRendering = DEVICE_FEATURE_STATE_ENABLED; + Features.MultithreadedResourceCreation = DEVICE_FEATURE_STATE_ENABLED; + Features.ComputeShaders = DEVICE_FEATURE_STATE_ENABLED; + Features.BindlessResources = DEVICE_FEATURE_STATE_ENABLED; + Features.BinaryOcclusionQueries = DEVICE_FEATURE_STATE_ENABLED; + Features.TimestampQueries = DEVICE_FEATURE_STATE_ENABLED; + Features.DurationQueries = DEVICE_FEATURE_STATE_ENABLED; #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 23, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 27, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif - const auto& vkDeviceLimits = m_PhysicalDevice->GetProperties().limits; - auto& TexCaps = m_DeviceCaps.TexCaps; + const auto& vkDeviceLimits = m_PhysicalDevice->GetProperties().limits; + const auto& vkEnabledFeatures = m_LogicalVkDevice->GetEnabledFeatures(); + + auto& TexCaps = m_DeviceCaps.TexCaps; TexCaps.MaxTexture1DDimension = vkDeviceLimits.maxImageDimension1D; TexCaps.MaxTexture1DArraySlices = vkDeviceLimits.maxImageArrayLayers; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index 66cf94c2..9b15f74b 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -74,13 +74,30 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, VkPhysicalDeviceFeatures2 Feats2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; VkPhysicalDeviceProperties2 Props2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; void** NextFeat = &Feats2.pNext; - (void)NextFeat; + + if (IsExtensionSupported(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) + { + *NextFeat = &m_ExtFeatures.ShaderFloat16Int8; + NextFeat = &m_ExtFeatures.ShaderFloat16Int8.pNext; + + m_ExtFeatures.ShaderFloat16Int8.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + } + + // VK_KHR_16bit_storage extension requires VK_KHR_storage_buffer_storage_class extension. + if (IsExtensionSupported(VK_KHR_16BIT_STORAGE_EXTENSION_NAME) && IsExtensionSupported(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME)) + { + *NextFeat = &m_ExtFeatures.Storage16Bit; + NextFeat = &m_ExtFeatures.Storage16Bit.pNext; + + m_ExtFeatures.Storage16Bit.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; + } // Enable mesh shader extension. if (IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME)) { - *NextFeat = &m_ExtFeatures.MeshShader; - NextFeat = &m_ExtFeatures.MeshShader.pNext; + *NextFeat = &m_ExtFeatures.MeshShader; + NextFeat = &m_ExtFeatures.MeshShader.pNext; + m_ExtFeatures.MeshShader.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV; } -- cgit v1.2.3