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