1 #ifndef _VKRAYTRACINGUTIL_HPP
2 #define _VKRAYTRACINGUTIL_HPP
3 /*-------------------------------------------------------------------------
4  * Vulkan CTS Framework
5  * --------------------
6  *
7  * Copyright (c) 2020 The Khronos Group Inc.
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 Vulkan ray tracing utility.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vkDefs.hpp"
27 #include "vkRef.hpp"
28 #include "vkMemUtil.hpp"
29 #include "vkBufferWithMemory.hpp"
30 
31 #include "deFloat16.h"
32 
33 #include "tcuVector.hpp"
34 #include "tcuVectorType.hpp"
35 
36 #include <vector>
37 
38 namespace vk
39 {
40 const VkTransformMatrixKHR identityMatrix3x4 = { { { 1.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f, 0.0f } } };
41 
42 template<typename T>
makeVkSharedPtr(Move<T> move)43 inline de::SharedPtr<Move<T>> makeVkSharedPtr(Move<T> move)
44 {
45 	return de::SharedPtr<Move<T>>(new Move<T>(move));
46 }
47 
48 template<typename T>
makeVkSharedPtr(de::MovePtr<T> movePtr)49 inline de::SharedPtr<de::MovePtr<T> > makeVkSharedPtr(de::MovePtr<T> movePtr)
50 {
51 	return de::SharedPtr<de::MovePtr<T> >(new de::MovePtr<T>(movePtr));
52 }
53 
54 template<typename T>
dataOrNullPtr(const std::vector<T> & v)55 inline const T* dataOrNullPtr(const std::vector<T>& v)
56 {
57 	return (v.empty() ? DE_NULL : v.data());
58 }
59 
60 template<typename T>
dataOrNullPtr(std::vector<T> & v)61 inline T* dataOrNullPtr(std::vector<T>& v)
62 {
63 	return (v.empty() ? DE_NULL : v.data());
64 }
65 
updateRayTracingGLSL(const std::string & str)66 inline std::string updateRayTracingGLSL (const std::string& str)
67 {
68 	return str;
69 }
70 
71 std::string getCommonRayGenerationShader (void);
72 
73 // Get lowercase version of the format name with no VK_FORMAT_ prefix.
74 std::string getFormatSimpleName (vk::VkFormat format);
75 
76 // Checks the given vertex buffer format is valid for acceleration structures.
77 // Note: VK_KHR_get_physical_device_properties2 and VK_KHR_acceleration_structure are supposed to be supported.
78 void checkAccelerationStructureVertexBufferFormat (const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice, vk::VkFormat format);
79 
80 class RaytracedGeometryBase
81 {
82 public:
83 								RaytracedGeometryBase			()										= delete;
84 								RaytracedGeometryBase			(const RaytracedGeometryBase& geometry)	= delete;
85 								RaytracedGeometryBase			(VkGeometryTypeKHR geometryType, VkFormat vertexFormat, VkIndexType indexType);
86 								virtual ~RaytracedGeometryBase	();
87 
getGeometryType(void) const88 	inline VkGeometryTypeKHR	getGeometryType					(void) const								{ return m_geometryType; }
isTrianglesType(void) const89 	inline bool					isTrianglesType					(void) const								{ return m_geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR; }
getVertexFormat(void) const90 	inline VkFormat				getVertexFormat					(void) const								{ return m_vertexFormat; }
getIndexType(void) const91 	inline VkIndexType			getIndexType					(void) const								{ return m_indexType; }
usesIndices(void) const92 	inline bool					usesIndices						(void) const								{ return m_indexType != VK_INDEX_TYPE_NONE_KHR; }
getGeometryFlags(void) const93 	inline VkGeometryFlagsKHR	getGeometryFlags				(void) const								{ return m_geometryFlags; }
setGeometryFlags(const VkGeometryFlagsKHR geometryFlags)94 	inline void					setGeometryFlags				(const VkGeometryFlagsKHR geometryFlags)	{ m_geometryFlags = geometryFlags; }
95 	virtual deUint32			getVertexCount					(void) const								= 0;
96 	virtual const deUint8*		getVertexPointer				(void) const								= 0;
97 	virtual VkDeviceSize		getVertexStride					(void) const								= 0;
98 	virtual VkDeviceSize		getAABBStride					(void) const								= 0;
99 	virtual size_t				getVertexByteSize				(void) const								= 0;
100 	virtual deUint32			getIndexCount					(void) const								= 0;
101 	virtual const deUint8*		getIndexPointer					(void) const								= 0;
102 	virtual VkDeviceSize		getIndexStride					(void) const								= 0;
103 	virtual size_t				getIndexByteSize				(void) const								= 0;
104 	virtual deUint32			getPrimitiveCount				(void) const								= 0;
105 	virtual void				addVertex						(const tcu::Vec3& vertex)					= 0;
106 	virtual void				addIndex						(const deUint32& index)						= 0;
107 private:
108 	VkGeometryTypeKHR			m_geometryType;
109 	VkFormat					m_vertexFormat;
110 	VkIndexType					m_indexType;
111 	VkGeometryFlagsKHR			m_geometryFlags;
112 };
113 
114 template <typename T>
convertSatRte(float f)115 inline T convertSatRte (float f)
116 {
117 	// \note Doesn't work for 64-bit types
118 	DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
119 	DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
120 
121 	deInt64	minVal	= std::numeric_limits<T>::min();
122 	deInt64 maxVal	= std::numeric_limits<T>::max();
123 	float	q		= deFloatFrac(f);
124 	deInt64 intVal	= (deInt64)(f-q);
125 
126 	// Rounding.
127 	if (q == 0.5f)
128 	{
129 		if (intVal % 2 != 0)
130 			intVal++;
131 	}
132 	else if (q > 0.5f)
133 		intVal++;
134 	// else Don't add anything
135 
136 	// Saturate.
137 	intVal = de::max(minVal, de::min(maxVal, intVal));
138 
139 	return (T)intVal;
140 }
141 
142 // Converts float to signed integer with variable width.
143 // Source float is assumed to be in the [-1, 1] range.
144 template <typename T>
deFloat32ToSNorm(float src)145 inline T deFloat32ToSNorm (float src)
146 {
147 	DE_STATIC_ASSERT(std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed);
148 	const T range	= std::numeric_limits<T>::max();
149 	const T intVal	= convertSatRte<T>(src * static_cast<float>(range));
150 	return de::clamp<T>(intVal, -range, range);
151 }
152 
153 typedef tcu::Vector<deFloat16, 2>			Vec2_16;
154 typedef tcu::Vector<deFloat16, 3>			Vec3_16;
155 typedef tcu::Vector<deFloat16, 4>			Vec4_16;
156 typedef tcu::Vector<deInt16, 2>				Vec2_16SNorm;
157 typedef tcu::Vector<deInt16, 3>				Vec3_16SNorm;
158 typedef tcu::Vector<deInt16, 4>				Vec4_16SNorm;
159 typedef tcu::Vector<deInt8, 2>				Vec2_8SNorm;
160 typedef tcu::Vector<deInt8, 3>				Vec3_8SNorm;
161 typedef tcu::Vector<deInt8, 4>				Vec4_8SNorm;
162 
163 template<typename V>	VkFormat			vertexFormatFromType				();
vertexFormatFromType()164 template<>				inline VkFormat		vertexFormatFromType<tcu::Vec2>		()							{ return VK_FORMAT_R32G32_SFLOAT; }
vertexFormatFromType()165 template<>				inline VkFormat		vertexFormatFromType<tcu::Vec3>		()							{ return VK_FORMAT_R32G32B32_SFLOAT; }
vertexFormatFromType()166 template<>				inline VkFormat		vertexFormatFromType<tcu::Vec4>		()							{ return VK_FORMAT_R32G32B32A32_SFLOAT; }
vertexFormatFromType()167 template<>				inline VkFormat		vertexFormatFromType<Vec2_16>		()							{ return VK_FORMAT_R16G16_SFLOAT; }
vertexFormatFromType()168 template<>				inline VkFormat		vertexFormatFromType<Vec3_16>		()							{ return VK_FORMAT_R16G16B16_SFLOAT; }
vertexFormatFromType()169 template<>				inline VkFormat		vertexFormatFromType<Vec4_16>		()							{ return VK_FORMAT_R16G16B16A16_SFLOAT; }
vertexFormatFromType()170 template<>				inline VkFormat		vertexFormatFromType<Vec2_16SNorm>	()							{ return VK_FORMAT_R16G16_SNORM; }
vertexFormatFromType()171 template<>				inline VkFormat		vertexFormatFromType<Vec3_16SNorm>	()							{ return VK_FORMAT_R16G16B16_SNORM; }
vertexFormatFromType()172 template<>				inline VkFormat		vertexFormatFromType<Vec4_16SNorm>	()							{ return VK_FORMAT_R16G16B16A16_SNORM; }
vertexFormatFromType()173 template<>				inline VkFormat		vertexFormatFromType<tcu::DVec2>	()							{ return VK_FORMAT_R64G64_SFLOAT; }
vertexFormatFromType()174 template<>				inline VkFormat		vertexFormatFromType<tcu::DVec3>	()							{ return VK_FORMAT_R64G64B64_SFLOAT; }
vertexFormatFromType()175 template<>				inline VkFormat		vertexFormatFromType<tcu::DVec4>	()							{ return VK_FORMAT_R64G64B64A64_SFLOAT; }
vertexFormatFromType()176 template<>				inline VkFormat		vertexFormatFromType<Vec2_8SNorm>	()							{ return VK_FORMAT_R8G8_SNORM; }
vertexFormatFromType()177 template<>				inline VkFormat		vertexFormatFromType<Vec3_8SNorm>	()							{ return VK_FORMAT_R8G8B8_SNORM; }
vertexFormatFromType()178 template<>				inline VkFormat		vertexFormatFromType<Vec4_8SNorm>	()							{ return VK_FORMAT_R8G8B8A8_SNORM; }
179 
180 struct EmptyIndex {};
181 template<typename I>	VkIndexType			indexTypeFromType					();
indexTypeFromType()182 template<>				inline VkIndexType	indexTypeFromType<deUint16>			()							{ return VK_INDEX_TYPE_UINT16; }
indexTypeFromType()183 template<>				inline VkIndexType	indexTypeFromType<deUint32>			()							{ return VK_INDEX_TYPE_UINT32; }
indexTypeFromType()184 template<>				inline VkIndexType	indexTypeFromType<EmptyIndex>		()							{ return VK_INDEX_TYPE_NONE_KHR; }
185 
186 template<typename V>	V					convertFloatTo						(const tcu::Vec3& vertex);
convertFloatTo(const tcu::Vec3 & vertex)187 template<>				inline tcu::Vec2	convertFloatTo<tcu::Vec2>			(const tcu::Vec3& vertex)	{ return tcu::Vec2(vertex.x(), vertex.y()); }
convertFloatTo(const tcu::Vec3 & vertex)188 template<>				inline tcu::Vec3	convertFloatTo<tcu::Vec3>			(const tcu::Vec3& vertex)	{ return vertex; }
convertFloatTo(const tcu::Vec3 & vertex)189 template<>				inline tcu::Vec4	convertFloatTo<tcu::Vec4>			(const tcu::Vec3& vertex)	{ return tcu::Vec4(vertex.x(), vertex.y(), vertex.z(), 0.0f); }
convertFloatTo(const tcu::Vec3 & vertex)190 template<>				inline Vec2_16		convertFloatTo<Vec2_16>				(const tcu::Vec3& vertex)	{ return Vec2_16(deFloat32To16(vertex.x()), deFloat32To16(vertex.y())); }
convertFloatTo(const tcu::Vec3 & vertex)191 template<>				inline Vec3_16		convertFloatTo<Vec3_16>				(const tcu::Vec3& vertex)	{ return Vec3_16(deFloat32To16(vertex.x()), deFloat32To16(vertex.y()), deFloat32To16(vertex.z())); }
convertFloatTo(const tcu::Vec3 & vertex)192 template<>				inline Vec4_16		convertFloatTo<Vec4_16>				(const tcu::Vec3& vertex)	{ return Vec4_16(deFloat32To16(vertex.x()), deFloat32To16(vertex.y()), deFloat32To16(vertex.z()), deFloat32To16(0.0f)); }
convertFloatTo(const tcu::Vec3 & vertex)193 template<>				inline Vec2_16SNorm	convertFloatTo<Vec2_16SNorm>		(const tcu::Vec3& vertex)	{ return Vec2_16SNorm(deFloat32ToSNorm<deInt16>(vertex.x()), deFloat32ToSNorm<deInt16>(vertex.y())); }
convertFloatTo(const tcu::Vec3 & vertex)194 template<>				inline Vec3_16SNorm	convertFloatTo<Vec3_16SNorm>		(const tcu::Vec3& vertex)	{ return Vec3_16SNorm(deFloat32ToSNorm<deInt16>(vertex.x()), deFloat32ToSNorm<deInt16>(vertex.y()), deFloat32ToSNorm<deInt16>(vertex.z())); }
convertFloatTo(const tcu::Vec3 & vertex)195 template<>				inline Vec4_16SNorm	convertFloatTo<Vec4_16SNorm>		(const tcu::Vec3& vertex)	{ return Vec4_16SNorm(deFloat32ToSNorm<deInt16>(vertex.x()), deFloat32ToSNorm<deInt16>(vertex.y()), deFloat32ToSNorm<deInt16>(vertex.z()), deFloat32ToSNorm<deInt16>(0.0f)); }
convertFloatTo(const tcu::Vec3 & vertex)196 template<>				inline tcu::DVec2	convertFloatTo<tcu::DVec2>			(const tcu::Vec3& vertex)	{ return tcu::DVec2(static_cast<double>(vertex.x()), static_cast<double>(vertex.y())); }
convertFloatTo(const tcu::Vec3 & vertex)197 template<>				inline tcu::DVec3	convertFloatTo<tcu::DVec3>			(const tcu::Vec3& vertex)	{ return tcu::DVec3(static_cast<double>(vertex.x()), static_cast<double>(vertex.y()), static_cast<double>(vertex.z())); }
convertFloatTo(const tcu::Vec3 & vertex)198 template<>				inline tcu::DVec4	convertFloatTo<tcu::DVec4>			(const tcu::Vec3& vertex)	{ return tcu::DVec4(static_cast<double>(vertex.x()), static_cast<double>(vertex.y()), static_cast<double>(vertex.z()), 0.0); }
convertFloatTo(const tcu::Vec3 & vertex)199 template<>				inline Vec2_8SNorm	convertFloatTo<Vec2_8SNorm>			(const tcu::Vec3& vertex)	{ return Vec2_8SNorm(deFloat32ToSNorm<deInt8>(vertex.x()), deFloat32ToSNorm<deInt8>(vertex.y())); }
convertFloatTo(const tcu::Vec3 & vertex)200 template<>				inline Vec3_8SNorm	convertFloatTo<Vec3_8SNorm>			(const tcu::Vec3& vertex)	{ return Vec3_8SNorm(deFloat32ToSNorm<deInt8>(vertex.x()), deFloat32ToSNorm<deInt8>(vertex.y()), deFloat32ToSNorm<deInt8>(vertex.z())); }
convertFloatTo(const tcu::Vec3 & vertex)201 template<>				inline Vec4_8SNorm	convertFloatTo<Vec4_8SNorm>			(const tcu::Vec3& vertex)	{ return Vec4_8SNorm(deFloat32ToSNorm<deInt8>(vertex.x()), deFloat32ToSNorm<deInt8>(vertex.y()), deFloat32ToSNorm<deInt8>(vertex.z()), deFloat32ToSNorm<deInt8>(0.0f)); }
202 
203 template<typename V>	V					convertIndexTo						(deUint32 index);
convertIndexTo(deUint32 index)204 template<>				inline EmptyIndex	convertIndexTo<EmptyIndex>			(deUint32 index)			{ DE_UNREF(index); TCU_THROW(TestError, "Cannot add empty index"); }
convertIndexTo(deUint32 index)205 template<>				inline deUint16		convertIndexTo<deUint16>			(deUint32 index)			{ return static_cast<deUint16>(index); }
convertIndexTo(deUint32 index)206 template<>				inline deUint32		convertIndexTo<deUint32>			(deUint32 index)			{ return index; }
207 
208 template<typename V, typename I>
209 class RaytracedGeometry : public RaytracedGeometryBase
210 {
211 public:
212 						RaytracedGeometry			()									= delete;
213 						RaytracedGeometry			(const RaytracedGeometry& geometry)	= delete;
214 						RaytracedGeometry			(VkGeometryTypeKHR geometryType, deUint32 paddingBlocks = 0u);
215 						RaytracedGeometry			(VkGeometryTypeKHR geometryType, const std::vector<V>& vertices, const std::vector<I>& indices = std::vector<I>(), deUint32 paddingBlocks = 0u);
216 
217 	deUint32			getVertexCount				(void) const override;
218 	const deUint8*		getVertexPointer			(void) const override;
219 	VkDeviceSize		getVertexStride				(void) const override;
220 	VkDeviceSize		getAABBStride				(void) const override;
221 	size_t				getVertexByteSize			(void) const override;
222 	deUint32			getIndexCount				(void) const override;
223 	const deUint8*		getIndexPointer				(void) const override;
224 	VkDeviceSize		getIndexStride				(void) const override;
225 	size_t				getIndexByteSize			(void) const override;
226 	deUint32			getPrimitiveCount			(void) const override;
227 
228 	void				addVertex					(const tcu::Vec3& vertex) override;
229 	void				addIndex					(const deUint32& index) override;
230 
231 private:
232 	void				init						();					// To be run in constructors.
233 	void				checkGeometryType			() const;			// Checks geometry type is valid.
234 	void				calcBlockSize				();					// Calculates and saves vertex buffer block size.
235 	size_t				getBlockSize				() const;			// Return stored vertex buffer block size.
236 	void				addNativeVertex				(const V& vertex);	// Adds new vertex in native format.
237 
238 	// The implementation below stores vertices as byte blocks to take the requested padding into account. m_vertices is the array
239 	// of bytes containing vertex data.
240 	//
241 	// For triangles, the padding block has a size that is a multiple of the vertex size and each vertex is stored in a byte block
242 	// equivalent to:
243 	//
244 	//	struct Vertex
245 	//	{
246 	//		V		vertex;
247 	//		deUint8	padding[m_paddingBlocks * sizeof(V)];
248 	//	};
249 	//
250 	// For AABBs, the padding block has a size that is a multiple of kAABBPadBaseSize (see below) and vertices are stored in pairs
251 	// before the padding block. This is equivalent to:
252 	//
253 	//		struct VertexPair
254 	//		{
255 	//			V		vertices[2];
256 	//			deUint8	padding[m_paddingBlocks * kAABBPadBaseSize];
257 	//		};
258 	//
259 	// The size of each pseudo-structure above is saved to one of the correspoding union members below.
260 	union BlockSize
261 	{
262 		size_t trianglesBlockSize;
263 		size_t aabbsBlockSize;
264 	};
265 
266 	const deUint32			m_paddingBlocks;
267 	size_t					m_vertexCount;
268 	std::vector<deUint8>	m_vertices;			// Vertices are stored as byte blocks.
269 	std::vector<I>			m_indices;			// Indices are stored natively.
270 	BlockSize				m_blockSize;		// For m_vertices.
271 
272 	// Data sizes.
273 	static constexpr size_t	kVertexSize			= sizeof(V);
274 	static constexpr size_t	kIndexSize			= sizeof(I);
275 	static constexpr size_t	kAABBPadBaseSize	= 8; // As required by the spec.
276 };
277 
278 template<typename V, typename I>
RaytracedGeometry(VkGeometryTypeKHR geometryType,deUint32 paddingBlocks)279 RaytracedGeometry<V, I>::RaytracedGeometry (VkGeometryTypeKHR geometryType, deUint32 paddingBlocks)
280 	: RaytracedGeometryBase(geometryType, vertexFormatFromType<V>(), indexTypeFromType<I>())
281 	, m_paddingBlocks(paddingBlocks)
282 	, m_vertexCount(0)
283 {
284 	init();
285 }
286 
287 template<typename V, typename I>
RaytracedGeometry(VkGeometryTypeKHR geometryType,const std::vector<V> & vertices,const std::vector<I> & indices,deUint32 paddingBlocks)288 RaytracedGeometry<V,I>::RaytracedGeometry (VkGeometryTypeKHR geometryType, const std::vector<V>& vertices, const std::vector<I>& indices, deUint32 paddingBlocks)
289 	: RaytracedGeometryBase(geometryType, vertexFormatFromType<V>(), indexTypeFromType<I>())
290 	, m_paddingBlocks(paddingBlocks)
291 	, m_vertexCount(0)
292 	, m_vertices()
293 	, m_indices(indices)
294 {
295 	init();
296 	for (const auto& vertex : vertices)
297 		addNativeVertex(vertex);
298 }
299 
300 template<typename V, typename I>
getVertexCount(void) const301 deUint32 RaytracedGeometry<V,I>::getVertexCount (void) const
302 {
303 	return (isTrianglesType() ? static_cast<deUint32>(m_vertexCount) : 0u);
304 }
305 
306 template<typename V, typename I>
getVertexPointer(void) const307 const deUint8* RaytracedGeometry<V, I>::getVertexPointer (void) const
308 {
309 	DE_ASSERT(!m_vertices.empty());
310 	return reinterpret_cast<const deUint8*>(m_vertices.data());
311 }
312 
313 template<typename V, typename I>
getVertexStride(void) const314 VkDeviceSize RaytracedGeometry<V,I>::getVertexStride (void) const
315 {
316 	return ((!isTrianglesType()) ? 0ull : static_cast<VkDeviceSize>(getBlockSize()));
317 }
318 
319 template<typename V, typename I>
getAABBStride(void) const320 VkDeviceSize RaytracedGeometry<V, I>::getAABBStride (void) const
321 {
322 	return (isTrianglesType() ? 0ull : static_cast<VkDeviceSize>(getBlockSize()));
323 }
324 
325 template<typename V, typename I>
getVertexByteSize(void) const326 size_t RaytracedGeometry<V, I>::getVertexByteSize (void) const
327 {
328 	return m_vertices.size();
329 }
330 
331 template<typename V, typename I>
getIndexCount(void) const332 deUint32 RaytracedGeometry<V, I>::getIndexCount (void) const
333 {
334 	return static_cast<deUint32>(isTrianglesType() ? m_indices.size() : 0);
335 }
336 
337 template<typename V, typename I>
getIndexPointer(void) const338 const deUint8* RaytracedGeometry<V, I>::getIndexPointer (void) const
339 {
340 	const auto indexCount = getIndexCount();
341 	DE_UNREF(indexCount); // For release builds.
342 	DE_ASSERT(indexCount > 0u);
343 
344 	return reinterpret_cast<const deUint8*>(m_indices.data());
345 }
346 
347 template<typename V, typename I>
getIndexStride(void) const348 VkDeviceSize RaytracedGeometry<V, I>::getIndexStride (void) const
349 {
350 	return static_cast<VkDeviceSize>(kIndexSize);
351 }
352 
353 template<typename V, typename I>
getIndexByteSize(void) const354 size_t RaytracedGeometry<V, I>::getIndexByteSize (void) const
355 {
356 	const auto indexCount = getIndexCount();
357 	DE_ASSERT(indexCount > 0u);
358 
359 	return (indexCount * kIndexSize);
360 }
361 
362 template<typename V, typename I>
getPrimitiveCount(void) const363 deUint32 RaytracedGeometry<V,I>::getPrimitiveCount (void) const
364 {
365 	return static_cast<deUint32>(isTrianglesType() ? (usesIndices() ? m_indices.size() / 3 : m_vertexCount / 3) : (m_vertexCount / 2));
366 }
367 
368 template<typename V, typename I>
addVertex(const tcu::Vec3 & vertex)369 void RaytracedGeometry<V, I>::addVertex (const tcu::Vec3& vertex)
370 {
371 	addNativeVertex(convertFloatTo<V>(vertex));
372 }
373 
374 template<typename V, typename I>
addNativeVertex(const V & vertex)375 void RaytracedGeometry<V, I>::addNativeVertex (const V& vertex)
376 {
377 	const auto oldSize			= m_vertices.size();
378 	const auto blockSize		= getBlockSize();
379 
380 	if (isTrianglesType())
381 	{
382 		// Reserve new block, copy vertex at the beginning of the new block.
383 		m_vertices.resize(oldSize + blockSize, deUint8{0});
384 		deMemcpy(&m_vertices[oldSize], &vertex, kVertexSize);
385 	}
386 	else // AABB
387 	{
388 		if (m_vertexCount % 2 == 0)
389 		{
390 			// New block needed.
391 			m_vertices.resize(oldSize + blockSize, deUint8{0});
392 			deMemcpy(&m_vertices[oldSize], &vertex, kVertexSize);
393 		}
394 		else
395 		{
396 			// Insert in the second position of last existing block.
397 			//
398 			//												Vertex Size
399 			//												+-------+
400 			//	+-------------+------------+----------------------------------------+
401 			//	|             |            |      ...       | vertex vertex padding |
402 			//	+-------------+------------+----------------+-----------------------+
403 			//												+-----------------------+
404 			//														Block Size
405 			//	+-------------------------------------------------------------------+
406 			//							Old Size
407 			//
408 			deMemcpy(&m_vertices[oldSize - blockSize + kVertexSize], &vertex, kVertexSize);
409 		}
410 	}
411 
412 	++m_vertexCount;
413 }
414 
415 template<typename V, typename I>
addIndex(const deUint32 & index)416 void RaytracedGeometry<V, I>::addIndex (const deUint32& index)
417 {
418 	m_indices.push_back(convertIndexTo<I>(index));
419 }
420 
421 template<typename V, typename I>
init()422 void RaytracedGeometry<V, I>::init ()
423 {
424 	checkGeometryType();
425 	calcBlockSize();
426 }
427 
428 template<typename V, typename I>
checkGeometryType() const429 void RaytracedGeometry<V, I>::checkGeometryType () const
430 {
431 	const auto geometryType = getGeometryType();
432 	DE_UNREF(geometryType); // For release builds.
433 	DE_ASSERT(geometryType == VK_GEOMETRY_TYPE_TRIANGLES_KHR || geometryType == VK_GEOMETRY_TYPE_AABBS_KHR);
434 }
435 
436 template<typename V, typename I>
calcBlockSize()437 void RaytracedGeometry<V, I>::calcBlockSize ()
438 {
439 	if (isTrianglesType())
440 		m_blockSize.trianglesBlockSize = kVertexSize * static_cast<size_t>(1u + m_paddingBlocks);
441 	else
442 		m_blockSize.aabbsBlockSize = 2 * kVertexSize + m_paddingBlocks * kAABBPadBaseSize;
443 }
444 
445 template<typename V, typename I>
getBlockSize() const446 size_t RaytracedGeometry<V, I>::getBlockSize () const
447 {
448 	return (isTrianglesType() ? m_blockSize.trianglesBlockSize : m_blockSize.aabbsBlockSize);
449 }
450 
451 de::SharedPtr<RaytracedGeometryBase> makeRaytracedGeometry (VkGeometryTypeKHR geometryType, VkFormat vertexFormat, VkIndexType indexType, bool padVertices = false);
452 
453 VkDeviceAddress getBufferDeviceAddress ( const DeviceInterface&	vkd,
454 										 const VkDevice			device,
455 										 const VkBuffer			buffer,
456 										 VkDeviceSize			offset );
457 
458 class SerialStorage
459 {
460 public:
461 	enum
462 	{
463 		DE_SERIALIZED_FIELD(DRIVER_UUID,		VK_UUID_SIZE),		// VK_UUID_SIZE bytes of data matching VkPhysicalDeviceIDProperties::driverUUID
464 		DE_SERIALIZED_FIELD(COMPAT_UUID,		VK_UUID_SIZE),		// VK_UUID_SIZE bytes of data identifying the compatibility for comparison using vkGetDeviceAccelerationStructureCompatibilityKHR
465 		DE_SERIALIZED_FIELD(SERIALIZED_SIZE,	sizeof(deUint64)),	// A 64-bit integer of the total size matching the value queried using VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR
466 		DE_SERIALIZED_FIELD(DESERIALIZED_SIZE,	sizeof(deUint64)),	// A 64-bit integer of the deserialized size to be passed in to VkAccelerationStructureCreateInfoKHR::size
467 		DE_SERIALIZED_FIELD(HANDLES_COUNT,		sizeof(deUint64)),	// A 64-bit integer of the count of the number of acceleration structure handles following. This will be zero for a bottom-level acceleration structure.
468 		SERIAL_STORAGE_SIZE_MIN
469 	};
470 
471 											SerialStorage		() = delete;
472 											SerialStorage		(const DeviceInterface&						vk,
473 																 const VkDevice								device,
474 																 Allocator&									allocator,
475 																 const VkAccelerationStructureBuildTypeKHR	buildType,
476 																 const VkDeviceSize							storageSize);
477 
478 	VkDeviceOrHostAddressKHR				getAddress			(const DeviceInterface&	vk,
479 																 const VkDevice			device);
480 	VkDeviceOrHostAddressConstKHR			getAddressConst		(const DeviceInterface&	vk,
481 																 const VkDevice			device);
482 	VkDeviceSize							getStorageSize		();
483 	deUint64								getDeserializedSize	();
484 
485 protected:
486 	VkAccelerationStructureBuildTypeKHR		m_buildType;
487 	de::MovePtr<BufferWithMemory>			m_buffer;
488 	VkDeviceSize							m_storageSize;
489 
490 };
491 
492 class BottomLevelAccelerationStructure
493 {
494 public:
495 	static deUint32										getRequiredAllocationCount				(void);
496 
497 														BottomLevelAccelerationStructure		();
498 														BottomLevelAccelerationStructure		(const BottomLevelAccelerationStructure&		other) = delete;
499 	virtual												~BottomLevelAccelerationStructure		();
500 
501 	virtual void										setGeometryData							(const std::vector<tcu::Vec3>&					geometryData,
502 																								 const bool										triangles,
503 																								 const VkGeometryFlagsKHR						geometryFlags			= 0u );
504 	virtual void										setDefaultGeometryData					(const VkShaderStageFlagBits					testStage,
505 																								 const VkGeometryFlagsKHR						geometryFlags			= 0u );
506 	virtual void										setGeometryCount						(const size_t									geometryCount);
507 	virtual void										addGeometry								(de::SharedPtr<RaytracedGeometryBase>&			raytracedGeometry);
508 	virtual void										addGeometry								(const std::vector<tcu::Vec3>&					geometryData,
509 																								 const bool										triangles,
510 																								 const VkGeometryFlagsKHR						geometryFlags			= 0u );
511 
512 	virtual void										setBuildType							(const VkAccelerationStructureBuildTypeKHR		buildType) = DE_NULL;
513 	virtual void										setCreateFlags							(const VkAccelerationStructureCreateFlagsKHR	createFlags) = DE_NULL;
514 	virtual void										setCreateGeneric						(bool											createGeneric) = 0;
515 	virtual void										setBuildFlags							(const VkBuildAccelerationStructureFlagsKHR		buildFlags) = DE_NULL;
516 	virtual void										setBuildWithoutGeometries				(bool											buildWithoutGeometries) = 0;
517 	virtual void										setBuildWithoutPrimitives				(bool											buildWithoutPrimitives) = 0;
518 	virtual void										setDeferredOperation					(const bool										deferredOperation,
519 																								 const deUint32									workerThreadCount		= 0u ) = DE_NULL;
520 	virtual void										setUseArrayOfPointers					(const bool										useArrayOfPointers) = DE_NULL;
521 	virtual void										setIndirectBuildParameters				(const VkBuffer									indirectBuffer,
522 																								 const VkDeviceSize								indirectBufferOffset,
523 																								 const deUint32									indirectBufferStride) = DE_NULL;
524 	virtual VkBuildAccelerationStructureFlagsKHR		getBuildFlags							() const = DE_NULL;
525 	VkDeviceSize										getStructureSize						() const;
526 
527 	// methods specific for each acceleration structure
528 	virtual void										create									(const DeviceInterface&							vk,
529 																								 const VkDevice									device,
530 																								 Allocator&										allocator,
531 																								 VkDeviceSize									structureSize,
532 																								 VkDeviceAddress								deviceAddress			= 0u) = DE_NULL;
533 	virtual void										build									(const DeviceInterface&							vk,
534 																								 const VkDevice									device,
535 																								 const VkCommandBuffer							cmdBuffer) = DE_NULL;
536 	virtual void										copyFrom								(const DeviceInterface&							vk,
537 																								 const VkDevice									device,
538 																								 const VkCommandBuffer							cmdBuffer,
539 																								 BottomLevelAccelerationStructure*				accelerationStructure,
540 																								 bool											compactCopy) = DE_NULL;
541 
542 	virtual void										serialize								(const DeviceInterface&							vk,
543 																								 const VkDevice									device,
544 																								 const VkCommandBuffer							cmdBuffer,
545 																								 SerialStorage*									storage) = DE_NULL;
546 	virtual void										deserialize								(const DeviceInterface&							vk,
547 																								 const VkDevice									device,
548 																								 const VkCommandBuffer							cmdBuffer,
549 																								 SerialStorage*									storage) = DE_NULL;
550 
551 	// helper methods for typical acceleration structure creation tasks
552 	void												createAndBuild							(const DeviceInterface&							vk,
553 																								 const VkDevice									device,
554 																								 const VkCommandBuffer							cmdBuffer,
555 																								 Allocator&										allocator,
556 																								 VkDeviceAddress								deviceAddress			= 0u );
557 	void												createAndCopyFrom						(const DeviceInterface&							vk,
558 																								 const VkDevice									device,
559 																								 const VkCommandBuffer							cmdBuffer,
560 																								 Allocator&										allocator,
561 																								 BottomLevelAccelerationStructure*				accelerationStructure,
562 																								 VkDeviceSize									compactCopySize			= 0u,
563 																								 VkDeviceAddress								deviceAddress			= 0u);
564 	void												createAndDeserializeFrom				(const DeviceInterface&							vk,
565 																								 const VkDevice									device,
566 																								 const VkCommandBuffer							cmdBuffer,
567 																								 Allocator&										allocator,
568 																								 SerialStorage*									storage,
569 																								 VkDeviceAddress								deviceAddress			= 0u);
570 
571 	virtual const VkAccelerationStructureKHR*			getPtr									(void) const = DE_NULL;
572 protected:
573 	std::vector<de::SharedPtr<RaytracedGeometryBase>>	m_geometriesData;
574 	VkDeviceSize										m_structureSize;
575 	VkDeviceSize										m_updateScratchSize;
576 	VkDeviceSize										m_buildScratchSize;
577 };
578 
579 de::MovePtr<BottomLevelAccelerationStructure> makeBottomLevelAccelerationStructure ();
580 
581 struct InstanceData
582 {
InstanceDatavk::InstanceData583 								InstanceData (VkTransformMatrixKHR							matrix_,
584 											  deUint32										instanceCustomIndex_,
585 											  deUint32										mask_,
586 											  deUint32										instanceShaderBindingTableRecordOffset_,
587 											  VkGeometryInstanceFlagsKHR					flags_)
588 									: matrix(matrix_), instanceCustomIndex(instanceCustomIndex_), mask(mask_), instanceShaderBindingTableRecordOffset(instanceShaderBindingTableRecordOffset_), flags(flags_)
589 								{
590 								}
591 	VkTransformMatrixKHR		matrix;
592 	deUint32					instanceCustomIndex;
593 	deUint32					mask;
594 	deUint32					instanceShaderBindingTableRecordOffset;
595 	VkGeometryInstanceFlagsKHR	flags;
596 };
597 
598 class TopLevelAccelerationStructure
599 {
600 public:
601 	static deUint32													getRequiredAllocationCount			(void);
602 
603 																	TopLevelAccelerationStructure		();
604 																	TopLevelAccelerationStructure		(const TopLevelAccelerationStructure&				other) = delete;
605 	virtual															~TopLevelAccelerationStructure		();
606 
607 	virtual void													setInstanceCount					(const size_t										instanceCount);
608 	virtual void													addInstance							(de::SharedPtr<BottomLevelAccelerationStructure>	bottomLevelStructure,
609 																										 const VkTransformMatrixKHR&						matrix									= identityMatrix3x4,
610 																										 deUint32											instanceCustomIndex						= 0,
611 																										 deUint32											mask									= 0xFF,
612 																										 deUint32											instanceShaderBindingTableRecordOffset	= 0,
613 																										 VkGeometryInstanceFlagsKHR							flags									= VkGeometryInstanceFlagBitsKHR(0u)	);
614 
615 	virtual void													setBuildType						(const VkAccelerationStructureBuildTypeKHR			buildType) = DE_NULL;
616 	virtual void													setCreateFlags						(const VkAccelerationStructureCreateFlagsKHR		createFlags) = DE_NULL;
617 	virtual void													setCreateGeneric					(bool												createGeneric) = 0;
618 	virtual void													setBuildFlags						(const VkBuildAccelerationStructureFlagsKHR			buildFlags) = DE_NULL;
619 	virtual void													setBuildWithoutPrimitives			(bool												buildWithoutPrimitives) = 0;
620 	virtual void													setInactiveInstances				(bool												inactiveInstances) = 0;
621 	virtual void													setDeferredOperation				(const bool											deferredOperation,
622 																										 const deUint32										workerThreadCount = 0u) = DE_NULL;
623 	virtual void													setUseArrayOfPointers				(const bool											useArrayOfPointers) = DE_NULL;
624 	virtual void													setIndirectBuildParameters			(const VkBuffer										indirectBuffer,
625 																										 const VkDeviceSize									indirectBufferOffset,
626 																										 const deUint32										indirectBufferStride) = DE_NULL;
627 	virtual VkBuildAccelerationStructureFlagsKHR					getBuildFlags						() const = DE_NULL;
628 	VkDeviceSize													getStructureSize					() const;
629 
630 	// methods specific for each acceleration structure
631 	virtual void													create								(const DeviceInterface&						vk,
632 																										 const VkDevice								device,
633 																										 Allocator&									allocator,
634 																										 VkDeviceSize								structureSize			= 0u,
635 																										 VkDeviceAddress							deviceAddress			= 0u ) = DE_NULL;
636 	virtual void													build								(const DeviceInterface&						vk,
637 																										 const VkDevice								device,
638 																										 const VkCommandBuffer						cmdBuffer) = DE_NULL;
639 	virtual void													copyFrom							(const DeviceInterface&						vk,
640 																										 const VkDevice								device,
641 																										 const VkCommandBuffer						cmdBuffer,
642 																										 TopLevelAccelerationStructure*				accelerationStructure,
643 																										 bool										compactCopy) = DE_NULL;
644 
645 	virtual void													serialize							(const DeviceInterface&						vk,
646 																										 const VkDevice								device,
647 																										 const VkCommandBuffer						cmdBuffer,
648 																										 SerialStorage*								storage) = DE_NULL;
649 	virtual void													deserialize							(const DeviceInterface&						vk,
650 																										 const VkDevice								device,
651 																										 const VkCommandBuffer						cmdBuffer,
652 																										 SerialStorage*								storage) = DE_NULL;
653 
654 	// helper methods for typical acceleration structure creation tasks
655 	void															createAndBuild						(const DeviceInterface&						vk,
656 																										 const VkDevice								device,
657 																										 const VkCommandBuffer						cmdBuffer,
658 																										 Allocator&									allocator,
659 																										 VkDeviceAddress							deviceAddress			= 0u );
660 	void															createAndCopyFrom					(const DeviceInterface&						vk,
661 																										 const VkDevice								device,
662 																										 const VkCommandBuffer						cmdBuffer,
663 																										 Allocator&									allocator,
664 																										 TopLevelAccelerationStructure*				accelerationStructure,
665 																										 VkDeviceSize								compactCopySize			= 0u,
666 																										 VkDeviceAddress							deviceAddress			= 0u);
667 	void															createAndDeserializeFrom			(const DeviceInterface&						vk,
668 																										 const VkDevice								device,
669 																										 const VkCommandBuffer						cmdBuffer,
670 																										 Allocator&									allocator,
671 																										 SerialStorage*								storage,
672 																										 VkDeviceAddress							deviceAddress			= 0u);
673 
674 	virtual const VkAccelerationStructureKHR*						getPtr								(void) const = DE_NULL;
675 
676 protected:
677 	std::vector<de::SharedPtr<BottomLevelAccelerationStructure> >	m_bottomLevelInstances;
678 	std::vector<InstanceData>										m_instanceData;
679 	VkDeviceSize													m_structureSize;
680 	VkDeviceSize													m_updateScratchSize;
681 	VkDeviceSize													m_buildScratchSize;
682 };
683 
684 de::MovePtr<TopLevelAccelerationStructure> makeTopLevelAccelerationStructure ();
685 
686 bool queryAccelerationStructureSize (const DeviceInterface&							vk,
687 									 const VkDevice									device,
688 									 const VkCommandBuffer							cmdBuffer,
689 									 const std::vector<VkAccelerationStructureKHR>&	accelerationStructureHandles,
690 									 VkAccelerationStructureBuildTypeKHR			buildType,
691 									 const VkQueryPool								queryPool,
692 									 VkQueryType									queryType,
693 									 deUint32										firstQuery,
694 									 std::vector<VkDeviceSize>&						results);
695 
696 class RayTracingPipeline
697 {
698 public:
699 																RayTracingPipeline			();
700 																~RayTracingPipeline			();
701 
702 	void														addShader					(VkShaderStageFlagBits									shaderStage,
703 																							 Move<VkShaderModule>									shaderModule,
704 																							 deUint32												group,
705 																							 const VkSpecializationInfo*							specializationInfo = nullptr);
706 	void														addShader					(VkShaderStageFlagBits									shaderStage,
707 																							 de::SharedPtr<Move<VkShaderModule>>					shaderModule,
708 																							 deUint32												group,
709 																							 const VkSpecializationInfo*							specializationInfoPtr = nullptr);
710 	void														addLibrary					(de::SharedPtr<de::MovePtr<RayTracingPipeline>>			pipelineLibrary);
711 	Move<VkPipeline>											createPipeline				(const DeviceInterface&									vk,
712 																							 const VkDevice											device,
713 																							 const VkPipelineLayout									pipelineLayout,
714 																							 const std::vector<de::SharedPtr<Move<VkPipeline>>>&	pipelineLibraries			= std::vector<de::SharedPtr<Move<VkPipeline>>>());
715 	std::vector<de::SharedPtr<Move<VkPipeline>>>				createPipelineWithLibraries	(const DeviceInterface&									vk,
716 																							 const VkDevice											device,
717 																							 const VkPipelineLayout									pipelineLayout);
718 	de::MovePtr<BufferWithMemory>								createShaderBindingTable	(const DeviceInterface&									vk,
719 																							 const VkDevice											device,
720 																							 const VkPipeline										pipeline,
721 																							 Allocator&												allocator,
722 																							 const deUint32&										shaderGroupHandleSize,
723 																							 const deUint32											shaderGroupBaseAlignment,
724 																							 const deUint32&										firstGroup,
725 																							 const deUint32&										groupCount,
726 																							 const VkBufferCreateFlags&								additionalBufferCreateFlags	= VkBufferCreateFlags(0u),
727 																							 const VkBufferUsageFlags&								additionalBufferUsageFlags	= VkBufferUsageFlags(0u),
728 																							 const MemoryRequirement&								additionalMemoryRequirement	= MemoryRequirement::Any,
729 																							 const VkDeviceAddress&									opaqueCaptureAddress		= 0u,
730 																							 const deUint32											shaderBindingTableOffset	= 0u,
731 																							 const deUint32											shaderRecordSize			= 0u,
732 																							 const void**											shaderGroupDataPtrPerGroup	= nullptr);
733 	void														setCreateFlags				(const VkPipelineCreateFlags&							pipelineCreateFlags);
734 	void														setMaxRecursionDepth		(const deUint32&										maxRecursionDepth);
735 	void														setMaxPayloadSize			(const deUint32&										maxPayloadSize);
736 	void														setMaxAttributeSize			(const deUint32&										maxAttributeSize);
737 	void														setDeferredOperation		(const bool												deferredOperation,
738 																							 const deUint32											workerThreadCount = 0);
739 	void														addDynamicState				(const VkDynamicState&									dynamicState);
740 
741 
742 protected:
743 	Move<VkPipeline>											createPipelineKHR			(const DeviceInterface&									vk,
744 																							 const VkDevice											device,
745 																							 const VkPipelineLayout									pipelineLayout,
746 																							 const std::vector<de::SharedPtr<Move<VkPipeline>>>&	pipelineLibraries);
747 
748 	std::vector<de::SharedPtr<Move<VkShaderModule> > >			m_shadersModules;
749 	std::vector<de::SharedPtr<de::MovePtr<RayTracingPipeline>>>	m_pipelineLibraries;
750 	std::vector<VkPipelineShaderStageCreateInfo>				m_shaderCreateInfos;
751 	std::vector<VkRayTracingShaderGroupCreateInfoKHR>			m_shadersGroupCreateInfos;
752 	VkPipelineCreateFlags										m_pipelineCreateFlags;
753 	deUint32													m_maxRecursionDepth;
754 	deUint32													m_maxPayloadSize;
755 	deUint32													m_maxAttributeSize;
756 	bool														m_deferredOperation;
757 	deUint32													m_workerThreadCount;
758 	std::vector<VkDynamicState>									m_dynamicStates;
759 };
760 
761 class RayTracingProperties
762 {
763 protected:
RayTracingProperties()764 									RayTracingProperties						() {};
765 
766 public:
RayTracingProperties(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)767 									RayTracingProperties						(const InstanceInterface&	vki,
768 																				 const VkPhysicalDevice		physicalDevice) { DE_UNREF(vki); DE_UNREF(physicalDevice); };
~RayTracingProperties()769 	virtual							~RayTracingProperties						() {};
770 
771 	virtual deUint32				getShaderGroupHandleSize					(void)	= DE_NULL;
772 	virtual deUint32				getMaxRecursionDepth						(void)	= DE_NULL;
773 	virtual deUint32				getMaxShaderGroupStride						(void)	= DE_NULL;
774 	virtual deUint32				getShaderGroupBaseAlignment					(void)	= DE_NULL;
775 	virtual deUint64				getMaxGeometryCount							(void)	= DE_NULL;
776 	virtual deUint64				getMaxInstanceCount							(void)	= DE_NULL;
777 	virtual deUint64				getMaxPrimitiveCount						(void)	= DE_NULL;
778 	virtual deUint32				getMaxDescriptorSetAccelerationStructures	(void)	= DE_NULL;
779 	virtual deUint32				getMaxRayDispatchInvocationCount			(void)	= DE_NULL;
780 	virtual deUint32				getMaxRayHitAttributeSize					(void)	= DE_NULL;
781 };
782 
783 de::MovePtr<RayTracingProperties> makeRayTracingProperties (const InstanceInterface&	vki,
784 															const VkPhysicalDevice		physicalDevice);
785 
786 void cmdTraceRays	(const DeviceInterface&					vk,
787 					 VkCommandBuffer						commandBuffer,
788 					 const VkStridedDeviceAddressRegionKHR*	raygenShaderBindingTableRegion,
789 					 const VkStridedDeviceAddressRegionKHR*	missShaderBindingTableRegion,
790 					 const VkStridedDeviceAddressRegionKHR*	hitShaderBindingTableRegion,
791 					 const VkStridedDeviceAddressRegionKHR*	callableShaderBindingTableRegion,
792 					 deUint32								width,
793 					 deUint32								height,
794 					 deUint32								depth);
795 
796 void cmdTraceRaysIndirect	(const DeviceInterface&					vk,
797 							 VkCommandBuffer						commandBuffer,
798 							 const VkStridedDeviceAddressRegionKHR*	raygenShaderBindingTableRegion,
799 							 const VkStridedDeviceAddressRegionKHR*	missShaderBindingTableRegion,
800 							 const VkStridedDeviceAddressRegionKHR*	hitShaderBindingTableRegion,
801 							 const VkStridedDeviceAddressRegionKHR*	callableShaderBindingTableRegion,
802 							 VkDeviceAddress						indirectDeviceAddress);
803 } // vk
804 
805 #endif // _VKRAYTRACINGUTIL_HPP
806