blob: 3182a79c5bc8ca7e46a8851a34f7f2ce25ab8610 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 <limits>
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);
}
bool is8BitStorageFeaturesSupported (const Context& context, Extension8BitStorageFeatures toCheck)
{
VkPhysicalDevice8BitStorageFeaturesKHR extensionFeatures = context.get8BitStorageFeatures();
if ((toCheck & EXT8BITSTORAGEFEATURES_STORAGE_BUFFER) != 0 && extensionFeatures.storageBuffer8BitAccess == VK_FALSE)
TCU_FAIL("storageBuffer8BitAccess has to be supported");
if ((toCheck & EXT8BITSTORAGEFEATURES_UNIFORM_STORAGE_BUFFER) != 0 && extensionFeatures.uniformAndStorageBuffer8BitAccess == VK_FALSE)
return false;
if ((toCheck & EXT8BITSTORAGEFEATURES_PUSH_CONSTANT) != 0 && extensionFeatures.storagePushConstant8 == VK_FALSE)
return false;
return true;
}
#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;
}
bool is16BitStorageFeaturesSupported (const Context& context, Extension16BitStorageFeatures toCheck)
{
const VkPhysicalDevice16BitStorageFeatures& extensionFeatures = context.get16BitStorageFeatures();
if ((toCheck & EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK) != 0 && extensionFeatures.storageBuffer16BitAccess == VK_FALSE)
return false;
if ((toCheck & EXT16BITSTORAGEFEATURES_UNIFORM) != 0 && extensionFeatures.uniformAndStorageBuffer16BitAccess == VK_FALSE)
return false;
if ((toCheck & EXT16BITSTORAGEFEATURES_PUSH_CONSTANT) != 0 && extensionFeatures.storagePushConstant16 == VK_FALSE)
return false;
if ((toCheck & EXT16BITSTORAGEFEATURES_INPUT_OUTPUT) != 0 && extensionFeatures.storageInputOutput16 == VK_FALSE)
return false;
return true;
}
bool isVariablePointersFeaturesSupported (const Context& context, ExtensionVariablePointersFeatures toCheck)
{
const VkPhysicalDeviceVariablePointersFeatures& extensionFeatures = context.getVariablePointersFeatures();
if ((toCheck & EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER) != 0 && extensionFeatures.variablePointersStorageBuffer == VK_FALSE)
return false;
if ((toCheck & EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS) != 0 && extensionFeatures.variablePointers == VK_FALSE)
return false;
return true;
}
bool isFloat16Int8FeaturesSupported (const Context& context, ExtensionFloat16Int8Features toCheck)
{
const VkPhysicalDeviceFloat16Int8FeaturesKHR& extensionFeatures = context.getShaderFloat16Int8Features();
if ((toCheck & EXTFLOAT16INT8FEATURES_FLOAT16) != 0 && extensionFeatures.shaderFloat16 == VK_FALSE)
return false;
if ((toCheck & EXTFLOAT16INT8FEATURES_INT8) != 0 && extensionFeatures.shaderInt8 == VK_FALSE)
return false;
return true;
}
bool isFloatControlsFeaturesSupported (const Context& context, const ExtensionFloatControlsFeatures& toCheck)
{
// 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;
// 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
ExtensionFloatControlsFeatures refControls;
{
refControls.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR;
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 = VkShaderFloatControlsIndependenceKHR;
FCIndependence fcInd32 = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR;
FCIndependence fcIndAll = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR;
FCIndependence fcIndNone = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR;
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;
}
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;
default:
DE_ASSERT(0);
}
return 0u;
}
std::string getVulkanName (const deUint32 version)
{
return std::string(version == VK_API_VERSION_1_1 ? "1.1" : "1.0");
}
// Generate and return 64-bit integers.
//
// Expected count to be at least 16.
std::vector<deInt64> getInt64s (de::Random& rnd, const deUint32 count)
{
std::vector<deInt64> 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<deUint32>(data.size()); numNdx < count; ++numNdx)
data.push_back(static_cast<deInt64>(rnd.getUint64()));
return data;
}
// Generate and return 32-bit integers.
//
// Expected count to be at least 16.
std::vector<deInt32> getInt32s (de::Random& rnd, const deUint32 count)
{
std::vector<deInt32> 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<deUint32>(data.size()); numNdx < count; ++numNdx)
data.push_back(static_cast<deInt32>(rnd.getUint32()));
return data;
}
// Generate and return 16-bit integers.
//
// Expected count to be at least 8.
std::vector<deInt16> getInt16s (de::Random& rnd, const deUint32 count)
{
std::vector<deInt16> 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<deUint32>(data.size()); numNdx < count; ++numNdx)
data.push_back(static_cast<deInt16>(rnd.getUint16()));
return data;
}
// Generate and return 8-bit integers.
//
// Expected count to be at least 8.
std::vector<deInt8> getInt8s (de::Random& rnd, const deUint32 count)
{
std::vector<deInt8> 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<deUint32>(data.size()); numNdx < count; ++numNdx)
data.push_back(static_cast<deInt8>(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<double> getFloat64s (de::Random& rnd, deUint32 count)
{
std::vector<double> 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<double>::infinity());
float64.push_back(-std::numeric_limits<double>::infinity());
// SNaN
float64.push_back(std::numeric_limits<double>::signaling_NaN());
float64.push_back(-std::numeric_limits<double>::signaling_NaN());
// QNaN
float64.push_back(std::numeric_limits<double>::quiet_NaN());
float64.push_back(-std::numeric_limits<double>::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<double>(deUint64(0x3B0357C299A88EA8)));
float64.push_back(bitwiseCast<double>(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<double>(deUint64(0x3FD2000000000000)));
float64.push_back(bitwiseCast<double>(deUint64(0xBFD2000000000000)));
// Normalized 64-bit float falling exact half way within two 16-bit normalized
float64.push_back(bitwiseCast<double>(deUint64(0x3F100C0000000000)));
float64.push_back(bitwiseCast<double>(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<deUint32>(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<float> getFloat32s (de::Random& rnd, deUint32 count)
{
std::vector<float> float32;
float32.reserve(count);
// Zero
float32.push_back(0.f);
float32.push_back(-0.f);
// Infinity
float32.push_back(std::numeric_limits<float>::infinity());
float32.push_back(-std::numeric_limits<float>::infinity());
// SNaN
float32.push_back(std::numeric_limits<float>::signaling_NaN());
float32.push_back(-std::numeric_limits<float>::signaling_NaN());
// QNaN
float32.push_back(std::numeric_limits<float>::quiet_NaN());
float32.push_back(-std::numeric_limits<float>::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<float>(deUint32(0x3880ff00)));
float32.push_back(bitwiseCast<float>(deUint32(0xb880ff00)));
// Normalized 32-bit float falling exact half way within two 16-bit normalized
float32.push_back(bitwiseCast<float>(deUint32(0x38803000)));
float32.push_back(bitwiseCast<float>(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<deUint32>(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<deFloat16> getFloat16s (de::Random& rnd, deUint32 count)
{
std::vector<deFloat16> 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<deUint32>(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