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