blob: 7248f07f80894af5dacf7533f9de98596cadc364 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief SPIR-V Assembly Tests for the VK_KHR_16bit_storage
*//*--------------------------------------------------------------------*/
#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::Float16;
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
{
enum ShaderTemplate
{
SHADERTEMPLATE_TYPES = 0,
SHADERTEMPLATE_STRIDE32BIT_STD140,
SHADERTEMPLATE_STRIDE32BIT_STD430,
SHADERTEMPLATE_STRIDE16BIT_STD140,
SHADERTEMPLATE_STRIDE16BIT_STD430,
SHADERTEMPLATE_STRIDEMIX_STD140,
SHADERTEMPLATE_STRIDEMIX_STD430
};
bool compare16Bit (float original, deUint16 returned, RoundingModeFlags flags, tcu::TestLog& log)
{
return compare16BitFloat (original, returned, flags, log);
}
bool compare16Bit (deUint16 original, float returned, RoundingModeFlags flags, tcu::TestLog& log)
{
DE_UNREF(flags);
return compare16BitFloat (original, returned, log);
}
bool compare16Bit (deInt16 original, deInt16 returned, RoundingModeFlags flags, tcu::TestLog& log)
{
DE_UNREF(flags);
DE_UNREF(log);
return (returned == original);
}
struct StructTestData
{
const int structArraySize; //Size of Struct Array
const int nestedArraySize; //Max size of any nested arrays
};
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},
};
static const StructTestData structData = {7, 11};
enum TestDefDataType
{
DATATYPE_FLOAT,
DATATYPE_VEC2,
DATATYPE_INT,
DATATYPE_UINT,
DATATYPE_IVEC2,
DATATYPE_UVEC2
};
struct TestDefinition
{
InstanceContext instanceContext;
TestDefDataType dataType;
};
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;
}
int getStructSize(const ShaderTemplate shaderTemplate)
{
switch (shaderTemplate)
{
case SHADERTEMPLATE_STRIDE16BIT_STD140:
return 600 * structData.structArraySize; //size of struct in f16 with offsets
case SHADERTEMPLATE_STRIDE16BIT_STD430:
return 184 * structData.structArraySize; //size of struct in f16 with offsets
case SHADERTEMPLATE_STRIDE32BIT_STD140:
return 304 * structData.structArraySize; //size of struct in f32 with offsets
case SHADERTEMPLATE_STRIDE32BIT_STD430:
return 184 * structData.structArraySize; //size of struct in f32 with offset
case SHADERTEMPLATE_STRIDEMIX_STD140:
return 4480 * structData.structArraySize / 2; //size of struct in 16b with offset
case SHADERTEMPLATE_STRIDEMIX_STD430:
return 1216 * structData.structArraySize / 2; //size of struct in 16b with offset
default:
DE_ASSERT(0);
}
return 0;
}
// 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)
{
vector<deUint8> originalBytes;
originalFloats[outputNdx].getBuffer()->getPackedBytes(originalBytes);
const deUint16* returned = static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr());
const float* original = reinterpret_cast<const float*>(&originalBytes.front());
const deUint32 count = static_cast<deUint32>(expectedOutputs[outputNdx].getByteSize() / sizeof(deUint16));
const deUint32 inputStride = static_cast<deUint32>(originalBytes.size() / sizeof(float)) / count;
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
if (!compare16BitFloat(original[numNdx * inputStride], returned[numNdx], RoundingMode, log))
return false;
}
return true;
}
template<RoundingModeFlags RoundingMode>
bool graphicsCheck16BitFloats64 (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)
{
vector<deUint8> originalBytes;
originalFloats[outputNdx].getBuffer()->getPackedBytes(originalBytes);
const deUint16* returned = static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr());
const double* original = reinterpret_cast<const double*>(&originalBytes.front());
const deUint32 count = static_cast<deUint32>(originalBytes.size() / sizeof(double));
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
if (!compare16BitFloat64(original[numNdx], returned[numNdx], RoundingMode, log))
return false;
}
return true;
}
bool computeCheckBuffersFloats (const std::vector<Resource>& originalFloats,
const vector<AllocationSp>& outputAllocs,
const std::vector<Resource>& /*expectedOutputs*/,
tcu::TestLog& /*log*/)
{
std::vector<deUint8> result;
originalFloats.front().getBuffer()->getPackedBytes(result);
const deUint16 * results = reinterpret_cast<const deUint16 *>(&result[0]);
const deUint16 * expected = reinterpret_cast<const deUint16 *>(outputAllocs.front()->getHostPtr());
for (size_t i = 0; i < result.size() / sizeof (deUint16); ++i)
{
if (results[i] == expected[i])
continue;
if (Float16(results[i]).isNaN() && Float16(expected[i]).isNaN())
continue;
return false;
}
return true;
}
template<RoundingModeFlags RoundingMode>
bool computeCheck16BitFloats (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)
{
vector<deUint8> originalBytes;
originalFloats[outputNdx].getBuffer()->getPackedBytes(originalBytes);
const deUint16* returned = static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr());
const float* original = reinterpret_cast<const float*>(&originalBytes.front());
const deUint32 count = static_cast<deUint32>(expectedOutputs[outputNdx].getByteSize() / sizeof(deUint16));
const deUint32 inputStride = static_cast<deUint32>(originalBytes.size() / sizeof(float)) / count;
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
if (!compare16BitFloat(original[numNdx * inputStride], returned[numNdx], RoundingMode, log))
return false;
}
return true;
}
template<RoundingModeFlags RoundingMode>
bool computeCheck16BitFloats64 (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)
{
vector<deUint8> originalBytes;
originalFloats[outputNdx].getBuffer()->getPackedBytes(originalBytes);
const deUint16* returned = static_cast<const deUint16*>(outputAllocs[outputNdx]->getHostPtr());
const double* original = reinterpret_cast<const double*>(&originalBytes.front());
const deUint32 count = static_cast<deUint32>(originalBytes.size() / sizeof(double));
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
if (!compare16BitFloat64(original[numNdx], returned[numNdx], RoundingMode, log))
return false;
}
return true;
}
// Batch function to check arrays of 64-bit floats.
//
// For comparing 64-bit floats, we just need the expected value precomputed in the test case.
// So we need expected outputs here but not original floats.
bool check64BitFloats (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)
{
vector<deUint8> expectedBytes;
expectedOutputs[outputNdx].getBuffer()->getPackedBytes(expectedBytes);
const double* returnedAsDouble = static_cast<const double*>(outputAllocs[outputNdx]->getHostPtr());
const double* expectedAsDouble = reinterpret_cast<const double*>(&expectedBytes.front());
const deUint32 count = static_cast<deUint32>(expectedBytes.size() / sizeof(double));
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
if (!compare64BitFloat(expectedAsDouble[numNdx], returnedAsDouble[numNdx], 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)
{
vector<deUint8> expectedBytes;
expectedOutputs[outputNdx].getBuffer()->getPackedBytes(expectedBytes);
const float* returnedAsFloat = static_cast<const float*>(outputAllocs[outputNdx]->getHostPtr());
const float* expectedAsFloat = reinterpret_cast<const float*>(&expectedBytes.front());
const deUint32 count = static_cast<deUint32>(expectedBytes.size() / sizeof(float));
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
if (!compare32BitFloat(expectedAsFloat[numNdx], returnedAsFloat[numNdx], log))
return false;
}
return true;
}
void addInfo(vector<bool>& info, int& ndx, const int count, bool isData)
{
for (int index = 0; index < count; ++index)
info[ndx++] = isData;
}
vector<deFloat16> data16bitStd140 (de::Random& rnd)
{
return getFloat16s(rnd, getStructSize(SHADERTEMPLATE_STRIDE16BIT_STD140));
}
vector<bool> info16bitStd140 (void)
{
int ndx = 0u;
vector<bool> infoData (getStructSize(SHADERTEMPLATE_STRIDE16BIT_STD140));
for(int elementNdx = 0; elementNdx < structData.structArraySize; ++elementNdx)
{
infoData[ndx++] = true; //f16
infoData[ndx++] = false; //offset
infoData[ndx++] = true; //v2f16
infoData[ndx++] = true; //v2f16
addInfo(infoData, ndx, 3, true); //v3f16
infoData[ndx++] = false; //offset
addInfo(infoData, ndx, 4, true); //v4f16
addInfo(infoData, ndx, 4, false); //offset
//f16[3];
for (int i = 0; i < 3; ++i)
{
infoData[ndx++] = true; //f16[0];
addInfo(infoData, ndx, 7, false); //offset
}
//struct {f16, v2f16[3]} [11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
//struct.f16
infoData[ndx++] = true; //f16
addInfo(infoData, ndx, 7, false); //offset
//struct.f16.v2f16[3]
for (int j = 0; j < 3; ++j)
{
infoData[ndx++] = true; //v2f16
infoData[ndx++] = true; //v2f16
addInfo(infoData, ndx, 6, false); //offset
}
}
//vec2[11];
for (int i = 0; i < structData.nestedArraySize; ++i)
{
infoData[ndx++] = true; //v2f16
infoData[ndx++] = true; //v2f16
addInfo(infoData, ndx, 6, false); //offset
}
//f16
infoData[ndx++] = true; //f16
addInfo(infoData, ndx, 7, false); //offset
//vec3[11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
addInfo(infoData, ndx, 3, true); //vec3
addInfo(infoData, ndx, 5, false); //offset
}
//vec4[3]
for (int i = 0; i < 3; ++i)
{
addInfo(infoData, ndx, 4, true); //vec4
addInfo(infoData, ndx, 4, false); //offset
}
}
//Please check the data and offset
DE_ASSERT(ndx == static_cast<int>(infoData.size()));
return infoData;
}
vector<deFloat16> data16bitStd430 (de::Random& rnd)
{
return getFloat16s(rnd, getStructSize(SHADERTEMPLATE_STRIDE16BIT_STD430));
}
vector<bool> info16bitStd430 (void)
{
int ndx = 0u;
vector<bool> infoData (getStructSize(SHADERTEMPLATE_STRIDE16BIT_STD430));
for(int elementNdx = 0; elementNdx < structData.structArraySize; ++elementNdx)
{
infoData[ndx++] = true; //f16
infoData[ndx++] = false; //offset
infoData[ndx++] = true; //v2f16
infoData[ndx++] = true; //v2f16
addInfo(infoData, ndx, 3, true); //v3f16
infoData[ndx++] = false; //offset
addInfo(infoData, ndx, 4, true); //v4f16
//f16[3];
for (int i = 0; i < 3; ++i)
{
infoData[ndx++] = true; //f16;
}
addInfo(infoData, ndx, 1, false); //offset
//struct {f16, v2f16[3]} [11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
//struct.f16
infoData[ndx++] = true; //f16
infoData[ndx++] = false; //offset
//struct.f16.v2f16[3]
for (int j = 0; j < 3; ++j)
{
infoData[ndx++] = true; //v2f16
infoData[ndx++] = true; //v2f16
}
}
//vec2[11];
for (int i = 0; i < structData.nestedArraySize; ++i)
{
infoData[ndx++] = true; //v2f16
infoData[ndx++] = true; //v2f16
}
//f16
infoData[ndx++] = true; //f16
infoData[ndx++] = false; //offset
//vec3[11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
addInfo(infoData, ndx, 3, true); //vec3
infoData[ndx++] = false; //offset
}
//vec4[3]
for (int i = 0; i < 3; ++i)
{
addInfo(infoData, ndx, 4, true); //vec4
}
}
//Please check the data and offset
DE_ASSERT(ndx == static_cast<int>(infoData.size()));
return infoData;
}
vector<float> data32bitStd140 (de::Random& rnd)
{
return getFloat32s(rnd, getStructSize(SHADERTEMPLATE_STRIDE32BIT_STD140));
}
vector<bool> info32bitStd140 (void)
{
int ndx = 0u;
vector<bool> infoData (getStructSize(SHADERTEMPLATE_STRIDE32BIT_STD140));
for(int elementNdx = 0; elementNdx < structData.structArraySize; ++elementNdx)
{
infoData[ndx++] = true; //f32
infoData[ndx++] = false; //offset
infoData[ndx++] = true; //v2f32
infoData[ndx++] = true; //v2f32
addInfo(infoData, ndx, 3, true); //v3f32
infoData[ndx++] = false; //offset
addInfo(infoData, ndx, 4, true); //v4f16
//f32[3];
for (int i = 0; i < 3; ++i)
{
infoData[ndx++] = true; //f32;
addInfo(infoData, ndx, 3, false); //offset
}
//struct {f32, v2f32[3]} [11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
//struct.f32
infoData[ndx++] = true; //f32
addInfo(infoData, ndx, 3, false); //offset
//struct.f32.v2f16[3]
for (int j = 0; j < 3; ++j)
{
infoData[ndx++] = true; //v2f32
infoData[ndx++] = true; //v2f32
infoData[ndx++] = false; //offset
infoData[ndx++] = false; //offset
}
}
//v2f32[11];
for (int i = 0; i < structData.nestedArraySize; ++i)
{
infoData[ndx++] = true; //v2f32
infoData[ndx++] = true; //v2f32
infoData[ndx++] = false; //offset
infoData[ndx++] = false; //offset
}
//f16
infoData[ndx++] = true; //f16
addInfo(infoData, ndx, 3, false); //offset
//vec3[11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
addInfo(infoData, ndx, 3, true); //v3f32
infoData[ndx++] = false; //offset
}
//vec4[3]
for (int i = 0; i < 3; ++i)
{
addInfo(infoData, ndx, 4, true); //vec4
}
}
//Please check the data and offset
DE_ASSERT(ndx == static_cast<int>(infoData.size()));
return infoData;
}
vector<float> data32bitStd430 (de::Random& rnd)
{
return getFloat32s(rnd, getStructSize(SHADERTEMPLATE_STRIDE32BIT_STD430));
}
vector<bool> info32bitStd430 (void)
{
int ndx = 0u;
vector<bool> infoData (getStructSize(SHADERTEMPLATE_STRIDE32BIT_STD430));
for(int elementNdx = 0; elementNdx < structData.structArraySize; ++elementNdx)
{
infoData[ndx++] = true; //f32
infoData[ndx++] = false; //offset
infoData[ndx++] = true; //v2f32
infoData[ndx++] = true; //v2f32
addInfo(infoData, ndx, 3, true); //v3f32
infoData[ndx++] = false; //offset
addInfo(infoData, ndx, 4, true); //v4f16
//f32[3];
for (int i = 0; i < 3; ++i)
{
infoData[ndx++] = true; //f32;
}
infoData[ndx++] = false; //offset
//struct {f32, v2f32[3]} [11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
//struct.f32
infoData[ndx++] = true; //f32
infoData[ndx++] = false; //offset
//struct.f32.v2f16[3]
for (int j = 0; j < 3; ++j)
{
infoData[ndx++] = true; //v2f32
infoData[ndx++] = true; //v2f32
}
}
//v2f32[11];
for (int i = 0; i < structData.nestedArraySize; ++i)
{
infoData[ndx++] = true; //v2f32
infoData[ndx++] = true; //v2f32
}
//f32
infoData[ndx++] = true; //f32
infoData[ndx++] = false; //offset
//vec3[11]
for (int i = 0; i < structData.nestedArraySize; ++i)
{
addInfo(infoData, ndx, 3, true); //v3f32
infoData[ndx++] = false; //offset
}
//vec4[3]
for (int i = 0; i < 3; ++i)
{
addInfo(infoData, ndx, 4, true); //vec4
}
}
//Please check the data and offset
DE_ASSERT(ndx == static_cast<int>(infoData.size()));
return infoData;
}
vector<deInt16> dataMixStd140 (de::Random& rnd)
{
return getInt16s(rnd, getStructSize(SHADERTEMPLATE_STRIDEMIX_STD140));
}
vector<bool> infoMixStd140 (void)
{
int ndx = 0u;
vector<bool> infoData (getStructSize(SHADERTEMPLATE_STRIDEMIX_STD140));
for(int elementNdx = 0; elementNdx < structData.structArraySize; ++elementNdx)
{
infoData[ndx++] = true; //16b
addInfo(infoData, ndx, 1, false); //offset
addInfo(infoData, ndx, 2, true); //32b
addInfo(infoData, ndx, 2, true); //v2b16
addInfo(infoData, ndx, 2, false); //offset
addInfo(infoData, ndx, 4, true); //v2b32
addInfo(infoData, ndx, 3, true); //v3b16
addInfo(infoData, ndx, 1, false); //offset
addInfo(infoData, ndx, 6, true); //v3b32
addInfo(infoData, ndx, 2, false); //offset
addInfo(infoData, ndx, 4, true); //v4b16
addInfo(infoData, ndx, 4, false); //offset
addInfo(infoData, ndx, 8, true); //v4b32
//strut {b16, b32, v2b16[11], b32[11]}
for (int i = 0; i < structData.nestedArraySize; ++i)
{
infoData[ndx++] = true; //16b
addInfo(infoData, ndx, 1, false); //offset
addInfo(infoData, ndx, 2, true); //32b
addInfo(infoData, ndx, 4, false); //offset
for (int j = 0; j < structData.nestedArraySize; ++j)
{
addInfo(infoData, ndx, 2, true); //v2b16[11]
addInfo(infoData, ndx, 6, false); //offset
}
for (int j = 0; j < structData.nestedArraySize; ++j)
{
addInfo(infoData, ndx, 2, true); //b32[11]
addInfo(infoData, ndx, 6, false); //offset
}
}
for (int i = 0; i < structData.nestedArraySize; ++i)
{
infoData[ndx++] = true; //16b[11]
addInfo(infoData, ndx, 7, false); //offset
}
for (int i = 0; i < structData.nestedArraySize; ++i)
{
addInfo(infoData, ndx, 2, true); //b32bIn[11]
addInfo(infoData, ndx, 6, false); //offset
}
}
//Please check the data and offset
DE_ASSERT(ndx == static_cast<int>(infoData.size()));
return infoData;
}
vector<deInt16> dataMixStd430 (de::Random& rnd)
{
return getInt16s(rnd, getStructSize(SHADERTEMPLATE_STRIDEMIX_STD430));
}
vector<bool> infoMixStd430 (void)
{
int ndx = 0u;
vector<bool> infoData (getStructSize(SHADERTEMPLATE_STRIDEMIX_STD430));
for(int elementNdx = 0; elementNdx < structData.structArraySize; ++elementNdx)
{
infoData[ndx++] = true; //16b
addInfo(infoData, ndx, 1, false); //offset
addInfo(infoData, ndx, 2, true); //32b
addInfo(infoData, ndx, 2, true); //v2b16
addInfo(infoData, ndx, 2, false); //offset
addInfo(infoData, ndx, 4, true); //v2b32
addInfo(infoData, ndx, 3, true); //v3b16
addInfo(infoData, ndx, 1, false); //offset
addInfo(infoData, ndx, 6, true); //v3b32
addInfo(infoData, ndx, 2, false); //offset
addInfo(infoData, ndx, 4, true); //v4b16
addInfo(infoData, ndx, 4, false); //offset
addInfo(infoData, ndx, 8, true); //v4b32
//strut {b16, b32, v2b16[11], b32[11]}
for (int i = 0; i < structData.nestedArraySize; ++i)
{
infoData[ndx++] = true; //16b
addInfo(infoData, ndx, 1, false); //offset
addInfo(infoData, ndx, 2, true); //32b
addInfo(infoData, ndx, 22, true); //v2b16[11]
addInfo(infoData, ndx, 22, true); //b32[11]
}
addInfo(infoData, ndx, 11, true); //16b[11]
infoData[ndx++] = false; //offset
addInfo(infoData, ndx, 22, true); //32b[11]
addInfo(infoData, ndx, 6, false); //offset
}
//Please check the data and offset
DE_ASSERT(ndx == static_cast<int>(infoData.size()));
return infoData;
}
template<typename originType, typename resultType, ShaderTemplate funcOrigin, ShaderTemplate funcResult>
bool compareStruct(const resultType* returned, const originType* original, tcu::TestLog& log)
{
vector<bool> resultInfo;
vector<bool> originInfo;
vector<resultType> resultToCompare;
vector<originType> originToCompare;
switch(funcOrigin)
{
case SHADERTEMPLATE_STRIDE16BIT_STD140:
originInfo = info16bitStd140();
break;
case SHADERTEMPLATE_STRIDE16BIT_STD430:
originInfo = info16bitStd430();
break;
case SHADERTEMPLATE_STRIDE32BIT_STD140:
originInfo = info32bitStd140();
break;
case SHADERTEMPLATE_STRIDE32BIT_STD430:
originInfo = info32bitStd430();
break;
case SHADERTEMPLATE_STRIDEMIX_STD140:
originInfo = infoMixStd140();
break;
case SHADERTEMPLATE_STRIDEMIX_STD430:
originInfo = infoMixStd430();
break;
default:
DE_ASSERT(0);
}
switch(funcResult)
{
case SHADERTEMPLATE_STRIDE16BIT_STD140:
resultInfo = info16bitStd140();
break;
case SHADERTEMPLATE_STRIDE16BIT_STD430:
resultInfo = info16bitStd430();
break;
case SHADERTEMPLATE_STRIDE32BIT_STD140:
resultInfo = info32bitStd140();
break;
case SHADERTEMPLATE_STRIDE32BIT_STD430:
resultInfo = info32bitStd430();
break;
case SHADERTEMPLATE_STRIDEMIX_STD140:
resultInfo = infoMixStd140();
break;
case SHADERTEMPLATE_STRIDEMIX_STD430:
resultInfo = infoMixStd430();
break;
default:
DE_ASSERT(0);
}
for (unsigned int ndx = 0; ndx < static_cast<unsigned int>(resultInfo.size()); ++ndx)
{
if (resultInfo[ndx])
resultToCompare.push_back(returned[ndx]);
}
for (unsigned int ndx = 0; ndx < static_cast<unsigned int>(originInfo.size()); ++ndx)
{
if (originInfo[ndx])
originToCompare.push_back(original[ndx]);
}
//Different offset but that same amount of data
DE_ASSERT(originToCompare.size() == resultToCompare.size());
for (unsigned int ndx = 0; ndx < static_cast<unsigned int>(originToCompare.size()); ++ndx)
{
if (!compare16Bit(originToCompare[ndx], resultToCompare[ndx], RoundingModeFlags(ROUNDINGMODE_RTE | ROUNDINGMODE_RTZ), log))
return false;
}
return true;
}
template<typename originType, typename resultType, ShaderTemplate funcOrigin, ShaderTemplate funcResult>
bool computeCheckStruct (const std::vector<Resource>& originalFloats,
const vector<AllocationSp>& outputAllocs,
const std::vector<Resource>& /* expectedOutputs */,
tcu::TestLog& log)
{
for (deUint32 outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
{
vector<deUint8> originalBytes;
originalFloats[outputNdx].getBuffer()->getPackedBytes(originalBytes);
const resultType* returned = static_cast<const resultType*>(outputAllocs[outputNdx]->getHostPtr());
const originType* original = reinterpret_cast<const originType*>(&originalBytes.front());
if(!compareStruct<originType, resultType, funcOrigin, funcResult>(returned, original, log))
return false;
}
return true;
}
template<typename originType, typename resultType, ShaderTemplate funcOrigin, ShaderTemplate funcResult>
bool graphicsCheckStruct (const std::vector<Resource>& originalFloats,
const vector<AllocationSp>& outputAllocs,
const std::vector<Resource>& /* expectedOutputs */,
tcu::TestLog& log)
{
for (deUint32 outputNdx = 0; outputNdx < static_cast<deUint32>(outputAllocs.size()); ++outputNdx)
{
vector<deUint8> originalBytes;
originalFloats[outputNdx].getBuffer()->getPackedBytes(originalBytes);
const resultType* returned = static_cast<const resultType*>(outputAllocs[outputNdx]->getHostPtr());
const originType* original = reinterpret_cast<const originType*>(&originalBytes.front());
if(!compareStruct<originType, resultType, funcOrigin, funcResult>(returned, original, log))
return false;
}
return true;
}
string getStructShaderComponet (const ShaderTemplate component)
{
switch(component)
{
case SHADERTEMPLATE_TYPES:
return string(
"%f16 = OpTypeFloat 16\n"
"%v2f16 = OpTypeVector %f16 2\n"
"%v3f16 = OpTypeVector %f16 3\n"
"%v4f16 = OpTypeVector %f16 4\n"
"%f16ptr = OpTypePointer Uniform %f16\n"
"%v2f16ptr = OpTypePointer Uniform %v2f16\n"
"%v3f16ptr = OpTypePointer Uniform %v3f16\n"
"%v4f16ptr = OpTypePointer Uniform %v4f16\n"
"\n"
"%f32ptr = OpTypePointer Uniform %f32\n"
"%v2f32ptr = OpTypePointer Uniform %v2f32\n"
"%v3f32ptr = OpTypePointer Uniform %v3f32\n"
"%v4f32ptr = OpTypePointer Uniform %v4f32\n");
case SHADERTEMPLATE_STRIDE16BIT_STD140:
return string(
//struct {f16, v2f16[3]} [11]
"OpDecorate %v2f16arr3 ArrayStride 16\n"
"OpMemberDecorate %struct16 0 Offset 0\n"
"OpMemberDecorate %struct16 1 Offset 16\n"
"OpDecorate %struct16arr11 ArrayStride 64\n"
"OpDecorate %f16arr3 ArrayStride 16\n"
"OpDecorate %v2f16arr11 ArrayStride 16\n"
"OpDecorate %v3f16arr11 ArrayStride 16\n"
"OpDecorate %v4f16arr3 ArrayStride 16\n"
"OpDecorate %f16StructArr7 ArrayStride 1200\n"
"\n"
"OpMemberDecorate %f16Struct 0 Offset 0\n" //f16
"OpMemberDecorate %f16Struct 1 Offset 4\n" //v2f16
"OpMemberDecorate %f16Struct 2 Offset 8\n" //v3f16
"OpMemberDecorate %f16Struct 3 Offset 16\n" //v4f16
"OpMemberDecorate %f16Struct 4 Offset 32\n" //f16[3]
"OpMemberDecorate %f16Struct 5 Offset 80\n" //struct {f16, v2f16[3]} [11]
"OpMemberDecorate %f16Struct 6 Offset 784\n" //v2f16[11]
"OpMemberDecorate %f16Struct 7 Offset 960\n" //f16
"OpMemberDecorate %f16Struct 8 Offset 976\n" //v3f16[11]
"OpMemberDecorate %f16Struct 9 Offset 1152\n"); //v4f16[3]
case SHADERTEMPLATE_STRIDE16BIT_STD430:
return string(
//struct {f16, v2f16[3]} [11]
"OpDecorate %v2f16arr3 ArrayStride 4\n"
"OpMemberDecorate %struct16 0 Offset 0\n"
"OpMemberDecorate %struct16 1 Offset 4\n"
"OpDecorate %struct16arr11 ArrayStride 16\n"
"OpDecorate %f16arr3 ArrayStride 2\n"
"OpDecorate %v2f16arr11 ArrayStride 4\n"
"OpDecorate %v3f16arr11 ArrayStride 8\n"
"OpDecorate %v4f16arr3 ArrayStride 8\n"
"OpDecorate %f16StructArr7 ArrayStride 368\n"
"\n"
"OpMemberDecorate %f16Struct 0 Offset 0\n" //f16
"OpMemberDecorate %f16Struct 1 Offset 4\n" //v2f16
"OpMemberDecorate %f16Struct 2 Offset 8\n" //v3f16
"OpMemberDecorate %f16Struct 3 Offset 16\n" //v4f16
"OpMemberDecorate %f16Struct 4 Offset 24\n" //f16[3]
"OpMemberDecorate %f16Struct 5 Offset 32\n" //struct {f16, v2f16[3]} [11]
"OpMemberDecorate %f16Struct 6 Offset 208\n" //v2f16[11]
"OpMemberDecorate %f16Struct 7 Offset 252\n" //f16
"OpMemberDecorate %f16Struct 8 Offset 256\n" //v3f16[11]
"OpMemberDecorate %f16Struct 9 Offset 344\n"); //v4f16[3]
case SHADERTEMPLATE_STRIDE32BIT_STD140:
return string (
//struct {f32, v2f32[3]} [11]
"OpDecorate %v2f32arr3 ArrayStride 16\n"
"OpMemberDecorate %struct32 0 Offset 0\n"
"OpMemberDecorate %struct32 1 Offset 16\n"
"OpDecorate %struct32arr11 ArrayStride 64\n"
"OpDecorate %f32arr3 ArrayStride 16\n"
"OpDecorate %v2f32arr11 ArrayStride 16\n"
"OpDecorate %v3f32arr11 ArrayStride 16\n"
"OpDecorate %v4f32arr3 ArrayStride 16\n"
"OpDecorate %f32StructArr7 ArrayStride 1216\n"
"\n"
"OpMemberDecorate %f32Struct 0 Offset 0\n" //f32
"OpMemberDecorate %f32Struct 1 Offset 8\n" //v2f32
"OpMemberDecorate %f32Struct 2 Offset 16\n" //v3f32
"OpMemberDecorate %f32Struct 3 Offset 32\n" //v4f32
"OpMemberDecorate %f32Struct 4 Offset 48\n" //f32[3]
"OpMemberDecorate %f32Struct 5 Offset 96\n" //struct {f32, v2f32[3]} [11]
"OpMemberDecorate %f32Struct 6 Offset 800\n" //v2f32[11]
"OpMemberDecorate %f32Struct 7 Offset 976\n" //f32
"OpMemberDecorate %f32Struct 8 Offset 992\n" //v3f32[11]
"OpMemberDecorate %f32Struct 9 Offset 1168\n"); //v4f32[3]
case SHADERTEMPLATE_STRIDE32BIT_STD430:
return string(
//struct {f32, v2f32[3]} [11]
"OpDecorate %v2f32arr3 ArrayStride 8\n"
"OpMemberDecorate %struct32 0 Offset 0\n"
"OpMemberDecorate %struct32 1 Offset 8\n"
"OpDecorate %struct32arr11 ArrayStride 32\n"
"OpDecorate %f32arr3 ArrayStride 4\n"
"OpDecorate %v2f32arr11 ArrayStride 8\n"
"OpDecorate %v3f32arr11 ArrayStride 16\n"
"OpDecorate %v4f32arr3 ArrayStride 16\n"
"OpDecorate %f32StructArr7 ArrayStride 736\n"
"\n"
"OpMemberDecorate %f32Struct 0 Offset 0\n" //f32
"OpMemberDecorate %f32Struct 1 Offset 8\n" //v2f32
"OpMemberDecorate %f32Struct 2 Offset 16\n" //v3f32
"OpMemberDecorate %f32Struct 3 Offset 32\n" //v4f32
"OpMemberDecorate %f32Struct 4 Offset 48\n" //f32[3]
"OpMemberDecorate %f32Struct 5 Offset 64\n" //struct {f32, v2f32[3]}[11]
"OpMemberDecorate %f32Struct 6 Offset 416\n" //v2f32[11]
"OpMemberDecorate %f32Struct 7 Offset 504\n" //f32
"OpMemberDecorate %f32Struct 8 Offset 512\n" //v3f32[11]
"OpMemberDecorate %f32Struct 9 Offset 688\n"); //v4f32[3]
case SHADERTEMPLATE_STRIDEMIX_STD140:
return string(
"\n"//strutNestedIn {b16, b32, v2b16[11], b32[11]}
"OpDecorate %v2b16NestedArr11${InOut} ArrayStride 16\n" //v2b16[11]
"OpDecorate %b32NestedArr11${InOut} ArrayStride 16\n" //b32[11]
"OpMemberDecorate %sNested${InOut} 0 Offset 0\n" //b16
"OpMemberDecorate %sNested${InOut} 1 Offset 4\n" //b32
"OpMemberDecorate %sNested${InOut} 2 Offset 16\n" //v2b16[11]
"OpMemberDecorate %sNested${InOut} 3 Offset 192\n" //b32[11]
"OpDecorate %sNestedArr11${InOut} ArrayStride 368\n" //strutNestedIn[11]
"\n"//strutIn {b16, b32, v2b16, v2b32, v3b16, v3b32, v4b16, v4b32, strutNestedIn[11], b16In[11], b32bIn[11]}
"OpDecorate %sb16Arr11${InOut} ArrayStride 16\n" //b16In[11]
"OpDecorate %sb32Arr11${InOut} ArrayStride 16\n" //b32bIn[11]
"OpMemberDecorate %struct${InOut} 0 Offset 0\n" //b16
"OpMemberDecorate %struct${InOut} 1 Offset 4\n" //b32
"OpMemberDecorate %struct${InOut} 2 Offset 8\n" //v2b16
"OpMemberDecorate %struct${InOut} 3 Offset 16\n" //v2b32
"OpMemberDecorate %struct${InOut} 4 Offset 24\n" //v3b16
"OpMemberDecorate %struct${InOut} 5 Offset 32\n" //v3b32
"OpMemberDecorate %struct${InOut} 6 Offset 48\n" //v4b16
"OpMemberDecorate %struct${InOut} 7 Offset 64\n" //v4b32
"OpMemberDecorate %struct${InOut} 8 Offset 80\n" //strutNestedIn[11]
"OpMemberDecorate %struct${InOut} 9 Offset 4128\n" //b16In[11]
"OpMemberDecorate %struct${InOut} 10 Offset 4304\n" //b32bIn[11]
"OpDecorate %structArr7${InOut} ArrayStride 4480\n"); //strutIn[7]
case SHADERTEMPLATE_STRIDEMIX_STD430:
return string(
"\n"//strutNestedOut {b16, b32, v2b16[11], b32[11]}
"OpDecorate %v2b16NestedArr11${InOut} ArrayStride 4\n" //v2b16[11]
"OpDecorate %b32NestedArr11${InOut} ArrayStride 4\n" //b32[11]
"OpMemberDecorate %sNested${InOut} 0 Offset 0\n" //b16
"OpMemberDecorate %sNested${InOut} 1 Offset 4\n" //b32
"OpMemberDecorate %sNested${InOut} 2 Offset 8\n" //v2b16[11]
"OpMemberDecorate %sNested${InOut} 3 Offset 52\n" //b32[11]
"OpDecorate %sNestedArr11${InOut} ArrayStride 96\n" //strutNestedOut[11]
"\n"//strutOut {b16, b32, v2b16, v2b32, v3b16, v3b32, v4b16, v4b32, strutNestedOut[11], b16Out[11], b32bOut[11]}
"OpDecorate %sb16Arr11${InOut} ArrayStride 2\n" //b16Out[11]
"OpDecorate %sb32Arr11${InOut} ArrayStride 4\n" //b32bOut[11]
"OpMemberDecorate %struct${InOut} 0 Offset 0\n" //b16
"OpMemberDecorate %struct${InOut} 1 Offset 4\n" //b32
"OpMemberDecorate %struct${InOut} 2 Offset 8\n" //v2b16
"OpMemberDecorate %struct${InOut} 3 Offset 16\n" //v2b32
"OpMemberDecorate %struct${InOut} 4 Offset 24\n" //v3b16
"OpMemberDecorate %struct${InOut} 5 Offset 32\n" //v3b32
"OpMemberDecorate %struct${InOut} 6 Offset 48\n" //v4b16
"OpMemberDecorate %struct${InOut} 7 Offset 64\n" //v4b32
"OpMemberDecorate %struct${InOut} 8 Offset 80\n" //strutNestedOut[11]
"OpMemberDecorate %struct${InOut} 9 Offset 1136\n" //b16Out[11]
"OpMemberDecorate %struct${InOut} 10 Offset 1160\n" //b32bOut[11]
"OpDecorate %structArr7${InOut} ArrayStride 1216\n"); //strutOut[7]
default:
return string("");
}
}
/*Return string contains spirv loop begin.
the spec should contains "exeCount" - with name of const i32, it is number of executions
the spec should contains "loopName" - suffix for all local names
%Val${loopName} - index which can be used inside loop
"%ndxArr${loopName} = OpVariable %fp_i32 Function\n" - has to be defined outside
The function should be always use with endLoop function*/
std::string beginLoop(const std::map<std::string, std::string>& spec)
{
const tcu::StringTemplate loopBegin (
"OpStore %ndxArr${loopName} %zero\n"
"OpBranch %Loop${loopName}\n"
"%Loop${loopName} = OpLabel\n"
"OpLoopMerge %MergeLabel1${loopName} %MergeLabel2${loopName} None\n"
"OpBranch %Label1${loopName}\n"
"%Label1${loopName} = OpLabel\n"
"%Val${loopName} = OpLoad %i32 %ndxArr${loopName}\n"
"%LessThan${loopName} = OpSLessThan %bool %Val${loopName} %${exeCount}\n"
"OpBranchConditional %LessThan${loopName} %ifLabel${loopName} %MergeLabel1${loopName}\n"
"%ifLabel${loopName} = OpLabel\n");
return loopBegin.specialize(spec);
}
/*Return string contains spirv loop end.
the spec should contains "loopName" - suffix for all local names, suffix should be the same in beginLoop
The function should be always use with beginLoop function*/
std::string endLoop(const std::map<std::string, std::string>& spec)
{
const tcu::StringTemplate loopEnd (
"OpBranch %MergeLabel2${loopName}\n"
"%MergeLabel2${loopName} = OpLabel\n"
"%plusOne${loopName} = OpIAdd %i32 %Val${loopName} %c_i32_1\n"
"OpStore %ndxArr${loopName} %plusOne${loopName}\n"
"OpBranch %Loop${loopName}\n"
"%MergeLabel1${loopName} = OpLabel\n");
return loopEnd.specialize(spec);
}
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}\n"
"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"
"%v3u32 = OpTypeVector %u32 3\n"
"%uvec3ptr = OpTypePointer Input %v3u32\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"
"%c_i32_ci = OpConstant %i32 ${constarrayidx}\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 %v3u32 %id\n"
"%x = OpCompositeExtract %u32 %idval 0\n"
"%inloc = OpAccessChain %${base16}ptr %ssbo16 %zero %${arrayindex} ${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;
bool useConstantIndex;
unsigned constantIndex;
unsigned count;
unsigned inputStride;
};
const CompositeType cTypes[2][5] =
{
{
{"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", false, 0, numElements, 1},
{"scalar_const_idx_5", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", true, 5, numElements, 1},
{"scalar_const_idx_8", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", true, 8, numElements, 1},
{"vector", "v2f32", "v2f16", "OpDecorate %v2f32arr ArrayStride 8\nOpDecorate %v2f16arr ArrayStride 4\n", false, 0, numElements / 2, 2},
{"matrix", "v2f32", "v2f16", "OpDecorate %m4v2f32arr ArrayStride 32\nOpDecorate %m4v2f16arr ArrayStride 16\n", false, 0, numElements / 8, 8}
},
{
{"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 16\n", false, 0, numElements, 8},
{"scalar_const_idx_5", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 16\n", true, 5, numElements, 8},
{"scalar_const_idx_8", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 16\n", true, 8, numElements, 8},
{"vector", "v2f32", "v2f16", "OpDecorate %v2f32arr ArrayStride 8\nOpDecorate %v2f16arr ArrayStride 16\n", false, 0, numElements / 2, 8},
{"matrix", "v2f32", "v2f16", "OpDecorate %m4v2f32arr ArrayStride 32\nOpDecorate %m4v2f16arr ArrayStride 16\n", false, 0, numElements / 8, 8}
}
};
for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes[capIdx]); ++tyIdx)
{
ComputeShaderSpec spec;
map<string, string> specs;
string testName = string(CAPABILITIES[capIdx].name) + "_" + cTypes[capIdx][tyIdx].name + "_float";
specs["capability"] = CAPABILITIES[capIdx].cap;
specs["storage"] = CAPABILITIES[capIdx].decor;
specs["stride"] = cTypes[capIdx][tyIdx].stride;
specs["base32"] = cTypes[capIdx][tyIdx].base32;
specs["base16"] = cTypes[capIdx][tyIdx].base16;
specs["types"] = floatTypes;
specs["convert"] = "OpFConvert";
specs["constarrayidx"] = de::toString(cTypes[capIdx][tyIdx].constantIndex);
if (cTypes[capIdx][tyIdx].useConstantIndex)
specs["arrayindex"] = "c_i32_ci";
else
specs["arrayindex"] = "x";
const deUint32 inputStride = cTypes[capIdx][tyIdx].inputStride;
const deUint32 count = cTypes[capIdx][tyIdx].count;
const deUint32 scalarsPerItem = numElements / count;
vector<deFloat16> float16Data = getFloat16s(rnd, numElements * inputStride);
vector<float> float32Data;
float32Data.reserve(numElements);
for (deUint32 numIdx = 0; numIdx < count; ++numIdx)
for (deUint32 scalarIdx = 0; scalarIdx < scalarsPerItem; scalarIdx++)
float32Data.push_back(deFloat16To32(float16Data[numIdx * inputStride + scalarIdx]));
vector<float> float32DataConstIdx;
if (cTypes[capIdx][tyIdx].useConstantIndex)
{
const deUint32 numFloats = numElements / cTypes[capIdx][tyIdx].count;
for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx)
float32DataConstIdx.push_back(float32Data[cTypes[capIdx][tyIdx].constantIndex * numFloats + numIdx % numFloats]);
}
if (strcmp(cTypes[capIdx][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[capIdx][tyIdx].count, 1, 1);
spec.verifyIO = check32BitFloats;
spec.inputs.push_back(Resource(BufferSp(new Float16Buffer(float16Data)), CAPABILITIES[capIdx].dtype));
spec.outputs.push_back(Resource(BufferSp(new Float32Buffer(cTypes[capIdx][tyIdx].useConstantIndex ? float32DataConstIdx : 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;
bool useConstantIndex;
unsigned constantIndex;
unsigned count;
unsigned inputStride;
};
const CompositeType cTypes[2][8] =
{
{
{"scalar_sint", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", false, 0, numElements, 1},
{"scalar_sint_const_idx_5", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", true, 5, numElements, 1},
{"scalar_sint_const_idx_8", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", true, 8, numElements, 1},
{"scalar_uint", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", false, 0, numElements, 1},
{"scalar_uint_const_idx_5", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", true, 5, numElements, 1},
{"scalar_uint_const_idx_8", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", true, 8, numElements, 1},
{"vector_sint", true, sintTypes, "v4i32", "v4i16", "OpSConvert", "OpDecorate %v4i32arr ArrayStride 16\nOpDecorate %v4i16arr ArrayStride 8\n", false, 0, numElements / 4, 4},
{"vector_uint", false, uintTypes, "v4u32", "v4u16", "OpUConvert", "OpDecorate %v4u32arr ArrayStride 16\nOpDecorate %v4u16arr ArrayStride 8\n", false, 0, numElements / 4, 4}
},
{
{"scalar_sint", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 16\n", false, 0, numElements, 8},
{"scalar_sint_const_idx_5", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 16\n", true, 5, numElements, 8},
{"scalar_sint_const_idx_8", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 16\n", true, 8, numElements, 8},
{"scalar_uint", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 16\n", false, 0, numElements, 8},
{"scalar_uint_const_idx_5", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 16\n", true, 5, numElements, 8},
{"scalar_uint_const_idx_8", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 16\n", true, 8, numElements, 8},
{"vector_sint", true, sintTypes, "v4i32", "v4i16", "OpSConvert", "OpDecorate %v4i32arr ArrayStride 16\nOpDecorate %v4i16arr ArrayStride 16\n", false, 0, numElements / 4, 8},
{"vector_uint", false, uintTypes, "v4u32", "v4u16", "OpUConvert", "OpDecorate %v4u32arr ArrayStride 16\nOpDecorate %v4u16arr ArrayStride 16\n", false, 0, numElements / 4, 8}
}
};
for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes[capIdx]); ++tyIdx)
{
ComputeShaderSpec spec;
map<string, string> specs;
string testName = string(CAPABILITIES[capIdx].name) + "_" + cTypes[capIdx][tyIdx].name;
const deUint32 inputStride = cTypes[capIdx][tyIdx].inputStride;
vector<deInt16> inputs = getInt16s(rnd, numElements * inputStride);
vector<deInt32> sOutputs;
vector<deInt32> uOutputs;
const deUint16 signBitMask = 0x8000;
const deUint32 signExtendMask = 0xffff0000;
const deUint32 count = cTypes[capIdx][tyIdx].count;
const deUint32 scalarsPerItem = numElements / count;
sOutputs.reserve(numElements);
uOutputs.reserve(numElements);
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
for (deUint32 scalarIdx = 0; scalarIdx < scalarsPerItem; ++scalarIdx)
{
const deInt16 input = inputs[numNdx * inputStride + scalarIdx];
uOutputs.push_back(static_cast<deUint16>(input));
if (input & signBitMask)
sOutputs.push_back(static_cast<deInt32>(input | signExtendMask));
else
sOutputs.push_back(static_cast<deInt32>(input));
}
vector<deInt32> intDataConstIdx;
if (cTypes[capIdx][tyIdx].useConstantIndex)
{
for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx)
{
const deInt32 idx = cTypes[capIdx][tyIdx].constantIndex * scalarsPerItem + numIdx % scalarsPerItem;
if (cTypes[capIdx][tyIdx].isSigned)
intDataConstIdx.push_back(sOutputs[idx]);
else
intDataConstIdx.push_back(uOutputs[idx]);
}
}
specs["capability"] = CAPABILITIES[capIdx].cap;
specs["storage"] = CAPABILITIES[capIdx].decor;
specs["stride"] = cTypes[capIdx][tyIdx].stride;
specs["base32"] = cTypes[capIdx][tyIdx].base32;
specs["base16"] = cTypes[capIdx][tyIdx].base16;
specs["types"] = cTypes[capIdx][tyIdx].types;
specs["convert"] = cTypes[capIdx][tyIdx].opcode;
specs["constarrayidx"] = de::toString(cTypes[capIdx][tyIdx].constantIndex);
if (cTypes[capIdx][tyIdx].useConstantIndex)
specs["arrayindex"] = "c_i32_ci";
else
specs["arrayindex"] = "x";
spec.assembly = shaderTemplate.specialize(specs);
spec.numWorkGroups = IVec3(cTypes[capIdx][tyIdx].count, 1, 1);
spec.inputs.push_back(Resource(BufferSp(new Int16Buffer(inputs)), CAPABILITIES[capIdx].dtype));
if (cTypes[capIdx][tyIdx].useConstantIndex)
spec.outputs.push_back(Resource(BufferSp(new Int32Buffer(intDataConstIdx))));
else if (cTypes[capIdx][tyIdx].isSigned)
spec.outputs.push_back(Resource(BufferSp(new Int32Buffer(sOutputs))));
else
spec.outputs.push_back(Resource(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 addCompute16bitStorageUniform16To32ChainAccessGroup (tcu::TestCaseGroup* group)
{
tcu::TestContext& testCtx = group->getTestContext();
de::Random rnd (deStringHash(group->getName()));
const deUint32 structSize = 128; // In number of 16bit items. Includes padding.
vector<deFloat16> inputDataFloat = getFloat16s(rnd, structSize * 4);
vector<deInt16> inputDataInt = getInt16s(rnd, structSize * 4);
vector<float> outputDataFloat;
vector<deInt32> outputDataSInt;
vector<deInt32> outputDataUInt;
vector<tcu::UVec4> indices;
// Input is an array of a struct that varies on 16bit data type being tested:
//
// Float:
//
// float16 scalars[3]
// mat4x3 matrix
// vec3 vector
//
// Int:
//
// int16 scalars[3]
// int16 array2D[4][3]
// ivec3 vector
//
// UInt:
//
// uint16 scalars[3]
// uint16 array2D[4][3]
// uvec3 vector
const StringTemplate shaderTemplate (
" OpCapability Shader\n"
" OpCapability ${capability}\n"
" OpExtension \"SPV_KHR_16bit_storage\"\n"
" %1 = OpExtInstImport \"GLSL.std.450\"\n"
" OpMemoryModel Logical GLSL450\n"
" OpEntryPoint GLCompute %main \"main\"\n"
" OpExecutionMode %main LocalSize 1 1 1\n"
" OpSource GLSL 430\n"
" OpDecorate %Output BufferBlock\n"
" OpDecorate %dataOutput DescriptorSet 0\n"
" OpDecorate %dataOutput Binding 1\n"
" OpDecorate %scalarArray ArrayStride 16\n"
" OpDecorate %scalarArray2D ArrayStride 48\n"
" OpMemberDecorate %S 0 Offset 0\n"
" OpMemberDecorate %S 1 Offset 48\n"
" ${decoration:opt}\n"
" OpMemberDecorate %S 2 Offset 240\n"
" OpDecorate %_arr_S_uint_4 ArrayStride 256\n"
" OpMemberDecorate %Input 0 Offset 0\n"
" OpMemberDecorate %Output 0 Offset 0\n"
" OpDecorate %Input ${storage}\n"
" OpDecorate %dataInput DescriptorSet 0\n"
" OpDecorate %dataInput Binding 0\n"
" %f16 = OpTypeFloat 16\n"
" %f32 = OpTypeFloat 32\n"
" %i16 = OpTypeInt 16 1\n"
" %i32 = OpTypeInt 32 1\n"
" %u16 = OpTypeInt 16 0\n"
" %u32 = OpTypeInt 32 0\n"
" %void = OpTypeVoid\n"
" %voidFunc = OpTypeFunction %void\n"
" %_ptr_Function_uint = OpTypePointer Function %u32\n"
" %v3u32 = OpTypeVector %u32 3\n"
" %_ptr_Input_v3u32 = OpTypePointer Input %v3u32\n"
" %int_0 = OpConstant %i32 0\n"
" %uint_3 = OpConstant %u32 3\n"
" %uint_4 = OpConstant %u32 4\n"
" %s0 = OpConstant %u32 ${s0}\n"
" %s1 = OpConstant %u32 ${s1}\n"
" %s2 = OpConstant %u32 ${s2}\n"
" %s3 = OpConstant %u32 ${s3}\n"
" %Output = OpTypeStruct %${type}32\n"
" %_ptr_Uniform_Output = OpTypePointer Uniform %Output\n"
" %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n"
" %scalarArray = OpTypeArray %${type}16 %uint_3\n"
" %v3f16 = OpTypeVector %f16 3\n"
" %v3i16 = OpTypeVector %i16 3\n"
" %v3u16 = OpTypeVector %u16 3\n"
" %matrix = OpTypeMatrix %v3f16 4\n"
" %scalarArray2D = OpTypeArray %scalarArray %uint_4\n"
" %S = OpTypeStruct %scalarArray %${type2D} %v3${type}16\n"
" %_arr_S_uint_4 = OpTypeArray %S %uint_4\n"
" %Input = OpTypeStruct %_arr_S_uint_4\n"
" %_ptr_Uniform_Input = OpTypePointer Uniform %Input\n"
" %dataInput = OpVariable %_ptr_Uniform_Input Uniform\n"
" %_ptr_Uniform_16bit_data = OpTypePointer Uniform %${type}16\n"
" %_ptr_Uniform_32bit_data = OpTypePointer Uniform %${type}32\n"
" %main = OpFunction %void None %voidFunc\n"
" %entry = OpLabel\n"
" %dataPtr = ${accessChain}\n"
" %data = OpLoad %${type}16 %dataPtr\n"
" %converted = ${convert}\n"
" %outPtr = OpAccessChain %_ptr_Uniform_32bit_data %dataOutput %int_0\n"
" OpStore %outPtr %converted\n"
" OpReturn\n"
" OpFunctionEnd\n");
// Generate constant indices for OpChainAccess. We need to use constant values
// when indexing into structures. This loop generates all permutations.
for (deUint32 idx0 = 0; idx0 < 4; ++idx0)
for (deUint32 idx1 = 0; idx1 < 3; ++idx1)
for (deUint32 idx2 = 0; idx2 < (idx1 == 1u ? 4u : 3u); ++idx2)
for (deUint32 idx3 = 0; idx3 < (idx1 == 1u ? 3u : 1u); ++idx3)
indices.push_back(tcu::UVec4(idx0, idx1, idx2, idx3));
for (deUint32 numIdx = 0; numIdx < (deUint32)indices.size(); ++numIdx)
{
const deUint16 signBitMask = 0x8000;
const deUint32 signExtendMask = 0xffff0000;
// Determine the selected output float for the selected indices.
const tcu::UVec4 vec = indices[numIdx];
// Offsets are in multiples of 16bits. Floats are using matrix as the
// second field, which has different layout rules than 2D array.
// Therefore separate offset tables are needed.
const deUint32 fieldOffsetsFloat[3][3] =
{
{0u, 8u, 0u},
{24, 24u, 1u},
{120u, 1u, 0u}
};
const deUint32 fieldOffsetsInt[3][3] =
{
{0u, 8u, 0u},
{24, 24u, 8u},
{120u, 1u, 0u}
};
const deUint32 offsetFloat = vec.x() * structSize + fieldOffsetsFloat[vec.y()][0] + fieldOffsetsFloat[vec.y()][1] * vec.z() + fieldOffsetsFloat[vec.y()][2] * vec.w();
const deUint32 offsetInt = vec.x() * structSize + fieldOffsetsInt[vec.y()][0] + fieldOffsetsInt[vec.y()][1] * vec.z() + fieldOffsetsInt[vec.y()][2] * vec.w();
const bool hasSign = inputDataInt[offsetInt] & signBitMask;
outputDataFloat.push_back(deFloat16To32(inputDataFloat[offsetFloat]));
outputDataUInt.push_back((deUint16)inputDataInt[offsetInt]);
outputDataSInt.push_back((deInt32)(inputDataInt[offsetInt] | (hasSign ? signExtendMask : 0u)));
}
for (deUint32 indicesIdx = 0; indicesIdx < (deUint32)indices.size(); ++indicesIdx)
for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
{
string indexString = de::toString(indices[indicesIdx].x()) + "_" + de::toString(indices[indicesIdx].y()) + "_" + de::toString(indices[indicesIdx].z());
if (indices[indicesIdx].y() == 1)
indexString += string("_") + de::toString(indices[indicesIdx].w());
const string testNameBase = string(CAPABILITIES[capIdx].name) + "_" + indexString + "_";
struct DataType
{
string name;
string type;
string convert;
string type2D; // Matrix when using floats. 2D array otherwise.
BufferSp inputs;
BufferSp outputs;
};
const DataType dataTypes[] =
{
{ "float", "f", "OpFConvert %f32 %data", "matrix", BufferSp(new Float16Buffer(inputDataFloat)), BufferSp(new Float32Buffer(vector<float>(1, outputDataFloat[indicesIdx]))) },
{ "int", "i", "OpSConvert %i32 %data", "scalarArray2D", BufferSp(new Int16Buffer(inputDataInt)), BufferSp(new Int32Buffer(vector<deInt32>(1, outputDataSInt[indicesIdx]))) },
{ "uint", "u", "OpUConvert %u32 %data", "scalarArray2D", BufferSp(new Int16Buffer(inputDataInt)), BufferSp(new Int32Buffer(vector<deInt32>(1, outputDataUInt[indicesIdx]))) }
};
for (deUint32 dataTypeIdx = 0; dataTypeIdx < DE_LENGTH_OF_ARRAY(dataTypes); ++dataTypeIdx)
{
const string testName = testNameBase + dataTypes[dataTypeIdx].name;
map<string, string> specs;
ComputeShaderSpec spec;
specs["capability"] = CAPABILITIES[capIdx].cap;
specs["storage"] = CAPABILITIES[capIdx].decor;
specs["s0"] = de::toString(indices[indicesIdx].x());
specs["s1"] = de::toString(indices[indicesIdx].y());
specs["s2"] = de::toString(indices[indicesIdx].z());
specs["s3"] = de::toString(indices[indicesIdx].w());
specs["type"] = dataTypes[dataTypeIdx].type;
specs["convert"] = dataTypes[dataTypeIdx].convert;
specs["type2D"] = dataTypes[dataTypeIdx].type2D;
if (indices[indicesIdx].y() == 1)
specs["accessChain"] = "OpAccessChain %_ptr_Uniform_16bit_data %dataInput %int_0 %s0 %s1 %s2 %s3";
else
specs["accessChain"] = "OpAccessChain %_ptr_Uniform_16bit_data %dataInput %int_0 %s0 %s1 %s2";
if (dataTypeIdx == 0)
{
spec.verifyIO = check32BitFloats;
specs["decoration"] = "OpMemberDecorate %S 1 ColMajor\nOpMemberDecorate %S 1 MatrixStride 48\n";
}
spec.assembly = shaderTemplate.specialize(specs);
spec.numWorkGroups = IVec3(1, 1, 1);
spec.extensions.push_back ("VK_KHR_16bit_storage");
spec.requestedVulkanFeatures = get16BitStorageFeatures(CAPABILITIES[capIdx].name);
spec.inputs.push_back(Resource(dataTypes[dataTypeIdx].inputs, CAPABILITIES[capIdx].dtype));
spec.outputs.push_back(Resource(dataTypes[dataTypeIdx].outputs));
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"
"%void = OpTypeVoid\n"
"%voidf = OpTypeFunction %void\n"
"%u32 = OpTypeInt 32 0\n"
"%i32 = OpTypeInt 32 1\n"
"%f32 = OpTypeFloat 32\n"
"%v3u32 = OpTypeVector %u32 3\n"
"%uvec3ptr = OpTypePointer Input %v3u32\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"
"%c_i32_ci = OpConstant %i32 ${constarrayidx}\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 %v3u32 %id\n"
"%x = OpCompositeExtract %u32 %idval 0\n"
"%inloc = OpAccessChain %${base16}ptr %pc16 %zero %${arrayindex} ${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;
bool useConstantIndex;
unsigned constantIndex;
unsigned count;
};
const CompositeType cTypes[] =
{
{"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", false, 0, numElements},
{"scalar_const_idx_5", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", true, 5, numElements},
{"scalar_const_idx_8", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", true, 8, numElements},
{"vector", "v4f32", "v4f16", "OpDecorate %v4f32arr ArrayStride 16\nOpDecorate %v4f16arr ArrayStride 8\n", false, 0, numElements / 4},
{"matrix", "v4f32", "v4f16", "OpDecorate %m2v4f32arr ArrayStride 32\nOpDecorate %m2v4f16arr ArrayStride 16\n", false, 0, 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";
vector<float> float32DataConstIdx;
if (cTypes[tyIdx].useConstantIndex)
{
const deUint32 numFloats = numElements / cTypes[tyIdx].count;
for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx)
float32DataConstIdx.push_back(float32Data[cTypes[tyIdx].constantIndex * numFloats + numIdx % numFloats]);
}
specs["stride"] = cTypes[tyIdx].stride;
specs["base32"] = cTypes[tyIdx].base32;
specs["base16"] = cTypes[tyIdx].base16;
specs["types"] = floatTypes;
specs["convert"] = "OpFConvert";
specs["constarrayidx"] = de::toString(cTypes[tyIdx].constantIndex);
if (cTypes[tyIdx].useConstantIndex)
specs["arrayindex"] = "c_i32_ci";
else
specs["arrayindex"] = "x";
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(Resource(BufferSp(new Float32Buffer(cTypes[tyIdx].useConstantIndex ? float32DataConstIdx : 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;
bool useConstantIndex;
unsigned constantIndex;
unsigned count;
};
const CompositeType cTypes[] =
{
{"scalar_sint", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", false, 0, numElements},
{"scalar_sint_const_idx_5", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", true, 5, numElements},
{"scalar_sint_const_idx_8", true, sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", true, 8, numElements},
{"scalar_uint", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", false, 0, numElements},
{"scalar_uint_const_idx_5", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", true, 5, numElements},
{"scalar_uint_const_idx_8", false, uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", true, 8, numElements},
{"vector_sint", true, sintTypes, "v2i32", "v2i16", "OpSConvert", "OpDecorate %v2i32arr ArrayStride 8\nOpDecorate %v2i16arr ArrayStride 4\n", false, 0, numElements / 2},
{"vector_uint", false, uintTypes, "v2u32", "v2u16", "OpUConvert", "OpDecorate %v2u32arr ArrayStride 8\nOpDecorate %v2u16arr ArrayStride 4\n", false, 0, 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;
vector<deInt32> intDataConstIdx;
if (cTypes[tyIdx].useConstantIndex)
{
const deUint32 numInts = numElements / cTypes[tyIdx].count;
for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx)
{
const deInt32 idx = cTypes[tyIdx].constantIndex * numInts + numIdx % numInts;
if (cTypes[tyIdx].isSigned)
intDataConstIdx.push_back(sOutputs[idx]);
else
intDataConstIdx.push_back(uOutputs[idx]);
}
}
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;
specs["constarrayidx"] = de::toString(cTypes[tyIdx].constantIndex);
if (cTypes[tyIdx].useConstantIndex)
specs["arrayindex"] = "c_i32_ci";
else
specs["arrayindex"] = "x";
spec.assembly = shaderTemplate.specialize(specs);
spec.numWorkGroups = IVec3(cTypes[tyIdx].count, 1, 1);
spec.pushConstants = BufferSp(new Int16Buffer(inputs));
if (cTypes[tyIdx].useConstantIndex)
spec.outputs.push_back(Resource(BufferSp(new Int32Buffer(intDataConstIdx))));
else if (cTypes[tyIdx].isSigned)
spec.outputs.push_back(Resource(BufferSp(new Int32Buffer(sOutputs))));
else
spec.outputs.push_back(Resource(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];
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]));
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 ${arraystride}\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_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"
"%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_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");
// Scalar
{
const deUint32 arrayStrides[] = {4, 16};
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) + "_scalar_" + intFacts[factIdx].name;
specs["cap"] = CAPABILITIES[capIdx].cap;
specs["indecor"] = CAPABILITIES[capIdx].decor;
specs["itype32"] = intFacts[factIdx].type32;
specs["v4itype32"] = "%v4" + string(intFacts[factIdx].type32).substr(1);
specs["itype16"] = intFacts[factIdx].type16;
specs["signed"] = intFacts[factIdx].isSigned;
specs["convert"] = intFacts[factIdx].opcode;
specs["arraystride"] = de::toString(arrayStrides[capIdx]);
fragments["pre_main"] = scalarPreMain.specialize(specs);
fragments["testfun"] = scalarTestFunc.specialize(specs);
fragments["capability"] = capabilities.specialize(specs);
fragments["decoration"] = scalarDecoration.specialize(specs);
vector<deInt32> inputsPadded;
for (size_t dataIdx = 0; dataIdx < inputs.size(); ++dataIdx)
{
inputsPadded.push_back(inputs[dataIdx]);
for (deUint32 padIdx = 0; padIdx < arrayStrides[capIdx] / 4 - 1; ++padIdx)
inputsPadded.push_back(0);
}
GraphicsResources resources;
VulkanFeatures features;
resources.inputs.push_back(Resource(BufferSp(new Int32Buffer(inputsPadded)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
resources.outputs.push_back(Resource(BufferSp(new Int16Buffer(outputs)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
resources.inputs.back().setDescriptorType(CAPABILITIES[capIdx].dtype);
features = get16BitStorageFeatures(CAPABILITIES[capIdx].name);
features.coreFeatures.vertexPipelineStoresAndAtomics = true;
features.coreFeatures.fragmentStoresAndAtomics = true;
createTestsForAllStages(name, defaultColors, defaultColors, fragments, resources, extensions, testGroup, features);
}
}
// Vector
{
GraphicsResources resources;
resources.inputs.push_back(Resource(BufferSp(new Int32Buffer(inputs)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
resources.outputs.push_back(Resource(BufferSp(new Int16Buffer(outputs)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
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) + "_vector_" + intFacts[factIdx].name;
VulkanFeatures features;
specs["cap"] = CAPABILITIES[capIdx].cap;
specs["indecor"] = CAPABILITIES[capIdx].decor;
specs["itype32"] = intFacts[factIdx].type32;
specs["v4itype32"] = "%v4" + string(intFacts[factIdx].type32).substr(1);
specs["itype16"] = intFacts[factIdx].type16;
specs["signed"] = intFacts[factIdx].isSigned;
specs["convert"] = intFacts[factIdx].opcode;
fragments["pre_main"] = vecPreMain.specialize(specs);
fragments["testfun"] = vecTestFunc.specialize(specs);
fragments["capability"] = capabilities.specialize(specs);
fragments["decoration"] = vecDecoration.specialize(specs);
resources.inputs.back().setDescriptorType(CAPABILITIES[capIdx].dtype);
features = get16BitStorageFeatures(CAPABILITIES[capIdx].name);
features.coreFeatures.vertexPipelineStoresAndAtomics = true;
features.coreFeatures.fragmentStoresAndAtomics = true;
createTestsForAllStages(name, defaultColors, defaultColors, fragments, resources, extensions, testGroup, features);
}
}
}
void addCompute16bitStorageUniform16To16Group (tcu::TestCaseGroup* group)
{
tcu::TestContext& testCtx = group->getTestContext();
de::Random rnd (deStringHash(group->getName()));
const int numElements = 128;
const vector<deFloat16> float16Data = getFloat16s(rnd, numElements);
const vector<deFloat16> float16DummyData (numElements, 0);
ComputeShaderSpec spec;
std::ostringstream shaderTemplate;
shaderTemplate<<"OpCapability Shader\n"
<< "OpCapability StorageUniformBufferBlock16\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"
<< "OpDecorate %f16arr ArrayStride 2\n"
<< "OpMemberDecorate %SSBO_IN 0 Coherent\n"
<< "OpMemberDecorate %SSBO_OUT 0 Coherent\n"
<< "OpMemberDecorate %SSBO_IN 0 Offset 0\n"
<< "OpMemberDecorate %SSBO_OUT 0 Offset 0\n"
<< "OpDecorate %SSBO_IN BufferBlock\n"
<< "OpDecorate %SSBO_OUT BufferBlock\n"
<< "OpDecorate %ssboIN DescriptorSet 0\n"
<< "OpDecorate %ssboOUT DescriptorSet 0\n"
<< "OpDecorate %ssboIN Binding 0\n"
<< "OpDecorate %ssboOUT Binding 1\n"
<< "\n"
<< "%bool = OpTypeBool\n"
<< "%void = OpTypeVoid\n"
<< "%voidf = OpTypeFunction %void\n"
<< "%u32 = OpTypeInt 32 0\n"
<< "%i32 = OpTypeInt 32 1\n"
<< "%uvec3 = OpTypeVector %u32 3\n"
<< "%uvec3ptr = OpTypePointer Input %uvec3\n"
<< "%f16 = OpTypeFloat 16\n"
<< "%f16ptr = OpTypePointer Uniform %f16\n"
<< "\n"
<< "%zero = OpConstant %i32 0\n"
<< "%c_size = OpConstant %i32 " << numElements << "\n"
<< "\n"
<< "%f16arr = OpTypeArray %f16 %c_size\n"
<< "%SSBO_IN = OpTypeStruct %f16arr\n"
<< "%SSBO_OUT = OpTypeStruct %f16arr\n"
<< "%up_SSBOIN = OpTypePointer Uniform %SSBO_IN\n"
<< "%up_SSBOOUT = OpTypePointer Uniform %SSBO_OUT\n"
<< "%ssboIN = OpVariable %up_SSBOIN Uniform\n"
<< "%ssboOUT = OpVariable %up_SSBOOUT Uniform\n"
<< "\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"
<< "%y = OpCompositeExtract %u32 %idval 1\n"
<< "\n"
<< "%inlocx = OpAccessChain %f16ptr %ssboIN %zero %x \n"
<< "%valx = OpLoad %f16 %inlocx\n"
<< "%outlocx = OpAccessChain %f16ptr %ssboOUT %zero %x \n"
<< " OpStore %outlocx %valx\n"
<< "%inlocy = OpAccessChain %f16ptr %ssboIN %zero %y \n"
<< "%valy = OpLoad %f16 %inlocy\n"
<< "%outlocy = OpAccessChain %f16ptr %ssboOUT %zero %y \n"
<< " OpStore %outlocy %valy\n"
<< "\n"
<< " OpReturn\n"
<< " OpFunctionEnd\n";
spec.assembly = shaderTemplate.str();
spec.numWorkGroups = IVec3(numElements, numElements, 1);
spec.verifyIO = computeCheckBuffersFloats;
spec.coherentMemory = true;
spec.inputs.push_back(Resource(BufferSp(new Float16Buffer(float16Data))));
spec.outputs.push_back(Resource(BufferSp(new Float16Buffer(float16DummyData))));
spec.extensions.push_back("VK_KHR_16bit_storage");
spec.requestedVulkanFeatures = get16BitStorageFeatures("uniform_buffer_block");
group->addChild(new SpvAsmComputeShaderCase(testCtx, "stress_test", "Granularity stress test", spec));
}
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"
"%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;
VerifyIOFunc 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;
unsigned inputStride;
};
const CompositeType cTypes[2][3] =
{
{ // BufferBlock
{"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 4\nOpDecorate %f16arr ArrayStride 2\n", numElements, 1},
{"vector", "v4f32", "v4f16", "OpDecorate %v4f32arr ArrayStride 16\nOpDecorate %v4f16arr ArrayStride 8\n", numElements / 4, 1},
{"matrix", "v4f32", "v4f16", "OpDecorate %m2v4f32arr ArrayStride 32\nOpDecorate %m2v4f16arr ArrayStride 16\n", numElements / 8, 1}
},
{ // Block
{"scalar", "f32", "f16", "OpDecorate %f32arr ArrayStride 16\nOpDecorate %f16arr ArrayStride 2\n", numElements, 4},
{"vector", "v4f32", "v4f16", "OpDecorate %v4f32arr ArrayStride 16\nOpDecorate %v4f16arr ArrayStride 8\n", numElements / 4, 1},
{"matrix", "v4f32", "v4f16", "OpDecorate %m2v4f32arr ArrayStride 32\nOpDecorate %m2v4f16arr ArrayStride 16\n", numElements / 8, 1}
}
};
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[capIdx]); ++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[capIdx][tyIdx].name + "_float_" + rndModes[rndModeIdx].name;
vector<float> float32Data = getFloat32s(rnd, numElements * cTypes[capIdx][tyIdx].inputStride);
specs["capability"] = CAPABILITIES[capIdx].cap;
specs["storage"] = CAPABILITIES[capIdx].decor;
specs["stride"] = cTypes[capIdx][tyIdx].stride;
specs["base32"] = cTypes[capIdx][tyIdx].base32;
specs["base16"] = cTypes[capIdx][tyIdx].base16;
specs["rounding"] = rndModes[rndModeIdx].decor;
specs["types"] = floatTypes;
specs["convert"] = "OpFConvert";
if (strcmp(cTypes[capIdx][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[capIdx][tyIdx].count, 1, 1);
spec.verifyIO = rndModes[rndModeIdx].func;
spec.inputs.push_back(Resource(BufferSp(new Float32Buffer(float32Data)), CAPABILITIES[capIdx].dtype));
// 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(Resource(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;
unsigned inputStride;
};
const CompositeType cTypes[2][4] =
{
{
{"scalar_sint", sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 4\nOpDecorate %i16arr ArrayStride 2\n", numElements, 1},
{"scalar_uint", uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 4\nOpDecorate %u16arr ArrayStride 2\n", numElements, 1},
{"vector_sint", sintTypes, "v2i32", "v2i16", "OpSConvert", "OpDecorate %v2i32arr ArrayStride 8\nOpDecorate %v2i16arr ArrayStride 4\n", numElements / 2, 2},
{"vector_uint", uintTypes, "v2u32", "v2u16", "OpUConvert", "OpDecorate %v2u32arr ArrayStride 8\nOpDecorate %v2u16arr ArrayStride 4\n", numElements / 2, 2}
},
{
{"scalar_sint", sintTypes, "i32", "i16", "OpSConvert", "OpDecorate %i32arr ArrayStride 16\nOpDecorate %i16arr ArrayStride 2\n", numElements, 4},
{"scalar_uint", uintTypes, "u32", "u16", "OpUConvert", "OpDecorate %u32arr ArrayStride 16\nOpDecorate %u16arr ArrayStride 2\n", numElements, 4},
{"vector_sint", sintTypes, "v2i32", "v2i16", "OpSConvert", "OpDecorate %v2i32arr ArrayStride 16\nOpDecorate %v2i16arr ArrayStride 4\n", numElements / 2, 4},
{"vector_uint", uintTypes, "v2u32", "v2u16", "OpUConvert", "OpDecorate %v2u32arr ArrayStride 16\nOpDecorate %v2u16arr ArrayStride 4\n", numElements / 2, 4}
}
};
for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
for (deUint32 tyIdx = 0; tyIdx < DE_LENGTH_OF_ARRAY(cTypes[capIdx]); ++tyIdx)
{
ComputeShaderSpec spec;
map<string, string> specs;
string testName = string(CAPABILITIES[capIdx].name) + "_" + cTypes[capIdx][tyIdx].name;
const deUint32 inputStride = cTypes[capIdx][tyIdx].inputStride;
const deUint32 count = cTypes[capIdx][tyIdx].count;
const deUint32 scalarsPerItem = numElements / count;
vector<deInt32> inputs = getInt32s(rnd, numElements * inputStride);
vector<deInt16> outputs;
outputs.reserve(numElements);
for (deUint32 numNdx = 0; numNdx < count; ++numNdx)
for (deUint32 scalarIdx = 0; scalarIdx < scalarsPerItem; scalarIdx++)
outputs.push_back(static_cast<deInt16>(0xffff & inputs[numNdx * inputStride + scalarIdx]));
specs["capability"] = CAPABILITIES[capIdx].cap;
specs["storage"] = CAPABILITIES[capIdx].decor;
specs["stride"] = cTypes[capIdx][tyIdx].stride;
specs["base32"] = cTypes[capIdx][tyIdx].base32;
specs["base16"] = cTypes[capIdx][tyIdx].base16;
specs["types"] = cTypes[capIdx][tyIdx].types;
specs["convert"] = cTypes[capIdx][tyIdx].opcode;
spec.assembly = shaderTemplate.specialize(specs);
spec.numWorkGroups = IVec3(cTypes[capIdx][tyIdx].count, 1, 1);
spec.inputs.push_back(Resource(BufferSp(new Int32Buffer(inputs)), CAPABILITIES[capIdx].dtype));
spec.outputs.push_back(Resource(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 addCompute16bitStorageUniform16StructTo32StructGroup (tcu::TestCaseGroup* group)
{
tcu::TestContext& testCtx = group->getTestContext();
de::Random rnd (deStringHash(group->getName()));
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"
"\n"
"${strideF16}"
"\n"
"${strideF32}"
"\n"
"OpMemberDecorate %SSBO_IN 0 Offset 0\n"
"OpMemberDecorate %SSBO_OUT 0 Offset 0\n"
"OpDecorate %SSBO_IN ${storage}\n"
"OpDecorate %SSBO_OUT BufferBlock\n"
"OpDecorate %ssboIN DescriptorSet 0\n"
"OpDecorate %ssboOUT DescriptorSet 0\n"
"OpDecorate %ssboIN Binding 0\n"
"OpDecorate %ssboOUT Binding 1\n"
"\n"
"%bool = OpTypeBool\n"
"%void = OpTypeVoid\n"
"%voidf = OpTypeFunction %void\n"
"%u32 = OpTypeInt 32 0\n"
"%uvec3 = OpTypeVector %u32 3\n"
"%uvec3ptr = OpTypePointer Input %uvec3\n"
"\n"
"%i32 = OpTypeInt 32 1\n"
"%v2i32 = OpTypeVector %i32 2\n"
"%v4i32 = OpTypeVector %i32 4\n"
"\n"
"%f32 = OpTypeFloat 32\n"
"%v2f32 = OpTypeVector %f32 2\n"
"%v3f32 = OpTypeVector %f32 3\n"
"%v4f32 = OpTypeVector %f32 4\n"
"${types}\n"
"\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_4 = OpConstant %i32 4\n"
"%c_i32_5 = OpConstant %i32 5\n"
"%c_i32_6 = OpConstant %i32 6\n"
"%c_i32_7 = OpConstant %i32 7\n"
"%c_i32_8 = OpConstant %i32 8\n"
"%c_i32_9 = OpConstant %i32 9\n"
"\n"
"%c_u32_1 = OpConstant %u32 1\n"
"%c_u32_3 = OpConstant %u32 3\n"
"%c_u32_7 = OpConstant %u32 7\n"
"%c_u32_11 = OpConstant %u32 11\n"
"\n"
"%f16arr3 = OpTypeArray %f16 %c_u32_3\n"
"%v2f16arr3 = OpTypeArray %v2f16 %c_u32_3\n"
"%v2f16arr11 = OpTypeArray %v2f16 %c_u32_11\n"
"%v3f16arr11 = OpTypeArray %v3f16 %c_u32_11\n"
"%v4f16arr3 = OpTypeArray %v4f16 %c_u32_3\n"
"%struct16 = OpTypeStruct %f16 %v2f16arr3\n"
"%struct16arr11 = OpTypeArray %struct16 %c_u32_11\n"
"%f16Struct = OpTypeStruct %f16 %v2f16 %v3f16 %v4f16 %f16arr3 %struct16arr11 %v2f16arr11 %f16 %v3f16arr11 %v4f16arr3\n"
"\n"
"%f32arr3 = OpTypeArray %f32 %c_u32_3\n"
"%v2f32arr3 = OpTypeArray %v2f32 %c_u32_3\n"
"%v2f32arr11 = OpTypeArray %v2f32 %c_u32_11\n"
"%v3f32arr11 = OpTypeArray %v3f32 %c_u32_11\n"
"%v4f32arr3 = OpTypeArray %v4f32 %c_u32_3\n"
"%struct32 = OpTypeStruct %f32 %v2f32arr3\n"
"%struct32arr11 = OpTypeArray %struct32 %c_u32_11\n"
"%f32Struct = OpTypeStruct %f32 %v2f32 %v3f32 %v4f32 %f32arr3 %struct32arr11 %v2f32arr11 %f32 %v3f32arr11 %v4f32arr3\n"
"\n"
"%f16StructArr7 = OpTypeArray %f16Struct %c_u32_7\n"
"%f32StructArr7 = OpTypeArray %f32Struct %c_u32_7\n"
"%SSBO_IN = OpTypeStruct %f16StructArr7\n"
"%SSBO_OUT = OpTypeStruct %f32StructArr7\n"
"%up_SSBOIN = OpTypePointer Uniform %SSBO_IN\n"
"%up_SSBOOUT = OpTypePointer Uniform %SSBO_OUT\n"
"%ssboIN = OpVariable %up_SSBOIN Uniform\n"
"%ssboOUT = OpVariable %up_SSBOOUT Uniform\n"
"\n"
"%id = OpVariable %uvec3ptr Input\n"
"%main = OpFunction %void None %voidf\n"
"%label = OpLabel\n"
"\n"
"%idval = OpLoad %uvec3 %id\n"
"%x = OpCompositeExtract %u32 %idval 0\n"
"%y = OpCompositeExtract %u32 %idval 1\n"
"\n"
"%f16src = OpAccessChain %f16ptr %ssboIN %zero %x %zero\n"
"%val_f16 = OpLoad %f16 %f16src\n"
"%val_f32 = OpFConvert %f32 %val_f16\n"
"%f32dst = OpAccessChain %f32ptr %ssboOUT %zero %x %zero\n"
"OpStore %f32dst %val_f32\n"
"\n"
"%v2f16src = OpAccessChain %v2f16ptr %ssboIN %zero %x %c_i32_1\n"
"%val_v2f16 = OpLoad %v2f16 %v2f16src\n"
"%val_v2f32 = OpFConvert %v2f32 %val_v2f16\n"
"%v2f32dst = OpAccessChain %v2f32ptr %ssboOUT %zero %x %c_i32_1\n"
"OpStore %v2f32dst %val_v2f32\n"
"\n"
"%v3f16src = OpAccessChain %v3f16ptr %ssboIN %zero %x %c_i32_2\n"
"%val_v3f16 = OpLoad %v3f16 %v3f16src\n"
"%val_v3f32 = OpFConvert %v3f32 %val_v3f16\n"
"%v3f32dst = OpAccessChain %v3f32ptr %ssboOUT %zero %x %c_i32_2\n"
"OpStore %v3f32dst %val_v3f32\n"
"\n"
"%v4f16src = OpAccessChain %v4f16ptr %ssboIN %zero %x %c_i32_3\n"
"%val_v4f16 = OpLoad %v4f16 %v4f16src\n"
"%val_v4f32 = OpFConvert %v4f32 %val_v4f16\n"
"%v4f32dst = OpAccessChain %v4f32ptr %ssboOUT %zero %x %c_i32_3\n"
"OpStore %v4f32dst %val_v4f32\n"
"\n"
//struct {f16, v2f16[3]}
"%Sf16src = OpAccessChain %f16ptr %ssboIN %zero %x %c_i32_5 %y %zero\n"
"%Sval_f16 = OpLoad %f16 %Sf16src\n"
"%Sval_f32 = OpFConvert %f32 %Sval_f16\n"
"%Sf32dst2 = OpAccessChain %f32ptr %ssboOUT %zero %x %c_i32_5 %y %zero\n"
"OpStore %Sf32dst2 %Sval_f32\n"
"\n"
"%Sv2f16src0 = OpAccessChain %v2f16ptr %ssboIN %zero %x %c_i32_5 %y %c_i32_1 %zero\n"
"%Sv2f16_0 = OpLoad %v2f16 %Sv2f16src0\n"
"%Sv2f32_0 = OpFConvert %v2f32 %Sv2f16_0\n"
"%Sv2f32dst_0 = OpAccessChain %v2f32ptr %ssboOUT %zero %x %c_i32_5 %y %c_i32_1 %zero\n"
"OpStore %Sv2f32dst_0 %Sv2f32_0\n"
"\n"
"%Sv2f16src1 = OpAccessChain %v2f16ptr %ssboIN %zero %x %c_i32_5 %y %c_i32_1 %c_i32_1\n"
"%Sv2f16_1 = OpLoad %v2f16 %Sv2f16src1\n"
"%Sv2f32_1 = OpFConvert %v2f32 %Sv2f16_1\n"
"%Sv2f32dst_1 = OpAccessChain %v2f32ptr %ssboOUT %zero %x %c_i32_5 %y %c_i32_1 %c_i32_1\n"
"OpStore %Sv2f32dst_1 %Sv2f32_1\n"
"\n"
"%Sv2f16src2 = OpAccessChain %v2f16ptr %ssboIN %zero %x %c_i32_5 %y %c_i32_1 %c_i32_2\n"
"%Sv2f16_2 = OpLoad %v2f16 %Sv2f16src2\n"
"%Sv2f32_2 = OpFConvert %v2f32 %Sv2f16_2\n"
"%Sv2f32dst_2 = OpAccessChain %v2f32ptr %ssboOUT %zero %x %c_i32_5 %y %c_i32_1 %c_i32_2\n"
"OpStore %Sv2f32dst_2 %Sv2f32_2\n"
"\n"
"%v2f16src2 = OpAccessChain %v2f16ptr %ssboIN %zero %x %c_i32_6 %y\n"
"%val2_v2f16 = OpLoad %v2f16 %v2f16src2\n"
"%val2_v2f32 = OpFConvert %v2f32 %val2_v2f16\n"
"%v2f32dst2 = OpAccessChain %v2f32ptr %ssboOUT %zero %x %c_i32_6 %y\n"
"OpStore %v2f32dst2 %val2_v2f32\n"
"\n"
"%f16src2 = OpAccessChain %f16ptr %ssboIN %zero %x %c_i32_7\n"
"%val2_f16 = OpLoad %f16 %f16src2\n"
"%val2_f32 = OpFConvert %f32 %val2_f16\n"
"%f32dst2 = OpAccessChain %f32ptr %ssboOUT %zero %x %c_i32_7\n"
"OpStore %f32dst2 %val2_f32\n"
"\n"
"%v3f16src2 = OpAccessChain %v3f16ptr %ssboIN %zero %x %c_i32_8 %y\n"
"%val2_v3f16 = OpLoad %v3f16 %v3f16src2\n"
"%val2_v3f32 = OpFConvert %v3f32 %val2_v3f16\n"
"%v3f32dst2 = OpAccessChain %v3f32ptr %ssboOUT %zero %x %c_i32_8 %y\n"
"OpStore %v3f32dst2 %val2_v3f32\n"
"\n"
//Array with 3 elements
"%LessThan3 = OpSLessThan %bool %y %c_i32_3\n"
"OpSelectionMerge %BlockIf None\n"
"OpBranchConditional %LessThan3 %LabelIf %BlockIf\n"
"%LabelIf = OpLabel\n"
" %f16src3 = OpAccessChain %f16ptr %ssboIN %zero %x %c_i32_4 %y\n"
" %val3_f16 = OpLoad %f16 %f16src3\n"
" %val3_f32 = OpFConvert %f32 %val3_f16\n"
" %f32dst3 = OpAccessChain %f32ptr %ssboOUT %zero %x %c_i32_4 %y\n"
" OpStore %f32dst3 %val3_f32\n"
"\n"
" %v4f16src2 = OpAccessChain %v4f16ptr %ssboIN %zero %x %c_i32_9 %y\n"
" %val2_v4f16 = OpLoad %v4f16 %v4f16src2\n"
" %val2_v4f32 = OpFConvert %v4f32 %val2_v4f16\n"
" %v4f32dst2 = OpAccessChain %v4f32ptr %ssboOUT %zero %x %c_i32_9 %y\n"
" OpStore %v4f32dst2 %val2_v4f32\n"
"OpBranch %BlockIf\n"
"%BlockIf = OpLabel\n"
" OpReturn\n"
" OpFunctionEnd\n");
{ // Floats
vector<float> float32Data (getStructSize(SHADERTEMPLATE_STRIDE32BIT_STD430), 0.0f);
for (deUint32 capIdx = 0; capIdx < DE_LENGTH_OF_ARRAY(CAPABILITIES); ++capIdx)
{
vector<deFloat16> float16DData = (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == CAPABILITIES[capIdx].dtype) ? data16bitStd430(rnd) : data16bitStd140(rnd);
ComputeShaderSpec spec;
map<string, string> specs;
string testName = string(CAPABILITIES[capIdx].name);
specs["capability"] = CAPABILITIES[capIdx].cap;
specs["storage"] = CAPABILITIES[capIdx].decor;
specs["strideF16"] = getStructShaderComponet((VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == CAPABILITIES[capIdx].dtype) ? SHADERTEMPLATE_STRIDE16BIT_STD430 : SHADERTEMPLATE_STRIDE16BIT_STD140);
specs["strideF32"] = getStructShaderComponet(SHADERTEMPLATE_STRIDE32BIT_STD430);
specs["types"] = getStructShaderComponet(SHADERTEMPLATE_TYPES);
spec.assembly = shaderTemplate.specialize(specs);
spec.