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