• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *	  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Ray Tracing Pipeline Flags tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayTracingPipelineFlagsTests.hpp"
25 
26 #include "vkDefs.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkBarrierUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkRayTracingUtil.hpp"
39 #include "tcuCommandLine.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuStringTemplate.hpp"
42 
43 #include <algorithm>
44 #include <array>
45 #include <cmath>
46 #include <functional>
47 #include <iterator>
48 #include <memory>
49 #include <set>
50 #include <tuple>
51 
52 #ifdef INTERNAL_DEBUG
53 #include <iostream>
54 #endif
55 
56 #define ALL_RAY_TRACING_STAGES	(VK_SHADER_STAGE_RAYGEN_BIT_KHR			\
57 								| VK_SHADER_STAGE_ANY_HIT_BIT_KHR		\
58 								| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR	\
59 								| VK_SHADER_STAGE_MISS_BIT_KHR			\
60 								| VK_SHADER_STAGE_INTERSECTION_BIT_KHR	\
61 								| VK_SHADER_STAGE_CALLABLE_BIT_KHR)
62 namespace vkt
63 {
64 namespace RayTracing
65 {
66 namespace
67 {
68 using namespace vk;
69 using namespace vkt;
70 
71 #define ALIGN_STD430(type_) alignas(sizeof(type_)) type_
72 
73 #define INRANGE(x_, a_, b_) (((x_) >= (a_) && (x_) <= (b_)) || ((x_) >= (b_) && (x_) <= (a_)))
74 
75 enum class GeometryTypes : deUint32
76 {
77 	None			= 0x0,
78 	Triangle		= 0x1,
79 	Box				= 0x2,
80 	TriangleAndBox	= Triangle | Box
81 };
82 
83 struct TestParams
84 {
85 	deUint32				width;
86 	deUint32				height;
87 	VkBool32				onHhost;
88 	VkPipelineCreateFlags	flags;
89 	bool					useLibs;
90 	deUint32				instCount;
91 	GeometryTypes			geomTypes;
92 	deUint32				geomCount;
93 	deUint32				stbRecStride;
94 	deUint32				stbRecOffset;
95 	float					accuracy;
96 #define ENABLED(val_, mask_) (((val_)&(mask_))==(mask_))
missvkt::RayTracing::__anon6a2c4e450111::TestParams97 	bool miss()		const {	return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR);	}
ahitvkt::RayTracing::__anon6a2c4e450111::TestParams98 	bool ahit()		const { return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR); }
chitvkt::RayTracing::__anon6a2c4e450111::TestParams99 	bool chit()		const { return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR); }
isectvkt::RayTracing::__anon6a2c4e450111::TestParams100 	bool isect()	const { return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR); }
101 };
102 
rotateCcwZ(const tcu::Vec3 & p,const tcu::Vec3 & center,const float & radians)103 tcu::Vec3 rotateCcwZ (const tcu::Vec3& p, const tcu::Vec3& center, const float& radians)
104 {
105 	const float s = std::sin(radians);
106 	const float c = std::cos(radians);
107 	const auto  t = p - center;
108 	return tcu::Vec3(c * t.x() - s * t.y(), s * t.x() + c * t.y(), t.z()) + center;
109 }
110 
pointInRect2D(const tcu::Vec3 & p,const tcu::Vec3 & p0,const tcu::Vec3 & p1)111 bool pointInRect2D(const tcu::Vec3& p, const tcu::Vec3& p0, const tcu::Vec3& p1)
112 {
113 	return INRANGE(p.x(), p0.x(), p1.x()) && INRANGE(p.y(), p0.y(), p1.y());
114 }
115 
computeEffectiveShaderGroupCount(const TestParams & p)116 deUint32 computeEffectiveShaderGroupCount(const TestParams& p)
117 {
118 	DE_ASSERT(p.instCount && p.geomCount);
119 	return (p.geomCount * p.stbRecStride + p.stbRecOffset + 1);
120 }
121 
122 class RayTracingTestPipeline;
123 
124 class PipelineFlagsCase : public TestCase
125 {
126 public:
127 							PipelineFlagsCase		(tcu::TestContext&	testCtx,
128 													 const std::string&	name,
129 													 const TestParams&	testParams);
130 	virtual					~PipelineFlagsCase		(void) = default;
131 	virtual void			initPrograms			(SourceCollections&	programCollection) const override;
132 	virtual TestInstance*	createInstance			(Context&			context) const override;
133 	virtual void			checkSupport			(Context&			context) const override;
134 
135 	const deUint32&			shaderGroupHandleSize;
136 	const deUint32&			shaderGroupBaseAlignment;
137 
138 private:
139 	const TestParams		m_params;
140 
141 	const tcu::IVec4		m_rgenPayload;
142 	const deInt32			m_defMissRetGreenComp;
143 	const deInt32			m_defTriRetGreenComp;
144 	const deInt32			m_defBoxRetGreenComp;
145 	static	deInt32			calcDefBoxRetGreenComp	(const TestParams&	params,
146 													 deInt32			defTriRetGreenComp);
147 
148 	static deUint32			m_shaderGroupHandleSize;
149 	static deUint32			m_shaderGroupBaseAlignment;
150 };
151 
calcDefBoxRetGreenComp(const TestParams & params,deInt32 defTriRetGreenComp)152 deInt32 PipelineFlagsCase::calcDefBoxRetGreenComp (const TestParams& params, deInt32 defTriRetGreenComp)
153 {
154 	const deUint32	nameCount		= params.stbRecStride ? (params.geomCount * params.instCount) : params.instCount;
155 	const deUint32	triangleCount	= (params.geomTypes == GeometryTypes::Triangle || params.geomTypes == GeometryTypes::TriangleAndBox) ? nameCount : 0u;
156 	return defTriRetGreenComp + std::max(triangleCount, 32u);
157 }
158 deUint32 PipelineFlagsCase::m_shaderGroupHandleSize;
159 deUint32 PipelineFlagsCase::m_shaderGroupBaseAlignment;
160 
161 class PipelineFlagsInstance : public TestInstance
162 {
163 	using TopLevelASPtr		= de::SharedPtr<TopLevelAccelerationStructure>;
164 	using BottomLevelASPtr	= de::SharedPtr<BottomLevelAccelerationStructure>;
165 	using BottomLevelASPtrs	= std::vector<BottomLevelASPtr>;
166 	using TriGeometry		= std::array<tcu::Vec3, 3>;
167 	using BoxGeometry		= std::array<tcu::Vec3, 2>;
168 
169 	friend class RayTracingTestPipeline;
170 public:
171 									PipelineFlagsInstance					(Context&					context,
172 																			 const TestParams&			params,
173 																			 const deUint32&			shaderGroupHandleSize_,
174 																			 const deUint32&			shaderGroupBaseAlignment_,
175 																			 const tcu::IVec4&			rgenPayload_,
176 																			 deInt32					defMissRetGreenComp_,
177 																			 deInt32					defTriRetGreenComp_,
178 																			 deInt32					defBoxRetGreenComp_);
179 	virtual							~PipelineFlagsInstance					(void) =  default;
180 
181 	struct ShaderRecordEXT
182 	{
183 		ALIGN_STD430(GeometryTypes)	geomType;
184 		ALIGN_STD430(deUint32)		geomIndex;
185 		ALIGN_STD430(tcu::IVec4)	retValue;
186 
187 		ShaderRecordEXT	();
188 		ShaderRecordEXT	(GeometryTypes type, deUint32 index, const tcu::IVec4& ret);
189 	};
190 
191 	virtual tcu::TestStatus			iterate									(void) override;
192 
193 	const tcu::IVec4				rgenPayload;
194 	const deInt32					defMissRetGreenComp;
195 	const deInt32					defTriRetGreenComp;
196 	const deInt32					defBoxRetGreenComp;
197 
198 	const deUint32					shaderGroupHandleSize;
199 	const deUint32					shaderGroupBaseAlignment;
200 
201 private:
202 	struct HitGroup;
203 	using ShaderRecordEntry	= std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool /* initalized */>;
204 
205 	VkImageCreateInfo				makeImageCreateInfo						() const;
206 	std::vector<TriGeometry>		prepareTriGeometries					(const float						zCoord)			const;
207 	std::vector<BoxGeometry>		prepareBoxGeometries					(const float						zFront,
208 																			 const float						zBack)			const;
209 	std::vector<ShaderRecordEntry>	prepareShaderBindingTable				(void)												const;
210 	BottomLevelASPtrs				createBottomLevelAccelerationStructs	(VkCommandBuffer					cmdBuffer)		const;
211 	TopLevelASPtr					createTopLevelAccelerationStruct		(VkCommandBuffer					cmdBuffer,
212 																			 const BottomLevelASPtrs&			blasPtrs)		const;
213 	bool							verifyResult							(const BufferWithMemory*			resultBuffer)	const;
214 #ifdef INTERNAL_DEBUG
215 	void							printImage								(const tcu::IVec4*					image)			const;
216 #endif
217 
218 	template<class rayPayloadEXT, class shaderRecordEXT>
219 	struct Shader
220 	{
ignoreIntersectionvkt::RayTracing::__anon6a2c4e450111::PipelineFlagsInstance::Shader221 		virtual bool			ignoreIntersection	(const rayPayloadEXT&, const shaderRecordEXT&) const { return false; }
222 		virtual	rayPayloadEXT	invoke				(const rayPayloadEXT&, const shaderRecordEXT&) const = 0;
223 	};
224 	struct ShaderBase : Shader<tcu::IVec4, ShaderRecordEXT>
225 	{
226 		typedef tcu::IVec4			rayPayloadEXT;
227 		typedef ShaderRecordEXT		shaderRecordEXT;
228 		static const rayPayloadEXT	dummyPayload;
invokevkt::RayTracing::__anon6a2c4e450111::PipelineFlagsInstance::ShaderBase229 		virtual	rayPayloadEXT	invoke				(const rayPayloadEXT&, const shaderRecordEXT&) const override {
230 			return rayPayloadEXT();
231 		}
232 	};
233 	struct ClosestHitShader : ShaderBase
234 	{
invokevkt::RayTracing::__anon6a2c4e450111::PipelineFlagsInstance::ClosestHitShader235 		virtual	rayPayloadEXT	invoke				(const rayPayloadEXT& hitAttr, const shaderRecordEXT& rec) const override {
236 			return (rec.geomType == GeometryTypes::Triangle) ? rec.retValue : hitAttr;
237 		}
238 	};
239 	struct AnyHitShader : ShaderBase
240 	{
ignoreIntersectionvkt::RayTracing::__anon6a2c4e450111::PipelineFlagsInstance::AnyHitShader241 		virtual bool			ignoreIntersection(const rayPayloadEXT&, const shaderRecordEXT& rec) const override {
242 			return (rec.geomIndex % 2 == 1);
243 		}
244 	};
245 	struct IntersectionShader : ShaderBase
246 	{
invokevkt::RayTracing::__anon6a2c4e450111::PipelineFlagsInstance::IntersectionShader247 		virtual	rayPayloadEXT	invoke(const rayPayloadEXT&, const shaderRecordEXT& rec) const override {
248 			return (rec.retValue + tcu::IVec4(0, 2, 3, 4));
249 		}
250 	};
251 	struct MissShader : ShaderBase
252 	{
invokevkt::RayTracing::__anon6a2c4e450111::PipelineFlagsInstance::MissShader253 		virtual	rayPayloadEXT	invoke(const rayPayloadEXT&, const shaderRecordEXT& rec) const override {
254 			return rec.retValue; }
255 	};
256 	struct HitGroup
257 	{
258 		de::SharedPtr<AnyHitShader>			ahit;
259 		de::SharedPtr<ClosestHitShader>		chit;
260 		de::SharedPtr<IntersectionShader>	isect;
261 	};
262 
263 	tcu::IVec2					rayToImage								(const tcu::Vec2&								rayCoords) const;
264 	tcu::Vec2					imageToRay								(const tcu::IVec2&								imageCoords) const;
265 	deUint32					computeSamePixelCount					(const std::vector<tcu::IVec4>&					image,
266 																		 const tcu::Vec2								pixelCoords,
267 																		 const tcu::IVec4&								requiredColor,
268 																		 const tcu::IVec4&								floodColor,
269 																		 const std::function<bool(const tcu::Vec3&)>&	pointInGeometry,
270 																		 std::vector<std::pair<tcu::IVec4, tcu::IVec2>>	&auxBuffer) const;
271 	void						travelRay								(std::vector<tcu::IVec4>&						outImage,
272 																		 const deUint32									glLaunchIdExtX,
273 																		 const deUint32									glLaunchIdExtY,
274 																		 const std::vector<ShaderRecordEntry>&			shaderBindingTable,
275 																		 const MissShader&								missShader,
276 																		 const std::vector<TriGeometry>&				triangleGeometries,
277 																		 const std::vector<BoxGeometry>&				boxGeometries) const;
278 	const TestParams			m_params;
279 	const VkFormat				m_format;
280 };
281 PipelineFlagsInstance::ShaderBase::rayPayloadEXT const PipelineFlagsInstance::ShaderBase::dummyPayload{};
282 
ShaderRecordEXT()283 PipelineFlagsInstance::ShaderRecordEXT::ShaderRecordEXT ()
284 	: geomType	(GeometryTypes::None)
285 	, geomIndex	(~0u)
286 	, retValue	()
287 {
288 }
289 
ShaderRecordEXT(GeometryTypes type,deUint32 index,const tcu::IVec4 & ret)290 PipelineFlagsInstance::ShaderRecordEXT::ShaderRecordEXT (GeometryTypes type, deUint32 index, const tcu::IVec4& ret)
291 	: geomType(type)
292 	, geomIndex(index)
293 	, retValue(ret)
294 {
295 }
296 
297 class RayTracingTestPipeline : protected RayTracingPipeline
298 {
299 public:
RayTracingTestPipeline(Context & context,const PipelineFlagsInstance & testInstance,const TestParams & params)300 	RayTracingTestPipeline (Context& context, const PipelineFlagsInstance& testInstance, const TestParams& params)
301 		: m_context			(context)
302 		, m_vkd				(context.getDeviceInterface())
303 		, m_device			(context.getDevice())
304 		, m_allocator		(context.getDefaultAllocator())
305 		, m_testInstance	(testInstance)
306 		, m_params			(params)
307 	{
308 		m_rgenModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("rgen"), 0);
309 
310 		// miss shader is loaded into each test regardless m_params.miss() is set
311 		m_missModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("miss"), 0);
312 
313 		// cloest hit shader is loaded into each test regardless m_params.chit() is set
314 		m_chitModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("chit"), 0);
315 
316 		if (m_params.ahit())
317 			m_ahitModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("ahit"), 0);
318 
319 		if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox))
320 			m_isectModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("isect"), 0);
321 
322 		setCreateFlags(m_params.flags);
323 		setMaxPayloadSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
324 		setMaxAttributeSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
325 	}
326 
327 	template<class ShaderRecord> struct SBT
328 	{
329 		static const deUint32 recordSize = static_cast<deUint32>(sizeof(ShaderRecord));
330 
331 		const DeviceInterface&			m_vkd;
332 		const VkDevice					m_dev;
333 		const VkPipeline				m_pipeline;
334 		const deUint32					m_groupCount;
335 		const deUint32					m_handleSize;
336 		const deUint32					m_alignment;
337 		de::MovePtr<BufferWithMemory>	m_buffer;
338 		deUint8*						m_content;
339 
SBTvkt::RayTracing::__anon6a2c4e450111::RayTracingTestPipeline::SBT340 		SBT (const DeviceInterface& vkd, VkDevice dev, Allocator& allocator, VkPipeline pipeline,
341 			 deUint32 groupCount, deUint32 shaderGroupHandleSize,  deUint32 shaderGroupBaseAlignment)
342 			: m_vkd(vkd), m_dev(dev), m_pipeline(pipeline)
343 			, m_groupCount(groupCount), m_handleSize(shaderGroupHandleSize)
344 			, m_alignment(deAlign32(shaderGroupHandleSize + recordSize, shaderGroupBaseAlignment))
345 			, m_buffer(), m_content()
346 		{
347 			const deUint32				size		= groupCount * m_alignment;
348 			const VkBufferUsageFlags	flags		= VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
349 			VkBufferCreateInfo			info		= makeBufferCreateInfo(size, flags);
350 			const MemoryRequirement		memReq		= MemoryRequirement::HostVisible | MemoryRequirement::Coherent | MemoryRequirement::DeviceAddress;
351 			m_buffer	= de::MovePtr<BufferWithMemory>(new BufferWithMemory(m_vkd, m_dev, allocator, info, memReq));
352 			m_content	= (deUint8*)m_buffer->getAllocation().getHostPtr();
353 		}
354 
updateAtvkt::RayTracing::__anon6a2c4e450111::RayTracingTestPipeline::SBT355 		void updateAt (deUint32 index, const deUint8* handle, const ShaderRecord& rec)
356 		{
357 			DE_ASSERT(index < m_groupCount);
358 			deUint8* groupPos = m_content + index * m_alignment;
359 			deMemcpy(groupPos, handle, m_handleSize);
360 			deMemcpy(groupPos + m_handleSize, &rec, recordSize);
361 		}
362 
flushvkt::RayTracing::__anon6a2c4e450111::RayTracingTestPipeline::SBT363 		void flush ()
364 		{
365 			Allocation&					alloc	= m_buffer->getAllocation();
366 			flushMappedMemoryRange(m_vkd, m_dev, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
367 		}
368 
getAlignmentvkt::RayTracing::__anon6a2c4e450111::RayTracingTestPipeline::SBT369 		deUint32	getAlignment () const { return m_alignment; }
370 
getvkt::RayTracing::__anon6a2c4e450111::RayTracingTestPipeline::SBT371 		de::MovePtr<BufferWithMemory> get () { return m_buffer; }
372 	};
373 
374 	struct PLDeleter
375 	{
376 		const RayTracingTestPipeline*				pipeline;
377 		std::function<void(RayTracingPipeline*)>	whenDestroying;
PLDeletervkt::RayTracing::__anon6a2c4e450111::RayTracingTestPipeline::PLDeleter378 		PLDeleter (RayTracingTestPipeline* pl, std::function<void(RayTracingPipeline*)>	doWhenDestroying)
379 			: pipeline(pl), whenDestroying(doWhenDestroying) {}
operator ()vkt::RayTracing::__anon6a2c4e450111::RayTracingTestPipeline::PLDeleter380 		void operator()(RayTracingPipeline* pl)
381 		{
382 			if (pipeline != pl && pipeline->m_params.useLibs)
383 			{
384 				if (whenDestroying) whenDestroying(pl);
385 				delete pl;
386 			}
387 		}
388 	};
389 
createLibraryPipeline(std::function<void (RayTracingPipeline *)> doWhenDestroying)390 	auto createLibraryPipeline (std::function<void(RayTracingPipeline*)> doWhenDestroying)
391 		-> de::UniquePtr<RayTracingPipeline, PLDeleter>
392 	{
393 		RayTracingPipeline* pl = this;
394 		if (m_params.useLibs) {
395 			pl = new RayTracingPipeline;
396 			pl->setCreateFlags(m_params.flags | VK_PIPELINE_CREATE_LIBRARY_BIT_KHR);
397 			pl->setMaxPayloadSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
398 			pl->setMaxAttributeSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
399 		}
400 		return de::UniquePtr<RayTracingPipeline, PLDeleter>(pl, PLDeleter(this, doWhenDestroying));
401 	}
402 
createPipeline(const VkPipelineLayout pipelineLayout)403 	Move<VkPipeline>	createPipeline (const VkPipelineLayout pipelineLayout)
404 	{
405 		deUint32	groupIndex	= 0;
406 		const bool	checkIsect	= (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox);
407 
408 		auto		appendPipelineLibrary	= [this, &pipelineLayout](RayTracingPipeline* pl) -> void
409 		{
410 			m_libraries.emplace_back(makeVkSharedPtr(pl->createPipeline(m_vkd, m_device, pipelineLayout)));
411 		};
412 
413 		DE_ASSERT(						(VkShaderModule(0) != *m_rgenModule));
414 		DE_ASSERT(						(VkShaderModule(0) != *m_missModule));
415 		DE_ASSERT(m_params.ahit()	==	(VkShaderModule(0) != *m_ahitModule));
416 		DE_ASSERT(						(VkShaderModule(0) != *m_chitModule));
417 		DE_ASSERT(checkIsect		==	(VkShaderModule(0) != *m_isectModule));
418 
419 		// rgen in the main pipeline only
420 		addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, *m_rgenModule, groupIndex++);
421 
422 		createLibraryPipeline(appendPipelineLibrary)->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, *m_missModule, (m_params.useLibs ? 0 : groupIndex++));
423 
424 		{
425 			const deUint32 hitGroupIndex = m_params.useLibs ? 0 : groupIndex;
426 			auto pipeline = createLibraryPipeline(appendPipelineLibrary);
427 			if (m_params.ahit())	pipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR,		*m_ahitModule, hitGroupIndex);
428 			pipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,	*m_chitModule, hitGroupIndex);
429 			if (checkIsect)			pipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR,	*m_isectModule, hitGroupIndex);
430 		}
431 
432 		for (const auto& sg : m_shadersGroupCreateInfos)
433 		{
434 			static_cast<void>(sg);
435 			DE_ASSERT(sg.type != VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR);
436 		}
437 
438 		return RayTracingPipeline::createPipeline(m_vkd, m_device, pipelineLayout, m_libraries);
439 	}
440 
createRaygenShaderBindingTable(VkPipeline pipeline)441 	std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR>	createRaygenShaderBindingTable (VkPipeline pipeline)
442 	{
443 		de::MovePtr<BufferWithMemory>	sbt	= createShaderBindingTable(m_vkd, m_device, pipeline, m_allocator,
444 																	   m_testInstance.shaderGroupHandleSize,
445 																	   m_testInstance.shaderGroupBaseAlignment, 0, 1);
446 		VkStridedDeviceAddressRegionKHR	rgn	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(m_vkd, m_device, **sbt, 0),
447 																				m_testInstance.shaderGroupHandleSize,
448 																				m_testInstance.shaderGroupHandleSize);
449 		return { de::SharedPtr<BufferWithMemory>(sbt.release()), rgn };
450 	}
451 
createMissShaderBindingTable(VkPipeline pipeline)452 	std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR>	createMissShaderBindingTable (VkPipeline pipeline)
453 	{
454 		const auto		entries			= m_testInstance.prepareShaderBindingTable();
455 		const void*		shaderRecPtr	= static_cast<PipelineFlagsInstance::ShaderRecordEXT const*>(&std::get<2>(entries[1]));
456 		const deUint32	shaderRecSize	= static_cast<deUint32>(sizeof(PipelineFlagsInstance::ShaderRecordEXT));
457 		const deUint32	alignment		= deAlign32(m_testInstance.shaderGroupHandleSize + shaderRecSize, m_testInstance.shaderGroupBaseAlignment);
458 		const deUint32	sbtOffset		= 0;
459 
460 		de::MovePtr<BufferWithMemory>	sbt	= createShaderBindingTable(m_vkd, m_device, pipeline, m_allocator,
461 																	   m_testInstance.shaderGroupHandleSize,
462 																	   m_testInstance.shaderGroupBaseAlignment,
463 																	   1, 1,
464 																	   VkBufferCreateFlags(0u),
465 																	   VkBufferUsageFlags(0u),
466 																	   MemoryRequirement::Any,
467 																	   VkDeviceAddress(0),
468 																	   sbtOffset,
469 																	   shaderRecSize,
470 																	   &shaderRecPtr);
471 
472 		VkStridedDeviceAddressRegionKHR	rgn	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(m_vkd, m_device, **sbt, 0),
473 																				alignment,
474 																				m_testInstance.shaderGroupHandleSize);
475 		return { de::SharedPtr<BufferWithMemory>(sbt.release()), rgn };
476 	}
477 
createHitShaderBindingTable(VkPipeline pipeline)478 	std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR>	createHitShaderBindingTable (VkPipeline pipeline)
479 	{
480 		de::MovePtr<BufferWithMemory>	buf;
481 		VkStridedDeviceAddressRegionKHR	rgn;
482 
483 		std::vector<deUint8>	handles			(m_testInstance.shaderGroupHandleSize);
484 		auto					records			= m_testInstance.prepareShaderBindingTable();
485 		const deUint32			hitGroupCount	= deUint32(records.size() - 2);
486 
487 		SBT<PipelineFlagsInstance::ShaderRecordEXT> sbt(m_vkd, m_device, m_allocator, pipeline, hitGroupCount,
488 														m_testInstance.shaderGroupHandleSize, m_testInstance.shaderGroupBaseAlignment);
489 
490 		VK_CHECK(m_vkd.getRayTracingShaderGroupHandlesKHR(m_device, pipeline, 2, 1, handles.size(), handles.data()));
491 
492 		for (deUint32 i = 0; i < hitGroupCount; ++i)
493 		{
494 			// copy the SBT record if it was initialized in prepareShaderBindingTable()
495 			if (std::get<3>(records[i + 2]))
496 			{
497 				const PipelineFlagsInstance::ShaderRecordEXT& rec = std::get<2>(records[i + 2]);
498 				sbt.updateAt(i, handles.data(), rec);
499 			}
500 		}
501 
502 		sbt.flush();
503 		buf	= sbt.get();
504 		rgn = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(m_vkd, m_device, **buf, 0),
505 																		sbt.getAlignment(),	m_testInstance.shaderGroupHandleSize);
506 
507 		return { de::SharedPtr<BufferWithMemory>(buf.release()), rgn };
508 	}
509 
510 private:
511 	Context&										m_context;
512 	const DeviceInterface&							m_vkd;
513 	const VkDevice									m_device;
514 	Allocator&										m_allocator;
515 	const PipelineFlagsInstance&					m_testInstance;
516 	const TestParams								m_params;
517 	Move<VkShaderModule>							m_rgenModule;
518 	Move<VkShaderModule>							m_chitModule;
519 	Move<VkShaderModule>							m_ahitModule;
520 	Move<VkShaderModule>							m_isectModule;
521 	Move<VkShaderModule>							m_missModule;
522 	Move<VkShaderModule>							m_gapModule;
523 	std::vector<de::SharedPtr<Move<VkPipeline>>>	m_libraries;
524 };
525 
526 template<class T, class P = T(*)[1], class R = decltype(std::begin(*std::declval<P>()))>
makeStdBeginEnd(T * p,deUint32 n)527 auto makeStdBeginEnd(T* p, deUint32 n) -> std::pair<R, R>
528 {
529 	auto tmp = std::begin(*P(p));
530 	auto begin = tmp;
531 	std::advance(tmp, n);
532 	return { begin, tmp };
533 }
534 
PipelineFlagsCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)535 PipelineFlagsCase::PipelineFlagsCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
536 	: TestCase					(testCtx, name, std::string())
537 	, shaderGroupHandleSize		(m_shaderGroupHandleSize)
538 	, shaderGroupBaseAlignment	(m_shaderGroupBaseAlignment)
539 	, m_params					(params)
540 	, m_rgenPayload				(0, ':', 0, 0)
541 	, m_defMissRetGreenComp		('-')
542 	, m_defTriRetGreenComp		('A')
543 	, m_defBoxRetGreenComp		(calcDefBoxRetGreenComp(params, m_defTriRetGreenComp))
544 {
545 }
546 
checkSupport(Context & context) const547 void PipelineFlagsCase::checkSupport (Context& context) const
548 {
549 	if ((VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR & m_params.flags)
550 		&& (GeometryTypes::Triangle == m_params.geomTypes))
551 	{
552 		TCU_THROW(InternalError, "Illegal params combination: VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR and Triangles");
553 	}
554 
555 	if (!context.isDeviceFunctionalitySupported("VK_KHR_ray_tracing_pipeline"))
556 		TCU_THROW(NotSupportedError, "VK_KHR_ray_tracing_pipeline not supported");
557 
558 	// VK_KHR_acceleration_structure is required by VK_KHR_ray_tracing_pipeline.
559 	if (!context.isDeviceFunctionalitySupported("VK_KHR_acceleration_structure"))
560 		TCU_FAIL("VK_KHR_acceleration_structure not supported but VK_KHR_ray_tracing_pipeline supported");
561 
562 	// The same for VK_KHR_buffer_device_address.
563 	if (!context.isDeviceFunctionalitySupported("VK_KHR_buffer_device_address"))
564 		TCU_FAIL("VK_KHR_buffer_device_address not supported but VK_KHR_acceleration_structure supported");
565 
566 	if (m_params.useLibs && !context.isDeviceFunctionalitySupported("VK_KHR_pipeline_library"))
567 		TCU_FAIL("VK_KHR_pipeline_library not supported but VK_KHR_ray_tracing_pipeline supported");
568 
569 	const VkPhysicalDeviceRayTracingPipelineFeaturesKHR& rayTracingPipelineFeaturesKHR = context.getRayTracingPipelineFeatures();
570 	if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == DE_FALSE)
571 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
572 
573 	const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
574 	if (accelerationStructureFeaturesKHR.accelerationStructure == DE_FALSE)
575 		TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
576 
577 	if (m_params.onHhost && accelerationStructureFeaturesKHR.accelerationStructureHostCommands == DE_FALSE)
578 		TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureHostCommands");
579 
580 	checkAccelerationStructureVertexBufferFormat(context.getInstanceInterface(), context.getPhysicalDevice(), VK_FORMAT_R32G32B32_SFLOAT);
581 
582 	auto rayTracingProperties	= makeRayTracingProperties(context.getInstanceInterface(), context.getPhysicalDevice());
583 	m_shaderGroupHandleSize		= rayTracingProperties->getShaderGroupHandleSize();
584 	m_shaderGroupBaseAlignment	= rayTracingProperties->getShaderGroupBaseAlignment();
585 }
586 
initPrograms(SourceCollections & programCollection) const587 void PipelineFlagsCase::initPrograms (SourceCollections& programCollection) const
588 {
589 	const vk::ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
590 	const char						endl			= '\n';
591 	const deUint32					missIdx			= 0;
592 
593 	const std::string				payloadInDecl	=
594 		"layout(location = 0) rayPayloadInEXT ivec4 payload;";
595 
596 	const std::string				recordDecl		=
597 		"layout(shaderRecordEXT, std430) buffer Rec {\n"
598 		"  uint  geomType;\n"
599 		"  uint  geomIndex;\n"
600 		"  ivec4 retValue;\n"
601 		"} record;";
602 
603 	{
604 		std::stringstream str;
605 		str << "#version 460 core"																			<< endl
606 			<< "#extension GL_EXT_ray_tracing : require"													<< endl
607 			<< "layout(location = 0) rayPayloadEXT ivec4 payload;"											<< endl
608 			<< "layout(rgba32i, set = 0, binding = 0) uniform iimage2D result;"								<< endl
609 			<< "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;"					<< endl
610 			<< "void main()"																				<< endl
611 			<< "{"																							<< endl
612 			<< "  float rx           = (float(gl_LaunchIDEXT.x * 2) / float(gl_LaunchSizeEXT.x)) - 1.0;"	<< endl
613 			<< "  float ry           = (float(gl_LaunchIDEXT.y) + 0.5) / float(gl_LaunchSizeEXT.y);"		<< endl
614 			<< "  payload            = ivec4" << m_rgenPayload << ";"										<< endl
615 			<< "  uint  rayFlags     = gl_RayFlagsNoneEXT;"													<< endl
616 			<< "  uint  cullMask     = 0xFFu;"																<< endl
617 			<< "  uint  stbRecOffset = " << m_params.stbRecOffset << "u;"									<< endl
618 			<< "  uint  stbRecStride = " << m_params.stbRecStride << "u;"									<< endl
619 			<< "  uint  missIdx      = " << missIdx << "u;"													<< endl
620 			<< "  vec3  orig         = vec3(rx, ry, 1.0);"													<< endl
621 			<< "  float tmin         = 0.0;"																<< endl
622 			<< "  vec3  dir          = vec3(0.0, 0.0, -1.0);"												<< endl
623 			<< "  float tmax         = 1000.0;"																<< endl
624 			<< "  traceRayEXT(topLevelAS, rayFlags, cullMask, stbRecOffset, stbRecStride, missIdx, orig, tmin, dir, tmax, 0);"	<< endl
625 			<< "  imageStore(result, ivec2(gl_LaunchIDEXT.xy), payload);"									<< endl
626 			<< "}";
627 		programCollection.glslSources.add("rgen") << glu::RaygenSource(str.str()) << buildOptions;
628 	}
629 
630 	// miss shader is created in each test regardless the m_params.miss() is set
631 	{
632 		std::stringstream str;
633 		str	<< "#version 460 core"							<< endl
634 			<< "#extension GL_EXT_ray_tracing : require"	<< endl
635 			<< payloadInDecl								<< endl
636 			<< recordDecl									<< endl
637 			<< "void main()"								<< endl
638 			<< "{"											<< endl
639 			<< "  payload = record.retValue;"				<< endl
640 			<< "}";
641 		programCollection.glslSources.add("miss") << glu::MissSource(str.str()) << buildOptions;
642 	}
643 
644 	// closest hit shader is created in each test regardless the m_params.chit() is set
645 	{
646 		std::stringstream str;
647 		str << "#version 460 core"														<< endl
648 			<< "#extension GL_EXT_ray_tracing : require"								<< endl
649 			<< "hitAttributeEXT ivec4 hitAttribute;"									<< endl
650 			<< payloadInDecl															<< endl
651 			<< recordDecl																<< endl
652 			<< "void main()"															<< endl
653 			<< "{"																		<< endl
654 			<< "  if (record.geomType == " << deUint32(GeometryTypes::Triangle) << ")"	<< endl
655 			<< "    payload = record.retValue;"											<< endl
656 			<< "  else payload = hitAttribute;"											<< endl
657 			<< "}";
658 		programCollection.glslSources.add("chit") << glu::ClosestHitSource(str.str()) << buildOptions;
659 	}
660 
661 	if (m_params.ahit())
662 	{
663 		std::stringstream str;
664 		str << "#version 460 core"							<< endl
665 			<< "#extension GL_EXT_ray_tracing : require"	<< endl
666 			<< recordDecl									<< endl
667 			<< "void main()"								<< endl
668 			<< "{"											<< endl
669 			<< "  if (record.geomIndex % 2 == 1)"			<< endl
670 			<< "    ignoreIntersectionEXT;"					<< endl
671 			<< "}";
672 		programCollection.glslSources.add("ahit") << glu::AnyHitSource(str.str()) << buildOptions;
673 	}
674 
675 	if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox))
676 	{
677 		std::stringstream str;
678 		str << "#version 460 core"								<< endl
679 			<< "#extension GL_EXT_ray_tracing : require"		<< endl
680 			<< "hitAttributeEXT ivec4 hitAttribute;"			<< endl
681 			<< recordDecl										<< endl
682 			<< "void main()"									<< endl
683 			<< "{"												<< endl
684 			<< "  hitAttribute = ivec4(record.retValue.x + 0"	<< endl
685 			<< "                      ,record.retValue.y + 2"	<< endl
686 			<< "                      ,record.retValue.z + 3"	<< endl
687 			<< "                      ,record.retValue.w + 4);"	<< endl
688 			<< "  reportIntersectionEXT(0.0, 0);"				<< endl
689 			<< "}";
690 		programCollection.glslSources.add("isect") << glu::IntersectionSource(str.str()) << buildOptions;
691 	}
692 }
693 
createInstance(Context & context) const694 TestInstance* PipelineFlagsCase::createInstance (Context& context) const
695 {
696 	return new PipelineFlagsInstance(context, m_params, shaderGroupHandleSize, shaderGroupBaseAlignment,
697 													m_rgenPayload, m_defMissRetGreenComp, m_defTriRetGreenComp, m_defBoxRetGreenComp);
698 }
699 
PipelineFlagsInstance(Context & context,const TestParams & params,const deUint32 & shaderGroupHandleSize_,const deUint32 & shaderGroupBaseAlignment_,const tcu::IVec4 & rgenPayload_,deInt32 defMissRetGreenComp_,deInt32 defTriRetGreenComp_,deInt32 defBoxRetGreenComp_)700 PipelineFlagsInstance::PipelineFlagsInstance (Context&			context,
701 											  const TestParams&	params,
702 											  const deUint32&	shaderGroupHandleSize_,
703 											  const deUint32&	shaderGroupBaseAlignment_,
704 											  const tcu::IVec4& rgenPayload_,
705 											  deInt32			defMissRetGreenComp_,
706 											  deInt32			defTriRetGreenComp_,
707 											  deInt32			defBoxRetGreenComp_)
708 	: TestInstance				(context)
709 	, rgenPayload				(rgenPayload_)
710 	, defMissRetGreenComp		(defMissRetGreenComp_)
711 	, defTriRetGreenComp		(defTriRetGreenComp_)
712 	, defBoxRetGreenComp		(defBoxRetGreenComp_)
713 	, shaderGroupHandleSize		(shaderGroupHandleSize_)
714 	, shaderGroupBaseAlignment	(shaderGroupBaseAlignment_)
715 	, m_params					(params)
716 	, m_format					(VK_FORMAT_R32G32B32A32_SINT)
717 {
718 }
719 
makeImageCreateInfo() const720 VkImageCreateInfo PipelineFlagsInstance::makeImageCreateInfo () const
721 {
722 	const deUint32				familyIndex		= m_context.getUniversalQueueFamilyIndex();
723 	const VkImageCreateInfo		imageCreateInfo	=
724 	{
725 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,																// VkStructureType			sType;
726 		DE_NULL,																							// const void*				pNext;
727 		(VkImageCreateFlags)0u,																				// VkImageCreateFlags		flags;
728 		VK_IMAGE_TYPE_2D,																					// VkImageType				imageType;
729 		m_format,																							// VkFormat					format;
730 		makeExtent3D(m_params.width, m_params.height, 1u),													// VkExtent3D				extent;
731 		1u,																									// deUint32					mipLevels;
732 		1u,																									// deUint32					arrayLayers;
733 		VK_SAMPLE_COUNT_1_BIT,																				// VkSampleCountFlagBits	samples;
734 		VK_IMAGE_TILING_OPTIMAL,																			// VkImageTiling			tiling;
735 		VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,		// VkImageUsageFlags		usage;
736 		VK_SHARING_MODE_EXCLUSIVE,																			// VkSharingMode			sharingMode;
737 		1u,																									// deUint32					queueFamilyIndexCount;
738 		&familyIndex,																						// const deUint32*			pQueueFamilyIndices;
739 		VK_IMAGE_LAYOUT_UNDEFINED																			// VkImageLayout			initialLayout;
740 	};
741 
742 	return imageCreateInfo;
743 }
744 
745 std::vector<PipelineFlagsInstance::TriGeometry>
prepareTriGeometries(const float zCoord) const746 PipelineFlagsInstance::prepareTriGeometries (const float zCoord) const
747 {
748 	const tcu::Vec3	center(-0.5f, 0.5f, zCoord);
749 	const tcu::Vec3	start(0.0f, 0.5f, zCoord);
750 	const deUint32 maxTriangles = m_params.instCount * m_params.geomCount;
751 	const deUint32 trianglesCount = deMaxu32(maxTriangles, 3);
752 	const float angle = (4.0f * std::acos(0.0f)) / float(trianglesCount);
753 
754 	tcu::Vec3	point(start);
755 	std::vector<TriGeometry> geometries(maxTriangles);
756 	for (deUint32 inst = 0, idx = 0; inst < m_params.instCount; ++inst)
757 	{
758 		for (deUint32 geom = 0; geom < m_params.geomCount; ++geom, ++idx)
759 		{
760 			TriGeometry& geometry = geometries[idx];
761 
762 			geometry[0] = center;
763 			geometry[1] = point;
764 			geometry[2] = (maxTriangles >= 3 && trianglesCount - idx == 1u) ? start : rotateCcwZ(point, center, angle);
765 
766 			point = geometry[2];
767 		}
768 	}
769 
770 	return geometries;
771 }
772 
773 std::vector<PipelineFlagsInstance::BoxGeometry>
prepareBoxGeometries(const float zFront,const float zBack) const774 PipelineFlagsInstance::prepareBoxGeometries (const float zFront, const float zBack) const
775 {
776 	const deUint32				maxBoxes	= m_params.instCount * m_params.geomCount;
777 
778 	std::vector<BoxGeometry>	boxes		(maxBoxes);
779 	deUint32					boxesPerDim	= 0u;
780 	float						boxWidth	= 0.0f;
781 	float						boxHeight	= 0.0f;
782 
783 	// find nearest square ceil number
784 	do
785 	{
786 		++boxesPerDim;
787 		boxWidth = 1.0f / float(boxesPerDim);
788 		boxHeight = 1.0f / float(boxesPerDim);
789 	} while (boxesPerDim * boxesPerDim < maxBoxes);
790 
791 	for (deUint32 boxY = 0, boxIdx = 0; boxY < boxesPerDim && boxIdx < maxBoxes; ++boxY)
792 	{
793 		for (deUint32 boxX = 0; boxX < boxesPerDim && boxIdx < maxBoxes; ++boxX, ++boxIdx)
794 		{
795 			const float x = float(boxX) * boxWidth;
796 			const float y = float(boxY) * boxHeight;
797 			BoxGeometry box = { { tcu::Vec3(x, y, zFront), tcu::Vec3((x + boxWidth), (y + boxHeight), zBack) } };
798 			boxes[boxIdx].swap(box);
799 		}
800 	}
801 
802 	return boxes;
803 }
804 
805 PipelineFlagsInstance::BottomLevelASPtrs
createBottomLevelAccelerationStructs(VkCommandBuffer cmdBuffer) const806 PipelineFlagsInstance::createBottomLevelAccelerationStructs (VkCommandBuffer cmdBuffer) const
807 {
808 	const DeviceInterface&		vkd			= m_context.getDeviceInterface();
809 	const VkDevice				device		= m_context.getDevice();
810 	Allocator&					allocator	= m_context.getDefaultAllocator();
811 	const VkGeometryFlagsKHR	geomFlags	= m_params.ahit() ? VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR : VK_GEOMETRY_OPAQUE_BIT_KHR;
812 
813 	BottomLevelASPtrs			result;
814 
815 	if (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)))
816 	{
817 		const auto	geometries = prepareTriGeometries(0.0f);
818 
819 		for (deUint32 inst = 0, idx = 0; inst < m_params.instCount; ++inst)
820 		{
821 			auto blas = makeBottomLevelAccelerationStructure();
822 			blas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR : VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR);
823 
824 			for (deUint32 geom = 0; geom < m_params.geomCount; ++geom, ++idx)
825 			{
826 				const TriGeometry& triangle = geometries[idx];
827 				blas->addGeometry(std::vector<tcu::Vec3>(triangle.begin(), triangle.end()), true, geomFlags);
828 			}
829 
830 			blas->createAndBuild(vkd, device, cmdBuffer, allocator);
831 			result.emplace_back(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
832 		}
833 	}
834 
835 	if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox))
836 	{
837 		const auto	geometries = prepareBoxGeometries(0.0f, 0.0f);
838 
839 		for (deUint32 inst = 0, idx = 0; inst < m_params.instCount; ++inst)
840 		{
841 			auto blas = makeBottomLevelAccelerationStructure();
842 			blas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR : VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR);
843 
844 			for (deUint32 geom = 0; geom < m_params.geomCount; ++geom, ++idx)
845 			{
846 				const BoxGeometry& box = geometries[idx];
847 				blas->addGeometry(std::vector<tcu::Vec3>(box.begin(), box.end()), false, geomFlags);
848 			}
849 
850 			blas->createAndBuild(vkd, device, cmdBuffer, allocator);
851 			result.emplace_back(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
852 		}
853 	}
854 
855 	return result;
856 }
857 
858 PipelineFlagsInstance::TopLevelASPtr
createTopLevelAccelerationStruct(VkCommandBuffer cmdBuffer,const BottomLevelASPtrs & blasPtrs) const859 PipelineFlagsInstance::createTopLevelAccelerationStruct (VkCommandBuffer cmdBuffer, const BottomLevelASPtrs& blasPtrs) const
860 {
861 	const DeviceInterface&	vkd							= m_context.getDeviceInterface();
862 	const VkDevice			device						= m_context.getDevice();
863 	Allocator&				allocator					= m_context.getDefaultAllocator();
864 	const deUint32			groupsAndGapsPerInstance	= computeEffectiveShaderGroupCount(m_params);
865 
866 	auto					tlas		= makeTopLevelAccelerationStructure();
867 
868 	tlas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR : VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR);
869 	tlas->setInstanceCount(blasPtrs.size());
870 	for (auto begin = blasPtrs.begin(), end = blasPtrs.end(), i = begin; i != end; ++i)
871 	{
872 		const deUint32 instanceShaderBindingTableRecordOffset = static_cast<deUint32>(std::distance(begin, i) * groupsAndGapsPerInstance);
873 		tlas->addInstance(*i, identityMatrix3x4, 0, 0xFF, instanceShaderBindingTableRecordOffset);
874 	}
875 	tlas->createAndBuild(vkd, device, cmdBuffer, allocator);
876 
877 	return TopLevelASPtr(tlas.release());
878 }
879 
prepareShaderBindingTable() const880 std::vector<PipelineFlagsInstance::ShaderRecordEntry> PipelineFlagsInstance::prepareShaderBindingTable() const
881 {
882 	const bool						includeTriangles = (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)));
883 	const bool						includeBoxes = (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox));
884 	const deUint32					groupsAndGapsPerInstance = computeEffectiveShaderGroupCount(m_params);
885 	const deUint32					commonGroupCount = 2; // general groups for rgen and miss
886 	const deUint32					triangleGroupCount = includeTriangles ? (groupsAndGapsPerInstance * m_params.instCount) : 0;
887 	const deUint32					proceduralGroupCount = includeBoxes ? (groupsAndGapsPerInstance * m_params.instCount) : 0;
888 	const deUint32					totalGroupCount = commonGroupCount + triangleGroupCount + proceduralGroupCount;
889 
890 	std::vector<ShaderRecordEntry>	shaderRecords(totalGroupCount);
891 
892 	shaderRecords[0] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( VK_SHADER_STAGE_RAYGEN_BIT_KHR, {}, {}, true );
893 	shaderRecords[1] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( VK_SHADER_STAGE_MISS_BIT_KHR, {}, { GeometryTypes::Box, (~0u), tcu::IVec4(0, defMissRetGreenComp, 0, 0) }, true );
894 
895 	de::SharedPtr<AnyHitShader>			ahit(new AnyHitShader);
896 	de::SharedPtr<ClosestHitShader>		chit(new ClosestHitShader);
897 	de::SharedPtr<IntersectionShader>	isect(new IntersectionShader);
898 
899 	if (includeTriangles)
900 	{
901 		std::set<deUint32>	usedIndexes;
902 		deInt32	greenComp = defTriRetGreenComp;
903 
904 		const deUint32 recordsToSkip = commonGroupCount;
905 
906 		for (deUint32 instance = 0; instance < m_params.instCount; ++instance)
907 		{
908 			const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
909 			for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
910 			{
911 				const deUint32 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset;
912 				if (usedIndexes.find(shaderGroupIndex) == usedIndexes.end())
913 				{
914 					HitGroup			hitGroup;
915 					VkShaderStageFlags	flags = 0;
916 					if (m_params.ahit()) {
917 						flags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
918 						hitGroup.ahit = ahit;
919 					}
920 					flags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
921 					hitGroup.chit = chit;
922 					shaderRecords[shaderGroupIndex] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( flags, hitGroup, { GeometryTypes::Triangle, geometryIndex, tcu::IVec4(0, greenComp++, 0, 0) }, true );
923 					usedIndexes.insert(shaderGroupIndex);
924 				}
925 			}
926 		}
927 	}
928 
929 	if (includeBoxes)
930 	{
931 		std::set<deUint32>	usedIndexes;
932 		deInt32	greenComp = defBoxRetGreenComp;
933 
934 		const deUint32 recordsToSkip = triangleGroupCount + commonGroupCount;
935 
936 		for (deUint32 instance = 0; instance < m_params.instCount; ++instance)
937 		{
938 			const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
939 			for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
940 			{
941 				const deUint32 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset;
942 				if (usedIndexes.find(shaderGroupIndex) == usedIndexes.end())
943 				{
944 					HitGroup			hitGroup;
945 					VkShaderStageFlags	flags = 0;
946 					if (m_params.ahit()) {
947 						flags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
948 						hitGroup.ahit = ahit;
949 					}
950 					flags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
951 					hitGroup.chit = chit;
952 					{ //In the case of AABB isect must be provided, otherwise we will process AABB with TRIANGLES_HIT_GROUP
953 						flags |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
954 						hitGroup.isect = isect;
955 					}
956 					shaderRecords[shaderGroupIndex] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>( flags, hitGroup, { GeometryTypes::Box, geometryIndex, tcu::IVec4(0, greenComp++, 0, 0) }, true );
957 					usedIndexes.insert(shaderGroupIndex);
958 				}
959 			}
960 		}
961 	}
962 
963 	return shaderRecords;
964 }
965 
rayToImage(const tcu::Vec2 & rayCoords) const966 tcu::IVec2 PipelineFlagsInstance::rayToImage(const tcu::Vec2& rayCoords) const
967 {
968 	return tcu::IVec2(
969 		deInt32(((rayCoords.x() + 1.0f) * float(m_params.width)) / 2.0f),
970 		deInt32((rayCoords.y() * float(m_params.height)) - 0.5f)
971 	);
972 }
973 
imageToRay(const tcu::IVec2 & imageCoords) const974 tcu::Vec2 PipelineFlagsInstance::imageToRay(const tcu::IVec2& imageCoords) const
975 {
976 	const float		rx = (float(imageCoords.x() * 2) / float(m_params.width)) - 1.0f;
977 	const float		ry = (float(imageCoords.y()) + 0.5f) / float(m_params.height);
978 	return tcu::Vec2(rx, ry);
979 }
980 
computeSamePixelCount(const std::vector<tcu::IVec4> & image,const tcu::Vec2 pixelCoords,const tcu::IVec4 & requiredColor,const tcu::IVec4 & floodColor,const std::function<bool (const tcu::Vec3 &)> & pointInGeometry,std::vector<std::pair<tcu::IVec4,tcu::IVec2>> & auxBuffer) const981 deUint32 PipelineFlagsInstance::computeSamePixelCount (const std::vector<tcu::IVec4>&						image,
982 																     const tcu::Vec2									pixelCoords,
983 																	 const tcu::IVec4&									requiredColor,
984 																	 const tcu::IVec4&									floodColor,
985 																	 const std::function<bool(const tcu::Vec3&)>&		pointInGeometry,
986 																	 std::vector<std::pair<tcu::IVec4, tcu::IVec2>>&	auxBuffer) const
987 {
988 	if (!pointInGeometry(tcu::Vec3(pixelCoords.x(), pixelCoords.y(), 0.0f))) return 0;
989 
990 	auxBuffer.resize(image.size() * 4);
991 	std::transform(image.begin(), image.end(), auxBuffer.begin(), [](const tcu::IVec4& c) -> std::pair<tcu::IVec4, tcu::IVec2> { return { c, tcu::IVec2() }; });
992 
993 	tcu::Vec2		rayCoord;
994 	tcu::IVec2		imageCoords = rayToImage(pixelCoords);
995 	deUint32		pixelIndex	= imageCoords.y() * m_params.width + imageCoords.x();
996 	tcu::IVec4		imageColor	= image[pixelIndex];
997 
998 	if (requiredColor != imageColor) return 0;
999 
1000 	deInt32			stackIndex	= 0;
1001 	deUint32		sameCount	= 1;
1002 	auxBuffer[stackIndex].second = imageCoords;
1003 
1004 	while (stackIndex >= 0)
1005 	{
1006 		imageCoords = auxBuffer[stackIndex].second;		--stackIndex;
1007 
1008 		if (imageCoords.x() < 0 || imageCoords.x() >= deInt32(m_params.width)
1009 			|| imageCoords.y() < 0 || imageCoords.y() >= deInt32(m_params.height)) continue;
1010 
1011 		rayCoord = imageToRay(imageCoords);
1012 		if (!pointInGeometry(tcu::Vec3(rayCoord.x(), rayCoord.y(), 0.0f))) continue;
1013 
1014 		pixelIndex = imageCoords.y() * m_params.width + imageCoords.x();
1015 		imageColor = auxBuffer[pixelIndex].first;
1016 		if (requiredColor != imageColor) continue;
1017 
1018 		auxBuffer[pixelIndex].first = floodColor;
1019 		sameCount += 1;
1020 
1021 		auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x() - 1, imageCoords.y());
1022 		auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x() + 1, imageCoords.y());
1023 		auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x(), imageCoords.y() - 1);
1024 		auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x(), imageCoords.y() + 1);
1025 	}
1026 
1027 	return sameCount;
1028 }
1029 
travelRay(std::vector<tcu::IVec4> & outImage,const deUint32 glLaunchIdExtX,const deUint32 glLaunchIdExtY,const std::vector<ShaderRecordEntry> & shaderBindingTable,const MissShader & missShader,const std::vector<TriGeometry> & triangleGeometries,const std::vector<BoxGeometry> & boxGeometries) const1030 void PipelineFlagsInstance::travelRay (std::vector<tcu::IVec4>&					outImage,
1031 									   const deUint32							glLaunchIdExtX,
1032 									   const deUint32							glLaunchIdExtY,
1033 									   const std::vector<ShaderRecordEntry>&	shaderBindingTable,
1034 									   const MissShader&						missShader,
1035 									   const std::vector<TriGeometry>&			triangleGeometries,
1036 									   const std::vector<BoxGeometry>&			boxGeometries) const
1037 {
1038 	const tcu::Vec2	rayCoords					= imageToRay(tcu::IVec2(glLaunchIdExtX, glLaunchIdExtY));
1039 	const bool		includeTriangles			= (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)));
1040 	const bool		includeBoxes				= (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox));
1041 	const deUint32	commonGroupCount			= 2; // general groups for rgen and miss
1042 	const deUint32	groupsAndGapsPerInstance	= computeEffectiveShaderGroupCount(m_params);
1043 	const deUint32	triangleGroupCount			= includeTriangles ? (groupsAndGapsPerInstance * m_params.instCount) : 0;
1044 
1045 	bool			hitHappened					(false);
1046 	deUint32		shaderGroupIndex			(~0u);
1047 	tcu::IVec4		payload						(rgenPayload);
1048 	const tcu::Vec3	origin						(rayCoords.x(), rayCoords.y(), 1.0f);
1049 
1050 	if (includeTriangles)
1051 	{
1052 		const deUint32 recordsToSkip = commonGroupCount;
1053 		for (deUint32 instance = 0; !hitHappened && (instance < m_params.instCount); ++instance)
1054 		{
1055 			const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
1056 			for (deUint32 geometryIndex = 0; !hitHappened && (geometryIndex < m_params.geomCount); ++geometryIndex)
1057 			{
1058 				const TriGeometry& geometry = triangleGeometries[instance * m_params.geomCount + geometryIndex];
1059 				shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset;
1060 				if (pointInTriangle2D(origin, geometry[0], geometry[1], geometry[2]))
1061 				{
1062 					hitHappened = true;
1063 				}
1064 			}
1065 		}
1066 	}
1067 
1068 	if (includeBoxes)
1069 	{
1070 		const deUint32 recordsToSkip = triangleGroupCount + commonGroupCount;
1071 		for (deUint32 instance = 0; !hitHappened && (instance < m_params.instCount); ++instance)
1072 		{
1073 			const deUint32 instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
1074 			for (deUint32 geometryIndex = 0; !hitHappened && (geometryIndex < m_params.geomCount); ++geometryIndex)
1075 			{
1076 				const BoxGeometry& geometry = boxGeometries[instance * m_params.geomCount + geometryIndex];
1077 				shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride + m_params.stbRecOffset;
1078 				if (pointInRect2D(origin, geometry[0], geometry[1]))
1079 				{
1080 					hitHappened = true;
1081 				}
1082 			}
1083 		}
1084 	}
1085 
1086 	if (hitHappened)
1087 	{
1088 		const ShaderRecordEXT&		shaderRecord	= std::get<2>(shaderBindingTable[shaderGroupIndex]);
1089 		const HitGroup&				hitGroup		= std::get<1>(shaderBindingTable[shaderGroupIndex]);
1090 		const VkShaderStageFlags	flags			= std::get<0>(shaderBindingTable[shaderGroupIndex]);
1091 		auto						hitAttribute	= rgenPayload;
1092 		bool						ignoreIsect		= false;
1093 
1094 		// check if the SBT entry was was initialized
1095 		DE_ASSERT(std::get<3>(shaderBindingTable[shaderGroupIndex]));
1096 
1097 		if (flags & VK_SHADER_STAGE_INTERSECTION_BIT_KHR)
1098 		{
1099 			hitAttribute = hitGroup.isect->invoke(IntersectionShader::dummyPayload, shaderRecord);
1100 		}
1101 		if (flags & VK_SHADER_STAGE_ANY_HIT_BIT_KHR)
1102 		{
1103 			ignoreIsect = hitGroup.ahit->ignoreIntersection(AnyHitShader::dummyPayload, shaderRecord);
1104 		}
1105 		if (ignoreIsect)
1106 		{
1107 			payload = missShader.invoke(MissShader::dummyPayload, std::get<2>(shaderBindingTable[1]));
1108 		}
1109 		else if (flags & VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)
1110 		{
1111 			payload = hitGroup.chit->invoke(hitAttribute, shaderRecord);
1112 		}
1113 	}
1114 	else
1115 	{
1116 		payload = missShader.invoke(MissShader::dummyPayload, std::get<2>(shaderBindingTable[1]));
1117 	}
1118 
1119 	outImage[glLaunchIdExtY * m_params.width + glLaunchIdExtX] = payload;
1120 }
1121 
1122 #ifdef INTERNAL_DEBUG
printImage(const tcu::IVec4 * image) const1123 void PipelineFlagsInstance::printImage(const tcu::IVec4* image) const
1124 {
1125 	for (deUint32 y = 0; y < m_params.height; ++y)
1126 	{
1127 		for (deUint32 x = 0; x < m_params.width; ++x)
1128 			std::cout << static_cast<char>(image[(m_params.height - y - 1) * m_params.width + x].y());
1129 		std::cout << std::endl;
1130 	}
1131 }
1132 #endif
1133 
verifyResult(const BufferWithMemory * resultBuffer) const1134 bool PipelineFlagsInstance::verifyResult (const BufferWithMemory* resultBuffer) const
1135 {
1136 	const auto								triangleGeometries	= prepareTriGeometries(0.0f);
1137 	const auto								boxGeometries		= prepareBoxGeometries(0.0f, 0.0f);
1138 
1139 	const bool								includeTriangles	= (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)));
1140 	const bool								includeBoxes		= (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox));
1141 
1142 	const tcu::IVec4*						resultImageData		= (tcu::IVec4*)(resultBuffer->getAllocation().getHostPtr());
1143 	auto									resultImageBounds	= makeStdBeginEnd(resultImageData, (m_params.width * m_params.height));
1144 	const std::vector<tcu::IVec4>			resultImage			(resultImageBounds.first, resultImageBounds.second);
1145 	std::vector<tcu::IVec4>					referenceImage		(m_params.width * m_params.height);
1146 
1147 	const std::vector<ShaderRecordEntry>	shaderBindingTable	= prepareShaderBindingTable();
1148 
1149 	MissShader								missShader{};
1150 
1151 	// perform offline ray-tracing
1152 	for (deUint32 glLaunchIdExtY = 0; glLaunchIdExtY < m_params.height; ++glLaunchIdExtY)
1153 	{
1154 		for (deUint32 glLaunchIdExtX = 0; glLaunchIdExtX < m_params.width; ++glLaunchIdExtX)
1155 		{
1156 			travelRay(referenceImage, glLaunchIdExtX, glLaunchIdExtY,
1157 					 shaderBindingTable, missShader,
1158 					 triangleGeometries, boxGeometries);
1159 		}
1160 	}
1161 
1162 #ifdef INTERNAL_DEBUG
1163 	std::cout << "===== RES =====" << std::endl;
1164 	printImage(resultImageData);
1165 	std::cout << std::endl;
1166 	std::cout << "===== REF =====" << std::endl;
1167 	printImage(referenceImage.data());
1168 	std::cout << std::endl;
1169 #endif
1170 
1171 	const tcu::IVec4								floodColor(0, '*', 0, 0);
1172 	std::vector<std::pair<tcu::IVec4, tcu::IVec2>>	auxBuffer(referenceImage.size() * 4);
1173 
1174 	if (includeTriangles)
1175 	{
1176 		TriGeometry								tri;
1177 		std::function<bool(const tcu::Vec3&)>	pointInGeometry = std::bind(pointInTriangle2D, std::placeholders::_1, std::ref(tri[0]), std::ref(tri[1]), std::ref(tri[2]));
1178 
1179 		for (deUint32 instance = 0; instance < m_params.instCount; ++instance)
1180 		{
1181 			for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
1182 			{
1183 				if (!(m_params.ahit() && (geometryIndex % 2 == 1)))
1184 				{
1185 					tri = triangleGeometries[instance * m_params.geomCount + geometryIndex];
1186 					const tcu::Vec2 center((tri[0].x() + tri[1].x() + tri[2].x()) / 3.0f, (tri[0].y() + tri[1].y() + tri[2].y()) / 3.0f);
1187 
1188 					const tcu::IVec2	refImageCoords	= rayToImage(center);
1189 					const tcu::IVec4	requiredColor	= referenceImage[refImageCoords.y() * m_params.width + refImageCoords.x()];
1190 
1191 					deUint32 resultPixelCount = computeSamePixelCount(resultImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer);
1192 					deUint32 referencePixelCount = computeSamePixelCount(referenceImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer);
1193 
1194 					if (!resultPixelCount || !referencePixelCount) return false;
1195 					if (resultPixelCount > referencePixelCount) std::swap(resultPixelCount, referencePixelCount);
1196 
1197 					const float similarity = float(resultPixelCount) / float(referencePixelCount);
1198 					if (similarity < m_params.accuracy) return false;
1199 				}
1200 			}
1201 		}
1202 	}
1203 
1204 	if (includeBoxes)
1205 	{
1206 		BoxGeometry								box;
1207 		std::function<bool(const tcu::Vec3&)>	pointInGeometry = std::bind(pointInRect2D, std::placeholders::_1, std::ref(box[0]), std::ref(box[1]));
1208 
1209 		for (deUint32 instance = 0; instance < m_params.instCount; ++instance)
1210 		{
1211 			for (deUint32 geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
1212 			{
1213 				if (!(m_params.ahit() && (geometryIndex % 2 == 1)))
1214 				{
1215 					box = boxGeometries[instance * m_params.geomCount + geometryIndex];
1216 					const tcu::Vec2 center((box[0].x() + box[1].x()) / 2.0f, (box[0].y() + box[1].y()) / 2.0f);
1217 
1218 					const tcu::IVec2	refImageCoords = rayToImage(center);
1219 					const tcu::IVec4	requiredColor = referenceImage[refImageCoords.y() * m_params.width + refImageCoords.x()];
1220 
1221 					deUint32 resultPixelCount = computeSamePixelCount(resultImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer);
1222 					deUint32 referencePixelCount = computeSamePixelCount(referenceImage, center, requiredColor, floodColor, pointInGeometry, auxBuffer);
1223 
1224 					if (!resultPixelCount || !referencePixelCount) return false;
1225 					if (resultPixelCount > referencePixelCount) std::swap(resultPixelCount, referencePixelCount);
1226 
1227 					const float similarity = float(resultPixelCount) / float(referencePixelCount);
1228 					if (similarity < m_params.accuracy) return false;
1229 				}
1230 			}
1231 		}
1232 	}
1233 
1234 	return true;
1235 }
1236 
iterate(void)1237 tcu::TestStatus PipelineFlagsInstance::iterate(void)
1238 {
1239 	const DeviceInterface& vkd = m_context.getDeviceInterface();
1240 	const VkDevice							device = m_context.getDevice();
1241 	const deUint32							familyIndex = m_context.getUniversalQueueFamilyIndex();
1242 	const VkQueue							queue = m_context.getUniversalQueue();
1243 	Allocator& allocator = m_context.getDefaultAllocator();
1244 
1245 	const VkImageCreateInfo					imageCreateInfo = makeImageCreateInfo();
1246 	const VkImageSubresourceRange			imageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
1247 	const de::MovePtr<ImageWithMemory>		image = de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
1248 	const Move<VkImageView>					imageView = makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_2D, m_format, imageSubresourceRange);
1249 	const VkDescriptorImageInfo				descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
1250 
1251 	const deUint32							resultBufferSize = (m_params.width * m_params.height * mapVkFormat(m_format).getPixelSize());
1252 	const VkBufferCreateInfo				resultBufferCreateInfo = makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1253 	const VkImageSubresourceLayers			resultBufferImageSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
1254 	const VkBufferImageCopy					resultBufferImageRegion = makeBufferImageCopy(makeExtent3D(m_params.width, m_params.height, 1u), resultBufferImageSubresourceLayers);
1255 	de::MovePtr<BufferWithMemory>			resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
1256 
1257 	const Move<VkDescriptorSetLayout>		descriptorSetLayout = DescriptorSetLayoutBuilder()
1258 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
1259 		.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
1260 		.build(vkd, device);
1261 	const Move<VkDescriptorPool>			descriptorPool = DescriptorPoolBuilder()
1262 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1263 		.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
1264 		.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1265 	const Move<VkDescriptorSet>				descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
1266 
1267 	de::MovePtr<RayTracingTestPipeline>		rayTracingPipeline = de::newMovePtr<RayTracingTestPipeline>(std::ref(m_context), std::cref(*this), m_params);
1268 
1269 	const Move<VkPipelineLayout>			pipelineLayout = makePipelineLayout(vkd, device, *descriptorSetLayout);
1270 	Move<VkPipeline>						pipeline = rayTracingPipeline->createPipeline(*pipelineLayout);
1271 
1272 	de::SharedPtr<BufferWithMemory>			raygenShaderBindingTable;
1273 	VkStridedDeviceAddressRegionKHR			raygenShaderBindingTableRegion;
1274 	std::tie(raygenShaderBindingTable, raygenShaderBindingTableRegion) = rayTracingPipeline->createRaygenShaderBindingTable(*pipeline);
1275 
1276 	de::SharedPtr<BufferWithMemory>			missShaderBindingTable;
1277 	VkStridedDeviceAddressRegionKHR			missShaderBindingTableRegion;
1278 	std::tie(missShaderBindingTable, missShaderBindingTableRegion) = rayTracingPipeline->createMissShaderBindingTable(*pipeline);
1279 
1280 	de::SharedPtr<BufferWithMemory>			hitShaderBindingTable;
1281 	VkStridedDeviceAddressRegionKHR			hitShaderBindingTableRegion;
1282 	std::tie(hitShaderBindingTable, hitShaderBindingTableRegion) = rayTracingPipeline->createHitShaderBindingTable(*pipeline);
1283 
1284 	const VkStridedDeviceAddressRegionKHR	callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
1285 
1286 	const Move<VkCommandPool>				cmdPool = createCommandPool(vkd, device, 0, familyIndex);
1287 	const Move<VkCommandBuffer>				cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1288 
1289 	beginCommandBuffer(vkd, *cmdBuffer);
1290 
1291 	BottomLevelASPtrs						blasPtrs = createBottomLevelAccelerationStructs(*cmdBuffer);
1292 	TopLevelASPtr							tlasPtr = createTopLevelAccelerationStruct(*cmdBuffer, blasPtrs);
1293 
1294 	VkWriteDescriptorSetAccelerationStructureKHR	accelerationStructureWriteDescriptorSet =
1295 	{
1296 		VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,	//  VkStructureType						sType;
1297 		DE_NULL,															//  const void*							pNext;
1298 		1u,																	//  deUint32							accelerationStructureCount;
1299 		tlasPtr->getPtr()													//  const VkAccelerationStructureKHR*	pAccelerationStructures;
1300 	};
1301 
1302 	DescriptorSetUpdateBuilder()
1303 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
1304 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
1305 		.update(vkd, device);
1306 
1307 	vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL);
1308 
1309 	vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
1310 
1311 	const VkImageSubresourceRange	subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1312 	const VkImageMemoryBarrier				imageMemoryBarrier = makeImageMemoryBarrier(VK_ACCESS_NONE, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, image->get(), subresourceRange);
1313 	cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &imageMemoryBarrier);
1314 
1315 	cmdTraceRays(vkd,
1316 		*cmdBuffer,
1317 		&raygenShaderBindingTableRegion,	// rgen
1318 		&missShaderBindingTableRegion,		// miss
1319 		&hitShaderBindingTableRegion,		// hit
1320 		&callableShaderBindingTableRegion,	// call
1321 		m_params.width, m_params.height, 1);
1322 
1323 	const VkMemoryBarrier				postTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
1324 	const VkMemoryBarrier				postCopyMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1325 	cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
1326 
1327 	vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **resultBuffer, 1u, &resultBufferImageRegion);
1328 
1329 	cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyMemoryBarrier);
1330 
1331 	endCommandBuffer(vkd, *cmdBuffer);
1332 
1333 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
1334 
1335 	invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(), resultBuffer->getAllocation().getOffset(), resultBufferSize);
1336 
1337 	return verifyResult(resultBuffer.get()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
1338 }
1339 
1340 class NoNullShadersFlagGenerator
1341 {
1342 public:
1343 	using FlagsSet = std::set<VkPipelineCreateFlags>;
1344 	struct BitAndName {
1345 		VkPipelineCreateFlagBits	bit;
1346 		const char* name;
1347 	};
1348 	static const BitAndName	bits[4];
name(VkPipelineCreateFlags flags)1349 	static std::string	name (VkPipelineCreateFlags flags) {
1350 		int count = 0;
1351 		std::stringstream ss;
1352 		for (auto begin = std::begin(bits), end = std::end(bits), i = begin; i != end; ++i) {
1353 			if (flags & i->bit) {
1354 				if (count++) ss << "_or_";
1355 				ss << i->name;
1356 			}
1357 		}
1358 		return count ? ss.str() : "none";
1359 	}
mask(const FlagsSet & flags)1360 	static VkPipelineCreateFlags mask (const FlagsSet& flags) {
1361 		VkPipelineCreateFlags result{};
1362 		for (auto f : flags) result |= f;
1363 		return result;
1364 	}
NoNullShadersFlagGenerator()1365 	NoNullShadersFlagGenerator() : m_next(0) {
1366 		FlagsSet fs;
1367 		for (const auto& b : bits) fs.insert(b.bit);
1368 		combine(m_combs, fs);
1369 	}
reset()1370 	void	reset() { m_next = 0; }
next(VkPipelineCreateFlags & flags)1371 	bool	next(VkPipelineCreateFlags& flags) {
1372 		if (m_next < m_combs.size()) {
1373 			flags = mask(m_combs[m_next++]);
1374 			return true;
1375 		}
1376 		return false;
1377 	}
combine(std::vector<FlagsSet> & result,const FlagsSet & v)1378 	void combine(std::vector<FlagsSet>& result, const FlagsSet& v) {
1379 		if (v.empty() || result.end() != std::find(result.begin(), result.end(), v)) return;
1380 		result.push_back(v);
1381 		for (deUint32 i = 0; i < v.size(); ++i) {
1382 			FlagsSet w(v);
1383 			w.erase(std::next(w.begin(), i));
1384 			combine(result, w);
1385 		}
1386 	}
1387 private:
1388 	size_t					m_next;
1389 	std::vector<FlagsSet>	m_combs;
1390 };
1391 const NoNullShadersFlagGenerator::BitAndName	NoNullShadersFlagGenerator::bits[] = {
1392 	{ VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR,		"any"	},
1393 	{ VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR,	"chit"	},
1394 	{ VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR,	"isect"	},
1395 	{ VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR,			"miss"	},
1396 };
1397 
1398 } // unnamed
1399 
createPipelineFlagsTests(tcu::TestContext & testCtx)1400 tcu::TestCaseGroup*	createPipelineFlagsTests (tcu::TestContext& testCtx)
1401 {
1402 	const deUint32 strides[] = { 3, 5 };
1403 	const deUint32 offsets[] = { 7 };
1404 
1405 	struct {
1406 		bool		type;
1407 		const char*	name;
1408 	} const processors[] = { { false, "gpu" }, { true, "cpu" } };
1409 	struct {
1410 		bool		type;
1411 		const char* name;
1412 	} const libs[]{ { true, "use_libs" }, { false, "no_libs" } };
1413 	struct {
1414 		GeometryTypes	type;
1415 		const char*		name;
1416 	} const geometries[] = { { GeometryTypes::Triangle, "triangles" }, { GeometryTypes::Box, "boxes" }, { GeometryTypes::TriangleAndBox, "tri_and_box" } };
1417 
1418 	NoNullShadersFlagGenerator	flagsGenerator;
1419 
1420 	TestParams		p;
1421 #ifdef INTERNAL_DEBUG
1422 	p.width			= 30;
1423 	p.height		= 8;
1424 	p.accuracy		= 0.80f;
1425 #else
1426 	p.width			= 256;
1427 	p.height		= 256;
1428 	p.accuracy		= 0.95f;
1429 #endif
1430 	p.onHhost		= false;
1431 	p.useLibs		= false;
1432 	p.flags			= 0;
1433 	p.geomTypes		= GeometryTypes::None;
1434 	p.instCount		= 3;
1435 	p.geomCount		= 2;
1436 	p.stbRecStride	= 0;
1437 	p.stbRecOffset	= 0;
1438 
1439 	auto group = new tcu::TestCaseGroup(testCtx, "pipeline_no_null_shaders_flag", "Pipeline NO_NULL_*_SHADER flags tests");
1440 
1441 	for (auto& processor : processors)
1442 	{
1443 		auto processorGroup = new tcu::TestCaseGroup(testCtx, processor.name, "");
1444 
1445 		for (auto& geometry : geometries)
1446 		{
1447 			auto geometryGroup = new tcu::TestCaseGroup(testCtx, geometry.name, "");
1448 
1449 			for (auto& stride : strides)
1450 			{
1451 				auto strideGroup = new tcu::TestCaseGroup(testCtx, ("stride_" + std::to_string(stride)).c_str(), "");
1452 
1453 				for (auto& offset : offsets)
1454 				{
1455 					auto offsetGroup = new tcu::TestCaseGroup(testCtx, ("offset_" + std::to_string(offset)).c_str(), "");
1456 
1457 					for (auto& lib : libs)
1458 					{
1459 						auto libGroup = new tcu::TestCaseGroup(testCtx, lib.name, "");
1460 
1461 						VkPipelineCreateFlags	flags;
1462 
1463 						flagsGenerator.reset();
1464 
1465 						while (flagsGenerator.next(flags))
1466 						{
1467 							if ((VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR & flags)
1468 								&& (GeometryTypes::Triangle == geometry.type)) continue;
1469 
1470 							p.onHhost		= processor.type;
1471 							p.geomTypes		= geometry.type;
1472 							p.stbRecStride	= stride;
1473 							p.stbRecOffset	= offset;
1474 							p.flags			= flags;
1475 							p.useLibs		= lib.type;
1476 
1477 							libGroup->addChild(new PipelineFlagsCase(testCtx, flagsGenerator.name(flags), p));
1478 						}
1479 						offsetGroup->addChild(libGroup);
1480 					}
1481 					strideGroup->addChild(offsetGroup);
1482 				}
1483 				geometryGroup->addChild(strideGroup);
1484 			}
1485 			processorGroup->addChild(geometryGroup);
1486 		}
1487 		group->addChild(processorGroup);
1488 	}
1489 
1490 	return group;
1491 }
1492 
1493 }	// RayTracing
1494 }	// vkt
1495