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