blob: d4b080b2ee7b498180a1041ef2f8c0f1048e7666 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Copyright (c) 2016 The Android Open Source Project
*
* 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 Random uniform block layout case.
*//*--------------------------------------------------------------------*/
#include "vktRandomUniformBlockCase.hpp"
#include "deRandom.hpp"
namespace vkt
{
namespace ubo
{
namespace
{
static std::string genName (char first, char last, int ndx)
{
std::string str = "";
int alphabetLen = last - first + 1;
while (ndx > alphabetLen)
{
str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
ndx = (ndx - 1) / alphabetLen;
}
str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
return str;
}
} // anonymous
RandomUniformBlockCase::RandomUniformBlockCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
BufferMode bufferMode,
deUint32 features,
deUint32 seed)
: UniformBlockCase (testCtx, name, description, bufferMode, LOAD_FULL_MATRIX, (features & FEATURE_OUT_OF_ORDER_OFFSETS) != 0u)
, m_features (features)
, m_maxVertexBlocks ((features & FEATURE_VERTEX_BLOCKS) ? 4 : 0)
, m_maxFragmentBlocks ((features & FEATURE_FRAGMENT_BLOCKS) ? 4 : 0)
, m_maxSharedBlocks ((features & FEATURE_SHARED_BLOCKS) ? 4 : 0)
, m_maxInstances ((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0)
, m_maxArrayLength ((features & FEATURE_ARRAYS) ? 8 : 0)
, m_maxStructDepth ((features & FEATURE_STRUCTS) ? 2 : 0)
, m_maxBlockMembers (5)
, m_maxStructMembers (4)
, m_seed (seed)
, m_blockNdx (1)
, m_uniformNdx (1)
, m_structNdx (1)
, m_availableDescriptorUniformBuffers (12)
{
de::Random rnd(m_seed);
int numShared = m_maxSharedBlocks > 0 ? rnd.getInt(1, m_maxSharedBlocks) : 0;
int numVtxBlocks = m_maxVertexBlocks-numShared > 0 ? rnd.getInt(1, m_maxVertexBlocks - numShared) : 0;
int numFragBlocks = m_maxFragmentBlocks-numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared): 0;
// calculate how many additional descriptors we can use for arrays
// this is needed for descriptor_indexing testing as we need to take in to account
// maxPerStageDescriptorUniformBuffers limit and we can't query it as we need to
// generate shaders before Context is created; minimal value of this limit is 12
m_availableDescriptorUniformBuffers -= numVtxBlocks + numFragBlocks;
for (int ndx = 0; ndx < numShared; ndx++)
generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT);
for (int ndx = 0; ndx < numVtxBlocks; ndx++)
generateBlock(rnd, DECLARE_VERTEX);
for (int ndx = 0; ndx < numFragBlocks; ndx++)
generateBlock(rnd, DECLARE_FRAGMENT);
init();
}
void RandomUniformBlockCase::generateBlock (de::Random& rnd, deUint32 layoutFlags)
{
DE_ASSERT(m_blockNdx <= 'z' - 'a');
const float instanceArrayWeight = 0.3f;
UniformBlock& block = m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx));
int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
int numUniforms = rnd.getInt(1, m_maxBlockMembers);
if (m_features & FEATURE_DESCRIPTOR_INDEXING)
{
// generate arrays only when we are within the limit
if (m_availableDescriptorUniformBuffers > 3)
numInstances = rnd.getInt(2, 4);
else if (m_availableDescriptorUniformBuffers > 1)
numInstances = m_availableDescriptorUniformBuffers;
else
numInstances = 0;
m_availableDescriptorUniformBuffers -= numInstances;
}
if (numInstances > 0)
block.setArraySize(numInstances);
if (numInstances > 0 || rnd.getBool())
block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx));
// Layout flag candidates.
std::vector<deUint32> layoutFlagCandidates;
layoutFlagCandidates.push_back(0);
if (m_features & FEATURE_STD140_LAYOUT)
layoutFlagCandidates.push_back(LAYOUT_STD140);
if (m_features & FEATURE_STD430_LAYOUT)
layoutFlagCandidates.push_back(LAYOUT_STD430);
if (m_features & FEATURE_SCALAR_LAYOUT)
layoutFlagCandidates.push_back(LAYOUT_SCALAR);
if (m_features & FEATURE_16BIT_STORAGE)
layoutFlags |= LAYOUT_16BIT_STORAGE;
if (m_features & FEATURE_8BIT_STORAGE)
layoutFlags |= LAYOUT_8BIT_STORAGE;
if (m_features & FEATURE_DESCRIPTOR_INDEXING)
layoutFlags |= LAYOUT_DESCRIPTOR_INDEXING;
layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
if (m_features & FEATURE_MATRIX_LAYOUT)
{
static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR };
layoutFlags |= rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
}
block.setFlags(layoutFlags);
for (int ndx = 0; ndx < numUniforms; ndx++)
generateUniform(rnd, block);
m_blockNdx += 1;
}
void RandomUniformBlockCase::generateUniform (de::Random& rnd, UniformBlock& block)
{
const float unusedVtxWeight = 0.15f;
const float unusedFragWeight = 0.15f;
bool unusedOk = (m_features & FEATURE_UNUSED_UNIFORMS) != 0;
deUint32 flags = 0;
std::string name = genName('a', 'z', m_uniformNdx);
VarType type = generateType(rnd, 0, true);
flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
block.addUniform(Uniform(name, type, flags));
m_uniformNdx += 1;
}
VarType RandomUniformBlockCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk)
{
const float structWeight = 0.1f;
const float arrayWeight = 0.1f;
if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
{
const float unusedVtxWeight = 0.15f;
const float unusedFragWeight = 0.15f;
bool unusedOk = (m_features & FEATURE_UNUSED_MEMBERS) != 0;
std::vector<VarType> memberTypes;
int numMembers = rnd.getInt(1, m_maxStructMembers);
// Generate members first so nested struct declarations are in correct order.
for (int ndx = 0; ndx < numMembers; ndx++)
memberTypes.push_back(generateType(rnd, typeDepth+1, true));
StructType& structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx));
m_structNdx += 1;
DE_ASSERT(numMembers <= 'Z' - 'A');
for (int ndx = 0; ndx < numMembers; ndx++)
{
deUint32 flags = 0;
flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags);
}
return VarType(&structType, m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u);
}
else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
{
const bool arraysOfArraysOk = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
const int arrayLength = rnd.getInt(1, m_maxArrayLength);
VarType elementType = generateType(rnd, typeDepth, arraysOfArraysOk);
return VarType(elementType, arrayLength);
}
else
{
std::vector<glu::DataType> typeCandidates;
typeCandidates.push_back(glu::TYPE_FLOAT);
typeCandidates.push_back(glu::TYPE_INT);
typeCandidates.push_back(glu::TYPE_UINT);
typeCandidates.push_back(glu::TYPE_BOOL);
if (m_features & FEATURE_16BIT_STORAGE) {
typeCandidates.push_back(glu::TYPE_UINT16);
typeCandidates.push_back(glu::TYPE_INT16);
typeCandidates.push_back(glu::TYPE_FLOAT16);
}
if (m_features & FEATURE_8BIT_STORAGE) {
typeCandidates.push_back(glu::TYPE_UINT8);
typeCandidates.push_back(glu::TYPE_INT8);
}
if (m_features & FEATURE_VECTORS)
{
typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
typeCandidates.push_back(glu::TYPE_INT_VEC2);
typeCandidates.push_back(glu::TYPE_INT_VEC3);
typeCandidates.push_back(glu::TYPE_INT_VEC4);
typeCandidates.push_back(glu::TYPE_UINT_VEC2);
typeCandidates.push_back(glu::TYPE_UINT_VEC3);
typeCandidates.push_back(glu::TYPE_UINT_VEC4);
typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
if (m_features & FEATURE_16BIT_STORAGE)
{
typeCandidates.push_back(glu::TYPE_FLOAT16_VEC2);
typeCandidates.push_back(glu::TYPE_FLOAT16_VEC3);
typeCandidates.push_back(glu::TYPE_FLOAT16_VEC4);
typeCandidates.push_back(glu::TYPE_INT16_VEC2);
typeCandidates.push_back(glu::TYPE_INT16_VEC3);
typeCandidates.push_back(glu::TYPE_INT16_VEC4);
typeCandidates.push_back(glu::TYPE_UINT16_VEC2);
typeCandidates.push_back(glu::TYPE_UINT16_VEC3);
typeCandidates.push_back(glu::TYPE_UINT16_VEC4);
}
if (m_features & FEATURE_8BIT_STORAGE)
{
typeCandidates.push_back(glu::TYPE_INT8_VEC2);
typeCandidates.push_back(glu::TYPE_INT8_VEC3);
typeCandidates.push_back(glu::TYPE_INT8_VEC4);
typeCandidates.push_back(glu::TYPE_UINT8_VEC2);
typeCandidates.push_back(glu::TYPE_UINT8_VEC3);
typeCandidates.push_back(glu::TYPE_UINT8_VEC4);
}
}
if (m_features & FEATURE_MATRICES)
{
typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
}
glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
deUint32 flags = (m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u);
if (glu::dataTypeSupportsPrecisionModifier(type))
{
// Precision.
static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH };
flags |= rnd.choose<deUint32>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
}
return VarType(type, flags);
}
}
} // ubo
} // vkt