• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  * Copyright (c) 2022 Valve Corporation.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief VK_EXT_shader_module_identifier tests
25  *//*--------------------------------------------------------------------*/
26 #include "vktPipelineShaderModuleIdentifierTests.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 
31 #include "vkQueryUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkObjUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkRayTracingUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkPipelineConstructionUtil.hpp"
42 #include "vkBarrierUtil.hpp"
43 
44 #include "tcuMaybe.hpp"
45 #include "tcuCommandLine.hpp"
46 #include "tcuFormatUtil.hpp"
47 #include "tcuImageCompare.hpp"
48 #include "tcuTestLog.hpp"
49 
50 #include "deUniquePtr.hpp"
51 #include "deRandom.hpp"
52 
53 #include <vector>
54 #include <utility>
55 #include <string>
56 #include <sstream>
57 #include <algorithm>
58 #include <iterator>
59 #include <memory>
60 #include <set>
61 #include <limits>
62 
63 namespace vkt
64 {
65 namespace pipeline
66 {
67 
68 namespace
69 {
70 
71 using GroupPtr	= de::MovePtr<tcu::TestCaseGroup>;
72 using StringVec	= std::vector<std::string>;
73 using namespace vk;
74 
75 using ShaderModuleId	= std::vector<uint8_t>;
76 using ShaderModuleIdPtr	= std::unique_ptr<ShaderModuleId>;
77 using ShaderStageIdPtr	= std::unique_ptr<VkPipelineShaderStageModuleIdentifierCreateInfoEXT>;
78 
79 // Helper function to create a shader module identifier from a VkShaderModuleIdentifierEXT structure.
makeShaderModuleId(const VkShaderModuleIdentifierEXT & idExt)80 ShaderModuleId makeShaderModuleId (const VkShaderModuleIdentifierEXT& idExt)
81 {
82 	if (idExt.identifierSize == 0u || idExt.identifierSize > VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT)
83 		TCU_FAIL("Invalid identifierSize returned");
84 
85 	ShaderModuleId identifier(idExt.identifier, idExt.identifier + idExt.identifierSize);
86 	return identifier;
87 }
88 
89 // Helper function to obtain the shader module identifier for a VkShaderModule as a return value.
getShaderModuleIdentifier(const DeviceInterface & vkd,const VkDevice device,const VkShaderModule module)90 ShaderModuleId getShaderModuleIdentifier (const DeviceInterface& vkd, const VkDevice device, const VkShaderModule module)
91 {
92 	VkShaderModuleIdentifierEXT idExt = initVulkanStructure();
93 	vkd.getShaderModuleIdentifierEXT(device, module, &idExt);
94 	return makeShaderModuleId(idExt);
95 }
96 
97 // Helper function to obtain the shader module identifier from a VkShaderModuleCreateInfo structure as a return value.
getShaderModuleIdentifier(const DeviceInterface & vkd,const VkDevice device,const VkShaderModuleCreateInfo & createInfo)98 ShaderModuleId getShaderModuleIdentifier (const DeviceInterface& vkd, const VkDevice device, const VkShaderModuleCreateInfo& createInfo)
99 {
100 	VkShaderModuleIdentifierEXT idExt = initVulkanStructure();
101 	vkd.getShaderModuleCreateInfoIdentifierEXT(device, &createInfo, &idExt);
102 	return makeShaderModuleId(idExt);
103 }
104 
105 // Helper function to create a VkShaderModuleCreateInfo structure.
makeShaderModuleCreateInfo(size_t codeSize,const uint32_t * pCode,const VkShaderModuleCreateFlags createFlags=0u,const void * pNext=nullptr)106 VkShaderModuleCreateInfo makeShaderModuleCreateInfo (size_t codeSize, const uint32_t* pCode, const VkShaderModuleCreateFlags createFlags = 0u, const void* pNext = nullptr)
107 {
108 	const VkShaderModuleCreateInfo moduleCreateInfo =
109 	{
110 		VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,	//	VkStructureType				sType;
111 		pNext,											//	const void*					pNext;
112 		createFlags,									//	VkShaderModuleCreateFlags	flags;
113 		codeSize,										//	size_t						codeSize;
114 		pCode,											//	const uint32_t*				pCode;
115 	};
116 	return moduleCreateInfo;
117 }
118 
119 // On the actual pipeline in use, will we use module IDs or other data?
120 enum class UseModuleCase
121 {
122 	ID = 0,
123 	ZERO_LEN_ID,
124 	ZERO_LEN_ID_NULL_PTR,
125 	ZERO_LEN_ID_GARBAGE_PTR,
126 	ALL_ZEROS,
127 	ALL_ONES,
128 	PSEUDORANDOM_ID,
129 };
130 
isZeroLen(UseModuleCase usage)131 bool isZeroLen (UseModuleCase usage)
132 {
133 	bool zeroLen = false;
134 
135 	switch (usage)
136 	{
137 	case UseModuleCase::ZERO_LEN_ID:
138 	case UseModuleCase::ZERO_LEN_ID_NULL_PTR:
139 	case UseModuleCase::ZERO_LEN_ID_GARBAGE_PTR:
140 		zeroLen = true;
141 		break;
142 	default:
143 		break;
144 	}
145 
146 	return zeroLen;
147 }
148 
expectCacheMiss(UseModuleCase usage)149 bool expectCacheMiss (UseModuleCase usage)
150 {
151 	bool miss = false;
152 
153 	switch (usage)
154 	{
155 	case UseModuleCase::ALL_ZEROS:
156 	case UseModuleCase::ALL_ONES:
157 	case UseModuleCase::PSEUDORANDOM_ID:
158 		miss = true;
159 		break;
160 	default:
161 		break;
162 	}
163 
164 	return miss;
165 }
166 
167 // Modify a shader module id according to the type of use.
maybeMangleShaderModuleId(ShaderModuleId & moduleId,UseModuleCase moduleUse,de::Random & rnd)168 void maybeMangleShaderModuleId (ShaderModuleId& moduleId, UseModuleCase moduleUse, de::Random& rnd)
169 {
170 	if (moduleUse == UseModuleCase::ALL_ZEROS || moduleUse == UseModuleCase::ALL_ONES)
171 	{
172 		deMemset(moduleId.data(), ((moduleUse == UseModuleCase::ALL_ZEROS) ? 0 : 0xFF), de::dataSize(moduleId));
173 	}
174 	else if (moduleUse == UseModuleCase::PSEUDORANDOM_ID)
175 	{
176 		for (auto& byte : moduleId)
177 			byte = rnd.getUint8();
178 	}
179 }
180 
181 // Helper function to create a VkPipelineShaderStageModuleIdentifierCreateInfoEXT structure.
makeShaderStageModuleIdentifierCreateInfo(const ShaderModuleId & moduleId,UseModuleCase moduleUse,de::Random * rnd=nullptr)182 ShaderStageIdPtr makeShaderStageModuleIdentifierCreateInfo (const ShaderModuleId& moduleId, UseModuleCase moduleUse, de::Random* rnd = nullptr)
183 {
184 	ShaderStageIdPtr createInfo(new VkPipelineShaderStageModuleIdentifierCreateInfoEXT(initVulkanStructure()));
185 
186 	createInfo->identifierSize = (isZeroLen(moduleUse) ? 0u : de::sizeU32(moduleId));
187 
188 	switch (moduleUse)
189 	{
190 	case UseModuleCase::ID:
191 	case UseModuleCase::ZERO_LEN_ID:
192 	case UseModuleCase::ALL_ZEROS: // For this one and below, the module id will have been modified outside.
193 	case UseModuleCase::ALL_ONES:
194 	case UseModuleCase::PSEUDORANDOM_ID:
195 		createInfo->pIdentifier = de::dataOrNull(moduleId);
196 		break;
197 	case UseModuleCase::ZERO_LEN_ID_NULL_PTR:
198 		break; // Already null as part of initVulkanStructure().
199 	case UseModuleCase::ZERO_LEN_ID_GARBAGE_PTR:
200 		{
201 			DE_ASSERT(rnd);
202 
203 			// Fill pointer with random bytes.
204 			auto pIdentifierPtr = reinterpret_cast<uint8_t*>(&(createInfo->pIdentifier));
205 
206 			for (size_t i = 0; i < sizeof(createInfo->pIdentifier); ++i)
207 				pIdentifierPtr[i] = rnd->getUint8();
208 		}
209 		break;
210 	default:
211 		DE_ASSERT(false);
212 		break;
213 	}
214 
215 	return createInfo;
216 }
217 
retUsedModule(ShaderWrapper * module,UseModuleCase moduleUse)218 ShaderWrapper* retUsedModule (ShaderWrapper* module, UseModuleCase moduleUse)
219 {
220 	static ShaderWrapper emptyWrapper = ShaderWrapper();
221 	return (isZeroLen(moduleUse) ? module : &emptyWrapper);
222 }
223 
224 enum class PipelineType
225 {
226 	COMPUTE = 0,
227 	GRAPHICS,
228 	RAY_TRACING,
229 };
230 
231 enum class GraphicsShaderType
232 {
233 	VERTEX = 0,
234 	TESS_CONTROL,
235 	TESS_EVAL,
236 	GEOMETRY,
237 	FRAG,
238 };
239 
240 enum class RayTracingShaderType
241 {
242 	RAY_GEN = 0,
243 	CLOSEST_HIT,
244 	ANY_HIT,
245 	INTERSECTION,
246 	MISS,
247 	CALLABLE,
248 };
249 
250 using GraphicsShaderVec	= std::vector<GraphicsShaderType>;
251 using RTShaderVec		= std::vector<RayTracingShaderType>;
252 
operator <<(std::ostream & out,GraphicsShaderType type)253 std::ostream& operator<<(std::ostream& out, GraphicsShaderType type)
254 {
255 	switch (type)
256 	{
257 	case GraphicsShaderType::VERTEX:			out << "vert";		break;
258 	case GraphicsShaderType::TESS_CONTROL:		out << "tesc";		break;
259 	case GraphicsShaderType::TESS_EVAL:			out << "tese";		break;
260 	case GraphicsShaderType::GEOMETRY:			out << "geom";		break;
261 	case GraphicsShaderType::FRAG:				out << "frag";		break;
262 	default:
263 		DE_ASSERT(false);
264 		break;
265 	}
266 	return out;
267 }
268 
operator <<(std::ostream & out,RayTracingShaderType type)269 std::ostream& operator<<(std::ostream& out, RayTracingShaderType type)
270 {
271 	switch (type)
272 	{
273 	case RayTracingShaderType::RAY_GEN:			out << "rgen";		break;
274 	case RayTracingShaderType::CLOSEST_HIT:		out << "chit";		break;
275 	case RayTracingShaderType::ANY_HIT:			out << "ahit";		break;
276 	case RayTracingShaderType::INTERSECTION:	out << "isec";		break;
277 	case RayTracingShaderType::MISS:			out << "miss";		break;
278 	case RayTracingShaderType::CALLABLE:		out << "call";		break;
279 	default:
280 		DE_ASSERT(false);
281 		break;
282 	}
283 	return out;
284 }
285 
286 template <class T>
toString(const std::vector<T> & vec)287 std::string toString(const std::vector<T>& vec)
288 {
289 	std::ostringstream out;
290 	for (size_t i = 0; i < vec.size(); ++i)
291 		out << ((i == 0) ? "" : "_") << vec.at(i);
292 	return out.str();
293 }
294 
295 // Pipeline executable properties helpers.
296 struct PipelineExecutableStat
297 {
PipelineExecutableStatvkt::pipeline::__anon8967aaa10111::PipelineExecutableStat298 	PipelineExecutableStat (std::string name_, std::string description_, VkPipelineExecutableStatisticFormatKHR format_, VkPipelineExecutableStatisticValueKHR value_)
299 		: name			(std::move(name_))
300 		, description	(std::move(description_))
301 		, format		(format_)
302 		, value			(value_)
303 		{}
304 
305 	const std::string								name;
306 	const std::string								description;
307 	const VkPipelineExecutableStatisticFormatKHR	format;
308 	const VkPipelineExecutableStatisticValueKHR		value;
309 };
310 
311 struct PipelineExecutableInternalRepresentation
312 {
PipelineExecutableInternalRepresentationvkt::pipeline::__anon8967aaa10111::PipelineExecutableInternalRepresentation313 	PipelineExecutableInternalRepresentation (std::string name_, std::string description_, bool isText_, const std::vector<uint8_t>& data)
314 		: name			(std::move(name_))
315 		, description	(std::move(description_))
316 		, m_isText		(isText_)
317 		, m_text		()
318 		, m_bytes		()
319 	{
320 		if (m_isText)
321 			m_text = std::string(reinterpret_cast<const char*>(data.data()));
322 		else
323 			m_bytes = data;
324 	}
325 
326 	const std::string name;
327 	const std::string description;
328 
isTextvkt::pipeline::__anon8967aaa10111::PipelineExecutableInternalRepresentation329 	bool						isText		(void) const { return m_isText; }
getTextvkt::pipeline::__anon8967aaa10111::PipelineExecutableInternalRepresentation330 	const std::string&			getText		(void) const { DE_ASSERT(isText()); return m_text; }
getBytesvkt::pipeline::__anon8967aaa10111::PipelineExecutableInternalRepresentation331 	const std::vector<uint8_t>&	getBytes	(void) const { DE_ASSERT(!isText()); return m_bytes; }
332 
333 protected:
334 	const bool				m_isText;
335 	std::string				m_text;
336 	std::vector<uint8_t>	m_bytes;
337 };
338 
339 struct PipelineExecutableProperty
340 {
PipelineExecutablePropertyvkt::pipeline::__anon8967aaa10111::PipelineExecutableProperty341 	PipelineExecutableProperty (VkShaderStageFlags stageFlags_, std::string name_, std::string description_, uint32_t subgroupSize_)
342 		: stageFlags	(stageFlags_)
343 		, name			(std::move(name_))
344 		, description	(std::move(description_))
345 		, subgroupSize	(subgroupSize_)
346 		, m_stats		()
347 		, m_irs			()
348 		{}
349 
350 	const VkShaderStageFlags	stageFlags;
351 	const std::string			name;
352 	const std::string			description;
353 	const uint32_t				subgroupSize;
354 
addStatvkt::pipeline::__anon8967aaa10111::PipelineExecutableProperty355 	void addStat	(const PipelineExecutableStat& stat)					{ m_stats.emplace_back(stat); }
addIRvkt::pipeline::__anon8967aaa10111::PipelineExecutableProperty356 	void addIR		(const PipelineExecutableInternalRepresentation& ir)	{ m_irs.emplace_back(ir); }
357 
getStatsvkt::pipeline::__anon8967aaa10111::PipelineExecutableProperty358 	const std::vector<PipelineExecutableStat>&						getStats	(void) const { return m_stats; }
getIRsvkt::pipeline::__anon8967aaa10111::PipelineExecutableProperty359 	const std::vector<PipelineExecutableInternalRepresentation>&	getIRs		(void) const { return m_irs; }
360 
361 protected:
362 	std::vector<PipelineExecutableStat>						m_stats;
363 	std::vector<PipelineExecutableInternalRepresentation>	m_irs;
364 };
365 
366 // This will NOT compare stats and IRs, only flags, name, description and subgroup sizes.
operator ==(const PipelineExecutableProperty & a,const PipelineExecutableProperty & b)367 bool operator== (const PipelineExecutableProperty& a, const PipelineExecutableProperty& b)
368 {
369 	return (a.stageFlags == b.stageFlags && a.name == b.name && a.description == b.description && a.subgroupSize == b.subgroupSize);
370 }
371 
372 // For sorting if used as a map key or in a set. Based on the property name.
operator <(const PipelineExecutableProperty & a,const PipelineExecutableProperty & b)373 bool operator< (const PipelineExecutableProperty& a, const PipelineExecutableProperty& b)
374 {
375 	return (a.name < b.name);
376 }
377 
operator <<(std::ostream & out,const PipelineExecutableProperty & prop)378 std::ostream& operator<< (std::ostream& out, const PipelineExecutableProperty& prop)
379 {
380 	out << "PipelineExecutableProperty("
381 		<< "stageFlags=\"" << prop.stageFlags << "\", "
382 		<< "name=\"" << prop.name << "\", "
383 		<< "description=\"" << prop.description << "\", "
384 		<< "subgroupSize=\"" << prop.subgroupSize << "\")";
385 	return out;
386 }
387 
388 // What to capture from a pipeline.
389 enum class CapturedPropertiesBits
390 {
391 	NONE	= 0,
392 	STATS	= 1,
393 	IRS		= 2,
394 };
395 using CapturedPropertiesFlags = uint32_t;
396 
getPipelineCreateFlags(CapturedPropertiesFlags capturedProperties)397 VkPipelineCreateFlags getPipelineCreateFlags (CapturedPropertiesFlags capturedProperties)
398 {
399 	VkPipelineCreateFlags createFlags = 0u;
400 
401 	if (capturedProperties & static_cast<int>(CapturedPropertiesBits::STATS))
402 		createFlags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
403 
404 	if (capturedProperties & static_cast<int>(CapturedPropertiesBits::IRS))
405 		createFlags |= VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR;
406 
407 	return createFlags;
408 }
409 
makePipelineInfo(VkPipeline pipeline)410 VkPipelineInfoKHR makePipelineInfo (VkPipeline pipeline)
411 {
412 	VkPipelineInfoKHR pipelineInfo = initVulkanStructure();
413 	pipelineInfo.pipeline = pipeline;
414 	return pipelineInfo;
415 }
416 
makePipelineExecutableInfo(VkPipeline pipeline,size_t executableIndex)417 VkPipelineExecutableInfoKHR makePipelineExecutableInfo (VkPipeline pipeline, size_t executableIndex)
418 {
419 	VkPipelineExecutableInfoKHR info = initVulkanStructure();
420 	info.pipeline			= pipeline;
421 	info.executableIndex	= static_cast<uint32_t>(executableIndex);
422 	return info;
423 }
424 
425 using PipelineExecutablePropertyVec = std::vector<PipelineExecutableProperty>;
426 
operator <<(std::ostream & out,const PipelineExecutablePropertyVec & vec)427 std::ostream& operator<< (std::ostream& out, const PipelineExecutablePropertyVec& vec)
428 {
429 	bool first = true;
430 	out << "[";
431 	for (const auto& prop : vec)
432 	{
433 		out << (first ? "" : ", ") << prop;
434 		first = false;
435 	}
436 	out << "]";
437 	return out;
438 }
439 
getPipelineExecutableProperties(const DeviceInterface & vkd,VkDevice device,VkPipeline pipeline,CapturedPropertiesFlags captureFlags)440 PipelineExecutablePropertyVec getPipelineExecutableProperties (const DeviceInterface& vkd, VkDevice device, VkPipeline pipeline, CapturedPropertiesFlags captureFlags)
441 {
442 	PipelineExecutablePropertyVec	properties;
443 	const auto						pipelineInfo	= makePipelineInfo(pipeline);
444 	uint32_t						executableCount	= 0u;
445 
446 	std::vector<VkPipelineExecutablePropertiesKHR> propertiesKHR;
447 	VK_CHECK(vkd.getPipelineExecutablePropertiesKHR(device, &pipelineInfo, &executableCount, nullptr));
448 
449 	// No properties?
450 	if (executableCount == 0u)
451 		return properties;
452 
453 	propertiesKHR.resize(executableCount, initVulkanStructure());
454 	VK_CHECK(vkd.getPipelineExecutablePropertiesKHR(device, &pipelineInfo, &executableCount, propertiesKHR.data()));
455 
456 	// Make a property with every result structure.
457 	properties.reserve(propertiesKHR.size());
458 	for (const auto& prop : propertiesKHR)
459 		properties.emplace_back(prop.stages, prop.name, prop.description, prop.subgroupSize);
460 
461 	// Query stats if requested.
462 	if (captureFlags & static_cast<int>(CapturedPropertiesBits::STATS))
463 	{
464 		for (size_t exeIdx = 0; exeIdx < properties.size(); ++exeIdx)
465 		{
466 			uint32_t										statCount		= 0u;
467 			std::vector<VkPipelineExecutableStatisticKHR>	statsKHR;
468 			const auto										executableInfo	= makePipelineExecutableInfo(pipeline, exeIdx);
469 
470 			VK_CHECK(vkd.getPipelineExecutableStatisticsKHR(device, &executableInfo, &statCount, nullptr));
471 
472 			if (statCount == 0u)
473 				continue;
474 
475 			statsKHR.resize(statCount, initVulkanStructure());
476 			VK_CHECK(vkd.getPipelineExecutableStatisticsKHR(device, &executableInfo, &statCount, statsKHR.data()));
477 
478 			for (const auto& stat : statsKHR)
479 				properties[exeIdx].addStat(PipelineExecutableStat(stat.name, stat.description, stat.format, stat.value));
480 		}
481 	}
482 
483 	// Query IRs if requested.
484 	if (captureFlags & static_cast<int>(CapturedPropertiesBits::IRS))
485 	{
486 		for (size_t exeIdx = 0; exeIdx < properties.size(); ++exeIdx)
487 		{
488 			uint32_t													irsCount		= 0u;
489 			std::vector<VkPipelineExecutableInternalRepresentationKHR>	irsKHR;
490 			std::vector<std::vector<uint8_t>>							irsData;
491 			const auto													executableInfo	= makePipelineExecutableInfo(pipeline, exeIdx);
492 
493 			// Get count.
494 			VK_CHECK(vkd.getPipelineExecutableInternalRepresentationsKHR(device, &executableInfo, &irsCount, nullptr));
495 
496 			if (irsCount == 0u)
497 				continue;
498 
499 			// Get data sizes.
500 			irsData.resize(irsCount);
501 			irsKHR.resize(irsCount, initVulkanStructure());
502 			VK_CHECK(vkd.getPipelineExecutableInternalRepresentationsKHR(device, &executableInfo, &irsCount, irsKHR.data()));
503 
504 			// Get data.
505 			for (size_t irIdx = 0; irIdx < irsKHR.size(); ++irIdx)
506 			{
507 				auto& dataBuffer	= irsData[irIdx];
508 				auto& irKHR			= irsKHR[irIdx];
509 
510 				dataBuffer.resize(irKHR.dataSize);
511 				irKHR.pData = dataBuffer.data();
512 			}
513 			VK_CHECK(vkd.getPipelineExecutableInternalRepresentationsKHR(device, &executableInfo, &irsCount, irsKHR.data()));
514 
515 			// Append IRs to property.
516 			for (size_t irIdx = 0; irIdx < irsKHR.size(); ++irIdx)
517 			{
518 				const auto& ir = irsKHR[irIdx];
519 				properties[exeIdx].addIR(PipelineExecutableInternalRepresentation(ir.name, ir.description, ir.isText, irsData[irIdx]));
520 			}
521 		}
522 	}
523 
524 	return properties;
525 }
526 
527 struct BaseParams
528 {
529 	const PipelineType			pipelineType;
530 	GraphicsShaderVec			graphicsShaders;
531 	RTShaderVec					rtShaders;
532 	const uint8_t				pipelineCount;
533 	const tcu::Maybe<uint8_t>	pipelineToRun;
534 	const bool					useSpecializationConstants;
535 	const bool					useCache;
536 	const bool					useMaintenance5;
537 
BaseParamsvkt::pipeline::__anon8967aaa10111::BaseParams538 	BaseParams (PipelineType				pipelineType_,
539 				GraphicsShaderVec			graphicsShaders_,
540 				RTShaderVec					rtShaders_,
541 				uint8_t						pipelineCount_,
542 				const tcu::Maybe<uint8_t>&	pipelineToRun_,
543 				bool						useSCs_,
544 				bool						useCache_,
545 				bool						useMaintenance5_)
546 		: pipelineType					(pipelineType_)
547 		, graphicsShaders				(std::move(graphicsShaders_))
548 		, rtShaders						(std::move(rtShaders_))
549 		, pipelineCount					(pipelineCount_)
550 		, pipelineToRun					(pipelineToRun_)
551 		, useSpecializationConstants	(useSCs_)
552 		, useCache						(useCache_)
553 		, useMaintenance5				(useMaintenance5_)
554 	{
555 		if (pipelineType != PipelineType::GRAPHICS)
556 			DE_ASSERT(graphicsShaders.empty());
557 		else if (pipelineType != PipelineType::RAY_TRACING)
558 			DE_ASSERT(rtShaders.empty());
559 
560 		if (static_cast<bool>(pipelineToRun))
561 			DE_ASSERT(pipelineToRun.get() < pipelineCount);
562 
563 		// We'll use one descriptor set per pipeline, so we only want a few pipelines.
564 		DE_ASSERT(static_cast<uint32_t>(pipelineCount) <= 4u);
565 	}
566 
567 	// Make the class polymorphic, needed below.
~BaseParamsvkt::pipeline::__anon8967aaa10111::BaseParams568 	virtual ~BaseParams () {}
569 
stageCountPerPipelinevkt::pipeline::__anon8967aaa10111::BaseParams570 	size_t stageCountPerPipeline (void) const
571 	{
572 		size_t stageCount = 0;
573 
574 		switch (pipelineType)
575 		{
576 		case PipelineType::COMPUTE:			stageCount = 1u;						break;
577 		case PipelineType::GRAPHICS:		stageCount = graphicsShaders.size();	break;
578 		case PipelineType::RAY_TRACING:		stageCount = rtShaders.size();			break;
579 		default:
580 			DE_ASSERT(false);
581 			break;
582 		}
583 
584 		return stageCount;
585 	}
586 
587 protected:
hasGraphicsStagevkt::pipeline::__anon8967aaa10111::BaseParams588 	bool hasGraphicsStage (GraphicsShaderType stage) const
589 	{
590 		if (pipelineType != PipelineType::GRAPHICS)
591 			return false;
592 		return de::contains(begin(graphicsShaders), end(graphicsShaders), stage);
593 	}
594 
hasRTStagevkt::pipeline::__anon8967aaa10111::BaseParams595 	bool hasRTStage (RayTracingShaderType stage) const
596 	{
597 		if (pipelineType != PipelineType::RAY_TRACING)
598 			return false;
599 		return de::contains(begin(rtShaders), end(rtShaders), stage);
600 	}
601 
602 public:
hasGeomvkt::pipeline::__anon8967aaa10111::BaseParams603 	bool hasGeom (void) const
604 	{
605 		return hasGraphicsStage(GraphicsShaderType::GEOMETRY);
606 	}
607 
hasTessvkt::pipeline::__anon8967aaa10111::BaseParams608 	bool hasTess (void) const
609 	{
610 		return (hasGraphicsStage(GraphicsShaderType::TESS_CONTROL) || hasGraphicsStage(GraphicsShaderType::TESS_EVAL));
611 	}
612 
hasVertexPipelineStagevkt::pipeline::__anon8967aaa10111::BaseParams613 	bool hasVertexPipelineStage (void) const
614 	{
615 		return (hasGraphicsStage(GraphicsShaderType::VERTEX) || hasTess() || hasGeom());
616 	}
617 
hasFragvkt::pipeline::__anon8967aaa10111::BaseParams618 	bool hasFrag (void) const
619 	{
620 		return hasGraphicsStage(GraphicsShaderType::FRAG);
621 	}
622 
hasRayTracingvkt::pipeline::__anon8967aaa10111::BaseParams623 	bool hasRayTracing (void) const
624 	{
625 		return (pipelineType == PipelineType::RAY_TRACING);
626 	}
627 
hasHitvkt::pipeline::__anon8967aaa10111::BaseParams628 	bool hasHit (void) const
629 	{
630 		return (hasRTStage(RayTracingShaderType::ANY_HIT) || hasRTStage(RayTracingShaderType::CLOSEST_HIT) || hasRTStage(RayTracingShaderType::INTERSECTION));
631 	}
632 
hasISecvkt::pipeline::__anon8967aaa10111::BaseParams633 	bool hasISec (void) const
634 	{
635 		return hasRTStage(RayTracingShaderType::INTERSECTION);
636 	}
637 
hasMissvkt::pipeline::__anon8967aaa10111::BaseParams638 	bool hasMiss (void) const
639 	{
640 		return hasRTStage(RayTracingShaderType::MISS);
641 	}
642 
getPipelineStageFlagsvkt::pipeline::__anon8967aaa10111::BaseParams643 	VkPipelineStageFlags getPipelineStageFlags (void) const
644 	{
645 		if (pipelineType == PipelineType::COMPUTE)
646 			return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
647 
648 		if (pipelineType == PipelineType::RAY_TRACING)
649 			return VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
650 
651 		if (pipelineType == PipelineType::GRAPHICS)
652 		{
653 			VkPipelineStageFlags stageFlags = 0u;
654 
655 			for (const auto& stage : graphicsShaders)
656 			{
657 				switch (stage)
658 				{
659 				case GraphicsShaderType::VERTEX:		stageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;					break;
660 				case GraphicsShaderType::TESS_CONTROL:	stageFlags |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;	break;
661 				case GraphicsShaderType::TESS_EVAL:		stageFlags |= VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;	break;
662 				case GraphicsShaderType::GEOMETRY:		stageFlags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;				break;
663 				case GraphicsShaderType::FRAG:			stageFlags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;				break;
664 				default:
665 					DE_ASSERT(false);
666 					break;
667 				}
668 			}
669 
670 			return stageFlags;
671 		}
672 
673 		DE_ASSERT(false);
674 		return 0u;
675 	}
676 
getShaderStageFlagsvkt::pipeline::__anon8967aaa10111::BaseParams677 	VkShaderStageFlags getShaderStageFlags (void) const
678 	{
679 		if (pipelineType == PipelineType::COMPUTE)
680 			return VK_SHADER_STAGE_COMPUTE_BIT;
681 
682 		if (pipelineType == PipelineType::RAY_TRACING)
683 		{
684 			VkShaderStageFlags stageFlags = 0u;
685 
686 			for (const auto& stage : rtShaders)
687 			{
688 				switch (stage)
689 				{
690 				case RayTracingShaderType::RAY_GEN:			stageFlags |= VK_SHADER_STAGE_RAYGEN_BIT_KHR;		break;
691 				case RayTracingShaderType::CLOSEST_HIT:		stageFlags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;	break;
692 				case RayTracingShaderType::ANY_HIT:			stageFlags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;		break;
693 				case RayTracingShaderType::INTERSECTION:	stageFlags |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;	break;
694 				case RayTracingShaderType::MISS:			stageFlags |= VK_SHADER_STAGE_MISS_BIT_KHR;			break;
695 				case RayTracingShaderType::CALLABLE:		stageFlags |= VK_SHADER_STAGE_CALLABLE_BIT_KHR;		break;
696 				default:
697 					DE_ASSERT(false);
698 					break;
699 				}
700 			}
701 
702 			return stageFlags;
703 		}
704 
705 		if (pipelineType == PipelineType::GRAPHICS)
706 		{
707 			VkShaderStageFlags stageFlags = 0u;
708 
709 			for (const auto& stage : graphicsShaders)
710 			{
711 				switch (stage)
712 				{
713 				case GraphicsShaderType::VERTEX:		stageFlags |= VK_SHADER_STAGE_VERTEX_BIT;					break;
714 				case GraphicsShaderType::TESS_CONTROL:	stageFlags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;		break;
715 				case GraphicsShaderType::TESS_EVAL:		stageFlags |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;	break;
716 				case GraphicsShaderType::GEOMETRY:		stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT;					break;
717 				case GraphicsShaderType::FRAG:			stageFlags |= VK_SHADER_STAGE_FRAGMENT_BIT;					break;
718 				default:
719 					DE_ASSERT(false);
720 					break;
721 				}
722 			}
723 
724 			return stageFlags;
725 		}
726 
727 		DE_ASSERT(false);
728 		return 0u;
729 	}
730 };
731 
732 using BaseParamsPtr = std::unique_ptr<BaseParams>;
733 
checkShaderModuleIdentifierSupport(Context & context)734 void checkShaderModuleIdentifierSupport (Context& context)
735 {
736 	context.requireDeviceFunctionality("VK_EXT_shader_module_identifier");
737 }
738 
getTwoShaderIdentifierProperties(Context & context,VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT * properties1,VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT * properties2)739 void getTwoShaderIdentifierProperties	(Context& context,
740 										 VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT* properties1,
741 										 VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT* properties2)
742 {
743 	*properties1 = initVulkanStructure();
744 	*properties2 = initVulkanStructure();
745 
746 	const auto&					vki				= context.getInstanceInterface();
747 	const auto					physicalDevice	= context.getPhysicalDevice();
748 	VkPhysicalDeviceProperties2	main			= initVulkanStructure(properties1);
749 
750 	vki.getPhysicalDeviceProperties2(physicalDevice, &main);
751 	main.pNext = properties2;
752 	vki.getPhysicalDeviceProperties2(physicalDevice, &main);
753 }
754 
constantAlgorithmUUIDCase(Context & context)755 tcu::TestStatus constantAlgorithmUUIDCase (Context& context)
756 {
757 	VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT properties1, properties2;
758 	getTwoShaderIdentifierProperties(context, &properties1, &properties2);
759 
760 	const auto uuidSize = static_cast<size_t>(VK_UUID_SIZE);
761 
762 	if (deMemCmp(properties1.shaderModuleIdentifierAlgorithmUUID, properties2.shaderModuleIdentifierAlgorithmUUID, uuidSize) != 0)
763 		return tcu::TestStatus::fail("shaderModuleIdentifierAlgorithmUUID not constant accross calls");
764 
765 	uint8_t nullUUID[uuidSize];
766 	deMemset(nullUUID, 0, uuidSize);
767 
768 	if (deMemCmp(properties1.shaderModuleIdentifierAlgorithmUUID, nullUUID, uuidSize) == 0)
769 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "shaderModuleIdentifierAlgorithmUUID is all zeros");
770 
771 	return tcu::TestStatus::pass("Pass");
772 }
773 
generateShaderConstants(PipelineType pipelineType,uint8_t pipelineCount,size_t stageCount)774 std::vector<uint32_t> generateShaderConstants (PipelineType pipelineType, uint8_t pipelineCount, size_t stageCount)
775 {
776 	std::vector<uint32_t> shaderConstants;
777 
778 	for (uint8_t pipelineIdx = 0; pipelineIdx < pipelineCount; ++pipelineIdx)
779 		for (size_t stageIdx = 0; stageIdx < stageCount; ++stageIdx)
780 			shaderConstants.push_back(0xEB000000u
781 				| ((static_cast<uint32_t>(pipelineType) & 0xFFu)  << 16)
782 				| ((static_cast<uint32_t>(pipelineIdx)  & 0xFFu)  <<  8)
783 				| ((static_cast<uint32_t>(stageIdx)     & 0xFFu)       )
784 			);
785 
786 	return shaderConstants;
787 }
788 
getShaderIdx(uint8_t pipelineIdx,size_t stageIdx,size_t stageCount)789 size_t getShaderIdx (uint8_t pipelineIdx, size_t stageIdx, size_t stageCount)
790 {
791 	const auto pIdx = static_cast<size_t>(pipelineIdx);
792 	return (pIdx * stageCount + stageIdx);
793 }
794 
generateSources(SourceCollections & programCollection,const BaseParams * params_)795 void generateSources (SourceCollections& programCollection, const BaseParams* params_)
796 {
797 	const auto&	params			= *params_;
798 	const auto	stageCount		= params.stageCountPerPipeline();
799 	const auto	constantValues	= generateShaderConstants(params.pipelineType, params.pipelineCount, stageCount);
800 
801 	StringVec constantDecls;	// Per pipeline and stage.
802 	StringVec pipelineAdds;		// Per pipeline.
803 	StringVec stageStores;		// Per stage.
804 
805 	std::string ssboDecl;		// Universal.
806 	std::string uboDecls;		// Universal.
807 	std::string outValueDecl	= "    uint outValue = stageConstant;\n";	// Universal.
808 
809 	// Each stage in each pipeline will have one specific constant value.
810 	{
811 		for (uint8_t pipelineIdx = 0; pipelineIdx < params.pipelineCount; ++pipelineIdx)
812 			for (size_t stageIdx = 0; stageIdx < stageCount; ++stageIdx)
813 			{
814 				constantDecls.push_back(params.useSpecializationConstants
815 					? "layout (constant_id=0) const uint stageConstant = 0u;\n"
816 					: "const uint stageConstant = " + std::to_string(constantValues.at(getShaderIdx(pipelineIdx, stageIdx, stageCount))) + "u;\n");
817 			}
818 	}
819 
820 	// Each pipeline will have slightly different code by adding more values to the constant in each shader.
821 	// The values will come from UBOs and, in practice, will contain zeros.
822 	{
823 		pipelineAdds.reserve(params.pipelineCount);
824 
825 		for (uint8_t pipelineIdx = 0; pipelineIdx < params.pipelineCount; ++pipelineIdx)
826 		{
827 			std::string	additions;
828 			const auto	addCount	= static_cast<size_t>(pipelineIdx + 1);
829 
830 			for (size_t addIdx = 0; addIdx < addCount; ++addIdx)
831 			{
832 				const auto uboId = addIdx + 1;
833 				additions += "    outValue += ubo_" + std::to_string(uboId) + ".value;\n";
834 			}
835 
836 			pipelineAdds.push_back(additions);
837 		}
838 	}
839 
840 	// Each stage will write the output value to an SSBO position.
841 	{
842 		stageStores.reserve(stageCount);
843 
844 		for (size_t stageIdx = 0; stageIdx < stageCount; ++stageIdx)
845 		{
846 			const auto stageStore = "    ssbo.values[" + std::to_string(stageIdx) + "] = outValue;\n";
847 			stageStores.push_back(stageStore);
848 		}
849 	}
850 
851 	// The SSBO declaration is constant.
852 	ssboDecl = "layout (set=0, binding=0, std430) buffer SSBOBlock { uint values[]; } ssbo;\n";
853 
854 	// The UBO declarations are constant. We need one UBO per pipeline, but all pipelines declare them all.
855 	{
856 		for (uint8_t pipelineIdx = 0; pipelineIdx < params.pipelineCount; ++pipelineIdx)
857 		{
858 			const auto uboId = pipelineIdx + 1;
859 			const auto idStr = std::to_string(uboId);
860 			uboDecls += "layout (set=0, binding=" + idStr + ") uniform UBOBlock" + idStr + " { uint value; } ubo_" + idStr + ";\n";
861 		}
862 	}
863 
864 	if (params.pipelineType == PipelineType::COMPUTE)
865 	{
866 		const std::string localSize	= (params.useSpecializationConstants
867 									? "layout (local_size_x_id=1, local_size_y_id=2, local_size_z_id=3) in;\n"
868 									: "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n");
869 
870 		for (uint8_t pipelineIdx = 0; pipelineIdx < params.pipelineCount; ++pipelineIdx)
871 		{
872 			const auto			plIdxSz		= static_cast<size_t>(pipelineIdx);
873 			const std::string	shaderName	= "comp_" + std::to_string(plIdxSz);
874 			const auto			shaderIdx	= getShaderIdx(pipelineIdx, 0, stageCount);
875 
876 			std::ostringstream comp;
877 			comp
878 				<< "#version 450\n"
879 				<< localSize
880 				<< ssboDecl
881 				<< uboDecls
882 				<< constantDecls.at(shaderIdx)
883 				<< "void main (void) {\n"
884 				<< outValueDecl
885 				<< pipelineAdds.at(plIdxSz)
886 				<< "    if (gl_LocalInvocationIndex == 0u) {\n"
887 				<< stageStores.at(0)
888 				<< "    }\n"
889 				<< "}\n"
890 				;
891 			programCollection.glslSources.add(shaderName) << glu::ComputeSource(comp.str());
892 		}
893 	}
894 	else if (params.pipelineType == PipelineType::GRAPHICS)
895 	{
896 		bool hasVertex			= false;
897 		bool hasTessControl		= false;
898 		bool hasTessEval		= false;
899 		bool hasGeom			= false;
900 		bool hasFrag			= false;
901 
902 		// Assign a unique index to each active shader type.
903 		size_t vertShaderIdx	= 0u;
904 		size_t tescShaderIdx	= 0u;
905 		size_t teseShaderIdx	= 0u;
906 		size_t geomShaderIdx	= 0u;
907 		size_t fragShaderIdx	= 0u;
908 		size_t curShaderIdx		= 0u;
909 
910 		const std::set<GraphicsShaderType> uniqueStages (begin(params.graphicsShaders), end(params.graphicsShaders));
911 
912 		for (const auto& stage : uniqueStages)
913 		{
914 			switch (stage)
915 			{
916 			case GraphicsShaderType::VERTEX:		hasVertex		= true;	vertShaderIdx = curShaderIdx++;	break;
917 			case GraphicsShaderType::TESS_CONTROL:	hasTessControl	= true;	tescShaderIdx = curShaderIdx++;	break;
918 			case GraphicsShaderType::TESS_EVAL:		hasTessEval		= true;	teseShaderIdx = curShaderIdx++;	break;
919 			case GraphicsShaderType::GEOMETRY:		hasGeom			= true;	geomShaderIdx = curShaderIdx++;	break;
920 			case GraphicsShaderType::FRAG:			hasFrag			= true;	fragShaderIdx = curShaderIdx++;	break;
921 			default:								DE_ASSERT(false);										break;
922 			}
923 		}
924 
925 		const bool hasTess = (hasTessControl || hasTessEval);
926 
927 		for (uint8_t pipelineIdx = 0; pipelineIdx < params.pipelineCount; ++pipelineIdx)
928 		{
929 			const auto plIdxSz = static_cast<size_t>(pipelineIdx);
930 
931 			if (hasVertex)
932 			{
933 				const std::string	shaderName	= "vert_" + std::to_string(plIdxSz);
934 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, vertShaderIdx, stageCount);
935 
936 				std::ostringstream vert;
937 				vert
938 					<< "#version 450\n"
939 					<< "out gl_PerVertex\n"
940 					<< "{\n"
941 					<< "    vec4 gl_Position;\n"
942 					<< (hasTess ? "" : "    float gl_PointSize;\n")
943 					<< "};\n"
944 					;
945 
946 				if (hasTess)
947 				{
948 					vert
949 						<< "vec2 vertexPositions[3] = vec2[](\n"
950 						<< "    vec2( 0.0, -0.5),\n"
951 						<< "    vec2( 0.5,  0.5),\n"
952 						<< "    vec2(-0.5,  0.5)\n"
953 						<< ");\n"
954 						;
955 				}
956 
957 				vert
958 					<< ssboDecl
959 					<< uboDecls
960 					<< constantDecls.at(shaderIdx)
961 					<< "void main (void) {\n"
962 					<< outValueDecl
963 					<< pipelineAdds.at(plIdxSz)
964 					<< stageStores.at(vertShaderIdx)
965 					;
966 
967 				if (hasTess)
968 				{
969 					vert << "    gl_Position = vec4(vertexPositions[gl_VertexIndex], 0.0, 1.0);\n";
970 				}
971 				else
972 				{
973 					vert
974 						<< "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
975 						<< "    gl_PointSize = 1.0;\n"
976 						;
977 				}
978 
979 				vert << "}\n";
980 
981 				programCollection.glslSources.add(shaderName) << glu::VertexSource(vert.str());
982 			}
983 
984 			if (hasFrag)
985 			{
986 				const std::string	shaderName	= "frag_" + std::to_string(plIdxSz);
987 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, fragShaderIdx, stageCount);
988 
989 				std::ostringstream frag;
990 				frag
991 					<< "#version 450\n"
992 					<< "layout (location=0) out vec4 outColor;\n"
993 					<< ssboDecl
994 					<< uboDecls
995 					<< constantDecls.at(shaderIdx)
996 					<< "void main (void) {\n"
997 					<< outValueDecl
998 					<< pipelineAdds.at(plIdxSz)
999 					<< stageStores.at(fragShaderIdx)
1000 					<< "    outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
1001 					<< "}\n"
1002 					;
1003 				programCollection.glslSources.add(shaderName) << glu::FragmentSource(frag.str());
1004 			}
1005 
1006 			if (hasTessControl)
1007 			{
1008 				const std::string	shaderName	= "tesc_" + std::to_string(plIdxSz);
1009 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, tescShaderIdx, stageCount);
1010 
1011 				std::ostringstream tesc;
1012 				tesc
1013 					<< "#version 450\n"
1014 					<< "layout (vertices=3) out;\n"
1015 					<< "in gl_PerVertex\n"
1016 					<< "{\n"
1017 					<< "    vec4 gl_Position;\n"
1018 					<< "} gl_in[gl_MaxPatchVertices];\n"
1019 					<< "out gl_PerVertex\n"
1020 					<< "{\n"
1021 					<< "    vec4 gl_Position;\n"
1022 					<< "} gl_out[];\n"
1023 					<< ssboDecl
1024 					<< uboDecls
1025 					<< constantDecls.at(shaderIdx)
1026 					<< "void main (void) {\n"
1027 					<< outValueDecl
1028 					<< pipelineAdds.at(plIdxSz)
1029 					<< stageStores.at(tescShaderIdx)
1030 					<< "    gl_TessLevelInner[0] = 1.0;\n"
1031 					<< "    gl_TessLevelInner[1] = 1.0;\n"
1032 					<< "    gl_TessLevelOuter[0] = 1.0;\n"
1033 					<< "    gl_TessLevelOuter[1] = 1.0;\n"
1034 					<< "    gl_TessLevelOuter[2] = 1.0;\n"
1035 					<< "    gl_TessLevelOuter[3] = 1.0;\n"
1036 					<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1037 					<< "}\n"
1038 					;
1039 				programCollection.glslSources.add(shaderName) << glu::TessellationControlSource(tesc.str());
1040 			}
1041 
1042 			if (hasTessEval)
1043 			{
1044 				const std::string	shaderName	= "tese_" + std::to_string(plIdxSz);
1045 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, teseShaderIdx, stageCount);
1046 
1047 				std::ostringstream tese;
1048 				tese
1049 					<< "#version 450\n"
1050 					<< "layout (triangles, fractional_odd_spacing, cw) in;\n"
1051 					<< "in gl_PerVertex\n"
1052 					<< "{\n"
1053 					<< "    vec4 gl_Position;\n"
1054 					<< "} gl_in[gl_MaxPatchVertices];\n"
1055 					<< "out gl_PerVertex\n"
1056 					<< "{\n"
1057 					<< "    vec4 gl_Position;\n"
1058 					<< "};\n"
1059 					<< ssboDecl
1060 					<< uboDecls
1061 					<< constantDecls.at(shaderIdx)
1062 					<< "void main (void) {\n"
1063 					<< outValueDecl
1064 					<< pipelineAdds.at(plIdxSz)
1065 					<< stageStores.at(teseShaderIdx)
1066 					<< "    gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
1067 					<< "                  (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
1068 					<< "                  (gl_TessCoord.z * gl_in[2].gl_Position);\n"
1069 					<< "}\n"
1070 					;
1071 				programCollection.glslSources.add(shaderName) << glu::TessellationEvaluationSource(tese.str());
1072 			}
1073 
1074 			if (hasGeom)
1075 			{
1076 				const std::string	shaderName	= "geom_" + std::to_string(plIdxSz);
1077 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, geomShaderIdx, stageCount);
1078 				const auto			inputPrim	= (hasTess ? "triangles" : "points");
1079 				const auto			outputPrim	= (hasTess ? "triangle_strip" : "points");
1080 				const auto			vertexCount	= (hasTess ? 3u : 1u);
1081 
1082 				std::ostringstream geom;
1083 				geom
1084 					<< "#version 450\n"
1085 					<< "layout (" << inputPrim << ") in;\n"
1086 					<< "layout (" << outputPrim << ", max_vertices=" << vertexCount << ") out;\n"
1087 					<< "in gl_PerVertex\n"
1088 					<< "{\n"
1089 					<< "    vec4 gl_Position;\n"
1090 					<< (hasTess ? "" : "    float gl_PointSize;\n")
1091 					<< "} gl_in[" << vertexCount << "];\n"
1092 					<< "out gl_PerVertex\n"
1093 					<< "{\n"
1094 					<< "    vec4 gl_Position;\n"
1095 					<< (hasTess ? "" : "    float gl_PointSize;\n")
1096 					<< "};\n"
1097 					<< ssboDecl
1098 					<< uboDecls
1099 					<< constantDecls.at(shaderIdx)
1100 					<< "void main (void) {\n"
1101 					<< outValueDecl
1102 					<< pipelineAdds.at(plIdxSz)
1103 					<< stageStores.at(geomShaderIdx)
1104 					;
1105 
1106 				for (uint32_t i = 0; i < vertexCount; ++i)
1107 				{
1108 					geom
1109 						<< "    gl_Position = gl_in[" << i << "].gl_Position;\n"
1110 						<< (hasTess ? "" : "    gl_PointSize = gl_in[" + std::to_string(i) + "].gl_PointSize;\n")
1111 						<< "    EmitVertex();\n"
1112 						;
1113 				}
1114 
1115 				geom << "}\n";
1116 
1117 				programCollection.glslSources.add(shaderName) << glu::GeometrySource(geom.str());
1118 			}
1119 		}
1120 	}
1121 	else if (params.pipelineType == PipelineType::RAY_TRACING)
1122 	{
1123 		bool hasRayGen			= false;
1124 		bool hasAnyHit			= false;
1125 		bool hasClosestHit		= false;
1126 		bool hasIntersection	= false;
1127 		bool hasMiss			= false;
1128 		bool hasCallable		= false;
1129 
1130 		// Assign a unique index to each active shader type.
1131 		size_t rgenShaderIdx	= 0u;
1132 		size_t ahitShaderIdx	= 0u;
1133 		size_t chitShaderIdx	= 0u;
1134 		size_t isecShaderIdx	= 0u;
1135 		size_t missShaderIdx	= 0u;
1136 		size_t callShaderIdx	= 0u;
1137 		size_t curShaderIdx		= 0u;
1138 
1139 		const std::set<RayTracingShaderType> uniqueStages (begin(params.rtShaders), end(params.rtShaders));
1140 
1141 		for (const auto& stage : uniqueStages)
1142 		{
1143 			switch (stage)
1144 			{
1145 			case RayTracingShaderType::RAY_GEN:			hasRayGen		= true;	rgenShaderIdx = curShaderIdx++;	break;
1146 			case RayTracingShaderType::ANY_HIT:			hasAnyHit		= true;	ahitShaderIdx = curShaderIdx++;	break;
1147 			case RayTracingShaderType::CLOSEST_HIT:		hasClosestHit	= true;	chitShaderIdx = curShaderIdx++;	break;
1148 			case RayTracingShaderType::INTERSECTION:	hasIntersection	= true;	isecShaderIdx = curShaderIdx++;	break;
1149 			case RayTracingShaderType::MISS:			hasMiss			= true;	missShaderIdx = curShaderIdx++;	break;
1150 			case RayTracingShaderType::CALLABLE:		hasCallable		= true; callShaderIdx = curShaderIdx++;	break;
1151 			default:									DE_ASSERT(false);										break;
1152 			}
1153 		}
1154 
1155 		const vk::ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true/* allow SPIR-V 1.4 */);
1156 		const bool						needsRayTraced	= (hasAnyHit || hasClosestHit || hasIntersection || hasMiss);
1157 
1158 		for (uint8_t pipelineIdx = 0; pipelineIdx < params.pipelineCount; ++pipelineIdx)
1159 		{
1160 			const auto plIdxSz = static_cast<size_t>(pipelineIdx);
1161 
1162 			if (hasRayGen)
1163 			{
1164 				const std::string	shaderName	= "rgen_" + std::to_string(plIdxSz);
1165 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, rgenShaderIdx, stageCount);
1166 
1167 				std::ostringstream rgen;
1168 				rgen
1169 					<< "#version 460\n"
1170 					<< "#extension GL_EXT_ray_tracing : require\n"
1171 					<< (needsRayTraced ? "layout (location=0) rayPayloadEXT vec3 hitValue;\n" : "")
1172 					<< (hasCallable ? "layout (location=0) callableDataEXT float unused;\n" : "")
1173 					// Ray tracing pipelines will use a separate set for the acceleration structure.
1174 					<< "layout (set=1, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
1175 					<< ssboDecl
1176 					<< uboDecls
1177 					<< constantDecls.at(shaderIdx)
1178 					<< "void main (void) {\n"
1179 					<< outValueDecl
1180 					<< pipelineAdds.at(plIdxSz)
1181 					<< "    if (gl_LaunchIDEXT.x == 0u) {\n"
1182 					<< stageStores.at(rgenShaderIdx)
1183 					<< "    }\n"
1184 					<< "    uint  rayFlags = 0;\n"
1185 					<< "    uint  cullMask = 0xFF;\n"
1186 					<< "    float tmin     = 0.0;\n"
1187 					<< "    float tmax     = 10.0;\n"
1188 					// Rays will be traced towards +Z and geometry should be in the [0, 1] range in both X and Y, possibly at Z=5.
1189 					// If a hit and a miss shader are used, a second ray will be traced starting at X=1.5, which should result in a miss.
1190 					<< "    vec3  origin   = vec3(float(gl_LaunchIDEXT.x) + 0.5f, 0.5, 0.0);\n"
1191 					<< "    vec3  direct   = vec3(0.0, 0.0, 1.0);\n"
1192 					<< (needsRayTraced ? "    traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n" : "")
1193 					<< (hasCallable ? "    executeCallableEXT(0, 0);\n" : "")
1194 					<< "}\n"
1195 					;
1196 				programCollection.glslSources.add(shaderName) << glu::RaygenSource(rgen.str()) << buildOptions;
1197 			}
1198 
1199 			if (hasAnyHit)
1200 			{
1201 				const std::string	shaderName	= "ahit_" + std::to_string(plIdxSz);
1202 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, ahitShaderIdx, stageCount);
1203 
1204 				// VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR should be used.
1205 				std::stringstream ahit;
1206 				ahit
1207 					<< "#version 460\n"
1208 					<< "#extension GL_EXT_ray_tracing : require\n"
1209 					<< "layout (location=0) rayPayloadInEXT vec3 hitValue;\n"
1210 					<< "hitAttributeEXT vec3 attribs;\n"
1211 					<< ssboDecl
1212 					<< uboDecls
1213 					<< constantDecls.at(shaderIdx)
1214 					<< "void main()\n"
1215 					<< "{\n"
1216 					<< outValueDecl
1217 					<< pipelineAdds.at(plIdxSz)
1218 					<< stageStores.at(ahitShaderIdx)
1219 					<< "}\n"
1220 					;
1221 
1222 				programCollection.glslSources.add(shaderName) << glu::AnyHitSource(ahit.str()) << buildOptions;
1223 			}
1224 
1225 			if (hasClosestHit)
1226 			{
1227 				const std::string	shaderName	= "chit_" + std::to_string(plIdxSz);
1228 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, chitShaderIdx, stageCount);
1229 
1230 				std::stringstream chit;
1231 				chit
1232 					<< "#version 460\n"
1233 					<< "#extension GL_EXT_ray_tracing : require\n"
1234 					<< "layout (location=0) rayPayloadInEXT vec3 hitValue;\n"
1235 					<< "hitAttributeEXT vec3 attribs;\n"
1236 					<< ssboDecl
1237 					<< uboDecls
1238 					<< constantDecls.at(shaderIdx)
1239 					<< "void main()\n"
1240 					<< "{\n"
1241 					<< outValueDecl
1242 					<< pipelineAdds.at(plIdxSz)
1243 					<< stageStores.at(chitShaderIdx)
1244 					<< "}\n"
1245 					;
1246 
1247 				programCollection.glslSources.add(shaderName) << glu::ClosestHitSource(chit.str()) << buildOptions;
1248 			}
1249 
1250 			if (hasIntersection)
1251 			{
1252 				const std::string	shaderName	= "isec_" + std::to_string(plIdxSz);
1253 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, isecShaderIdx, stageCount);
1254 
1255 				std::stringstream isec;
1256 				isec
1257 					<< "#version 460\n"
1258 					<< "#extension GL_EXT_ray_tracing : require\n"
1259 					<< "hitAttributeEXT vec3 hitAttribute;\n"
1260 					<< ssboDecl
1261 					<< uboDecls
1262 					<< constantDecls.at(shaderIdx)
1263 					<< "void main()\n"
1264 					<< "{\n"
1265 					<< outValueDecl
1266 					<< pipelineAdds.at(plIdxSz)
1267 					<< stageStores.at(isecShaderIdx)
1268 					<< "  hitAttribute = vec3(0.0, 0.0, 0.0);\n"
1269 					<< "  reportIntersectionEXT(5.0, 0);\n"
1270 					<< "}\n"
1271 					;
1272 
1273 				programCollection.glslSources.add(shaderName) << glu::IntersectionSource(isec.str()) << buildOptions;
1274 			}
1275 
1276 			if (hasMiss)
1277 			{
1278 				const std::string	shaderName	= "miss_" + std::to_string(plIdxSz);
1279 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, missShaderIdx, stageCount);
1280 
1281 				std::stringstream miss;
1282 				miss
1283 					<< "#version 460\n"
1284 					<< "#extension GL_EXT_ray_tracing : require\n"
1285 					<< "layout (location=0) rayPayloadInEXT vec3 hitValue;\n"
1286 					<< ssboDecl
1287 					<< uboDecls
1288 					<< constantDecls.at(shaderIdx)
1289 					<< "void main()\n"
1290 					<< "{\n"
1291 					<< outValueDecl
1292 					<< pipelineAdds.at(plIdxSz)
1293 					<< stageStores.at(missShaderIdx)
1294 					<< "}\n"
1295 					;
1296 
1297 				programCollection.glslSources.add(shaderName) << glu::MissSource(miss.str()) << buildOptions;
1298 			}
1299 
1300 			if (hasCallable)
1301 			{
1302 				const std::string	shaderName	= "call_" + std::to_string(plIdxSz);
1303 				const auto			shaderIdx	= getShaderIdx(pipelineIdx, callShaderIdx, stageCount);
1304 
1305 				std::stringstream call;
1306 				call
1307 					<< "#version 460\n"
1308 					<< "#extension GL_EXT_ray_tracing : require\n"
1309 					<< "layout (location=0) callableDataInEXT float unused;\n"
1310 					<< ssboDecl
1311 					<< uboDecls
1312 					<< constantDecls.at(shaderIdx)
1313 					<< "void main()\n"
1314 					<< "{\n"
1315 					<< outValueDecl
1316 					<< pipelineAdds.at(plIdxSz)
1317 					<< stageStores.at(callShaderIdx)
1318 					<< "}\n"
1319 					;
1320 
1321 				programCollection.glslSources.add(shaderName) << glu::CallableSource(call.str()) << buildOptions;
1322 			}
1323 		}
1324 	}
1325 	else
1326 		DE_ASSERT(false);
1327 }
1328 
1329 // Virtual base class that uses the functions above to generate sources and check for support.
1330 class SourcesAndSupportFromParamsBase : public vkt::TestCase
1331 {
1332 public:
SourcesAndSupportFromParamsBase(tcu::TestContext & testCtx,const std::string & name,BaseParamsPtr && params)1333 					SourcesAndSupportFromParamsBase		(tcu::TestContext& testCtx, const std::string& name, BaseParamsPtr&& params)
1334 						: vkt::TestCase(testCtx, name)
1335 						, m_params(std::move(params))
1336 						{}
~SourcesAndSupportFromParamsBase(void)1337 	virtual			~SourcesAndSupportFromParamsBase	(void) {}
1338 	void			initPrograms						(vk::SourceCollections& programCollection) const override;
1339 	void			checkSupport						(Context& context) const override;
1340 
1341 protected:
1342 	const BaseParamsPtr m_params;
1343 };
1344 
initPrograms(vk::SourceCollections & programCollection) const1345 void SourcesAndSupportFromParamsBase::initPrograms (vk::SourceCollections &programCollection) const
1346 {
1347 	generateSources(programCollection, m_params.get());
1348 }
1349 
checkSupport(Context & context) const1350 void SourcesAndSupportFromParamsBase::checkSupport (Context &context) const
1351 {
1352 	checkShaderModuleIdentifierSupport(context);
1353 
1354 	if (m_params->hasVertexPipelineStage())
1355 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
1356 
1357 	if (m_params->hasFrag())
1358 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
1359 
1360 	if (m_params->hasTess())
1361 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
1362 
1363 	if (m_params->hasGeom())
1364 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
1365 
1366 	if (m_params->hasRayTracing())
1367 	{
1368 		context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
1369 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
1370 	}
1371 }
1372 
1373 // Check shader module identifiers are constant across different API calls.
1374 class ConstantModuleIdentifiersInstance : public vkt::TestInstance
1375 {
1376 public:
1377 	enum class APICall { MODULE = 0, CREATE_INFO, BOTH };
1378 
1379 	struct Params : public BaseParams
1380 	{
1381 		APICall	apiCall;
1382 		bool	differentDevices;
1383 
Paramsvkt::pipeline::__anon8967aaa10111::ConstantModuleIdentifiersInstance::Params1384 		Params (PipelineType				pipelineType_,
1385 				GraphicsShaderVec			graphicsShaders_,
1386 				RTShaderVec					rtShaders_,
1387 				uint8_t						pipelineCount_,
1388 				const tcu::Maybe<uint8_t>&	pipelineToRun_,
1389 				bool						useSCs_,
1390 				bool						useCache_,
1391 				APICall						apiCall_,
1392 				bool						differentDevices_)
1393 			: BaseParams		(pipelineType_, graphicsShaders_, rtShaders_, pipelineCount_, pipelineToRun_, useSCs_, useCache_, false)
1394 			, apiCall			(apiCall_)
1395 			, differentDevices	(differentDevices_)
1396 			{}
1397 
~Paramsvkt::pipeline::__anon8967aaa10111::ConstantModuleIdentifiersInstance::Params1398 		virtual ~Params () {}
1399 
needsVkModulevkt::pipeline::__anon8967aaa10111::ConstantModuleIdentifiersInstance::Params1400 		bool needsVkModule (void) const
1401 		{
1402 			return (apiCall != APICall::CREATE_INFO);
1403 		}
1404 	};
1405 
1406 	using ParamsPtr = std::unique_ptr<Params>;
1407 
ConstantModuleIdentifiersInstance(Context & context,const Params * params)1408 					ConstantModuleIdentifiersInstance	(Context& context, const Params* params)
1409 						: vkt::TestInstance(context)
1410 						, m_params(params)
1411 						{}
~ConstantModuleIdentifiersInstance(void)1412 	virtual			~ConstantModuleIdentifiersInstance	(void) {}
1413 	tcu::TestStatus	runTest								(const DeviceInterface& vkd1, const VkDevice device1,
1414 														 const DeviceInterface& vkd2, const VkDevice device2);
1415 	tcu::TestStatus	iterate								(void) override;
1416 
1417 protected:
1418 	const Params* m_params;
1419 };
1420 
runTest(const DeviceInterface & vkd1,const VkDevice device1,const DeviceInterface & vkd2,const VkDevice device2)1421 tcu::TestStatus ConstantModuleIdentifiersInstance::runTest (const DeviceInterface& vkd1, const VkDevice device1,
1422 															const DeviceInterface& vkd2, const VkDevice device2)
1423 {
1424 	const auto& binaries = m_context.getBinaryCollection();
1425 	DE_ASSERT(!binaries.empty());
1426 
1427 	std::set<ShaderModuleId>	uniqueIds;
1428 	bool						pass		= true;
1429 	size_t						binaryCount	= 0u;
1430 
1431 	for (const auto& binary : binaries)
1432 	{
1433 		++binaryCount;
1434 		binary.setUsed();
1435 
1436 		const auto binSize			= binary.getSize();
1437 		const auto binData			= reinterpret_cast<const uint32_t*>(binary.getBinary());
1438 		const auto shaderModule1	= (m_params->needsVkModule() ? createShaderModule(vkd1, device1, binary) : Move<VkShaderModule>());
1439 		const auto shaderModule2	= (m_params->needsVkModule() ? createShaderModule(vkd2, device2, binary) : Move<VkShaderModule>());
1440 
1441 		// The first one will be a VkShaderModule if needed.
1442 		const auto id1				= (m_params->needsVkModule()
1443 									? getShaderModuleIdentifier(vkd1, device1, shaderModule1.get())
1444 									: getShaderModuleIdentifier(vkd1, device1, makeShaderModuleCreateInfo(binSize, binData)));
1445 
1446 		// The second one will be a VkShaderModule only when comparing shader modules.
1447 		const auto id2				= ((m_params->apiCall == APICall::MODULE)
1448 									? getShaderModuleIdentifier(vkd2, device2, shaderModule2.get())
1449 									: getShaderModuleIdentifier(vkd2, device2, makeShaderModuleCreateInfo(binSize, binData)));
1450 
1451 		if (id1 != id2)
1452 			pass = false;
1453 
1454 		uniqueIds.insert(id1);
1455 	}
1456 
1457 	if (!pass)
1458 		return tcu::TestStatus::fail("The same shader module returned different identifiers");
1459 
1460 	if (uniqueIds.size() != binaryCount)
1461 		return tcu::TestStatus::fail("Different modules share the same identifier");
1462 
1463 	return tcu::TestStatus::pass("Pass");
1464 }
1465 
1466 // Helper to create a new device supporting shader module identifiers.
1467 struct DeviceHelper
1468 {
1469 	Move<VkDevice>						device;
1470 	std::unique_ptr<DeviceDriver>		vkd;
1471 	deUint32							queueFamilyIndex;
1472 	VkQueue								queue;
1473 	std::unique_ptr<SimpleAllocator>	allocator;
1474 
1475 	// Forbid copy and assignment.
1476 	DeviceHelper (const DeviceHelper&) = delete;
1477 	DeviceHelper& operator= (const DeviceHelper& other) = delete;
1478 
DeviceHelpervkt::pipeline::__anon8967aaa10111::DeviceHelper1479 	DeviceHelper (Context& context, bool enableRayTracing = false)
1480 	{
1481 		const auto&	vkp					= context.getPlatformInterface();
1482 		const auto&	vki					= context.getInstanceInterface();
1483 		const auto	instance			= context.getInstance();
1484 		const auto	physicalDevice		= context.getPhysicalDevice();
1485 
1486 		queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1487 
1488 		// Get device features (these have to be checked in the test case).
1489 		VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT		shaderIdFeatures		= initVulkanStructure();
1490 		VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT	cacheControlFeatures	= initVulkanStructure(&shaderIdFeatures);
1491 
1492 		VkPhysicalDeviceDescriptorIndexingFeaturesEXT			descriptorIdxFeatures	= initVulkanStructure(&cacheControlFeatures);
1493 		VkPhysicalDeviceBufferDeviceAddressFeaturesKHR			deviceAddressFeatures	= initVulkanStructure(&descriptorIdxFeatures);
1494 
1495 		VkPhysicalDeviceFeatures2								deviceFeatures			= initVulkanStructure(enableRayTracing
1496 																												? reinterpret_cast<void*>(&deviceAddressFeatures)
1497 																												: reinterpret_cast<void*>(&cacheControlFeatures));
1498 
1499 		vki.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures);
1500 
1501 		// Make sure robust buffer access is disabled as in the default device.
1502 		deviceFeatures.features.robustBufferAccess = VK_FALSE;
1503 
1504 		const auto queuePriority = 1.0f;
1505 		const VkDeviceQueueCreateInfo queueInfo
1506 		{
1507 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,			//	VkStructureType					sType;
1508 			nullptr,											//	const void*						pNext;
1509 			0u,													//	VkDeviceQueueCreateFlags		flags;
1510 			queueFamilyIndex,									//	deUint32						queueFamilyIndex;
1511 			1u,													//	deUint32						queueCount;
1512 			&queuePriority,										//	const float*					pQueuePriorities;
1513 		};
1514 
1515 		// Required extensions. Note: many of these require VK_KHR_get_physical_device_properties2, which is an instance extension.
1516 		std::vector<const char*> requiredExtensions
1517 		{
1518 			"VK_EXT_pipeline_creation_cache_control",
1519 			"VK_EXT_shader_module_identifier",
1520 		};
1521 
1522 		if (enableRayTracing)
1523 		{
1524 			requiredExtensions.push_back("VK_KHR_maintenance3");
1525 			requiredExtensions.push_back("VK_EXT_descriptor_indexing");
1526 			requiredExtensions.push_back("VK_KHR_buffer_device_address");
1527 			requiredExtensions.push_back("VK_KHR_deferred_host_operations");
1528 			requiredExtensions.push_back("VK_KHR_acceleration_structure");
1529 			requiredExtensions.push_back("VK_KHR_shader_float_controls");
1530 			requiredExtensions.push_back("VK_KHR_spirv_1_4");
1531 			requiredExtensions.push_back("VK_KHR_ray_tracing_pipeline");
1532 		}
1533 
1534 		const VkDeviceCreateInfo createInfo
1535 		{
1536 			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,				//	VkStructureType					sType;
1537 			deviceFeatures.pNext,								//	const void*						pNext;
1538 			0u,													//	VkDeviceCreateFlags				flags;
1539 			1u,													//	deUint32						queueCreateInfoCount;
1540 			&queueInfo,											//	const VkDeviceQueueCreateInfo*	pQueueCreateInfos;
1541 			0u,													//	deUint32						enabledLayerCount;
1542 			nullptr,											//	const char* const*				ppEnabledLayerNames;
1543 			de::sizeU32(requiredExtensions),					//	deUint32						enabledExtensionCount;
1544 			de::dataOrNull(requiredExtensions),					//	const char* const*				ppEnabledExtensionNames;
1545 			&deviceFeatures.features,							//	const VkPhysicalDeviceFeatures*	pEnabledFeatures;
1546 		};
1547 
1548 		// Create custom device and related objects
1549 		device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki, physicalDevice, &createInfo);
1550 		vkd.reset(new DeviceDriver(vkp, instance, device.get(), context.getUsedApiVersion()));
1551 		queue = getDeviceQueue(*vkd, *device, queueFamilyIndex, 0u);
1552 		allocator.reset(new SimpleAllocator(*vkd, device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
1553 	}
1554 };
1555 
iterate(void)1556 tcu::TestStatus ConstantModuleIdentifiersInstance::iterate (void)
1557 {
1558 	// The second device may be the one from the context or a new device for the cases that require different devices.
1559 	const auto&							vkd		= m_context.getDeviceInterface();
1560 	const auto							device	= m_context.getDevice();
1561 	const std::unique_ptr<DeviceHelper>	helper	(m_params->differentDevices ? new DeviceHelper(m_context) : nullptr);
1562 
1563 	const auto&		di1		= vkd;
1564 	const auto		dev1	= device;
1565 	const auto&		di2		= (m_params->differentDevices ? *helper->vkd : vkd);
1566 	const auto		dev2	= (m_params->differentDevices ? helper->device.get() : device);
1567 
1568 	return runTest(di1, dev1, di2, dev2);
1569 }
1570 
1571 class ConstantModuleIdentifiersCase : public SourcesAndSupportFromParamsBase
1572 {
1573 public:
1574 	using Params	= ConstantModuleIdentifiersInstance::Params;
1575 	using ParamsPtr	= ConstantModuleIdentifiersInstance::ParamsPtr;
1576 
ConstantModuleIdentifiersCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr && params)1577 					ConstantModuleIdentifiersCase	(tcu::TestContext& testCtx, const std::string& name, ParamsPtr&& params)
1578 						: SourcesAndSupportFromParamsBase(testCtx, name, BaseParamsPtr(static_cast<BaseParams*>(params.release())))
1579 						{}
~ConstantModuleIdentifiersCase(void)1580 	virtual			~ConstantModuleIdentifiersCase	(void) {}
1581 	TestInstance*	createInstance					(Context& context) const override;
1582 };
1583 
createInstance(Context & context) const1584 TestInstance* ConstantModuleIdentifiersCase::createInstance (Context &context) const
1585 {
1586 	const auto paramsPtr = dynamic_cast<Params*>(m_params.get());
1587 	DE_ASSERT(paramsPtr);
1588 
1589 	return new ConstantModuleIdentifiersInstance(context, paramsPtr);
1590 }
1591 
1592 // Tests that create one or more pipelines using several shaders, obtain the shader ids from one of the pipelines and use them to
1593 // attempt creation of a new pipeline to be used normally.
1594 class CreateAndUseIdsInstance : public vkt::TestInstance
1595 {
1596 public:
1597 	using RndGenPtr = std::shared_ptr<de::Random>;
1598 
1599 	struct Params : public BaseParams
1600 	{
1601 		PipelineConstructionType	constructionType;
1602 		bool						useRTLibraries;		// Use ray tracing libraries? For monolithic builds only.
1603 		bool						useMaintenance5;
1604 		UseModuleCase				moduleUseCase;
1605 		CapturedPropertiesFlags		capturedProperties;	// For UseModuleCase::ID only.
1606 		RndGenPtr					rnd;
1607 
Paramsvkt::pipeline::__anon8967aaa10111::CreateAndUseIdsInstance::Params1608 		Params (PipelineType				pipelineType_,
1609 				GraphicsShaderVec			graphicsShaders_,
1610 				RTShaderVec					rtShaders_,
1611 				uint8_t						pipelineCount_,
1612 				const tcu::Maybe<uint8_t>&	pipelineToRun_,
1613 				bool						useSCs_,
1614 				bool						useCache_,
1615 				bool						useMaintenance5_,
1616 				PipelineConstructionType	constructionType_,
1617 				bool						useRTLibraries_,
1618 				UseModuleCase				moduleUseCase_,
1619 				CapturedPropertiesFlags		capturedProperties_)
1620 			: BaseParams		(pipelineType_, graphicsShaders_, rtShaders_, pipelineCount_, pipelineToRun_, useSCs_, useCache_, useMaintenance5_)
1621 			, constructionType	(constructionType_)
1622 			, useRTLibraries	(useRTLibraries_)
1623 			, useMaintenance5	(false)
1624 			, moduleUseCase		(moduleUseCase_)
1625 			, capturedProperties(capturedProperties_)
1626 			, rnd				()
1627 			{
1628 				DE_ASSERT(!useRTLibraries || hasRayTracing());
1629 				DE_ASSERT(!useRTLibraries || constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
1630 				DE_ASSERT(capturedProperties == 0u || moduleUseCase == UseModuleCase::ID);
1631 
1632 				// We will only be capturing properties if using one pipeline that will be run later.
1633 				DE_ASSERT(capturedProperties == 0u || (pipelineCount == uint8_t{1} && static_cast<bool>(pipelineToRun)));
1634 			}
1635 
~Paramsvkt::pipeline::__anon8967aaa10111::CreateAndUseIdsInstance::Params1636 		virtual ~Params () {}
1637 
1638 		// Convenience helper method.
getRndGenvkt::pipeline::__anon8967aaa10111::CreateAndUseIdsInstance::Params1639 		de::Random& getRndGen (void) const
1640 		{
1641 			return *rnd;
1642 		}
1643 
1644 		// Copy parameters resetting the random number generator with a new seed.
copyvkt::pipeline::__anon8967aaa10111::CreateAndUseIdsInstance::Params1645 		BaseParamsPtr copy (uint32_t newSeed)
1646 		{
1647 			std::unique_ptr<Params> clone (new Params(*this));
1648 			clone->rnd.reset(new de::Random(newSeed));
1649 			return BaseParamsPtr(clone.release());
1650 		}
1651 	};
1652 
1653 	using ParamsPtr = std::unique_ptr<Params>;
1654 
CreateAndUseIdsInstance(Context & context,const Params * params)1655 						CreateAndUseIdsInstance		(Context& context, const Params* params)
1656 							: vkt::TestInstance	(context)
1657 							, m_params			(params)
1658 							{}
~CreateAndUseIdsInstance(void)1659 	virtual				~CreateAndUseIdsInstance	(void) {}
1660 
1661 	tcu::TestStatus		iterate						(void) override;
1662 
1663 protected:
1664 	const Params* m_params;
1665 };
1666 
1667 class CreateAndUseIdsCase : public SourcesAndSupportFromParamsBase
1668 {
1669 public:
CreateAndUseIdsCase(tcu::TestContext & testCtx,const std::string & name,BaseParamsPtr && params)1670 					CreateAndUseIdsCase		(tcu::TestContext& testCtx, const std::string& name, BaseParamsPtr&& params)
1671 						: SourcesAndSupportFromParamsBase	(testCtx, name, std::move(params))
1672 						, m_createAndUseIdsParams			(dynamic_cast<const CreateAndUseIdsInstance::Params*>(m_params.get()))
1673 						{
1674 							DE_ASSERT(m_createAndUseIdsParams);
1675 						}
~CreateAndUseIdsCase(void)1676 	virtual			~CreateAndUseIdsCase	(void) {}
1677 	void			checkSupport			(Context& context) const override;
1678 	TestInstance*	createInstance			(Context& context) const override;
1679 
1680 protected:
1681 	const CreateAndUseIdsInstance::Params* m_createAndUseIdsParams;
1682 };
1683 
checkSupport(Context & context) const1684 void CreateAndUseIdsCase::checkSupport (Context &context) const
1685 {
1686 	SourcesAndSupportFromParamsBase::checkSupport(context);
1687 
1688 	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_createAndUseIdsParams->constructionType);
1689 
1690 	if (m_createAndUseIdsParams->useRTLibraries)
1691 		context.requireDeviceFunctionality("VK_KHR_pipeline_library");
1692 
1693 	if (m_createAndUseIdsParams->capturedProperties != 0u)
1694 		context.requireDeviceFunctionality("VK_KHR_pipeline_executable_properties");
1695 
1696 	if ((m_params->pipelineType == PipelineType::COMPUTE || m_params->hasRayTracing()) && static_cast<bool>(m_params->pipelineToRun)) {
1697 		const auto features = context.getPipelineCreationCacheControlFeatures();
1698 		if (features.pipelineCreationCacheControl == DE_FALSE)
1699 			TCU_THROW(NotSupportedError, "Feature 'pipelineCreationCacheControl' is not enabled");
1700 	}
1701 
1702 	if (m_params->useMaintenance5)
1703 		context.requireDeviceFunctionality("VK_KHR_maintenance5");
1704 }
1705 
createInstance(Context & context) const1706 TestInstance* CreateAndUseIdsCase::createInstance (Context &context) const
1707 {
1708 	return new CreateAndUseIdsInstance(context, m_createAndUseIdsParams);
1709 }
1710 
1711 using SpecInfoPtr	= std::unique_ptr<VkSpecializationInfo>;
1712 using SCMapEntryVec	= std::vector<VkSpecializationMapEntry>;
1713 
maybeMakeSpecializationInfo(bool makeIt,const VkSpecializationMapEntry * entry,std::vector<uint32_t>::const_iterator & iter)1714 SpecInfoPtr maybeMakeSpecializationInfo (bool makeIt, const VkSpecializationMapEntry* entry, std::vector<uint32_t>::const_iterator& iter)
1715 {
1716 	if (!makeIt)
1717 		return nullptr;
1718 
1719 	DE_ASSERT(entry);
1720 	SpecInfoPtr info (new VkSpecializationInfo);
1721 
1722 	info->mapEntryCount	= 1u;
1723 	info->pMapEntries	= entry;
1724 	info->dataSize		= sizeof(uint32_t);
1725 	info->pData			= &(*(iter++));
1726 
1727 	return info;
1728 }
1729 
makeRasterizationState(bool rasterizationDisabled)1730 VkPipelineRasterizationStateCreateInfo makeRasterizationState (bool rasterizationDisabled)
1731 {
1732 	VkPipelineRasterizationStateCreateInfo state = initVulkanStructure();
1733 	state.rasterizerDiscardEnable = (rasterizationDisabled ? VK_TRUE : VK_FALSE);
1734 	state.lineWidth = 1.0f;
1735 	return state;
1736 }
1737 
1738 class PipelineStageInfo
1739 {
1740 protected:
1741 	ShaderWrapper		m_shader;
1742 	ShaderModuleId		m_moduleId;
1743 	ShaderStageIdPtr	m_moduleIdCreateInfo;
1744 	SpecInfoPtr			m_specInfo;
1745 
1746 public:
PipelineStageInfo()1747 	PipelineStageInfo ()
1748 		: m_shader				()
1749 		, m_moduleId			()
1750 		, m_moduleIdCreateInfo	()
1751 		, m_specInfo			()
1752 		{}
1753 
setModule(const DeviceInterface & vkd,const VkDevice device,const ShaderWrapper shader,UseModuleCase moduleUse,de::Random & rnd)1754 	void setModule (const DeviceInterface &vkd, const VkDevice device, const ShaderWrapper shader, UseModuleCase moduleUse, de::Random& rnd)
1755 	{
1756 		m_shader				= shader;
1757 
1758 		m_moduleId				= getShaderModuleIdentifier(vkd, device, shader.getModule());
1759 		maybeMangleShaderModuleId(m_moduleId, moduleUse, rnd);
1760 
1761 		m_moduleIdCreateInfo	= makeShaderStageModuleIdentifierCreateInfo(m_moduleId, moduleUse, &rnd);
1762 	}
1763 
setSpecInfo(SpecInfoPtr && specInfo)1764 	void setSpecInfo (SpecInfoPtr&& specInfo)
1765 	{
1766 		m_specInfo = std::move(specInfo);
1767 	}
1768 
getModule(void) const1769 	ShaderWrapper getModule (void) const
1770 	{
1771 		return m_shader;
1772 	}
1773 
getUsedModule(UseModuleCase moduleUse)1774 	ShaderWrapper* getUsedModule (UseModuleCase moduleUse)
1775 	{
1776 		return retUsedModule(&m_shader, moduleUse);
1777 	}
1778 
getModuleIdCreateInfo(void) const1779 	const VkPipelineShaderStageModuleIdentifierCreateInfoEXT* getModuleIdCreateInfo (void) const
1780 	{
1781 		return m_moduleIdCreateInfo.get();
1782 	}
1783 
getSpecInfo(void) const1784 	const VkSpecializationInfo* getSpecInfo (void) const
1785 	{
1786 		return m_specInfo.get();
1787 	}
1788 
1789 	// Forbid copy and assignment. This would break the relationship between moduleId and moduleIdCreateInfo.
1790 	PipelineStageInfo (const PipelineStageInfo&) = delete;
1791 	PipelineStageInfo& operator=(const PipelineStageInfo&) = delete;
1792 };
1793 
makeComputeSpecConstants(uint32_t stageConstant)1794 std::vector<uint32_t> makeComputeSpecConstants (uint32_t stageConstant)
1795 {
1796 	return std::vector<uint32_t>{stageConstant, 1u, 1u, 1u};
1797 }
1798 
makeComputeSpecMapEntries(void)1799 SCMapEntryVec makeComputeSpecMapEntries (void)
1800 {
1801 	const auto		kNumEntries	= 4u; // Matches the vector above.
1802 	const auto		entrySizeSz	= sizeof(uint32_t);
1803 	const auto		entrySize	= static_cast<uint32_t>(entrySizeSz);
1804 	SCMapEntryVec	entries;
1805 
1806 	entries.reserve(kNumEntries);
1807 	for (uint32_t i = 0u; i < kNumEntries; ++i)
1808 	{
1809 		const VkSpecializationMapEntry entry =
1810 		{
1811 			i,					//	uint32_t	constantID;
1812 			(entrySize * i),	//	uint32_t	offset;
1813 			entrySizeSz,		//	size_t		size;
1814 		};
1815 		entries.push_back(entry);
1816 	}
1817 
1818 	return entries;
1819 }
1820 
makeComputeSpecInfo(const SCMapEntryVec & scEntries,const std::vector<uint32_t> & scData)1821 SpecInfoPtr makeComputeSpecInfo (const SCMapEntryVec& scEntries, const std::vector<uint32_t>& scData)
1822 {
1823 	SpecInfoPtr scInfo (new VkSpecializationInfo);
1824 
1825 	scInfo->mapEntryCount	= de::sizeU32(scEntries);
1826 	scInfo->pMapEntries		= de::dataOrNull(scEntries);
1827 	scInfo->dataSize		= de::dataSize(scData);
1828 	scInfo->pData			= de::dataOrNull(scData);
1829 
1830 	return scInfo;
1831 }
1832 
iterate(void)1833 tcu::TestStatus CreateAndUseIdsInstance::iterate (void)
1834 {
1835 	const auto&			vki				= m_context.getInstanceInterface();
1836 	const auto&			vkd				= m_context.getDeviceInterface();
1837 	const auto			physicalDevice	= m_context.getPhysicalDevice();
1838 	const auto			device			= m_context.getDevice();
1839 	auto&				alloc			= m_context.getDefaultAllocator();
1840 	const auto			queue			= m_context.getUniversalQueue();
1841 	const auto			queueIndex		= m_context.getUniversalQueueFamilyIndex();
1842 
1843 	const auto			pipelineStages	= m_params->getPipelineStageFlags();
1844 	const auto			shaderStages	= m_params->getShaderStageFlags();
1845 	const auto			captureFlags	= getPipelineCreateFlags(m_params->capturedProperties);
1846 	const bool			needsCapture	= (captureFlags != 0u);
1847 	const auto			isGraphics		= (m_params->pipelineType == PipelineType::GRAPHICS);
1848 	const auto			isCompute		= (m_params->pipelineType == PipelineType::COMPUTE);
1849 	const auto			fbFormat		= VK_FORMAT_R8G8B8A8_UNORM;
1850 	const auto			tcuFbFormat		= mapVkFormat(fbFormat);
1851 	const auto			pixelSize		= tcu::getPixelSize(tcuFbFormat);
1852 	const auto			fbExtent		= makeExtent3D(1u, 1u, 1u);
1853 	const tcu::IVec3	iExtent			(static_cast<int>(fbExtent.width), static_cast<int>(fbExtent.height), static_cast<int>(fbExtent.depth));
1854 	const auto			isRT			= m_params->hasRayTracing();
1855 	const auto			hasHit			= m_params->hasHit();
1856 	const auto			hasHitAndMiss	= hasHit && m_params->hasMiss();
1857 	const auto			stagesCount		= m_params->stageCountPerPipeline();
1858 	const auto			pipelineCount32	= static_cast<uint32_t>(m_params->pipelineCount);
1859 	const auto			hasTess			= m_params->hasTess();
1860 	const auto			topology		= (hasTess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
1861 	const auto			patchCPs		= (hasTess ? 3u : 0u);
1862 	const auto			useSCs			= m_params->useSpecializationConstants;
1863 	const auto			shaderConstants	= generateShaderConstants(m_params->pipelineType, m_params->pipelineCount, stagesCount);
1864 	const auto			runOnePipeline	= static_cast<bool>(m_params->pipelineToRun);
1865 	const bool			reqCacheMiss	= expectCacheMiss(m_params->moduleUseCase);
1866 	const bool			qualityWarn		= (m_params->useCache && !needsCapture);
1867 	const tcu::Vec4		clearColor		(0.0f, 0.0f, 0.0f, 0.0f);
1868 	const tcu::Vec4		blueColor		(0.0f, 0.0f, 1.0f, 1.0f); // Must match fragment shader above.
1869 
1870 	// Used when capturing pipeline executable properties.
1871 	PipelineExecutablePropertyVec classicExeProps;
1872 	PipelineExecutablePropertyVec identifierExeProps;
1873 
1874 	// Command pool and buffer.
1875 	const auto cmdPool		= makeCommandPool(vkd, device, queueIndex);
1876 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1877 	const auto cmdBuffer	= cmdBufferPtr.get();
1878 
1879 	// Begin command buffer. We may need it below for RT.
1880 	beginCommandBuffer(vkd, cmdBuffer);
1881 
1882 	// Descriptor set layouts. Typically 1 but ray tracing tests use a separate set for the acceleration structure.
1883 	std::vector<VkDescriptorSetLayout> setLayouts;
1884 
1885 	DescriptorSetLayoutBuilder setLayoutBuilder;
1886 	setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, shaderStages);
1887 	for (uint8_t i = 0; i < m_params->pipelineCount; ++i)
1888 		setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, shaderStages);
1889 	const auto mainSetLayout = setLayoutBuilder.build(vkd, device);
1890 	setLayouts.push_back(mainSetLayout.get());
1891 
1892 	const auto auxSetLayout	= (isRT
1893 							? DescriptorSetLayoutBuilder().addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, shaderStages).build(vkd, device)
1894 							: Move<VkDescriptorSetLayout>());
1895 	if (isRT)
1896 		setLayouts.push_back(auxSetLayout.get());
1897 
1898 	// Pipeline layout.
1899 	PipelineLayoutWrapper pipelineLayout (m_params->constructionType, vkd, device, de::sizeU32(setLayouts), de::dataOrNull(setLayouts));
1900 
1901 	// Descriptor pool.
1902 	DescriptorPoolBuilder poolBuilder;
1903 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1904 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pipelineCount32);
1905 	if (isRT)
1906 		poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
1907 	const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, de::sizeU32(setLayouts));
1908 
1909 	// Descriptor buffers.
1910 	const auto			storageBufferSize	= static_cast<VkDeviceSize>(sizeof(uint32_t) * stagesCount);
1911 	const auto			storageBufferInfo	= makeBufferCreateInfo(storageBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1912 	BufferWithMemory	storageBuffer		(vkd, device, alloc, storageBufferInfo, MemoryRequirement::HostVisible);
1913 	auto&				storageBufferAlloc	= storageBuffer.getAllocation();
1914 	void*				storageBufferData	= storageBufferAlloc.getHostPtr();
1915 
1916 	// For the uniform buffers we'll use a single allocation.
1917 	const auto			deviceProperties	= getPhysicalDeviceProperties(vki, physicalDevice);
1918 	const auto			minBlock			= de::roundUp(static_cast<VkDeviceSize>(sizeof(uint32_t)), deviceProperties.limits.minUniformBufferOffsetAlignment);
1919 	const auto			uniformBufferSize	= minBlock * pipelineCount32;
1920 	const auto			uniformBufferInfo	= makeBufferCreateInfo(uniformBufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
1921 	BufferWithMemory	uniformBuffer		(vkd, device, alloc, uniformBufferInfo, MemoryRequirement::HostVisible);
1922 	auto&				uniformBufferAlloc	= uniformBuffer.getAllocation();
1923 	void*				uniformBufferData	= uniformBufferAlloc.getHostPtr();
1924 
1925 	deMemset(storageBufferData, 0, static_cast<size_t>(storageBufferSize));
1926 	deMemset(uniformBufferData, 0, static_cast<size_t>(uniformBufferSize));
1927 	flushAlloc(vkd, device, storageBufferAlloc);
1928 	flushAlloc(vkd, device, uniformBufferAlloc);
1929 
1930 	// Acceleration structures if needed.
1931 	using TLASPtr = de::MovePtr<TopLevelAccelerationStructure>;
1932 	using BLASPtr = de::SharedPtr<BottomLevelAccelerationStructure>;
1933 
1934 	TLASPtr tlas;
1935 	BLASPtr blas;
1936 
1937 	if (isRT)
1938 	{
1939 		tlas = makeTopLevelAccelerationStructure();
1940 		blas = BLASPtr(makeBottomLevelAccelerationStructure().release());
1941 
1942 		// If we don't want hits we move the geometry way off in the X axis.
1943 		// If we want hits and misses we launch 2 rays (see raygen shader).
1944 		const float xOffset = (hasHit ? 0.0f : 100.0f);
1945 
1946 		if (m_params->hasISec())
1947 		{
1948 			// AABB around (0.5, 0.5, 5).
1949 			const std::vector<tcu::Vec3> geometry
1950 			{
1951 				tcu::Vec3(0.0f + xOffset, 0.0f, 4.0f),
1952 				tcu::Vec3(1.0f + xOffset, 1.0f, 6.0f),
1953 			};
1954 
1955 			blas->addGeometry(geometry, false/*isTriangles*/, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
1956 		}
1957 		else
1958 		{
1959 			// Triangle surrounding (0.5, 0.5, 5).
1960 			const std::vector<tcu::Vec3> geometry
1961 			{
1962 				tcu::Vec3(0.25f + xOffset, 0.25f, 5.0f),
1963 				tcu::Vec3(0.75f + xOffset, 0.25f, 5.0f),
1964 				tcu::Vec3(0.5f  + xOffset, 0.75f, 5.0f),
1965 			};
1966 
1967 			blas->addGeometry(geometry, true/*isTriangles*/, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
1968 		}
1969 		blas->createAndBuild(vkd, device, cmdBuffer, alloc);
1970 		tlas->setInstanceCount(1u);
1971 		tlas->addInstance(blas, identityMatrix3x4, 0u, 0xFFu, 0u, VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR);
1972 
1973 		tlas->createAndBuild(vkd, device, cmdBuffer, alloc);
1974 	}
1975 
1976 	// Graphics pipeline data if needed.
1977 	std::unique_ptr<ImageWithMemory>	colorAtt;
1978 	VkImageSubresourceRange				colorSRR;
1979 	VkImageSubresourceLayers			colorSRL;
1980 	Move<VkImageView>					colorAttView;
1981 	RenderPassWrapper					renderPass;
1982 	std::unique_ptr<BufferWithMemory>	verifBuffer;
1983 	std::vector<VkViewport>				viewports;
1984 	std::vector<VkRect2D>				scissors;
1985 
1986 	// This is constant for all shader stages.
1987 	const VkSpecializationMapEntry scMapEntry =
1988 	{
1989 		0u,					//	uint32_t	constantID;
1990 		0u,					//	uint32_t	offset;
1991 		sizeof(uint32_t),	//	size_t		size;
1992 	};
1993 
1994 	if (isGraphics)
1995 	{
1996 		const VkImageCreateInfo colorAttCreateInfo =
1997 		{
1998 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										//	VkStructureType			sType;
1999 			nullptr,																	//	const void*				pNext;
2000 			0u,																			//	VkImageCreateFlags		flags;
2001 			VK_IMAGE_TYPE_2D,															//	VkImageType				imageType;
2002 			fbFormat,																	//	VkFormat				format;
2003 			fbExtent,																	//	VkExtent3D				extent;
2004 			1u,																			//	uint32_t				mipLevels;
2005 			1u,																			//	uint32_t				arrayLayers;
2006 			VK_SAMPLE_COUNT_1_BIT,														//	VkSampleCountFlagBits	samples;
2007 			VK_IMAGE_TILING_OPTIMAL,													//	VkImageTiling			tiling;
2008 			(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),	//	VkImageUsageFlags		usage;
2009 			VK_SHARING_MODE_EXCLUSIVE,													//	VkSharingMode			sharingMode;
2010 			0u,																			//	uint32_t				queueFamilyIndexCount;
2011 			nullptr,																	//	const uint32_t*			pQueueFamilyIndices;
2012 			VK_IMAGE_LAYOUT_UNDEFINED,													//	VkImageLayout			initialLayout;
2013 		};
2014 
2015 		colorAtt		.reset(new ImageWithMemory(vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any));
2016 		colorSRR		= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2017 		colorSRL		= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
2018 		colorAttView	= makeImageView(vkd, device, colorAtt->get(), VK_IMAGE_VIEW_TYPE_2D, fbFormat, colorSRR);
2019 		renderPass		= RenderPassWrapper(m_params->constructionType, vkd, device, fbFormat);
2020 		renderPass.createFramebuffer(vkd, device, **colorAtt, colorAttView.get(), fbExtent.width, fbExtent.height);
2021 
2022 		DE_ASSERT(fbExtent.width == 1u && fbExtent.height == 1u && fbExtent.depth == 1u);
2023 		const auto verifBufferSize = static_cast<VkDeviceSize>(pixelSize);
2024 		const auto verifBufferInfo = makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2025 		verifBuffer.reset(new BufferWithMemory(vkd, device, alloc, verifBufferInfo, MemoryRequirement::HostVisible));
2026 
2027 		viewports.push_back(makeViewport(fbExtent));
2028 		scissors.push_back(makeRect2D(fbExtent));
2029 	}
2030 
2031 	// Descriptor sets.
2032 	const auto mainDescriptorSet	= makeDescriptorSet(vkd, device, descriptorPool.get(), mainSetLayout.get());
2033 	const auto auxDescriptorSet		= (isRT ? makeDescriptorSet(vkd, device, descriptorPool.get(), auxSetLayout.get()) : Move<VkDescriptorSet>());
2034 
2035 	std::vector<VkDescriptorSet> rawDescriptorSets;
2036 	rawDescriptorSets.push_back(mainDescriptorSet.get());
2037 	if (isRT)
2038 		rawDescriptorSets.push_back(auxDescriptorSet.get());
2039 
2040 	// Update descriptor sets.
2041 	DescriptorSetUpdateBuilder updateBuilder;
2042 	{
2043 		const auto storageDescInfo = makeDescriptorBufferInfo(storageBuffer.get(), 0ull, storageBufferSize);
2044 		updateBuilder.writeSingle(mainDescriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageDescInfo);
2045 	}
2046 	for (uint32_t uboIdx = 0u; uboIdx < pipelineCount32; ++uboIdx)
2047 	{
2048 		const auto uboDescInfo = makeDescriptorBufferInfo(uniformBuffer.get(), minBlock * uboIdx, minBlock);
2049 		updateBuilder.writeSingle(mainDescriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(uboIdx + 1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uboDescInfo);
2050 	}
2051 	if (isRT)
2052 	{
2053 		const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
2054 		{
2055 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
2056 			nullptr,
2057 			1u,
2058 			tlas.get()->getPtr(),
2059 		};
2060 
2061 		updateBuilder.writeSingle(auxDescriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
2062 	}
2063 	updateBuilder.update(vkd, device);
2064 
2065 	// Make pipelines.
2066 	using ModuleVec			= std::vector<ShaderWrapper>;
2067 	using PipelinePtrVec	= std::vector<Move<VkPipeline>>;
2068 	using PipelineVec		= std::vector<VkPipeline>;
2069 	using WrapperVec		= std::vector<std::unique_ptr<GraphicsPipelineWrapper>>;
2070 	using BufferPtr			= de::MovePtr<BufferWithMemory>;
2071 
2072 	ModuleVec vertModules;
2073 	ModuleVec tescModules;
2074 	ModuleVec teseModules;
2075 	ModuleVec geomModules;
2076 	ModuleVec fragModules;
2077 
2078 	ModuleVec compModules;
2079 
2080 	ModuleVec rgenModules;
2081 	ModuleVec ahitModules;
2082 	ModuleVec chitModules;
2083 	ModuleVec isecModules;
2084 	ModuleVec missModules;
2085 	ModuleVec callModules;
2086 
2087 	BufferPtr rgenSBT;
2088 	BufferPtr xhitSBT;
2089 	BufferPtr missSBT;
2090 	BufferPtr callSBT;
2091 
2092 	VkStridedDeviceAddressRegionKHR rgenRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2093 	VkStridedDeviceAddressRegionKHR xhitRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2094 	VkStridedDeviceAddressRegionKHR missRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2095 	VkStridedDeviceAddressRegionKHR callRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2096 
2097 	WrapperVec				pipelineWrappers;	// For graphics pipelines.
2098 	PipelinePtrVec			pipelinePtrs;		// For other pipelines.
2099 	PipelineVec				pipelines;
2100 	Move<VkPipelineCache>	pipelineCache;
2101 
2102 	if (m_params->useCache)
2103 	{
2104 		const VkPipelineCacheCreateInfo cacheCreateInfo = initVulkanStructure();
2105 		pipelineCache = createPipelineCache(vkd, device, &cacheCreateInfo);
2106 	}
2107 
2108 	const auto& binaries = m_context.getBinaryCollection();
2109 
2110 	if (isGraphics)
2111 	{
2112 		const VkPipelineVertexInputStateCreateInfo		vertexInputState			= initVulkanStructure();
2113 		const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyState			=
2114 		{
2115 			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
2116 			nullptr,														//	const void*								pNext;
2117 			0u,																//	VkPipelineInputAssemblyStateCreateFlags	flags;
2118 			topology,														//	VkPrimitiveTopology						topology;
2119 			VK_FALSE,														//	VkBool32								primitiveRestartEnable;
2120 		};
2121 		const VkPipelineDepthStencilStateCreateInfo		depthStencilState			= initVulkanStructure();
2122 		VkPipelineMultisampleStateCreateInfo			multisampleState			= initVulkanStructure();
2123 		multisampleState.rasterizationSamples										= VK_SAMPLE_COUNT_1_BIT;
2124 		VkPipelineColorBlendAttachmentState				colorBlendAttachmentState;
2125 		deMemset(&colorBlendAttachmentState, 0, sizeof(colorBlendAttachmentState));
2126 		colorBlendAttachmentState.colorWriteMask									= (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
2127 		const VkPipelineColorBlendStateCreateInfo		colorBlendState				=
2128 		{
2129 			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType
2130 			nullptr,													//	const void*									pNext
2131 			0u,															//	VkPipelineColorBlendStateCreateFlags		flags
2132 			VK_FALSE,													//	VkBool32									logicOpEnable
2133 			VK_LOGIC_OP_CLEAR,											//	VkLogicOp									logicOp
2134 			1u,															//	deUint32									attachmentCount
2135 			&colorBlendAttachmentState,									//	const VkPipelineColorBlendAttachmentState*	pAttachments
2136 			{ 0.0f, 0.0f, 0.0f, 0.0f }									//	float										blendConstants[4]
2137 		};
2138 
2139 		auto shaderConstIt = shaderConstants.begin();
2140 
2141 		// In case we have to run a pipeline.
2142 		PipelineStageInfo vertToRun;
2143 		PipelineStageInfo tescToRun;
2144 		PipelineStageInfo teseToRun;
2145 		PipelineStageInfo geomToRun;
2146 		PipelineStageInfo fragToRun;
2147 
2148 		for (uint32_t i = 0; i < pipelineCount32; ++i)
2149 		{
2150 			const auto runThis	= (runOnePipeline && static_cast<uint32_t>(m_params->pipelineToRun.get()) == i);
2151 			const auto suffix	= "_" + std::to_string(i);
2152 			const auto vertName	= "vert" + suffix;
2153 			const auto tescName	= "tesc" + suffix;
2154 			const auto teseName	= "tese" + suffix;
2155 			const auto geomName	= "geom" + suffix;
2156 			const auto fragName	= "frag" + suffix;
2157 
2158 			pipelineWrappers.emplace_back(new GraphicsPipelineWrapper(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_params->constructionType, captureFlags));
2159 			auto& wrapper = *pipelineWrappers.back();
2160 
2161 			ShaderWrapper	vertModule;
2162 			ShaderWrapper	tescModule;
2163 			ShaderWrapper	teseModule;
2164 			ShaderWrapper	geomModule;
2165 			ShaderWrapper	fragModule;
2166 
2167 			SpecInfoPtr		vertSpecInfo;
2168 			SpecInfoPtr		tescSpecInfo;
2169 			SpecInfoPtr		teseSpecInfo;
2170 			SpecInfoPtr		geomSpecInfo;
2171 			SpecInfoPtr		fragSpecInfo;
2172 
2173 			vertModules		.push_back(ShaderWrapper(vkd, device, binaries.get(vertName)));
2174 			vertModule		= vertModules.back();
2175 			vertSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2176 
2177 			if (binaries.contains(tescName))
2178 			{
2179 				tescModules		.push_back(ShaderWrapper(vkd, device, binaries.get(tescName)));
2180 				tescModule		= tescModules.back();
2181 				tescSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2182 			}
2183 
2184 			if (binaries.contains(teseName))
2185 			{
2186 				teseModules		.push_back(ShaderWrapper(vkd, device, binaries.get(teseName)));
2187 				teseModule		= teseModules.back();
2188 				teseSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2189 			}
2190 
2191 			if (binaries.contains(geomName))
2192 			{
2193 				geomModules		.push_back(ShaderWrapper(vkd, device, binaries.get(geomName)));
2194 				geomModule		= geomModules.back();
2195 				geomSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2196 			}
2197 
2198 			if (binaries.contains(fragName))
2199 			{
2200 				fragModules		.push_back(ShaderWrapper(vkd, device, binaries.get(fragName)));
2201 				fragModule		= fragModules.back();
2202 				fragSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2203 			}
2204 
2205 			const auto rasterizationState = makeRasterizationState(!fragModule.isSet());
2206 
2207 			if (m_params->useMaintenance5)
2208 				wrapper.setPipelineCreateFlags2(translateCreateFlag(captureFlags));
2209 
2210 			wrapper	.setDefaultPatchControlPoints(patchCPs)
2211 					.setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
2212 					.setupPreRasterizationShaderState2(
2213 						viewports,
2214 						scissors,
2215 						pipelineLayout,
2216 						renderPass.get(),
2217 						0u,
2218 						vertModule,
2219 						&rasterizationState,
2220 						tescModule,
2221 						teseModule,
2222 						geomModule,
2223 						vertSpecInfo.get(),
2224 						tescSpecInfo.get(),
2225 						teseSpecInfo.get(),
2226 						geomSpecInfo.get(),
2227 						nullptr,
2228 						PipelineRenderingCreateInfoWrapper(),
2229 						pipelineCache.get())
2230 					.setupFragmentShaderState(
2231 						pipelineLayout,
2232 						renderPass.get(),
2233 						0u,
2234 						fragModule,
2235 						&depthStencilState,
2236 						&multisampleState,
2237 						fragSpecInfo.get(),
2238 						pipelineCache.get())
2239 					.setupFragmentOutputState(*renderPass, 0u, &colorBlendState, &multisampleState, pipelineCache.get())
2240 					.setMonolithicPipelineLayout(pipelineLayout)
2241 					.buildPipeline(pipelineCache.get());
2242 
2243 			pipelines.push_back(wrapper.getPipeline());
2244 
2245 			// Capture properties if needed.
2246 			if (needsCapture)
2247 				classicExeProps = getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2248 
2249 			if (runThis)
2250 			{
2251 				vertToRun.setModule(vkd, device, vertModule, m_params->moduleUseCase, m_params->getRndGen());
2252 				vertToRun.setSpecInfo(std::move(vertSpecInfo));
2253 
2254 				if (tescModule.isSet())
2255 				{
2256 					tescToRun.setModule(vkd, device, tescModule, m_params->moduleUseCase, m_params->getRndGen());
2257 					tescToRun.setSpecInfo(std::move(tescSpecInfo));
2258 				}
2259 
2260 				if (teseModule.isSet())
2261 				{
2262 					teseToRun.setModule(vkd, device, teseModule, m_params->moduleUseCase, m_params->getRndGen());
2263 					teseToRun.setSpecInfo(std::move(teseSpecInfo));
2264 				}
2265 
2266 				if (geomModule.isSet())
2267 				{
2268 					geomToRun.setModule(vkd, device, geomModule, m_params->moduleUseCase, m_params->getRndGen());
2269 					geomToRun.setSpecInfo(std::move(geomSpecInfo));
2270 				}
2271 
2272 				if (fragModule.isSet())
2273 				{
2274 					fragToRun.setModule(vkd, device, fragModule, m_params->moduleUseCase, m_params->getRndGen());
2275 					fragToRun.setSpecInfo(std::move(fragSpecInfo));
2276 				}
2277 			}
2278 		}
2279 
2280 		if (runOnePipeline)
2281 		{
2282 			// Append the pipeline to run at the end of the vector.
2283 			pipelineWrappers.emplace_back(new GraphicsPipelineWrapper(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_params->constructionType, captureFlags));
2284 			auto& wrapper = *pipelineWrappers.back();
2285 
2286 			const auto fragModule			= fragToRun.getModule();
2287 			const auto rasterizationState	= makeRasterizationState(!fragModule.isSet());
2288 
2289 			try
2290 			{
2291 				wrapper	.setDefaultPatchControlPoints(patchCPs)
2292 						.setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
2293 						.setupPreRasterizationShaderState3(
2294 							viewports,
2295 							scissors,
2296 							pipelineLayout,
2297 							renderPass.get(),
2298 							0u,
2299 							*vertToRun.getUsedModule(m_params->moduleUseCase),
2300 							PipelineShaderStageModuleIdentifierCreateInfoWrapper(vertToRun.getModuleIdCreateInfo()),
2301 							&rasterizationState,
2302 							*tescToRun.getUsedModule(m_params->moduleUseCase),
2303 							PipelineShaderStageModuleIdentifierCreateInfoWrapper(tescToRun.getModuleIdCreateInfo()),
2304 							*teseToRun.getUsedModule(m_params->moduleUseCase),
2305 							PipelineShaderStageModuleIdentifierCreateInfoWrapper(teseToRun.getModuleIdCreateInfo()),
2306 							*geomToRun.getUsedModule(m_params->moduleUseCase),
2307 							PipelineShaderStageModuleIdentifierCreateInfoWrapper(geomToRun.getModuleIdCreateInfo()),
2308 							vertToRun.getSpecInfo(),
2309 							tescToRun.getSpecInfo(),
2310 							teseToRun.getSpecInfo(),
2311 							geomToRun.getSpecInfo(),
2312 							nullptr,
2313 							PipelineRenderingCreateInfoWrapper(),
2314 							pipelineCache.get())
2315 						.setupFragmentShaderState2(
2316 							pipelineLayout,
2317 							renderPass.get(),
2318 							0u,
2319 							*fragToRun.getUsedModule(m_params->moduleUseCase),
2320 							fragToRun.getModuleIdCreateInfo(),
2321 							&depthStencilState,
2322 							&multisampleState,
2323 							fragToRun.getSpecInfo(),
2324 							pipelineCache.get())
2325 						.setupFragmentOutputState(*renderPass, 0u, &colorBlendState, &multisampleState, pipelineCache.get())
2326 						.setMonolithicPipelineLayout(pipelineLayout)
2327 						.buildPipeline(pipelineCache.get());
2328 
2329 				if (reqCacheMiss)
2330 					TCU_FAIL("Cache miss expected");
2331 			}
2332 			catch (const PipelineCompileRequiredError& err)
2333 			{
2334 				if (reqCacheMiss)
2335 					return tcu::TestStatus::pass("Pass");
2336 
2337 				if (qualityWarn)
2338 					return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "VK_PIPELINE_COMPILE_REQUIRED despite passing a pipeline cache");
2339 				return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED"); // ;_;
2340 			}
2341 
2342 			pipelines.push_back(wrapper.getPipeline());
2343 
2344 			if (needsCapture)
2345 				identifierExeProps = getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2346 		}
2347 	}
2348 	else if (isCompute)
2349 	{
2350 		const auto	invalidPipelineIdx	= std::numeric_limits<uint32_t>::max();
2351 		auto		idxToRun			= invalidPipelineIdx;
2352 
2353 		for (uint32_t i = 0; i < pipelineCount32; ++i)
2354 		{
2355 			const auto runThis		= (runOnePipeline && static_cast<uint32_t>(m_params->pipelineToRun.get()) == i);
2356 			const auto suffix		= "_" + std::to_string(i);
2357 			const auto compName		= "comp" + suffix;
2358 
2359 			const auto scData		= (useSCs ? makeComputeSpecConstants(shaderConstants.at(i)) : std::vector<uint32_t>());
2360 			const auto scEntries	= (useSCs ? makeComputeSpecMapEntries() : std::vector<VkSpecializationMapEntry>());
2361 			const auto scInfo		= (useSCs ? makeComputeSpecInfo(scEntries, scData) : nullptr);
2362 
2363 			compModules.push_back(ShaderWrapper(vkd, device, binaries.get(compName)));
2364 			pipelinePtrs.push_back(makeComputePipeline(vkd, device, pipelineLayout.get(), captureFlags, nullptr, compModules.back().getModule(), 0u, scInfo.get(), pipelineCache.get()));
2365 			pipelines.push_back(pipelinePtrs.back().get());
2366 
2367 			if (runThis)
2368 				idxToRun = i;
2369 
2370 			if (needsCapture)
2371 				classicExeProps = getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2372 		}
2373 
2374 		if (idxToRun != invalidPipelineIdx)
2375 		{
2376 			auto& compModule		= compModules.at(idxToRun);
2377 			auto moduleId			= getShaderModuleIdentifier(vkd, device, compModule.getModule());
2378 
2379 			maybeMangleShaderModuleId(moduleId, m_params->moduleUseCase, m_params->getRndGen());
2380 
2381 			const auto modInfo		= makeShaderStageModuleIdentifierCreateInfo(moduleId, m_params->moduleUseCase, &(m_params->getRndGen()));
2382 			const auto scData		= (useSCs ? makeComputeSpecConstants(shaderConstants.at(idxToRun)) : std::vector<uint32_t>());
2383 			const auto scEntries	= (useSCs ? makeComputeSpecMapEntries() : std::vector<VkSpecializationMapEntry>());
2384 			const auto scInfo		= (useSCs ? makeComputeSpecInfo(scEntries, scData) : nullptr);
2385 
2386 			// Append the pipeline to run at the end of the vector.
2387 			{
2388 				const auto pipelineFlags = (VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT | captureFlags);
2389 
2390 				const VkPipelineShaderStageCreateInfo pipelineShaderStageParams =
2391 				{
2392 					VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,				// VkStructureType						sType;
2393 					modInfo.get(),														// const void*							pNext;
2394 					0u,																	// VkPipelineShaderStageCreateFlags		flags;
2395 					VK_SHADER_STAGE_COMPUTE_BIT,										// VkShaderStageFlagBits				stage;
2396 					retUsedModule(&compModule, m_params->moduleUseCase)->getModule(),	// VkShaderModule						module;
2397 					"main",																// const char*							pName;
2398 					scInfo.get(),														// const VkSpecializationInfo*			pSpecializationInfo;
2399 				};
2400 
2401 				const VkComputePipelineCreateInfo pipelineCreateInfo =
2402 				{
2403 					VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,		// VkStructureType					sType;
2404 					nullptr,											// const void*						pNext;
2405 					pipelineFlags,										// VkPipelineCreateFlags			flags;
2406 					pipelineShaderStageParams,							// VkPipelineShaderStageCreateInfo	stage;
2407 					pipelineLayout.get(),								// VkPipelineLayout					layout;
2408 					DE_NULL,											// VkPipeline						basePipelineHandle;
2409 					0,													// deInt32							basePipelineIndex;
2410 				};
2411 
2412 				VkPipeline	pipeline;
2413 				VkResult	creationResult = vkd.createComputePipelines(device, pipelineCache.get(), 1u, &pipelineCreateInfo, nullptr, &pipeline);
2414 
2415 				if (creationResult == VK_PIPELINE_COMPILE_REQUIRED)
2416 				{
2417 					if (reqCacheMiss)
2418 						return tcu::TestStatus::pass("Pass");
2419 
2420 					if (qualityWarn)
2421 						return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "VK_PIPELINE_COMPILE_REQUIRED despite passing a pipeline cache");
2422 					return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED"); // ;_;
2423 				}
2424 				VK_CHECK(creationResult);
2425 
2426 				if (reqCacheMiss)
2427 					TCU_FAIL("Cache miss expected");
2428 
2429 				Move<VkPipeline> pipelinePtr(check<VkPipeline>(pipeline), Deleter<VkPipeline>(vkd, device, nullptr));
2430 				pipelinePtrs.emplace_back(pipelinePtr);
2431 				pipelines.push_back(pipeline);
2432 
2433 				if (needsCapture)
2434 					identifierExeProps = getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2435 			}
2436 		}
2437 	}
2438 	else if (isRT)
2439 	{
2440 		// Get some ray tracing properties and constants.
2441 		const auto rayTracingPropertiesKHR	= makeRayTracingProperties(vki, physicalDevice);
2442 		const auto shaderGroupHandleSize	= rayTracingPropertiesKHR->getShaderGroupHandleSize();
2443 		const auto shaderGroupBaseAlignment	= rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
2444 		const auto vec3Size					= static_cast<uint32_t>(sizeof(tcu::Vec3));
2445 
2446 		// Empty pipeline vector, needed in a couple places.
2447 		const std::vector<VkPipeline> emptyPipelinesVec;
2448 
2449 		auto shaderConstIt = shaderConstants.begin();
2450 
2451 		// In case we have to run a pipeline.
2452 		PipelineStageInfo rgenToRun;
2453 		PipelineStageInfo chitToRun;
2454 		PipelineStageInfo ahitToRun;
2455 		PipelineStageInfo isecToRun;
2456 		PipelineStageInfo missToRun;
2457 		PipelineStageInfo callToRun;
2458 
2459 		for (uint32_t i = 0; i < pipelineCount32; ++i)
2460 		{
2461 			const auto runThis	= (runOnePipeline && static_cast<uint32_t>(m_params->pipelineToRun.get()) == i);
2462 			const auto suffix	= "_" + std::to_string(i);
2463 			const auto rgenName	= "rgen" + suffix;
2464 			const auto chitName	= "chit" + suffix;
2465 			const auto ahitName	= "ahit" + suffix;
2466 			const auto isecName	= "isec" + suffix;
2467 			const auto missName	= "miss" + suffix;
2468 			const auto callName	= "call" + suffix;
2469 
2470 			ShaderWrapper	rgenModule;
2471 			ShaderWrapper	chitModule;
2472 			ShaderWrapper	ahitModule;
2473 			ShaderWrapper	isecModule;
2474 			ShaderWrapper	missModule;
2475 			ShaderWrapper	callModule;
2476 
2477 			SpecInfoPtr		rgenSpecInfo;
2478 			SpecInfoPtr		chitSpecInfo;
2479 			SpecInfoPtr		ahitSpecInfo;
2480 			SpecInfoPtr		isecSpecInfo;
2481 			SpecInfoPtr		missSpecInfo;
2482 			SpecInfoPtr		callSpecInfo;
2483 
2484 			uint32_t				groupCount	= 1u;
2485 			const uint32_t			rgenGroup	= 0u;
2486 			tcu::Maybe<uint32_t>	xhitGroup;
2487 			tcu::Maybe<uint32_t>	missGroup;
2488 			tcu::Maybe<uint32_t>	callGroup;
2489 
2490 			rgenModules		.push_back(ShaderWrapper(vkd, device, binaries.get(rgenName)));
2491 			rgenModule		= rgenModules.back();
2492 			rgenSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2493 
2494 			if (binaries.contains(chitName))
2495 			{
2496 				chitModules		.push_back(ShaderWrapper(vkd, device, binaries.get(chitName)));
2497 				chitModule		= chitModules.back();
2498 				chitSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2499 				xhitGroup		= (static_cast<bool>(xhitGroup) ? xhitGroup : tcu::just(groupCount++));
2500 			}
2501 
2502 			if (binaries.contains(ahitName))
2503 			{
2504 				ahitModules		.push_back(ShaderWrapper(vkd, device, binaries.get(ahitName)));
2505 				ahitModule		= ahitModules.back();
2506 				ahitSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2507 				xhitGroup		= (static_cast<bool>(xhitGroup) ? xhitGroup : tcu::just(groupCount++));
2508 			}
2509 
2510 			if (binaries.contains(isecName))
2511 			{
2512 				isecModules		.push_back(ShaderWrapper(vkd, device, binaries.get(isecName)));
2513 				isecModule		= isecModules.back();
2514 				isecSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2515 				xhitGroup		= (static_cast<bool>(xhitGroup) ? xhitGroup : tcu::just(groupCount++));
2516 			}
2517 
2518 			if (binaries.contains(missName))
2519 			{
2520 				missModules		.push_back(ShaderWrapper(vkd, device, binaries.get(missName)));
2521 				missModule		= missModules.back();
2522 				missSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2523 				missGroup		= tcu::just(groupCount++);
2524 			}
2525 
2526 			if (binaries.contains(callName))
2527 			{
2528 				callModules		.push_back(ShaderWrapper(vkd, device, binaries.get(callName)));
2529 				callModule		= callModules.back();
2530 				callSpecInfo	= maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2531 				callGroup		= tcu::just(groupCount++);
2532 			}
2533 
2534 			{
2535 				const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
2536 
2537 				// These have to match the shaders.
2538 				rayTracingPipeline->setMaxPayloadSize(vec3Size);
2539 				rayTracingPipeline->setMaxAttributeSize(vec3Size);
2540 
2541 				// Make it a library if we are using libraries.
2542 				rayTracingPipeline->setCreateFlags(captureFlags | (m_params->useRTLibraries ? VK_PIPELINE_CREATE_LIBRARY_BIT_KHR : 0));
2543 
2544 				rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule.getModule(), rgenGroup, rgenSpecInfo.get());
2545 
2546 				if (chitModule.isSet())
2547 					rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitModule.getModule(), xhitGroup.get(), chitSpecInfo.get());
2548 
2549 				if (ahitModule.isSet())
2550 					rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, ahitModule.getModule(), xhitGroup.get(), ahitSpecInfo.get());
2551 
2552 				if (isecModule.isSet())
2553 					rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, isecModule.getModule(), xhitGroup.get(), isecSpecInfo.get());
2554 
2555 				if (missModule.isSet())
2556 					rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missModule.getModule(), missGroup.get(), missSpecInfo.get());
2557 
2558 				if (callModule.isSet())
2559 					rayTracingPipeline->addShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR, callModule.getModule(), callGroup.get(), callSpecInfo.get());
2560 
2561 				pipelinePtrs.emplace_back(rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get(), emptyPipelinesVec, pipelineCache.get()));
2562 				pipelines.push_back(pipelinePtrs.back().get());
2563 
2564 				// We may need to link the pipeline just like we'll do with shader module identifiers below.
2565 				if (m_params->useRTLibraries)
2566 				{
2567 					const auto linkedPipeline = de::newMovePtr<RayTracingPipeline>();
2568 
2569 					linkedPipeline->setMaxPayloadSize(vec3Size);
2570 					linkedPipeline->setMaxAttributeSize(vec3Size);
2571 					linkedPipeline->setCreateFlags(captureFlags);
2572 
2573 					const std::vector<VkPipeline> rawPipelines(1u, pipelines.back());
2574 					pipelinePtrs.emplace_back(linkedPipeline->createPipeline(vkd, device, pipelineLayout.get(), rawPipelines, pipelineCache.get()));
2575 					pipelines.push_back(pipelinePtrs.back().get());
2576 				}
2577 
2578 				if (needsCapture)
2579 					classicExeProps = getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2580 			}
2581 
2582 			if (runThis)
2583 			{
2584 				rgenToRun.setModule(vkd, device, rgenModule, m_params->moduleUseCase, m_params->getRndGen());
2585 				rgenToRun.setSpecInfo(std::move(rgenSpecInfo));
2586 
2587 				if (chitModule.isSet())
2588 				{
2589 					chitToRun.setModule(vkd, device, chitModule, m_params->moduleUseCase, m_params->getRndGen());
2590 					chitToRun.setSpecInfo(std::move(chitSpecInfo));
2591 				}
2592 
2593 				if (ahitModule.isSet())
2594 				{
2595 					ahitToRun.setModule(vkd, device, ahitModule, m_params->moduleUseCase, m_params->getRndGen());
2596 					ahitToRun.setSpecInfo(std::move(ahitSpecInfo));
2597 				}
2598 
2599 				if (isecModule.isSet())
2600 				{
2601 					isecToRun.setModule(vkd, device, isecModule, m_params->moduleUseCase, m_params->getRndGen());
2602 					isecToRun.setSpecInfo(std::move(isecSpecInfo));
2603 				}
2604 
2605 				if (missModule.isSet())
2606 				{
2607 					missToRun.setModule(vkd, device, missModule, m_params->moduleUseCase, m_params->getRndGen());
2608 					missToRun.setSpecInfo(std::move(missSpecInfo));
2609 				}
2610 
2611 				if (callModule.isSet())
2612 				{
2613 					callToRun.setModule(vkd, device, callModule, m_params->moduleUseCase, m_params->getRndGen());
2614 					callToRun.setSpecInfo(std::move(callSpecInfo));
2615 				}
2616 			}
2617 		}
2618 
2619 		if (runOnePipeline)
2620 		{
2621 			uint32_t				groupCount	= 1u;
2622 			const uint32_t			rgenGroup	= 0u;
2623 			tcu::Maybe<uint32_t>	xhitGroup;
2624 			tcu::Maybe<uint32_t>	missGroup;
2625 			tcu::Maybe<uint32_t>	callGroup;
2626 
2627 			const auto rgenModule = rgenToRun.getModule(); DE_UNREF(rgenModule);
2628 			const auto chitModule = chitToRun.getModule();
2629 			const auto ahitModule = ahitToRun.getModule();
2630 			const auto isecModule = isecToRun.getModule();
2631 			const auto missModule = missToRun.getModule();
2632 			const auto callModule = callToRun.getModule();
2633 
2634 			if (chitModule.isSet())
2635 				xhitGroup = (xhitGroup ? xhitGroup : tcu::just(groupCount++));
2636 			if (ahitModule.isSet())
2637 				xhitGroup = (xhitGroup ? xhitGroup : tcu::just(groupCount++));
2638 			if (isecModule.isSet())
2639 				xhitGroup = (xhitGroup ? xhitGroup : tcu::just(groupCount++));
2640 
2641 			if (missModule.isSet())
2642 				missGroup = tcu::just(groupCount++);
2643 
2644 			if (callModule.isSet())
2645 				callGroup = tcu::just(groupCount++);
2646 
2647 			const auto shaderOwningPipelinePtr	= makeVkSharedPtr(de::newMovePtr<RayTracingPipeline>());
2648 			const auto shaderOwningPipeline		= shaderOwningPipelinePtr->get();
2649 
2650 			de::SharedPtr<de::MovePtr<RayTracingPipeline>>	auxiliaryPipelinePtr;
2651 			RayTracingPipeline*								auxiliaryPipeline		= nullptr;
2652 
2653 			if (m_params->useRTLibraries)
2654 			{
2655 				// The shader-owning pipeline will be a library and auxiliaryPipeline will be the bound pipeline helper.
2656 				auxiliaryPipelinePtr	= makeVkSharedPtr(de::newMovePtr<RayTracingPipeline>());
2657 				auxiliaryPipeline		= auxiliaryPipelinePtr->get();
2658 			}
2659 
2660 			// The bound pipeline is the shader-owning pipeline if not using libraries, or the auxiliary pipeline otherwise.
2661 			RayTracingPipeline* boundPipeline = (m_params->useRTLibraries ? auxiliaryPipeline : shaderOwningPipeline);
2662 
2663 			shaderOwningPipeline->setMaxPayloadSize(vec3Size);
2664 			shaderOwningPipeline->setMaxAttributeSize(vec3Size);
2665 			{
2666 				VkPipelineCreateFlags creationFlags = (VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT | captureFlags);
2667 				if (m_params->useRTLibraries)
2668 					creationFlags |= VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
2669 				shaderOwningPipeline->setCreateFlags(creationFlags);
2670 			}
2671 
2672 			shaderOwningPipeline->addShader(
2673 				VK_SHADER_STAGE_RAYGEN_BIT_KHR,
2674 				rgenToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2675 				rgenGroup,
2676 				rgenToRun.getSpecInfo(), 0,
2677 				rgenToRun.getModuleIdCreateInfo());
2678 
2679 			if (chitModule.isSet())
2680 			{
2681 				shaderOwningPipeline->addShader(
2682 					VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
2683 					chitToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2684 					xhitGroup.get(),
2685 					chitToRun.getSpecInfo(), 0,
2686 					chitToRun.getModuleIdCreateInfo());
2687 			}
2688 
2689 			if (ahitModule.isSet())
2690 			{
2691 				shaderOwningPipeline->addShader(
2692 					VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
2693 					ahitToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2694 					xhitGroup.get(),
2695 					ahitToRun.getSpecInfo(), 0,
2696 					ahitToRun.getModuleIdCreateInfo());
2697 			}
2698 
2699 			if (isecModule.isSet())
2700 			{
2701 				shaderOwningPipeline->addShader(
2702 					VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
2703 					isecToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2704 					xhitGroup.get(),
2705 					isecToRun.getSpecInfo(), 0,
2706 					isecToRun.getModuleIdCreateInfo());
2707 			}
2708 
2709 			if (missModule.isSet())
2710 			{
2711 				shaderOwningPipeline->addShader(
2712 					VK_SHADER_STAGE_MISS_BIT_KHR,
2713 					missToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2714 					missGroup.get(),
2715 					missToRun.getSpecInfo(), 0,
2716 					missToRun.getModuleIdCreateInfo());
2717 			}
2718 
2719 			if (callModule.isSet())
2720 			{
2721 				shaderOwningPipeline->addShader(
2722 					VK_SHADER_STAGE_CALLABLE_BIT_KHR,
2723 					callToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2724 					callGroup.get(),
2725 					callToRun.getSpecInfo(), 0,
2726 					callToRun.getModuleIdCreateInfo());
2727 			}
2728 
2729 			// Append the pipeline, SBTs and regions to use at the end of their vectors.
2730 			try
2731 			{
2732 				pipelinePtrs.emplace_back(shaderOwningPipeline->createPipeline(vkd, device, pipelineLayout.get(), emptyPipelinesVec, pipelineCache.get()));
2733 				pipelines.push_back(pipelinePtrs.back().get());
2734 			}
2735 			catch (const RayTracingPipeline::CompileRequiredError& err)
2736 			{
2737 				if (reqCacheMiss)
2738 					return tcu::TestStatus::pass("Pass");
2739 
2740 				if (qualityWarn)
2741 					return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "VK_PIPELINE_COMPILE_REQUIRED despite passing a pipeline cache");
2742 				return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED"); // ;_;
2743 			}
2744 
2745 			if (m_params->useRTLibraries)
2746 			{
2747 				// Create a new pipeline using the library created above, and use it as the active pipeline.
2748 				auxiliaryPipeline->setMaxPayloadSize(vec3Size);
2749 				auxiliaryPipeline->setMaxAttributeSize(vec3Size);
2750 				auxiliaryPipeline->setCreateFlags(VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT | captureFlags);
2751 
2752 				try
2753 				{
2754 					const std::vector<VkPipeline> rawPipelines(1u, pipelines.back());
2755 					pipelinePtrs.emplace_back(auxiliaryPipeline->createPipeline(vkd, device, pipelineLayout.get(), rawPipelines, pipelineCache.get()));
2756 					pipelines.push_back(pipelinePtrs.back().get());
2757 
2758 					if (reqCacheMiss)
2759 						TCU_FAIL("Cache miss expected");
2760 				}
2761 				catch (const RayTracingPipeline::CompileRequiredError& err)
2762 				{
2763 					if (reqCacheMiss)
2764 						return tcu::TestStatus::pass("Pass");
2765 
2766 					if (qualityWarn)
2767 						return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "VK_PIPELINE_COMPILE_REQUIRED on library use despite passing a pipeline cache");
2768 					return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED on library use"); // ;_;
2769 				}
2770 			}
2771 			else if (reqCacheMiss)
2772 				TCU_FAIL("Cache miss expected");
2773 
2774 			if (needsCapture)
2775 				identifierExeProps = getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2776 
2777 			const auto pipeline = pipelines.back();
2778 
2779 			rgenSBT		= boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, rgenGroup, 1u);
2780 			rgenRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, rgenSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
2781 
2782 			if (xhitGroup)
2783 			{
2784 				xhitSBT		= boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, xhitGroup.get(), 1u);
2785 				xhitRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, xhitSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
2786 			}
2787 
2788 			if (missGroup)
2789 			{
2790 				missSBT		= boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, missGroup.get(), 1u);
2791 				missRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
2792 			}
2793 
2794 			if (callGroup)
2795 			{
2796 				callSBT		= boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, callGroup.get(), 1u);
2797 				callRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, callSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
2798 			}
2799 		}
2800 	}
2801 	else
2802 	{
2803 		DE_ASSERT(false);
2804 	}
2805 
2806 	// Early exit if we don't need to run any pipeline.
2807 	if (!runOnePipeline)
2808 		return tcu::TestStatus::pass("Pass (not using any pipeline)");
2809 
2810 	// Compare executable properties if captured.
2811 	if (needsCapture)
2812 	{
2813 		using PipelineExecutablePropertySet = std::set<PipelineExecutableProperty>;
2814 
2815 		const PipelineExecutablePropertySet classicProps	(begin(classicExeProps), end(classicExeProps));
2816 		const PipelineExecutablePropertySet identifierProps	(begin(identifierExeProps), end(identifierExeProps));
2817 
2818 		if (classicProps != identifierProps)
2819 		{
2820 			auto& log = m_context.getTestContext().getLog();
2821 
2822 			log << tcu::TestLog::Message << "Properties without identifiers: " << classicExeProps << tcu::TestLog::EndMessage;
2823 			log << tcu::TestLog::Message << "Properties with    identifiers: " << identifierExeProps << tcu::TestLog::EndMessage;
2824 
2825 			TCU_FAIL("Pipeline executable properties differ (check log for details)");
2826 		}
2827 	}
2828 
2829 	if (isGraphics)
2830 	{
2831 		const auto		bindPoint	= VK_PIPELINE_BIND_POINT_GRAPHICS;
2832 		const auto		vertexCount	= (m_params->hasTess() ? 3u : 1u);
2833 
2834 		renderPass.begin(vkd, cmdBuffer, scissors.at(0u), clearColor);
2835 		vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, de::sizeU32(rawDescriptorSets), de::dataOrNull(rawDescriptorSets), 0u, nullptr);
2836 		vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipelines.back());
2837 		vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
2838 		renderPass.end(vkd, cmdBuffer);
2839 
2840 		const auto copyRegion			= makeBufferImageCopy(fbExtent, colorSRL);
2841 		const auto preHostBarrier		= makeMemoryBarrier((VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT), VK_ACCESS_HOST_READ_BIT);
2842 		const auto postRenderBarrier	= makeImageMemoryBarrier(
2843 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
2844 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2845 			colorAtt->get(), colorSRR);
2846 
2847 		// Copy color attachment to verification buffer.
2848 		cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &postRenderBarrier);
2849 		vkd.cmdCopyImageToBuffer(cmdBuffer, colorAtt->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer->get(), 1u, &copyRegion);
2850 
2851 		// Synchronize SSBO and verification buffer reads from the host.
2852 		cmdPipelineMemoryBarrier(vkd, cmdBuffer, (VK_PIPELINE_STAGE_TRANSFER_BIT | pipelineStages), VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
2853 	}
2854 	else if (isCompute)
2855 	{
2856 		const auto	bindPoint		= VK_PIPELINE_BIND_POINT_COMPUTE;
2857 		const auto	preHostBarrier	= makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
2858 
2859 		vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, de::sizeU32(rawDescriptorSets), de::dataOrNull(rawDescriptorSets), 0u, nullptr);
2860 		vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipelines.back());
2861 		vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
2862 		cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStages, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
2863 	}
2864 	else if (isRT)
2865 	{
2866 		const auto	bindPoint		= VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
2867 		const auto	preHostBarrier	= makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
2868 		const auto	rayCount		= (hasHitAndMiss ? 2u : 1u);
2869 
2870 		vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, de::sizeU32(rawDescriptorSets), de::dataOrNull(rawDescriptorSets), 0u, nullptr);
2871 		vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipelines.back());
2872 		vkd.cmdTraceRaysKHR(cmdBuffer, &rgenRegion, &missRegion, &xhitRegion, &callRegion, rayCount, 1u, 1u);
2873 		cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStages, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
2874 	}
2875 	else
2876 	{
2877 		DE_ASSERT(false);
2878 	}
2879 
2880 	// Finish and submit command buffer.
2881 	endCommandBuffer(vkd, cmdBuffer);
2882 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2883 
2884 	// Verify framebuffer if used.
2885 	if (isGraphics)
2886 	{
2887 		auto& verifBufferAlloc	= verifBuffer->getAllocation();
2888 		void* verifBufferData	= verifBufferAlloc.getHostPtr();
2889 
2890 		invalidateAlloc(vkd, device, verifBufferAlloc);
2891 
2892 		tcu::ConstPixelBufferAccess	resultAccess	(tcuFbFormat, iExtent, verifBufferData);
2893 		const tcu::Vec4				expectedColor	= (m_params->hasFrag() ? blueColor : clearColor);
2894 		const auto					resultColor		= resultAccess.getPixel(0, 0);
2895 
2896 		if (resultColor != expectedColor)
2897 		{
2898 			std::ostringstream msg;
2899 			msg << "Unexpected color found in Framebuffer: expected " << expectedColor << " but found " << resultColor;
2900 			TCU_FAIL(msg.str());
2901 		}
2902 	}
2903 
2904 	// Verify SSBO data.
2905 	{
2906 		invalidateAlloc(vkd, device, storageBufferAlloc);
2907 		std::vector<uint32_t> outputData(stagesCount, 0u);
2908 		deMemcpy(outputData.data(), storageBufferData, de::dataSize(outputData));
2909 
2910 		for (size_t stageIdx = 0u; stageIdx < stagesCount; ++stageIdx)
2911 		{
2912 			const auto& expected	= shaderConstants.at(getShaderIdx(m_params->pipelineToRun.get(), stageIdx, stagesCount));
2913 			const auto& result		= outputData.at(stageIdx);
2914 
2915 			if (expected != result)
2916 			{
2917 				std::ostringstream msg;
2918 				msg << "Unexpected data found for stage " << stageIdx << std::hex << ": expected 0x" << expected << " but found 0x" << result;
2919 				TCU_FAIL(msg.str());
2920 			}
2921 		}
2922 	}
2923 
2924 	return tcu::TestStatus::pass("Pass");
2925 }
2926 
2927 enum class Winding
2928 {
2929 	CW = 0,
2930 	CCW,
2931 };
2932 
2933 enum class Partitioning
2934 {
2935 	INTEGER = 0,
2936 	FRACTIONAL_ODD,
2937 };
2938 
operator <<(std::ostream & out,Winding w)2939 std::ostream& operator<<(std::ostream& out, Winding w)
2940 {
2941 	return (out << ((w == Winding::CW) ? "triangle_cw" : "triangle_ccw"));
2942 }
2943 
operator <<(std::ostream & out,Partitioning p)2944 std::ostream& operator<<(std::ostream& out, Partitioning p)
2945 {
2946 	return (out << ((p == Partitioning::INTEGER) ? "integer" : "fractional_odd"));
2947 }
2948 
2949 class HLSLTessellationInstance : public vkt::TestInstance
2950 {
2951 public:
HLSLTessellationInstance(Context & context,PipelineConstructionType constructionType)2952 						HLSLTessellationInstance	(Context& context, PipelineConstructionType constructionType)
2953 							: vkt::TestInstance		(context)
2954 							, m_constructionType	(constructionType)
2955 							{}
~HLSLTessellationInstance(void)2956 	virtual				~HLSLTessellationInstance	(void) {}
2957 
2958 	tcu::TestStatus		iterate						(void) override;
2959 
2960 protected:
2961 	const PipelineConstructionType m_constructionType;
2962 };
2963 
2964 class HLSLTessellationCase : public vkt::TestCase
2965 {
2966 public:
HLSLTessellationCase(tcu::TestContext & testCtx,const std::string & name,PipelineConstructionType constructionType)2967 					HLSLTessellationCase	(tcu::TestContext& testCtx, const std::string& name, PipelineConstructionType constructionType)
2968 						: vkt::TestCase			(testCtx, name)
2969 						, m_constructionType	(constructionType)
2970 						{}
~HLSLTessellationCase(void)2971 	virtual			~HLSLTessellationCase	(void) {}
2972 
2973 	void			checkSupport			(Context& context) const override;
2974 	void			initPrograms			(vk::SourceCollections& programCollection) const override;
createInstance(Context & context) const2975 	TestInstance*	createInstance			(Context& context) const override { return new HLSLTessellationInstance(context, m_constructionType); }
2976 
2977 	static std::vector<tcu::Vec4> getOutputColors (void);
2978 
2979 protected:
2980 	const PipelineConstructionType m_constructionType;
2981 };
2982 
getOutputColors(void)2983 std::vector<tcu::Vec4> HLSLTessellationCase::getOutputColors (void)
2984 {
2985 	std::vector<tcu::Vec4> outColors
2986 	{
2987 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
2988 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
2989 		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
2990 		tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
2991 	};
2992 
2993 	return outColors;
2994 }
2995 
checkSupport(Context & context) const2996 void HLSLTessellationCase::checkSupport (Context &context) const
2997 {
2998 	const auto&	vki				= context.getInstanceInterface();
2999 	const auto	physicalDevice	= context.getPhysicalDevice();
3000 
3001 	checkPipelineConstructionRequirements(vki, physicalDevice, m_constructionType);
3002 	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
3003 	checkShaderModuleIdentifierSupport(context);
3004 }
3005 
initPrograms(vk::SourceCollections & programCollection) const3006 void HLSLTessellationCase::initPrograms (vk::SourceCollections &programCollection) const
3007 {
3008 	// Vertex shader.
3009 	{
3010 		// Full-screen triangle.
3011 		std::ostringstream vert;
3012 		vert
3013 			<< "#version 450\n"
3014 			<< "out gl_PerVertex\n"
3015 			<< "{\n"
3016 			<< "    vec4 gl_Position;\n"
3017 			<< "};\n"
3018 			<< "vec2 vertexPositions[3] = vec2[](\n"
3019 			<< "    vec2(-1.0, -1.0),\n"
3020 			<< "    vec2( 3.0, -1.0),\n"
3021 			<< "    vec2(-1.0,  3.0)\n"
3022 			<< ");\n"
3023 			<< "void main (void) {\n"
3024 			<< "    gl_Position = vec4(vertexPositions[gl_VertexIndex], 0.0, 1.0);\n"
3025 			<< "}\n"
3026 			;
3027 
3028 		programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
3029 	}
3030 
3031 	// Fragment shader, which outputs the color from the previous stages.
3032 	{
3033 		std::ostringstream frag;
3034 		frag
3035 			<< "#version 450\n"
3036 			<< "layout (location=0) in vec4 inColor;\n"
3037 			<< "layout (location=0) out vec4 outColor;\n"
3038 			<< "void main (void) {\n"
3039 			<< "    outColor = inColor;\n"
3040 			<< "}\n"
3041 			;
3042 
3043 		programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
3044 	}
3045 
3046 	// Tessellation evaluation shader (AKA domain shader) in HLSL, common for every pipeline.
3047 	// Contrary to GLSL, HLSL allows us to omit execution modes in the "tese" shader and specify them on the "tesc" shader.
3048 	{
3049 		std::ostringstream tese;
3050 		tese
3051 			<< "struct HullShaderOutput\n"
3052 			<< "{\n"
3053 			<< "    float4 Position : SV_Position;\n"
3054 			<< "    [[vk::location(0)]] float4 Color : COLOR0;\n"
3055 			<< "};\n"
3056 			<< "\n"
3057 			<< "struct HullShaderConstantOutput\n"
3058 			<< "{\n"
3059 			<< "    float TessLevelOuter[4] : SV_TessFactor;\n"
3060 			<< "    float TessLevelInner[2] : SV_InsideTessFactor;\n"
3061 			<< "};\n"
3062 			<< "\n"
3063 			<< "struct DomainShaderOutput\n"
3064 			<< "{\n"
3065 			<< "    float4 Position : SV_Position;\n"
3066 			<< "    [[vk::location(0)]] float4 Color : COLOR0;\n"
3067 			<< "};\n"
3068 			<< "\n"
3069 			<< "DomainShaderOutput main (HullShaderConstantOutput input, float3 TessCoord : SV_DomainLocation, const OutputPatch<HullShaderOutput, 3> patch)\n"
3070 			<< "{\n"
3071 			<< "    DomainShaderOutput output = (DomainShaderOutput)0;\n"
3072 			<< "\n"
3073 			<< "    output.Position = (TessCoord.x * patch[0].Position) +\n"
3074 			<< "                      (TessCoord.y * patch[1].Position) +\n"
3075 			<< "                      (TessCoord.z * patch[2].Position);\n"
3076 			<< "\n"
3077 			<< "    output.Color = (TessCoord.x * patch[0].Color) +\n"
3078 			<< "                   (TessCoord.y * patch[1].Color) +\n"
3079 			<< "                   (TessCoord.z * patch[2].Color);\n"
3080 			<< "\n"
3081 			<< "    return output;\n"
3082 			<< "}\n"
3083 			;
3084 
3085 		programCollection.hlslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
3086 	}
3087 
3088 	// Tessellation control shaders. Create 4 combinations with different execution modes. Each combination will also assign a different color to the vertices.
3089 	// We will later run each pipeline to draw a pixel in a framebuffer (using viewports and scissors) to end up with 4 distinct colors.
3090 	{
3091 		const auto	outColors	= getOutputColors();
3092 		size_t		colorIdx	= 0;
3093 
3094 		const Winding		windings[]		= { Winding::CW, Winding::CCW };
3095 		const Partitioning	partitionings[]	= { Partitioning::INTEGER, Partitioning::FRACTIONAL_ODD };
3096 
3097 		for (const auto& winding : windings)
3098 			for (const auto& partitioning : partitionings)
3099 			{
3100 				std::ostringstream tesc;
3101 				tesc
3102 					<< "struct VertexShaderOutput\n"
3103 					<< "{\n"
3104 					<< "    float4 Position : SV_Position;\n"
3105 					<< "};\n"
3106 					<< "\n"
3107 					<< "struct HullShaderOutput\n"
3108 					<< "{\n"
3109 					<< "    float4 Position : SV_Position;\n"
3110 					<< "    [[vk::location(0)]] float4 Color : COLOR0;\n"
3111 					<< "};\n"
3112 					<< "\n"
3113 					<< "struct HullShaderConstantOutput\n"
3114 					<< "{\n"
3115 					<< "    float TessLevelOuter[4] : SV_TessFactor;\n"
3116 					<< "    float TessLevelInner[2] : SV_InsideTessFactor;\n"
3117 					<< "};\n"
3118 					<< "\n"
3119 					<< "[domain(\"tri\")]\n"
3120 					<< "[partitioning(\"" << partitioning << "\")]\n"
3121 					<< "[outputtopology(\"" << winding << "\")]\n"
3122 					<< "[outputcontrolpoints(3)]\n"
3123 					<< "[patchconstantfunc(\"PCF\")]\n"
3124 					<< "HullShaderOutput main (InputPatch<VertexShaderOutput, 3> patch, uint InvocationID : SV_OutputControlPointID)\n"
3125 					<< "{\n"
3126 					<< "    HullShaderOutput output = (HullShaderOutput)0;\n"
3127 					<< "    output.Position = patch[InvocationID].Position;\n"
3128 					<< "    output.Color = float4" << outColors.at(colorIdx) << ";\n"
3129 					<< "    return output;\n"
3130 					<< "}\n"
3131 					<< "\n"
3132 					<< "HullShaderConstantOutput PCF (InputPatch<VertexShaderOutput, 3> patch, uint InvocationID : SV_PrimitiveID)\n"
3133 					<< "{\n"
3134 					<< "    HullShaderConstantOutput output = (HullShaderConstantOutput)0;\n"
3135 					<< "\n"
3136 					<< "    output.TessLevelOuter[0] = 1;\n"
3137 					<< "    output.TessLevelOuter[1] = 1;\n"
3138 					<< "    output.TessLevelOuter[2] = 1;\n"
3139 					<< "    output.TessLevelOuter[3] = 1;\n"
3140 					<< "\n"
3141 					<< "    output.TessLevelInner[0] = 1;\n"
3142 					<< "    output.TessLevelInner[1] = 1;\n"
3143 					<< "\n"
3144 					<< "    return output;\n"
3145 					<< "}\n"
3146 					;
3147 
3148 				const auto idxStr = std::to_string(colorIdx);
3149 				programCollection.hlslSources.add("tesc" + idxStr) << glu::TessellationControlSource(tesc.str());
3150 
3151 				++colorIdx;
3152 			}
3153 	}
3154 }
3155 
iterate(void)3156 tcu::TestStatus HLSLTessellationInstance::iterate (void)
3157 {
3158 	const auto&			vki				= m_context.getInstanceInterface();
3159 	const auto&			vkd				= m_context.getDeviceInterface();
3160 	const auto			physicalDevice	= m_context.getPhysicalDevice();
3161 	const auto			device			= m_context.getDevice();
3162 	auto&				alloc			= m_context.getDefaultAllocator();
3163 	const auto			queue			= m_context.getUniversalQueue();
3164 	const auto			queueIndex		= m_context.getUniversalQueueFamilyIndex();
3165 
3166 	const auto			fbFormat		= VK_FORMAT_R8G8B8A8_UNORM;
3167 	const auto			fbExtent		= makeExtent3D(2u, 2u, 1u);
3168 	const tcu::IVec3	iExtent			(static_cast<int>(fbExtent.width), static_cast<int>(fbExtent.height), static_cast<int>(fbExtent.depth));
3169 	const auto			tcuFbFormat		= mapVkFormat(fbFormat);
3170 	const auto			pixelSize		= tcu::getPixelSize(tcuFbFormat);
3171 	const auto			topology		= VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
3172 	const auto			patchCPs		= 3u;
3173 	const tcu::Vec4		clearColor		(0.0f, 0.0f, 0.0f, 1.0f);
3174 	const auto			bindPoint		= VK_PIPELINE_BIND_POINT_GRAPHICS;
3175 
3176 	const std::vector<VkViewport>	rpViewports	(1u, makeViewport(fbExtent));
3177 	const std::vector<VkRect2D>		rpScissors	(1u, makeRect2D(fbExtent));
3178 
3179 	// Color attachment.
3180 	const VkImageCreateInfo colorAttCreateInfo =
3181 	{
3182 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										//	VkStructureType			sType;
3183 		nullptr,																	//	const void*				pNext;
3184 		0u,																			//	VkImageCreateFlags		flags;
3185 		VK_IMAGE_TYPE_2D,															//	VkImageType				imageType;
3186 		fbFormat,																	//	VkFormat				format;
3187 		fbExtent,																	//	VkExtent3D				extent;
3188 		1u,																			//	uint32_t				mipLevels;
3189 		1u,																			//	uint32_t				arrayLayers;
3190 		VK_SAMPLE_COUNT_1_BIT,														//	VkSampleCountFlagBits	samples;
3191 		VK_IMAGE_TILING_OPTIMAL,													//	VkImageTiling			tiling;
3192 		(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),	//	VkImageUsageFlags		usage;
3193 		VK_SHARING_MODE_EXCLUSIVE,													//	VkSharingMode			sharingMode;
3194 		0u,																			//	uint32_t				queueFamilyIndexCount;
3195 		nullptr,																	//	const uint32_t*			pQueueFamilyIndices;
3196 		VK_IMAGE_LAYOUT_UNDEFINED,													//	VkImageLayout			initialLayout;
3197 	};
3198 
3199 	ImageWithMemory		colorAtt		(vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any);
3200 	const auto			colorSRR		= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
3201 	const auto			colorSRL		= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
3202 	const auto			colorAttView	= makeImageView(vkd, device, colorAtt.get(), VK_IMAGE_VIEW_TYPE_2D, fbFormat, colorSRR);
3203 	RenderPassWrapper	renderPass		(m_constructionType, vkd, device, fbFormat);
3204 	renderPass.createFramebuffer(vkd, device, colorAtt.get(), colorAttView.get(), fbExtent.width, fbExtent.height);
3205 
3206 	// Verification buffer.
3207 	DE_ASSERT(fbExtent.depth == 1u);
3208 	const auto			verifBufferSize	= static_cast<VkDeviceSize>(pixelSize) * fbExtent.width * fbExtent.height;
3209 	const auto			verifBufferInfo	= makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
3210 	BufferWithMemory	verifBuffer		(vkd, device, alloc, verifBufferInfo, MemoryRequirement::HostVisible);
3211 
3212 	// Create shader modules, obtain IDs and verify all of them differ.
3213 	const auto&	binaries	= m_context.getBinaryCollection();
3214 	const auto	vertModule	= ShaderWrapper(vkd, device, binaries.get("vert"));
3215 	const auto	fragModule	= ShaderWrapper(vkd, device, binaries.get("frag"));
3216 	const auto	teseModule	= ShaderWrapper(vkd, device, binaries.get("tese"));
3217 
3218 	std::vector<ShaderWrapper>	tescModules;
3219 	{
3220 		size_t tescIdx = 0;
3221 
3222 		for (;;)
3223 		{
3224 			const auto shaderName = "tesc" + std::to_string(tescIdx);
3225 			if (!binaries.contains(shaderName))
3226 				break;
3227 			tescModules.emplace_back(ShaderWrapper(vkd, device, binaries.get(shaderName)));
3228 
3229 			++tescIdx;
3230 		}
3231 	}
3232 
3233 	const auto vertId = getShaderModuleIdentifier(vkd, device, vertModule.getModule());
3234 	const auto fragId = getShaderModuleIdentifier(vkd, device, fragModule.getModule());
3235 	const auto teseId = getShaderModuleIdentifier(vkd, device, teseModule.getModule());
3236 	std::vector<ShaderModuleId> tescIds;
3237 	for (const auto& mod : tescModules)
3238 		tescIds.emplace_back(getShaderModuleIdentifier(vkd, device, mod.getModule()));
3239 
3240 	// Verify all of them are unique.
3241 	{
3242 		std::vector<ShaderModuleId> allIds;
3243 		allIds.emplace_back(vertId);
3244 		allIds.emplace_back(fragId);
3245 		allIds.emplace_back(teseId);
3246 		for (const auto& id : tescIds)
3247 			allIds.emplace_back(id);
3248 
3249 		std::set<ShaderModuleId> uniqueIds (begin(allIds), end(allIds));
3250 
3251 		if (allIds.size() != uniqueIds.size())
3252 			TCU_FAIL("Not every module has a unique ID");
3253 	}
3254 
3255 	// Constant structures used when creating pipelines.
3256 	const VkPipelineVertexInputStateCreateInfo		vertexInputState			= initVulkanStructure();
3257 	const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyState			=
3258 	{
3259 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
3260 		nullptr,														//	const void*								pNext;
3261 		0u,																//	VkPipelineInputAssemblyStateCreateFlags	flags;
3262 		topology,														//	VkPrimitiveTopology						topology;
3263 		VK_FALSE,														//	VkBool32								primitiveRestartEnable;
3264 	};
3265 	const VkPipelineDepthStencilStateCreateInfo		depthStencilState			= initVulkanStructure();
3266 	VkPipelineMultisampleStateCreateInfo			multisampleState			= initVulkanStructure();
3267 	multisampleState.rasterizationSamples										= VK_SAMPLE_COUNT_1_BIT;
3268 	VkPipelineColorBlendAttachmentState				colorBlendAttachmentState;
3269 	deMemset(&colorBlendAttachmentState, 0, sizeof(colorBlendAttachmentState));
3270 	colorBlendAttachmentState.colorWriteMask									= (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
3271 	const VkPipelineColorBlendStateCreateInfo		colorBlendState				=
3272 	{
3273 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType
3274 		nullptr,													//	const void*									pNext
3275 		0u,															//	VkPipelineColorBlendStateCreateFlags		flags
3276 		VK_FALSE,													//	VkBool32									logicOpEnable
3277 		VK_LOGIC_OP_CLEAR,											//	VkLogicOp									logicOp
3278 		1u,															//	deUint32									attachmentCount
3279 		&colorBlendAttachmentState,									//	const VkPipelineColorBlendAttachmentState*	pAttachments
3280 		{ 0.0f, 0.0f, 0.0f, 0.0f }									//	float										blendConstants[4]
3281 	};
3282 	const auto										rasterizationState			= makeRasterizationState(false/*rasterizationDisabled*/);
3283 
3284 	// Pipeline cache.
3285 	const VkPipelineCacheCreateInfo cacheCreateInfo = initVulkanStructure();
3286 	const auto pipelineCache = createPipelineCache(vkd, device, &cacheCreateInfo);
3287 
3288 	// Empty pipeline layout.
3289 	const PipelineLayoutWrapper pipelineLayout (m_constructionType, vkd, device);
3290 
3291 	using GraphicsPipelineWrapperPtr = std::unique_ptr<GraphicsPipelineWrapper>;
3292 
3293 	// Create temporary pipelines with them to prime the cache.
3294 	{
3295 		for (const auto& tescModule : tescModules)
3296 		{
3297 			GraphicsPipelineWrapperPtr wrapper (new GraphicsPipelineWrapper(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_constructionType));
3298 
3299 			try
3300 			{
3301 				wrapper->setDefaultPatchControlPoints(patchCPs)
3302 						.setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
3303 						.setupPreRasterizationShaderState2(
3304 							rpViewports,
3305 							rpScissors,
3306 							pipelineLayout,
3307 							renderPass.get(),
3308 							0u,
3309 							vertModule,
3310 							&rasterizationState,
3311 							tescModule,
3312 							teseModule,
3313 							ShaderWrapper(),
3314 							nullptr,
3315 							nullptr,
3316 							nullptr,
3317 							nullptr,
3318 							nullptr,
3319 							PipelineRenderingCreateInfoWrapper(),
3320 							pipelineCache.get())
3321 						.setupFragmentShaderState(
3322 							pipelineLayout,
3323 							renderPass.get(),
3324 							0u,
3325 							fragModule,
3326 							&depthStencilState,
3327 							&multisampleState,
3328 							nullptr,
3329 							pipelineCache.get())
3330 						.setupFragmentOutputState(
3331 							*renderPass,
3332 							0u,
3333 							&colorBlendState,
3334 							&multisampleState,
3335 							pipelineCache.get())
3336 						.setMonolithicPipelineLayout(pipelineLayout)
3337 						.buildPipeline(pipelineCache.get());
3338 			}
3339 			catch (const PipelineCompileRequiredError& err)
3340 			{
3341 				TCU_FAIL("PipelineCompileRequiredError received while priming pipeline cache");
3342 			}
3343 		}
3344 	}
3345 
3346 	// Create pipelines using shader module ids. These will actually be run. Note the changing viewports and scissors.
3347 	std::vector<GraphicsPipelineWrapperPtr>	pipelineWrappers;
3348 	std::vector<VkViewport>					viewports;
3349 	std::vector<VkRect2D>					scissors;
3350 
3351 	const auto vertIdInfo = makeShaderStageModuleIdentifierCreateInfo(vertId, UseModuleCase::ID);
3352 	const auto fragIdInfo = makeShaderStageModuleIdentifierCreateInfo(fragId, UseModuleCase::ID);
3353 	const auto teseIdInfo = makeShaderStageModuleIdentifierCreateInfo(teseId, UseModuleCase::ID);
3354 	std::vector<ShaderStageIdPtr> tescIdInfos;
3355 	for (const auto& tescId : tescIds)
3356 		tescIdInfos.emplace_back(makeShaderStageModuleIdentifierCreateInfo(tescId, UseModuleCase::ID));
3357 
3358 	for (size_t tescIdx = 0; tescIdx < tescModules.size(); ++tescIdx)
3359 	{
3360 		const auto	row	= tescIdx / fbExtent.width;
3361 		const auto	col	= tescIdx % fbExtent.width;
3362 
3363 		viewports.emplace_back(makeViewport(static_cast<float>(col), static_cast<float>(row), 1.0f, 1.0f, 0.0f, 1.0f));
3364 		scissors.emplace_back(makeRect2D(static_cast<int32_t>(col), static_cast<int32_t>(row), 1u, 1u));
3365 		pipelineWrappers.emplace_back(new GraphicsPipelineWrapper(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_constructionType));
3366 
3367 		const auto& wrapper = pipelineWrappers.back();
3368 
3369 		try
3370 		{
3371 			wrapper->setDefaultPatchControlPoints(patchCPs)
3372 					.setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
3373 					.setupPreRasterizationShaderState3(
3374 						std::vector<VkViewport>(1u, viewports.back()),
3375 						std::vector<VkRect2D>(1u, scissors.back()),
3376 						pipelineLayout,
3377 						renderPass.get(),
3378 						0u,
3379 						ShaderWrapper(),
3380 						PipelineShaderStageModuleIdentifierCreateInfoWrapper(vertIdInfo.get()),
3381 						&rasterizationState,
3382 						ShaderWrapper(),
3383 						PipelineShaderStageModuleIdentifierCreateInfoWrapper(tescIdInfos.at(tescIdx).get()),
3384 						ShaderWrapper(),
3385 						PipelineShaderStageModuleIdentifierCreateInfoWrapper(teseIdInfo.get()),
3386 						ShaderWrapper(),
3387 						PipelineShaderStageModuleIdentifierCreateInfoWrapper(),
3388 						nullptr,
3389 						nullptr,
3390 						nullptr,
3391 						nullptr,
3392 						nullptr,
3393 						PipelineRenderingCreateInfoWrapper(),
3394 						pipelineCache.get())
3395 					.setupFragmentShaderState2(
3396 						pipelineLayout,
3397 						renderPass.get(),
3398 						0u,
3399 						ShaderWrapper(),
3400 						PipelineShaderStageModuleIdentifierCreateInfoWrapper(fragIdInfo.get()),
3401 						&depthStencilState,
3402 						&multisampleState,
3403 						nullptr,
3404 						pipelineCache.get())
3405 					.setupFragmentOutputState(
3406 						*renderPass,
3407 						0u,
3408 						&colorBlendState,
3409 						&multisampleState,
3410 						pipelineCache.get())
3411 					.setMonolithicPipelineLayout(pipelineLayout)
3412 					.buildPipeline(pipelineCache.get());
3413 		}
3414 		catch (const PipelineCompileRequiredError& err)
3415 		{
3416 			return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "PipelineCompileRequiredError received despite using pipeline cache");
3417 		}
3418 	}
3419 
3420 	// Use pipelines in a render pass.
3421 	const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
3422 	const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
3423 	const auto cmdBuffer = cmdBufferPtr.get();
3424 
3425 	beginCommandBuffer(vkd, cmdBuffer);
3426 	renderPass.begin(vkd, cmdBuffer, rpScissors.at(0u), clearColor);
3427 	for (const auto& wrapper : pipelineWrappers)
3428 	{
3429 		vkd.cmdBindPipeline(cmdBuffer, bindPoint, wrapper->getPipeline());
3430 		vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
3431 	}
3432 	renderPass.end(vkd, cmdBuffer);
3433 
3434 	// Transfer color attachment to verification buffer.
3435 	const auto copyRegion			= makeBufferImageCopy(fbExtent, colorSRL);
3436 	const auto preHostBarrier		= makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
3437 	const auto postRenderBarrier	= makeImageMemoryBarrier(
3438 		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
3439 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
3440 		colorAtt.get(), colorSRR);
3441 
3442 	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &postRenderBarrier);
3443 	vkd.cmdCopyImageToBuffer(cmdBuffer, colorAtt.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u, &copyRegion);
3444 	cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
3445 
3446 	endCommandBuffer(vkd, cmdBuffer);
3447 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
3448 
3449 	// Verify result.
3450 	{
3451 		auto&		log					= m_context.getTestContext().getLog();
3452 		const auto	outColors			= HLSLTessellationCase::getOutputColors();
3453 		auto&		verifBufferAlloc	= verifBuffer.getAllocation();
3454 		void*		verifBufferData		= verifBufferAlloc.getHostPtr();
3455 
3456 		invalidateAlloc(vkd, device, verifBufferAlloc);
3457 
3458 		tcu::ConstPixelBufferAccess	resultAccess	(tcuFbFormat, iExtent, verifBufferData);
3459 		tcu::TextureLevel			referenceLevel	(tcuFbFormat, iExtent.x(), iExtent.y());
3460 		const auto					referenceAccess	= referenceLevel.getAccess();
3461 		const tcu::Vec4				threshold		(0.0f, 0.0f, 0.0f, 0.0f);
3462 
3463 		for (int x = 0; x < iExtent.x(); ++x)
3464 			for (int y = 0; y < iExtent.y(); ++y)
3465 				referenceAccess.setPixel(outColors.at(y*iExtent.x() + x), x, y);
3466 
3467 		tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold, tcu::COMPARE_LOG_EVERYTHING);
3468 	}
3469 
3470 	return tcu::TestStatus::pass("Pass");
3471 }
3472 
3473 } // anonymous namespace
3474 
createShaderModuleIdentifierTests(tcu::TestContext & testCtx,vk::PipelineConstructionType constructionType)3475 tcu::TestCaseGroup* createShaderModuleIdentifierTests (tcu::TestContext& testCtx, vk::PipelineConstructionType constructionType)
3476 {
3477 	// No pipelines are actually constructed in some of these variants, so adding them to a single group is fine.
3478 	GroupPtr mainGroup (new tcu::TestCaseGroup(testCtx, "shader_module_identifier"));
3479 
3480 	if (constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3481 	{
3482 		// Test shader module identifier extension properties
3483 		GroupPtr propertiesGroup (new tcu::TestCaseGroup(testCtx, "properties"));
3484 
3485 		addFunctionCase(propertiesGroup.get(), "constant_algorithm_uuid", checkShaderModuleIdentifierSupport, constantAlgorithmUUIDCase);
3486 
3487 		mainGroup->addChild(propertiesGroup.release());
3488 	}
3489 
3490 	const struct
3491 	{
3492 		PipelineType		pipelineType;
3493 		bool				useRTLibraries;
3494 		const char*			name;
3495 	} pipelineTypeCases[] =
3496 	{
3497 		{ PipelineType::COMPUTE,		false,	"compute"			},
3498 		{ PipelineType::GRAPHICS,		false,	"graphics"			},
3499 		{ PipelineType::RAY_TRACING,	false,	"ray_tracing"		},
3500 		{ PipelineType::RAY_TRACING,	true,	"ray_tracing_libs"	},
3501 	};
3502 
3503 	const uint8_t pipelineCountCases[] = { uint8_t{1}, uint8_t{4} };
3504 
3505 	const std::vector<GraphicsShaderVec> graphicsShadersCases
3506 	{
3507 		{ GraphicsShaderType::VERTEX },
3508 		{ GraphicsShaderType::VERTEX, GraphicsShaderType::FRAG },
3509 		{ GraphicsShaderType::VERTEX, GraphicsShaderType::TESS_CONTROL, GraphicsShaderType::TESS_EVAL, GraphicsShaderType::FRAG },
3510 		{ GraphicsShaderType::VERTEX, GraphicsShaderType::GEOMETRY, GraphicsShaderType::FRAG },
3511 		{ GraphicsShaderType::VERTEX, GraphicsShaderType::TESS_CONTROL, GraphicsShaderType::TESS_EVAL, GraphicsShaderType::GEOMETRY, GraphicsShaderType::FRAG },
3512 	};
3513 
3514 	const std::vector<RTShaderVec> rtShadersCases
3515 	{
3516 		{ RayTracingShaderType::RAY_GEN, RayTracingShaderType::MISS },
3517 		{ RayTracingShaderType::RAY_GEN, RayTracingShaderType::CLOSEST_HIT, RayTracingShaderType::MISS },
3518 		{ RayTracingShaderType::RAY_GEN, RayTracingShaderType::ANY_HIT, RayTracingShaderType::CLOSEST_HIT, RayTracingShaderType::MISS },
3519 		{ RayTracingShaderType::RAY_GEN, RayTracingShaderType::INTERSECTION, RayTracingShaderType::ANY_HIT, RayTracingShaderType::CLOSEST_HIT, RayTracingShaderType::MISS },
3520 		{ RayTracingShaderType::RAY_GEN, RayTracingShaderType::CALLABLE },
3521 	};
3522 
3523 	const struct
3524 	{
3525 		bool		useSCs;
3526 		const char*	name;
3527 	} useSCCases[] =
3528 	{
3529 		{ false,	"no_spec_constants"		},
3530 		{ true,		"use_spec_constants"	},
3531 	};
3532 
3533 	// Tests checking the identifiers are constant.
3534 	if (constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3535 	{
3536 		// Test shader modules have constant and unique identifiers
3537 		GroupPtr constantIdsGroup (new tcu::TestCaseGroup(testCtx, "constant_identifiers"));
3538 
3539 		const struct
3540 		{
3541 			ConstantModuleIdentifiersInstance::APICall	apiCall;
3542 			const char*									name;
3543 		} apiCallCases[] =
3544 		{
3545 			{ ConstantModuleIdentifiersInstance::APICall::MODULE,		"module_id"			},
3546 			{ ConstantModuleIdentifiersInstance::APICall::CREATE_INFO,	"create_info_id"	},
3547 			{ ConstantModuleIdentifiersInstance::APICall::BOTH,			"both_ids"			},
3548 		};
3549 
3550 		const struct
3551 		{
3552 			bool			differentDevice;
3553 			const char*		name;
3554 		} differentDeviceCases[] =
3555 		{
3556 			{ false,	"same_device"		},
3557 			{ true,		"different_devices"	},
3558 		};
3559 
3560 		for (const auto& pipelineTypeCase : pipelineTypeCases)
3561 		{
3562 			// Skip this case for constant module identifiers.
3563 			if (pipelineTypeCase.useRTLibraries)
3564 				continue;
3565 
3566 			GroupPtr pipelineTypeGroup (new tcu::TestCaseGroup(testCtx, pipelineTypeCase.name));
3567 
3568 			for (const auto& pipelineCountCase : pipelineCountCases)
3569 			{
3570 				const auto countGroupName = std::to_string(static_cast<int>(pipelineCountCase)) + "_variants";
3571 
3572 				GroupPtr pipelineCountGroup (new tcu::TestCaseGroup(testCtx, countGroupName.c_str()));
3573 
3574 				for (const auto& useSCCase : useSCCases)
3575 				{
3576 					GroupPtr useSCGroup (new tcu::TestCaseGroup(testCtx, useSCCase.name));
3577 
3578 					for (const auto& apiCallCase : apiCallCases)
3579 					{
3580 						GroupPtr apiCallGroup (new tcu::TestCaseGroup(testCtx, apiCallCase.name));
3581 
3582 						for (const auto& differentDeviceCase : differentDeviceCases)
3583 						{
3584 							GroupPtr differentDeviceGroup (new tcu::TestCaseGroup(testCtx, differentDeviceCase.name));
3585 
3586 							using Params = ConstantModuleIdentifiersInstance::Params;
3587 
3588 							Params commonParams(
3589 								pipelineTypeCase.pipelineType,
3590 								{}, {}, pipelineCountCase, tcu::Nothing,
3591 								useSCCase.useSCs, false, apiCallCase.apiCall, differentDeviceCase.differentDevice);
3592 
3593 							if (pipelineTypeCase.pipelineType == PipelineType::GRAPHICS)
3594 							{
3595 								for (const auto& graphicsShadersCase : graphicsShadersCases)
3596 								{
3597 									std::unique_ptr<Params> params (new Params(commonParams));
3598 									params->graphicsShaders = graphicsShadersCase;
3599 									differentDeviceGroup->addChild(new ConstantModuleIdentifiersCase(testCtx, toString(graphicsShadersCase), std::move(params)));
3600 								}
3601 							}
3602 							else if (pipelineTypeCase.pipelineType == PipelineType::RAY_TRACING)
3603 							{
3604 								for (const auto& rtShadersCase : rtShadersCases)
3605 								{
3606 									std::unique_ptr<Params> params (new Params(commonParams));
3607 									params->rtShaders = rtShadersCase;
3608 									differentDeviceGroup->addChild(new ConstantModuleIdentifiersCase(testCtx, toString(rtShadersCase), std::move(params)));
3609 								}
3610 							}
3611 							else	// Compute
3612 							{
3613 								std::unique_ptr<Params> params (new Params(commonParams));
3614 								differentDeviceGroup->addChild(new ConstantModuleIdentifiersCase(testCtx, "comp", std::move(params)));
3615 							}
3616 
3617 							apiCallGroup->addChild(differentDeviceGroup.release());
3618 						}
3619 
3620 						useSCGroup->addChild(apiCallGroup.release());
3621 					}
3622 
3623 					pipelineCountGroup->addChild(useSCGroup.release());
3624 				}
3625 
3626 				pipelineTypeGroup->addChild(pipelineCountGroup.release());
3627 			}
3628 
3629 			constantIdsGroup->addChild(pipelineTypeGroup.release());
3630 		}
3631 
3632 		mainGroup->addChild(constantIdsGroup.release());
3633 	}
3634 
3635 	// Tests creating pipelines using the module id extension structures.
3636 	{
3637 		const struct
3638 		{
3639 			bool		useVkPipelineCache;
3640 			const char*	name;
3641 		} pipelineCacheCases[] =
3642 		{
3643 			{ false,	"no_pipeline_cache"		},
3644 			{ true,		"use_pipeline_cache"	},
3645 		};
3646 
3647 		const struct
3648 		{
3649 			UseModuleCase		moduleUse;
3650 			const char*			name;
3651 		} moduleUsageCases[] =
3652 		{
3653 			{ UseModuleCase::ID,						"use_id"					},
3654 			{ UseModuleCase::ZERO_LEN_ID,				"zero_len_id"				},
3655 			{ UseModuleCase::ZERO_LEN_ID_NULL_PTR,		"zero_len_id_null_ptr"		},
3656 			{ UseModuleCase::ZERO_LEN_ID_GARBAGE_PTR,	"zero_len_id_garbage_ptr"	},
3657 			{ UseModuleCase::ALL_ZEROS,					"all_zeros_id"				},
3658 			{ UseModuleCase::ALL_ONES,					"all_ones_id"				},
3659 			{ UseModuleCase::PSEUDORANDOM_ID,			"pseudorandom_id"			},
3660 		};
3661 
3662 		const struct
3663 		{
3664 			CapturedPropertiesBits		capturedProperties;
3665 			const char*					name;
3666 		} capturingCases[] =
3667 		{
3668 			{ CapturedPropertiesBits::NONE,				"no_exec_properties"		},
3669 			{ CapturedPropertiesBits::STATS,			"capture_stats"				},
3670 			{ CapturedPropertiesBits::IRS,				"capture_irs"				},
3671 		};
3672 
3673 		uint32_t rndSeed = 1651848014u;
3674 
3675 		// Test creating and using pipelines from shader module identifiers
3676 		GroupPtr pipelineFromIdsGroup (new tcu::TestCaseGroup(testCtx, "pipeline_from_id"));
3677 
3678 		for (const auto& pipelineTypeCase : pipelineTypeCases)
3679 		{
3680 			if (pipelineTypeCase.pipelineType != PipelineType::GRAPHICS && constructionType != PipelineConstructionType::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3681 				continue;
3682 
3683 			GroupPtr pipelineTypeGroup (new tcu::TestCaseGroup(testCtx, pipelineTypeCase.name));
3684 
3685 			for (const auto& pipelineCountCase : pipelineCountCases)
3686 			{
3687 				const auto countGroupName = std::to_string(static_cast<int>(pipelineCountCase)) + "_variants";
3688 
3689 				GroupPtr pipelineCountGroup (new tcu::TestCaseGroup(testCtx, countGroupName.c_str()));
3690 
3691 				for (const auto& useSCCase : useSCCases)
3692 				{
3693 					GroupPtr useSCGroup (new tcu::TestCaseGroup(testCtx, useSCCase.name));
3694 
3695 					for (const auto& pipelineCacheCase : pipelineCacheCases)
3696 					{
3697 						GroupPtr pipelineCacheGroup (new tcu::TestCaseGroup(testCtx, pipelineCacheCase.name));
3698 
3699 						for (const auto& moduleUsageCase : moduleUsageCases)
3700 						{
3701 							GroupPtr moduleUsageGroup (new tcu::TestCaseGroup(testCtx, moduleUsageCase.name));
3702 
3703 							for (const auto& capturingCase : capturingCases)
3704 							{
3705 								// We are only going to attempt to capture properties in a specific subset of the tests.
3706 								if (capturingCase.capturedProperties != CapturedPropertiesBits::NONE &&
3707 									(pipelineCountCase > 1u || moduleUsageCase.moduleUse != UseModuleCase::ID))
3708 									continue;
3709 
3710 								GroupPtr captureGroup (new tcu::TestCaseGroup(testCtx, capturingCase.name));
3711 
3712 								DE_ASSERT(pipelineCountCase > 0u);
3713 								const uint8_t pipelineToRun = (pipelineCountCase == 1u ? uint8_t{0} : static_cast<uint8_t>(pipelineCountCase - 2u));
3714 
3715 								CreateAndUseIdsInstance::Params baseParams(
3716 									pipelineTypeCase.pipelineType,
3717 									{}, {}, pipelineCountCase, tcu::just(pipelineToRun),
3718 									useSCCase.useSCs, pipelineCacheCase.useVkPipelineCache, false,
3719 									constructionType, pipelineTypeCase.useRTLibraries,
3720 									moduleUsageCase.moduleUse,
3721 									static_cast<CapturedPropertiesFlags>(capturingCase.capturedProperties));
3722 
3723 								if (pipelineTypeCase.pipelineType == PipelineType::GRAPHICS)
3724 								{
3725 									for (const auto& graphicsShadersCase : graphicsShadersCases)
3726 									{
3727 										BaseParamsPtr params = baseParams.copy(rndSeed++);
3728 										params->graphicsShaders = graphicsShadersCase;
3729 										captureGroup->addChild(new CreateAndUseIdsCase(testCtx, toString(graphicsShadersCase), std::move(params)));
3730 									}
3731 								}
3732 								else if (pipelineTypeCase.pipelineType == PipelineType::RAY_TRACING)
3733 								{
3734 									for (const auto& rtShadersCase : rtShadersCases)
3735 									{
3736 										BaseParamsPtr params = baseParams.copy(rndSeed++);
3737 										params->rtShaders = rtShadersCase;
3738 										captureGroup->addChild(new CreateAndUseIdsCase(testCtx, toString(rtShadersCase), std::move(params)));
3739 									}
3740 								}
3741 								else	// Compute
3742 								{
3743 									BaseParamsPtr params = baseParams.copy(rndSeed++);
3744 									captureGroup->addChild(new CreateAndUseIdsCase(testCtx, "comp", std::move(params)));
3745 								}
3746 
3747 								moduleUsageGroup->addChild(captureGroup.release());
3748 							}
3749 
3750 							pipelineCacheGroup->addChild(moduleUsageGroup.release());
3751 						}
3752 
3753 						useSCGroup->addChild(pipelineCacheGroup.release());
3754 					}
3755 
3756 					pipelineCountGroup->addChild(useSCGroup.release());
3757 				}
3758 
3759 				pipelineTypeGroup->addChild(pipelineCountGroup.release());
3760 			}
3761 
3762 			pipelineFromIdsGroup->addChild(pipelineTypeGroup.release());
3763 		}
3764 
3765 		mainGroup->addChild(pipelineFromIdsGroup.release());
3766 	}
3767 
3768 	// Tests checking HLSL tessellation shaders with module identifiers
3769 	{
3770 		GroupPtr hlslTessGroup (new tcu::TestCaseGroup(testCtx, "hlsl_tessellation"));
3771 		hlslTessGroup->addChild(new HLSLTessellationCase(testCtx, "test", constructionType));
3772 		mainGroup->addChild(hlslTessGroup.release());
3773 	}
3774 
3775 	// misc tests
3776 	if (constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3777 	{
3778 		const uint8_t pipelineToRun = 0u;
3779 		CreateAndUseIdsInstance::Params baseParams(
3780 			PipelineType::GRAPHICS,
3781 			{}, {}, uint8_t{1u}, tcu::just(uint8_t{pipelineToRun}),
3782 			false, false, true,
3783 			constructionType, false,
3784 			UseModuleCase::ID,
3785 			static_cast<CapturedPropertiesFlags>(CapturedPropertiesBits::STATS));
3786 		baseParams.graphicsShaders = graphicsShadersCases[1];
3787 
3788 		GroupPtr miscGroup(new tcu::TestCaseGroup(testCtx, "misc", ""));
3789 
3790 		BaseParamsPtr params = baseParams.copy(1);
3791 		miscGroup->addChild(new CreateAndUseIdsCase(testCtx, "capture_statistics_maintenance5", std::move(params)));
3792 
3793 		baseParams.capturedProperties = static_cast<CapturedPropertiesFlags>(CapturedPropertiesBits::IRS);
3794 		params = baseParams.copy(2);
3795 		miscGroup->addChild(new CreateAndUseIdsCase(testCtx, "capture_internal_representations_maintenance5", std::move(params)));
3796 
3797 		mainGroup->addChild(miscGroup.release());
3798 	}
3799 
3800 	return mainGroup.release();
3801 }
3802 
3803 } // pipeline
3804 } // vkt
3805