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 
34 namespace vkt
35 {
36 namespace ubo
37 {
38 
39 // Uniform block details.
40 
41 enum 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_STD430		= (1<<9),
55 	LAYOUT_SCALAR		= (1<<10),
56 	LAYOUT_MASK			= LAYOUT_SHARED|LAYOUT_PACKED|LAYOUT_STD140|LAYOUT_STD430|LAYOUT_SCALAR|LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR|LAYOUT_OFFSET,
57 
58 	DECLARE_VERTEX		= (1<<11),
59 	DECLARE_FRAGMENT	= (1<<12),
60 	DECLARE_BOTH		= DECLARE_VERTEX|DECLARE_FRAGMENT,
61 
62 	UNUSED_VERTEX		= (1<<13),	//!< Uniform or struct member is not read in vertex shader.
63 	UNUSED_FRAGMENT		= (1<<14),	//!< Uniform or struct member is not read in fragment shader.
64 	UNUSED_BOTH			= UNUSED_VERTEX|UNUSED_FRAGMENT,
65 
66 	LAYOUT_16BIT_STORAGE= (1<<15),  //!< Support VK_KHR_16bit_storage extension
67 	LAYOUT_8BIT_STORAGE	= (1<<16),  //!< Support VK_KHR_8bit_storage extension
68 };
69 
70 enum MatrixLoadFlags
71 {
72 	LOAD_FULL_MATRIX		= 0,
73 	LOAD_MATRIX_COMPONENTS	= 1,
74 };
75 
76 class StructType;
77 
78 class VarType
79 {
80 public:
81 						VarType			(void);
82 						VarType			(const VarType& other);
83 						VarType			(glu::DataType basicType, deUint32 flags);
84 						VarType			(const VarType& elementType, int arraySize);
85 	explicit			VarType			(const StructType* structPtr, deUint32 flags = 0u);
86 						~VarType		(void);
87 
isBasicType(void) const88 	bool				isBasicType		(void) const	{ return m_type == TYPE_BASIC;	}
isArrayType(void) const89 	bool				isArrayType		(void) const	{ return m_type == TYPE_ARRAY;	}
isStructType(void) const90 	bool				isStructType	(void) const	{ return m_type == TYPE_STRUCT;	}
91 
getFlags(void) const92 	deUint32			getFlags		(void) const	{ return m_flags;					}
getBasicType(void) const93 	glu::DataType		getBasicType	(void) const	{ return m_data.basicType;			}
94 
getElementType(void) const95 	const VarType&		getElementType	(void) const	{ return *m_data.array.elementType;	}
getArraySize(void) const96 	int					getArraySize	(void) const	{ return m_data.array.size;			}
97 
getStruct(void) const98 	const StructType&	getStruct		(void) const	{ return *m_data.structPtr;			}
getStructPtr(void) const99 	const StructType*	getStructPtr	(void) const	{ DE_ASSERT(isStructType()); return m_data.structPtr;			}
100 
101 	VarType&			operator=		(const VarType& other);
102 
103 private:
104 	enum Type
105 	{
106 		TYPE_BASIC,
107 		TYPE_ARRAY,
108 		TYPE_STRUCT,
109 
110 		TYPE_LAST
111 	};
112 
113 	Type				m_type;
114 	deUint32			m_flags;
115 	union Data
116 	{
117 		glu::DataType		basicType;
118 		struct
119 		{
120 			VarType*		elementType;
121 			int				size;
122 		} array;
123 		const StructType*	structPtr;
124 
Data(void)125 		Data (void)
126 		{
127 			array.elementType	= DE_NULL;
128 			array.size			= 0;
129 		};
130 	} m_data;
131 };
132 
133 class StructMember
134 {
135 public:
StructMember(const std::string & name,const VarType & type,deUint32 flags)136 						StructMember	(const std::string& name, const VarType& type, deUint32 flags)
137 							: m_name(name), m_type(type), m_flags(flags)
138 						{}
StructMember(void)139 						StructMember	(void)
140 							: m_flags(0)
141 						{}
142 
getName(void) const143 	const std::string&	getName			(void) const { return m_name;	}
getType(void) const144 	const VarType&		getType			(void) const { return m_type;	}
getFlags(void) const145 	deUint32			getFlags		(void) const { return m_flags;	}
146 
147 private:
148 	std::string			m_name;
149 	VarType				m_type;
150 	deUint32			m_flags;
151 };
152 
153 class StructType
154 {
155 public:
156 	typedef std::vector<StructMember>::iterator			Iterator;
157 	typedef std::vector<StructMember>::const_iterator	ConstIterator;
158 
StructType(const std::string & typeName)159 								StructType		(const std::string& typeName) : m_typeName(typeName) {}
~StructType(void)160 								~StructType		(void) {}
161 
getTypeName(void) const162 	const std::string&			getTypeName		(void) const	{ return m_typeName;			}
hasTypeName(void) const163 	bool						hasTypeName		(void) const	{ return !m_typeName.empty();	}
164 
begin(void)165 	inline Iterator				begin			(void)			{ return m_members.begin();		}
begin(void) const166 	inline ConstIterator		begin			(void) const	{ return m_members.begin();		}
end(void)167 	inline Iterator				end				(void)			{ return m_members.end();		}
end(void) const168 	inline ConstIterator		end				(void) const	{ return m_members.end();		}
169 
170 	void						addMember		(const std::string& name, const VarType& type, deUint32 flags = 0);
171 
172 private:
173 	std::string					m_typeName;
174 	std::vector<StructMember>	m_members;
175 };
176 
177 class Uniform
178 {
179 public:
180 						Uniform			(const std::string& name, const VarType& type, deUint32 flags = 0);
181 
getName(void) const182 	const std::string&	getName			(void) const { return m_name;	}
getType(void) const183 	const VarType&		getType			(void) const { return m_type;	}
getFlags(void) const184 	deUint32			getFlags		(void) const { return m_flags;	}
185 
186 private:
187 	std::string			m_name;
188 	VarType				m_type;
189 	deUint32			m_flags;
190 };
191 
192 class UniformBlock
193 {
194 public:
195 	typedef std::vector<Uniform>::iterator			Iterator;
196 	typedef std::vector<Uniform>::const_iterator	ConstIterator;
197 
198 							UniformBlock		(const std::string& blockName);
199 
getBlockName(void) const200 	const std::string&		getBlockName		(void) const { return m_blockName;		}
getInstanceName(void) const201 	const std::string&		getInstanceName		(void) const { return m_instanceName;	}
hasInstanceName(void) const202 	bool					hasInstanceName		(void) const { return !m_instanceName.empty();	}
isArray(void) const203 	bool					isArray				(void) const { return m_arraySize > 0;			}
getArraySize(void) const204 	int						getArraySize		(void) const { return m_arraySize;				}
getFlags(void) const205 	deUint32				getFlags			(void) const { return m_flags;					}
206 
setInstanceName(const std::string & name)207 	void					setInstanceName		(const std::string& name)	{ m_instanceName = name;			}
setFlags(deUint32 flags)208 	void					setFlags			(deUint32 flags)			{ m_flags = flags;					}
setArraySize(int arraySize)209 	void					setArraySize		(int arraySize)				{ m_arraySize = arraySize;			}
addUniform(const Uniform & uniform)210 	void					addUniform			(const Uniform& uniform)	{ m_uniforms.push_back(uniform);	}
211 
begin(void)212 	inline Iterator			begin				(void)			{ return m_uniforms.begin();	}
begin(void) const213 	inline ConstIterator	begin				(void) const	{ return m_uniforms.begin();	}
end(void)214 	inline Iterator			end					(void)			{ return m_uniforms.end();		}
end(void) const215 	inline ConstIterator	end					(void) const	{ return m_uniforms.end();		}
216 
217 private:
218 	std::string				m_blockName;
219 	std::string				m_instanceName;
220 	std::vector<Uniform>	m_uniforms;
221 	int						m_arraySize;	//!< Array size or 0 if not interface block array.
222 	deUint32				m_flags;
223 };
224 
225 typedef de::SharedPtr<StructType>	StructTypeSP;
226 typedef de::SharedPtr<UniformBlock>	UniformBlockSP;
227 
228 class ShaderInterface
229 {
230 public:
231 								ShaderInterface			(void);
232 								~ShaderInterface		(void);
233 
234 	StructType&					allocStruct				(const std::string& name);
235 	void						getNamedStructs			(std::vector<const StructType*>& structs) const;
236 
237 	UniformBlock&				allocBlock				(const std::string& name);
238 
getNumUniformBlocks(void) const239 	int							getNumUniformBlocks		(void) const	{ return (int)m_uniformBlocks.size();	}
getUniformBlock(int ndx) const240 	const UniformBlock&			getUniformBlock			(int ndx) const	{ return *m_uniformBlocks[ndx];			}
241 	bool						usesBlockLayout			(UniformFlags layoutFlag) const;
242 
243 private:
244 	std::vector<StructTypeSP>		m_structs;
245 	std::vector<UniformBlockSP>		m_uniformBlocks;
246 };
247 
248 struct BlockLayoutEntry
249 {
BlockLayoutEntryvkt::ubo::BlockLayoutEntry250 	BlockLayoutEntry (void)
251 		: size					(0)
252 		, blockDeclarationNdx	(-1)
253 		, bindingNdx			(-1)
254 		, instanceNdx			(-1)
255 	{
256 	}
257 
258 	std::string			name;
259 	int					size;
260 	std::vector<int>	activeUniformIndices;
261 	int					blockDeclarationNdx;
262 	int					bindingNdx;
263 	int					instanceNdx;
264 };
265 
266 struct UniformLayoutEntry
267 {
UniformLayoutEntryvkt::ubo::UniformLayoutEntry268 	UniformLayoutEntry (void)
269 		: type			(glu::TYPE_LAST)
270 		, size			(0)
271 		, blockNdx		(-1)
272 		, offset		(-1)
273 		, arraySize		(-1)
274 		, arrayStride	(-1)
275 		, matrixStride	(-1)
276 		, topLevelArraySize		(-1)
277 		, topLevelArrayStride	(-1)
278 		, isRowMajor	(false)
279 		, instanceNdx	(0)
280 	{
281 	}
282 
283 	std::string			name;
284 	glu::DataType		type;
285 	int					size;
286 	int					blockNdx;
287 	int					offset;
288 	int					arraySize;
289 	int					arrayStride;
290 	int					matrixStride;
291 	int					topLevelArraySize;
292 	int					topLevelArrayStride;
293 	bool				isRowMajor;
294 	int					instanceNdx;
295 };
296 
297 class UniformLayout
298 {
299 public:
300 	std::vector<BlockLayoutEntry>		blocks;
301 	std::vector<UniformLayoutEntry>		uniforms;
302 
303 	int									getUniformLayoutIndex	(int blockDeclarationNdx, const std::string& name) const;
304 	int									getBlockLayoutIndex		(int blockDeclarationNdx, int instanceNdx) const;
305 };
306 
307 class UniformBlockCase : public vkt::TestCase
308 {
309 public:
310 	enum BufferMode
311 	{
312 		BUFFERMODE_SINGLE = 0,	//!< Single buffer shared between uniform blocks.
313 		BUFFERMODE_PER_BLOCK,	//!< Per-block buffers
314 
315 		BUFFERMODE_LAST
316 	};
317 
318 								UniformBlockCase			(tcu::TestContext&	testCtx,
319 															 const std::string&	name,
320 															 const std::string&	description,
321 															 BufferMode			bufferMode,
322 															 MatrixLoadFlags	matrixLoadFlag,
323 															 bool				shuffleUniformMembers = false);
324 								~UniformBlockCase			(void);
325 
326 	virtual	void				initPrograms				(vk::SourceCollections& programCollection) const;
327 	virtual TestInstance*		createInstance				(Context& context) const;
usesBlockLayout(UniformFlags layoutFlag) const328 	bool						usesBlockLayout				(UniformFlags layoutFlag) const { return m_interface.usesBlockLayout(layoutFlag); }
329 
330 protected:
331 	void						init						(void);
332 
333 	BufferMode					m_bufferMode;
334 	ShaderInterface				m_interface;
335 	MatrixLoadFlags				m_matrixLoadFlag;
336 	const bool					m_shuffleUniformMembers;	//!< Used with explicit offsets to test out of order member offsets
337 
338 private:
339 	std::string					m_vertShaderSource;
340 	std::string					m_fragShaderSource;
341 
342 	std::vector<deUint8>		m_data;						//!< Data.
343 	std::map<int, void*>		m_blockPointers;			//!< Reference block pointers.
344 	UniformLayout				m_uniformLayout;			//!< std140 layout.
345 };
346 
347 } // ubo
348 } // vkt
349 
350 #endif // _VKTUNIFORMBLOCKCASE_HPP
351