1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Random uniform block layout case.
24 *//*--------------------------------------------------------------------*/
25
26#include "vktRandomUniformBlockCase.hpp"
27#include "deRandom.hpp"
28
29namespace vkt
30{
31namespace ubo
32{
33
34namespace
35{
36
37static std::string genName (char first, char last, int ndx)
38{
39	std::string	str			= "";
40	int			alphabetLen	= last - first + 1;
41
42	while (ndx > alphabetLen)
43	{
44		str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
45		ndx = (ndx - 1) / alphabetLen;
46	}
47
48	str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
49
50	return str;
51}
52
53} // anonymous
54
55RandomUniformBlockCase::RandomUniformBlockCase (tcu::TestContext&	testCtx,
56												const std::string&	name,
57												const std::string&	description,
58												BufferMode			bufferMode,
59												deUint32			features,
60												deUint32			seed)
61	: UniformBlockCase		(testCtx, name, description, bufferMode, LOAD_FULL_MATRIX, (features & FEATURE_OUT_OF_ORDER_OFFSETS) != 0u)
62	, m_features			(features)
63	, m_maxVertexBlocks		((features & FEATURE_VERTEX_BLOCKS)		? 4 : 0)
64	, m_maxFragmentBlocks	((features & FEATURE_FRAGMENT_BLOCKS)	? 4 : 0)
65	, m_maxSharedBlocks		((features & FEATURE_SHARED_BLOCKS)		? 4 : 0)
66	, m_maxInstances		((features & FEATURE_INSTANCE_ARRAYS)	? 3 : 0)
67	, m_maxArrayLength		((features & FEATURE_ARRAYS)			? 8 : 0)
68	, m_maxStructDepth		((features & FEATURE_STRUCTS)			? 2 : 0)
69	, m_maxBlockMembers		(5)
70	, m_maxStructMembers	(4)
71	, m_seed				(seed)
72	, m_blockNdx			(1)
73	, m_uniformNdx			(1)
74	, m_structNdx			(1)
75{
76	de::Random rnd(m_seed);
77
78	int numShared		= m_maxSharedBlocks				> 0	? rnd.getInt(1, m_maxSharedBlocks)				: 0;
79	int numVtxBlocks	= m_maxVertexBlocks-numShared	> 0	? rnd.getInt(1, m_maxVertexBlocks - numShared)	: 0;
80	int	numFragBlocks	= m_maxFragmentBlocks-numShared	> 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared): 0;
81
82	for (int ndx = 0; ndx < numShared; ndx++)
83		generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT);
84
85	for (int ndx = 0; ndx < numVtxBlocks; ndx++)
86		generateBlock(rnd, DECLARE_VERTEX);
87
88	for (int ndx = 0; ndx < numFragBlocks; ndx++)
89		generateBlock(rnd, DECLARE_FRAGMENT);
90
91	init();
92}
93
94void RandomUniformBlockCase::generateBlock (de::Random& rnd, deUint32 layoutFlags)
95{
96	DE_ASSERT(m_blockNdx <= 'z' - 'a');
97
98	const float		instanceArrayWeight	= 0.3f;
99	UniformBlock&	block				= m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx));
100	int				numInstances		= (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
101	int				numUniforms			= rnd.getInt(1, m_maxBlockMembers);
102
103	if (numInstances > 0)
104		block.setArraySize(numInstances);
105
106	if (numInstances > 0 || rnd.getBool())
107		block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx));
108
109	// Layout flag candidates.
110	std::vector<deUint32> layoutFlagCandidates;
111	layoutFlagCandidates.push_back(0);
112
113	if (m_features & FEATURE_STD140_LAYOUT)
114		layoutFlagCandidates.push_back(LAYOUT_STD140);
115
116	layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
117
118	if (m_features & FEATURE_MATRIX_LAYOUT)
119	{
120		static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR };
121		layoutFlags |= rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
122	}
123
124	block.setFlags(layoutFlags);
125
126	for (int ndx = 0; ndx < numUniforms; ndx++)
127		generateUniform(rnd, block);
128
129	m_blockNdx += 1;
130}
131
132void RandomUniformBlockCase::generateUniform (de::Random& rnd, UniformBlock& block)
133{
134	const float		unusedVtxWeight		= 0.15f;
135	const float		unusedFragWeight	= 0.15f;
136	bool			unusedOk			= (m_features & FEATURE_UNUSED_UNIFORMS) != 0;
137	deUint32		flags				= 0;
138	std::string		name				= genName('a', 'z', m_uniformNdx);
139	VarType			type				= generateType(rnd, 0, true);
140
141	flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight)		? UNUSED_VERTEX		: 0;
142	flags |= (unusedOk && rnd.getFloat() < unusedFragWeight)	? UNUSED_FRAGMENT	: 0;
143
144	block.addUniform(Uniform(name, type, flags));
145
146	m_uniformNdx += 1;
147}
148
149VarType RandomUniformBlockCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk)
150{
151	const float structWeight	= 0.1f;
152	const float arrayWeight		= 0.1f;
153
154	if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
155	{
156		const float				unusedVtxWeight		= 0.15f;
157		const float				unusedFragWeight	= 0.15f;
158		bool					unusedOk			= (m_features & FEATURE_UNUSED_MEMBERS) != 0;
159		std::vector<VarType>	memberTypes;
160		int						numMembers = rnd.getInt(1, m_maxStructMembers);
161
162		// Generate members first so nested struct declarations are in correct order.
163		for (int ndx = 0; ndx < numMembers; ndx++)
164			memberTypes.push_back(generateType(rnd, typeDepth+1, true));
165
166		StructType& structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx));
167		m_structNdx += 1;
168
169		DE_ASSERT(numMembers <= 'Z' - 'A');
170		for (int ndx = 0; ndx < numMembers; ndx++)
171		{
172			deUint32 flags = 0;
173
174			flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight)		? UNUSED_VERTEX		: 0;
175			flags |= (unusedOk && rnd.getFloat() < unusedFragWeight)	? UNUSED_FRAGMENT	: 0;
176
177			structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags);
178		}
179
180		return VarType(&structType, m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u);
181	}
182	else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
183	{
184		const bool	arraysOfArraysOk	= (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
185		const int	arrayLength			= rnd.getInt(1, m_maxArrayLength);
186		VarType		elementType			= generateType(rnd, typeDepth, arraysOfArraysOk);
187		return VarType(elementType, arrayLength);
188	}
189	else
190	{
191		std::vector<glu::DataType> typeCandidates;
192
193		typeCandidates.push_back(glu::TYPE_FLOAT);
194		typeCandidates.push_back(glu::TYPE_INT);
195		typeCandidates.push_back(glu::TYPE_UINT);
196		typeCandidates.push_back(glu::TYPE_BOOL);
197
198		if (m_features & FEATURE_VECTORS)
199		{
200			typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
201			typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
202			typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
203			typeCandidates.push_back(glu::TYPE_INT_VEC2);
204			typeCandidates.push_back(glu::TYPE_INT_VEC3);
205			typeCandidates.push_back(glu::TYPE_INT_VEC4);
206			typeCandidates.push_back(glu::TYPE_UINT_VEC2);
207			typeCandidates.push_back(glu::TYPE_UINT_VEC3);
208			typeCandidates.push_back(glu::TYPE_UINT_VEC4);
209			typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
210			typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
211			typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
212		}
213
214		if (m_features & FEATURE_MATRICES)
215		{
216			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
217			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
218			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
219			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
220			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
221			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
222			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
223			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
224		}
225
226		glu::DataType	type	= rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
227		deUint32		flags	= (m_shuffleUniformMembers ? static_cast<deUint32>(LAYOUT_OFFSET) : 0u);
228
229		if (!glu::isDataTypeBoolOrBVec(type))
230		{
231			// Precision.
232			static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH };
233			flags |= rnd.choose<deUint32>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
234		}
235
236		return VarType(type, flags);
237	}
238}
239
240} // ubo
241} // vkt
242