From a09d692eabba70d5f79db99918faa7eace93eddf Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 3 Oct 2020 19:04:44 -0700 Subject: Added device features to inidicate 8-bit types support (API240074) --- Graphics/GraphicsEngine/interface/APIInfo.h | 2 +- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 17 +++++- .../src/RenderDeviceD3D11Impl.cpp | 12 +++- .../src/RenderDeviceD3D12Impl.cpp | 6 +- .../src/RenderDeviceGLImpl.cpp | 8 ++- .../VulkanUtilities/VulkanPhysicalDevice.hpp | 1 + .../GraphicsEngineVulkan/src/EngineFactoryVk.cpp | 71 +++++++++++++++++++--- .../src/RenderDeviceVkImpl.cpp | 2 +- .../src/VulkanUtilities/VulkanPhysicalDevice.cpp | 21 +++++-- 9 files changed, 118 insertions(+), 22 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index d47c9a70..a7596e3f 100644 --- a/Graphics/GraphicsEngine/interface/APIInfo.h +++ b/Graphics/GraphicsEngine/interface/APIInfo.h @@ -30,7 +30,7 @@ /// \file /// Diligent API information -#define DILIGENT_API_VERSION 240073 +#define DILIGENT_API_VERSION 240074 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 69769968..b681c498 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1600,6 +1600,16 @@ struct DeviceFeatures /// Indicates if 16-bit floats and ints can be used as input/output of a shader entry point. DEVICE_FEATURE_STATE ShaderInputOutput16 DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + /// Indicates if device supports native 8-bit integer operations. + DEVICE_FEATURE_STATE ShaderInt8 DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + + /// Indicates if device supports reading and writing 8-bit types from buffers bound + /// as shader resource or unordered access views. + DEVICE_FEATURE_STATE ResourceBuffer8BitAccess DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + + /// Indicates if device supports reading 8-bit types from uniform buffers. + DEVICE_FEATURE_STATE UniformBuffer8BitAccess DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + #if DILIGENT_CPP_INTERFACE DeviceFeatures() noexcept {} @@ -1631,10 +1641,13 @@ struct DeviceFeatures ShaderFloat16 {State}, ResourceBuffer16BitAccess {State}, UniformBuffer16BitAccess {State}, - ShaderInputOutput16 {State} + ShaderInputOutput16 {State}, + ShaderInt8 {State}, + ResourceBuffer8BitAccess {State}, + UniformBuffer8BitAccess {State} { # if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(*this) == 27, "Did you add a new feature to DeviceFeatures? Please handle its status above."); + static_assert(sizeof(*this) == 30, "Did you add a new feature to DeviceFeatures? Please handle its status above."); # endif } #endif diff --git a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp index ffd746fb..76020ed8 100644 --- a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp @@ -164,13 +164,19 @@ RenderDeviceD3D11Impl::RenderDeviceD3D11Impl(IReferenceCounters* pRefCo } // Explicit fp16 is only supported in DXC through Shader Model 6.2, so there's no support for FXC or D3D11. + // clang-format off UNSUPPORTED_FEATURE(ResourceBuffer16BitAccess, "16-bit native access to resource buffers is"); - UNSUPPORTED_FEATURE(UniformBuffer16BitAccess, "16-bit native access to uniform buffers is"); - UNSUPPORTED_FEATURE(ShaderInputOutput16, "16-bit shader input/output is"); + UNSUPPORTED_FEATURE(UniformBuffer16BitAccess, "16-bit native access to uniform buffers is"); + UNSUPPORTED_FEATURE(ShaderInputOutput16, "16-bit shader input/output is"); + + UNSUPPORTED_FEATURE(ShaderInt8, "Native 8-bit shader operations are"); + UNSUPPORTED_FEATURE(ResourceBuffer8BitAccess, "8-bit native access to resource buffers is"); + UNSUPPORTED_FEATURE(UniformBuffer8BitAccess, "8-bit native access to uniform buffers is"); + // clang-format on #undef UNSUPPORTED_FEATURE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 27, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 30, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif auto& TexCaps = m_DeviceCaps.TexCaps; diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 0cf5440a..db86d662 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -289,11 +289,15 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo CHECK_REQUIRED_FEATURE(ResourceBuffer16BitAccess, "16-bit resoure buffer access is"); CHECK_REQUIRED_FEATURE(UniformBuffer16BitAccess, "16-bit uniform buffer access is"); CHECK_REQUIRED_FEATURE(ShaderInputOutput16, "16-bit shader inputs/outputs are"); + + CHECK_REQUIRED_FEATURE(ShaderInt8, "8-bit shader operations are"); + CHECK_REQUIRED_FEATURE(ResourceBuffer8BitAccess, "8-bit resoure buffer access is"); + CHECK_REQUIRED_FEATURE(UniformBuffer8BitAccess, "8-bit uniform buffer access is"); // clang-format on #undef CHECK_REQUIRED_FEATURE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 27, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 30, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif auto& TexCaps = m_DeviceCaps.TexCaps; diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp index 49b930e3..466f1387 100644 --- a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp @@ -364,6 +364,9 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, SET_FEATURE_STATE(ResourceBuffer16BitAccess, CheckExtension("GL_EXT_shader_16bit_storage"), "16-bit resoure buffer access is"); SET_FEATURE_STATE(UniformBuffer16BitAccess, CheckExtension("GL_EXT_shader_16bit_storage"), "16-bit uniform buffer access is"); SET_FEATURE_STATE(ShaderInputOutput16, false, "16-bit shader inputs/outputs are"); + SET_FEATURE_STATE(ShaderInt8, CheckExtension("GL_EXT_shader_explicit_arithmetic_types_int8"), "8-bit integer shader operations are"); + SET_FEATURE_STATE(ResourceBuffer8BitAccess, CheckExtension("GL_EXT_shader_8bit_storage"), "8-bit resoure buffer access is"); + SET_FEATURE_STATE(UniformBuffer8BitAccess, CheckExtension("GL_EXT_shader_8bit_storage"), "8-bit uniform buffer access is"); // clang-format on TexCaps.MaxTexture1DDimension = MaxTextureSize; @@ -423,6 +426,9 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, SET_FEATURE_STATE(ResourceBuffer16BitAccess, strstr(Extensions, "shader_16bit_storage"), "16-bit resoure buffer access is"); SET_FEATURE_STATE(UniformBuffer16BitAccess, strstr(Extensions, "shader_16bit_storage"), "16-bit uniform buffer access is"); SET_FEATURE_STATE(ShaderInputOutput16, false, "16-bit shader inputs/outputs are"); + SET_FEATURE_STATE(ShaderInt8, strstr(Extensions, "shader_explicit_arithmetic_types_int8"), "8-bit integer shader operations are"); + SET_FEATURE_STATE(ResourceBuffer8BitAccess, strstr(Extensions, "shader_8bit_storage"), "8-bit resoure buffer access is"); + SET_FEATURE_STATE(UniformBuffer8BitAccess, strstr(Extensions, "shader_8bit_storage"), "8-bit uniform buffer access is"); // clang-format on TexCaps.MaxTexture1DDimension = 0; // Not supported in GLES 3.2 @@ -450,7 +456,7 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, #undef SET_FEATURE_STATE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 27, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 30, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif } diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp index 848055eb..b4e734c7 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp @@ -41,6 +41,7 @@ public: { VkPhysicalDeviceMeshShaderFeaturesNV MeshShader = {}; VkPhysicalDevice16BitStorageFeaturesKHR Storage16Bit = {}; + VkPhysicalDevice8BitStorageFeaturesKHR Storage8Bit = {}; VkPhysicalDeviceShaderFloat16Int8FeaturesKHR ShaderFloat16Int8 = {}; }; diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index 04bc3a1f..6a81faba 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -174,7 +174,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E VkPhysicalDeviceFeatures EnabledFeatures = {}; EnabledFeatures.fullDrawIndexUint32 = PhysicalDeviceFeatures.fullDrawIndexUint32; - auto GetFeatureState = [&](DEVICE_FEATURE_STATE RequestedState, bool IsFeatureSupported, const char* FeatureName) // + auto GetFeatureState = [](DEVICE_FEATURE_STATE RequestedState, bool IsFeatureSupported, const char* FeatureName) // { switch (RequestedState) { @@ -252,7 +252,10 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E ENABLE_FEATURE(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE, MeshShaders, "Mesh shaders are"); auto ShaderFloat16Int8 = DeiceExtFeatures.ShaderFloat16Int8; + // clang-format off ENABLE_FEATURE(ShaderFloat16Int8.shaderFloat16 != VK_FALSE, ShaderFloat16, "16-bit float shader operations are"); + ENABLE_FEATURE(ShaderFloat16Int8.shaderInt8 != VK_FALSE, ShaderInt8, "8-bit int shader operations are"); + // clang-format on auto Storage16BitFeats = DeiceExtFeatures.Storage16Bit; // clang-format off @@ -260,6 +263,12 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E 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 + + auto Storage8BitFeats = DeiceExtFeatures.Storage8Bit; + // clang-format off + ENABLE_FEATURE(Storage8BitFeats.storageBuffer8BitAccess != VK_FALSE, ResourceBuffer8BitAccess, "8-bit resoure buffer access is"); + ENABLE_FEATURE(Storage8BitFeats.uniformAndStorageBuffer8BitAccess != VK_FALSE, UniformBuffer8BitAccess, "8-bit uniform buffer access is"); + // clang-format on #undef FeatureSupport @@ -280,21 +289,29 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E NextExt = &MeshShaderFeats.pNext; } - if (EngineCI.Features.ShaderFloat16 != DEVICE_FEATURE_STATE_DISABLED) + if (EngineCI.Features.ShaderFloat16 != DEVICE_FEATURE_STATE_DISABLED || + EngineCI.Features.ShaderInt8 != DEVICE_FEATURE_STATE_DISABLED) { - VERIFY_EXPR(ShaderFloat16Int8.shaderFloat16 != VK_FALSE); + VERIFY_EXPR(ShaderFloat16Int8.shaderFloat16 != VK_FALSE || ShaderFloat16Int8.shaderInt8 != 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"); + "and at least one of shaderFloat16 or shaderInt8 features is TRUE"); DeviceExtensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); + if (EngineCI.Features.ShaderFloat16 == DEVICE_FEATURE_STATE_DISABLED) + ShaderFloat16Int8.shaderFloat16 = VK_FALSE; + if (EngineCI.Features.ShaderInt8 == DEVICE_FEATURE_STATE_DISABLED) + ShaderFloat16Int8.shaderInt8 = VK_FALSE; + *NextExt = &ShaderFloat16Int8; NextExt = &ShaderFloat16Int8.pNext; } + bool StorageBufferStorageClassExtensionRequired = false; + // clang-format off - if (EngineCI.Features.ResourceBuffer16BitAccess != DEVICE_FEATURE_STATE_DISABLED || - EngineCI.Features.UniformBuffer16BitAccess != DEVICE_FEATURE_STATE_DISABLED || + 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 { @@ -315,7 +332,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E 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); + StorageBufferStorageClassExtensionRequired = true; if (EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED) Storage16BitFeats.storageBuffer16BitAccess = VK_FALSE; @@ -328,13 +345,51 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E NextExt = &Storage16BitFeats.pNext; } + // clang-format off + if (EngineCI.Features.ResourceBuffer8BitAccess != DEVICE_FEATURE_STATE_DISABLED || + EngineCI.Features.UniformBuffer8BitAccess != DEVICE_FEATURE_STATE_DISABLED) + // clang-format on + { + // clang-format off + VERIFY_EXPR(EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage8BitFeats.storageBuffer8BitAccess != VK_FALSE); + VERIFY_EXPR(EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage8BitFeats.uniformAndStorageBuffer8BitAccess != VK_FALSE); + // clang-format on + + VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_8BIT_STORAGE_EXTENSION_NAME), + "VK_KHR_8bit_storage must be supported as it has already been checked by VulkanPhysicalDevice and at least one of " + "storageBuffer8BitAccess or uniformAndStorageBuffer8BitAccess features is TRUE"); + DeviceExtensions.push_back(VK_KHR_8BIT_STORAGE_EXTENSION_NAME); + + // VK_KHR_8bit_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 " + "storageBuffer8BitAccess or uniformAndStorageBuffer8BitAccess features is TRUE"); + StorageBufferStorageClassExtensionRequired = true; + + if (EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED) + Storage8BitFeats.storageBuffer8BitAccess = VK_FALSE; + if (EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED) + Storage8BitFeats.uniformAndStorageBuffer8BitAccess = VK_FALSE; + + *NextExt = &Storage8BitFeats; + NextExt = &Storage8BitFeats.pNext; + } + + if (StorageBufferStorageClassExtensionRequired) + { + VERIFY_EXPR(PhysicalDevice->IsExtensionSupported(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME)); + DeviceExtensions.push_back(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME); + } + *NextExt = nullptr; } #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 27, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 30, "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 204aaa74..c36b98b0 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -220,7 +220,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* Features.DurationQueries = DEVICE_FEATURE_STATE_ENABLED; #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 27, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 30, "Did you add a new feature to DeviceFeatures? Please handle its satus here (if necessary)."); #endif const auto& vkDeviceLimits = m_PhysicalDevice->GetProperties().limits; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index 9b15f74b..92a5e4d4 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -83,13 +83,24 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, 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)) + // VK_KHR_16bit_storage and VK_KHR_8bit_storage extensions require VK_KHR_storage_buffer_storage_class extension. + if (IsExtensionSupported(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME)) { - *NextFeat = &m_ExtFeatures.Storage16Bit; - NextFeat = &m_ExtFeatures.Storage16Bit.pNext; + if (IsExtensionSupported(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) + { + *NextFeat = &m_ExtFeatures.Storage16Bit; + NextFeat = &m_ExtFeatures.Storage16Bit.pNext; + + m_ExtFeatures.Storage16Bit.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; + } - m_ExtFeatures.Storage16Bit.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; + if (IsExtensionSupported(VK_KHR_8BIT_STORAGE_EXTENSION_NAME)) + { + *NextFeat = &m_ExtFeatures.Storage8Bit; + NextFeat = &m_ExtFeatures.Storage8Bit.pNext; + + m_ExtFeatures.Storage8Bit.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; + } } // Enable mesh shader extension. -- cgit v1.2.3