| /*------------------------------------------------------------------------- |
| * 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 SPIR-V Assembly Tests for the VK_KHR_16bit_storage |
| *//*--------------------------------------------------------------------*/ |
| |
| // VK_KHR_16bit_storage |
| // |
| // \todo [2017-02-08 antiagainst] Additional corner cases to check: |
| // |
| // * Test OpAccessChain with subword types |
| // * For newly enabled types T: |
| // * For composite types: vector, matrix, structures, array over T: |
| // 1. Use OpAccessChain to form a pointer to a subword type. |
| // 2. Load the subword value X16. |
| // 3. Convert X16 to X32. |
| // 4. Store X32 to BufferBlock. |
| // 5. Host inspects X32. |
| // * Test {StorageInputOutput16} 16-to-16: |
| // * For newly enabled types T: |
| // 1. Host creates X16 stream values of type T. |
| // 2. Shaders have corresponding capability. |
| // 3. For each viable shader stage: |
| // 3a. Load X16 Input variable. |
| // 3b. Store X16 to Output variable. |
| // 4. Host inspects resulting values. |
| // * Test {StorageInputOutput16} 16-to-16 one value to two: |
| // Like the previous test, but write X16 to two different output variables. |
| // (Checks that the 16-bit intermediate value can be used twice.) |
| |
| #include "vktSpvAsm16bitStorageTests.hpp" |
| |
| #include "tcuFloat.hpp" |
| #include "tcuRGBA.hpp" |
| #include "tcuStringTemplate.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuVectorUtil.hpp" |
| |
| #include "vkDefs.hpp" |
| #include "vkDeviceUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkPlatform.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkRef.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkStrUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| |
| #include "deRandom.hpp" |
| #include "deStringUtil.hpp" |
| #include "deUniquePtr.hpp" |
| #include "deMath.h" |
| |
| #include "vktSpvAsmComputeShaderCase.hpp" |
| #include "vktSpvAsmComputeShaderTestUtil.hpp" |
| #include "vktSpvAsmGraphicsShaderTestUtil.hpp" |
| #include "vktTestCaseUtil.hpp" |
| #include "vktTestGroupUtil.hpp" |
| |
| #include <limits> |
| #include <map> |
| #include <string> |
| #include <sstream> |
| #include <utility> |
| |
| namespace vkt |
| { |
| namespace SpirVAssembly |
| { |
| |
| using namespace vk; |
| using std::map; |
| using std::string; |
| using std::vector; |
| using tcu::IVec3; |
| using tcu::IVec4; |
| using tcu::RGBA; |
| using tcu::TestLog; |
| using tcu::TestStatus; |
| using tcu::Vec4; |
| using de::UniquePtr; |
| using tcu::StringTemplate; |
| using tcu::Vec4; |
| |
| namespace |
| { |
| |
| struct Capability |
| { |
| const char* name; |
| const char* cap; |
| const char* decor; |
| vk::VkDescriptorType dtype; |
| }; |
| |
| static const Capability CAPABILITIES[] = |
| { |
| {"uniform_buffer_block", "StorageUniformBufferBlock16", "BufferBlock", VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}, |
| {"uniform", "StorageUniform16", "Block", VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER}, |
| }; |
| |
| VulkanFeatures get16BitStorageFeatures (const char* cap) |
| { |
| VulkanFeatures features; |
| if (string(cap) == "uniform_buffer_block") |
| features.ext16BitStorage = EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK; |
| else if (string(cap) == "uniform") |
| features.ext16BitStorage = EXT16BITSTORAGEFEATURES_UNIFORM; |
| else |
| DE_ASSERT(false && "not supported"); |
| |
| return features; |
| } |
| |
| |
| // Batch function to check arrays of 16-bit floats. |
| // |
| // For comparing 16-bit floats, we need to consider both RTZ and RTE. So we can only recalculate |
| // the expected values here instead of get the expected values directly from the test case. |
| // Thus we need original floats here but not expected outputs. |
| template<RoundingModeFlags RoundingMode> |
| bool graphicsCheck16BitFloats (const std::vector<Resource>& originalFloats, |
| const vector<AllocationSp>& outputAllocs, |
| const std::vector<Resource>& /* expectedOutputs */, |
| tcu::TestLog& log) |
| { |
| if (outputAllocs.size() != originalFloats.size()) |
| return false; |
| |
| for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx) |
| { |
| const deUint16* returned = static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr()); |
| const float* original = static_cast<const float*>(originalFloats[outputNdx].second->data()); |
| const deUint32 count = static_cast<deUint32>(originalFloats[outputNdx].second->getNumBytes() / sizeof(float)); |
| |
| for (deUint32 numNdx = 0; numNdx < count; ++numNdx) |
| if (!compare16BitFloat(original[numNdx], returned[numNdx], RoundingMode, log)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| template<RoundingModeFlags RoundingMode> |
| bool computeCheck16BitFloats (const std::vector<BufferSp>& originalFloats, |
| const vector<AllocationSp>& outputAllocs, |
| const std::vector<BufferSp>& /* expectedOutputs */, |
| tcu::TestLog& log) |
| { |
| if (outputAllocs.size() != originalFloats.size()) |
| return false; |
| |
| for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx) |
| { |
| const deUint16* returned = static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr()); |
| const float* original = static_cast<const float*>(originalFloats[outputNdx]->data()); |
| const deUint32 count = static_cast<deUint32>(originalFloats[outputNdx]->getNumBytes() / sizeof(float)); |
| |
| for (deUint32 numNdx = 0; numNdx < count; ++numNdx) |
| if (!compare16BitFloat(original[numNdx], returned[numNdx], RoundingMode, log)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| // Batch function to check arrays of 32-bit floats. |
| // |
| // For comparing 32-bit floats, we just need the expected value precomputed in the test case. |
| // So we need expected outputs here but not original floats. |
| bool check32BitFloats (const std::vector<Resource>& /* originalFloats */, |
| const std::vector<AllocationSp>& outputAllocs, |
| const std::vector<Resource>& expectedOutputs, |
| tcu::TestLog& log) |
| { |
| if (outputAllocs.size() != expectedOutputs.size()) |
| return false; |
| |
| for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx) |
| { |
| const float* returnedAsFloat = static_cast<const float*>(outputAllocs[outputNdx]->getHostPtr()); |
| const float* expectedAsFloat = static_cast<const float*>(expectedOutputs[outputNdx].second->data()); |
| const deUint32 count = static_cast<deUint32>(expectedOutputs[outputNdx].second->getNumBytes() / sizeof(float)); |
| |
| for (deUint32 numNdx = 0; numNdx < count; ++numNdx) |
| if (!compare32BitFloat(expectedAsFloat[numNdx], returnedAsFloat[numNdx], log)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // Overload for compute pipeline |
| bool check32BitFloats (const std::vector<BufferSp>& /* originalFloats */, |
| const std::vector<AllocationSp>& outputAllocs, |
| const std::vector<BufferSp>& expectedOutputs, |
| tcu::TestLog& log) |
| { |
| if (outputAllocs.size() != expectedOutputs.size()) |
| return false; |
| |
| for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx) |
| { |
| const float* returnedAsFloat = static_cast<const float*>(outputAllocs[outputNdx]->getHostPtr()); |
| const float* expectedAsFloat = static_cast<const float*>(expectedOutputs[outputNdx]->data()); |
| const deUint32 count = static_cast<deUint32>(expectedOutputs[outputNdx]->getNumBytes() / sizeof(float)); |
| |
| for (deUint32 numNdx = 0; numNdx < count; ++numNdx) |
| if (!compare32BitFloat(expectedAsFloat[numNdx], returnedAsFloat[numNdx], log)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // Generate and return 32-bit integers. |
| // |
| // Expected count to be at least 16. |
| vector<deInt32> getInt32s (de::Random& rnd, const deUint32 count) |
| { |
| 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. |
| vector<deInt16> getInt16s (de::Random& rnd, const deUint32 count) |
| { |
| 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; |
| } |
| |
| // 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). |
| vector<float> getFloat32s (de::Random& rnd, deUint32 count) |
| { |
| 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). |
| vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count) |
| { |
| 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; |
| } |
| |
| void addCompute16bitStorageUniform16To32Group (tcu::TestCaseGroup* group) |
| { |
| tcu::TestContext& testCtx = group->getTestContext(); |
| de::Random rnd (deStringHash(group->getName())); |
| const int numElements = 128; |
| |
| const StringTemplate shaderTemplate ( |
| "OpCapability Shader\n" |
| "OpCapability ${capability}\n" |
| "OpExtension \"SPV_KHR_16bit_storage\"\n" |
| "OpMemoryModel Logical GLSL450\n" |
| "OpEntryPoint GLCompute %main \"main\" %id\n" |
| "OpExecutionMode %main LocalSize 1 1 1\n" |
| "OpDecorate %id BuiltIn GlobalInvocationId\n" |
| |
| "${stride}" |
| |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpDecorate %SSBO16 ${storage}\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 1\n" |
| "OpDecorate %ssbo16 Binding 0\n" |
| |
| "${matrix_decor:opt}\n" |
| |
| "%bool = OpTypeBool\n" |
| "%void = OpTypeVoid\n" |
| "%voidf = OpTypeFunction %void\n" |
| "%u32 = OpTypeInt 32 0\n" |
| "%i32 = OpTypeInt 32 1\n" |
| "%f32 = OpTypeFloat 32\n" |
| "%uvec3 = OpTypeVector %u32 3\n" |
| "%fvec3 = OpTypeVector %f32 3\n" |
| "%uvec3ptr = OpTypePointer Input %uvec3\n" |
| "%i32ptr = OpTypePointer Uniform %i32\n" |
| "%f32ptr = OpTypePointer Uniform %f32\n" |
| |
| "%zero = OpConstant %i32 0\n" |
| "%c_i32_1 = OpConstant %i32 1\n" |
| "%c_i32_2 = OpConstant %i32 2\n" |
| "%c_i32_3 = OpConstant %i32 3\n" |
| "%c_i32_16 = OpConstant %i32 16\n" |
| "%c_i32_32 = OpConstant %i32 32\n" |
| "%c_i32_64 = OpConstant %i32 64\n" |
| "%c_i32_128 = OpConstant %i32 128\n" |
| |
| "%i32arr = OpTypeArray %i32 %c_i32_128\n" |
| "%f32arr = OpTypeArray %f32 %c_i32_128\n" |
| |
| "${types}\n" |
| "${matrix_types:opt}\n" |
| |
| "%SSBO32 = OpTypeStruct %${matrix_prefix:opt}${base32}arr\n" |
| "%SSBO16 = OpTypeStruct %${matrix_prefix:opt}${base16}arr\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| "%ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| "%ssbo16 = OpVariable %up_SSBO16 Uniform\n" |
| |
| "%id = OpVariable %uvec3ptr Input\n" |
| |
| "%main = OpFunction %void None %voidf\n" |
| "%label = OpLabel\n" |
| "%idval = OpLoad %uvec3 %id\n" |
| "%x = OpCompositeExtract %u32 %idval 0\n" |
| "%inloc = OpAccessChain %${base16}ptr %ssbo16 %zero %x ${index0:opt}\n" |
| "%val16 = OpLoad %${base16} %inloc\n" |
| "%val32 = ${convert} %${base32} %val16\n" |
| "%outloc = OpAccessChain %${base32}ptr %ssbo32 %zero %x ${index0:opt}\n" |
| " OpStore %outloc %val32\n" |
| "${matrix_store:opt}\n" |
| " OpReturn\n" |
| " OpFunctionEnd\n"); |
| |
| { // floats |
| const char floatTypes[] = |
| "%f16 = OpTypeFloat 16\n" |
| "%f16ptr = OpTypePointer Uniform %f16\n" |
| "%f16arr = OpTypeArray %f16 %c_i32_128\n" |
| "%v2f16 = OpTypeVector %f16 2\n" |
| "%v2f32 = OpTypeVector %f32 2\n" |
| "%v2f16ptr = OpTypePointer Uniform %v2f16\n" |
| "%v2f32ptr = OpTypePointer Uniform %v2f32\n" |
| "%v2f16arr = OpTypeArray %v2f16 %c_i32_64\n" |
| "%v2f32arr = OpTypeArray %v2f32 %c_i32_64\n"; |
| |
| struct CompositeType |
| { |
| const char* name; |
| const char* base32; |
| const char* base16; |
| const char* stride; |
| unsigned count; |
| }; |
| |
| const CompositeType cTypes[] = |
| { |
| {"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", numElements}, |
| {"vector", "v2f32", "v2f16", "OpDecorate %v2f32arr ArrayStride 8\nOpDecorate %v2f16arr ArrayStride 4\n", numElements / 2}, |
| {"matrix", "v2f32", "v2f16", "OpDecorate %m4v2f32arr ArrayStride 32\nOpDecorate %m4v2f16arr ArrayStride 16\n", numElements / 8}, |
| }; |
| |
| vector<deFloat16> float16Data = getFloat16s(rnd, numElements); |
| vector<float> float32Data; |
| |
| float32Data.reserve(numElements); |
| for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx) |
| float32Data.push_back(deFloat16To32(float16Data[numIdx])); |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx) |
| { |
| ComputeShaderSpec spec; |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name + "_float"; |
| |
| specs["capability"] = CAPABILITIES[capIdx].cap; |
| specs["storage"] = CAPABILITIES[capIdx].decor; |
| specs["stride"] = cTypes[tyIdx].stride; |
| specs["base32"] = cTypes[tyIdx].base32; |
| specs["base16"] = cTypes[tyIdx].base16; |
| specs["types"] = floatTypes; |
| specs["convert"] = "OpFConvert"; |
| |
| if (strcmp(cTypes[tyIdx].name, "matrix") == 0) |
| { |
| specs["index0"] = "%zero"; |
| specs["matrix_prefix"] = "m4"; |
| specs["matrix_types"] = |
| "%m4v2f16 = OpTypeMatrix %v2f16 4\n" |
| "%m4v2f32 = OpTypeMatrix %v2f32 4\n" |
| "%m4v2f16arr = OpTypeArray %m4v2f16 %c_i32_16\n" |
| "%m4v2f32arr = OpTypeArray %m4v2f32 %c_i32_16\n"; |
| specs["matrix_decor"] = |
| "OpMemberDecorate %SSBO32 0 ColMajor\n" |
| "OpMemberDecorate %SSBO32 0 MatrixStride 8\n" |
| "OpMemberDecorate %SSBO16 0 ColMajor\n" |
| "OpMemberDecorate %SSBO16 0 MatrixStride 4\n"; |
| specs["matrix_store"] = |
| "%inloc_1 = OpAccessChain %v2f16ptr %ssbo16 %zero %x %c_i32_1\n" |
| "%val16_1 = OpLoad %v2f16 %inloc_1\n" |
| "%val32_1 = OpFConvert %v2f32 %val16_1\n" |
| "%outloc_1 = OpAccessChain %v2f32ptr %ssbo32 %zero %x %c_i32_1\n" |
| " OpStore %outloc_1 %val32_1\n" |
| |
| "%inloc_2 = OpAccessChain %v2f16ptr %ssbo16 %zero %x %c_i32_2\n" |
| "%val16_2 = OpLoad %v2f16 %inloc_2\n" |
| "%val32_2 = OpFConvert %v2f32 %val16_2\n" |
| "%outloc_2 = OpAccessChain %v2f32ptr %ssbo32 %zero %x %c_i32_2\n" |
| " OpStore %outloc_2 %val32_2\n" |
| |
| "%inloc_3 = OpAccessChain %v2f16ptr %ssbo16 %zero %x %c_i32_3\n" |
| "%val16_3 = OpLoad %v2f16 %inloc_3\n" |
| "%val32_3 = OpFConvert %v2f32 %val16_3\n" |
| "%outloc_3 = OpAccessChain %v2f32ptr %ssbo32 %zero %x %c_i32_3\n" |
| " OpStore %outloc_3 %val32_3\n"; |
| } |
| |
| spec.assembly = shaderTemplate.specialize(specs); |
| spec.numWorkGroups = IVec3(cTypes[tyIdx].count, 1, 1); |
| spec.verifyIO = check32BitFloats; |
| spec.inputTypes[0] = CAPABILITIES[capIdx].dtype; |
| |
| spec.inputs.push_back(BufferSp(new Float16Buffer(float16Data))); |
| spec.outputs.push_back(BufferSp(new Float32Buffer(float32Data))); |
| spec.extensions.push_back("VK_KHR_16bit_storage"); |
| spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name); |
| |
| group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec)); |
| } |
| } |
| |
| { // Integers |
| const char sintTypes[] = |
| "%i16 = OpTypeInt 16 1\n" |
| "%i16ptr = OpTypePointer Uniform %i16\n" |
| "%i16arr = OpTypeArray %i16 %c_i32_128\n" |
| "%v4i16 = OpTypeVector %i16 4\n" |
| "%v4i32 = OpTypeVector %i32 4\n" |
| "%v4i16ptr = OpTypePointer Uniform %v4i16\n" |
| "%v4i32ptr = OpTypePointer Uniform %v4i32\n" |
| "%v4i16arr = OpTypeArray %v4i16 %c_i32_32\n" |
| "%v4i32arr = OpTypeArray %v4i32 %c_i32_32\n"; |
| |
| const char uintTypes[] = |
| "%u16 = OpTypeInt 16 0\n" |
| "%u16ptr = OpTypePointer Uniform %u16\n" |
| "%u32ptr = OpTypePointer Uniform %u32\n" |
| "%u16arr = OpTypeArray %u16 %c_i32_128\n" |
| "%u32arr = OpTypeArray %u32 %c_i32_128\n" |
| "%v4u16 = OpTypeVector %u16 4\n" |
| "%v4u32 = OpTypeVector %u32 4\n" |
| "%v4u16ptr = OpTypePointer Uniform %v4u16\n" |
| "%v4u32ptr = OpTypePointer Uniform %v4u32\n" |
| "%v4u16arr = OpTypeArray %v4u16 %c_i32_32\n" |
| "%v4u32arr = OpTypeArray %v4u32 %c_i32_32\n"; |
| |
| struct CompositeType |
| { |
| const char* name; |
| bool isSigned; |
| const char* types; |
| const char* base32; |
| const char* base16; |
| const char* opcode; |
| const char* stride; |
| unsigned count; |
| }; |
| |
| const CompositeType cTypes[] = |
| { |
| {"scalar_sint", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", numElements}, |
| {"scalar_uint", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", numElements}, |
| {"vector_sint", true, sintTypes, "v4i32", "v4i16", "OpSConvert", "OpDecorate %v4i32arr ArrayStride 16\nOpDecorate %v4i16arr ArrayStride 8\n", numElements / 4}, |
| {"vector_uint", false, uintTypes, "v4u32", "v4u16", "OpUConvert", "OpDecorate %v4u32arr ArrayStride 16\nOpDecorate %v4u16arr ArrayStride 8\n", numElements / 4}, |
| }; |
| |
| vector<deInt16> inputs = getInt16s(rnd, numElements); |
| vector<deInt32> sOutputs; |
| vector<deInt32> uOutputs; |
| const deUint16 signBitMask = 0x8000; |
| const deUint32 signExtendMask = 0xffff0000; |
| |
| sOutputs.reserve(inputs.size()); |
| uOutputs.reserve(inputs.size()); |
| |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| { |
| uOutputs.push_back(static_cast<deUint16>(inputs[numNdx])); |
| if (inputs[numNdx] & signBitMask) |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask)); |
| else |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx])); |
| } |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx) |
| { |
| ComputeShaderSpec spec; |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name; |
| |
| specs["capability"] = CAPABILITIES[capIdx].cap; |
| specs["storage"] = CAPABILITIES[capIdx].decor; |
| specs["stride"] = cTypes[tyIdx].stride; |
| specs["base32"] = cTypes[tyIdx].base32; |
| specs["base16"] = cTypes[tyIdx].base16; |
| specs["types"] = cTypes[tyIdx].types; |
| specs["convert"] = cTypes[tyIdx].opcode; |
| |
| spec.assembly = shaderTemplate.specialize(specs); |
| spec.numWorkGroups = IVec3(cTypes[tyIdx].count, 1, 1); |
| spec.inputTypes[0] = CAPABILITIES[capIdx].dtype; |
| |
| spec.inputs.push_back(BufferSp(new Int16Buffer(inputs))); |
| if (cTypes[tyIdx].isSigned) |
| spec.outputs.push_back(BufferSp(new Int32Buffer(sOutputs))); |
| else |
| spec.outputs.push_back(BufferSp(new Int32Buffer(uOutputs))); |
| spec.extensions.push_back("VK_KHR_16bit_storage"); |
| spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name); |
| |
| group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec)); |
| } |
| } |
| } |
| |
| void addCompute16bitStoragePushConstant16To32Group (tcu::TestCaseGroup* group) |
| { |
| tcu::TestContext& testCtx = group->getTestContext(); |
| de::Random rnd (deStringHash(group->getName())); |
| const int numElements = 64; |
| |
| const StringTemplate shaderTemplate ( |
| "OpCapability Shader\n" |
| "OpCapability StoragePushConstant16\n" |
| "OpExtension \"SPV_KHR_16bit_storage\"\n" |
| "OpMemoryModel Logical GLSL450\n" |
| "OpEntryPoint GLCompute %main \"main\" %id\n" |
| "OpExecutionMode %main LocalSize 1 1 1\n" |
| "OpDecorate %id BuiltIn GlobalInvocationId\n" |
| |
| "${stride}" |
| |
| "OpDecorate %PC16 Block\n" |
| "OpMemberDecorate %PC16 0 Offset 0\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n" |
| |
| "${matrix_decor:opt}\n" |
| |
| "%bool = OpTypeBool\n" |
| "%void = OpTypeVoid\n" |
| "%voidf = OpTypeFunction %void\n" |
| "%u32 = OpTypeInt 32 0\n" |
| "%i32 = OpTypeInt 32 1\n" |
| "%f32 = OpTypeFloat 32\n" |
| "%uvec3 = OpTypeVector %u32 3\n" |
| "%fvec3 = OpTypeVector %f32 3\n" |
| "%uvec3ptr = OpTypePointer Input %uvec3\n" |
| "%i32ptr = OpTypePointer Uniform %i32\n" |
| "%f32ptr = OpTypePointer Uniform %f32\n" |
| |
| "%zero = OpConstant %i32 0\n" |
| "%c_i32_1 = OpConstant %i32 1\n" |
| "%c_i32_8 = OpConstant %i32 8\n" |
| "%c_i32_16 = OpConstant %i32 16\n" |
| "%c_i32_32 = OpConstant %i32 32\n" |
| "%c_i32_64 = OpConstant %i32 64\n" |
| |
| "%i32arr = OpTypeArray %i32 %c_i32_64\n" |
| "%f32arr = OpTypeArray %f32 %c_i32_64\n" |
| |
| "${types}\n" |
| "${matrix_types:opt}\n" |
| |
| "%PC16 = OpTypeStruct %${matrix_prefix:opt}${base16}arr\n" |
| "%pp_PC16 = OpTypePointer PushConstant %PC16\n" |
| "%pc16 = OpVariable %pp_PC16 PushConstant\n" |
| "%SSBO32 = OpTypeStruct %${matrix_prefix:opt}${base32}arr\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| |
| "%id = OpVariable %uvec3ptr Input\n" |
| |
| "%main = OpFunction %void None %voidf\n" |
| "%label = OpLabel\n" |
| "%idval = OpLoad %uvec3 %id\n" |
| "%x = OpCompositeExtract %u32 %idval 0\n" |
| "%inloc = OpAccessChain %${base16}ptr %pc16 %zero %x ${index0:opt}\n" |
| "%val16 = OpLoad %${base16} %inloc\n" |
| "%val32 = ${convert} %${base32} %val16\n" |
| "%outloc = OpAccessChain %${base32}ptr %ssbo32 %zero %x ${index0:opt}\n" |
| " OpStore %outloc %val32\n" |
| "${matrix_store:opt}\n" |
| " OpReturn\n" |
| " OpFunctionEnd\n"); |
| |
| { // floats |
| const char floatTypes[] = |
| "%f16 = OpTypeFloat 16\n" |
| "%f16ptr = OpTypePointer PushConstant %f16\n" |
| "%f16arr = OpTypeArray %f16 %c_i32_64\n" |
| "%v4f16 = OpTypeVector %f16 4\n" |
| "%v4f32 = OpTypeVector %f32 4\n" |
| "%v4f16ptr = OpTypePointer PushConstant %v4f16\n" |
| "%v4f32ptr = OpTypePointer Uniform %v4f32\n" |
| "%v4f16arr = OpTypeArray %v4f16 %c_i32_16\n" |
| "%v4f32arr = OpTypeArray %v4f32 %c_i32_16\n"; |
| |
| struct CompositeType |
| { |
| const char* name; |
| const char* base32; |
| const char* base16; |
| const char* stride; |
| unsigned count; |
| }; |
| |
| const CompositeType cTypes[] = |
| { |
| {"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", numElements}, |
| {"vector", "v4f32", "v4f16", "OpDecorate %v4f32arr ArrayStride 16\nOpDecorate %v4f16arr ArrayStride 8\n", numElements / 4}, |
| {"matrix", "v4f32", "v4f16", "OpDecorate %m2v4f32arr ArrayStride 32\nOpDecorate %m2v4f16arr ArrayStride 16\n", numElements / 8}, |
| }; |
| |
| vector<deFloat16> float16Data = getFloat16s(rnd, numElements); |
| vector<float> float32Data; |
| |
| float32Data.reserve(numElements); |
| for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx) |
| float32Data.push_back(deFloat16To32(float16Data[numIdx])); |
| |
| for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx) |
| { |
| ComputeShaderSpec spec; |
| map<string, string> specs; |
| string testName = string(cTypes[tyIdx].name) + "_float"; |
| |
| specs["stride"] = cTypes[tyIdx].stride; |
| specs["base32"] = cTypes[tyIdx].base32; |
| specs["base16"] = cTypes[tyIdx].base16; |
| specs["types"] = floatTypes; |
| specs["convert"] = "OpFConvert"; |
| |
| if (strcmp(cTypes[tyIdx].name, "matrix") == 0) |
| { |
| specs["index0"] = "%zero"; |
| specs["matrix_prefix"] = "m2"; |
| specs["matrix_types"] = |
| "%m2v4f16 = OpTypeMatrix %v4f16 2\n" |
| "%m2v4f32 = OpTypeMatrix %v4f32 2\n" |
| "%m2v4f16arr = OpTypeArray %m2v4f16 %c_i32_8\n" |
| "%m2v4f32arr = OpTypeArray %m2v4f32 %c_i32_8\n"; |
| specs["matrix_decor"] = |
| "OpMemberDecorate %SSBO32 0 ColMajor\n" |
| "OpMemberDecorate %SSBO32 0 MatrixStride 16\n" |
| "OpMemberDecorate %PC16 0 ColMajor\n" |
| "OpMemberDecorate %PC16 0 MatrixStride 8\n"; |
| specs["matrix_store"] = |
| "%inloc_1 = OpAccessChain %v4f16ptr %pc16 %zero %x %c_i32_1\n" |
| "%val16_1 = OpLoad %v4f16 %inloc_1\n" |
| "%val32_1 = OpFConvert %v4f32 %val16_1\n" |
| "%outloc_1 = OpAccessChain %v4f32ptr %ssbo32 %zero %x %c_i32_1\n" |
| " OpStore %outloc_1 %val32_1\n"; |
| } |
| |
| spec.assembly = shaderTemplate.specialize(specs); |
| spec.numWorkGroups = IVec3(cTypes[tyIdx].count, 1, 1); |
| spec.verifyIO = check32BitFloats; |
| spec.pushConstants = BufferSp(new Float16Buffer(float16Data)); |
| |
| spec.outputs.push_back(BufferSp(new Float32Buffer(float32Data))); |
| spec.extensions.push_back("VK_KHR_16bit_storage"); |
| spec.requestedVulkanFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT; |
| |
| group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec)); |
| } |
| } |
| { // integers |
| const char sintTypes[] = |
| "%i16 = OpTypeInt 16 1\n" |
| "%i16ptr = OpTypePointer PushConstant %i16\n" |
| "%i16arr = OpTypeArray %i16 %c_i32_64\n" |
| "%v2i16 = OpTypeVector %i16 2\n" |
| "%v2i32 = OpTypeVector %i32 2\n" |
| "%v2i16ptr = OpTypePointer PushConstant %v2i16\n" |
| "%v2i32ptr = OpTypePointer Uniform %v2i32\n" |
| "%v2i16arr = OpTypeArray %v2i16 %c_i32_32\n" |
| "%v2i32arr = OpTypeArray %v2i32 %c_i32_32\n"; |
| |
| const char uintTypes[] = |
| "%u16 = OpTypeInt 16 0\n" |
| "%u16ptr = OpTypePointer PushConstant %u16\n" |
| "%u32ptr = OpTypePointer Uniform %u32\n" |
| "%u16arr = OpTypeArray %u16 %c_i32_64\n" |
| "%u32arr = OpTypeArray %u32 %c_i32_64\n" |
| "%v2u16 = OpTypeVector %u16 2\n" |
| "%v2u32 = OpTypeVector %u32 2\n" |
| "%v2u16ptr = OpTypePointer PushConstant %v2u16\n" |
| "%v2u32ptr = OpTypePointer Uniform %v2u32\n" |
| "%v2u16arr = OpTypeArray %v2u16 %c_i32_32\n" |
| "%v2u32arr = OpTypeArray %v2u32 %c_i32_32\n"; |
| |
| struct CompositeType |
| { |
| const char* name; |
| bool isSigned; |
| const char* types; |
| const char* base32; |
| const char* base16; |
| const char* opcode; |
| const char* stride; |
| unsigned count; |
| }; |
| |
| const CompositeType cTypes[] = |
| { |
| {"scalar_sint", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", numElements}, |
| {"scalar_uint", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", numElements}, |
| {"vector_sint", true, sintTypes, "v2i32", "v2i16", "OpSConvert", "OpDecorate %v2i32arr ArrayStride 8\nOpDecorate %v2i16arr ArrayStride 4\n", numElements / 2}, |
| {"vector_uint", false, uintTypes, "v2u32", "v2u16", "OpUConvert", "OpDecorate %v2u32arr ArrayStride 8\nOpDecorate %v2u16arr ArrayStride 4\n", numElements / 2}, |
| }; |
| |
| vector<deInt16> inputs = getInt16s(rnd, numElements); |
| vector<deInt32> sOutputs; |
| vector<deInt32> uOutputs; |
| const deUint16 signBitMask = 0x8000; |
| const deUint32 signExtendMask = 0xffff0000; |
| |
| sOutputs.reserve(inputs.size()); |
| uOutputs.reserve(inputs.size()); |
| |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| { |
| uOutputs.push_back(static_cast<deUint16>(inputs[numNdx])); |
| if (inputs[numNdx] & signBitMask) |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask)); |
| else |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx])); |
| } |
| |
| for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx) |
| { |
| ComputeShaderSpec spec; |
| map<string, string> specs; |
| const char* testName = cTypes[tyIdx].name; |
| |
| specs["stride"] = cTypes[tyIdx].stride; |
| specs["base32"] = cTypes[tyIdx].base32; |
| specs["base16"] = cTypes[tyIdx].base16; |
| specs["types"] = cTypes[tyIdx].types; |
| specs["convert"] = cTypes[tyIdx].opcode; |
| |
| spec.assembly = shaderTemplate.specialize(specs); |
| spec.numWorkGroups = IVec3(cTypes[tyIdx].count, 1, 1); |
| spec.pushConstants = BufferSp(new Int16Buffer(inputs)); |
| |
| if (cTypes[tyIdx].isSigned) |
| spec.outputs.push_back(BufferSp(new Int32Buffer(sOutputs))); |
| else |
| spec.outputs.push_back(BufferSp(new Int32Buffer(uOutputs))); |
| spec.extensions.push_back("VK_KHR_16bit_storage"); |
| spec.requestedVulkanFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT; |
| |
| group->addChild(new SpvAsmComputeShaderCase(testCtx, testName, testName, spec)); |
| } |
| } |
| } |
| |
| void addGraphics16BitStorageUniformInt32To16Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| map<string, string> fragments; |
| const deUint32 numDataPoints = 256; |
| RGBA defaultColors[4]; |
| GraphicsResources resources; |
| vector<string> extensions; |
| const StringTemplate capabilities ("OpCapability ${cap}\n"); |
| // inputs and outputs are declared to be vectors of signed integers. |
| // However, depending on the test, they may be interpreted as unsiged |
| // integers. That won't be a problem as long as we passed the bits |
| // in faithfully to the pipeline. |
| vector<deInt32> inputs = getInt32s(rnd, numDataPoints); |
| vector<deInt16> outputs; |
| |
| outputs.reserve(inputs.size()); |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| outputs.push_back(static_cast<deInt16>(0xffff & inputs[numNdx])); |
| |
| resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(inputs)))); |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int16Buffer(outputs)))); |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\""; |
| |
| getDefaultColors(defaultColors); |
| |
| struct IntegerFacts |
| { |
| const char* name; |
| const char* type32; |
| const char* type16; |
| const char* opcode; |
| const char* isSigned; |
| }; |
| |
| const IntegerFacts intFacts[] = |
| { |
| {"sint", "%i32", "%i16", "OpSConvert", "1"}, |
| {"uint", "%u32", "%u16", "OpUConvert", "0"}, |
| }; |
| |
| const StringTemplate scalarPreMain( |
| "${itype16} = OpTypeInt 16 ${signed}\n" |
| "%c_i32_256 = OpConstant %i32 256\n" |
| " %up_i32 = OpTypePointer Uniform ${itype32}\n" |
| " %up_i16 = OpTypePointer Uniform ${itype16}\n" |
| " %ra_i32 = OpTypeArray ${itype32} %c_i32_256\n" |
| " %ra_i16 = OpTypeArray ${itype16} %c_i32_256\n" |
| " %SSBO32 = OpTypeStruct %ra_i32\n" |
| " %SSBO16 = OpTypeStruct %ra_i16\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"); |
| |
| const StringTemplate scalarDecoration( |
| "OpDecorate %ra_i32 ArrayStride 4\n" |
| "OpDecorate %ra_i16 ArrayStride 2\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 ${indecor}\n" |
| "OpDecorate %SSBO16 BufferBlock\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n" |
| "OpDecorate %ssbo16 Binding 1\n"); |
| |
| const StringTemplate scalarTestFunc( |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_256\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %up_i32 %ssbo32 %c_i32_0 %30\n" |
| "%val32 = OpLoad ${itype32} %src\n" |
| "%val16 = ${convert} ${itype16} %val32\n" |
| " %dst = OpAccessChain %up_i16 %ssbo16 %c_i32_0 %30\n" |
| " OpStore %dst %val16\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"); |
| |
| const StringTemplate vecPreMain( |
| "${itype16} = OpTypeInt 16 ${signed}\n" |
| " %c_i32_64 = OpConstant %i32 64\n" |
| "%v4itype32 = OpTypeVector ${itype32} 4\n" |
| "%v4itype16 = OpTypeVector ${itype16} 4\n" |
| " %up_v4i32 = OpTypePointer Uniform %v4itype32\n" |
| " %up_v4i16 = OpTypePointer Uniform %v4itype16\n" |
| " %ra_v4i32 = OpTypeArray %v4itype32 %c_i32_64\n" |
| " %ra_v4i16 = OpTypeArray %v4itype16 %c_i32_64\n" |
| " %SSBO32 = OpTypeStruct %ra_v4i32\n" |
| " %SSBO16 = OpTypeStruct %ra_v4i16\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"); |
| |
| const StringTemplate vecDecoration( |
| "OpDecorate %ra_v4i32 ArrayStride 16\n" |
| "OpDecorate %ra_v4i16 ArrayStride 8\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 ${indecor}\n" |
| "OpDecorate %SSBO16 BufferBlock\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n" |
| "OpDecorate %ssbo16 Binding 1\n"); |
| |
| const StringTemplate vecTestFunc( |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_64\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %up_v4i32 %ssbo32 %c_i32_0 %30\n" |
| "%val32 = OpLoad %v4itype32 %src\n" |
| "%val16 = ${convert} %v4itype16 %val32\n" |
| " %dst = OpAccessChain %up_v4i16 %ssbo16 %c_i32_0 %30\n" |
| " OpStore %dst %val16\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"); |
| |
| struct Category |
| { |
| const char* name; |
| const StringTemplate& preMain; |
| const StringTemplate& decoration; |
| const StringTemplate& testFunction; |
| }; |
| |
| const Category categories[] = |
| { |
| {"scalar", scalarPreMain, scalarDecoration, scalarTestFunc}, |
| {"vector", vecPreMain, vecDecoration, vecTestFunc}, |
| }; |
| |
| for (deUint32 catIdx = 0; catIdx < DE_LENGTH_OF_ARRAY(categories); ++catIdx) |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 factIdx = 0; factIdx < DE_LENGTH_OF_ARRAY(intFacts); ++factIdx) |
| { |
| map<string, string> specs; |
| string name = string(CAPABILITIES[capIdx].name) + "_" + categories[catIdx].name + "_" + intFacts[factIdx].name; |
| |
| specs["cap"] = CAPABILITIES[capIdx].cap; |
| specs["indecor"] = CAPABILITIES[capIdx].decor; |
| specs["itype32"] = intFacts[factIdx].type32; |
| specs["itype16"] = intFacts[factIdx].type16; |
| specs["signed"] = intFacts[factIdx].isSigned; |
| specs["convert"] = intFacts[factIdx].opcode; |
| |
| fragments["pre_main"] = categories[catIdx].preMain.specialize(specs); |
| fragments["testfun"] = categories[catIdx].testFunction.specialize(specs); |
| fragments["capability"] = capabilities.specialize(specs); |
| fragments["decoration"] = categories[catIdx].decoration.specialize(specs); |
| |
| resources.inputs.back().first = CAPABILITIES[capIdx].dtype; |
| |
| createTestsForAllStages(name, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name)); |
| } |
| } |
| |
| void addCompute16bitStorageUniform32To16Group (tcu::TestCaseGroup* group) |
| { |
| tcu::TestContext& testCtx = group->getTestContext(); |
| de::Random rnd (deStringHash(group->getName())); |
| const int numElements = 128; |
| |
| const StringTemplate shaderTemplate ( |
| "OpCapability Shader\n" |
| "OpCapability ${capability}\n" |
| "OpExtension \"SPV_KHR_16bit_storage\"\n" |
| "OpMemoryModel Logical GLSL450\n" |
| "OpEntryPoint GLCompute %main \"main\" %id\n" |
| "OpExecutionMode %main LocalSize 1 1 1\n" |
| "OpDecorate %id BuiltIn GlobalInvocationId\n" |
| |
| "${stride}" |
| |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 ${storage}\n" |
| "OpDecorate %SSBO16 BufferBlock\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n" |
| "OpDecorate %ssbo16 Binding 1\n" |
| |
| "${matrix_decor:opt}\n" |
| |
| "${rounding:opt}\n" |
| |
| "%bool = OpTypeBool\n" |
| "%void = OpTypeVoid\n" |
| "%voidf = OpTypeFunction %void\n" |
| "%u32 = OpTypeInt 32 0\n" |
| "%i32 = OpTypeInt 32 1\n" |
| "%f32 = OpTypeFloat 32\n" |
| "%uvec3 = OpTypeVector %u32 3\n" |
| "%fvec3 = OpTypeVector %f32 3\n" |
| "%uvec3ptr = OpTypePointer Input %uvec3\n" |
| "%i32ptr = OpTypePointer Uniform %i32\n" |
| "%f32ptr = OpTypePointer Uniform %f32\n" |
| |
| "%zero = OpConstant %i32 0\n" |
| "%c_i32_1 = OpConstant %i32 1\n" |
| "%c_i32_16 = OpConstant %i32 16\n" |
| "%c_i32_32 = OpConstant %i32 32\n" |
| "%c_i32_64 = OpConstant %i32 64\n" |
| "%c_i32_128 = OpConstant %i32 128\n" |
| |
| "%i32arr = OpTypeArray %i32 %c_i32_128\n" |
| "%f32arr = OpTypeArray %f32 %c_i32_128\n" |
| |
| "${types}\n" |
| "${matrix_types:opt}\n" |
| |
| "%SSBO32 = OpTypeStruct %${matrix_prefix:opt}${base32}arr\n" |
| "%SSBO16 = OpTypeStruct %${matrix_prefix:opt}${base16}arr\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| "%ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| "%ssbo16 = OpVariable %up_SSBO16 Uniform\n" |
| |
| "%id = OpVariable %uvec3ptr Input\n" |
| |
| "%main = OpFunction %void None %voidf\n" |
| "%label = OpLabel\n" |
| "%idval = OpLoad %uvec3 %id\n" |
| "%x = OpCompositeExtract %u32 %idval 0\n" |
| "%inloc = OpAccessChain %${base32}ptr %ssbo32 %zero %x ${index0:opt}\n" |
| "%val32 = OpLoad %${base32} %inloc\n" |
| "%val16 = ${convert} %${base16} %val32\n" |
| "%outloc = OpAccessChain %${base16}ptr %ssbo16 %zero %x ${index0:opt}\n" |
| " OpStore %outloc %val16\n" |
| "${matrix_store:opt}\n" |
| " OpReturn\n" |
| " OpFunctionEnd\n"); |
| |
| { // Floats |
| const char floatTypes[] = |
| "%f16 = OpTypeFloat 16\n" |
| "%f16ptr = OpTypePointer Uniform %f16\n" |
| "%f16arr = OpTypeArray %f16 %c_i32_128\n" |
| "%v4f16 = OpTypeVector %f16 4\n" |
| "%v4f32 = OpTypeVector %f32 4\n" |
| "%v4f16ptr = OpTypePointer Uniform %v4f16\n" |
| "%v4f32ptr = OpTypePointer Uniform %v4f32\n" |
| "%v4f16arr = OpTypeArray %v4f16 %c_i32_32\n" |
| "%v4f32arr = OpTypeArray %v4f32 %c_i32_32\n"; |
| |
| struct RndMode |
| { |
| const char* name; |
| const char* decor; |
| ComputeVerifyIOFunc func; |
| }; |
| |
| const RndMode rndModes[] = |
| { |
| {"rtz", "OpDecorate %val16 FPRoundingMode RTZ", computeCheck16BitFloats<ROUNDINGMODE_RTZ>}, |
| {"rte", "OpDecorate %val16 FPRoundingMode RTE", computeCheck16BitFloats<ROUNDINGMODE_RTE>}, |
| {"unspecified_rnd_mode", "", computeCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>}, |
| }; |
| |
| struct CompositeType |
| { |
| const char* name; |
| const char* base32; |
| const char* base16; |
| const char* stride; |
| unsigned count; |
| }; |
| |
| const CompositeType cTypes[] = |
| { |
| {"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", numElements}, |
| {"vector", "v4f32", "v4f16", "OpDecorate %v4f32arr ArrayStride 16\nOpDecorate %v4f16arr ArrayStride 8\n", numElements / 4}, |
| {"matrix", "v4f32", "v4f16", "OpDecorate %m2v4f32arr ArrayStride 32\nOpDecorate %m2v4f16arr ArrayStride 16\n", numElements / 8}, |
| }; |
| |
| vector<float> float32Data = getFloat32s(rnd, numElements); |
| vector<deFloat16> float16DummyData (numElements, 0); |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx) |
| for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx) |
| { |
| ComputeShaderSpec spec; |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name + "_float_" + rndModes[rndModeIdx].name; |
| |
| specs["capability"] = CAPABILITIES[capIdx].cap; |
| specs["storage"] = CAPABILITIES[capIdx].decor; |
| specs["stride"] = cTypes[tyIdx].stride; |
| specs["base32"] = cTypes[tyIdx].base32; |
| specs["base16"] = cTypes[tyIdx].base16; |
| specs["rounding"] = rndModes[rndModeIdx].decor; |
| specs["types"] = floatTypes; |
| specs["convert"] = "OpFConvert"; |
| |
| if (strcmp(cTypes[tyIdx].name, "matrix") == 0) |
| { |
| if (strcmp(rndModes[rndModeIdx].name, "rtz") == 0) |
| specs["rounding"] += "\nOpDecorate %val16_1 FPRoundingMode RTZ\n"; |
| else if (strcmp(rndModes[rndModeIdx].name, "rte") == 0) |
| specs["rounding"] += "\nOpDecorate %val16_1 FPRoundingMode RTE\n"; |
| |
| specs["index0"] = "%zero"; |
| specs["matrix_prefix"] = "m2"; |
| specs["matrix_types"] = |
| "%m2v4f16 = OpTypeMatrix %v4f16 2\n" |
| "%m2v4f32 = OpTypeMatrix %v4f32 2\n" |
| "%m2v4f16arr = OpTypeArray %m2v4f16 %c_i32_16\n" |
| "%m2v4f32arr = OpTypeArray %m2v4f32 %c_i32_16\n"; |
| specs["matrix_decor"] = |
| "OpMemberDecorate %SSBO32 0 ColMajor\n" |
| "OpMemberDecorate %SSBO32 0 MatrixStride 16\n" |
| "OpMemberDecorate %SSBO16 0 ColMajor\n" |
| "OpMemberDecorate %SSBO16 0 MatrixStride 8\n"; |
| specs["matrix_store"] = |
| "%inloc_1 = OpAccessChain %v4f32ptr %ssbo32 %zero %x %c_i32_1\n" |
| "%val32_1 = OpLoad %v4f32 %inloc_1\n" |
| "%val16_1 = OpFConvert %v4f16 %val32_1\n" |
| "%outloc_1 = OpAccessChain %v4f16ptr %ssbo16 %zero %x %c_i32_1\n" |
| " OpStore %outloc_1 %val16_1\n"; |
| } |
| |
| spec.assembly = shaderTemplate.specialize(specs); |
| spec.numWorkGroups = IVec3(cTypes[tyIdx].count, 1, 1); |
| spec.verifyIO = rndModes[rndModeIdx].func; |
| spec.inputTypes[0] = CAPABILITIES[capIdx].dtype; |
| |
| spec.inputs.push_back(BufferSp(new Float32Buffer(float32Data))); |
| // We provided a custom verifyIO in the above in which inputs will be used for checking. |
| // So put dummy data in the expected values. |
| spec.outputs.push_back(BufferSp(new Float16Buffer(float16DummyData))); |
| spec.extensions.push_back("VK_KHR_16bit_storage"); |
| spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name); |
| |
| group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec)); |
| } |
| } |
| |
| { // Integers |
| const char sintTypes[] = |
| "%i16 = OpTypeInt 16 1\n" |
| "%i16ptr = OpTypePointer Uniform %i16\n" |
| "%i16arr = OpTypeArray %i16 %c_i32_128\n" |
| "%v2i16 = OpTypeVector %i16 2\n" |
| "%v2i32 = OpTypeVector %i32 2\n" |
| "%v2i16ptr = OpTypePointer Uniform %v2i16\n" |
| "%v2i32ptr = OpTypePointer Uniform %v2i32\n" |
| "%v2i16arr = OpTypeArray %v2i16 %c_i32_64\n" |
| "%v2i32arr = OpTypeArray %v2i32 %c_i32_64\n"; |
| |
| const char uintTypes[] = |
| "%u16 = OpTypeInt 16 0\n" |
| "%u16ptr = OpTypePointer Uniform %u16\n" |
| "%u32ptr = OpTypePointer Uniform %u32\n" |
| "%u16arr = OpTypeArray %u16 %c_i32_128\n" |
| "%u32arr = OpTypeArray %u32 %c_i32_128\n" |
| "%v2u16 = OpTypeVector %u16 2\n" |
| "%v2u32 = OpTypeVector %u32 2\n" |
| "%v2u16ptr = OpTypePointer Uniform %v2u16\n" |
| "%v2u32ptr = OpTypePointer Uniform %v2u32\n" |
| "%v2u16arr = OpTypeArray %v2u16 %c_i32_64\n" |
| "%v2u32arr = OpTypeArray %v2u32 %c_i32_64\n"; |
| |
| struct CompositeType |
| { |
| const char* name; |
| const char* types; |
| const char* base32; |
| const char* base16; |
| const char* opcode; |
| const char* stride; |
| unsigned count; |
| }; |
| |
| const CompositeType cTypes[] = |
| { |
| {"scalar_sint", sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", numElements}, |
| {"scalar_uint", uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", numElements}, |
| {"vector_sint", sintTypes, "v2i32", "v2i16", "OpSConvert", "OpDecorate %v2i32arr ArrayStride 8\nOpDecorate %v2i16arr ArrayStride 4\n", numElements / 2}, |
| {"vector_uint", uintTypes, "v2u32", "v2u16", "OpUConvert", "OpDecorate %v2u32arr ArrayStride 8\nOpDecorate %v2u16arr ArrayStride 4\n", numElements / 2}, |
| }; |
| |
| vector<deInt32> inputs = getInt32s(rnd, numElements); |
| vector<deInt16> outputs; |
| |
| outputs.reserve(inputs.size()); |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| outputs.push_back(static_cast<deInt16>(0xffff & inputs[numNdx])); |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes); ++tyIdx) |
| { |
| ComputeShaderSpec spec; |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_" + cTypes[tyIdx].name; |
| |
| specs["capability"] = CAPABILITIES[capIdx].cap; |
| specs["storage"] = CAPABILITIES[capIdx].decor; |
| specs["stride"] = cTypes[tyIdx].stride; |
| specs["base32"] = cTypes[tyIdx].base32; |
| specs["base16"] = cTypes[tyIdx].base16; |
| specs["types"] = cTypes[tyIdx].types; |
| specs["convert"] = cTypes[tyIdx].opcode; |
| |
| spec.assembly = shaderTemplate.specialize(specs); |
| spec.numWorkGroups = IVec3(cTypes[tyIdx].count, 1, 1); |
| spec.inputTypes[0] = CAPABILITIES[capIdx].dtype; |
| |
| spec.inputs.push_back(BufferSp(new Int32Buffer(inputs))); |
| spec.outputs.push_back(BufferSp(new Int16Buffer(outputs))); |
| spec.extensions.push_back("VK_KHR_16bit_storage"); |
| spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name); |
| |
| group->addChild(new SpvAsmComputeShaderCase(testCtx, testName.c_str(), testName.c_str(), spec)); |
| } |
| } |
| } |
| |
| void addGraphics16BitStorageUniformFloat32To16Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| map<string, string> fragments; |
| GraphicsResources resources; |
| vector<string> extensions; |
| const deUint32 numDataPoints = 256; |
| RGBA defaultColors[4]; |
| vector<float> float32Data = getFloat32s(rnd, numDataPoints); |
| vector<deFloat16> float16DummyData (numDataPoints, 0); |
| const StringTemplate capabilities ("OpCapability ${cap}\n"); |
| |
| resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(float32Data)))); |
| // We use a custom verifyIO to check the result via computing directly from inputs; the contents in outputs do not matter. |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float16Buffer(float16DummyData)))); |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\""; |
| |
| struct RndMode |
| { |
| const char* name; |
| const char* decor; |
| GraphicsVerifyIOFunc f; |
| }; |
| |
| getDefaultColors(defaultColors); |
| |
| { // scalar cases |
| fragments["pre_main"] = |
| " %f16 = OpTypeFloat 16\n" |
| "%c_i32_256 = OpConstant %i32 256\n" |
| " %up_f32 = OpTypePointer Uniform %f32\n" |
| " %up_f16 = OpTypePointer Uniform %f16\n" |
| " %ra_f32 = OpTypeArray %f32 %c_i32_256\n" |
| " %ra_f16 = OpTypeArray %f16 %c_i32_256\n" |
| " %SSBO32 = OpTypeStruct %ra_f32\n" |
| " %SSBO16 = OpTypeStruct %ra_f16\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"; |
| |
| const StringTemplate decoration ( |
| "OpDecorate %ra_f32 ArrayStride 4\n" |
| "OpDecorate %ra_f16 ArrayStride 2\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 ${indecor}\n" |
| "OpDecorate %SSBO16 BufferBlock\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n" |
| "OpDecorate %ssbo16 Binding 1\n" |
| "${rounddecor}\n"); |
| |
| fragments["testfun"] = |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_256\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %up_f32 %ssbo32 %c_i32_0 %30\n" |
| "%val32 = OpLoad %f32 %src\n" |
| "%val16 = OpFConvert %f16 %val32\n" |
| " %dst = OpAccessChain %up_f16 %ssbo16 %c_i32_0 %30\n" |
| " OpStore %dst %val16\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"; |
| |
| const RndMode rndModes[] = |
| { |
| {"rtz", "OpDecorate %val16 FPRoundingMode RTZ", graphicsCheck16BitFloats<ROUNDINGMODE_RTZ>}, |
| {"rte", "OpDecorate %val16 FPRoundingMode RTE", graphicsCheck16BitFloats<ROUNDINGMODE_RTE>}, |
| {"unspecified_rnd_mode", "", graphicsCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>}, |
| }; |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx) |
| { |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_scalar_float_" + rndModes[rndModeIdx].name; |
| |
| specs["cap"] = CAPABILITIES[capIdx].cap; |
| specs["indecor"] = CAPABILITIES[capIdx].decor; |
| specs["rounddecor"] = rndModes[rndModeIdx].decor; |
| |
| fragments["capability"] = capabilities.specialize(specs); |
| fragments["decoration"] = decoration.specialize(specs); |
| |
| resources.inputs.back().first = CAPABILITIES[capIdx].dtype; |
| resources.verifyIO = rndModes[rndModeIdx].f; |
| |
| |
| createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name)); |
| } |
| } |
| |
| { // vector cases |
| fragments["pre_main"] = |
| " %f16 = OpTypeFloat 16\n" |
| " %c_i32_64 = OpConstant %i32 64\n" |
| " %v4f16 = OpTypeVector %f16 4\n" |
| " %up_v4f32 = OpTypePointer Uniform %v4f32\n" |
| " %up_v4f16 = OpTypePointer Uniform %v4f16\n" |
| " %ra_v4f32 = OpTypeArray %v4f32 %c_i32_64\n" |
| " %ra_v4f16 = OpTypeArray %v4f16 %c_i32_64\n" |
| " %SSBO32 = OpTypeStruct %ra_v4f32\n" |
| " %SSBO16 = OpTypeStruct %ra_v4f16\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"; |
| |
| const StringTemplate decoration ( |
| "OpDecorate %ra_v4f32 ArrayStride 16\n" |
| "OpDecorate %ra_v4f16 ArrayStride 8\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 ${indecor}\n" |
| "OpDecorate %SSBO16 BufferBlock\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n" |
| "OpDecorate %ssbo16 Binding 1\n" |
| "${rounddecor}\n"); |
| |
| // ssbo16[] <- convert ssbo32[] to 16bit float |
| fragments["testfun"] = |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_64\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30\n" |
| "%val32 = OpLoad %v4f32 %src\n" |
| "%val16 = OpFConvert %v4f16 %val32\n" |
| " %dst = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30\n" |
| " OpStore %dst %val16\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"; |
| |
| const RndMode rndModes[] = |
| { |
| {"rtz", "OpDecorate %val16 FPRoundingMode RTZ", graphicsCheck16BitFloats<ROUNDINGMODE_RTZ>}, |
| {"rte", "OpDecorate %val16 FPRoundingMode RTE", graphicsCheck16BitFloats<ROUNDINGMODE_RTE>}, |
| {"unspecified_rnd_mode", "", graphicsCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>}, |
| }; |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx) |
| { |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_vector_float_" + rndModes[rndModeIdx].name; |
| |
| specs["cap"] = CAPABILITIES[capIdx].cap; |
| specs["indecor"] = CAPABILITIES[capIdx].decor; |
| specs["rounddecor"] = rndModes[rndModeIdx].decor; |
| |
| fragments["capability"] = capabilities.specialize(specs); |
| fragments["decoration"] = decoration.specialize(specs); |
| |
| resources.inputs.back().first = CAPABILITIES[capIdx].dtype; |
| resources.verifyIO = rndModes[rndModeIdx].f; |
| |
| |
| createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name)); |
| } |
| } |
| |
| { // matrix cases |
| fragments["pre_main"] = |
| " %f16 = OpTypeFloat 16\n" |
| " %c_i32_16 = OpConstant %i32 16\n" |
| " %v4f16 = OpTypeVector %f16 4\n" |
| " %m4x4f32 = OpTypeMatrix %v4f32 4\n" |
| " %m4x4f16 = OpTypeMatrix %v4f16 4\n" |
| " %up_v4f32 = OpTypePointer Uniform %v4f32\n" |
| " %up_v4f16 = OpTypePointer Uniform %v4f16\n" |
| "%a16m4x4f32 = OpTypeArray %m4x4f32 %c_i32_16\n" |
| "%a16m4x4f16 = OpTypeArray %m4x4f16 %c_i32_16\n" |
| " %SSBO32 = OpTypeStruct %a16m4x4f32\n" |
| " %SSBO16 = OpTypeStruct %a16m4x4f16\n" |
| " %up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| " %up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"; |
| |
| const StringTemplate decoration ( |
| "OpDecorate %a16m4x4f32 ArrayStride 64\n" |
| "OpDecorate %a16m4x4f16 ArrayStride 32\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO32 0 ColMajor\n" |
| "OpMemberDecorate %SSBO32 0 MatrixStride 16\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 ColMajor\n" |
| "OpMemberDecorate %SSBO16 0 MatrixStride 8\n" |
| "OpDecorate %SSBO32 ${indecor}\n" |
| "OpDecorate %SSBO16 BufferBlock\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n" |
| "OpDecorate %ssbo16 Binding 1\n" |
| "${rounddecor}\n"); |
| |
| fragments["testfun"] = |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_16\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| " %write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src_0 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_0\n" |
| " %src_1 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_1\n" |
| " %src_2 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_2\n" |
| " %src_3 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_3\n" |
| "%val32_0 = OpLoad %v4f32 %src_0\n" |
| "%val32_1 = OpLoad %v4f32 %src_1\n" |
| "%val32_2 = OpLoad %v4f32 %src_2\n" |
| "%val32_3 = OpLoad %v4f32 %src_3\n" |
| "%val16_0 = OpFConvert %v4f16 %val32_0\n" |
| "%val16_1 = OpFConvert %v4f16 %val32_1\n" |
| "%val16_2 = OpFConvert %v4f16 %val32_2\n" |
| "%val16_3 = OpFConvert %v4f16 %val32_3\n" |
| " %dst_0 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_0\n" |
| " %dst_1 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_1\n" |
| " %dst_2 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_2\n" |
| " %dst_3 = OpAccessChain %up_v4f16 %ssbo16 %c_i32_0 %30 %c_i32_3\n" |
| " OpStore %dst_0 %val16_0\n" |
| " OpStore %dst_1 %val16_1\n" |
| " OpStore %dst_2 %val16_2\n" |
| " OpStore %dst_3 %val16_3\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"; |
| |
| const RndMode rndModes[] = |
| { |
| {"rte", "OpDecorate %val16_0 FPRoundingMode RTE\nOpDecorate %val16_1 FPRoundingMode RTE\nOpDecorate %val16_2 FPRoundingMode RTE\nOpDecorate %val16_3 FPRoundingMode RTE", graphicsCheck16BitFloats<ROUNDINGMODE_RTE>}, |
| {"rtz", "OpDecorate %val16_0 FPRoundingMode RTZ\nOpDecorate %val16_1 FPRoundingMode RTZ\nOpDecorate %val16_2 FPRoundingMode RTZ\nOpDecorate %val16_3 FPRoundingMode RTZ", graphicsCheck16BitFloats<ROUNDINGMODE_RTZ>}, |
| {"unspecified_rnd_mode", "", graphicsCheck16BitFloats<RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)>}, |
| }; |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx) |
| { |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_matrix_float_" + rndModes[rndModeIdx].name; |
| |
| specs["cap"] = CAPABILITIES[capIdx].cap; |
| specs["indecor"] = CAPABILITIES[capIdx].decor; |
| specs["rounddecor"] = rndModes[rndModeIdx].decor; |
| |
| fragments["capability"] = capabilities.specialize(specs); |
| fragments["decoration"] = decoration.specialize(specs); |
| |
| resources.inputs.back().first = CAPABILITIES[capIdx].dtype; |
| resources.verifyIO = rndModes[rndModeIdx].f; |
| |
| |
| createTestsForAllStages(testName, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name)); |
| } |
| } |
| } |
| |
| void addGraphics16BitStorageInputOutputFloat32To16Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| RGBA defaultColors[4]; |
| vector<string> extensions; |
| map<string, string> fragments = passthruFragments(); |
| const deUint32 numDataPoints = 64; |
| vector<float> float32Data = getFloat32s(rnd, numDataPoints); |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| |
| fragments["capability"] = "OpCapability StorageInputOutput16\n"; |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\"\n"; |
| |
| getDefaultColors(defaultColors); |
| |
| struct RndMode |
| { |
| const char* name; |
| const char* decor; |
| RoundingModeFlags flags; |
| }; |
| |
| const RndMode rndModes[] = |
| { |
| {"rtz", "OpDecorate %ret FPRoundingMode RTZ", ROUNDINGMODE_RTZ}, |
| {"rte", "OpDecorate %ret FPRoundingMode RTE", ROUNDINGMODE_RTE}, |
| {"unspecified_rnd_mode", "", RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ)}, |
| }; |
| |
| struct Case |
| { |
| const char* name; |
| const char* interfaceOpFunc; |
| const char* preMain; |
| const char* inputType; |
| const char* outputType; |
| deUint32 numPerCase; |
| deUint32 numElements; |
| }; |
| |
| const Case cases[] = |
| { |
| { // Scalar cases |
| "scalar", |
| |
| "%interface_op_func = OpFunction %f16 None %f16_f32_function\n" |
| " %io_param1 = OpFunctionParameter %f32\n" |
| " %entry = OpLabel\n" |
| " %ret = OpFConvert %f16 %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n", |
| |
| " %f16 = OpTypeFloat 16\n" |
| " %op_f16 = OpTypePointer Output %f16\n" |
| " %a3f16 = OpTypeArray %f16 %c_i32_3\n" |
| " %op_a3f16 = OpTypePointer Output %a3f16\n" |
| "%f16_f32_function = OpTypeFunction %f16 %f32\n" |
| " %a3f32 = OpTypeArray %f32 %c_i32_3\n" |
| " %ip_a3f32 = OpTypePointer Input %a3f32\n", |
| |
| "f32", |
| "f16", |
| 4, |
| 1, |
| }, |
| { // Vector cases |
| "vector", |
| |
| "%interface_op_func = OpFunction %v2f16 None %v2f16_v2f32_function\n" |
| " %io_param1 = OpFunctionParameter %v2f32\n" |
| " %entry = OpLabel\n" |
| " %ret = OpFConvert %v2f16 %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n", |
| |
| " %f16 = OpTypeFloat 16\n" |
| " %v2f16 = OpTypeVector %f16 2\n" |
| " %op_v2f16 = OpTypePointer Output %v2f16\n" |
| " %a3v2f16 = OpTypeArray %v2f16 %c_i32_3\n" |
| " %op_a3v2f16 = OpTypePointer Output %a3v2f16\n" |
| "%v2f16_v2f32_function = OpTypeFunction %v2f16 %v2f32\n" |
| " %a3v2f32 = OpTypeArray %v2f32 %c_i32_3\n" |
| " %ip_a3v2f32 = OpTypePointer Input %a3v2f32\n", |
| |
| "v2f32", |
| "v2f16", |
| 2 * 4, |
| 2, |
| } |
| }; |
| |
| VulkanFeatures requiredFeatures; |
| requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT; |
| |
| for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx) |
| for (deUint32 rndModeIdx = 0; rndModeIdx < DE_LENGTH_OF_ARRAY(rndModes); ++rndModeIdx) |
| { |
| fragments["interface_op_func"] = cases[caseIdx].interfaceOpFunc; |
| fragments["pre_main"] = cases[caseIdx].preMain; |
| fragments["decoration"] = rndModes[rndModeIdx].decor; |
| |
| fragments["input_type"] = cases[caseIdx].inputType; |
| fragments["output_type"] = cases[caseIdx].outputType; |
| |
| GraphicsInterfaces interfaces; |
| const deUint32 numPerCase = cases[caseIdx].numPerCase; |
| vector<float> subInputs (numPerCase); |
| vector<deFloat16> subOutputs (numPerCase); |
| |
| // The pipeline need this to call compare16BitFloat() when checking the result. |
| interfaces.setRoundingMode(rndModes[rndModeIdx].flags); |
| |
| for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx) |
| { |
| string testName = string(cases[caseIdx].name) + numberToString(caseNdx) + "_" + rndModes[rndModeIdx].name; |
| |
| for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx) |
| { |
| subInputs[numNdx] = float32Data[caseNdx * numPerCase + numNdx]; |
| // We derive the expected result from inputs directly in the graphics pipeline. |
| subOutputs[numNdx] = 0; |
| } |
| interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT32), BufferSp(new Float32Buffer(subInputs))), |
| std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT16), BufferSp(new Float16Buffer(subOutputs)))); |
| createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures); |
| } |
| } |
| } |
| |
| void addGraphics16BitStorageInputOutputFloat16To32Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| RGBA defaultColors[4]; |
| vector<string> extensions; |
| map<string, string> fragments = passthruFragments(); |
| const deUint32 numDataPoints = 64; |
| vector<deFloat16> float16Data (getFloat16s(rnd, numDataPoints)); |
| vector<float> float32Data; |
| |
| float32Data.reserve(numDataPoints); |
| for (deUint32 numIdx = 0; numIdx < numDataPoints; ++numIdx) |
| float32Data.push_back(deFloat16To32(float16Data[numIdx])); |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| |
| fragments["capability"] = "OpCapability StorageInputOutput16\n"; |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\"\n"; |
| |
| getDefaultColors(defaultColors); |
| |
| struct Case |
| { |
| const char* name; |
| const char* interfaceOpFunc; |
| const char* preMain; |
| const char* inputType; |
| const char* outputType; |
| deUint32 numPerCase; |
| deUint32 numElements; |
| }; |
| |
| Case cases[] = |
| { |
| { // Scalar cases |
| "scalar", |
| |
| "%interface_op_func = OpFunction %f32 None %f32_f16_function\n" |
| " %io_param1 = OpFunctionParameter %f16\n" |
| " %entry = OpLabel\n" |
| " %ret = OpFConvert %f32 %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n", |
| |
| " %f16 = OpTypeFloat 16\n" |
| " %ip_f16 = OpTypePointer Input %f16\n" |
| " %a3f16 = OpTypeArray %f16 %c_i32_3\n" |
| " %ip_a3f16 = OpTypePointer Input %a3f16\n" |
| "%f32_f16_function = OpTypeFunction %f32 %f16\n" |
| " %a3f32 = OpTypeArray %f32 %c_i32_3\n" |
| " %op_a3f32 = OpTypePointer Output %a3f32\n", |
| |
| "f16", |
| "f32", |
| 4, |
| 1, |
| }, |
| { // Vector cases |
| "vector", |
| |
| "%interface_op_func = OpFunction %v2f32 None %v2f32_v2f16_function\n" |
| " %io_param1 = OpFunctionParameter %v2f16\n" |
| " %entry = OpLabel\n" |
| " %ret = OpFConvert %v2f32 %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n", |
| |
| " %f16 = OpTypeFloat 16\n" |
| " %v2f16 = OpTypeVector %f16 2\n" |
| " %ip_v2f16 = OpTypePointer Input %v2f16\n" |
| " %a3v2f16 = OpTypeArray %v2f16 %c_i32_3\n" |
| " %ip_a3v2f16 = OpTypePointer Input %a3v2f16\n" |
| "%v2f32_v2f16_function = OpTypeFunction %v2f32 %v2f16\n" |
| " %a3v2f32 = OpTypeArray %v2f32 %c_i32_3\n" |
| " %op_a3v2f32 = OpTypePointer Output %a3v2f32\n", |
| |
| "v2f16", |
| "v2f32", |
| 2 * 4, |
| 2, |
| } |
| }; |
| |
| VulkanFeatures requiredFeatures; |
| requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT; |
| |
| for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx) |
| { |
| fragments["interface_op_func"] = cases[caseIdx].interfaceOpFunc; |
| fragments["pre_main"] = cases[caseIdx].preMain; |
| |
| fragments["input_type"] = cases[caseIdx].inputType; |
| fragments["output_type"] = cases[caseIdx].outputType; |
| |
| GraphicsInterfaces interfaces; |
| const deUint32 numPerCase = cases[caseIdx].numPerCase; |
| vector<deFloat16> subInputs (numPerCase); |
| vector<float> subOutputs (numPerCase); |
| |
| for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx) |
| { |
| string testName = string(cases[caseIdx].name) + numberToString(caseNdx); |
| |
| for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx) |
| { |
| subInputs[numNdx] = float16Data[caseNdx * numPerCase + numNdx]; |
| subOutputs[numNdx] = float32Data[caseNdx * numPerCase + numNdx]; |
| } |
| interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT16), BufferSp(new Float16Buffer(subInputs))), |
| std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_FLOAT32), BufferSp(new Float32Buffer(subOutputs)))); |
| createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures); |
| } |
| } |
| } |
| |
| void addGraphics16BitStorageInputOutputInt32To16Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| RGBA defaultColors[4]; |
| vector<string> extensions; |
| map<string, string> fragments = passthruFragments(); |
| const deUint32 numDataPoints = 64; |
| // inputs and outputs are declared to be vectors of signed integers. |
| // However, depending on the test, they may be interpreted as unsiged |
| // integers. That won't be a problem as long as we passed the bits |
| // in faithfully to the pipeline. |
| vector<deInt32> inputs = getInt32s(rnd, numDataPoints); |
| vector<deInt16> outputs; |
| |
| outputs.reserve(inputs.size()); |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| outputs.push_back(static_cast<deInt16>(0xffff & inputs[numNdx])); |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| |
| fragments["capability"] = "OpCapability StorageInputOutput16\n"; |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\"\n"; |
| |
| getDefaultColors(defaultColors); |
| |
| const StringTemplate scalarInterfaceOpFunc( |
| "%interface_op_func = OpFunction %${type16} None %${type16}_${type32}_function\n" |
| " %io_param1 = OpFunctionParameter %${type32}\n" |
| " %entry = OpLabel\n" |
| " %ret = ${convert} %${type16} %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n"); |
| |
| const StringTemplate scalarPreMain( |
| " %${type16} = OpTypeInt 16 ${signed}\n" |
| " %op_${type16} = OpTypePointer Output %${type16}\n" |
| " %a3${type16} = OpTypeArray %${type16} %c_i32_3\n" |
| " %op_a3${type16} = OpTypePointer Output %a3${type16}\n" |
| "%${type16}_${type32}_function = OpTypeFunction %${type16} %${type32}\n" |
| " %a3${type32} = OpTypeArray %${type32} %c_i32_3\n" |
| " %ip_a3${type32} = OpTypePointer Input %a3${type32}\n"); |
| |
| const StringTemplate vecInterfaceOpFunc( |
| "%interface_op_func = OpFunction %${type16} None %${type16}_${type32}_function\n" |
| " %io_param1 = OpFunctionParameter %${type32}\n" |
| " %entry = OpLabel\n" |
| " %ret = ${convert} %${type16} %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n"); |
| |
| const StringTemplate vecPreMain( |
| " %i16 = OpTypeInt 16 1\n" |
| " %u16 = OpTypeInt 16 0\n" |
| " %v4i16 = OpTypeVector %i16 4\n" |
| " %v4u16 = OpTypeVector %u16 4\n" |
| " %op_${type16} = OpTypePointer Output %${type16}\n" |
| " %a3${type16} = OpTypeArray %${type16} %c_i32_3\n" |
| " %op_a3${type16} = OpTypePointer Output %a3${type16}\n" |
| "%${type16}_${type32}_function = OpTypeFunction %${type16} %${type32}\n" |
| " %a3${type32} = OpTypeArray %${type32} %c_i32_3\n" |
| " %ip_a3${type32} = OpTypePointer Input %a3${type32}\n"); |
| |
| struct Case |
| { |
| const char* name; |
| const StringTemplate& interfaceOpFunc; |
| const StringTemplate& preMain; |
| const char* type32; |
| const char* type16; |
| const char* sign; |
| const char* opcode; |
| deUint32 numPerCase; |
| deUint32 numElements; |
| }; |
| |
| Case cases[] = |
| { |
| {"scalar_sint", scalarInterfaceOpFunc, scalarPreMain, "i32", "i16", "1", "OpSConvert", 4, 1}, |
| {"scalar_uint", scalarInterfaceOpFunc, scalarPreMain, "u32", "u16", "0", "OpUConvert", 4, 1}, |
| {"vector_sint", vecInterfaceOpFunc, vecPreMain, "v4i32", "v4i16", "1", "OpSConvert", 4 * 4, 4}, |
| {"vector_uint", vecInterfaceOpFunc, vecPreMain, "v4u32", "v4u16", "0", "OpUConvert", 4 * 4, 4}, |
| }; |
| |
| VulkanFeatures requiredFeatures; |
| requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT; |
| |
| for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx) |
| { |
| map<string, string> specs; |
| |
| specs["type32"] = cases[caseIdx].type32; |
| specs["type16"] = cases[caseIdx].type16; |
| specs["signed"] = cases[caseIdx].sign; |
| specs["convert"] = cases[caseIdx].opcode; |
| |
| fragments["pre_main"] = cases[caseIdx].preMain.specialize(specs); |
| fragments["interface_op_func"] = cases[caseIdx].interfaceOpFunc.specialize(specs); |
| fragments["input_type"] = cases[caseIdx].type32; |
| fragments["output_type"] = cases[caseIdx].type16; |
| |
| GraphicsInterfaces interfaces; |
| const deUint32 numPerCase = cases[caseIdx].numPerCase; |
| vector<deInt32> subInputs (numPerCase); |
| vector<deInt16> subOutputs (numPerCase); |
| |
| for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx) |
| { |
| string testName = string(cases[caseIdx].name) + numberToString(caseNdx); |
| |
| for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx) |
| { |
| subInputs[numNdx] = inputs[caseNdx * numPerCase + numNdx]; |
| subOutputs[numNdx] = outputs[caseNdx * numPerCase + numNdx]; |
| } |
| if (strcmp(cases[caseIdx].sign, "1") == 0) |
| { |
| interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT32), BufferSp(new Int32Buffer(subInputs))), |
| std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT16), BufferSp(new Int16Buffer(subOutputs)))); |
| } |
| else |
| { |
| interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT32), BufferSp(new Int32Buffer(subInputs))), |
| std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT16), BufferSp(new Int16Buffer(subOutputs)))); |
| } |
| createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures); |
| } |
| } |
| } |
| |
| void addGraphics16BitStorageInputOutputInt16To32Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| RGBA defaultColors[4]; |
| vector<string> extensions; |
| map<string, string> fragments = passthruFragments(); |
| const deUint32 numDataPoints = 64; |
| // inputs and outputs are declared to be vectors of signed integers. |
| // However, depending on the test, they may be interpreted as unsiged |
| // integers. That won't be a problem as long as we passed the bits |
| // in faithfully to the pipeline. |
| vector<deInt16> inputs = getInt16s(rnd, numDataPoints); |
| vector<deInt32> sOutputs; |
| vector<deInt32> uOutputs; |
| const deUint16 signBitMask = 0x8000; |
| const deUint32 signExtendMask = 0xffff0000; |
| |
| sOutputs.reserve(inputs.size()); |
| uOutputs.reserve(inputs.size()); |
| |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| { |
| uOutputs.push_back(static_cast<deUint16>(inputs[numNdx])); |
| if (inputs[numNdx] & signBitMask) |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask)); |
| else |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx])); |
| } |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| |
| fragments["capability"] = "OpCapability StorageInputOutput16\n"; |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\"\n"; |
| |
| getDefaultColors(defaultColors); |
| |
| const StringTemplate scalarIfOpFunc ( |
| "%interface_op_func = OpFunction %${type32} None %${type32}_${type16}_function\n" |
| " %io_param1 = OpFunctionParameter %${type16}\n" |
| " %entry = OpLabel\n" |
| " %ret = ${convert} %${type32} %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n"); |
| |
| const StringTemplate scalarPreMain ( |
| " %${type16} = OpTypeInt 16 ${signed}\n" |
| " %ip_${type16} = OpTypePointer Input %${type16}\n" |
| " %a3${type16} = OpTypeArray %${type16} %c_i32_3\n" |
| " %ip_a3${type16} = OpTypePointer Input %a3${type16}\n" |
| "%${type32}_${type16}_function = OpTypeFunction %${type32} %${type16}\n" |
| " %a3${type32} = OpTypeArray %${type32} %c_i32_3\n" |
| " %op_a3${type32} = OpTypePointer Output %a3${type32}\n"); |
| |
| const StringTemplate vecIfOpFunc ( |
| "%interface_op_func = OpFunction %${type32} None %${type32}_${type16}_function\n" |
| " %io_param1 = OpFunctionParameter %${type16}\n" |
| " %entry = OpLabel\n" |
| " %ret = ${convert} %${type32} %io_param1\n" |
| " OpReturnValue %ret\n" |
| " OpFunctionEnd\n"); |
| |
| const StringTemplate vecPreMain ( |
| " %i16 = OpTypeInt 16 1\n" |
| " %u16 = OpTypeInt 16 0\n" |
| " %v4i16 = OpTypeVector %i16 4\n" |
| " %v4u16 = OpTypeVector %u16 4\n" |
| " %ip_${type16} = OpTypePointer Input %${type16}\n" |
| " %a3${type16} = OpTypeArray %${type16} %c_i32_3\n" |
| " %ip_a3${type16} = OpTypePointer Input %a3${type16}\n" |
| "%${type32}_${type16}_function = OpTypeFunction %${type32} %${type16}\n" |
| " %a3${type32} = OpTypeArray %${type32} %c_i32_3\n" |
| " %op_a3${type32} = OpTypePointer Output %a3${type32}\n"); |
| |
| struct Case |
| { |
| const char* name; |
| const StringTemplate& interfaceOpFunc; |
| const StringTemplate& preMain; |
| const char* type32; |
| const char* type16; |
| const char* sign; |
| const char* opcode; |
| deUint32 numPerCase; |
| deUint32 numElements; |
| }; |
| |
| Case cases[] = |
| { |
| {"scalar_sint", scalarIfOpFunc, scalarPreMain, "i32", "i16", "1", "OpSConvert", 4, 1}, |
| {"scalar_uint", scalarIfOpFunc, scalarPreMain, "u32", "u16", "0", "OpUConvert", 4, 1}, |
| {"vector_sint", vecIfOpFunc, vecPreMain, "v4i32", "v4i16", "1", "OpSConvert", 4 * 4, 4}, |
| {"vector_uint", vecIfOpFunc, vecPreMain, "v4u32", "v4u16", "0", "OpUConvert", 4 * 4, 4}, |
| }; |
| |
| VulkanFeatures requiredFeatures; |
| requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_INPUT_OUTPUT; |
| |
| for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(cases); ++caseIdx) |
| { |
| map<string, string> specs; |
| |
| specs["type32"] = cases[caseIdx].type32; |
| specs["type16"] = cases[caseIdx].type16; |
| specs["signed"] = cases[caseIdx].sign; |
| specs["convert"] = cases[caseIdx].opcode; |
| |
| fragments["pre_main"] = cases[caseIdx].preMain.specialize(specs); |
| fragments["interface_op_func"] = cases[caseIdx].interfaceOpFunc.specialize(specs); |
| fragments["input_type"] = cases[caseIdx].type16; |
| fragments["output_type"] = cases[caseIdx].type32; |
| |
| GraphicsInterfaces interfaces; |
| const deUint32 numPerCase = cases[caseIdx].numPerCase; |
| vector<deInt16> subInputs (numPerCase); |
| vector<deInt32> subOutputs (numPerCase); |
| |
| for (deUint32 caseNdx = 0; caseNdx < numDataPoints / numPerCase; ++caseNdx) |
| { |
| string testName = string(cases[caseIdx].name) + numberToString(caseNdx); |
| |
| for (deUint32 numNdx = 0; numNdx < numPerCase; ++numNdx) |
| { |
| subInputs[numNdx] = inputs[caseNdx * numPerCase + numNdx]; |
| if (cases[caseIdx].sign[0] == '1') |
| subOutputs[numNdx] = sOutputs[caseNdx * numPerCase + numNdx]; |
| else |
| subOutputs[numNdx] = uOutputs[caseNdx * numPerCase + numNdx]; |
| } |
| if (strcmp(cases[caseIdx].sign, "1") == 0) |
| { |
| interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT16), BufferSp(new Int16Buffer(subInputs))), |
| std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_INT32), BufferSp(new Int32Buffer(subOutputs)))); |
| } |
| else |
| { |
| interfaces.setInputOutput(std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT16), BufferSp(new Int16Buffer(subInputs))), |
| std::make_pair(IFDataType(cases[caseIdx].numElements, NUMBERTYPE_UINT32), BufferSp(new Int32Buffer(subOutputs)))); |
| } |
| createTestsForAllStages(testName, defaultColors, defaultColors, fragments, interfaces, extensions, testGroup, requiredFeatures); |
| } |
| } |
| } |
| |
| void addGraphics16BitStoragePushConstantFloat16To32Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| map<string, string> fragments; |
| RGBA defaultColors[4]; |
| vector<string> extensions; |
| GraphicsResources resources; |
| PushConstants pcs; |
| const deUint32 numDataPoints = 64; |
| vector<deFloat16> float16Data (getFloat16s(rnd, numDataPoints)); |
| vector<float> float32Data; |
| VulkanFeatures requiredFeatures; |
| |
| float32Data.reserve(numDataPoints); |
| for (deUint32 numIdx = 0; numIdx < numDataPoints; ++numIdx) |
| float32Data.push_back(deFloat16To32(float16Data[numIdx])); |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT; |
| |
| fragments["capability"] = "OpCapability StoragePushConstant16\n"; |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\""; |
| |
| pcs.setPushConstant(BufferSp(new Float16Buffer(float16Data))); |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(float32Data)))); |
| resources.verifyIO = check32BitFloats; |
| |
| getDefaultColors(defaultColors); |
| |
| const StringTemplate testFun ( |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 ${count}\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain ${pp_type16} %pc16 %c_i32_0 %30 ${index0:opt}\n" |
| "%val16 = OpLoad ${f_type16} %src\n" |
| "%val32 = OpFConvert ${f_type32} %val16\n" |
| " %dst = OpAccessChain ${up_type32} %ssbo32 %c_i32_0 %30 ${index0:opt}\n" |
| " OpStore %dst %val32\n" |
| |
| "${store:opt}\n" |
| |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"); |
| |
| { // Scalar cases |
| fragments["pre_main"] = |
| " %f16 = OpTypeFloat 16\n" |
| " %c_i32_64 = OpConstant %i32 64\n" // Should be the same as numDataPoints |
| " %a64f16 = OpTypeArray %f16 %c_i32_64\n" |
| " %a64f32 = OpTypeArray %f32 %c_i32_64\n" |
| " %pp_f16 = OpTypePointer PushConstant %f16\n" |
| " %up_f32 = OpTypePointer Uniform %f32\n" |
| " %SSBO32 = OpTypeStruct %a64f32\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %PC16 = OpTypeStruct %a64f16\n" |
| " %pp_PC16 = OpTypePointer PushConstant %PC16\n" |
| " %pc16 = OpVariable %pp_PC16 PushConstant\n"; |
| |
| fragments["decoration"] = |
| "OpDecorate %a64f16 ArrayStride 2\n" |
| "OpDecorate %a64f32 ArrayStride 4\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpDecorate %PC16 Block\n" |
| "OpMemberDecorate %PC16 0 Offset 0\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n"; |
| |
| map<string, string> specs; |
| |
| specs["count"] = "%c_i32_64"; |
| specs["pp_type16"] = "%pp_f16"; |
| specs["f_type16"] = "%f16"; |
| specs["f_type32"] = "%f32"; |
| specs["up_type32"] = "%up_f32"; |
| |
| fragments["testfun"] = testFun.specialize(specs); |
| |
| createTestsForAllStages("scalar", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures); |
| } |
| |
| { // Vector cases |
| fragments["pre_main"] = |
| " %f16 = OpTypeFloat 16\n" |
| " %v4f16 = OpTypeVector %f16 4\n" |
| " %c_i32_16 = OpConstant %i32 16\n" |
| " %a16v4f16 = OpTypeArray %v4f16 %c_i32_16\n" |
| " %a16v4f32 = OpTypeArray %v4f32 %c_i32_16\n" |
| " %pp_v4f16 = OpTypePointer PushConstant %v4f16\n" |
| " %up_v4f32 = OpTypePointer Uniform %v4f32\n" |
| " %SSBO32 = OpTypeStruct %a16v4f32\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %PC16 = OpTypeStruct %a16v4f16\n" |
| " %pp_PC16 = OpTypePointer PushConstant %PC16\n" |
| " %pc16 = OpVariable %pp_PC16 PushConstant\n"; |
| |
| fragments["decoration"] = |
| "OpDecorate %a16v4f16 ArrayStride 8\n" |
| "OpDecorate %a16v4f32 ArrayStride 16\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpDecorate %PC16 Block\n" |
| "OpMemberDecorate %PC16 0 Offset 0\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n"; |
| |
| map<string, string> specs; |
| |
| specs["count"] = "%c_i32_16"; |
| specs["pp_type16"] = "%pp_v4f16"; |
| specs["f_type16"] = "%v4f16"; |
| specs["f_type32"] = "%v4f32"; |
| specs["up_type32"] = "%up_v4f32"; |
| |
| fragments["testfun"] = testFun.specialize(specs); |
| |
| createTestsForAllStages("vector", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures); |
| } |
| |
| { // Matrix cases |
| fragments["pre_main"] = |
| " %c_i32_8 = OpConstant %i32 8\n" |
| " %f16 = OpTypeFloat 16\n" |
| " %v4f16 = OpTypeVector %f16 4\n" |
| " %m2v4f16 = OpTypeMatrix %v4f16 2\n" |
| " %m2v4f32 = OpTypeMatrix %v4f32 2\n" |
| "%a8m2v4f16 = OpTypeArray %m2v4f16 %c_i32_8\n" |
| "%a8m2v4f32 = OpTypeArray %m2v4f32 %c_i32_8\n" |
| " %pp_v4f16 = OpTypePointer PushConstant %v4f16\n" |
| " %up_v4f32 = OpTypePointer Uniform %v4f32\n" |
| " %SSBO32 = OpTypeStruct %a8m2v4f32\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %PC16 = OpTypeStruct %a8m2v4f16\n" |
| " %pp_PC16 = OpTypePointer PushConstant %PC16\n" |
| " %pc16 = OpVariable %pp_PC16 PushConstant\n"; |
| |
| fragments["decoration"] = |
| "OpDecorate %a8m2v4f16 ArrayStride 16\n" |
| "OpDecorate %a8m2v4f32 ArrayStride 32\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO32 0 ColMajor\n" |
| "OpMemberDecorate %SSBO32 0 MatrixStride 16\n" |
| "OpDecorate %PC16 Block\n" |
| "OpMemberDecorate %PC16 0 Offset 0\n" |
| "OpMemberDecorate %PC16 0 ColMajor\n" |
| "OpMemberDecorate %PC16 0 MatrixStride 8\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n"; |
| |
| map<string, string> specs; |
| |
| specs["count"] = "%c_i32_8"; |
| specs["pp_type16"] = "%pp_v4f16"; |
| specs["up_type32"] = "%up_v4f32"; |
| specs["f_type16"] = "%v4f16"; |
| specs["f_type32"] = "%v4f32"; |
| specs["index0"] = "%c_i32_0"; |
| specs["store"] = |
| " %src_1 = OpAccessChain %pp_v4f16 %pc16 %c_i32_0 %30 %c_i32_1\n" |
| "%val16_1 = OpLoad %v4f16 %src_1\n" |
| "%val32_1 = OpFConvert %v4f32 %val16_1\n" |
| " %dst_1 = OpAccessChain %up_v4f32 %ssbo32 %c_i32_0 %30 %c_i32_1\n" |
| " OpStore %dst_1 %val32_1\n"; |
| |
| fragments["testfun"] = testFun.specialize(specs); |
| |
| createTestsForAllStages("matrix", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures); |
| } |
| } |
| |
| void addGraphics16BitStoragePushConstantInt16To32Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| map<string, string> fragments; |
| RGBA defaultColors[4]; |
| const deUint32 numDataPoints = 64; |
| vector<deInt16> inputs = getInt16s(rnd, numDataPoints); |
| vector<deInt32> sOutputs; |
| vector<deInt32> uOutputs; |
| PushConstants pcs; |
| GraphicsResources resources; |
| vector<string> extensions; |
| const deUint16 signBitMask = 0x8000; |
| const deUint32 signExtendMask = 0xffff0000; |
| VulkanFeatures requiredFeatures; |
| |
| sOutputs.reserve(inputs.size()); |
| uOutputs.reserve(inputs.size()); |
| |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| { |
| uOutputs.push_back(static_cast<deUint16>(inputs[numNdx])); |
| if (inputs[numNdx] & signBitMask) |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask)); |
| else |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx])); |
| } |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| requiredFeatures.ext16BitStorage = EXT16BITSTORAGEFEATURES_PUSH_CONSTANT; |
| |
| fragments["capability"] = "OpCapability StoragePushConstant16\n"; |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\""; |
| |
| pcs.setPushConstant(BufferSp(new Int16Buffer(inputs))); |
| |
| getDefaultColors(defaultColors); |
| |
| const StringTemplate testFun ( |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_${count}\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %pp_${type16} %pc16 %c_i32_0 %30\n" |
| "%val16 = OpLoad %${type16} %src\n" |
| "%val32 = ${convert} %${type32} %val16\n" |
| " %dst = OpAccessChain %up_${type32} %ssbo32 %c_i32_0 %30\n" |
| " OpStore %dst %val32\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"); |
| |
| { // Scalar cases |
| const StringTemplate preMain ( |
| " %${type16} = OpTypeInt 16 ${signed}\n" |
| " %c_i32_${count} = OpConstant %i32 ${count}\n" // Should be the same as numDataPoints |
| "%a${count}${type16} = OpTypeArray %${type16} %c_i32_${count}\n" |
| "%a${count}${type32} = OpTypeArray %${type32} %c_i32_${count}\n" |
| " %pp_${type16} = OpTypePointer PushConstant %${type16}\n" |
| " %up_${type32} = OpTypePointer Uniform %${type32}\n" |
| " %SSBO32 = OpTypeStruct %a${count}${type32}\n" |
| " %up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %PC16 = OpTypeStruct %a${count}${type16}\n" |
| " %pp_PC16 = OpTypePointer PushConstant %PC16\n" |
| " %pc16 = OpVariable %pp_PC16 PushConstant\n"); |
| |
| const StringTemplate decoration ( |
| "OpDecorate %a${count}${type16} ArrayStride 2\n" |
| "OpDecorate %a${count}${type32} ArrayStride 4\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpDecorate %PC16 Block\n" |
| "OpMemberDecorate %PC16 0 Offset 0\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n"); |
| |
| { // signed int |
| map<string, string> specs; |
| |
| specs["type16"] = "i16"; |
| specs["type32"] = "i32"; |
| specs["signed"] = "1"; |
| specs["count"] = "64"; |
| specs["convert"] = "OpSConvert"; |
| |
| fragments["testfun"] = testFun.specialize(specs); |
| fragments["pre_main"] = preMain.specialize(specs); |
| fragments["decoration"] = decoration.specialize(specs); |
| |
| resources.outputs.clear(); |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(sOutputs)))); |
| createTestsForAllStages("sint_scalar", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures); |
| } |
| { // signed int |
| map<string, string> specs; |
| |
| specs["type16"] = "u16"; |
| specs["type32"] = "u32"; |
| specs["signed"] = "0"; |
| specs["count"] = "64"; |
| specs["convert"] = "OpUConvert"; |
| |
| fragments["testfun"] = testFun.specialize(specs); |
| fragments["pre_main"] = preMain.specialize(specs); |
| fragments["decoration"] = decoration.specialize(specs); |
| |
| resources.outputs.clear(); |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(uOutputs)))); |
| createTestsForAllStages("uint_scalar", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures); |
| } |
| } |
| |
| { // Vector cases |
| const StringTemplate preMain ( |
| " %${base_type16} = OpTypeInt 16 ${signed}\n" |
| " %${type16} = OpTypeVector %${base_type16} 2\n" |
| " %c_i32_${count} = OpConstant %i32 ${count}\n" |
| "%a${count}${type16} = OpTypeArray %${type16} %c_i32_${count}\n" |
| "%a${count}${type32} = OpTypeArray %${type32} %c_i32_${count}\n" |
| " %pp_${type16} = OpTypePointer PushConstant %${type16}\n" |
| " %up_${type32} = OpTypePointer Uniform %${type32}\n" |
| " %SSBO32 = OpTypeStruct %a${count}${type32}\n" |
| " %up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %PC16 = OpTypeStruct %a${count}${type16}\n" |
| " %pp_PC16 = OpTypePointer PushConstant %PC16\n" |
| " %pc16 = OpVariable %pp_PC16 PushConstant\n"); |
| |
| const StringTemplate decoration ( |
| "OpDecorate %a${count}${type16} ArrayStride 4\n" |
| "OpDecorate %a${count}${type32} ArrayStride 8\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpDecorate %PC16 Block\n" |
| "OpMemberDecorate %PC16 0 Offset 0\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 0\n"); |
| |
| { // signed int |
| map<string, string> specs; |
| |
| specs["base_type16"] = "i16"; |
| specs["type16"] = "v2i16"; |
| specs["type32"] = "v2i32"; |
| specs["signed"] = "1"; |
| specs["count"] = "32"; // 64 / 2 |
| specs["convert"] = "OpSConvert"; |
| |
| fragments["testfun"] = testFun.specialize(specs); |
| fragments["pre_main"] = preMain.specialize(specs); |
| fragments["decoration"] = decoration.specialize(specs); |
| |
| resources.outputs.clear(); |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(sOutputs)))); |
| createTestsForAllStages("sint_vector", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures); |
| } |
| { // signed int |
| map<string, string> specs; |
| |
| specs["base_type16"] = "u16"; |
| specs["type16"] = "v2u16"; |
| specs["type32"] = "v2u32"; |
| specs["signed"] = "0"; |
| specs["count"] = "32"; |
| specs["convert"] = "OpUConvert"; |
| |
| fragments["testfun"] = testFun.specialize(specs); |
| fragments["pre_main"] = preMain.specialize(specs); |
| fragments["decoration"] = decoration.specialize(specs); |
| |
| resources.outputs.clear(); |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(uOutputs)))); |
| createTestsForAllStages("uint_vector", defaultColors, defaultColors, fragments, pcs, resources, extensions, testGroup, requiredFeatures); |
| } |
| } |
| } |
| |
| void addGraphics16BitStorageUniformInt16To32Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| map<string, string> fragments; |
| const deUint32 numDataPoints = 256; |
| RGBA defaultColors[4]; |
| vector<deInt16> inputs = getInt16s(rnd, numDataPoints); |
| vector<deInt32> sOutputs; |
| vector<deInt32> uOutputs; |
| GraphicsResources resources; |
| vector<string> extensions; |
| const deUint16 signBitMask = 0x8000; |
| const deUint32 signExtendMask = 0xffff0000; |
| const StringTemplate capabilities ("OpCapability ${cap}\n"); |
| |
| sOutputs.reserve(inputs.size()); |
| uOutputs.reserve(inputs.size()); |
| |
| for (deUint32 numNdx = 0; numNdx < inputs.size(); ++numNdx) |
| { |
| uOutputs.push_back(static_cast<deUint16>(inputs[numNdx])); |
| if (inputs[numNdx] & signBitMask) |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx] | signExtendMask)); |
| else |
| sOutputs.push_back(static_cast<deInt32>(inputs[numNdx])); |
| } |
| |
| resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int16Buffer(inputs)))); |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\""; |
| |
| getDefaultColors(defaultColors); |
| |
| struct IntegerFacts |
| { |
| const char* name; |
| const char* type32; |
| const char* type16; |
| const char* opcode; |
| bool isSigned; |
| }; |
| |
| const IntegerFacts intFacts[] = |
| { |
| {"sint", "%i32", "%i16", "OpSConvert", true}, |
| {"uint", "%u32", "%u16", "OpUConvert", false}, |
| }; |
| |
| const StringTemplate scalarPreMain ( |
| "${itype16} = OpTypeInt 16 ${signed}\n" |
| " %c_i32_256 = OpConstant %i32 256\n" |
| " %up_i32 = OpTypePointer Uniform ${itype32}\n" |
| " %up_i16 = OpTypePointer Uniform ${itype16}\n" |
| " %ra_i32 = OpTypeArray ${itype32} %c_i32_256\n" |
| " %ra_i16 = OpTypeArray ${itype16} %c_i32_256\n" |
| " %SSBO32 = OpTypeStruct %ra_i32\n" |
| " %SSBO16 = OpTypeStruct %ra_i16\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"); |
| |
| const StringTemplate scalarDecoration ( |
| "OpDecorate %ra_i32 ArrayStride 4\n" |
| "OpDecorate %ra_i16 ArrayStride 2\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpDecorate %SSBO16 ${indecor}\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 1\n" |
| "OpDecorate %ssbo16 Binding 0\n"); |
| |
| const StringTemplate scalarTestFunc ( |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_256\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %up_i16 %ssbo16 %c_i32_0 %30\n" |
| "%val16 = OpLoad ${itype16} %src\n" |
| "%val32 = ${convert} ${itype32} %val16\n" |
| " %dst = OpAccessChain %up_i32 %ssbo32 %c_i32_0 %30\n" |
| " OpStore %dst %val32\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"); |
| |
| const StringTemplate vecPreMain ( |
| "${itype16} = OpTypeInt 16 ${signed}\n" |
| "%c_i32_128 = OpConstant %i32 128\n" |
| "%v2itype16 = OpTypeVector ${itype16} 2\n" |
| "%v2itype32 = OpTypeVector ${itype32} 2\n" |
| " %up_v2i32 = OpTypePointer Uniform %v2itype32\n" |
| " %up_v2i16 = OpTypePointer Uniform %v2itype16\n" |
| " %ra_v2i32 = OpTypeArray %v2itype32 %c_i32_128\n" |
| " %ra_v2i16 = OpTypeArray %v2itype16 %c_i32_128\n" |
| " %SSBO32 = OpTypeStruct %ra_v2i32\n" |
| " %SSBO16 = OpTypeStruct %ra_v2i16\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"); |
| |
| const StringTemplate vecDecoration ( |
| "OpDecorate %ra_v2i32 ArrayStride 8\n" |
| "OpDecorate %ra_v2i16 ArrayStride 4\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpDecorate %SSBO16 ${indecor}\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 1\n" |
| "OpDecorate %ssbo16 Binding 0\n"); |
| |
| const StringTemplate vecTestFunc ( |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_128\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %up_v2i16 %ssbo16 %c_i32_0 %30\n" |
| "%val16 = OpLoad %v2itype16 %src\n" |
| "%val32 = ${convert} %v2itype32 %val16\n" |
| " %dst = OpAccessChain %up_v2i32 %ssbo32 %c_i32_0 %30\n" |
| " OpStore %dst %val32\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"); |
| |
| struct Category |
| { |
| const char* name; |
| const StringTemplate& preMain; |
| const StringTemplate& decoration; |
| const StringTemplate& testFunction; |
| }; |
| |
| const Category categories[] = |
| { |
| {"scalar", scalarPreMain, scalarDecoration, scalarTestFunc}, |
| {"vector", vecPreMain, vecDecoration, vecTestFunc}, |
| }; |
| |
| for (deUint32 catIdx = 0; catIdx < DE_LENGTH_OF_ARRAY(categories); ++catIdx) |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| for (deUint32 factIdx = 0; factIdx < DE_LENGTH_OF_ARRAY(intFacts); ++factIdx) |
| { |
| map<string, string> specs; |
| string name = string(CAPABILITIES[capIdx].name) + "_" + categories[catIdx].name + "_" + intFacts[factIdx].name; |
| |
| specs["cap"] = CAPABILITIES[capIdx].cap; |
| specs["indecor"] = CAPABILITIES[capIdx].decor; |
| specs["itype32"] = intFacts[factIdx].type32; |
| specs["itype16"] = intFacts[factIdx].type16; |
| if (intFacts[factIdx].isSigned) |
| specs["signed"] = "1"; |
| else |
| specs["signed"] = "0"; |
| specs["convert"] = intFacts[factIdx].opcode; |
| |
| fragments["pre_main"] = categories[catIdx].preMain.specialize(specs); |
| fragments["testfun"] = categories[catIdx].testFunction.specialize(specs); |
| fragments["capability"] = capabilities.specialize(specs); |
| fragments["decoration"] = categories[catIdx].decoration.specialize(specs); |
| |
| resources.inputs.back().first = CAPABILITIES[capIdx].dtype; |
| resources.outputs.clear(); |
| if (intFacts[factIdx].isSigned) |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(sOutputs)))); |
| else |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Int32Buffer(uOutputs)))); |
| |
| createTestsForAllStages(name, defaultColors, defaultColors, fragments, resources, extensions, testGroup, get16BitStorageFeatures(CAPABILITIES[capIdx].name)); |
| } |
| } |
| |
| void addGraphics16BitStorageUniformFloat16To32Group (tcu::TestCaseGroup* testGroup) |
| { |
| de::Random rnd (deStringHash(testGroup->getName())); |
| map<string, string> fragments; |
| GraphicsResources resources; |
| vector<string> extensions; |
| const deUint32 numDataPoints = 256; |
| RGBA defaultColors[4]; |
| const StringTemplate capabilities ("OpCapability ${cap}\n"); |
| vector<deFloat16> float16Data = getFloat16s(rnd, numDataPoints); |
| vector<float> float32Data; |
| |
| float32Data.reserve(numDataPoints); |
| for (deUint32 numIdx = 0; numIdx < numDataPoints; ++numIdx) |
| float32Data.push_back(deFloat16To32(float16Data[numIdx])); |
| |
| resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float16Buffer(float16Data)))); |
| resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Float32Buffer(float32Data)))); |
| resources.verifyIO = check32BitFloats; |
| |
| extensions.push_back("VK_KHR_16bit_storage"); |
| fragments["extension"] = "OpExtension \"SPV_KHR_16bit_storage\""; |
| |
| getDefaultColors(defaultColors); |
| |
| { // scalar cases |
| fragments["pre_main"] = |
| " %f16 = OpTypeFloat 16\n" |
| "%c_i32_256 = OpConstant %i32 256\n" |
| " %up_f32 = OpTypePointer Uniform %f32\n" |
| " %up_f16 = OpTypePointer Uniform %f16\n" |
| " %ra_f32 = OpTypeArray %f32 %c_i32_256\n" |
| " %ra_f16 = OpTypeArray %f16 %c_i32_256\n" |
| " %SSBO32 = OpTypeStruct %ra_f32\n" |
| " %SSBO16 = OpTypeStruct %ra_f16\n" |
| "%up_SSBO32 = OpTypePointer Uniform %SSBO32\n" |
| "%up_SSBO16 = OpTypePointer Uniform %SSBO16\n" |
| " %ssbo32 = OpVariable %up_SSBO32 Uniform\n" |
| " %ssbo16 = OpVariable %up_SSBO16 Uniform\n"; |
| |
| const StringTemplate decoration ( |
| "OpDecorate %ra_f32 ArrayStride 4\n" |
| "OpDecorate %ra_f16 ArrayStride 2\n" |
| "OpMemberDecorate %SSBO32 0 Offset 0\n" |
| "OpMemberDecorate %SSBO16 0 Offset 0\n" |
| "OpDecorate %SSBO32 BufferBlock\n" |
| "OpDecorate %SSBO16 ${indecor}\n" |
| "OpDecorate %ssbo32 DescriptorSet 0\n" |
| "OpDecorate %ssbo16 DescriptorSet 0\n" |
| "OpDecorate %ssbo32 Binding 1\n" |
| "OpDecorate %ssbo16 Binding 0\n"); |
| |
| // ssbo32[] <- convert ssbo16[] to 32bit float |
| fragments["testfun"] = |
| "%test_code = OpFunction %v4f32 None %v4f32_function\n" |
| " %param = OpFunctionParameter %v4f32\n" |
| |
| "%entry = OpLabel\n" |
| " %i = OpVariable %fp_i32 Function\n" |
| " OpStore %i %c_i32_0\n" |
| " OpBranch %loop\n" |
| |
| " %loop = OpLabel\n" |
| " %15 = OpLoad %i32 %i\n" |
| " %lt = OpSLessThan %bool %15 %c_i32_256\n" |
| " OpLoopMerge %merge %inc None\n" |
| " OpBranchConditional %lt %write %merge\n" |
| |
| "%write = OpLabel\n" |
| " %30 = OpLoad %i32 %i\n" |
| " %src = OpAccessChain %up_f16 %ssbo16 %c_i32_0 %30\n" |
| "%val16 = OpLoad %f16 %src\n" |
| "%val32 = OpFConvert %f32 %val16\n" |
| " %dst = OpAccessChain %up_f32 %ssbo32 %c_i32_0 %30\n" |
| " OpStore %dst %val32\n" |
| " OpBranch %inc\n" |
| |
| " %inc = OpLabel\n" |
| " %37 = OpLoad %i32 %i\n" |
| " %39 = OpIAdd %i32 %37 %c_i32_1\n" |
| " OpStore %i %39\n" |
| " OpBranch %loop\n" |
| |
| "%merge = OpLabel\n" |
| " OpReturnValue %param\n" |
| |
| "OpFunctionEnd\n"; |
| |
| for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx) |
| { |
| map<string, string> specs; |
| string testName = string(CAPABILITIES[capIdx].name) + "_scalar_float"; |
| |
| specs["cap"] = CAPABILITIES[capIdx].cap; |
| specs |