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