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