/*------------------------------------------------------------------------- * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Utilities for Vulkan SPIR-V assembly tests *//*--------------------------------------------------------------------*/ #include "vktSpvAsmUtils.hpp" #include "deMemory.h" #include "deSTLUtil.hpp" #include "vkQueryUtil.hpp" #include "vkRefUtil.hpp" #include "vkPlatform.hpp" #include namespace vkt { namespace SpirVAssembly { using namespace vk; std::string VariableLocation::toString() const { return "set_" + de::toString(set) + "_binding_" + de::toString(binding); } std::string VariableLocation::toDescription() const { return "Set " + de::toString(set) + " and Binding " + de::toString(binding); } #define IS_CORE_FEATURE_AVAILABLE(CHECKED, AVAILABLE, FEATURE) \ if ((CHECKED.FEATURE != DE_FALSE) && (AVAILABLE.FEATURE == DE_FALSE)) { *missingFeature = #FEATURE; return false; } bool isCoreFeaturesSupported (const Context& context, const vk::VkPhysicalDeviceFeatures& toCheck, const char** missingFeature) { const VkPhysicalDeviceFeatures& availableFeatures = context.getDeviceFeatures(); IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, robustBufferAccess) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, fullDrawIndexUint32) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, imageCubeArray) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, independentBlend) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, geometryShader) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, tessellationShader) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sampleRateShading) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, dualSrcBlend) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, logicOp) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, multiDrawIndirect) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, drawIndirectFirstInstance) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, depthClamp) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, depthBiasClamp) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, fillModeNonSolid) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, depthBounds) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, wideLines) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, largePoints) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, alphaToOne) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, multiViewport) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, samplerAnisotropy) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, textureCompressionETC2) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, textureCompressionASTC_LDR) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, textureCompressionBC) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, occlusionQueryPrecise) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, pipelineStatisticsQuery) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, vertexPipelineStoresAndAtomics) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, fragmentStoresAndAtomics) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderTessellationAndGeometryPointSize) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderImageGatherExtended) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderStorageImageExtendedFormats) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderStorageImageMultisample) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderStorageImageReadWithoutFormat) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderStorageImageWriteWithoutFormat) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderUniformBufferArrayDynamicIndexing) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderSampledImageArrayDynamicIndexing) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderStorageBufferArrayDynamicIndexing) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderStorageImageArrayDynamicIndexing) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderClipDistance) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderCullDistance) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderFloat64) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderInt64) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderInt16) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderResourceResidency) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, shaderResourceMinLod) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseBinding) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidencyBuffer) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidencyImage2D) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidencyImage3D) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidency2Samples) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidency4Samples) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidency8Samples) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidency16Samples) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, sparseResidencyAliased) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, variableMultisampleRate) IS_CORE_FEATURE_AVAILABLE(toCheck, availableFeatures, inheritedQueries) return true; } #define IS_AVAIL(EXT_NAME, FEATURE) \ if (toCheck.FEATURE && !extensionFeatures.FEATURE) { *missingFeature = EXT_NAME #FEATURE; return false; } bool isFloat16Int8FeaturesSupported(const Context& context, const vk::VkPhysicalDeviceShaderFloat16Int8Features& toCheck, const char **missingFeature) { const VkPhysicalDeviceShaderFloat16Int8Features& extensionFeatures = context.getShaderFloat16Int8Features(); IS_AVAIL("ShaderFloat16Int8.", shaderFloat16); IS_AVAIL("ShaderFloat16Int8.", shaderInt8); return true; } bool is8BitStorageFeaturesSupported(const Context& context, const vk::VkPhysicalDevice8BitStorageFeatures& toCheck, const char **missingFeature) { const VkPhysicalDevice8BitStorageFeatures& extensionFeatures = context.get8BitStorageFeatures(); IS_AVAIL("8BitStorage.", storageBuffer8BitAccess); IS_AVAIL("8BitStorage.", uniformAndStorageBuffer8BitAccess); IS_AVAIL("8BitStorage.", storagePushConstant8); return true; } bool is16BitStorageFeaturesSupported(const Context& context, const vk::VkPhysicalDevice16BitStorageFeatures& toCheck, const char **missingFeature) { const VkPhysicalDevice16BitStorageFeatures& extensionFeatures = context.get16BitStorageFeatures(); IS_AVAIL("16BitStorage.", storageBuffer16BitAccess); IS_AVAIL("16BitStorage.", uniformAndStorageBuffer16BitAccess); IS_AVAIL("16BitStorage.", storagePushConstant16); IS_AVAIL("16BitStorage.", storageInputOutput16); return true; } bool isVariablePointersFeaturesSupported(const Context& context, const vk::VkPhysicalDeviceVariablePointersFeatures& toCheck, const char **missingFeature) { const VkPhysicalDeviceVariablePointersFeatures& extensionFeatures = context.getVariablePointersFeatures(); IS_AVAIL("VariablePointers.", variablePointersStorageBuffer); IS_AVAIL("VariablePointers.", variablePointers); return true; } bool isVulkanMemoryModelFeaturesSupported(const Context& context, const vk::VkPhysicalDeviceVulkanMemoryModelFeatures& toCheck, const char **missingFeature) { const VkPhysicalDeviceVulkanMemoryModelFeatures& extensionFeatures = context.getVulkanMemoryModelFeatures(); IS_AVAIL("VulkanMemoryModel.", vulkanMemoryModel); IS_AVAIL("VulkanMemoryModel.", vulkanMemoryModelDeviceScope); IS_AVAIL("VulkanMemoryModel.", vulkanMemoryModelAvailabilityVisibilityChains); return true; } #ifndef CTS_USES_VULKANSC bool isIntegerDotProductFeaturesSupported(const Context& context, const vk::VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR& toCheck, const char **missingFeature) { const VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR& extensionFeatures = context.getShaderIntegerDotProductFeatures(); IS_AVAIL("ShaderIntegerDotProduct.", shaderIntegerDotProduct); return true; } #endif // CTS_USES_VULKANSC #undef IS_AVAIL bool isFloatControlsFeaturesSupported (const Context& context, const vk::VkPhysicalDeviceFloatControlsProperties& toCheck, const char **missingFeature) { // if all flags are set to false then no float control features are actualy requested by the test if ((toCheck.shaderSignedZeroInfNanPreserveFloat16 || toCheck.shaderSignedZeroInfNanPreserveFloat32 || toCheck.shaderSignedZeroInfNanPreserveFloat64 || toCheck.shaderDenormPreserveFloat16 || toCheck.shaderDenormPreserveFloat32 || toCheck.shaderDenormPreserveFloat64 || toCheck.shaderDenormFlushToZeroFloat16 || toCheck.shaderDenormFlushToZeroFloat32 || toCheck.shaderDenormFlushToZeroFloat64 || toCheck.shaderRoundingModeRTEFloat16 || toCheck.shaderRoundingModeRTEFloat32 || toCheck.shaderRoundingModeRTEFloat64 || toCheck.shaderRoundingModeRTZFloat16 || toCheck.shaderRoundingModeRTZFloat32 || toCheck.shaderRoundingModeRTZFloat64) == false) return true; *missingFeature = "Float controls properties"; // return false when float control features are requested and proper extension is not supported if (!context.isDeviceFunctionalitySupported("VK_KHR_shader_float_controls")) return false; // perform query to get supported float control properties vk::VkPhysicalDeviceFloatControlsProperties refControls; { refControls.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES; refControls.pNext = DE_NULL; VkPhysicalDeviceProperties2 deviceProperties; deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; deviceProperties.pNext = &refControls; const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); const vk::InstanceInterface& instanceInterface = context.getInstanceInterface(); instanceInterface.getPhysicalDeviceProperties2(physicalDevice, &deviceProperties); } using FCIndependence = VkShaderFloatControlsIndependence; FCIndependence fcInd32 = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY; FCIndependence fcIndAll = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; FCIndependence fcIndNone = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE; bool requiredDenormBehaviorNotSupported = ((toCheck.denormBehaviorIndependence == fcIndAll) && (refControls.denormBehaviorIndependence != fcIndAll)) || ((toCheck.denormBehaviorIndependence == fcInd32) && (refControls.denormBehaviorIndependence == fcIndNone)); bool requiredRoundingModeNotSupported = ((toCheck.roundingModeIndependence == fcIndAll) && (refControls.roundingModeIndependence != fcIndAll)) || ((toCheck.roundingModeIndependence == fcInd32) && (refControls.roundingModeIndependence == fcIndNone)); // check if flags needed by the test are not supported by the device bool requiredFeaturesNotSupported = requiredDenormBehaviorNotSupported || requiredRoundingModeNotSupported || (toCheck.shaderDenormFlushToZeroFloat16 && !refControls.shaderDenormFlushToZeroFloat16) || (toCheck.shaderDenormPreserveFloat16 && !refControls.shaderDenormPreserveFloat16) || (toCheck.shaderRoundingModeRTEFloat16 && !refControls.shaderRoundingModeRTEFloat16) || (toCheck.shaderRoundingModeRTZFloat16 && !refControls.shaderRoundingModeRTZFloat16) || (toCheck.shaderSignedZeroInfNanPreserveFloat16 && !refControls.shaderSignedZeroInfNanPreserveFloat16) || (toCheck.shaderDenormFlushToZeroFloat32 && !refControls.shaderDenormFlushToZeroFloat32) || (toCheck.shaderDenormPreserveFloat32 && !refControls.shaderDenormPreserveFloat32) || (toCheck.shaderRoundingModeRTEFloat32 && !refControls.shaderRoundingModeRTEFloat32) || (toCheck.shaderRoundingModeRTZFloat32 && !refControls.shaderRoundingModeRTZFloat32) || (toCheck.shaderSignedZeroInfNanPreserveFloat32 && !refControls.shaderSignedZeroInfNanPreserveFloat32) || (toCheck.shaderDenormFlushToZeroFloat64 && !refControls.shaderDenormFlushToZeroFloat64) || (toCheck.shaderDenormPreserveFloat64 && !refControls.shaderDenormPreserveFloat64) || (toCheck.shaderRoundingModeRTEFloat64 && !refControls.shaderRoundingModeRTEFloat64) || (toCheck.shaderRoundingModeRTZFloat64 && !refControls.shaderRoundingModeRTZFloat64) || (toCheck.shaderSignedZeroInfNanPreserveFloat64 && !refControls.shaderSignedZeroInfNanPreserveFloat64); // we checked if required features are not supported - we need to // negate the result to know if all required features are available return !requiredFeaturesNotSupported; } bool isVulkanFeaturesSupported(const Context& context, const VulkanFeatures& requested, const char **missingFeature) { if (!isCoreFeaturesSupported(context, requested.coreFeatures, missingFeature)) return false; if (!is8BitStorageFeaturesSupported(context, requested.ext8BitStorage, missingFeature)) return false; if (!is16BitStorageFeaturesSupported(context, requested.ext16BitStorage, missingFeature)) return false; if (!isVariablePointersFeaturesSupported(context, requested.extVariablePointers, missingFeature)) return false; if (!isFloat16Int8FeaturesSupported(context, requested.extFloat16Int8, missingFeature)) return false; if (!isVulkanMemoryModelFeaturesSupported(context, requested.extVulkanMemoryModel, missingFeature)) return false; if (!isFloatControlsFeaturesSupported(context, requested.floatControlsProperties, missingFeature)) return false; #ifndef CTS_USES_VULKANSC if (!isIntegerDotProductFeaturesSupported(context, requested.extIntegerDotProduct, missingFeature)) return false; #endif // CTS_USES_VULKANSC return true; } deUint32 getMinRequiredVulkanVersion (const SpirvVersion version) { switch(version) { case SPIRV_VERSION_1_0: return VK_API_VERSION_1_0; case SPIRV_VERSION_1_1: case SPIRV_VERSION_1_2: case SPIRV_VERSION_1_3: case SPIRV_VERSION_1_4: return VK_API_VERSION_1_1; case SPIRV_VERSION_1_5: return VK_API_VERSION_1_2; case SPIRV_VERSION_1_6: #ifndef CTS_USES_VULKANSC return VK_API_VERSION_1_3; #else// CTS_USES_VULKANSC TCU_THROW(NotSupportedError, "Unsupported SPIR-V version"); #endif // CTS_USES_VULKANSC default: DE_ASSERT(0); } return 0u; } std::string getVulkanName (const deUint32 version) { if (version == VK_API_VERSION_1_1) return "1.1"; if (version == VK_API_VERSION_1_2) return "1.2"; #ifndef CTS_USES_VULKANSC if (version == VK_API_VERSION_1_3) return "1.3"; #endif // CTS_USES_VULKANSC return "1.0"; } // Generate and return 64-bit integers. // // Expected count to be at least 16. std::vector getInt64s (de::Random& rnd, const deUint32 count) { std::vector data; data.reserve(count); // Make sure we have boundary numbers. data.push_back(deInt64(0x0000000000000000)); // 0 data.push_back(deInt64(0x0000000000000001)); // 1 data.push_back(deInt64(0x000000000000002a)); // 42 data.push_back(deInt64(0x000000007fffffff)); // 2147483647 data.push_back(deInt64(0x0000000080000000)); // 2147483648 data.push_back(deInt64(0x00000000ffffffff)); // 4294967295 data.push_back(deInt64(0x0000000100000000)); // 4294967296 data.push_back(deInt64(0x7fffffffffffffff)); // 9223372036854775807 data.push_back(deInt64(0x8000000000000000)); // -9223372036854775808 data.push_back(deInt64(0x8000000000000001)); // -9223372036854775807 data.push_back(deInt64(0xffffffff00000000)); // -4294967296 data.push_back(deInt64(0xffffffff00000001)); // -4294967295 data.push_back(deInt64(0xffffffff80000000)); // -2147483648 data.push_back(deInt64(0xffffffff80000001)); // -2147483647 data.push_back(deInt64(0xffffffffffffffd6)); // -42 data.push_back(deInt64(0xffffffffffffffff)); // -1 DE_ASSERT(count >= data.size()); for (deUint32 numNdx = static_cast(data.size()); numNdx < count; ++numNdx) data.push_back(static_cast(rnd.getUint64())); return data; } // Generate and return 32-bit integers. // // Expected count to be at least 16. std::vector getInt32s (de::Random& rnd, const deUint32 count) { std::vector data; data.reserve(count); // Make sure we have boundary numbers. data.push_back(deInt32(0x00000000)); // 0 data.push_back(deInt32(0x00000001)); // 1 data.push_back(deInt32(0x0000002a)); // 42 data.push_back(deInt32(0x00007fff)); // 32767 data.push_back(deInt32(0x00008000)); // 32768 data.push_back(deInt32(0x0000ffff)); // 65535 data.push_back(deInt32(0x00010000)); // 65536 data.push_back(deInt32(0x7fffffff)); // 2147483647 data.push_back(deInt32(0x80000000)); // -2147483648 data.push_back(deInt32(0x80000001)); // -2147483647 data.push_back(deInt32(0xffff0000)); // -65536 data.push_back(deInt32(0xffff0001)); // -65535 data.push_back(deInt32(0xffff8000)); // -32768 data.push_back(deInt32(0xffff8001)); // -32767 data.push_back(deInt32(0xffffffd6)); // -42 data.push_back(deInt32(0xffffffff)); // -1 DE_ASSERT(count >= data.size()); for (deUint32 numNdx = static_cast(data.size()); numNdx < count; ++numNdx) data.push_back(static_cast(rnd.getUint32())); return data; } // Generate and return 16-bit integers. // // Expected count to be at least 8. std::vector getInt16s (de::Random& rnd, const deUint32 count) { std::vector data; data.reserve(count); // Make sure we have boundary numbers. data.push_back(deInt16(0x0000)); // 0 data.push_back(deInt16(0x0001)); // 1 data.push_back(deInt16(0x002a)); // 42 data.push_back(deInt16(0x7fff)); // 32767 data.push_back(deInt16(0x8000)); // -32868 data.push_back(deInt16(0x8001)); // -32767 data.push_back(deInt16(0xffd6)); // -42 data.push_back(deInt16(0xffff)); // -1 DE_ASSERT(count >= data.size()); for (deUint32 numNdx = static_cast(data.size()); numNdx < count; ++numNdx) data.push_back(static_cast(rnd.getUint16())); return data; } // Generate and return 8-bit integers. // // Expected count to be at least 8. std::vector getInt8s (de::Random& rnd, const deUint32 count) { std::vector data; data.reserve(count); // Make sure we have boundary numbers. data.push_back(deInt8(0x00)); // 0 data.push_back(deInt8(0x01)); // 1 data.push_back(deInt8(0x2a)); // 42 data.push_back(deInt8(0x7f)); // 127 data.push_back(deInt8(0x80)); // -128 data.push_back(deInt8(0x81)); // -127 data.push_back(deInt8(0xd6)); // -42 data.push_back(deInt8(0xff)); // -1 DE_ASSERT(count >= data.size()); for (deUint32 numNdx = static_cast(data.size()); numNdx < count; ++numNdx) data.push_back(static_cast(rnd.getUint8())); return data; } // IEEE-754 floating point numbers: // +--------+------+----------+-------------+ // | binary | sign | exponent | significand | // +--------+------+----------+-------------+ // | 64-bit | 1 | 11 | 52 | // +--------+------+----------+-------------+ // | 32-bit | 1 | 8 | 23 | // +--------+------+----------+-------------+ // | 16-bit | 1 | 5 | 10 | // +--------+------+----------+-------------+ // // 64-bit floats: // // (0x3FD2000000000000: 0.28125: with exact match in 16-bit normalized) // (0x3F10060000000000: exact half way within two 16-bit normalized; round to zero: 0x0401) // (0xBF10060000000000: exact half way within two 16-bit normalized; round to zero: 0x8402) // (0x3F100C0000000000: not exact half way within two 16-bit normalized; round to zero: 0x0403) // (0xBF100C0000000000: not exact half way within two 16-bit normalized; round to zero: 0x8404) // Generate and return 64-bit floats // // The first 24 number pairs are manually picked, while the rest are randomly generated. // Expected count to be at least 24 (numPicks). std::vector getFloat64s (de::Random& rnd, deUint32 count) { std::vector float64; float64.reserve(count); if (count >= 24) { // Zero float64.push_back(0.f); float64.push_back(-0.f); // Infinity float64.push_back(std::numeric_limits::infinity()); float64.push_back(-std::numeric_limits::infinity()); // SNaN float64.push_back(std::numeric_limits::signaling_NaN()); float64.push_back(-std::numeric_limits::signaling_NaN()); // QNaN float64.push_back(std::numeric_limits::quiet_NaN()); float64.push_back(-std::numeric_limits::quiet_NaN()); // Denormalized 64-bit float matching 0 in 16-bit float64.push_back(ldexp((double)1.f, -1023)); float64.push_back(-ldexp((double)1.f, -1023)); // Normalized 64-bit float matching 0 in 16-bit float64.push_back(ldexp((double)1.f, -100)); float64.push_back(-ldexp((double)1.f, -100)); // Normalized 64-bit float with exact denormalized match in 16-bit float64.push_back(bitwiseCast(deUint64(0x3B0357C299A88EA8))); float64.push_back(bitwiseCast(deUint64(0xBB0357C299A88EA8))); // Normalized 64-bit float with exact normalized match in 16-bit float64.push_back(ldexp((double)1.f, -14)); // 2e-14: minimum 16-bit positive normalized float64.push_back(-ldexp((double)1.f, -14)); // 2e-14: maximum 16-bit negative normalized // Normalized 64-bit float falling above half way within two 16-bit normalized float64.push_back(bitwiseCast(deUint64(0x3FD2000000000000))); float64.push_back(bitwiseCast(deUint64(0xBFD2000000000000))); // Normalized 64-bit float falling exact half way within two 16-bit normalized float64.push_back(bitwiseCast(deUint64(0x3F100C0000000000))); float64.push_back(bitwiseCast(deUint64(0xBF100C0000000000))); // Some number float64.push_back((double)0.28125f); float64.push_back((double)-0.28125f); // Normalized 64-bit float matching infinity in 16-bit float64.push_back(ldexp((double)1.f, 100)); float64.push_back(-ldexp((double)1.f, 100)); } const deUint32 numPicks = static_cast(float64.size()); DE_ASSERT(count >= numPicks); count -= numPicks; for (deUint32 numNdx = 0; numNdx < count; ++numNdx) { double randValue = rnd.getDouble(); float64.push_back(randValue); } return float64; } // IEEE-754 floating point numbers: // +--------+------+----------+-------------+ // | binary | sign | exponent | significand | // +--------+------+----------+-------------+ // | 16-bit | 1 | 5 | 10 | // +--------+------+----------+-------------+ // | 32-bit | 1 | 8 | 23 | // +--------+------+----------+-------------+ // // 16-bit floats: // // 0 000 00 00 0000 0001 (0x0001: 2e-24: minimum positive denormalized) // 0 000 00 11 1111 1111 (0x03ff: 2e-14 - 2e-24: maximum positive denormalized) // 0 000 01 00 0000 0000 (0x0400: 2e-14: minimum positive normalized) // // 32-bit floats: // // 0 011 1110 1 001 0000 0000 0000 0000 0000 (0x3e900000: 0.28125: with exact match in 16-bit normalized) // 0 011 1000 1 000 0000 0011 0000 0000 0000 (0x38803000: exact half way within two 16-bit normalized; round to zero: 0x0401) // 1 011 1000 1 000 0000 0011 0000 0000 0000 (0xb8803000: exact half way within two 16-bit normalized; round to zero: 0x8402) // 0 011 1000 1 000 0000 1111 1111 0000 0000 (0x3880ff00: not exact half way within two 16-bit normalized; round to zero: 0x0403) // 1 011 1000 1 000 0000 1111 1111 0000 0000 (0xb880ff00: not exact half way within two 16-bit normalized; round to zero: 0x8404) // Generate and return 32-bit floats // // The first 24 number pairs are manually picked, while the rest are randomly generated. // Expected count to be at least 24 (numPicks). std::vector getFloat32s (de::Random& rnd, deUint32 count) { std::vector float32; float32.reserve(count); // Zero float32.push_back(0.f); float32.push_back(-0.f); // Infinity float32.push_back(std::numeric_limits::infinity()); float32.push_back(-std::numeric_limits::infinity()); // SNaN float32.push_back(std::numeric_limits::signaling_NaN()); float32.push_back(-std::numeric_limits::signaling_NaN()); // QNaN float32.push_back(std::numeric_limits::quiet_NaN()); float32.push_back(-std::numeric_limits::quiet_NaN()); // Denormalized 32-bit float matching 0 in 16-bit float32.push_back(deFloatLdExp(1.f, -127)); float32.push_back(-deFloatLdExp(1.f, -127)); // Normalized 32-bit float matching 0 in 16-bit float32.push_back(deFloatLdExp(1.f, -100)); float32.push_back(-deFloatLdExp(1.f, -100)); // Normalized 32-bit float with exact denormalized match in 16-bit float32.push_back(deFloatLdExp(1.f, -24)); // 2e-24: minimum 16-bit positive denormalized float32.push_back(-deFloatLdExp(1.f, -24)); // 2e-24: maximum 16-bit negative denormalized // Normalized 32-bit float with exact normalized match in 16-bit float32.push_back(deFloatLdExp(1.f, -14)); // 2e-14: minimum 16-bit positive normalized float32.push_back(-deFloatLdExp(1.f, -14)); // 2e-14: maximum 16-bit negative normalized // Normalized 32-bit float falling above half way within two 16-bit normalized float32.push_back(bitwiseCast(deUint32(0x3880ff00))); float32.push_back(bitwiseCast(deUint32(0xb880ff00))); // Normalized 32-bit float falling exact half way within two 16-bit normalized float32.push_back(bitwiseCast(deUint32(0x38803000))); float32.push_back(bitwiseCast(deUint32(0xb8803000))); // Some number float32.push_back(0.28125f); float32.push_back(-0.28125f); // Normalized 32-bit float matching infinity in 16-bit float32.push_back(deFloatLdExp(1.f, 100)); float32.push_back(-deFloatLdExp(1.f, 100)); const deUint32 numPicks = static_cast(float32.size()); DE_ASSERT(count >= numPicks); count -= numPicks; for (deUint32 numNdx = 0; numNdx < count; ++numNdx) float32.push_back(rnd.getFloat()); return float32; } // IEEE-754 floating point numbers: // +--------+------+----------+-------------+ // | binary | sign | exponent | significand | // +--------+------+----------+-------------+ // | 16-bit | 1 | 5 | 10 | // +--------+------+----------+-------------+ // | 32-bit | 1 | 8 | 23 | // +--------+------+----------+-------------+ // // 16-bit floats: // // 0 000 00 00 0000 0001 (0x0001: 2e-24: minimum positive denormalized) // 0 000 00 11 1111 1111 (0x03ff: 2e-14 - 2e-24: maximum positive denormalized) // 0 000 01 00 0000 0000 (0x0400: 2e-14: minimum positive normalized) // // 0 000 00 00 0000 0000 (0x0000: +0) // 0 111 11 00 0000 0000 (0x7c00: +Inf) // 0 000 00 11 1111 0000 (0x03f0: +Denorm) // 0 000 01 00 0000 0001 (0x0401: +Norm) // 0 111 11 00 0000 1111 (0x7c0f: +SNaN) // 0 111 11 00 1111 0000 (0x7c0f: +QNaN) // Generate and return 16-bit floats and their corresponding 32-bit values. // // The first 14 number pairs are manually picked, while the rest are randomly generated. // Expected count to be at least 14 (numPicks). std::vector getFloat16s (de::Random& rnd, deUint32 count) { std::vector float16; float16.reserve(count); // Zero float16.push_back(deUint16(0x0000)); float16.push_back(deUint16(0x8000)); // Infinity float16.push_back(deUint16(0x7c00)); float16.push_back(deUint16(0xfc00)); // SNaN float16.push_back(deUint16(0x7c0f)); float16.push_back(deUint16(0xfc0f)); // QNaN float16.push_back(deUint16(0x7cf0)); float16.push_back(deUint16(0xfcf0)); // Denormalized float16.push_back(deUint16(0x03f0)); float16.push_back(deUint16(0x83f0)); // Normalized float16.push_back(deUint16(0x0401)); float16.push_back(deUint16(0x8401)); // Some normal number float16.push_back(deUint16(0x14cb)); float16.push_back(deUint16(0x94cb)); const deUint32 numPicks = static_cast(float16.size()); DE_ASSERT(count >= numPicks); count -= numPicks; for (deUint32 numIdx = 0; numIdx < count; ++numIdx) float16.push_back(rnd.getUint16()); return float16; } std::string getOpCapabilityShader() { return "OpCapability Shader\n"; } std::string getUnusedEntryPoint() { return "OpEntryPoint Vertex %unused_func \"unused_func\"\n"; } std::string getUnusedDecorations(const VariableLocation& location) { return "OpMemberDecorate %UnusedBufferType 0 Offset 0\n" "OpMemberDecorate %UnusedBufferType 1 Offset 4\n" "OpDecorate %UnusedBufferType BufferBlock\n" "OpDecorate %unused_buffer DescriptorSet " + de::toString(location.set) + "\n" "OpDecorate %unused_buffer Binding " + de::toString(location.binding) + "\n"; } std::string getUnusedTypesAndConstants() { return "%c_f32_101 = OpConstant %f32 101\n" "%c_i32_201 = OpConstant %i32 201\n" "%UnusedBufferType = OpTypeStruct %f32 %i32\n" "%unused_ptr_Uniform_UnusedBufferType = OpTypePointer Uniform %UnusedBufferType\n" "%unused_ptr_Uniform_float = OpTypePointer Uniform %f32\n" "%unused_ptr_Uniform_int = OpTypePointer Uniform %i32\n"; } std::string getUnusedBuffer() { return "%unused_buffer = OpVariable %unused_ptr_Uniform_UnusedBufferType Uniform\n"; } std::string getUnusedFunctionBody() { return "%unused_func = OpFunction %void None %voidf\n" "%unused_func_label = OpLabel\n" "%unused_out_float_ptr = OpAccessChain %unused_ptr_Uniform_float %unused_buffer %c_i32_0\n" "OpStore %unused_out_float_ptr %c_f32_101\n" "%unused_out_int_ptr = OpAccessChain %unused_ptr_Uniform_int %unused_buffer %c_i32_1\n" "OpStore %unused_out_int_ptr %c_i32_201\n" "OpReturn\n" "OpFunctionEnd\n"; } } // SpirVAssembly } // vkt