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