• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  * Copyright (c) 2022 Valve Corporation.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief VK_EXT_shader_module_identifier tests
25  *//*--------------------------------------------------------------------*/
26 #include "vktPipelineShaderModuleIdentifierTests.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 
31 #include "vkQueryUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkObjUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkRayTracingUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkPipelineConstructionUtil.hpp"
42 #include "vkBarrierUtil.hpp"
43 
44 #include "tcuMaybe.hpp"
45 #include "tcuCommandLine.hpp"
46 #include "tcuFormatUtil.hpp"
47 #include "tcuImageCompare.hpp"
48 #include "tcuTestLog.hpp"
49 
50 #include "deUniquePtr.hpp"
51 #include "deRandom.hpp"
52 
53 #include <vector>
54 #include <utility>
55 #include <string>
56 #include <sstream>
57 #include <algorithm>
58 #include <iterator>
59 #include <memory>
60 #include <set>
61 #include <limits>
62 
63 namespace vkt
64 {
65 namespace pipeline
66 {
67 
68 namespace
69 {
70 
71 using GroupPtr  = de::MovePtr<tcu::TestCaseGroup>;
72 using StringVec = std::vector<std::string>;
73 using namespace vk;
74 
75 using ShaderModuleId    = std::vector<uint8_t>;
76 using ShaderModuleIdPtr = std::unique_ptr<ShaderModuleId>;
77 using ShaderStageIdPtr  = std::unique_ptr<VkPipelineShaderStageModuleIdentifierCreateInfoEXT>;
78 
79 // Helper function to create a shader module identifier from a VkShaderModuleIdentifierEXT structure.
makeShaderModuleId(const VkShaderModuleIdentifierEXT & idExt)80 ShaderModuleId makeShaderModuleId(const VkShaderModuleIdentifierEXT &idExt)
81 {
82     if (idExt.identifierSize == 0u || idExt.identifierSize > VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT)
83         TCU_FAIL("Invalid identifierSize returned");
84 
85     ShaderModuleId identifier(idExt.identifier, idExt.identifier + idExt.identifierSize);
86     return identifier;
87 }
88 
89 // Helper function to obtain the shader module identifier for a VkShaderModule as a return value.
getShaderModuleIdentifier(const DeviceInterface & vkd,const VkDevice device,const VkShaderModule module)90 ShaderModuleId getShaderModuleIdentifier(const DeviceInterface &vkd, const VkDevice device, const VkShaderModule module)
91 {
92     VkShaderModuleIdentifierEXT idExt = initVulkanStructure();
93     vkd.getShaderModuleIdentifierEXT(device, module, &idExt);
94     return makeShaderModuleId(idExt);
95 }
96 
97 // Helper function to obtain the shader module identifier from a VkShaderModuleCreateInfo structure as a return value.
getShaderModuleIdentifier(const DeviceInterface & vkd,const VkDevice device,const VkShaderModuleCreateInfo & createInfo)98 ShaderModuleId getShaderModuleIdentifier(const DeviceInterface &vkd, const VkDevice device,
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::__anoncd3947560111::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::__anoncd3947560111::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::__anoncd3947560111::PipelineExecutableInternalRepresentation357     bool isText(void) const
358     {
359         return m_isText;
360     }
getTextvkt::pipeline::__anoncd3947560111::PipelineExecutableInternalRepresentation361     const std::string &getText(void) const
362     {
363         DE_ASSERT(isText());
364         return m_text;
365     }
getBytesvkt::pipeline::__anoncd3947560111::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::__anoncd3947560111::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::__anoncd3947560111::PipelineExecutableProperty396     void addStat(const PipelineExecutableStat &stat)
397     {
398         m_stats.emplace_back(stat);
399     }
addIRvkt::pipeline::__anoncd3947560111::PipelineExecutableProperty400     void addIR(const PipelineExecutableInternalRepresentation &ir)
401     {
402         m_irs.emplace_back(ir);
403     }
404 
getStatsvkt::pipeline::__anoncd3947560111::PipelineExecutableProperty405     const std::vector<PipelineExecutableStat> &getStats(void) const
406     {
407         return m_stats;
408     }
getIRsvkt::pipeline::__anoncd3947560111::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::__anoncd3947560111::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::__anoncd3947560111::BaseParams622     virtual ~BaseParams()
623     {
624     }
625 
stageCountPerPipelinevkt::pipeline::__anoncd3947560111::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::__anoncd3947560111::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::__anoncd3947560111::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::__anoncd3947560111::BaseParams665     bool hasGeom(void) const
666     {
667         return hasGraphicsStage(GraphicsShaderType::GEOMETRY);
668     }
669 
hasTessvkt::pipeline::__anoncd3947560111::BaseParams670     bool hasTess(void) const
671     {
672         return (hasGraphicsStage(GraphicsShaderType::TESS_CONTROL) || hasGraphicsStage(GraphicsShaderType::TESS_EVAL));
673     }
674 
hasVertexPipelineStagevkt::pipeline::__anoncd3947560111::BaseParams675     bool hasVertexPipelineStage(void) const
676     {
677         return (hasGraphicsStage(GraphicsShaderType::VERTEX) || hasTess() || hasGeom());
678     }
679 
hasFragvkt::pipeline::__anoncd3947560111::BaseParams680     bool hasFrag(void) const
681     {
682         return hasGraphicsStage(GraphicsShaderType::FRAG);
683     }
684 
hasRayTracingvkt::pipeline::__anoncd3947560111::BaseParams685     bool hasRayTracing(void) const
686     {
687         return (pipelineType == PipelineType::RAY_TRACING);
688     }
689 
hasHitvkt::pipeline::__anoncd3947560111::BaseParams690     bool hasHit(void) const
691     {
692         return (hasRTStage(RayTracingShaderType::ANY_HIT) || hasRTStage(RayTracingShaderType::CLOSEST_HIT) ||
693                 hasRTStage(RayTracingShaderType::INTERSECTION));
694     }
695 
hasISecvkt::pipeline::__anoncd3947560111::BaseParams696     bool hasISec(void) const
697     {
698         return hasRTStage(RayTracingShaderType::INTERSECTION);
699     }
700 
hasMissvkt::pipeline::__anoncd3947560111::BaseParams701     bool hasMiss(void) const
702     {
703         return hasRTStage(RayTracingShaderType::MISS);
704     }
705 
getPipelineStageFlagsvkt::pipeline::__anoncd3947560111::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::__anoncd3947560111::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::__anoncd3947560111::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::__anoncd3947560111::ConstantModuleIdentifiersInstance::Params1438         virtual ~Params()
1439         {
1440         }
1441 
needsVkModulevkt::pipeline::__anoncd3947560111::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::__anoncd3947560111::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 
1545         VkPhysicalDeviceFeatures2 deviceFeatures =
1546             initVulkanStructure(enableRayTracing ? reinterpret_cast<void *>(&deviceAddressFeatures) :
1547                                                    reinterpret_cast<void *>(&cacheControlFeatures));
1548 
1549         vki.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures);
1550 
1551         // Make sure robust buffer access is disabled as in the default device.
1552         deviceFeatures.features.robustBufferAccess = VK_FALSE;
1553 
1554         const auto queuePriority = 1.0f;
1555         const VkDeviceQueueCreateInfo queueInfo{
1556             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
1557             nullptr,                                    // const void* pNext;
1558             0u,                                         // VkDeviceQueueCreateFlags flags;
1559             queueFamilyIndex,                           // uint32_t queueFamilyIndex;
1560             1u,                                         // uint32_t queueCount;
1561             &queuePriority,                             // const float* pQueuePriorities;
1562         };
1563 
1564         // Required extensions. Note: many of these require VK_KHR_get_physical_device_properties2, which is an instance extension.
1565         std::vector<const char *> requiredExtensions{
1566             "VK_EXT_pipeline_creation_cache_control",
1567             "VK_EXT_shader_module_identifier",
1568         };
1569 
1570         if (enableRayTracing)
1571         {
1572             requiredExtensions.push_back("VK_KHR_maintenance3");
1573             requiredExtensions.push_back("VK_EXT_descriptor_indexing");
1574             requiredExtensions.push_back("VK_KHR_buffer_device_address");
1575             requiredExtensions.push_back("VK_KHR_deferred_host_operations");
1576             requiredExtensions.push_back("VK_KHR_acceleration_structure");
1577             requiredExtensions.push_back("VK_KHR_shader_float_controls");
1578             requiredExtensions.push_back("VK_KHR_spirv_1_4");
1579             requiredExtensions.push_back("VK_KHR_ray_tracing_pipeline");
1580         }
1581 
1582         const VkDeviceCreateInfo createInfo{
1583             VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
1584             deviceFeatures.pNext,                 // const void* pNext;
1585             0u,                                   // VkDeviceCreateFlags flags;
1586             1u,                                   // uint32_t queueCreateInfoCount;
1587             &queueInfo,                           // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
1588             0u,                                   // uint32_t enabledLayerCount;
1589             nullptr,                              // const char* const* ppEnabledLayerNames;
1590             de::sizeU32(requiredExtensions),      // uint32_t enabledExtensionCount;
1591             de::dataOrNull(requiredExtensions),   // const char* const* ppEnabledExtensionNames;
1592             &deviceFeatures.features,             // const VkPhysicalDeviceFeatures* pEnabledFeatures;
1593         };
1594 
1595         // Create custom device and related objects
1596         device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki,
1597                                     physicalDevice, &createInfo);
1598         vkd.reset(new DeviceDriver(vkp, instance, device.get(), context.getUsedApiVersion(),
1599                                    context.getTestContext().getCommandLine()));
1600         queue = getDeviceQueue(*vkd, *device, queueFamilyIndex, 0u);
1601         allocator.reset(
1602             new SimpleAllocator(*vkd, device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
1603     }
1604 };
1605 
iterate(void)1606 tcu::TestStatus ConstantModuleIdentifiersInstance::iterate(void)
1607 {
1608     // The second device may be the one from the context or a new device for the cases that require different devices.
1609     const auto &vkd   = m_context.getDeviceInterface();
1610     const auto device = m_context.getDevice();
1611     const std::unique_ptr<DeviceHelper> helper(m_params->differentDevices ? new DeviceHelper(m_context) : nullptr);
1612 
1613     const auto &di1 = vkd;
1614     const auto dev1 = device;
1615     const auto &di2 = (m_params->differentDevices ? *helper->vkd : vkd);
1616     const auto dev2 = (m_params->differentDevices ? helper->device.get() : device);
1617 
1618     return runTest(di1, dev1, di2, dev2);
1619 }
1620 
1621 class ConstantModuleIdentifiersCase : public SourcesAndSupportFromParamsBase
1622 {
1623 public:
1624     using Params    = ConstantModuleIdentifiersInstance::Params;
1625     using ParamsPtr = ConstantModuleIdentifiersInstance::ParamsPtr;
1626 
ConstantModuleIdentifiersCase(tcu::TestContext & testCtx,const std::string & name,ParamsPtr && params)1627     ConstantModuleIdentifiersCase(tcu::TestContext &testCtx, const std::string &name, ParamsPtr &&params)
1628         : SourcesAndSupportFromParamsBase(testCtx, name, BaseParamsPtr(static_cast<BaseParams *>(params.release())))
1629     {
1630     }
~ConstantModuleIdentifiersCase(void)1631     virtual ~ConstantModuleIdentifiersCase(void)
1632     {
1633     }
1634     TestInstance *createInstance(Context &context) const override;
1635 };
1636 
createInstance(Context & context) const1637 TestInstance *ConstantModuleIdentifiersCase::createInstance(Context &context) const
1638 {
1639     const auto paramsPtr = dynamic_cast<Params *>(m_params.get());
1640     DE_ASSERT(paramsPtr);
1641 
1642     return new ConstantModuleIdentifiersInstance(context, paramsPtr);
1643 }
1644 
1645 // Tests that create one or more pipelines using several shaders, obtain the shader ids from one of the pipelines and use them to
1646 // attempt creation of a new pipeline to be used normally.
1647 class CreateAndUseIdsInstance : public vkt::TestInstance
1648 {
1649 public:
1650     using RndGenPtr = std::shared_ptr<de::Random>;
1651 
1652     struct Params : public BaseParams
1653     {
1654         PipelineConstructionType constructionType;
1655         bool useRTLibraries; // Use ray tracing libraries? For monolithic builds only.
1656         bool useMaintenance5;
1657         UseModuleCase moduleUseCase;
1658         CapturedPropertiesFlags capturedProperties; // For UseModuleCase::ID only.
1659         RndGenPtr rnd;
1660 
Paramsvkt::pipeline::__anoncd3947560111::CreateAndUseIdsInstance::Params1661         Params(PipelineType pipelineType_, GraphicsShaderVec graphicsShaders_, RTShaderVec rtShaders_,
1662                uint8_t pipelineCount_, const tcu::Maybe<uint8_t> &pipelineToRun_, bool useSCs_, bool useCache_,
1663                bool useMaintenance5_, PipelineConstructionType constructionType_, bool useRTLibraries_,
1664                UseModuleCase moduleUseCase_, CapturedPropertiesFlags capturedProperties_)
1665             : BaseParams(pipelineType_, graphicsShaders_, rtShaders_, pipelineCount_, pipelineToRun_, useSCs_,
1666                          useCache_, useMaintenance5_)
1667             , constructionType(constructionType_)
1668             , useRTLibraries(useRTLibraries_)
1669             , useMaintenance5(false)
1670             , moduleUseCase(moduleUseCase_)
1671             , capturedProperties(capturedProperties_)
1672             , rnd()
1673         {
1674             DE_ASSERT(!useRTLibraries || hasRayTracing());
1675             DE_ASSERT(!useRTLibraries || constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
1676             DE_ASSERT(capturedProperties == 0u || moduleUseCase == UseModuleCase::ID);
1677 
1678             // We will only be capturing properties if using one pipeline that will be run later.
1679             DE_ASSERT(capturedProperties == 0u || (pipelineCount == uint8_t{1} && static_cast<bool>(pipelineToRun)));
1680         }
1681 
~Paramsvkt::pipeline::__anoncd3947560111::CreateAndUseIdsInstance::Params1682         virtual ~Params()
1683         {
1684         }
1685 
1686         // Convenience helper method.
getRndGenvkt::pipeline::__anoncd3947560111::CreateAndUseIdsInstance::Params1687         de::Random &getRndGen(void) const
1688         {
1689             return *rnd;
1690         }
1691 
1692         // Copy parameters resetting the random number generator with a new seed.
copyvkt::pipeline::__anoncd3947560111::CreateAndUseIdsInstance::Params1693         BaseParamsPtr copy(uint32_t newSeed)
1694         {
1695             std::unique_ptr<Params> clone(new Params(*this));
1696             clone->rnd.reset(new de::Random(newSeed));
1697             return BaseParamsPtr(clone.release());
1698         }
1699     };
1700 
1701     using ParamsPtr = std::unique_ptr<Params>;
1702 
CreateAndUseIdsInstance(Context & context,const Params * params)1703     CreateAndUseIdsInstance(Context &context, const Params *params) : vkt::TestInstance(context), m_params(params)
1704     {
1705     }
~CreateAndUseIdsInstance(void)1706     virtual ~CreateAndUseIdsInstance(void)
1707     {
1708     }
1709 
1710     tcu::TestStatus iterate(void) override;
1711 
1712 protected:
1713     const Params *m_params;
1714 };
1715 
1716 class CreateAndUseIdsCase : public SourcesAndSupportFromParamsBase
1717 {
1718 public:
CreateAndUseIdsCase(tcu::TestContext & testCtx,const std::string & name,BaseParamsPtr && params)1719     CreateAndUseIdsCase(tcu::TestContext &testCtx, const std::string &name, BaseParamsPtr &&params)
1720         : SourcesAndSupportFromParamsBase(testCtx, name, std::move(params))
1721         , m_createAndUseIdsParams(dynamic_cast<const CreateAndUseIdsInstance::Params *>(m_params.get()))
1722     {
1723         DE_ASSERT(m_createAndUseIdsParams);
1724     }
~CreateAndUseIdsCase(void)1725     virtual ~CreateAndUseIdsCase(void)
1726     {
1727     }
1728     void checkSupport(Context &context) const override;
1729     TestInstance *createInstance(Context &context) const override;
1730 
1731 protected:
1732     const CreateAndUseIdsInstance::Params *m_createAndUseIdsParams;
1733 };
1734 
checkSupport(Context & context) const1735 void CreateAndUseIdsCase::checkSupport(Context &context) const
1736 {
1737     SourcesAndSupportFromParamsBase::checkSupport(context);
1738 
1739     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1740                                           m_createAndUseIdsParams->constructionType);
1741 
1742     if (m_createAndUseIdsParams->useRTLibraries)
1743         context.requireDeviceFunctionality("VK_KHR_pipeline_library");
1744 
1745     if (m_createAndUseIdsParams->capturedProperties != 0u)
1746         context.requireDeviceFunctionality("VK_KHR_pipeline_executable_properties");
1747 
1748     if ((m_params->pipelineType == PipelineType::COMPUTE || m_params->hasRayTracing()) &&
1749         static_cast<bool>(m_params->pipelineToRun))
1750     {
1751         const auto features = context.getPipelineCreationCacheControlFeatures();
1752         if (features.pipelineCreationCacheControl == false)
1753             TCU_THROW(NotSupportedError, "Feature 'pipelineCreationCacheControl' is not enabled");
1754     }
1755 
1756     if (m_params->useMaintenance5)
1757         context.requireDeviceFunctionality("VK_KHR_maintenance5");
1758 }
1759 
createInstance(Context & context) const1760 TestInstance *CreateAndUseIdsCase::createInstance(Context &context) const
1761 {
1762     return new CreateAndUseIdsInstance(context, m_createAndUseIdsParams);
1763 }
1764 
1765 using SpecInfoPtr   = std::unique_ptr<VkSpecializationInfo>;
1766 using SCMapEntryVec = std::vector<VkSpecializationMapEntry>;
1767 
maybeMakeSpecializationInfo(bool makeIt,const VkSpecializationMapEntry * entry,std::vector<uint32_t>::const_iterator & iter)1768 SpecInfoPtr maybeMakeSpecializationInfo(bool makeIt, const VkSpecializationMapEntry *entry,
1769                                         std::vector<uint32_t>::const_iterator &iter)
1770 {
1771     if (!makeIt)
1772         return nullptr;
1773 
1774     DE_ASSERT(entry);
1775     SpecInfoPtr info(new VkSpecializationInfo);
1776 
1777     info->mapEntryCount = 1u;
1778     info->pMapEntries   = entry;
1779     info->dataSize      = sizeof(uint32_t);
1780     info->pData         = &(*(iter++));
1781 
1782     return info;
1783 }
1784 
makeRasterizationState(bool rasterizationDisabled)1785 VkPipelineRasterizationStateCreateInfo makeRasterizationState(bool rasterizationDisabled)
1786 {
1787     VkPipelineRasterizationStateCreateInfo state = initVulkanStructure();
1788     state.rasterizerDiscardEnable                = (rasterizationDisabled ? VK_TRUE : VK_FALSE);
1789     state.lineWidth                              = 1.0f;
1790     return state;
1791 }
1792 
1793 class PipelineStageInfo
1794 {
1795 protected:
1796     ShaderWrapper m_shader;
1797     ShaderModuleId m_moduleId;
1798     ShaderStageIdPtr m_moduleIdCreateInfo;
1799     SpecInfoPtr m_specInfo;
1800 
1801 public:
PipelineStageInfo()1802     PipelineStageInfo() : m_shader(), m_moduleId(), m_moduleIdCreateInfo(), m_specInfo()
1803     {
1804     }
1805 
setModule(const DeviceInterface & vkd,const VkDevice device,const ShaderWrapper shader,UseModuleCase moduleUse,de::Random & rnd)1806     void setModule(const DeviceInterface &vkd, const VkDevice device, const ShaderWrapper shader,
1807                    UseModuleCase moduleUse, de::Random &rnd)
1808     {
1809         m_shader = shader;
1810 
1811         m_moduleId = getShaderModuleIdentifier(vkd, device, shader.getModule());
1812         maybeMangleShaderModuleId(m_moduleId, moduleUse, rnd);
1813 
1814         m_moduleIdCreateInfo = makeShaderStageModuleIdentifierCreateInfo(m_moduleId, moduleUse, &rnd);
1815     }
1816 
setSpecInfo(SpecInfoPtr && specInfo)1817     void setSpecInfo(SpecInfoPtr &&specInfo)
1818     {
1819         m_specInfo = std::move(specInfo);
1820     }
1821 
getModule(void) const1822     ShaderWrapper getModule(void) const
1823     {
1824         return m_shader;
1825     }
1826 
getUsedModule(UseModuleCase moduleUse)1827     ShaderWrapper *getUsedModule(UseModuleCase moduleUse)
1828     {
1829         return retUsedModule(&m_shader, moduleUse);
1830     }
1831 
getModuleIdCreateInfo(void) const1832     const VkPipelineShaderStageModuleIdentifierCreateInfoEXT *getModuleIdCreateInfo(void) const
1833     {
1834         return m_moduleIdCreateInfo.get();
1835     }
1836 
getSpecInfo(void) const1837     const VkSpecializationInfo *getSpecInfo(void) const
1838     {
1839         return m_specInfo.get();
1840     }
1841 
1842     // Forbid copy and assignment. This would break the relationship between moduleId and moduleIdCreateInfo.
1843     PipelineStageInfo(const PipelineStageInfo &)            = delete;
1844     PipelineStageInfo &operator=(const PipelineStageInfo &) = delete;
1845 };
1846 
makeComputeSpecConstants(uint32_t stageConstant)1847 std::vector<uint32_t> makeComputeSpecConstants(uint32_t stageConstant)
1848 {
1849     return std::vector<uint32_t>{stageConstant, 1u, 1u, 1u};
1850 }
1851 
makeComputeSpecMapEntries(void)1852 SCMapEntryVec makeComputeSpecMapEntries(void)
1853 {
1854     const auto kNumEntries = 4u; // Matches the vector above.
1855     const auto entrySizeSz = sizeof(uint32_t);
1856     const auto entrySize   = static_cast<uint32_t>(entrySizeSz);
1857     SCMapEntryVec entries;
1858 
1859     entries.reserve(kNumEntries);
1860     for (uint32_t i = 0u; i < kNumEntries; ++i)
1861     {
1862         const VkSpecializationMapEntry entry = {
1863             i,               // uint32_t constantID;
1864             (entrySize * i), // uint32_t offset;
1865             entrySizeSz,     // size_t size;
1866         };
1867         entries.push_back(entry);
1868     }
1869 
1870     return entries;
1871 }
1872 
makeComputeSpecInfo(const SCMapEntryVec & scEntries,const std::vector<uint32_t> & scData)1873 SpecInfoPtr makeComputeSpecInfo(const SCMapEntryVec &scEntries, const std::vector<uint32_t> &scData)
1874 {
1875     SpecInfoPtr scInfo(new VkSpecializationInfo);
1876 
1877     scInfo->mapEntryCount = de::sizeU32(scEntries);
1878     scInfo->pMapEntries   = de::dataOrNull(scEntries);
1879     scInfo->dataSize      = de::dataSize(scData);
1880     scInfo->pData         = de::dataOrNull(scData);
1881 
1882     return scInfo;
1883 }
1884 
iterate(void)1885 tcu::TestStatus CreateAndUseIdsInstance::iterate(void)
1886 {
1887     const auto &vki           = m_context.getInstanceInterface();
1888     const auto &vkd           = m_context.getDeviceInterface();
1889     const auto physicalDevice = m_context.getPhysicalDevice();
1890     const auto device         = m_context.getDevice();
1891     auto &alloc               = m_context.getDefaultAllocator();
1892     const auto queue          = m_context.getUniversalQueue();
1893     const auto queueIndex     = m_context.getUniversalQueueFamilyIndex();
1894 
1895     const auto pipelineStages = m_params->getPipelineStageFlags();
1896     const auto shaderStages   = m_params->getShaderStageFlags();
1897     const auto captureFlags   = getPipelineCreateFlags(m_params->capturedProperties);
1898     const bool needsCapture   = (captureFlags != 0u);
1899     const auto isGraphics     = (m_params->pipelineType == PipelineType::GRAPHICS);
1900     const auto isCompute      = (m_params->pipelineType == PipelineType::COMPUTE);
1901     const auto fbFormat       = VK_FORMAT_R8G8B8A8_UNORM;
1902     const auto tcuFbFormat    = mapVkFormat(fbFormat);
1903     const auto pixelSize      = tcu::getPixelSize(tcuFbFormat);
1904     const auto fbExtent       = makeExtent3D(1u, 1u, 1u);
1905     const tcu::IVec3 iExtent(static_cast<int>(fbExtent.width), static_cast<int>(fbExtent.height),
1906                              static_cast<int>(fbExtent.depth));
1907     const auto isRT            = m_params->hasRayTracing();
1908     const auto hasHit          = m_params->hasHit();
1909     const auto hasHitAndMiss   = hasHit && m_params->hasMiss();
1910     const auto stagesCount     = m_params->stageCountPerPipeline();
1911     const auto pipelineCount32 = static_cast<uint32_t>(m_params->pipelineCount);
1912     const auto hasTess         = m_params->hasTess();
1913     const auto topology        = (hasTess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
1914     const auto patchCPs        = (hasTess ? 3u : 0u);
1915     const auto useSCs          = m_params->useSpecializationConstants;
1916     const auto shaderConstants = generateShaderConstants(m_params->pipelineType, m_params->pipelineCount, stagesCount);
1917     const auto runOnePipeline  = static_cast<bool>(m_params->pipelineToRun);
1918     const bool reqCacheMiss    = expectCacheMiss(m_params->moduleUseCase);
1919     const bool qualityWarn     = (m_params->useCache && !needsCapture);
1920     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 0.0f);
1921     const tcu::Vec4 blueColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match fragment shader above.
1922 
1923     // Used when capturing pipeline executable properties.
1924     PipelineExecutablePropertyVec classicExeProps;
1925     PipelineExecutablePropertyVec identifierExeProps;
1926 
1927     // Command pool and buffer.
1928     const auto cmdPool      = makeCommandPool(vkd, device, queueIndex);
1929     const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1930     const auto cmdBuffer    = cmdBufferPtr.get();
1931 
1932     // Begin command buffer. We may need it below for RT.
1933     beginCommandBuffer(vkd, cmdBuffer);
1934 
1935     // Descriptor set layouts. Typically 1 but ray tracing tests use a separate set for the acceleration structure.
1936     std::vector<VkDescriptorSetLayout> setLayouts;
1937 
1938     DescriptorSetLayoutBuilder setLayoutBuilder;
1939     setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, shaderStages);
1940     for (uint8_t i = 0; i < m_params->pipelineCount; ++i)
1941         setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, shaderStages);
1942     const auto mainSetLayout = setLayoutBuilder.build(vkd, device);
1943     setLayouts.push_back(mainSetLayout.get());
1944 
1945     const auto auxSetLayout = (isRT ? DescriptorSetLayoutBuilder()
1946                                           .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, shaderStages)
1947                                           .build(vkd, device) :
1948                                       Move<VkDescriptorSetLayout>());
1949     if (isRT)
1950         setLayouts.push_back(auxSetLayout.get());
1951 
1952     // Pipeline layout.
1953     PipelineLayoutWrapper pipelineLayout(m_params->constructionType, vkd, device, de::sizeU32(setLayouts),
1954                                          de::dataOrNull(setLayouts));
1955 
1956     // Descriptor pool.
1957     DescriptorPoolBuilder poolBuilder;
1958     poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1959     poolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pipelineCount32);
1960     if (isRT)
1961         poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
1962     const auto descriptorPool =
1963         poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, de::sizeU32(setLayouts));
1964 
1965     // Descriptor buffers.
1966     const auto storageBufferSize = static_cast<VkDeviceSize>(sizeof(uint32_t) * stagesCount);
1967     const auto storageBufferInfo = makeBufferCreateInfo(storageBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1968     BufferWithMemory storageBuffer(vkd, device, alloc, storageBufferInfo, MemoryRequirement::HostVisible);
1969     auto &storageBufferAlloc = storageBuffer.getAllocation();
1970     void *storageBufferData  = storageBufferAlloc.getHostPtr();
1971 
1972     // For the uniform buffers we'll use a single allocation.
1973     const auto deviceProperties  = getPhysicalDeviceProperties(vki, physicalDevice);
1974     const auto minBlock          = de::roundUp(static_cast<VkDeviceSize>(sizeof(uint32_t)),
1975                                                deviceProperties.limits.minUniformBufferOffsetAlignment);
1976     const auto uniformBufferSize = minBlock * pipelineCount32;
1977     const auto uniformBufferInfo = makeBufferCreateInfo(uniformBufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
1978     BufferWithMemory uniformBuffer(vkd, device, alloc, uniformBufferInfo, MemoryRequirement::HostVisible);
1979     auto &uniformBufferAlloc = uniformBuffer.getAllocation();
1980     void *uniformBufferData  = uniformBufferAlloc.getHostPtr();
1981 
1982     deMemset(storageBufferData, 0, static_cast<size_t>(storageBufferSize));
1983     deMemset(uniformBufferData, 0, static_cast<size_t>(uniformBufferSize));
1984     flushAlloc(vkd, device, storageBufferAlloc);
1985     flushAlloc(vkd, device, uniformBufferAlloc);
1986 
1987     // Acceleration structures if needed.
1988     using TLASPtr = de::MovePtr<TopLevelAccelerationStructure>;
1989     using BLASPtr = de::SharedPtr<BottomLevelAccelerationStructure>;
1990 
1991     TLASPtr tlas;
1992     BLASPtr blas;
1993 
1994     if (isRT)
1995     {
1996         tlas = makeTopLevelAccelerationStructure();
1997         blas = BLASPtr(makeBottomLevelAccelerationStructure().release());
1998 
1999         // If we don't want hits we move the geometry way off in the X axis.
2000         // If we want hits and misses we launch 2 rays (see raygen shader).
2001         const float xOffset = (hasHit ? 0.0f : 100.0f);
2002 
2003         if (m_params->hasISec())
2004         {
2005             // AABB around (0.5, 0.5, 5).
2006             const std::vector<tcu::Vec3> geometry{
2007                 tcu::Vec3(0.0f + xOffset, 0.0f, 4.0f),
2008                 tcu::Vec3(1.0f + xOffset, 1.0f, 6.0f),
2009             };
2010 
2011             blas->addGeometry(geometry, false /*isTriangles*/, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
2012         }
2013         else
2014         {
2015             // Triangle surrounding (0.5, 0.5, 5).
2016             const std::vector<tcu::Vec3> geometry{
2017                 tcu::Vec3(0.25f + xOffset, 0.25f, 5.0f),
2018                 tcu::Vec3(0.75f + xOffset, 0.25f, 5.0f),
2019                 tcu::Vec3(0.5f + xOffset, 0.75f, 5.0f),
2020             };
2021 
2022             blas->addGeometry(geometry, true /*isTriangles*/, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
2023         }
2024         blas->createAndBuild(vkd, device, cmdBuffer, alloc);
2025         tlas->setInstanceCount(1u);
2026         tlas->addInstance(blas, identityMatrix3x4, 0u, 0xFFu, 0u,
2027                           VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR);
2028 
2029         tlas->createAndBuild(vkd, device, cmdBuffer, alloc);
2030     }
2031 
2032     // Graphics pipeline data if needed.
2033     std::unique_ptr<ImageWithMemory> colorAtt;
2034     VkImageSubresourceRange colorSRR;
2035     VkImageSubresourceLayers colorSRL;
2036     Move<VkImageView> colorAttView;
2037     RenderPassWrapper renderPass;
2038     std::unique_ptr<BufferWithMemory> verifBuffer;
2039     std::vector<VkViewport> viewports;
2040     std::vector<VkRect2D> scissors;
2041 
2042     // This is constant for all shader stages.
2043     const VkSpecializationMapEntry scMapEntry = {
2044         0u,               // uint32_t constantID;
2045         0u,               // uint32_t offset;
2046         sizeof(uint32_t), // size_t size;
2047     };
2048 
2049     if (isGraphics)
2050     {
2051         const VkImageCreateInfo colorAttCreateInfo = {
2052             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                     // VkStructureType sType;
2053             nullptr,                                                                 // const void* pNext;
2054             0u,                                                                      // VkImageCreateFlags flags;
2055             VK_IMAGE_TYPE_2D,                                                        // VkImageType imageType;
2056             fbFormat,                                                                // VkFormat format;
2057             fbExtent,                                                                // VkExtent3D extent;
2058             1u,                                                                      // uint32_t mipLevels;
2059             1u,                                                                      // uint32_t arrayLayers;
2060             VK_SAMPLE_COUNT_1_BIT,                                                   // VkSampleCountFlagBits samples;
2061             VK_IMAGE_TILING_OPTIMAL,                                                 // VkImageTiling tiling;
2062             (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), // VkImageUsageFlags usage;
2063             VK_SHARING_MODE_EXCLUSIVE,                                               // VkSharingMode sharingMode;
2064             0u,                                                                      // uint32_t queueFamilyIndexCount;
2065             nullptr,                   // const uint32_t* pQueueFamilyIndices;
2066             VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
2067         };
2068 
2069         colorAtt.reset(new ImageWithMemory(vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any));
2070         colorSRR     = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2071         colorSRL     = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
2072         colorAttView = makeImageView(vkd, device, colorAtt->get(), VK_IMAGE_VIEW_TYPE_2D, fbFormat, colorSRR);
2073         renderPass   = RenderPassWrapper(m_params->constructionType, vkd, device, fbFormat);
2074         renderPass.createFramebuffer(vkd, device, **colorAtt, colorAttView.get(), fbExtent.width, fbExtent.height);
2075 
2076         DE_ASSERT(fbExtent.width == 1u && fbExtent.height == 1u && fbExtent.depth == 1u);
2077         const auto verifBufferSize = static_cast<VkDeviceSize>(pixelSize);
2078         const auto verifBufferInfo = makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2079         verifBuffer.reset(new BufferWithMemory(vkd, device, alloc, verifBufferInfo, MemoryRequirement::HostVisible));
2080 
2081         viewports.push_back(makeViewport(fbExtent));
2082         scissors.push_back(makeRect2D(fbExtent));
2083     }
2084 
2085     // Descriptor sets.
2086     const auto mainDescriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), mainSetLayout.get());
2087     const auto auxDescriptorSet =
2088         (isRT ? makeDescriptorSet(vkd, device, descriptorPool.get(), auxSetLayout.get()) : Move<VkDescriptorSet>());
2089 
2090     std::vector<VkDescriptorSet> rawDescriptorSets;
2091     rawDescriptorSets.push_back(mainDescriptorSet.get());
2092     if (isRT)
2093         rawDescriptorSets.push_back(auxDescriptorSet.get());
2094 
2095     // Update descriptor sets.
2096     DescriptorSetUpdateBuilder updateBuilder;
2097     {
2098         const auto storageDescInfo = makeDescriptorBufferInfo(storageBuffer.get(), 0ull, storageBufferSize);
2099         updateBuilder.writeSingle(mainDescriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u),
2100                                   VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageDescInfo);
2101     }
2102     for (uint32_t uboIdx = 0u; uboIdx < pipelineCount32; ++uboIdx)
2103     {
2104         const auto uboDescInfo = makeDescriptorBufferInfo(uniformBuffer.get(), minBlock * uboIdx, minBlock);
2105         updateBuilder.writeSingle(mainDescriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(uboIdx + 1u),
2106                                   VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uboDescInfo);
2107     }
2108     if (isRT)
2109     {
2110         const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo = {
2111             VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
2112             nullptr,
2113             1u,
2114             tlas.get()->getPtr(),
2115         };
2116 
2117         updateBuilder.writeSingle(auxDescriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u),
2118                                   VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
2119     }
2120     updateBuilder.update(vkd, device);
2121 
2122     // Make pipelines.
2123     using ModuleVec      = std::vector<ShaderWrapper>;
2124     using PipelinePtrVec = std::vector<Move<VkPipeline>>;
2125     using PipelineVec    = std::vector<VkPipeline>;
2126     using WrapperVec     = std::vector<std::unique_ptr<GraphicsPipelineWrapper>>;
2127     using BufferPtr      = de::MovePtr<BufferWithMemory>;
2128 
2129     ModuleVec vertModules;
2130     ModuleVec tescModules;
2131     ModuleVec teseModules;
2132     ModuleVec geomModules;
2133     ModuleVec fragModules;
2134 
2135     ModuleVec compModules;
2136 
2137     ModuleVec rgenModules;
2138     ModuleVec ahitModules;
2139     ModuleVec chitModules;
2140     ModuleVec isecModules;
2141     ModuleVec missModules;
2142     ModuleVec callModules;
2143 
2144     BufferPtr rgenSBT;
2145     BufferPtr xhitSBT;
2146     BufferPtr missSBT;
2147     BufferPtr callSBT;
2148 
2149     VkStridedDeviceAddressRegionKHR rgenRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2150     VkStridedDeviceAddressRegionKHR xhitRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2151     VkStridedDeviceAddressRegionKHR missRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2152     VkStridedDeviceAddressRegionKHR callRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0ull, 0ull);
2153 
2154     WrapperVec pipelineWrappers; // For graphics pipelines.
2155     PipelinePtrVec pipelinePtrs; // For other pipelines.
2156     PipelineVec pipelines;
2157     Move<VkPipelineCache> pipelineCache;
2158 
2159     if (m_params->useCache)
2160     {
2161         const VkPipelineCacheCreateInfo cacheCreateInfo = initVulkanStructure();
2162         pipelineCache                                   = createPipelineCache(vkd, device, &cacheCreateInfo);
2163     }
2164 
2165     const auto &binaries = m_context.getBinaryCollection();
2166 
2167     if (isGraphics)
2168     {
2169         const VkPipelineVertexInputStateCreateInfo vertexInputState     = initVulkanStructure();
2170         const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
2171             VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
2172             nullptr,                                                     // const void* pNext;
2173             0u,       // VkPipelineInputAssemblyStateCreateFlags flags;
2174             topology, // VkPrimitiveTopology topology;
2175             VK_FALSE, // VkBool32 primitiveRestartEnable;
2176         };
2177         const VkPipelineDepthStencilStateCreateInfo depthStencilState = initVulkanStructure();
2178         VkPipelineMultisampleStateCreateInfo multisampleState         = initVulkanStructure();
2179         multisampleState.rasterizationSamples                         = VK_SAMPLE_COUNT_1_BIT;
2180         VkPipelineColorBlendAttachmentState colorBlendAttachmentState;
2181         deMemset(&colorBlendAttachmentState, 0, sizeof(colorBlendAttachmentState));
2182         colorBlendAttachmentState.colorWriteMask =
2183             (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
2184         const VkPipelineColorBlendStateCreateInfo colorBlendState = {
2185             VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, //    VkStructureType                                sType
2186             nullptr,                    //    const void*                                    pNext
2187             0u,                         //    VkPipelineColorBlendStateCreateFlags        flags
2188             VK_FALSE,                   //    VkBool32                                    logicOpEnable
2189             VK_LOGIC_OP_CLEAR,          //    VkLogicOp                                    logicOp
2190             1u,                         //    uint32_t                                    attachmentCount
2191             &colorBlendAttachmentState, //    const VkPipelineColorBlendAttachmentState*    pAttachments
2192             {0.0f, 0.0f, 0.0f, 0.0f}    //    float                                        blendConstants[4]
2193         };
2194 
2195         auto shaderConstIt = shaderConstants.begin();
2196 
2197         // In case we have to run a pipeline.
2198         PipelineStageInfo vertToRun;
2199         PipelineStageInfo tescToRun;
2200         PipelineStageInfo teseToRun;
2201         PipelineStageInfo geomToRun;
2202         PipelineStageInfo fragToRun;
2203 
2204         for (uint32_t i = 0; i < pipelineCount32; ++i)
2205         {
2206             const auto runThis  = (runOnePipeline && static_cast<uint32_t>(m_params->pipelineToRun.get()) == i);
2207             const auto suffix   = "_" + std::to_string(i);
2208             const auto vertName = "vert" + suffix;
2209             const auto tescName = "tesc" + suffix;
2210             const auto teseName = "tese" + suffix;
2211             const auto geomName = "geom" + suffix;
2212             const auto fragName = "frag" + suffix;
2213 
2214             pipelineWrappers.emplace_back(new GraphicsPipelineWrapper(vki, vkd, physicalDevice, device,
2215                                                                       m_context.getDeviceExtensions(),
2216                                                                       m_params->constructionType, captureFlags));
2217             auto &wrapper = *pipelineWrappers.back();
2218 
2219             ShaderWrapper vertModule;
2220             ShaderWrapper tescModule;
2221             ShaderWrapper teseModule;
2222             ShaderWrapper geomModule;
2223             ShaderWrapper fragModule;
2224 
2225             SpecInfoPtr vertSpecInfo;
2226             SpecInfoPtr tescSpecInfo;
2227             SpecInfoPtr teseSpecInfo;
2228             SpecInfoPtr geomSpecInfo;
2229             SpecInfoPtr fragSpecInfo;
2230 
2231             vertModules.push_back(ShaderWrapper(vkd, device, binaries.get(vertName)));
2232             vertModule   = vertModules.back();
2233             vertSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2234 
2235             if (binaries.contains(tescName))
2236             {
2237                 tescModules.push_back(ShaderWrapper(vkd, device, binaries.get(tescName)));
2238                 tescModule   = tescModules.back();
2239                 tescSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2240             }
2241 
2242             if (binaries.contains(teseName))
2243             {
2244                 teseModules.push_back(ShaderWrapper(vkd, device, binaries.get(teseName)));
2245                 teseModule   = teseModules.back();
2246                 teseSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2247             }
2248 
2249             if (binaries.contains(geomName))
2250             {
2251                 geomModules.push_back(ShaderWrapper(vkd, device, binaries.get(geomName)));
2252                 geomModule   = geomModules.back();
2253                 geomSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2254             }
2255 
2256             if (binaries.contains(fragName))
2257             {
2258                 fragModules.push_back(ShaderWrapper(vkd, device, binaries.get(fragName)));
2259                 fragModule   = fragModules.back();
2260                 fragSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2261             }
2262 
2263             const auto rasterizationState = makeRasterizationState(!fragModule.isSet());
2264 
2265             if (m_params->useMaintenance5)
2266                 wrapper.setPipelineCreateFlags2(translateCreateFlag(captureFlags));
2267 
2268             wrapper.setDefaultPatchControlPoints(patchCPs)
2269                 .setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
2270                 .setupPreRasterizationShaderState2(viewports, scissors, pipelineLayout, renderPass.get(), 0u,
2271                                                    vertModule, &rasterizationState, tescModule, teseModule, geomModule,
2272                                                    vertSpecInfo.get(), tescSpecInfo.get(), teseSpecInfo.get(),
2273                                                    geomSpecInfo.get(), nullptr, nullptr, pipelineCache.get())
2274                 .setupFragmentShaderState(pipelineLayout, renderPass.get(), 0u, fragModule, &depthStencilState,
2275                                           &multisampleState, fragSpecInfo.get(), pipelineCache.get())
2276                 .setupFragmentOutputState(*renderPass, 0u, &colorBlendState, &multisampleState, pipelineCache.get())
2277                 .setMonolithicPipelineLayout(pipelineLayout)
2278                 .buildPipeline(pipelineCache.get());
2279 
2280             pipelines.push_back(wrapper.getPipeline());
2281 
2282             // Capture properties if needed.
2283             if (needsCapture)
2284                 classicExeProps =
2285                     getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2286 
2287             if (runThis)
2288             {
2289                 vertToRun.setModule(vkd, device, vertModule, m_params->moduleUseCase, m_params->getRndGen());
2290                 vertToRun.setSpecInfo(std::move(vertSpecInfo));
2291 
2292                 if (tescModule.isSet())
2293                 {
2294                     tescToRun.setModule(vkd, device, tescModule, m_params->moduleUseCase, m_params->getRndGen());
2295                     tescToRun.setSpecInfo(std::move(tescSpecInfo));
2296                 }
2297 
2298                 if (teseModule.isSet())
2299                 {
2300                     teseToRun.setModule(vkd, device, teseModule, m_params->moduleUseCase, m_params->getRndGen());
2301                     teseToRun.setSpecInfo(std::move(teseSpecInfo));
2302                 }
2303 
2304                 if (geomModule.isSet())
2305                 {
2306                     geomToRun.setModule(vkd, device, geomModule, m_params->moduleUseCase, m_params->getRndGen());
2307                     geomToRun.setSpecInfo(std::move(geomSpecInfo));
2308                 }
2309 
2310                 if (fragModule.isSet())
2311                 {
2312                     fragToRun.setModule(vkd, device, fragModule, m_params->moduleUseCase, m_params->getRndGen());
2313                     fragToRun.setSpecInfo(std::move(fragSpecInfo));
2314                 }
2315             }
2316         }
2317 
2318         if (runOnePipeline)
2319         {
2320             // Append the pipeline to run at the end of the vector.
2321             pipelineWrappers.emplace_back(new GraphicsPipelineWrapper(vki, vkd, physicalDevice, device,
2322                                                                       m_context.getDeviceExtensions(),
2323                                                                       m_params->constructionType, captureFlags));
2324             auto &wrapper = *pipelineWrappers.back();
2325 
2326             const auto fragModule         = fragToRun.getModule();
2327             const auto rasterizationState = makeRasterizationState(!fragModule.isSet());
2328 
2329             try
2330             {
2331                 wrapper.setDefaultPatchControlPoints(patchCPs)
2332                     .setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
2333                     .setupPreRasterizationShaderState3(
2334                         viewports, scissors, pipelineLayout, renderPass.get(), 0u,
2335                         *vertToRun.getUsedModule(m_params->moduleUseCase),
2336                         PipelineShaderStageModuleIdentifierCreateInfoWrapper(vertToRun.getModuleIdCreateInfo()),
2337                         &rasterizationState, *tescToRun.getUsedModule(m_params->moduleUseCase),
2338                         PipelineShaderStageModuleIdentifierCreateInfoWrapper(tescToRun.getModuleIdCreateInfo()),
2339                         *teseToRun.getUsedModule(m_params->moduleUseCase),
2340                         PipelineShaderStageModuleIdentifierCreateInfoWrapper(teseToRun.getModuleIdCreateInfo()),
2341                         *geomToRun.getUsedModule(m_params->moduleUseCase),
2342                         PipelineShaderStageModuleIdentifierCreateInfoWrapper(geomToRun.getModuleIdCreateInfo()),
2343                         vertToRun.getSpecInfo(), tescToRun.getSpecInfo(), teseToRun.getSpecInfo(),
2344                         geomToRun.getSpecInfo(), nullptr, PipelineRenderingCreateInfoWrapper(), pipelineCache.get())
2345                     .setupFragmentShaderState2(pipelineLayout, renderPass.get(), 0u,
2346                                                *fragToRun.getUsedModule(m_params->moduleUseCase),
2347                                                fragToRun.getModuleIdCreateInfo(), &depthStencilState, &multisampleState,
2348                                                fragToRun.getSpecInfo(), pipelineCache.get())
2349                     .setupFragmentOutputState(*renderPass, 0u, &colorBlendState, &multisampleState, pipelineCache.get())
2350                     .setMonolithicPipelineLayout(pipelineLayout)
2351                     .buildPipeline(pipelineCache.get());
2352 
2353                 if (reqCacheMiss)
2354                     TCU_FAIL("Cache miss expected");
2355             }
2356             catch (const PipelineCompileRequiredError &)
2357             {
2358                 if (reqCacheMiss)
2359                     return tcu::TestStatus::pass("Pass");
2360 
2361                 if (qualityWarn)
2362                     return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
2363                                            "VK_PIPELINE_COMPILE_REQUIRED despite passing a pipeline cache");
2364                 return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED"); // ;_;
2365             }
2366 
2367             pipelines.push_back(wrapper.getPipeline());
2368 
2369             if (needsCapture)
2370                 identifierExeProps =
2371                     getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2372         }
2373     }
2374     else if (isCompute)
2375     {
2376         const auto invalidPipelineIdx = std::numeric_limits<uint32_t>::max();
2377         auto idxToRun                 = invalidPipelineIdx;
2378 
2379         for (uint32_t i = 0; i < pipelineCount32; ++i)
2380         {
2381             const auto runThis  = (runOnePipeline && static_cast<uint32_t>(m_params->pipelineToRun.get()) == i);
2382             const auto suffix   = "_" + std::to_string(i);
2383             const auto compName = "comp" + suffix;
2384 
2385             const auto scData    = (useSCs ? makeComputeSpecConstants(shaderConstants.at(i)) : std::vector<uint32_t>());
2386             const auto scEntries = (useSCs ? makeComputeSpecMapEntries() : std::vector<VkSpecializationMapEntry>());
2387             const auto scInfo    = (useSCs ? makeComputeSpecInfo(scEntries, scData) : nullptr);
2388 
2389             compModules.push_back(ShaderWrapper(vkd, device, binaries.get(compName)));
2390             pipelinePtrs.push_back(makeComputePipeline(vkd, device, pipelineLayout.get(), captureFlags, nullptr,
2391                                                        compModules.back().getModule(), 0u, scInfo.get(),
2392                                                        pipelineCache.get()));
2393             pipelines.push_back(pipelinePtrs.back().get());
2394 
2395             if (runThis)
2396                 idxToRun = i;
2397 
2398             if (needsCapture)
2399                 classicExeProps =
2400                     getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2401         }
2402 
2403         if (idxToRun != invalidPipelineIdx)
2404         {
2405             auto &compModule = compModules.at(idxToRun);
2406             auto moduleId    = getShaderModuleIdentifier(vkd, device, compModule.getModule());
2407 
2408             maybeMangleShaderModuleId(moduleId, m_params->moduleUseCase, m_params->getRndGen());
2409 
2410             const auto modInfo =
2411                 makeShaderStageModuleIdentifierCreateInfo(moduleId, m_params->moduleUseCase, &(m_params->getRndGen()));
2412             const auto scData =
2413                 (useSCs ? makeComputeSpecConstants(shaderConstants.at(idxToRun)) : std::vector<uint32_t>());
2414             const auto scEntries = (useSCs ? makeComputeSpecMapEntries() : std::vector<VkSpecializationMapEntry>());
2415             const auto scInfo    = (useSCs ? makeComputeSpecInfo(scEntries, scData) : nullptr);
2416 
2417             // Append the pipeline to run at the end of the vector.
2418             {
2419                 const auto pipelineFlags = (VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT | captureFlags);
2420 
2421                 const VkPipelineShaderStageCreateInfo pipelineShaderStageParams = {
2422                     VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
2423                     modInfo.get(),                                       // const void* pNext;
2424                     0u,                                                  // VkPipelineShaderStageCreateFlags flags;
2425                     VK_SHADER_STAGE_COMPUTE_BIT,                         // VkShaderStageFlagBits stage;
2426                     retUsedModule(&compModule, m_params->moduleUseCase)->getModule(), // VkShaderModule module;
2427                     "main",                                                           // const char* pName;
2428                     scInfo.get(), // const VkSpecializationInfo* pSpecializationInfo;
2429                 };
2430 
2431                 const VkComputePipelineCreateInfo pipelineCreateInfo = {
2432                     VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
2433                     nullptr,                                        // const void* pNext;
2434                     pipelineFlags,                                  // VkPipelineCreateFlags flags;
2435                     pipelineShaderStageParams,                      // VkPipelineShaderStageCreateInfo stage;
2436                     pipelineLayout.get(),                           // VkPipelineLayout layout;
2437                     DE_NULL,                                        // VkPipeline basePipelineHandle;
2438                     0,                                              // int32_t basePipelineIndex;
2439                 };
2440 
2441                 VkPipeline pipeline;
2442                 VkResult creationResult = vkd.createComputePipelines(device, pipelineCache.get(), 1u,
2443                                                                      &pipelineCreateInfo, nullptr, &pipeline);
2444 
2445                 if (creationResult == VK_PIPELINE_COMPILE_REQUIRED)
2446                 {
2447                     if (reqCacheMiss)
2448                         return tcu::TestStatus::pass("Pass");
2449 
2450                     if (qualityWarn)
2451                         return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
2452                                                "VK_PIPELINE_COMPILE_REQUIRED despite passing a pipeline cache");
2453                     return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED"); // ;_;
2454                 }
2455                 VK_CHECK(creationResult);
2456 
2457                 if (reqCacheMiss)
2458                     TCU_FAIL("Cache miss expected");
2459 
2460                 Move<VkPipeline> pipelinePtr(check<VkPipeline>(pipeline), Deleter<VkPipeline>(vkd, device, nullptr));
2461                 pipelinePtrs.emplace_back(pipelinePtr);
2462                 pipelines.push_back(pipeline);
2463 
2464                 if (needsCapture)
2465                     identifierExeProps =
2466                         getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2467             }
2468         }
2469     }
2470     else if (isRT)
2471     {
2472         // Get some ray tracing properties and constants.
2473         const auto rayTracingPropertiesKHR  = makeRayTracingProperties(vki, physicalDevice);
2474         const auto shaderGroupHandleSize    = rayTracingPropertiesKHR->getShaderGroupHandleSize();
2475         const auto shaderGroupBaseAlignment = rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
2476         const auto vec3Size                 = static_cast<uint32_t>(sizeof(tcu::Vec3));
2477 
2478         // Empty pipeline vector, needed in a couple places.
2479         const std::vector<VkPipeline> emptyPipelinesVec;
2480 
2481         auto shaderConstIt = shaderConstants.begin();
2482 
2483         // In case we have to run a pipeline.
2484         PipelineStageInfo rgenToRun;
2485         PipelineStageInfo chitToRun;
2486         PipelineStageInfo ahitToRun;
2487         PipelineStageInfo isecToRun;
2488         PipelineStageInfo missToRun;
2489         PipelineStageInfo callToRun;
2490 
2491         for (uint32_t i = 0; i < pipelineCount32; ++i)
2492         {
2493             const auto runThis  = (runOnePipeline && static_cast<uint32_t>(m_params->pipelineToRun.get()) == i);
2494             const auto suffix   = "_" + std::to_string(i);
2495             const auto rgenName = "rgen" + suffix;
2496             const auto chitName = "chit" + suffix;
2497             const auto ahitName = "ahit" + suffix;
2498             const auto isecName = "isec" + suffix;
2499             const auto missName = "miss" + suffix;
2500             const auto callName = "call" + suffix;
2501 
2502             ShaderWrapper rgenModule;
2503             ShaderWrapper chitModule;
2504             ShaderWrapper ahitModule;
2505             ShaderWrapper isecModule;
2506             ShaderWrapper missModule;
2507             ShaderWrapper callModule;
2508 
2509             SpecInfoPtr rgenSpecInfo;
2510             SpecInfoPtr chitSpecInfo;
2511             SpecInfoPtr ahitSpecInfo;
2512             SpecInfoPtr isecSpecInfo;
2513             SpecInfoPtr missSpecInfo;
2514             SpecInfoPtr callSpecInfo;
2515 
2516             uint32_t groupCount      = 1u;
2517             const uint32_t rgenGroup = 0u;
2518             tcu::Maybe<uint32_t> xhitGroup;
2519             tcu::Maybe<uint32_t> missGroup;
2520             tcu::Maybe<uint32_t> callGroup;
2521 
2522             rgenModules.push_back(ShaderWrapper(vkd, device, binaries.get(rgenName)));
2523             rgenModule   = rgenModules.back();
2524             rgenSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2525 
2526             if (binaries.contains(chitName))
2527             {
2528                 chitModules.push_back(ShaderWrapper(vkd, device, binaries.get(chitName)));
2529                 chitModule   = chitModules.back();
2530                 chitSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2531                 xhitGroup    = (static_cast<bool>(xhitGroup) ? xhitGroup : tcu::just(groupCount++));
2532             }
2533 
2534             if (binaries.contains(ahitName))
2535             {
2536                 ahitModules.push_back(ShaderWrapper(vkd, device, binaries.get(ahitName)));
2537                 ahitModule   = ahitModules.back();
2538                 ahitSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2539                 xhitGroup    = (static_cast<bool>(xhitGroup) ? xhitGroup : tcu::just(groupCount++));
2540             }
2541 
2542             if (binaries.contains(isecName))
2543             {
2544                 isecModules.push_back(ShaderWrapper(vkd, device, binaries.get(isecName)));
2545                 isecModule   = isecModules.back();
2546                 isecSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2547                 xhitGroup    = (static_cast<bool>(xhitGroup) ? xhitGroup : tcu::just(groupCount++));
2548             }
2549 
2550             if (binaries.contains(missName))
2551             {
2552                 missModules.push_back(ShaderWrapper(vkd, device, binaries.get(missName)));
2553                 missModule   = missModules.back();
2554                 missSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2555                 missGroup    = tcu::just(groupCount++);
2556             }
2557 
2558             if (binaries.contains(callName))
2559             {
2560                 callModules.push_back(ShaderWrapper(vkd, device, binaries.get(callName)));
2561                 callModule   = callModules.back();
2562                 callSpecInfo = maybeMakeSpecializationInfo(useSCs, &scMapEntry, shaderConstIt);
2563                 callGroup    = tcu::just(groupCount++);
2564             }
2565 
2566             {
2567                 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
2568 
2569                 // These have to match the shaders.
2570                 rayTracingPipeline->setMaxPayloadSize(vec3Size);
2571                 rayTracingPipeline->setMaxAttributeSize(vec3Size);
2572 
2573                 // Make it a library if we are using libraries.
2574                 rayTracingPipeline->setCreateFlags(captureFlags |
2575                                                    (m_params->useRTLibraries ? VK_PIPELINE_CREATE_LIBRARY_BIT_KHR : 0));
2576 
2577                 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule.getModule(), rgenGroup,
2578                                               rgenSpecInfo.get());
2579 
2580                 if (chitModule.isSet())
2581                     rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitModule.getModule(),
2582                                                   xhitGroup.get(), chitSpecInfo.get());
2583 
2584                 if (ahitModule.isSet())
2585                     rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, ahitModule.getModule(),
2586                                                   xhitGroup.get(), ahitSpecInfo.get());
2587 
2588                 if (isecModule.isSet())
2589                     rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, isecModule.getModule(),
2590                                                   xhitGroup.get(), isecSpecInfo.get());
2591 
2592                 if (missModule.isSet())
2593                     rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missModule.getModule(), missGroup.get(),
2594                                                   missSpecInfo.get());
2595 
2596                 if (callModule.isSet())
2597                     rayTracingPipeline->addShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR, callModule.getModule(),
2598                                                   callGroup.get(), callSpecInfo.get());
2599 
2600                 pipelinePtrs.emplace_back(rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get(),
2601                                                                              emptyPipelinesVec, pipelineCache.get()));
2602                 pipelines.push_back(pipelinePtrs.back().get());
2603 
2604                 // We may need to link the pipeline just like we'll do with shader module identifiers below.
2605                 if (m_params->useRTLibraries)
2606                 {
2607                     const auto linkedPipeline = de::newMovePtr<RayTracingPipeline>();
2608 
2609                     linkedPipeline->setMaxPayloadSize(vec3Size);
2610                     linkedPipeline->setMaxAttributeSize(vec3Size);
2611                     linkedPipeline->setCreateFlags(captureFlags);
2612 
2613                     const std::vector<VkPipeline> rawPipelines(1u, pipelines.back());
2614                     pipelinePtrs.emplace_back(linkedPipeline->createPipeline(vkd, device, pipelineLayout.get(),
2615                                                                              rawPipelines, pipelineCache.get()));
2616                     pipelines.push_back(pipelinePtrs.back().get());
2617                 }
2618 
2619                 if (needsCapture)
2620                     classicExeProps =
2621                         getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2622             }
2623 
2624             if (runThis)
2625             {
2626                 rgenToRun.setModule(vkd, device, rgenModule, m_params->moduleUseCase, m_params->getRndGen());
2627                 rgenToRun.setSpecInfo(std::move(rgenSpecInfo));
2628 
2629                 if (chitModule.isSet())
2630                 {
2631                     chitToRun.setModule(vkd, device, chitModule, m_params->moduleUseCase, m_params->getRndGen());
2632                     chitToRun.setSpecInfo(std::move(chitSpecInfo));
2633                 }
2634 
2635                 if (ahitModule.isSet())
2636                 {
2637                     ahitToRun.setModule(vkd, device, ahitModule, m_params->moduleUseCase, m_params->getRndGen());
2638                     ahitToRun.setSpecInfo(std::move(ahitSpecInfo));
2639                 }
2640 
2641                 if (isecModule.isSet())
2642                 {
2643                     isecToRun.setModule(vkd, device, isecModule, m_params->moduleUseCase, m_params->getRndGen());
2644                     isecToRun.setSpecInfo(std::move(isecSpecInfo));
2645                 }
2646 
2647                 if (missModule.isSet())
2648                 {
2649                     missToRun.setModule(vkd, device, missModule, m_params->moduleUseCase, m_params->getRndGen());
2650                     missToRun.setSpecInfo(std::move(missSpecInfo));
2651                 }
2652 
2653                 if (callModule.isSet())
2654                 {
2655                     callToRun.setModule(vkd, device, callModule, m_params->moduleUseCase, m_params->getRndGen());
2656                     callToRun.setSpecInfo(std::move(callSpecInfo));
2657                 }
2658             }
2659         }
2660 
2661         if (runOnePipeline)
2662         {
2663             uint32_t groupCount      = 1u;
2664             const uint32_t rgenGroup = 0u;
2665             tcu::Maybe<uint32_t> xhitGroup;
2666             tcu::Maybe<uint32_t> missGroup;
2667             tcu::Maybe<uint32_t> callGroup;
2668 
2669             const auto rgenModule = rgenToRun.getModule();
2670             DE_UNREF(rgenModule);
2671             const auto chitModule = chitToRun.getModule();
2672             const auto ahitModule = ahitToRun.getModule();
2673             const auto isecModule = isecToRun.getModule();
2674             const auto missModule = missToRun.getModule();
2675             const auto callModule = callToRun.getModule();
2676 
2677             if (chitModule.isSet())
2678                 xhitGroup = (xhitGroup ? xhitGroup : tcu::just(groupCount++));
2679             if (ahitModule.isSet())
2680                 xhitGroup = (xhitGroup ? xhitGroup : tcu::just(groupCount++));
2681             if (isecModule.isSet())
2682                 xhitGroup = (xhitGroup ? xhitGroup : tcu::just(groupCount++));
2683 
2684             if (missModule.isSet())
2685                 missGroup = tcu::just(groupCount++);
2686 
2687             if (callModule.isSet())
2688                 callGroup = tcu::just(groupCount++);
2689 
2690             const auto shaderOwningPipelinePtr = makeVkSharedPtr(de::newMovePtr<RayTracingPipeline>());
2691             const auto shaderOwningPipeline    = shaderOwningPipelinePtr->get();
2692 
2693             de::SharedPtr<de::MovePtr<RayTracingPipeline>> auxiliaryPipelinePtr;
2694             RayTracingPipeline *auxiliaryPipeline = nullptr;
2695 
2696             if (m_params->useRTLibraries)
2697             {
2698                 // The shader-owning pipeline will be a library and auxiliaryPipeline will be the bound pipeline helper.
2699                 auxiliaryPipelinePtr = makeVkSharedPtr(de::newMovePtr<RayTracingPipeline>());
2700                 auxiliaryPipeline    = auxiliaryPipelinePtr->get();
2701             }
2702 
2703             // The bound pipeline is the shader-owning pipeline if not using libraries, or the auxiliary pipeline otherwise.
2704             RayTracingPipeline *boundPipeline = (m_params->useRTLibraries ? auxiliaryPipeline : shaderOwningPipeline);
2705 
2706             shaderOwningPipeline->setMaxPayloadSize(vec3Size);
2707             shaderOwningPipeline->setMaxAttributeSize(vec3Size);
2708             {
2709                 VkPipelineCreateFlags creationFlags =
2710                     (VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT | captureFlags);
2711                 if (m_params->useRTLibraries)
2712                     creationFlags |= VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
2713                 shaderOwningPipeline->setCreateFlags(creationFlags);
2714             }
2715 
2716             shaderOwningPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR,
2717                                             rgenToRun.getUsedModule(m_params->moduleUseCase)->getModule(), rgenGroup,
2718                                             rgenToRun.getSpecInfo(), 0, rgenToRun.getModuleIdCreateInfo());
2719 
2720             if (chitModule.isSet())
2721             {
2722                 shaderOwningPipeline->addShader(
2723                     VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2724                     xhitGroup.get(), chitToRun.getSpecInfo(), 0, chitToRun.getModuleIdCreateInfo());
2725             }
2726 
2727             if (ahitModule.isSet())
2728             {
2729                 shaderOwningPipeline->addShader(
2730                     VK_SHADER_STAGE_ANY_HIT_BIT_KHR, ahitToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2731                     xhitGroup.get(), ahitToRun.getSpecInfo(), 0, ahitToRun.getModuleIdCreateInfo());
2732             }
2733 
2734             if (isecModule.isSet())
2735             {
2736                 shaderOwningPipeline->addShader(
2737                     VK_SHADER_STAGE_INTERSECTION_BIT_KHR, isecToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2738                     xhitGroup.get(), isecToRun.getSpecInfo(), 0, isecToRun.getModuleIdCreateInfo());
2739             }
2740 
2741             if (missModule.isSet())
2742             {
2743                 shaderOwningPipeline->addShader(
2744                     VK_SHADER_STAGE_MISS_BIT_KHR, missToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2745                     missGroup.get(), missToRun.getSpecInfo(), 0, missToRun.getModuleIdCreateInfo());
2746             }
2747 
2748             if (callModule.isSet())
2749             {
2750                 shaderOwningPipeline->addShader(
2751                     VK_SHADER_STAGE_CALLABLE_BIT_KHR, callToRun.getUsedModule(m_params->moduleUseCase)->getModule(),
2752                     callGroup.get(), callToRun.getSpecInfo(), 0, callToRun.getModuleIdCreateInfo());
2753             }
2754 
2755             // Append the pipeline, SBTs and regions to use at the end of their vectors.
2756             try
2757             {
2758                 pipelinePtrs.emplace_back(shaderOwningPipeline->createPipeline(vkd, device, pipelineLayout.get(),
2759                                                                                emptyPipelinesVec, pipelineCache.get()));
2760                 pipelines.push_back(pipelinePtrs.back().get());
2761             }
2762             catch (const RayTracingPipeline::CompileRequiredError &)
2763             {
2764                 if (reqCacheMiss)
2765                     return tcu::TestStatus::pass("Pass");
2766 
2767                 if (qualityWarn)
2768                     return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
2769                                            "VK_PIPELINE_COMPILE_REQUIRED despite passing a pipeline cache");
2770                 return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED"); // ;_;
2771             }
2772 
2773             if (m_params->useRTLibraries)
2774             {
2775                 // Create a new pipeline using the library created above, and use it as the active pipeline.
2776                 auxiliaryPipeline->setMaxPayloadSize(vec3Size);
2777                 auxiliaryPipeline->setMaxAttributeSize(vec3Size);
2778                 auxiliaryPipeline->setCreateFlags(VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT |
2779                                                   captureFlags);
2780 
2781                 try
2782                 {
2783                     const std::vector<VkPipeline> rawPipelines(1u, pipelines.back());
2784                     pipelinePtrs.emplace_back(auxiliaryPipeline->createPipeline(vkd, device, pipelineLayout.get(),
2785                                                                                 rawPipelines, pipelineCache.get()));
2786                     pipelines.push_back(pipelinePtrs.back().get());
2787 
2788                     if (reqCacheMiss)
2789                         TCU_FAIL("Cache miss expected");
2790                 }
2791                 catch (const RayTracingPipeline::CompileRequiredError &)
2792                 {
2793                     if (reqCacheMiss)
2794                         return tcu::TestStatus::pass("Pass");
2795 
2796                     if (qualityWarn)
2797                         return tcu::TestStatus(
2798                             QP_TEST_RESULT_QUALITY_WARNING,
2799                             "VK_PIPELINE_COMPILE_REQUIRED on library use despite passing a pipeline cache");
2800                     return tcu::TestStatus::pass("VK_PIPELINE_COMPILE_REQUIRED on library use"); // ;_;
2801                 }
2802             }
2803             else if (reqCacheMiss)
2804                 TCU_FAIL("Cache miss expected");
2805 
2806             if (needsCapture)
2807                 identifierExeProps =
2808                     getPipelineExecutableProperties(vkd, device, pipelines.back(), m_params->capturedProperties);
2809 
2810             const auto pipeline = pipelines.back();
2811 
2812             rgenSBT    = boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize,
2813                                                                  shaderGroupBaseAlignment, rgenGroup, 1u);
2814             rgenRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, rgenSBT->get(), 0),
2815                                                            shaderGroupHandleSize, shaderGroupHandleSize);
2816 
2817             if (xhitGroup)
2818             {
2819                 xhitSBT = boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize,
2820                                                                   shaderGroupBaseAlignment, xhitGroup.get(), 1u);
2821                 xhitRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, xhitSBT->get(), 0),
2822                                                                shaderGroupHandleSize, shaderGroupHandleSize);
2823             }
2824 
2825             if (missGroup)
2826             {
2827                 missSBT = boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize,
2828                                                                   shaderGroupBaseAlignment, missGroup.get(), 1u);
2829                 missRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0),
2830                                                                shaderGroupHandleSize, shaderGroupHandleSize);
2831             }
2832 
2833             if (callGroup)
2834             {
2835                 callSBT = boundPipeline->createShaderBindingTable(vkd, device, pipeline, alloc, shaderGroupHandleSize,
2836                                                                   shaderGroupBaseAlignment, callGroup.get(), 1u);
2837                 callRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, callSBT->get(), 0),
2838                                                                shaderGroupHandleSize, shaderGroupHandleSize);
2839             }
2840         }
2841     }
2842     else
2843     {
2844         DE_ASSERT(false);
2845     }
2846 
2847     // Early exit if we don't need to run any pipeline.
2848     if (!runOnePipeline)
2849         return tcu::TestStatus::pass("Pass (not using any pipeline)");
2850 
2851     // Compare executable properties if captured.
2852     if (needsCapture)
2853     {
2854         using PipelineExecutablePropertySet = std::set<PipelineExecutableProperty>;
2855 
2856         const PipelineExecutablePropertySet classicProps(begin(classicExeProps), end(classicExeProps));
2857         const PipelineExecutablePropertySet identifierProps(begin(identifierExeProps), end(identifierExeProps));
2858 
2859         if (classicProps != identifierProps)
2860         {
2861             auto &log = m_context.getTestContext().getLog();
2862 
2863             log << tcu::TestLog::Message << "Properties without identifiers: " << classicExeProps
2864                 << tcu::TestLog::EndMessage;
2865             log << tcu::TestLog::Message << "Properties with    identifiers: " << identifierExeProps
2866                 << tcu::TestLog::EndMessage;
2867 
2868             TCU_FAIL("Pipeline executable properties differ (check log for details)");
2869         }
2870     }
2871 
2872     if (isGraphics)
2873     {
2874         const auto bindPoint   = VK_PIPELINE_BIND_POINT_GRAPHICS;
2875         const auto vertexCount = (m_params->hasTess() ? 3u : 1u);
2876 
2877         renderPass.begin(vkd, cmdBuffer, scissors.at(0u), clearColor);
2878         vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, de::sizeU32(rawDescriptorSets),
2879                                   de::dataOrNull(rawDescriptorSets), 0u, nullptr);
2880         vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipelines.back());
2881         vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
2882         renderPass.end(vkd, cmdBuffer);
2883 
2884         const auto copyRegion = makeBufferImageCopy(fbExtent, colorSRL);
2885         const auto preHostBarrier =
2886             makeMemoryBarrier((VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT), VK_ACCESS_HOST_READ_BIT);
2887         const auto postRenderBarrier = makeImageMemoryBarrier(
2888             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2889             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorAtt->get(), colorSRR);
2890 
2891         // Copy color attachment to verification buffer.
2892         cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2893                                       VK_PIPELINE_STAGE_TRANSFER_BIT, &postRenderBarrier);
2894         vkd.cmdCopyImageToBuffer(cmdBuffer, colorAtt->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer->get(),
2895                                  1u, &copyRegion);
2896 
2897         // Synchronize SSBO and verification buffer reads from the host.
2898         cmdPipelineMemoryBarrier(vkd, cmdBuffer, (VK_PIPELINE_STAGE_TRANSFER_BIT | pipelineStages),
2899                                  VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
2900     }
2901     else if (isCompute)
2902     {
2903         const auto bindPoint      = VK_PIPELINE_BIND_POINT_COMPUTE;
2904         const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
2905 
2906         vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, de::sizeU32(rawDescriptorSets),
2907                                   de::dataOrNull(rawDescriptorSets), 0u, nullptr);
2908         vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipelines.back());
2909         vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
2910         cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStages, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
2911     }
2912     else if (isRT)
2913     {
2914         const auto bindPoint      = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
2915         const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
2916         const auto rayCount       = (hasHitAndMiss ? 2u : 1u);
2917 
2918         vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, de::sizeU32(rawDescriptorSets),
2919                                   de::dataOrNull(rawDescriptorSets), 0u, nullptr);
2920         vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipelines.back());
2921         vkd.cmdTraceRaysKHR(cmdBuffer, &rgenRegion, &missRegion, &xhitRegion, &callRegion, rayCount, 1u, 1u);
2922         cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStages, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
2923     }
2924     else
2925     {
2926         DE_ASSERT(false);
2927     }
2928 
2929     // Finish and submit command buffer.
2930     endCommandBuffer(vkd, cmdBuffer);
2931     submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2932 
2933     // Verify framebuffer if used.
2934     if (isGraphics)
2935     {
2936         auto &verifBufferAlloc = verifBuffer->getAllocation();
2937         void *verifBufferData  = verifBufferAlloc.getHostPtr();
2938 
2939         invalidateAlloc(vkd, device, verifBufferAlloc);
2940 
2941         tcu::ConstPixelBufferAccess resultAccess(tcuFbFormat, iExtent, verifBufferData);
2942         const tcu::Vec4 expectedColor = (m_params->hasFrag() ? blueColor : clearColor);
2943         const auto resultColor        = resultAccess.getPixel(0, 0);
2944 
2945         if (resultColor != expectedColor)
2946         {
2947             std::ostringstream msg;
2948             msg << "Unexpected color found in Framebuffer: expected " << expectedColor << " but found " << resultColor;
2949             TCU_FAIL(msg.str());
2950         }
2951     }
2952 
2953     // Verify SSBO data.
2954     {
2955         invalidateAlloc(vkd, device, storageBufferAlloc);
2956         std::vector<uint32_t> outputData(stagesCount, 0u);
2957         deMemcpy(outputData.data(), storageBufferData, de::dataSize(outputData));
2958 
2959         for (size_t stageIdx = 0u; stageIdx < stagesCount; ++stageIdx)
2960         {
2961             const auto &expected =
2962                 shaderConstants.at(getShaderIdx(m_params->pipelineToRun.get(), stageIdx, stagesCount));
2963             const auto &result = outputData.at(stageIdx);
2964 
2965             if (expected != result)
2966             {
2967                 std::ostringstream msg;
2968                 msg << "Unexpected data found for stage " << stageIdx << std::hex << ": expected 0x" << expected
2969                     << " but found 0x" << result;
2970                 TCU_FAIL(msg.str());
2971             }
2972         }
2973     }
2974 
2975     return tcu::TestStatus::pass("Pass");
2976 }
2977 
2978 enum class Winding
2979 {
2980     CW = 0,
2981     CCW,
2982 };
2983 
2984 enum class Partitioning
2985 {
2986     INTEGER = 0,
2987     FRACTIONAL_ODD,
2988 };
2989 
operator <<(std::ostream & out,Winding w)2990 std::ostream &operator<<(std::ostream &out, Winding w)
2991 {
2992     return (out << ((w == Winding::CW) ? "triangle_cw" : "triangle_ccw"));
2993 }
2994 
operator <<(std::ostream & out,Partitioning p)2995 std::ostream &operator<<(std::ostream &out, Partitioning p)
2996 {
2997     return (out << ((p == Partitioning::INTEGER) ? "integer" : "fractional_odd"));
2998 }
2999 
3000 class HLSLTessellationInstance : public vkt::TestInstance
3001 {
3002 public:
HLSLTessellationInstance(Context & context,PipelineConstructionType constructionType)3003     HLSLTessellationInstance(Context &context, PipelineConstructionType constructionType)
3004         : vkt::TestInstance(context)
3005         , m_constructionType(constructionType)
3006     {
3007     }
~HLSLTessellationInstance(void)3008     virtual ~HLSLTessellationInstance(void)
3009     {
3010     }
3011 
3012     tcu::TestStatus iterate(void) override;
3013 
3014 protected:
3015     const PipelineConstructionType m_constructionType;
3016 };
3017 
3018 class HLSLTessellationCase : public vkt::TestCase
3019 {
3020 public:
HLSLTessellationCase(tcu::TestContext & testCtx,const std::string & name,PipelineConstructionType constructionType)3021     HLSLTessellationCase(tcu::TestContext &testCtx, const std::string &name, PipelineConstructionType constructionType)
3022         : vkt::TestCase(testCtx, name)
3023         , m_constructionType(constructionType)
3024     {
3025     }
~HLSLTessellationCase(void)3026     virtual ~HLSLTessellationCase(void)
3027     {
3028     }
3029 
3030     void checkSupport(Context &context) const override;
3031     void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const3032     TestInstance *createInstance(Context &context) const override
3033     {
3034         return new HLSLTessellationInstance(context, m_constructionType);
3035     }
3036 
3037     static std::vector<tcu::Vec4> getOutputColors(void);
3038 
3039 protected:
3040     const PipelineConstructionType m_constructionType;
3041 };
3042 
getOutputColors(void)3043 std::vector<tcu::Vec4> HLSLTessellationCase::getOutputColors(void)
3044 {
3045     std::vector<tcu::Vec4> outColors{
3046         tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
3047         tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
3048         tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
3049         tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
3050     };
3051 
3052     return outColors;
3053 }
3054 
checkSupport(Context & context) const3055 void HLSLTessellationCase::checkSupport(Context &context) const
3056 {
3057     const auto &vki           = context.getInstanceInterface();
3058     const auto physicalDevice = context.getPhysicalDevice();
3059 
3060     checkPipelineConstructionRequirements(vki, physicalDevice, m_constructionType);
3061     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
3062     checkShaderModuleIdentifierSupport(context);
3063 }
3064 
initPrograms(vk::SourceCollections & programCollection) const3065 void HLSLTessellationCase::initPrograms(vk::SourceCollections &programCollection) const
3066 {
3067     // Vertex shader.
3068     {
3069         // Full-screen triangle.
3070         std::ostringstream vert;
3071         vert << "#version 450\n"
3072              << "out gl_PerVertex\n"
3073              << "{\n"
3074              << "    vec4 gl_Position;\n"
3075              << "};\n"
3076              << "vec2 vertexPositions[3] = vec2[](\n"
3077              << "    vec2(-1.0, -1.0),\n"
3078              << "    vec2( 3.0, -1.0),\n"
3079              << "    vec2(-1.0,  3.0)\n"
3080              << ");\n"
3081              << "void main (void) {\n"
3082              << "    gl_Position = vec4(vertexPositions[gl_VertexIndex], 0.0, 1.0);\n"
3083              << "}\n";
3084 
3085         programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
3086     }
3087 
3088     // Fragment shader, which outputs the color from the previous stages.
3089     {
3090         std::ostringstream frag;
3091         frag << "#version 450\n"
3092              << "layout (location=0) in vec4 inColor;\n"
3093              << "layout (location=0) out vec4 outColor;\n"
3094              << "void main (void) {\n"
3095              << "    outColor = inColor;\n"
3096              << "}\n";
3097 
3098         programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
3099     }
3100 
3101     // Tessellation evaluation shader (AKA domain shader) in HLSL, common for every pipeline.
3102     // Contrary to GLSL, HLSL allows us to omit execution modes in the "tese" shader and specify them on the "tesc" shader.
3103     {
3104         std::ostringstream tese;
3105         tese << "struct HullShaderOutput\n"
3106              << "{\n"
3107              << "    float4 Position : SV_Position;\n"
3108              << "    [[vk::location(0)]] float4 Color : COLOR0;\n"
3109              << "};\n"
3110              << "\n"
3111              << "struct HullShaderConstantOutput\n"
3112              << "{\n"
3113              << "    float TessLevelOuter[4] : SV_TessFactor;\n"
3114              << "    float TessLevelInner[2] : SV_InsideTessFactor;\n"
3115              << "};\n"
3116              << "\n"
3117              << "struct DomainShaderOutput\n"
3118              << "{\n"
3119              << "    float4 Position : SV_Position;\n"
3120              << "    [[vk::location(0)]] float4 Color : COLOR0;\n"
3121              << "};\n"
3122              << "\n"
3123              << "DomainShaderOutput main (HullShaderConstantOutput input, float3 TessCoord : SV_DomainLocation, const "
3124                 "OutputPatch<HullShaderOutput, 3> patch)\n"
3125              << "{\n"
3126              << "    DomainShaderOutput output = (DomainShaderOutput)0;\n"
3127              << "\n"
3128              << "    output.Position = (TessCoord.x * patch[0].Position) +\n"
3129              << "                      (TessCoord.y * patch[1].Position) +\n"
3130              << "                      (TessCoord.z * patch[2].Position);\n"
3131              << "\n"
3132              << "    output.Color = (TessCoord.x * patch[0].Color) +\n"
3133              << "                   (TessCoord.y * patch[1].Color) +\n"
3134              << "                   (TessCoord.z * patch[2].Color);\n"
3135              << "\n"
3136              << "    return output;\n"
3137              << "}\n";
3138 
3139         programCollection.hlslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
3140     }
3141 
3142     // Tessellation control shaders. Create 4 combinations with different execution modes. Each combination will also assign a different color to the vertices.
3143     // We will later run each pipeline to draw a pixel in a framebuffer (using viewports and scissors) to end up with 4 distinct colors.
3144     {
3145         const auto outColors = getOutputColors();
3146         size_t colorIdx      = 0;
3147 
3148         const Winding windings[]           = {Winding::CW, Winding::CCW};
3149         const Partitioning partitionings[] = {Partitioning::INTEGER, Partitioning::FRACTIONAL_ODD};
3150 
3151         for (const auto &winding : windings)
3152             for (const auto &partitioning : partitionings)
3153             {
3154                 std::ostringstream tesc;
3155                 tesc << "struct VertexShaderOutput\n"
3156                      << "{\n"
3157                      << "    float4 Position : SV_Position;\n"
3158                      << "};\n"
3159                      << "\n"
3160                      << "struct HullShaderOutput\n"
3161                      << "{\n"
3162                      << "    float4 Position : SV_Position;\n"
3163                      << "    [[vk::location(0)]] float4 Color : COLOR0;\n"
3164                      << "};\n"
3165                      << "\n"
3166                      << "struct HullShaderConstantOutput\n"
3167                      << "{\n"
3168                      << "    float TessLevelOuter[4] : SV_TessFactor;\n"
3169                      << "    float TessLevelInner[2] : SV_InsideTessFactor;\n"
3170                      << "};\n"
3171                      << "\n"
3172                      << "[domain(\"tri\")]\n"
3173                      << "[partitioning(\"" << partitioning << "\")]\n"
3174                      << "[outputtopology(\"" << winding << "\")]\n"
3175                      << "[outputcontrolpoints(3)]\n"
3176                      << "[patchconstantfunc(\"PCF\")]\n"
3177                      << "HullShaderOutput main (InputPatch<VertexShaderOutput, 3> patch, uint InvocationID : "
3178                         "SV_OutputControlPointID)\n"
3179                      << "{\n"
3180                      << "    HullShaderOutput output = (HullShaderOutput)0;\n"
3181                      << "    output.Position = patch[InvocationID].Position;\n"
3182                      << "    output.Color = float4" << outColors.at(colorIdx) << ";\n"
3183                      << "    return output;\n"
3184                      << "}\n"
3185                      << "\n"
3186                      << "HullShaderConstantOutput PCF (InputPatch<VertexShaderOutput, 3> patch, uint InvocationID : "
3187                         "SV_PrimitiveID)\n"
3188                      << "{\n"
3189                      << "    HullShaderConstantOutput output = (HullShaderConstantOutput)0;\n"
3190                      << "\n"
3191                      << "    output.TessLevelOuter[0] = 1;\n"
3192                      << "    output.TessLevelOuter[1] = 1;\n"
3193                      << "    output.TessLevelOuter[2] = 1;\n"
3194                      << "    output.TessLevelOuter[3] = 1;\n"
3195                      << "\n"
3196                      << "    output.TessLevelInner[0] = 1;\n"
3197                      << "    output.TessLevelInner[1] = 1;\n"
3198                      << "\n"
3199                      << "    return output;\n"
3200                      << "}\n";
3201 
3202                 const auto idxStr = std::to_string(colorIdx);
3203                 programCollection.hlslSources.add("tesc" + idxStr) << glu::TessellationControlSource(tesc.str());
3204 
3205                 ++colorIdx;
3206             }
3207     }
3208 }
3209 
iterate(void)3210 tcu::TestStatus HLSLTessellationInstance::iterate(void)
3211 {
3212     const auto &vki           = m_context.getInstanceInterface();
3213     const auto &vkd           = m_context.getDeviceInterface();
3214     const auto physicalDevice = m_context.getPhysicalDevice();
3215     const auto device         = m_context.getDevice();
3216     auto &alloc               = m_context.getDefaultAllocator();
3217     const auto queue          = m_context.getUniversalQueue();
3218     const auto queueIndex     = m_context.getUniversalQueueFamilyIndex();
3219 
3220     const auto fbFormat = VK_FORMAT_R8G8B8A8_UNORM;
3221     const auto fbExtent = makeExtent3D(2u, 2u, 1u);
3222     const tcu::IVec3 iExtent(static_cast<int>(fbExtent.width), static_cast<int>(fbExtent.height),
3223                              static_cast<int>(fbExtent.depth));
3224     const auto tcuFbFormat = mapVkFormat(fbFormat);
3225     const auto pixelSize   = tcu::getPixelSize(tcuFbFormat);
3226     const auto topology    = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
3227     const auto patchCPs    = 3u;
3228     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3229     const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
3230 
3231     const std::vector<VkViewport> rpViewports(1u, makeViewport(fbExtent));
3232     const std::vector<VkRect2D> rpScissors(1u, makeRect2D(fbExtent));
3233 
3234     // Color attachment.
3235     const VkImageCreateInfo colorAttCreateInfo = {
3236         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                     // VkStructureType sType;
3237         nullptr,                                                                 // const void* pNext;
3238         0u,                                                                      // VkImageCreateFlags flags;
3239         VK_IMAGE_TYPE_2D,                                                        // VkImageType imageType;
3240         fbFormat,                                                                // VkFormat format;
3241         fbExtent,                                                                // VkExtent3D extent;
3242         1u,                                                                      // uint32_t mipLevels;
3243         1u,                                                                      // uint32_t arrayLayers;
3244         VK_SAMPLE_COUNT_1_BIT,                                                   // VkSampleCountFlagBits samples;
3245         VK_IMAGE_TILING_OPTIMAL,                                                 // VkImageTiling tiling;
3246         (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), // VkImageUsageFlags usage;
3247         VK_SHARING_MODE_EXCLUSIVE,                                               // VkSharingMode sharingMode;
3248         0u,                                                                      // uint32_t queueFamilyIndexCount;
3249         nullptr,                                                                 // const uint32_t* pQueueFamilyIndices;
3250         VK_IMAGE_LAYOUT_UNDEFINED,                                               // VkImageLayout initialLayout;
3251     };
3252 
3253     ImageWithMemory colorAtt(vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any);
3254     const auto colorSRR     = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
3255     const auto colorSRL     = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
3256     const auto colorAttView = makeImageView(vkd, device, colorAtt.get(), VK_IMAGE_VIEW_TYPE_2D, fbFormat, colorSRR);
3257     RenderPassWrapper renderPass(m_constructionType, vkd, device, fbFormat);
3258     renderPass.createFramebuffer(vkd, device, colorAtt.get(), colorAttView.get(), fbExtent.width, fbExtent.height);
3259 
3260     // Verification buffer.
3261     DE_ASSERT(fbExtent.depth == 1u);
3262     const auto verifBufferSize = static_cast<VkDeviceSize>(pixelSize) * fbExtent.width * fbExtent.height;
3263     const auto verifBufferInfo = makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
3264     BufferWithMemory verifBuffer(vkd, device, alloc, verifBufferInfo, MemoryRequirement::HostVisible);
3265 
3266     // Create shader modules, obtain IDs and verify all of them differ.
3267     const auto &binaries  = m_context.getBinaryCollection();
3268     const auto vertModule = ShaderWrapper(vkd, device, binaries.get("vert"));
3269     const auto fragModule = ShaderWrapper(vkd, device, binaries.get("frag"));
3270     const auto teseModule = ShaderWrapper(vkd, device, binaries.get("tese"));
3271 
3272     std::vector<ShaderWrapper> tescModules;
3273     {
3274         size_t tescIdx = 0;
3275 
3276         for (;;)
3277         {
3278             const auto shaderName = "tesc" + std::to_string(tescIdx);
3279             if (!binaries.contains(shaderName))
3280                 break;
3281             tescModules.emplace_back(ShaderWrapper(vkd, device, binaries.get(shaderName)));
3282 
3283             ++tescIdx;
3284         }
3285     }
3286 
3287     const auto vertId = getShaderModuleIdentifier(vkd, device, vertModule.getModule());
3288     const auto fragId = getShaderModuleIdentifier(vkd, device, fragModule.getModule());
3289     const auto teseId = getShaderModuleIdentifier(vkd, device, teseModule.getModule());
3290     std::vector<ShaderModuleId> tescIds;
3291     for (const auto &mod : tescModules)
3292         tescIds.emplace_back(getShaderModuleIdentifier(vkd, device, mod.getModule()));
3293 
3294     // Verify all of them are unique.
3295     {
3296         std::vector<ShaderModuleId> allIds;
3297         allIds.emplace_back(vertId);
3298         allIds.emplace_back(fragId);
3299         allIds.emplace_back(teseId);
3300         for (const auto &id : tescIds)
3301             allIds.emplace_back(id);
3302 
3303         std::set<ShaderModuleId> uniqueIds(begin(allIds), end(allIds));
3304 
3305         if (allIds.size() != uniqueIds.size())
3306             TCU_FAIL("Not every module has a unique ID");
3307     }
3308 
3309     // Constant structures used when creating pipelines.
3310     const VkPipelineVertexInputStateCreateInfo vertexInputState     = initVulkanStructure();
3311     const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
3312         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
3313         nullptr,                                                     // const void* pNext;
3314         0u,                                                          // VkPipelineInputAssemblyStateCreateFlags flags;
3315         topology,                                                    // VkPrimitiveTopology topology;
3316         VK_FALSE,                                                    // VkBool32 primitiveRestartEnable;
3317     };
3318     const VkPipelineDepthStencilStateCreateInfo depthStencilState = initVulkanStructure();
3319     VkPipelineMultisampleStateCreateInfo multisampleState         = initVulkanStructure();
3320     multisampleState.rasterizationSamples                         = VK_SAMPLE_COUNT_1_BIT;
3321     VkPipelineColorBlendAttachmentState colorBlendAttachmentState;
3322     deMemset(&colorBlendAttachmentState, 0, sizeof(colorBlendAttachmentState));
3323     colorBlendAttachmentState.colorWriteMask =
3324         (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
3325     const VkPipelineColorBlendStateCreateInfo colorBlendState = {
3326         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, //    VkStructureType                                sType
3327         nullptr,                    //    const void*                                    pNext
3328         0u,                         //    VkPipelineColorBlendStateCreateFlags        flags
3329         VK_FALSE,                   //    VkBool32                                    logicOpEnable
3330         VK_LOGIC_OP_CLEAR,          //    VkLogicOp                                    logicOp
3331         1u,                         //    uint32_t                                    attachmentCount
3332         &colorBlendAttachmentState, //    const VkPipelineColorBlendAttachmentState*    pAttachments
3333         {0.0f, 0.0f, 0.0f, 0.0f}    //    float                                        blendConstants[4]
3334     };
3335     const auto rasterizationState = makeRasterizationState(false /*rasterizationDisabled*/);
3336 
3337     // Pipeline cache.
3338     const VkPipelineCacheCreateInfo cacheCreateInfo = initVulkanStructure();
3339     const auto pipelineCache                        = createPipelineCache(vkd, device, &cacheCreateInfo);
3340 
3341     // Empty pipeline layout.
3342     const PipelineLayoutWrapper pipelineLayout(m_constructionType, vkd, device);
3343 
3344     using GraphicsPipelineWrapperPtr = std::unique_ptr<GraphicsPipelineWrapper>;
3345 
3346     // Create temporary pipelines with them to prime the cache.
3347     {
3348         for (const auto &tescModule : tescModules)
3349         {
3350             GraphicsPipelineWrapperPtr wrapper(new GraphicsPipelineWrapper(
3351                 vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_constructionType));
3352 
3353             try
3354             {
3355                 wrapper->setDefaultPatchControlPoints(patchCPs)
3356                     .setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
3357                     .setupPreRasterizationShaderState2(rpViewports, rpScissors, pipelineLayout, renderPass.get(), 0u,
3358                                                        vertModule, &rasterizationState, tescModule, teseModule,
3359                                                        ShaderWrapper(), nullptr, nullptr, nullptr, nullptr, nullptr,
3360                                                        nullptr, pipelineCache.get())
3361                     .setupFragmentShaderState(pipelineLayout, renderPass.get(), 0u, fragModule, &depthStencilState,
3362                                               &multisampleState, nullptr, pipelineCache.get())
3363                     .setupFragmentOutputState(*renderPass, 0u, &colorBlendState, &multisampleState, pipelineCache.get())
3364                     .setMonolithicPipelineLayout(pipelineLayout)
3365                     .buildPipeline(pipelineCache.get());
3366             }
3367             catch (const PipelineCompileRequiredError &)
3368             {
3369                 TCU_FAIL("PipelineCompileRequiredError received while priming pipeline cache");
3370             }
3371         }
3372     }
3373 
3374     // Create pipelines using shader module ids. These will actually be run. Note the changing viewports and scissors.
3375     std::vector<GraphicsPipelineWrapperPtr> pipelineWrappers;
3376     std::vector<VkViewport> viewports;
3377     std::vector<VkRect2D> scissors;
3378 
3379     const auto vertIdInfo = makeShaderStageModuleIdentifierCreateInfo(vertId, UseModuleCase::ID);
3380     const auto fragIdInfo = makeShaderStageModuleIdentifierCreateInfo(fragId, UseModuleCase::ID);
3381     const auto teseIdInfo = makeShaderStageModuleIdentifierCreateInfo(teseId, UseModuleCase::ID);
3382     std::vector<ShaderStageIdPtr> tescIdInfos;
3383     for (const auto &tescId : tescIds)
3384         tescIdInfos.emplace_back(makeShaderStageModuleIdentifierCreateInfo(tescId, UseModuleCase::ID));
3385 
3386     for (size_t tescIdx = 0; tescIdx < tescModules.size(); ++tescIdx)
3387     {
3388         const auto row = tescIdx / fbExtent.width;
3389         const auto col = tescIdx % fbExtent.width;
3390 
3391         viewports.emplace_back(makeViewport(static_cast<float>(col), static_cast<float>(row), 1.0f, 1.0f, 0.0f, 1.0f));
3392         scissors.emplace_back(makeRect2D(static_cast<int32_t>(col), static_cast<int32_t>(row), 1u, 1u));
3393         pipelineWrappers.emplace_back(new GraphicsPipelineWrapper(vki, vkd, physicalDevice, device,
3394                                                                   m_context.getDeviceExtensions(), m_constructionType));
3395 
3396         const auto &wrapper = pipelineWrappers.back();
3397 
3398         try
3399         {
3400             wrapper->setDefaultPatchControlPoints(patchCPs)
3401                 .setupVertexInputState(&vertexInputState, &inputAssemblyState, pipelineCache.get())
3402                 .setupPreRasterizationShaderState3(
3403                     std::vector<VkViewport>(1u, viewports.back()), std::vector<VkRect2D>(1u, scissors.back()),
3404                     pipelineLayout, renderPass.get(), 0u, ShaderWrapper(),
3405                     PipelineShaderStageModuleIdentifierCreateInfoWrapper(vertIdInfo.get()), &rasterizationState,
3406                     ShaderWrapper(),
3407                     PipelineShaderStageModuleIdentifierCreateInfoWrapper(tescIdInfos.at(tescIdx).get()),
3408                     ShaderWrapper(), PipelineShaderStageModuleIdentifierCreateInfoWrapper(teseIdInfo.get()),
3409                     ShaderWrapper(), PipelineShaderStageModuleIdentifierCreateInfoWrapper(), nullptr, nullptr, nullptr,
3410                     nullptr, nullptr, PipelineRenderingCreateInfoWrapper(), pipelineCache.get())
3411                 .setupFragmentShaderState2(pipelineLayout, renderPass.get(), 0u, ShaderWrapper(),
3412                                            PipelineShaderStageModuleIdentifierCreateInfoWrapper(fragIdInfo.get()),
3413                                            &depthStencilState, &multisampleState, nullptr, pipelineCache.get())
3414                 .setupFragmentOutputState(*renderPass, 0u, &colorBlendState, &multisampleState, pipelineCache.get())
3415                 .setMonolithicPipelineLayout(pipelineLayout)
3416                 .buildPipeline(pipelineCache.get());
3417         }
3418         catch (const PipelineCompileRequiredError &)
3419         {
3420             return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
3421                                    "PipelineCompileRequiredError received despite using pipeline cache");
3422         }
3423     }
3424 
3425     // Use pipelines in a render pass.
3426     const auto cmdPool      = makeCommandPool(vkd, device, queueIndex);
3427     const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
3428     const auto cmdBuffer    = cmdBufferPtr.get();
3429 
3430     beginCommandBuffer(vkd, cmdBuffer);
3431     renderPass.begin(vkd, cmdBuffer, rpScissors.at(0u), clearColor);
3432     for (const auto &wrapper : pipelineWrappers)
3433     {
3434         vkd.cmdBindPipeline(cmdBuffer, bindPoint, wrapper->getPipeline());
3435         vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
3436     }
3437     renderPass.end(vkd, cmdBuffer);
3438 
3439     // Transfer color attachment to verification buffer.
3440     const auto copyRegion        = makeBufferImageCopy(fbExtent, colorSRL);
3441     const auto preHostBarrier    = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
3442     const auto postRenderBarrier = makeImageMemoryBarrier(
3443         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
3444         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorAtt.get(), colorSRR);
3445 
3446     cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
3447                                   VK_PIPELINE_STAGE_TRANSFER_BIT, &postRenderBarrier);
3448     vkd.cmdCopyImageToBuffer(cmdBuffer, colorAtt.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u,
3449                              &copyRegion);
3450     cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
3451                              &preHostBarrier);
3452 
3453     endCommandBuffer(vkd, cmdBuffer);
3454     submitCommandsAndWait(vkd, device, queue, cmdBuffer);
3455 
3456     // Verify result.
3457     {
3458         auto &log              = m_context.getTestContext().getLog();
3459         const auto outColors   = HLSLTessellationCase::getOutputColors();
3460         auto &verifBufferAlloc = verifBuffer.getAllocation();
3461         void *verifBufferData  = verifBufferAlloc.getHostPtr();
3462 
3463         invalidateAlloc(vkd, device, verifBufferAlloc);
3464 
3465         tcu::ConstPixelBufferAccess resultAccess(tcuFbFormat, iExtent, verifBufferData);
3466         tcu::TextureLevel referenceLevel(tcuFbFormat, iExtent.x(), iExtent.y());
3467         const auto referenceAccess = referenceLevel.getAccess();
3468         const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f);
3469 
3470         for (int x = 0; x < iExtent.x(); ++x)
3471             for (int y = 0; y < iExtent.y(); ++y)
3472                 referenceAccess.setPixel(outColors.at(y * iExtent.x() + x), x, y);
3473 
3474         tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
3475                                    tcu::COMPARE_LOG_EVERYTHING);
3476     }
3477 
3478     return tcu::TestStatus::pass("Pass");
3479 }
3480 
3481 } // anonymous namespace
3482 
createShaderModuleIdentifierTests(tcu::TestContext & testCtx,vk::PipelineConstructionType constructionType)3483 tcu::TestCaseGroup *createShaderModuleIdentifierTests(tcu::TestContext &testCtx,
3484                                                       vk::PipelineConstructionType constructionType)
3485 {
3486     // No pipelines are actually constructed in some of these variants, so adding them to a single group is fine.
3487     GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "shader_module_identifier"));
3488 
3489     if (constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3490     {
3491         // Test shader module identifier extension properties
3492         GroupPtr propertiesGroup(new tcu::TestCaseGroup(testCtx, "properties"));
3493 
3494         addFunctionCase(propertiesGroup.get(), "constant_algorithm_uuid", checkShaderModuleIdentifierSupport,
3495                         constantAlgorithmUUIDCase);
3496 
3497         mainGroup->addChild(propertiesGroup.release());
3498     }
3499 
3500     const struct
3501     {
3502         PipelineType pipelineType;
3503         bool useRTLibraries;
3504         const char *name;
3505     } pipelineTypeCases[] = {
3506         {PipelineType::COMPUTE, false, "compute"},
3507         {PipelineType::GRAPHICS, false, "graphics"},
3508         {PipelineType::RAY_TRACING, false, "ray_tracing"},
3509         {PipelineType::RAY_TRACING, true, "ray_tracing_libs"},
3510     };
3511 
3512     const uint8_t pipelineCountCases[] = {uint8_t{1}, uint8_t{4}};
3513 
3514     const std::vector<GraphicsShaderVec> graphicsShadersCases{
3515         {GraphicsShaderType::VERTEX},
3516         {GraphicsShaderType::VERTEX, GraphicsShaderType::FRAG},
3517         {GraphicsShaderType::VERTEX, GraphicsShaderType::TESS_CONTROL, GraphicsShaderType::TESS_EVAL,
3518          GraphicsShaderType::FRAG},
3519         {GraphicsShaderType::VERTEX, GraphicsShaderType::GEOMETRY, GraphicsShaderType::FRAG},
3520         {GraphicsShaderType::VERTEX, GraphicsShaderType::TESS_CONTROL, GraphicsShaderType::TESS_EVAL,
3521          GraphicsShaderType::GEOMETRY, GraphicsShaderType::FRAG},
3522     };
3523 
3524     const std::vector<RTShaderVec> rtShadersCases{
3525         {RayTracingShaderType::RAY_GEN, RayTracingShaderType::MISS},
3526         {RayTracingShaderType::RAY_GEN, RayTracingShaderType::CLOSEST_HIT, RayTracingShaderType::MISS},
3527         {RayTracingShaderType::RAY_GEN, RayTracingShaderType::ANY_HIT, RayTracingShaderType::CLOSEST_HIT,
3528          RayTracingShaderType::MISS},
3529         {RayTracingShaderType::RAY_GEN, RayTracingShaderType::INTERSECTION, RayTracingShaderType::ANY_HIT,
3530          RayTracingShaderType::CLOSEST_HIT, RayTracingShaderType::MISS},
3531         {RayTracingShaderType::RAY_GEN, RayTracingShaderType::CALLABLE},
3532     };
3533 
3534     const struct
3535     {
3536         bool useSCs;
3537         const char *name;
3538     } useSCCases[] = {
3539         {false, "no_spec_constants"},
3540         {true, "use_spec_constants"},
3541     };
3542 
3543     // Tests checking the identifiers are constant.
3544     if (constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3545     {
3546         // Test shader modules have constant and unique identifiers
3547         GroupPtr constantIdsGroup(new tcu::TestCaseGroup(testCtx, "constant_identifiers"));
3548 
3549         const struct
3550         {
3551             ConstantModuleIdentifiersInstance::APICall apiCall;
3552             const char *name;
3553         } apiCallCases[] = {
3554             {ConstantModuleIdentifiersInstance::APICall::MODULE, "module_id"},
3555             {ConstantModuleIdentifiersInstance::APICall::CREATE_INFO, "create_info_id"},
3556             {ConstantModuleIdentifiersInstance::APICall::BOTH, "both_ids"},
3557         };
3558 
3559         const struct
3560         {
3561             bool differentDevice;
3562             const char *name;
3563         } differentDeviceCases[] = {
3564             {false, "same_device"},
3565             {true, "different_devices"},
3566         };
3567 
3568         for (const auto &pipelineTypeCase : pipelineTypeCases)
3569         {
3570             // Skip this case for constant module identifiers.
3571             if (pipelineTypeCase.useRTLibraries)
3572                 continue;
3573 
3574             GroupPtr pipelineTypeGroup(new tcu::TestCaseGroup(testCtx, pipelineTypeCase.name));
3575 
3576             for (const auto &pipelineCountCase : pipelineCountCases)
3577             {
3578                 const auto countGroupName = std::to_string(static_cast<int>(pipelineCountCase)) + "_variants";
3579 
3580                 GroupPtr pipelineCountGroup(new tcu::TestCaseGroup(testCtx, countGroupName.c_str()));
3581 
3582                 for (const auto &useSCCase : useSCCases)
3583                 {
3584                     GroupPtr useSCGroup(new tcu::TestCaseGroup(testCtx, useSCCase.name));
3585 
3586                     for (const auto &apiCallCase : apiCallCases)
3587                     {
3588                         GroupPtr apiCallGroup(new tcu::TestCaseGroup(testCtx, apiCallCase.name));
3589 
3590                         for (const auto &differentDeviceCase : differentDeviceCases)
3591                         {
3592                             GroupPtr differentDeviceGroup(new tcu::TestCaseGroup(testCtx, differentDeviceCase.name));
3593 
3594                             using Params = ConstantModuleIdentifiersInstance::Params;
3595 
3596                             Params commonParams(pipelineTypeCase.pipelineType, {}, {}, pipelineCountCase, tcu::Nothing,
3597                                                 useSCCase.useSCs, false, apiCallCase.apiCall,
3598                                                 differentDeviceCase.differentDevice);
3599 
3600                             if (pipelineTypeCase.pipelineType == PipelineType::GRAPHICS)
3601                             {
3602                                 for (const auto &graphicsShadersCase : graphicsShadersCases)
3603                                 {
3604                                     std::unique_ptr<Params> params(new Params(commonParams));
3605                                     params->graphicsShaders = graphicsShadersCase;
3606                                     differentDeviceGroup->addChild(new ConstantModuleIdentifiersCase(
3607                                         testCtx, toString(graphicsShadersCase), std::move(params)));
3608                                 }
3609                             }
3610                             else if (pipelineTypeCase.pipelineType == PipelineType::RAY_TRACING)
3611                             {
3612                                 for (const auto &rtShadersCase : rtShadersCases)
3613                                 {
3614                                     std::unique_ptr<Params> params(new Params(commonParams));
3615                                     params->rtShaders = rtShadersCase;
3616                                     differentDeviceGroup->addChild(new ConstantModuleIdentifiersCase(
3617                                         testCtx, toString(rtShadersCase), std::move(params)));
3618                                 }
3619                             }
3620                             else // Compute
3621                             {
3622                                 std::unique_ptr<Params> params(new Params(commonParams));
3623                                 differentDeviceGroup->addChild(
3624                                     new ConstantModuleIdentifiersCase(testCtx, "comp", std::move(params)));
3625                             }
3626 
3627                             apiCallGroup->addChild(differentDeviceGroup.release());
3628                         }
3629 
3630                         useSCGroup->addChild(apiCallGroup.release());
3631                     }
3632 
3633                     pipelineCountGroup->addChild(useSCGroup.release());
3634                 }
3635 
3636                 pipelineTypeGroup->addChild(pipelineCountGroup.release());
3637             }
3638 
3639             constantIdsGroup->addChild(pipelineTypeGroup.release());
3640         }
3641 
3642         mainGroup->addChild(constantIdsGroup.release());
3643     }
3644 
3645     // Tests creating pipelines using the module id extension structures.
3646     {
3647         const struct
3648         {
3649             bool useVkPipelineCache;
3650             const char *name;
3651         } pipelineCacheCases[] = {
3652             {false, "no_pipeline_cache"},
3653             {true, "use_pipeline_cache"},
3654         };
3655 
3656         const struct
3657         {
3658             UseModuleCase moduleUse;
3659             const char *name;
3660         } moduleUsageCases[] = {
3661             {UseModuleCase::ID, "use_id"},
3662             {UseModuleCase::ZERO_LEN_ID, "zero_len_id"},
3663             {UseModuleCase::ZERO_LEN_ID_NULL_PTR, "zero_len_id_null_ptr"},
3664             {UseModuleCase::ZERO_LEN_ID_GARBAGE_PTR, "zero_len_id_garbage_ptr"},
3665             {UseModuleCase::ALL_ZEROS, "all_zeros_id"},
3666             {UseModuleCase::ALL_ONES, "all_ones_id"},
3667             {UseModuleCase::PSEUDORANDOM_ID, "pseudorandom_id"},
3668         };
3669 
3670         const struct
3671         {
3672             CapturedPropertiesBits capturedProperties;
3673             const char *name;
3674         } capturingCases[] = {
3675             {CapturedPropertiesBits::NONE, "no_exec_properties"},
3676             {CapturedPropertiesBits::STATS, "capture_stats"},
3677             {CapturedPropertiesBits::IRS, "capture_irs"},
3678         };
3679 
3680         uint32_t rndSeed = 1651848014u;
3681 
3682         // Test creating and using pipelines from shader module identifiers
3683         GroupPtr pipelineFromIdsGroup(new tcu::TestCaseGroup(testCtx, "pipeline_from_id"));
3684 
3685         for (const auto &pipelineTypeCase : pipelineTypeCases)
3686         {
3687             if (pipelineTypeCase.pipelineType != PipelineType::GRAPHICS &&
3688                 constructionType != PipelineConstructionType::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3689                 continue;
3690 
3691             GroupPtr pipelineTypeGroup(new tcu::TestCaseGroup(testCtx, pipelineTypeCase.name));
3692 
3693             for (const auto &pipelineCountCase : pipelineCountCases)
3694             {
3695                 const auto countGroupName = std::to_string(static_cast<int>(pipelineCountCase)) + "_variants";
3696 
3697                 GroupPtr pipelineCountGroup(new tcu::TestCaseGroup(testCtx, countGroupName.c_str()));
3698 
3699                 for (const auto &useSCCase : useSCCases)
3700                 {
3701                     GroupPtr useSCGroup(new tcu::TestCaseGroup(testCtx, useSCCase.name));
3702 
3703                     for (const auto &pipelineCacheCase : pipelineCacheCases)
3704                     {
3705                         GroupPtr pipelineCacheGroup(new tcu::TestCaseGroup(testCtx, pipelineCacheCase.name));
3706 
3707                         for (const auto &moduleUsageCase : moduleUsageCases)
3708                         {
3709                             GroupPtr moduleUsageGroup(new tcu::TestCaseGroup(testCtx, moduleUsageCase.name));
3710 
3711                             for (const auto &capturingCase : capturingCases)
3712                             {
3713                                 // We are only going to attempt to capture properties in a specific subset of the tests.
3714                                 if (capturingCase.capturedProperties != CapturedPropertiesBits::NONE &&
3715                                     (pipelineCountCase > 1u || moduleUsageCase.moduleUse != UseModuleCase::ID))
3716                                     continue;
3717 
3718                                 GroupPtr captureGroup(new tcu::TestCaseGroup(testCtx, capturingCase.name));
3719 
3720                                 DE_ASSERT(pipelineCountCase > 0u);
3721                                 const uint8_t pipelineToRun =
3722                                     (pipelineCountCase == 1u ? uint8_t{0} :
3723                                                                static_cast<uint8_t>(pipelineCountCase - 2u));
3724 
3725                                 CreateAndUseIdsInstance::Params baseParams(
3726                                     pipelineTypeCase.pipelineType, {}, {}, pipelineCountCase, tcu::just(pipelineToRun),
3727                                     useSCCase.useSCs, pipelineCacheCase.useVkPipelineCache, false, constructionType,
3728                                     pipelineTypeCase.useRTLibraries, moduleUsageCase.moduleUse,
3729                                     static_cast<CapturedPropertiesFlags>(capturingCase.capturedProperties));
3730 
3731                                 if (pipelineTypeCase.pipelineType == PipelineType::GRAPHICS)
3732                                 {
3733                                     for (const auto &graphicsShadersCase : graphicsShadersCases)
3734                                     {
3735                                         BaseParamsPtr params    = baseParams.copy(rndSeed++);
3736                                         params->graphicsShaders = graphicsShadersCase;
3737                                         captureGroup->addChild(new CreateAndUseIdsCase(
3738                                             testCtx, toString(graphicsShadersCase), std::move(params)));
3739                                     }
3740                                 }
3741                                 else if (pipelineTypeCase.pipelineType == PipelineType::RAY_TRACING)
3742                                 {
3743                                     for (const auto &rtShadersCase : rtShadersCases)
3744                                     {
3745                                         BaseParamsPtr params = baseParams.copy(rndSeed++);
3746                                         params->rtShaders    = rtShadersCase;
3747                                         captureGroup->addChild(new CreateAndUseIdsCase(testCtx, toString(rtShadersCase),
3748                                                                                        std::move(params)));
3749                                     }
3750                                 }
3751                                 else // Compute
3752                                 {
3753                                     BaseParamsPtr params = baseParams.copy(rndSeed++);
3754                                     captureGroup->addChild(new CreateAndUseIdsCase(testCtx, "comp", std::move(params)));
3755                                 }
3756 
3757                                 moduleUsageGroup->addChild(captureGroup.release());
3758                             }
3759 
3760                             pipelineCacheGroup->addChild(moduleUsageGroup.release());
3761                         }
3762 
3763                         useSCGroup->addChild(pipelineCacheGroup.release());
3764                     }
3765 
3766                     pipelineCountGroup->addChild(useSCGroup.release());
3767                 }
3768 
3769                 pipelineTypeGroup->addChild(pipelineCountGroup.release());
3770             }
3771 
3772             pipelineFromIdsGroup->addChild(pipelineTypeGroup.release());
3773         }
3774 
3775         mainGroup->addChild(pipelineFromIdsGroup.release());
3776     }
3777 
3778     // Tests checking HLSL tessellation shaders with module identifiers
3779     {
3780         GroupPtr hlslTessGroup(new tcu::TestCaseGroup(testCtx, "hlsl_tessellation"));
3781         hlslTessGroup->addChild(new HLSLTessellationCase(testCtx, "test", constructionType));
3782         mainGroup->addChild(hlslTessGroup.release());
3783     }
3784 
3785     // misc tests
3786     if (constructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
3787     {
3788         const uint8_t pipelineToRun = 0u;
3789         CreateAndUseIdsInstance::Params baseParams(PipelineType::GRAPHICS, {}, {}, uint8_t{1u},
3790                                                    tcu::just(uint8_t{pipelineToRun}), false, false, true,
3791                                                    constructionType, false, UseModuleCase::ID,
3792                                                    static_cast<CapturedPropertiesFlags>(CapturedPropertiesBits::STATS));
3793         baseParams.graphicsShaders = graphicsShadersCases[1];
3794 
3795         GroupPtr miscGroup(new tcu::TestCaseGroup(testCtx, "misc"));
3796 
3797         BaseParamsPtr params = baseParams.copy(1);
3798         miscGroup->addChild(new CreateAndUseIdsCase(testCtx, "capture_statistics_maintenance5", std::move(params)));
3799 
3800         baseParams.capturedProperties = static_cast<CapturedPropertiesFlags>(CapturedPropertiesBits::IRS);
3801         params                        = baseParams.copy(2);
3802         miscGroup->addChild(
3803             new CreateAndUseIdsCase(testCtx, "capture_internal_representations_maintenance5", std::move(params)));
3804 
3805         mainGroup->addChild(miscGroup.release());
3806     }
3807 
3808     return mainGroup.release();
3809 }
3810 
3811 } // namespace pipeline
3812 } // namespace vkt
3813