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