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