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