VK_KHR_shader_integer_dot_product implementation
This extension is entirely promoted to Vulkan 1.3. Because this is an
unoptimized implementation, all new properties are set to false.
The extension adds 3 integer dot products:
- signed
- unsigned
- mixed signed and unsigned
These dot products can be executed either on 32 bit integers or
packed (4 x 8 bit) vectors. Also, they may have the result of the
dot products added to an accumulator. This add operation is a
saturated add for both signed and unsigned dot product operations.
Tests: dEQP-VK.spirv_assembly.instruction.compute.op*khr.*
Bug: b/204502925
Change-Id: Id3c42563d4f3b073e98671215dc19fd9ca702e5c
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/63248
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Commit-Queue: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index a4212c9..d6b5546 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -427,6 +427,10 @@
case spv::CapabilityStorageImageExtendedFormats: capabilities.StorageImageExtendedFormats = true; break;
case spv::CapabilityImageQuery: capabilities.ImageQuery = true; break;
case spv::CapabilityDerivativeControl: capabilities.DerivativeControl = true; break;
+ case spv::CapabilityDotProductInputAll: capabilities.DotProductInputAll = true; break;
+ case spv::CapabilityDotProductInput4x8Bit: capabilities.DotProductInput4x8Bit = true; break;
+ case spv::CapabilityDotProductInput4x8BitPacked: capabilities.DotProductInput4x8BitPacked = true; break;
+ case spv::CapabilityDotProduct: capabilities.DotProduct = true; break;
case spv::CapabilityInterpolationFunction: capabilities.InterpolationFunction = true; break;
case spv::CapabilityStorageImageWriteWithoutFormat: capabilities.StorageImageWriteWithoutFormat = true; break;
case spv::CapabilityGroupNonUniform: capabilities.GroupNonUniform = true; break;
@@ -651,6 +655,12 @@
case spv::OpIAddCarry:
case spv::OpISubBorrow:
case spv::OpDot:
+ case spv::OpSDot:
+ case spv::OpUDot:
+ case spv::OpSUDot:
+ case spv::OpSDotAccSat:
+ case spv::OpUDotAccSat:
+ case spv::OpSUDotAccSat:
case spv::OpConvertFToU:
case spv::OpConvertFToS:
case spv::OpConvertSToF:
@@ -787,6 +797,7 @@
if(!strcmp(ext, "SPV_KHR_multiview")) break;
if(!strcmp(ext, "SPV_EXT_shader_stencil_export")) break;
if(!strcmp(ext, "SPV_KHR_float_controls")) break;
+ if(!strcmp(ext, "SPV_KHR_integer_dot_product")) break;
if(!strcmp(ext, "SPV_KHR_non_semantic_info")) break;
if(!strcmp(ext, "SPV_KHR_vulkan_memory_model")) break;
if(!strcmp(ext, "SPV_GOOGLE_decorate_string")) break;
@@ -2028,6 +2039,12 @@
return EmitBinaryOp(insn, state);
case spv::OpDot:
+ case spv::OpSDot:
+ case spv::OpUDot:
+ case spv::OpSUDot:
+ case spv::OpSDotAccSat:
+ case spv::OpUDotAccSat:
+ case spv::OpSUDotAccSat:
return EmitDot(insn, state);
case spv::OpSelect:
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index c3a9815..efcdde4 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -674,6 +674,10 @@
bool StorageImageExtendedFormats : 1;
bool ImageQuery : 1;
bool DerivativeControl : 1;
+ bool DotProductInputAll : 1;
+ bool DotProductInput4x8Bit : 1;
+ bool DotProductInput4x8BitPacked : 1;
+ bool DotProduct : 1;
bool InterpolationFunction : 1;
bool StorageImageWriteWithoutFormat : 1;
bool GroupNonUniform : 1;
@@ -1387,7 +1391,12 @@
static bool HasTypeAndResult(spv::Op op);
// Helper as we often need to take dot products as part of doing other things.
- SIMD::Float Dot(unsigned numComponents, Operand const &x, Operand const &y) const;
+ static SIMD::Float FDot(unsigned numComponents, Operand const &x, Operand const &y);
+ static SIMD::Int SDot(unsigned numComponents, Operand const &x, Operand const &y, Operand const *accum);
+ static SIMD::UInt UDot(unsigned numComponents, Operand const &x, Operand const &y, Operand const *accum);
+ static SIMD::Int SUDot(unsigned numComponents, Operand const &x, Operand const &y, Operand const *accum);
+ static SIMD::Int AddSat(RValue<SIMD::Int> a, RValue<SIMD::Int> b);
+ static SIMD::UInt AddSat(RValue<SIMD::UInt> a, RValue<SIMD::UInt> b);
// Splits x into a floating-point significand in the range [0.5, 1.0)
// and an integral exponent of two, such that:
diff --git a/src/Pipeline/SpirvShaderArithmetic.cpp b/src/Pipeline/SpirvShaderArithmetic.cpp
index bc6bb59..0b56aa2 100644
--- a/src/Pipeline/SpirvShaderArithmetic.cpp
+++ b/src/Pipeline/SpirvShaderArithmetic.cpp
@@ -19,6 +19,8 @@
#include <spirv/unified1/spirv.hpp>
+#include <limits>
+
namespace sw {
SpirvShader::EmitResult SpirvShader::EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const
@@ -528,7 +530,43 @@
auto lhs = Operand(this, state, insn.word(3));
auto rhs = Operand(this, state, insn.word(4));
- dst.move(0, Dot(lhsType.componentCount, lhs, rhs));
+ auto opcode = insn.opcode();
+ switch(opcode)
+ {
+ case spv::OpDot:
+ dst.move(0, FDot(lhsType.componentCount, lhs, rhs));
+ break;
+ case spv::OpSDot:
+ dst.move(0, SDot(lhsType.componentCount, lhs, rhs, nullptr));
+ break;
+ case spv::OpUDot:
+ dst.move(0, UDot(lhsType.componentCount, lhs, rhs, nullptr));
+ break;
+ case spv::OpSUDot:
+ dst.move(0, SUDot(lhsType.componentCount, lhs, rhs, nullptr));
+ break;
+ case spv::OpSDotAccSat:
+ {
+ auto accum = Operand(this, state, insn.word(5));
+ dst.move(0, SDot(lhsType.componentCount, lhs, rhs, &accum));
+ }
+ break;
+ case spv::OpUDotAccSat:
+ {
+ auto accum = Operand(this, state, insn.word(5));
+ dst.move(0, UDot(lhsType.componentCount, lhs, rhs, &accum));
+ }
+ break;
+ case spv::OpSUDotAccSat:
+ {
+ auto accum = Operand(this, state, insn.word(5));
+ dst.move(0, SUDot(lhsType.componentCount, lhs, rhs, &accum));
+ }
+ break;
+ default:
+ UNREACHABLE("%s", OpcodeName(opcode));
+ break;
+ }
SPIRV_SHADER_DBG("{0}: {1}", insn.resultId(), dst);
SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), lhs);
@@ -537,7 +575,7 @@
return EmitResult::Continue;
}
-SIMD::Float SpirvShader::Dot(unsigned numComponents, Operand const &x, Operand const &y) const
+SIMD::Float SpirvShader::FDot(unsigned numComponents, Operand const &x, Operand const &y)
{
SIMD::Float d = x.Float(0) * y.Float(0);
@@ -549,6 +587,140 @@
return d;
}
+SIMD::Int SpirvShader::SDot(unsigned numComponents, Operand const &x, Operand const &y, Operand const *accum)
+{
+ SIMD::Int d(0);
+
+ if(numComponents == 1) // 4x8bit packed
+ {
+ numComponents = 4;
+ for(auto i = 0u; i < numComponents; i++)
+ {
+ Int4 xs(As<SByte4>(Extract(x.Int(0), i)));
+ Int4 ys(As<SByte4>(Extract(y.Int(0), i)));
+
+ Int4 xy = xs * ys;
+ rr::Int sum = Extract(xy, 0) + Extract(xy, 1) + Extract(xy, 2) + Extract(xy, 3);
+
+ d = Insert(d, sum, i);
+ }
+ }
+ else
+ {
+ d = x.Int(0) * y.Int(0);
+
+ for(auto i = 1u; i < numComponents; i++)
+ {
+ d += x.Int(i) * y.Int(i);
+ }
+ }
+
+ if(accum)
+ {
+ d = AddSat(d, accum->Int(0));
+ }
+
+ return d;
+}
+
+SIMD::UInt SpirvShader::UDot(unsigned numComponents, Operand const &x, Operand const &y, Operand const *accum)
+{
+ SIMD::UInt d(0);
+
+ if(numComponents == 1) // 4x8bit packed
+ {
+ numComponents = 4;
+ for(auto i = 0u; i < numComponents; i++)
+ {
+ Int4 xs(As<Byte4>(Extract(x.Int(0), i)));
+ Int4 ys(As<Byte4>(Extract(y.Int(0), i)));
+
+ UInt4 xy = xs * ys;
+ rr::UInt sum = Extract(xy, 0) + Extract(xy, 1) + Extract(xy, 2) + Extract(xy, 3);
+
+ d = Insert(d, sum, i);
+ }
+ }
+ else
+ {
+ d = x.UInt(0) * y.UInt(0);
+
+ for(auto i = 1u; i < numComponents; i++)
+ {
+ d += x.UInt(i) * y.UInt(i);
+ }
+ }
+
+ if(accum)
+ {
+ d = AddSat(d, accum->UInt(0));
+ }
+
+ return d;
+}
+
+SIMD::Int SpirvShader::SUDot(unsigned numComponents, Operand const &x, Operand const &y, Operand const *accum)
+{
+ SIMD::Int d(0);
+
+ if(numComponents == 1) // 4x8bit packed
+ {
+ numComponents = 4;
+ for(auto i = 0u; i < numComponents; i++)
+ {
+ Int4 xs(As<SByte4>(Extract(x.Int(0), i)));
+ Int4 ys(As<Byte4>(Extract(y.Int(0), i)));
+
+ Int4 xy = xs * ys;
+ rr::Int sum = Extract(xy, 0) + Extract(xy, 1) + Extract(xy, 2) + Extract(xy, 3);
+
+ d = Insert(d, sum, i);
+ }
+ }
+ else
+ {
+ d = x.Int(0) * As<SIMD::Int>(y.UInt(0));
+
+ for(auto i = 1u; i < numComponents; i++)
+ {
+ d += x.Int(i) * As<SIMD::Int>(y.UInt(i));
+ }
+ }
+
+ if(accum)
+ {
+ d = AddSat(d, accum->Int(0));
+ }
+
+ return d;
+}
+
+SIMD::Int SpirvShader::AddSat(RValue<SIMD::Int> a, RValue<SIMD::Int> b)
+{
+ SIMD::Int sum = a + b;
+ SIMD::Int sSign = sum >> 31;
+ SIMD::Int aSign = a >> 31;
+ SIMD::Int bSign = b >> 31;
+
+ // Overflow happened if both numbers added have the same sign and the sum has a different sign
+ SIMD::Int oob = ~(aSign ^ bSign) & (aSign ^ sSign);
+ SIMD::Int overflow = oob & sSign;
+ SIMD::Int underflow = oob & aSign;
+
+ return (overflow & std::numeric_limits<int32_t>::max()) |
+ (underflow & std::numeric_limits<int32_t>::min()) |
+ (~oob & sum);
+}
+
+SIMD::UInt SpirvShader::AddSat(RValue<SIMD::UInt> a, RValue<SIMD::UInt> b)
+{
+ SIMD::UInt sum = a + b;
+
+ // Overflow happened if the sum of unsigned integers is smaller than either of the 2 numbers being added
+ // Note: CmpLT()'s return value is automatically set to UINT_MAX when true
+ return CmpLT(sum, a) | sum;
+}
+
std::pair<SIMD::Float, SIMD::Int> SpirvShader::Frexp(RValue<SIMD::Float> val) const
{
// Assumes IEEE 754
diff --git a/src/Pipeline/SpirvShaderGLSLstd450.cpp b/src/Pipeline/SpirvShaderGLSLstd450.cpp
index d1edb79..582a092 100644
--- a/src/Pipeline/SpirvShaderGLSLstd450.cpp
+++ b/src/Pipeline/SpirvShaderGLSLstd450.cpp
@@ -295,7 +295,7 @@
auto I = Operand(this, state, insn.word(5));
auto N = Operand(this, state, insn.word(6));
- SIMD::Float d = Dot(type.componentCount, I, N);
+ SIMD::Float d = FDot(type.componentCount, I, N);
for(auto i = 0u; i < type.componentCount; i++)
{
@@ -310,7 +310,7 @@
auto eta = Operand(this, state, insn.word(7));
Decorations r = GetDecorationsForId(insn.resultId());
- SIMD::Float d = Dot(type.componentCount, I, N);
+ SIMD::Float d = FDot(type.componentCount, I, N);
SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d);
SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
SIMD::Float t = (eta.Float(0) * d + Sqrt(k, r.RelaxedPrecision));
@@ -327,7 +327,7 @@
auto I = Operand(this, state, insn.word(6));
auto Nref = Operand(this, state, insn.word(7));
- SIMD::Float d = Dot(type.componentCount, I, Nref);
+ SIMD::Float d = FDot(type.componentCount, I, Nref);
SIMD::Int neg = CmpLT(d, SIMD::Float(0.0f));
for(auto i = 0u; i < type.componentCount; i++)
@@ -340,7 +340,7 @@
case GLSLstd450Length:
{
auto x = Operand(this, state, insn.word(5));
- SIMD::Float d = Dot(getObjectType(insn.word(5)).componentCount, x, x);
+ SIMD::Float d = FDot(getObjectType(insn.word(5)).componentCount, x, x);
Decorations r = GetDecorationsForId(insn.resultId());
dst.move(0, Sqrt(d, r.RelaxedPrecision));
@@ -351,7 +351,7 @@
auto x = Operand(this, state, insn.word(5));
Decorations r = GetDecorationsForId(insn.resultId());
- SIMD::Float d = Dot(getObjectType(insn.word(5)).componentCount, x, x);
+ SIMD::Float d = FDot(getObjectType(insn.word(5)).componentCount, x, x);
SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d, r.RelaxedPrecision);
for(auto i = 0u; i < type.componentCount; i++)
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index a6d59cc..01aae1b 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -388,6 +388,11 @@
features->synchronization2 = VK_TRUE;
}
+static void getPhysicalDeviceShaderIntegerDotProductFeatures(VkPhysicalDeviceShaderIntegerDotProductFeatures *features)
+{
+ features->shaderIntegerDotProduct = VK_TRUE;
+}
+
void PhysicalDevice::getFeatures2(VkPhysicalDeviceFeatures2 *features) const
{
features->features = getFeatures();
@@ -509,6 +514,9 @@
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES:
getPhysicalDeviceSynchronization2Features(reinterpret_cast<struct VkPhysicalDeviceSynchronization2Features *>(curExtension));
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES:
+ getPhysicalDeviceShaderIntegerDotProductFeatures(reinterpret_cast<struct VkPhysicalDeviceShaderIntegerDotProductFeatures *>(curExtension));
+ break;
// Unsupported extensions, but used by dEQP
// TODO(b/176893525): This may not be legal.
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT:
@@ -516,7 +524,6 @@
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT:
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT:
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT:
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR:
break;
default:
UNSUPPORTED("curExtension->sType: %s", vk::Stringify(curExtension->sType).c_str());
@@ -1151,6 +1158,40 @@
properties->uniformTexelBufferOffsetSingleTexelAlignment = VK_FALSE;
}
+void PhysicalDevice::getProperties(VkPhysicalDeviceShaderIntegerDotProductProperties *properties) const
+{
+ properties->integerDotProduct8BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProduct8BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProduct8BitMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProduct4x8BitPackedUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProduct4x8BitPackedSignedAccelerated = VK_FALSE;
+ properties->integerDotProduct4x8BitPackedMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProduct16BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProduct16BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProduct16BitMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProduct32BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProduct32BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProduct32BitMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProduct64BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProduct64BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProduct64BitMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating8BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating16BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating32BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating64BitSignedAccelerated = VK_FALSE;
+ properties->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated = VK_FALSE;
+}
+
template<typename T>
static void getSamplerFilterMinmaxProperties(T *properties)
{
@@ -1333,6 +1374,13 @@
CheckFeature(requested, supported, descriptorBindingInlineUniformBlockUpdateAfterBind);
}
+bool PhysicalDevice::hasExtendedFeatures(const VkPhysicalDeviceShaderIntegerDotProductFeatures *requested) const
+{
+ auto supported = getSupportedFeatures(requested);
+
+ return CheckFeature(requested, supported, shaderIntegerDotProduct);
+}
+
bool PhysicalDevice::hasExtendedFeatures(const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *requested) const
{
auto supported = getSupportedFeatures(requested);
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
index f699fd9..ffbb5c7 100644
--- a/src/Vulkan/VkPhysicalDevice.hpp
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -48,6 +48,7 @@
bool hasExtendedFeatures(const VkPhysicalDeviceTextureCompressionASTCHDRFeatures *features) const;
bool hasExtendedFeatures(const VkPhysicalDeviceSubgroupSizeControlFeatures *requested) const;
bool hasExtendedFeatures(const VkPhysicalDeviceInlineUniformBlockFeatures *features) const;
+ bool hasExtendedFeatures(const VkPhysicalDeviceShaderIntegerDotProductFeatures *features) const;
bool hasExtendedFeatures(const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *requested) const;
const VkPhysicalDeviceProperties &getProperties() const;
@@ -83,6 +84,7 @@
void getProperties(VkPhysicalDeviceSubgroupSizeControlProperties *properties) const;
void getProperties(VkPhysicalDeviceInlineUniformBlockProperties *properties) const;
void getProperties(VkPhysicalDeviceTexelBufferAlignmentProperties *properties) const;
+ void getProperties(VkPhysicalDeviceShaderIntegerDotProductProperties *properties) const;
void getProperties(VkPhysicalDeviceVulkan11Properties *properties) const;
static void GetFormatProperties(Format format, VkFormatProperties *pFormatProperties);
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 31426e9..5c86cde 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -426,6 +426,7 @@
{ { VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION } },
{ { VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME, VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION } },
{ { VK_KHR_MAINTENANCE_4_EXTENSION_NAME, VK_KHR_MAINTENANCE_4_SPEC_VERSION } },
+ { { VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME, VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION } },
{ { VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION } },
{ { VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION } },
{ { VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME, VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION } },
@@ -988,6 +989,16 @@
}
}
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES:
+ {
+ const auto *integerDotProductFeatures = reinterpret_cast<const VkPhysicalDeviceShaderIntegerDotProductFeatures *>(extensionCreateInfo);
+ bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(integerDotProductFeatures);
+ if(!hasFeatures)
+ {
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+ }
+ }
+ break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES:
{
const auto *zeroInitializeWorkgroupMemoryFeatures = reinterpret_cast<const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *>(extensionCreateInfo);
@@ -3582,6 +3593,12 @@
vk::Cast(physicalDevice)->getProperties(properties);
}
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES:
+ {
+ auto properties = reinterpret_cast<VkPhysicalDeviceShaderIntegerDotProductProperties *>(extensionProperties);
+ vk::Cast(physicalDevice)->getProperties(properties);
+ }
+ break;
default:
// "the [driver] must skip over, without processing (other than reading the sType and pNext members) any structures in the chain with sType values not defined by [supported extenions]"
UNSUPPORTED("pProperties->pNext sType = %s", vk::Stringify(extensionProperties->sType).c_str());