1#ifndef _VKTUNIFORMBLOCKCASE_HPP
2#define _VKTUNIFORMBLOCKCASE_HPP
3/*------------------------------------------------------------------------
4 * Vulkan Conformance Tests
5 * ------------------------
6 *
7 * Copyright (c) 2015 The Khronos Group Inc.
8 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Uniform block tests.
25 *//*--------------------------------------------------------------------*/
26
27#include "deSharedPtr.hpp"
28#include "vktTestCase.hpp"
29#include "tcuDefs.hpp"
30#include "gluShaderUtil.hpp"
31
32#include <map>
33
34namespace vkt
35{
36namespace ubo
37{
38
39// Uniform block details.
40
41enum UniformFlags
42{
43	PRECISION_LOW		= (1<<0),
44	PRECISION_MEDIUM	= (1<<1),
45	PRECISION_HIGH		= (1<<2),
46	PRECISION_MASK		= PRECISION_LOW|PRECISION_MEDIUM|PRECISION_HIGH,
47
48	LAYOUT_SHARED		= (1<<3),
49	LAYOUT_PACKED		= (1<<4),
50	LAYOUT_STD140		= (1<<5),
51	LAYOUT_ROW_MAJOR	= (1<<6),
52	LAYOUT_COLUMN_MAJOR	= (1<<7),	//!< \note Lack of both flags means column-major matrix.
53	LAYOUT_OFFSET		= (1<<8),
54	LAYOUT_MASK			= LAYOUT_SHARED|LAYOUT_PACKED|LAYOUT_STD140|LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR|LAYOUT_OFFSET,
55
56	DECLARE_VERTEX		= (1<<9),
57	DECLARE_FRAGMENT	= (1<<10),
58	DECLARE_BOTH		= DECLARE_VERTEX|DECLARE_FRAGMENT,
59
60	UNUSED_VERTEX		= (1<<11),	//!< Uniform or struct member is not read in vertex shader.
61	UNUSED_FRAGMENT		= (1<<12),	//!< Uniform or struct member is not read in fragment shader.
62	UNUSED_BOTH			= UNUSED_VERTEX|UNUSED_FRAGMENT
63};
64
65enum MatrixLoadFlags
66{
67	LOAD_FULL_MATRIX		= 0,
68	LOAD_MATRIX_COMPONENTS	= 1,
69};
70
71class StructType;
72
73class VarType
74{
75public:
76						VarType			(void);
77						VarType			(const VarType& other);
78						VarType			(glu::DataType basicType, deUint32 flags);
79						VarType			(const VarType& elementType, int arraySize);
80	explicit			VarType			(const StructType* structPtr, deUint32 flags = 0u);
81						~VarType		(void);
82
83	bool				isBasicType		(void) const	{ return m_type == TYPE_BASIC;	}
84	bool				isArrayType		(void) const	{ return m_type == TYPE_ARRAY;	}
85	bool				isStructType	(void) const	{ return m_type == TYPE_STRUCT;	}
86
87	deUint32			getFlags		(void) const	{ return m_flags;					}
88	glu::DataType		getBasicType	(void) const	{ return m_data.basicType;			}
89
90	const VarType&		getElementType	(void) const	{ return *m_data.array.elementType;	}
91	int					getArraySize	(void) const	{ return m_data.array.size;			}
92
93	const StructType&	getStruct		(void) const	{ return *m_data.structPtr;			}
94
95	VarType&			operator=		(const VarType& other);
96
97private:
98	enum Type
99	{
100		TYPE_BASIC,
101		TYPE_ARRAY,
102		TYPE_STRUCT,
103
104		TYPE_LAST
105	};
106
107	Type				m_type;
108	deUint32			m_flags;
109	union Data
110	{
111		glu::DataType		basicType;
112		struct
113		{
114			VarType*		elementType;
115			int				size;
116		} array;
117		const StructType*	structPtr;
118
119		Data (void)
120		{
121			array.elementType	= DE_NULL;
122			array.size			= 0;
123		};
124	} m_data;
125};
126
127class StructMember
128{
129public:
130						StructMember	(const std::string& name, const VarType& type, deUint32 flags)
131							: m_name(name), m_type(type), m_flags(flags)
132						{}
133						StructMember	(void)
134							: m_flags(0)
135						{}
136
137	const std::string&	getName			(void) const { return m_name;	}
138	const VarType&		getType			(void) const { return m_type;	}
139	deUint32			getFlags		(void) const { return m_flags;	}
140
141private:
142	std::string			m_name;
143	VarType				m_type;
144	deUint32			m_flags;
145};
146
147class StructType
148{
149public:
150	typedef std::vector<StructMember>::iterator			Iterator;
151	typedef std::vector<StructMember>::const_iterator	ConstIterator;
152
153								StructType		(const std::string& typeName) : m_typeName(typeName) {}
154								~StructType		(void) {}
155
156	const std::string&			getTypeName		(void) const	{ return m_typeName;			}
157	bool						hasTypeName		(void) const	{ return !m_typeName.empty();	}
158
159	inline Iterator				begin			(void)			{ return m_members.begin();		}
160	inline ConstIterator		begin			(void) const	{ return m_members.begin();		}
161	inline Iterator				end				(void)			{ return m_members.end();		}
162	inline ConstIterator		end				(void) const	{ return m_members.end();		}
163
164	void						addMember		(const std::string& name, const VarType& type, deUint32 flags = 0);
165
166private:
167	std::string					m_typeName;
168	std::vector<StructMember>	m_members;
169};
170
171class Uniform
172{
173public:
174						Uniform			(const std::string& name, const VarType& type, deUint32 flags = 0);
175
176	const std::string&	getName			(void) const { return m_name;	}
177	const VarType&		getType			(void) const { return m_type;	}
178	deUint32			getFlags		(void) const { return m_flags;	}
179
180private:
181	std::string			m_name;
182	VarType				m_type;
183	deUint32			m_flags;
184};
185
186class UniformBlock
187{
188public:
189	typedef std::vector<Uniform>::iterator			Iterator;
190	typedef std::vector<Uniform>::const_iterator	ConstIterator;
191
192							UniformBlock		(const std::string& blockName);
193
194	const std::string&		getBlockName		(void) const { return m_blockName;		}
195	const std::string&		getInstanceName		(void) const { return m_instanceName;	}
196	bool					hasInstanceName		(void) const { return !m_instanceName.empty();	}
197	bool					isArray				(void) const { return m_arraySize > 0;			}
198	int						getArraySize		(void) const { return m_arraySize;				}
199	deUint32				getFlags			(void) const { return m_flags;					}
200
201	void					setInstanceName		(const std::string& name)	{ m_instanceName = name;			}
202	void					setFlags			(deUint32 flags)			{ m_flags = flags;					}
203	void					setArraySize		(int arraySize)				{ m_arraySize = arraySize;			}
204	void					addUniform			(const Uniform& uniform)	{ m_uniforms.push_back(uniform);	}
205
206	inline Iterator			begin				(void)			{ return m_uniforms.begin();	}
207	inline ConstIterator	begin				(void) const	{ return m_uniforms.begin();	}
208	inline Iterator			end					(void)			{ return m_uniforms.end();		}
209	inline ConstIterator	end					(void) const	{ return m_uniforms.end();		}
210
211private:
212	std::string				m_blockName;
213	std::string				m_instanceName;
214	std::vector<Uniform>	m_uniforms;
215	int						m_arraySize;	//!< Array size or 0 if not interface block array.
216	deUint32				m_flags;
217};
218
219typedef de::SharedPtr<StructType>	StructTypeSP;
220typedef de::SharedPtr<UniformBlock>	UniformBlockSP;
221
222class ShaderInterface
223{
224public:
225								ShaderInterface			(void);
226								~ShaderInterface		(void);
227
228	StructType&					allocStruct				(const std::string& name);
229	void						getNamedStructs			(std::vector<const StructType*>& structs) const;
230
231	UniformBlock&				allocBlock				(const std::string& name);
232
233	int							getNumUniformBlocks		(void) const	{ return (int)m_uniformBlocks.size();	}
234	const UniformBlock&			getUniformBlock			(int ndx) const	{ return *m_uniformBlocks[ndx];			}
235
236private:
237	std::vector<StructTypeSP>		m_structs;
238	std::vector<UniformBlockSP>		m_uniformBlocks;
239};
240
241struct BlockLayoutEntry
242{
243	BlockLayoutEntry (void)
244		: size					(0)
245		, blockDeclarationNdx	(-1)
246		, bindingNdx			(-1)
247		, instanceNdx			(-1)
248	{
249	}
250
251	std::string			name;
252	int					size;
253	std::vector<int>	activeUniformIndices;
254	int					blockDeclarationNdx;
255	int					bindingNdx;
256	int					instanceNdx;
257};
258
259struct UniformLayoutEntry
260{
261	UniformLayoutEntry (void)
262		: type			(glu::TYPE_LAST)
263		, size			(0)
264		, blockLayoutNdx(-1)
265		, offset		(-1)
266		, arrayStride	(-1)
267		, matrixStride	(-1)
268		, isRowMajor	(false)
269		, instanceNdx	(0)
270	{
271	}
272
273	std::string			name;
274	glu::DataType		type;
275	int					size;
276	int					blockLayoutNdx;
277	int					offset;
278	int					arrayStride;
279	int					matrixStride;
280	bool				isRowMajor;
281	int					instanceNdx;
282};
283
284class UniformLayout
285{
286public:
287	std::vector<BlockLayoutEntry>		blocks;
288	std::vector<UniformLayoutEntry>		uniforms;
289
290	int									getUniformLayoutIndex	(int blockDeclarationNdx, const std::string& name) const;
291	int									getBlockLayoutIndex		(int blockDeclarationNdx, int instanceNdx) const;
292};
293
294class UniformBlockCase : public vkt::TestCase
295{
296public:
297	enum BufferMode
298	{
299		BUFFERMODE_SINGLE = 0,	//!< Single buffer shared between uniform blocks.
300		BUFFERMODE_PER_BLOCK,	//!< Per-block buffers
301
302		BUFFERMODE_LAST
303	};
304
305								UniformBlockCase			(tcu::TestContext&	testCtx,
306															 const std::string&	name,
307															 const std::string&	description,
308															 BufferMode			bufferMode,
309															 MatrixLoadFlags	matrixLoadFlag,
310															 bool				shuffleUniformMembers = false);
311								~UniformBlockCase			(void);
312
313	virtual	void				initPrograms				(vk::SourceCollections& programCollection) const;
314	virtual TestInstance*		createInstance				(Context& context) const;
315
316protected:
317	void						init						(void);
318
319	BufferMode					m_bufferMode;
320	ShaderInterface				m_interface;
321	MatrixLoadFlags				m_matrixLoadFlag;
322	const bool					m_shuffleUniformMembers;	//!< Used with explicit offsets to test out of order member offsets
323
324private:
325	std::string					m_vertShaderSource;
326	std::string					m_fragShaderSource;
327
328	std::vector<deUint8>		m_data;						//!< Data.
329	std::map<int, void*>		m_blockPointers;			//!< Reference block pointers.
330	UniformLayout				m_uniformLayout;			//!< std140 layout.
331};
332
333} // ubo
334} // vkt
335
336#endif // _VKTUNIFORMBLOCKCASE_HPP
337