1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Ray Tracing Pipeline Flags tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayTracingPipelineFlagsTests.hpp"
25 
26 #include "vkDefs.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkBarrierUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkRayTracingUtil.hpp"
39 #include "tcuCommandLine.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuStringTemplate.hpp"
42 
43 #include <algorithm>
44 #include <array>
45 #include <cmath>
46 #include <functional>
47 #include <iterator>
48 #include <memory>
49 #include <set>
50 #include <tuple>
51 
52 #ifdef INTERNAL_DEBUG
53 #include <iostream>
54 #endif
55 
56 #define ALL_RAY_TRACING_STAGES                                                                                \
57     (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | \
58      VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR)
59 namespace vkt
60 {
61 namespace RayTracing
62 {
63 namespace
64 {
65 using namespace vk;
66 using namespace vkt;
67 
68 #define ALIGN_STD430(type_) alignas(sizeof(type_)) type_
69 
70 #define INRANGE(x_, a_, b_) (((x_) >= (a_) && (x_) <= (b_)) || ((x_) >= (b_) && (x_) <= (a_)))
71 
72 enum class GeometryTypes : uint32_t
73 {
74     None           = 0x0,
75     Triangle       = 0x1,
76     Box            = 0x2,
77     TriangleAndBox = Triangle | Box
78 };
79 
80 struct TestParams
81 {
82     uint32_t width;
83     uint32_t height;
84     VkBool32 onHhost;
85     VkPipelineCreateFlags flags;
86     bool useLibs;
87     bool useMaintenance5;
88     uint32_t instCount;
89     GeometryTypes geomTypes;
90     uint32_t geomCount;
91     uint32_t stbRecStride;
92     uint32_t stbRecOffset;
93     float accuracy;
94 #define ENABLED(val_, mask_) (((val_) & (mask_)) == (mask_))
missvkt::RayTracing::__anon99cb10d60111::TestParams95     bool miss() const
96     {
97         return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR);
98     }
ahitvkt::RayTracing::__anon99cb10d60111::TestParams99     bool ahit() const
100     {
101         return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR);
102     }
chitvkt::RayTracing::__anon99cb10d60111::TestParams103     bool chit() const
104     {
105         return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR);
106     }
isectvkt::RayTracing::__anon99cb10d60111::TestParams107     bool isect() const
108     {
109         return ENABLED(flags, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR);
110     }
111 };
112 
rotateCcwZ(const tcu::Vec3 & p,const tcu::Vec3 & center,const float & radians)113 tcu::Vec3 rotateCcwZ(const tcu::Vec3 &p, const tcu::Vec3 &center, const float &radians)
114 {
115     const float s = std::sin(radians);
116     const float c = std::cos(radians);
117     const auto t  = p - center;
118     return tcu::Vec3(c * t.x() - s * t.y(), s * t.x() + c * t.y(), t.z()) + center;
119 }
120 
pointInRect2D(const tcu::Vec3 & p,const tcu::Vec3 & p0,const tcu::Vec3 & p1)121 bool pointInRect2D(const tcu::Vec3 &p, const tcu::Vec3 &p0, const tcu::Vec3 &p1)
122 {
123     return INRANGE(p.x(), p0.x(), p1.x()) && INRANGE(p.y(), p0.y(), p1.y());
124 }
125 
computeEffectiveShaderGroupCount(const TestParams & p)126 uint32_t computeEffectiveShaderGroupCount(const TestParams &p)
127 {
128     DE_ASSERT(p.instCount && p.geomCount);
129     return (p.geomCount * p.stbRecStride + p.stbRecOffset + 1);
130 }
131 
132 class RayTracingTestPipeline;
133 
134 class PipelineFlagsCase : public TestCase
135 {
136 public:
137     PipelineFlagsCase(tcu::TestContext &testCtx, const std::string &name, const TestParams &testParams);
138     virtual ~PipelineFlagsCase(void) = default;
139     virtual void initPrograms(SourceCollections &programCollection) const override;
140     virtual TestInstance *createInstance(Context &context) const override;
141     virtual void checkSupport(Context &context) const override;
142 
143     const uint32_t &shaderGroupHandleSize;
144     const uint32_t &shaderGroupBaseAlignment;
145 
146 private:
147     const TestParams m_params;
148 
149     const tcu::IVec4 m_rgenPayload;
150     const int32_t m_defMissRetGreenComp;
151     const int32_t m_defTriRetGreenComp;
152     const int32_t m_defBoxRetGreenComp;
153     static int32_t calcDefBoxRetGreenComp(const TestParams &params, int32_t defTriRetGreenComp);
154 
155     static uint32_t m_shaderGroupHandleSize;
156     static uint32_t m_shaderGroupBaseAlignment;
157 };
158 
calcDefBoxRetGreenComp(const TestParams & params,int32_t defTriRetGreenComp)159 int32_t PipelineFlagsCase::calcDefBoxRetGreenComp(const TestParams &params, int32_t defTriRetGreenComp)
160 {
161     const uint32_t nameCount = params.stbRecStride ? (params.geomCount * params.instCount) : params.instCount;
162     const uint32_t triangleCount =
163         (params.geomTypes == GeometryTypes::Triangle || params.geomTypes == GeometryTypes::TriangleAndBox) ? nameCount :
164                                                                                                              0u;
165     return defTriRetGreenComp + std::max(triangleCount, 32u);
166 }
167 uint32_t PipelineFlagsCase::m_shaderGroupHandleSize;
168 uint32_t PipelineFlagsCase::m_shaderGroupBaseAlignment;
169 
170 class PipelineFlagsInstance : public TestInstance
171 {
172     using TopLevelASPtr     = de::SharedPtr<TopLevelAccelerationStructure>;
173     using BottomLevelASPtr  = de::SharedPtr<BottomLevelAccelerationStructure>;
174     using BottomLevelASPtrs = std::vector<BottomLevelASPtr>;
175     using TriGeometry       = std::array<tcu::Vec3, 3>;
176     using BoxGeometry       = std::array<tcu::Vec3, 2>;
177 
178     friend class RayTracingTestPipeline;
179 
180 public:
181     PipelineFlagsInstance(Context &context, const TestParams &params, const uint32_t &shaderGroupHandleSize_,
182                           const uint32_t &shaderGroupBaseAlignment_, const tcu::IVec4 &rgenPayload_,
183                           int32_t defMissRetGreenComp_, int32_t defTriRetGreenComp_, int32_t defBoxRetGreenComp_);
184     virtual ~PipelineFlagsInstance(void) = default;
185 
186     struct ShaderRecordEXT
187     {
188         ALIGN_STD430(GeometryTypes) geomType;
189         ALIGN_STD430(uint32_t) geomIndex;
190         ALIGN_STD430(tcu::IVec4) retValue;
191 
192         ShaderRecordEXT();
193         ShaderRecordEXT(GeometryTypes type, uint32_t index, const tcu::IVec4 &ret);
194     };
195 
196     virtual tcu::TestStatus iterate(void) override;
197 
198     const tcu::IVec4 rgenPayload;
199     const int32_t defMissRetGreenComp;
200     const int32_t defTriRetGreenComp;
201     const int32_t defBoxRetGreenComp;
202 
203     const uint32_t shaderGroupHandleSize;
204     const uint32_t shaderGroupBaseAlignment;
205 
206 private:
207     struct HitGroup;
208     using ShaderRecordEntry = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool /* initalized */>;
209 
210     VkImageCreateInfo makeImageCreateInfo() const;
211     std::vector<TriGeometry> prepareTriGeometries(const float zCoord) const;
212     std::vector<BoxGeometry> prepareBoxGeometries(const float zFront, const float zBack) const;
213     std::vector<ShaderRecordEntry> prepareShaderBindingTable(void) const;
214     BottomLevelASPtrs createBottomLevelAccelerationStructs(VkCommandBuffer cmdBuffer) const;
215     TopLevelASPtr createTopLevelAccelerationStruct(VkCommandBuffer cmdBuffer, const BottomLevelASPtrs &blasPtrs) const;
216     bool verifyResult(const BufferWithMemory *resultBuffer) const;
217 #ifdef INTERNAL_DEBUG
218     void printImage(const tcu::IVec4 *image) const;
219 #endif
220 
221     template <class rayPayloadEXT, class shaderRecordEXT>
222     struct Shader
223     {
~Shadervkt::RayTracing::__anon99cb10d60111::PipelineFlagsInstance::Shader224         virtual ~Shader()
225         {
226         }
227 
ignoreIntersectionvkt::RayTracing::__anon99cb10d60111::PipelineFlagsInstance::Shader228         virtual bool ignoreIntersection(const rayPayloadEXT &, const shaderRecordEXT &) const
229         {
230             return false;
231         }
232         virtual rayPayloadEXT invoke(const rayPayloadEXT &, const shaderRecordEXT &) const = 0;
233     };
234     struct ShaderBase : Shader<tcu::IVec4, ShaderRecordEXT>
235     {
236         typedef tcu::IVec4 rayPayloadEXT;
237         typedef ShaderRecordEXT shaderRecordEXT;
238         static const rayPayloadEXT dummyPayload;
invokevkt::RayTracing::__anon99cb10d60111::PipelineFlagsInstance::ShaderBase239         virtual rayPayloadEXT invoke(const rayPayloadEXT &, const shaderRecordEXT &) const override
240         {
241             return rayPayloadEXT();
242         }
243     };
244     struct ClosestHitShader : ShaderBase
245     {
invokevkt::RayTracing::__anon99cb10d60111::PipelineFlagsInstance::ClosestHitShader246         virtual rayPayloadEXT invoke(const rayPayloadEXT &hitAttr, const shaderRecordEXT &rec) const override
247         {
248             return (rec.geomType == GeometryTypes::Triangle) ? rec.retValue : hitAttr;
249         }
250     };
251     struct AnyHitShader : ShaderBase
252     {
ignoreIntersectionvkt::RayTracing::__anon99cb10d60111::PipelineFlagsInstance::AnyHitShader253         virtual bool ignoreIntersection(const rayPayloadEXT &, const shaderRecordEXT &rec) const override
254         {
255             return (rec.geomIndex % 2 == 1);
256         }
257     };
258     struct IntersectionShader : ShaderBase
259     {
invokevkt::RayTracing::__anon99cb10d60111::PipelineFlagsInstance::IntersectionShader260         virtual rayPayloadEXT invoke(const rayPayloadEXT &, const shaderRecordEXT &rec) const override
261         {
262             return (rec.retValue + tcu::IVec4(0, 2, 3, 4));
263         }
264     };
265     struct MissShader : ShaderBase
266     {
invokevkt::RayTracing::__anon99cb10d60111::PipelineFlagsInstance::MissShader267         virtual rayPayloadEXT invoke(const rayPayloadEXT &, const shaderRecordEXT &rec) const override
268         {
269             return rec.retValue;
270         }
271     };
272     struct HitGroup
273     {
274         de::SharedPtr<AnyHitShader> ahit;
275         de::SharedPtr<ClosestHitShader> chit;
276         de::SharedPtr<IntersectionShader> isect;
277     };
278 
279     tcu::IVec2 rayToImage(const tcu::Vec2 &rayCoords) const;
280     tcu::Vec2 imageToRay(const tcu::IVec2 &imageCoords) const;
281     uint32_t computeSamePixelCount(const std::vector<tcu::IVec4> &image, const tcu::Vec2 pixelCoords,
282                                    const tcu::IVec4 &requiredColor, const tcu::IVec4 &floodColor,
283                                    const std::function<bool(const tcu::Vec3 &)> &pointInGeometry,
284                                    std::vector<std::pair<tcu::IVec4, tcu::IVec2>> &auxBuffer) const;
285     void travelRay(std::vector<tcu::IVec4> &outImage, const uint32_t glLaunchIdExtX, const uint32_t glLaunchIdExtY,
286                    const std::vector<ShaderRecordEntry> &shaderBindingTable, const MissShader &missShader,
287                    const std::vector<TriGeometry> &triangleGeometries,
288                    const std::vector<BoxGeometry> &boxGeometries) const;
289     const TestParams m_params;
290     const VkFormat m_format;
291 };
292 PipelineFlagsInstance::ShaderBase::rayPayloadEXT const PipelineFlagsInstance::ShaderBase::dummyPayload{};
293 
ShaderRecordEXT()294 PipelineFlagsInstance::ShaderRecordEXT::ShaderRecordEXT() : geomType(GeometryTypes::None), geomIndex(~0u), retValue()
295 {
296 }
297 
ShaderRecordEXT(GeometryTypes type,uint32_t index,const tcu::IVec4 & ret)298 PipelineFlagsInstance::ShaderRecordEXT::ShaderRecordEXT(GeometryTypes type, uint32_t index, const tcu::IVec4 &ret)
299     : geomType(type)
300     , geomIndex(index)
301     , retValue(ret)
302 {
303 }
304 
305 class RayTracingTestPipeline : protected RayTracingPipeline
306 {
307 public:
RayTracingTestPipeline(Context & context,const PipelineFlagsInstance & testInstance,const TestParams & params)308     RayTracingTestPipeline(Context &context, const PipelineFlagsInstance &testInstance, const TestParams &params)
309         : m_context(context)
310         , m_vkd(context.getDeviceInterface())
311         , m_device(context.getDevice())
312         , m_allocator(context.getDefaultAllocator())
313         , m_testInstance(testInstance)
314         , m_params(params)
315     {
316         m_rgenModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("rgen"), 0);
317 
318         // miss shader is loaded into each test regardless m_params.miss() is set
319         m_missModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("miss"), 0);
320 
321         // cloest hit shader is loaded into each test regardless m_params.chit() is set
322         m_chitModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("chit"), 0);
323 
324         if (m_params.ahit())
325             m_ahitModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("ahit"), 0);
326 
327         if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) ||
328             (m_params.geomTypes == GeometryTypes::TriangleAndBox))
329             m_isectModule = createShaderModule(m_vkd, m_device, m_context.getBinaryCollection().get("isect"), 0);
330 
331         setCreateFlags(m_params.flags);
332         if (m_params.useMaintenance5)
333             setCreateFlags2(translateCreateFlag(m_params.flags));
334 
335         setMaxPayloadSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
336         setMaxAttributeSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
337     }
338 
339     template <class ShaderRecord>
340     struct SBT
341     {
342         static const uint32_t recordSize = static_cast<uint32_t>(sizeof(ShaderRecord));
343 
344         const DeviceInterface &m_vkd;
345         const VkDevice m_dev;
346         const VkPipeline m_pipeline;
347         const uint32_t m_groupCount;
348         const uint32_t m_handleSize;
349         const uint32_t m_alignment;
350         de::MovePtr<BufferWithMemory> m_buffer;
351         uint8_t *m_content;
352 
SBTvkt::RayTracing::__anon99cb10d60111::RayTracingTestPipeline::SBT353         SBT(const DeviceInterface &vkd, VkDevice dev, Allocator &allocator, VkPipeline pipeline, uint32_t groupCount,
354             uint32_t shaderGroupHandleSize, uint32_t shaderGroupBaseAlignment)
355             : m_vkd(vkd)
356             , m_dev(dev)
357             , m_pipeline(pipeline)
358             , m_groupCount(groupCount)
359             , m_handleSize(shaderGroupHandleSize)
360             , m_alignment(deAlign32(shaderGroupHandleSize + recordSize, shaderGroupBaseAlignment))
361             , m_buffer()
362             , m_content()
363         {
364             const uint32_t size            = groupCount * m_alignment;
365             const VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_DST_BIT |
366                                              VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR |
367                                              VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
368             VkBufferCreateInfo info = makeBufferCreateInfo(size, flags);
369             const MemoryRequirement memReq =
370                 MemoryRequirement::HostVisible | MemoryRequirement::Coherent | MemoryRequirement::DeviceAddress;
371             m_buffer  = de::MovePtr<BufferWithMemory>(new BufferWithMemory(m_vkd, m_dev, allocator, info, memReq));
372             m_content = (uint8_t *)m_buffer->getAllocation().getHostPtr();
373         }
374 
updateAtvkt::RayTracing::__anon99cb10d60111::RayTracingTestPipeline::SBT375         void updateAt(uint32_t index, const uint8_t *handle, const ShaderRecord &rec)
376         {
377             DE_ASSERT(index < m_groupCount);
378             uint8_t *groupPos = m_content + index * m_alignment;
379             deMemcpy(groupPos, handle, m_handleSize);
380             deMemcpy(groupPos + m_handleSize, &rec, recordSize);
381         }
382 
flushvkt::RayTracing::__anon99cb10d60111::RayTracingTestPipeline::SBT383         void flush()
384         {
385             Allocation &alloc = m_buffer->getAllocation();
386             flushMappedMemoryRange(m_vkd, m_dev, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
387         }
388 
getAlignmentvkt::RayTracing::__anon99cb10d60111::RayTracingTestPipeline::SBT389         uint32_t getAlignment() const
390         {
391             return m_alignment;
392         }
393 
getvkt::RayTracing::__anon99cb10d60111::RayTracingTestPipeline::SBT394         de::MovePtr<BufferWithMemory> get()
395         {
396             return m_buffer;
397         }
398     };
399 
400     struct PLDeleter
401     {
402         const RayTracingTestPipeline *pipeline;
403         std::function<void(RayTracingPipeline *)> whenDestroying;
PLDeletervkt::RayTracing::__anon99cb10d60111::RayTracingTestPipeline::PLDeleter404         PLDeleter(RayTracingTestPipeline *pl, std::function<void(RayTracingPipeline *)> doWhenDestroying)
405             : pipeline(pl)
406             , whenDestroying(doWhenDestroying)
407         {
408         }
operator ()vkt::RayTracing::__anon99cb10d60111::RayTracingTestPipeline::PLDeleter409         void operator()(RayTracingPipeline *pl)
410         {
411             if (pipeline != pl && pipeline->m_params.useLibs)
412             {
413                 if (whenDestroying)
414                     whenDestroying(pl);
415                 delete pl;
416             }
417         }
418     };
419 
createLibraryPipeline(std::function<void (RayTracingPipeline *)> doWhenDestroying)420     auto createLibraryPipeline(std::function<void(RayTracingPipeline *)> doWhenDestroying)
421         -> de::UniquePtr<RayTracingPipeline, PLDeleter>
422     {
423         RayTracingPipeline *pl = this;
424         if (m_params.useLibs)
425         {
426             pl = new RayTracingPipeline;
427             pl->setCreateFlags(m_params.flags | VK_PIPELINE_CREATE_LIBRARY_BIT_KHR);
428             pl->setMaxPayloadSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
429             pl->setMaxAttributeSize(sizeof(PipelineFlagsInstance::ShaderRecordEXT::retValue));
430         }
431         return de::UniquePtr<RayTracingPipeline, PLDeleter>(pl, PLDeleter(this, doWhenDestroying));
432     }
433 
createPipeline(const VkPipelineLayout pipelineLayout)434     Move<VkPipeline> createPipeline(const VkPipelineLayout pipelineLayout)
435     {
436         uint32_t groupIndex = 0;
437         const bool checkIsect =
438             (m_params.geomTypes == GeometryTypes::Box) || (m_params.geomTypes == GeometryTypes::TriangleAndBox);
439 
440         auto appendPipelineLibrary = [this, &pipelineLayout](RayTracingPipeline *pl) -> void
441         { m_libraries.emplace_back(makeVkSharedPtr(pl->createPipeline(m_vkd, m_device, pipelineLayout))); };
442 
443         DE_ASSERT((VkShaderModule(0) != *m_rgenModule));
444         DE_ASSERT((VkShaderModule(0) != *m_missModule));
445         DE_ASSERT(m_params.ahit() == (VkShaderModule(0) != *m_ahitModule));
446         DE_ASSERT((VkShaderModule(0) != *m_chitModule));
447         DE_ASSERT(checkIsect == (VkShaderModule(0) != *m_isectModule));
448 
449         // rgen in the main pipeline only
450         addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, *m_rgenModule, groupIndex++);
451 
452         createLibraryPipeline(appendPipelineLibrary)
453             ->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, *m_missModule, (m_params.useLibs ? 0 : groupIndex++));
454 
455         {
456             const uint32_t hitGroupIndex = m_params.useLibs ? 0 : groupIndex;
457             auto pipeline                = createLibraryPipeline(appendPipelineLibrary);
458             if (m_params.ahit())
459                 pipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, *m_ahitModule, hitGroupIndex);
460             pipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, *m_chitModule, hitGroupIndex);
461             if (checkIsect)
462                 pipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, *m_isectModule, hitGroupIndex);
463         }
464 
465         for (const auto &sg : m_shadersGroupCreateInfos)
466         {
467             static_cast<void>(sg);
468             DE_ASSERT(sg.type != VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR);
469         }
470 
471         return RayTracingPipeline::createPipeline(m_vkd, m_device, pipelineLayout, m_libraries);
472     }
473 
createRaygenShaderBindingTable(VkPipeline pipeline)474     std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR> createRaygenShaderBindingTable(
475         VkPipeline pipeline)
476     {
477         de::MovePtr<BufferWithMemory> sbt =
478             createShaderBindingTable(m_vkd, m_device, pipeline, m_allocator, m_testInstance.shaderGroupHandleSize,
479                                      m_testInstance.shaderGroupBaseAlignment, 0, 1);
480         VkStridedDeviceAddressRegionKHR rgn = makeStridedDeviceAddressRegionKHR(
481             getBufferDeviceAddress(m_vkd, m_device, **sbt, 0), m_testInstance.shaderGroupHandleSize,
482             m_testInstance.shaderGroupHandleSize);
483         return {de::SharedPtr<BufferWithMemory>(sbt.release()), rgn};
484     }
485 
createMissShaderBindingTable(VkPipeline pipeline)486     std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR> createMissShaderBindingTable(
487         VkPipeline pipeline)
488     {
489         const auto entries = m_testInstance.prepareShaderBindingTable();
490         const void *shaderRecPtr =
491             static_cast<PipelineFlagsInstance::ShaderRecordEXT const *>(&std::get<2>(entries[1]));
492         const uint32_t shaderRecSize = static_cast<uint32_t>(sizeof(PipelineFlagsInstance::ShaderRecordEXT));
493         const uint32_t alignment =
494             deAlign32(m_testInstance.shaderGroupHandleSize + shaderRecSize, m_testInstance.shaderGroupBaseAlignment);
495         const uint32_t sbtOffset = 0;
496 
497         de::MovePtr<BufferWithMemory> sbt = createShaderBindingTable(
498             m_vkd, m_device, pipeline, m_allocator, m_testInstance.shaderGroupHandleSize,
499             m_testInstance.shaderGroupBaseAlignment, 1, 1, VkBufferCreateFlags(0u), VkBufferUsageFlags(0u),
500             MemoryRequirement::Any, VkDeviceAddress(0), sbtOffset, shaderRecSize, &shaderRecPtr);
501 
502         VkStridedDeviceAddressRegionKHR rgn = makeStridedDeviceAddressRegionKHR(
503             getBufferDeviceAddress(m_vkd, m_device, **sbt, 0), alignment, m_testInstance.shaderGroupHandleSize);
504         return {de::SharedPtr<BufferWithMemory>(sbt.release()), rgn};
505     }
506 
createHitShaderBindingTable(VkPipeline pipeline)507     std::pair<de::SharedPtr<BufferWithMemory>, VkStridedDeviceAddressRegionKHR> createHitShaderBindingTable(
508         VkPipeline pipeline)
509     {
510         de::MovePtr<BufferWithMemory> buf;
511         VkStridedDeviceAddressRegionKHR rgn;
512 
513         std::vector<uint8_t> handles(m_testInstance.shaderGroupHandleSize);
514         auto records                 = m_testInstance.prepareShaderBindingTable();
515         const uint32_t hitGroupCount = uint32_t(records.size() - 2);
516 
517         SBT<PipelineFlagsInstance::ShaderRecordEXT> sbt(m_vkd, m_device, m_allocator, pipeline, hitGroupCount,
518                                                         m_testInstance.shaderGroupHandleSize,
519                                                         m_testInstance.shaderGroupBaseAlignment);
520 
521         VK_CHECK(m_vkd.getRayTracingShaderGroupHandlesKHR(m_device, pipeline, 2, 1, handles.size(), handles.data()));
522 
523         for (uint32_t i = 0; i < hitGroupCount; ++i)
524         {
525             // copy the SBT record if it was initialized in prepareShaderBindingTable()
526             if (std::get<3>(records[i + 2]))
527             {
528                 const PipelineFlagsInstance::ShaderRecordEXT &rec = std::get<2>(records[i + 2]);
529                 sbt.updateAt(i, handles.data(), rec);
530             }
531         }
532 
533         sbt.flush();
534         buf = sbt.get();
535         rgn = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(m_vkd, m_device, **buf, 0), sbt.getAlignment(),
536                                                 hitGroupCount * sbt.getAlignment());
537 
538         return {de::SharedPtr<BufferWithMemory>(buf.release()), rgn};
539     }
540 
541 private:
542     Context &m_context;
543     const DeviceInterface &m_vkd;
544     const VkDevice m_device;
545     Allocator &m_allocator;
546     const PipelineFlagsInstance &m_testInstance;
547     const TestParams m_params;
548     Move<VkShaderModule> m_rgenModule;
549     Move<VkShaderModule> m_chitModule;
550     Move<VkShaderModule> m_ahitModule;
551     Move<VkShaderModule> m_isectModule;
552     Move<VkShaderModule> m_missModule;
553     Move<VkShaderModule> m_gapModule;
554     std::vector<de::SharedPtr<Move<VkPipeline>>> m_libraries;
555 };
556 
557 template <class T, class P = T (*)[1], class R = decltype(std::begin(*std::declval<P>()))>
makeStdBeginEnd(T * p,uint32_t n)558 auto makeStdBeginEnd(T *p, uint32_t n) -> std::pair<R, R>
559 {
560     auto tmp   = std::begin(*P(p));
561     auto begin = tmp;
562     std::advance(tmp, n);
563     return {begin, tmp};
564 }
565 
PipelineFlagsCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)566 PipelineFlagsCase::PipelineFlagsCase(tcu::TestContext &testCtx, const std::string &name, const TestParams &params)
567     : TestCase(testCtx, name)
568     , shaderGroupHandleSize(m_shaderGroupHandleSize)
569     , shaderGroupBaseAlignment(m_shaderGroupBaseAlignment)
570     , m_params(params)
571     , m_rgenPayload(0, ':', 0, 0)
572     , m_defMissRetGreenComp('-')
573     , m_defTriRetGreenComp('A')
574     , m_defBoxRetGreenComp(calcDefBoxRetGreenComp(params, m_defTriRetGreenComp))
575 {
576 }
577 
checkSupport(Context & context) const578 void PipelineFlagsCase::checkSupport(Context &context) const
579 {
580     if ((VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR & m_params.flags) &&
581         (GeometryTypes::Triangle == m_params.geomTypes))
582     {
583         TCU_THROW(InternalError, "Illegal params combination: "
584                                  "VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR and Triangles");
585     }
586 
587     if (!context.isDeviceFunctionalitySupported("VK_KHR_ray_tracing_pipeline"))
588         TCU_THROW(NotSupportedError, "VK_KHR_ray_tracing_pipeline not supported");
589 
590     // VK_KHR_acceleration_structure is required by VK_KHR_ray_tracing_pipeline.
591     if (!context.isDeviceFunctionalitySupported("VK_KHR_acceleration_structure"))
592         TCU_FAIL("VK_KHR_acceleration_structure not supported but VK_KHR_ray_tracing_pipeline supported");
593 
594     // The same for VK_KHR_buffer_device_address.
595     if (!context.isDeviceFunctionalitySupported("VK_KHR_buffer_device_address"))
596         TCU_FAIL("VK_KHR_buffer_device_address not supported but VK_KHR_acceleration_structure supported");
597 
598     if (m_params.useLibs && !context.isDeviceFunctionalitySupported("VK_KHR_pipeline_library"))
599         TCU_FAIL("VK_KHR_pipeline_library not supported but VK_KHR_ray_tracing_pipeline supported");
600 
601     if (m_params.useMaintenance5)
602         context.requireDeviceFunctionality("VK_KHR_maintenance5");
603 
604     const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
605         context.getRayTracingPipelineFeatures();
606     if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
607         TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
608 
609     const VkPhysicalDeviceAccelerationStructureFeaturesKHR &accelerationStructureFeaturesKHR =
610         context.getAccelerationStructureFeatures();
611     if (accelerationStructureFeaturesKHR.accelerationStructure == false)
612         TCU_THROW(TestError, "VK_KHR_ray_tracing_pipeline requires "
613                              "VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
614 
615     if (m_params.onHhost && accelerationStructureFeaturesKHR.accelerationStructureHostCommands == false)
616         TCU_THROW(NotSupportedError,
617                   "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructureHostCommands");
618 
619     checkAccelerationStructureVertexBufferFormat(context.getInstanceInterface(), context.getPhysicalDevice(),
620                                                  VK_FORMAT_R32G32B32_SFLOAT);
621 
622     auto rayTracingProperties  = makeRayTracingProperties(context.getInstanceInterface(), context.getPhysicalDevice());
623     m_shaderGroupHandleSize    = rayTracingProperties->getShaderGroupHandleSize();
624     m_shaderGroupBaseAlignment = rayTracingProperties->getShaderGroupBaseAlignment();
625 }
626 
initPrograms(SourceCollections & programCollection) const627 void PipelineFlagsCase::initPrograms(SourceCollections &programCollection) const
628 {
629     const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
630     const char endl        = '\n';
631     const uint32_t missIdx = 0;
632 
633     const std::string payloadInDecl = "layout(location = 0) rayPayloadInEXT ivec4 payload;";
634 
635     const std::string recordDecl = "layout(shaderRecordEXT, std430) buffer Rec {\n"
636                                    "  uint  geomType;\n"
637                                    "  uint  geomIndex;\n"
638                                    "  ivec4 retValue;\n"
639                                    "} record;";
640 
641     {
642         std::stringstream str;
643         str << "#version 460 core" << endl
644             << "#extension GL_EXT_ray_tracing : require" << endl
645             << "layout(location = 0) rayPayloadEXT ivec4 payload;" << endl
646             << "layout(rgba32i, set = 0, binding = 0) uniform iimage2D result;" << endl
647             << "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;" << endl
648             << "void main()" << endl
649             << "{" << endl
650             << "  float rx           = (float(gl_LaunchIDEXT.x * 2) / float(gl_LaunchSizeEXT.x)) - 1.0;" << endl
651             << "  float ry           = (float(gl_LaunchIDEXT.y) + 0.5) / float(gl_LaunchSizeEXT.y);" << endl
652             << "  payload            = ivec4" << m_rgenPayload << ";" << endl
653             << "  uint  rayFlags     = gl_RayFlagsNoneEXT;" << endl
654             << "  uint  cullMask     = 0xFFu;" << endl
655             << "  uint  stbRecOffset = " << m_params.stbRecOffset << "u;" << endl
656             << "  uint  stbRecStride = " << m_params.stbRecStride << "u;" << endl
657             << "  uint  missIdx      = " << missIdx << "u;" << endl
658             << "  vec3  orig         = vec3(rx, ry, 1.0);" << endl
659             << "  float tmin         = 0.0;" << endl
660             << "  vec3  dir          = vec3(0.0, 0.0, -1.0);" << endl
661             << "  float tmax         = 1000.0;" << endl
662             << "  traceRayEXT(topLevelAS, rayFlags, cullMask, stbRecOffset, stbRecStride, missIdx, orig, tmin, dir, "
663                "tmax, 0);"
664             << endl
665             << "  imageStore(result, ivec2(gl_LaunchIDEXT.xy), payload);" << endl
666             << "}";
667         programCollection.glslSources.add("rgen") << glu::RaygenSource(str.str()) << buildOptions;
668     }
669 
670     // miss shader is created in each test regardless the m_params.miss() is set
671     {
672         std::stringstream str;
673         str << "#version 460 core" << endl
674             << "#extension GL_EXT_ray_tracing : require" << endl
675             << payloadInDecl << endl
676             << recordDecl << endl
677             << "void main()" << endl
678             << "{" << endl
679             << "  payload = record.retValue;" << endl
680             << "}";
681         programCollection.glslSources.add("miss") << glu::MissSource(str.str()) << buildOptions;
682     }
683 
684     // closest hit shader is created in each test regardless the m_params.chit() is set
685     {
686         std::stringstream str;
687         str << "#version 460 core" << endl
688             << "#extension GL_EXT_ray_tracing : require" << endl
689             << "hitAttributeEXT ivec4 hitAttribute;" << endl
690             << payloadInDecl << endl
691             << recordDecl << endl
692             << "void main()" << endl
693             << "{" << endl
694             << "  if (record.geomType == " << uint32_t(GeometryTypes::Triangle) << ")" << endl
695             << "    payload = record.retValue;" << endl
696             << "  else payload = hitAttribute;" << endl
697             << "}";
698         programCollection.glslSources.add("chit") << glu::ClosestHitSource(str.str()) << buildOptions;
699     }
700 
701     if (m_params.ahit())
702     {
703         std::stringstream str;
704         str << "#version 460 core" << endl
705             << "#extension GL_EXT_ray_tracing : require" << endl
706             << recordDecl << endl
707             << "void main()" << endl
708             << "{" << endl
709             << "  if (record.geomIndex % 2 == 1)" << endl
710             << "    ignoreIntersectionEXT;" << endl
711             << "}";
712         programCollection.glslSources.add("ahit") << glu::AnyHitSource(str.str()) << buildOptions;
713     }
714 
715     if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) ||
716         (m_params.geomTypes == GeometryTypes::TriangleAndBox))
717     {
718         std::stringstream str;
719         str << "#version 460 core" << endl
720             << "#extension GL_EXT_ray_tracing : require" << endl
721             << "hitAttributeEXT ivec4 hitAttribute;" << endl
722             << recordDecl << endl
723             << "void main()" << endl
724             << "{" << endl
725             << "  hitAttribute = ivec4(record.retValue.x + 0" << endl
726             << "                      ,record.retValue.y + 2" << endl
727             << "                      ,record.retValue.z + 3" << endl
728             << "                      ,record.retValue.w + 4);" << endl
729             << "  reportIntersectionEXT(0.0, 0);" << endl
730             << "}";
731         programCollection.glslSources.add("isect") << glu::IntersectionSource(str.str()) << buildOptions;
732     }
733 }
734 
createInstance(Context & context) const735 TestInstance *PipelineFlagsCase::createInstance(Context &context) const
736 {
737     return new PipelineFlagsInstance(context, m_params, shaderGroupHandleSize, shaderGroupBaseAlignment, m_rgenPayload,
738                                      m_defMissRetGreenComp, m_defTriRetGreenComp, m_defBoxRetGreenComp);
739 }
740 
PipelineFlagsInstance(Context & context,const TestParams & params,const uint32_t & shaderGroupHandleSize_,const uint32_t & shaderGroupBaseAlignment_,const tcu::IVec4 & rgenPayload_,int32_t defMissRetGreenComp_,int32_t defTriRetGreenComp_,int32_t defBoxRetGreenComp_)741 PipelineFlagsInstance::PipelineFlagsInstance(Context &context, const TestParams &params,
742                                              const uint32_t &shaderGroupHandleSize_,
743                                              const uint32_t &shaderGroupBaseAlignment_, const tcu::IVec4 &rgenPayload_,
744                                              int32_t defMissRetGreenComp_, int32_t defTriRetGreenComp_,
745                                              int32_t defBoxRetGreenComp_)
746     : TestInstance(context)
747     , rgenPayload(rgenPayload_)
748     , defMissRetGreenComp(defMissRetGreenComp_)
749     , defTriRetGreenComp(defTriRetGreenComp_)
750     , defBoxRetGreenComp(defBoxRetGreenComp_)
751     , shaderGroupHandleSize(shaderGroupHandleSize_)
752     , shaderGroupBaseAlignment(shaderGroupBaseAlignment_)
753     , m_params(params)
754     , m_format(VK_FORMAT_R32G32B32A32_SINT)
755 {
756 }
757 
makeImageCreateInfo() const758 VkImageCreateInfo PipelineFlagsInstance::makeImageCreateInfo() const
759 {
760     const uint32_t familyIndex              = m_context.getUniversalQueueFamilyIndex();
761     const VkImageCreateInfo imageCreateInfo = {
762         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,               // VkStructureType sType;
763         DE_NULL,                                           // const void* pNext;
764         (VkImageCreateFlags)0u,                            // VkImageCreateFlags flags;
765         VK_IMAGE_TYPE_2D,                                  // VkImageType imageType;
766         m_format,                                          // VkFormat format;
767         makeExtent3D(m_params.width, m_params.height, 1u), // VkExtent3D extent;
768         1u,                                                // uint32_t mipLevels;
769         1u,                                                // uint32_t arrayLayers;
770         VK_SAMPLE_COUNT_1_BIT,                             // VkSampleCountFlagBits samples;
771         VK_IMAGE_TILING_OPTIMAL,                           // VkImageTiling tiling;
772         VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
773             VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
774         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
775         1u,                                  // uint32_t queueFamilyIndexCount;
776         &familyIndex,                        // const uint32_t* pQueueFamilyIndices;
777         VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout initialLayout;
778     };
779 
780     return imageCreateInfo;
781 }
782 
prepareTriGeometries(const float zCoord) const783 std::vector<PipelineFlagsInstance::TriGeometry> PipelineFlagsInstance::prepareTriGeometries(const float zCoord) const
784 {
785     const tcu::Vec3 center(-0.5f, 0.5f, zCoord);
786     const tcu::Vec3 start(0.0f, 0.5f, zCoord);
787     const uint32_t maxTriangles   = m_params.instCount * m_params.geomCount;
788     const uint32_t trianglesCount = deMaxu32(maxTriangles, 3);
789     const float angle             = (4.0f * std::acos(0.0f)) / float(trianglesCount);
790 
791     tcu::Vec3 point(start);
792     std::vector<TriGeometry> geometries(maxTriangles);
793     for (uint32_t inst = 0, idx = 0; inst < m_params.instCount; ++inst)
794     {
795         for (uint32_t geom = 0; geom < m_params.geomCount; ++geom, ++idx)
796         {
797             TriGeometry &geometry = geometries[idx];
798 
799             geometry[0] = center;
800             geometry[1] = point;
801             geometry[2] = (maxTriangles >= 3 && trianglesCount - idx == 1u) ? start : rotateCcwZ(point, center, angle);
802 
803             point = geometry[2];
804         }
805     }
806 
807     return geometries;
808 }
809 
prepareBoxGeometries(const float zFront,const float zBack) const810 std::vector<PipelineFlagsInstance::BoxGeometry> PipelineFlagsInstance::prepareBoxGeometries(const float zFront,
811                                                                                             const float zBack) const
812 {
813     const uint32_t maxBoxes = m_params.instCount * m_params.geomCount;
814 
815     std::vector<BoxGeometry> boxes(maxBoxes);
816     uint32_t boxesPerDim = 0u;
817     float boxWidth       = 0.0f;
818     float boxHeight      = 0.0f;
819 
820     // find nearest square ceil number
821     do
822     {
823         ++boxesPerDim;
824         boxWidth  = 1.0f / float(boxesPerDim);
825         boxHeight = 1.0f / float(boxesPerDim);
826     } while (boxesPerDim * boxesPerDim < maxBoxes);
827 
828     for (uint32_t boxY = 0, boxIdx = 0; boxY < boxesPerDim && boxIdx < maxBoxes; ++boxY)
829     {
830         for (uint32_t boxX = 0; boxX < boxesPerDim && boxIdx < maxBoxes; ++boxX, ++boxIdx)
831         {
832             const float x   = float(boxX) * boxWidth;
833             const float y   = float(boxY) * boxHeight;
834             BoxGeometry box = {{tcu::Vec3(x, y, zFront), tcu::Vec3((x + boxWidth), (y + boxHeight), zBack)}};
835             boxes[boxIdx].swap(box);
836         }
837     }
838 
839     return boxes;
840 }
841 
createBottomLevelAccelerationStructs(VkCommandBuffer cmdBuffer) const842 PipelineFlagsInstance::BottomLevelASPtrs PipelineFlagsInstance::createBottomLevelAccelerationStructs(
843     VkCommandBuffer cmdBuffer) const
844 {
845     const DeviceInterface &vkd = m_context.getDeviceInterface();
846     const VkDevice device      = m_context.getDevice();
847     Allocator &allocator       = m_context.getDefaultAllocator();
848     const VkGeometryFlagsKHR geomFlags =
849         m_params.ahit() ? VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR : VK_GEOMETRY_OPAQUE_BIT_KHR;
850 
851     BottomLevelASPtrs result;
852 
853     if (!m_params.isect() &&
854         ((m_params.geomTypes == GeometryTypes::Triangle) || (m_params.geomTypes == GeometryTypes::TriangleAndBox)))
855     {
856         const auto geometries = prepareTriGeometries(0.0f);
857 
858         for (uint32_t inst = 0, idx = 0; inst < m_params.instCount; ++inst)
859         {
860             auto blas = makeBottomLevelAccelerationStructure();
861             blas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR :
862                                                   VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR);
863 
864             for (uint32_t geom = 0; geom < m_params.geomCount; ++geom, ++idx)
865             {
866                 const TriGeometry &triangle = geometries[idx];
867                 blas->addGeometry(std::vector<tcu::Vec3>(triangle.begin(), triangle.end()), true, geomFlags);
868             }
869 
870             blas->createAndBuild(vkd, device, cmdBuffer, allocator);
871             result.emplace_back(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
872         }
873     }
874 
875     if (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) ||
876         (m_params.geomTypes == GeometryTypes::TriangleAndBox))
877     {
878         const auto geometries = prepareBoxGeometries(0.0f, 0.0f);
879 
880         for (uint32_t inst = 0, idx = 0; inst < m_params.instCount; ++inst)
881         {
882             auto blas = makeBottomLevelAccelerationStructure();
883             blas->setUseMaintenance5(m_params.useMaintenance5);
884             blas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR :
885                                                   VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR);
886 
887             for (uint32_t geom = 0; geom < m_params.geomCount; ++geom, ++idx)
888             {
889                 const BoxGeometry &box = geometries[idx];
890                 blas->addGeometry(std::vector<tcu::Vec3>(box.begin(), box.end()), false, geomFlags);
891             }
892 
893             blas->createAndBuild(vkd, device, cmdBuffer, allocator);
894             result.emplace_back(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
895         }
896     }
897 
898     return result;
899 }
900 
createTopLevelAccelerationStruct(VkCommandBuffer cmdBuffer,const BottomLevelASPtrs & blasPtrs) const901 PipelineFlagsInstance::TopLevelASPtr PipelineFlagsInstance::createTopLevelAccelerationStruct(
902     VkCommandBuffer cmdBuffer, const BottomLevelASPtrs &blasPtrs) const
903 {
904     const DeviceInterface &vkd              = m_context.getDeviceInterface();
905     const VkDevice device                   = m_context.getDevice();
906     Allocator &allocator                    = m_context.getDefaultAllocator();
907     const uint32_t groupsAndGapsPerInstance = computeEffectiveShaderGroupCount(m_params);
908 
909     auto tlas = makeTopLevelAccelerationStructure();
910 
911     tlas->setBuildType(m_params.onHhost ? VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR :
912                                           VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR);
913     tlas->setInstanceCount(blasPtrs.size());
914     for (auto begin = blasPtrs.begin(), end = blasPtrs.end(), i = begin; i != end; ++i)
915     {
916         const uint32_t instanceShaderBindingTableRecordOffset =
917             static_cast<uint32_t>(std::distance(begin, i) * groupsAndGapsPerInstance);
918         tlas->addInstance(*i, identityMatrix3x4, 0, 0xFF, instanceShaderBindingTableRecordOffset);
919     }
920     tlas->createAndBuild(vkd, device, cmdBuffer, allocator);
921 
922     return TopLevelASPtr(tlas.release());
923 }
924 
prepareShaderBindingTable() const925 std::vector<PipelineFlagsInstance::ShaderRecordEntry> PipelineFlagsInstance::prepareShaderBindingTable() const
926 {
927     const bool includeTriangles             = (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) ||
928                                                          (m_params.geomTypes == GeometryTypes::TriangleAndBox)));
929     const bool includeBoxes                 = (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) ||
930                                (m_params.geomTypes == GeometryTypes::TriangleAndBox));
931     const uint32_t groupsAndGapsPerInstance = computeEffectiveShaderGroupCount(m_params);
932     const uint32_t commonGroupCount         = 2; // general groups for rgen and miss
933     const uint32_t triangleGroupCount       = includeTriangles ? (groupsAndGapsPerInstance * m_params.instCount) : 0;
934     const uint32_t proceduralGroupCount     = includeBoxes ? (groupsAndGapsPerInstance * m_params.instCount) : 0;
935     const uint32_t totalGroupCount          = commonGroupCount + triangleGroupCount + proceduralGroupCount;
936 
937     std::vector<ShaderRecordEntry> shaderRecords(totalGroupCount);
938 
939     shaderRecords[0] =
940         std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>(VK_SHADER_STAGE_RAYGEN_BIT_KHR, {}, {}, true);
941     shaderRecords[1] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>(
942         VK_SHADER_STAGE_MISS_BIT_KHR, {}, {GeometryTypes::Box, (~0u), tcu::IVec4(0, defMissRetGreenComp, 0, 0)}, true);
943 
944     de::SharedPtr<AnyHitShader> ahit(new AnyHitShader);
945     de::SharedPtr<ClosestHitShader> chit(new ClosestHitShader);
946     de::SharedPtr<IntersectionShader> isect(new IntersectionShader);
947 
948     if (includeTriangles)
949     {
950         std::set<uint32_t> usedIndexes;
951         int32_t greenComp = defTriRetGreenComp;
952 
953         const uint32_t recordsToSkip = commonGroupCount;
954 
955         for (uint32_t instance = 0; instance < m_params.instCount; ++instance)
956         {
957             const uint32_t instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
958             for (uint32_t geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
959             {
960                 const uint32_t shaderGroupIndex = instanceShaderBindingTableRecordOffset +
961                                                   geometryIndex * m_params.stbRecStride + m_params.stbRecOffset;
962                 if (usedIndexes.find(shaderGroupIndex) == usedIndexes.end())
963                 {
964                     HitGroup hitGroup;
965                     VkShaderStageFlags flags = 0;
966                     if (m_params.ahit())
967                     {
968                         flags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
969                         hitGroup.ahit = ahit;
970                     }
971                     flags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
972                     hitGroup.chit                   = chit;
973                     shaderRecords[shaderGroupIndex] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>(
974                         flags, hitGroup, {GeometryTypes::Triangle, geometryIndex, tcu::IVec4(0, greenComp++, 0, 0)},
975                         true);
976                     usedIndexes.insert(shaderGroupIndex);
977                 }
978             }
979         }
980     }
981 
982     if (includeBoxes)
983     {
984         std::set<uint32_t> usedIndexes;
985         int32_t greenComp = defBoxRetGreenComp;
986 
987         const uint32_t recordsToSkip = triangleGroupCount + commonGroupCount;
988 
989         for (uint32_t instance = 0; instance < m_params.instCount; ++instance)
990         {
991             const uint32_t instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
992             for (uint32_t geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
993             {
994                 const uint32_t shaderGroupIndex = instanceShaderBindingTableRecordOffset +
995                                                   geometryIndex * m_params.stbRecStride + m_params.stbRecOffset;
996                 if (usedIndexes.find(shaderGroupIndex) == usedIndexes.end())
997                 {
998                     HitGroup hitGroup;
999                     VkShaderStageFlags flags = 0;
1000                     if (m_params.ahit())
1001                     {
1002                         flags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
1003                         hitGroup.ahit = ahit;
1004                     }
1005                     flags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
1006                     hitGroup.chit = chit;
1007                     { //In the case of AABB isect must be provided, otherwise we will process AABB with TRIANGLES_HIT_GROUP
1008                         flags |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
1009                         hitGroup.isect = isect;
1010                     }
1011                     shaderRecords[shaderGroupIndex] = std::tuple<VkShaderStageFlags, HitGroup, ShaderRecordEXT, bool>(
1012                         flags, hitGroup, {GeometryTypes::Box, geometryIndex, tcu::IVec4(0, greenComp++, 0, 0)}, true);
1013                     usedIndexes.insert(shaderGroupIndex);
1014                 }
1015             }
1016         }
1017     }
1018 
1019     return shaderRecords;
1020 }
1021 
rayToImage(const tcu::Vec2 & rayCoords) const1022 tcu::IVec2 PipelineFlagsInstance::rayToImage(const tcu::Vec2 &rayCoords) const
1023 {
1024     return tcu::IVec2(int32_t(((rayCoords.x() + 1.0f) * float(m_params.width)) / 2.0f),
1025                       int32_t((rayCoords.y() * float(m_params.height)) - 0.5f));
1026 }
1027 
imageToRay(const tcu::IVec2 & imageCoords) const1028 tcu::Vec2 PipelineFlagsInstance::imageToRay(const tcu::IVec2 &imageCoords) const
1029 {
1030     const float rx = (float(imageCoords.x() * 2) / float(m_params.width)) - 1.0f;
1031     const float ry = (float(imageCoords.y()) + 0.5f) / float(m_params.height);
1032     return tcu::Vec2(rx, ry);
1033 }
1034 
computeSamePixelCount(const std::vector<tcu::IVec4> & image,const tcu::Vec2 pixelCoords,const tcu::IVec4 & requiredColor,const tcu::IVec4 & floodColor,const std::function<bool (const tcu::Vec3 &)> & pointInGeometry,std::vector<std::pair<tcu::IVec4,tcu::IVec2>> & auxBuffer) const1035 uint32_t PipelineFlagsInstance::computeSamePixelCount(const std::vector<tcu::IVec4> &image, const tcu::Vec2 pixelCoords,
1036                                                       const tcu::IVec4 &requiredColor, const tcu::IVec4 &floodColor,
1037                                                       const std::function<bool(const tcu::Vec3 &)> &pointInGeometry,
1038                                                       std::vector<std::pair<tcu::IVec4, tcu::IVec2>> &auxBuffer) const
1039 {
1040     if (!pointInGeometry(tcu::Vec3(pixelCoords.x(), pixelCoords.y(), 0.0f)))
1041         return 0;
1042 
1043     auxBuffer.resize(image.size() * 4);
1044     std::transform(image.begin(), image.end(), auxBuffer.begin(),
1045                    [](const tcu::IVec4 &c) -> std::pair<tcu::IVec4, tcu::IVec2> {
1046                        return {c, tcu::IVec2()};
1047                    });
1048 
1049     tcu::Vec2 rayCoord;
1050     tcu::IVec2 imageCoords = rayToImage(pixelCoords);
1051     uint32_t pixelIndex    = imageCoords.y() * m_params.width + imageCoords.x();
1052     tcu::IVec4 imageColor  = image[pixelIndex];
1053 
1054     if (requiredColor != imageColor)
1055         return 0;
1056 
1057     int32_t stackIndex           = 0;
1058     uint32_t sameCount           = 1;
1059     auxBuffer[stackIndex].second = imageCoords;
1060 
1061     while (stackIndex >= 0)
1062     {
1063         imageCoords = auxBuffer[stackIndex].second;
1064         --stackIndex;
1065 
1066         if (imageCoords.x() < 0 || imageCoords.x() >= int32_t(m_params.width) || imageCoords.y() < 0 ||
1067             imageCoords.y() >= int32_t(m_params.height))
1068             continue;
1069 
1070         rayCoord = imageToRay(imageCoords);
1071         if (!pointInGeometry(tcu::Vec3(rayCoord.x(), rayCoord.y(), 0.0f)))
1072             continue;
1073 
1074         pixelIndex = imageCoords.y() * m_params.width + imageCoords.x();
1075         imageColor = auxBuffer[pixelIndex].first;
1076         if (requiredColor != imageColor)
1077             continue;
1078 
1079         auxBuffer[pixelIndex].first = floodColor;
1080         sameCount += 1;
1081 
1082         auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x() - 1, imageCoords.y());
1083         auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x() + 1, imageCoords.y());
1084         auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x(), imageCoords.y() - 1);
1085         auxBuffer[++stackIndex].second = tcu::IVec2(imageCoords.x(), imageCoords.y() + 1);
1086     }
1087 
1088     return sameCount;
1089 }
1090 
travelRay(std::vector<tcu::IVec4> & outImage,const uint32_t glLaunchIdExtX,const uint32_t glLaunchIdExtY,const std::vector<ShaderRecordEntry> & shaderBindingTable,const MissShader & missShader,const std::vector<TriGeometry> & triangleGeometries,const std::vector<BoxGeometry> & boxGeometries) const1091 void PipelineFlagsInstance::travelRay(std::vector<tcu::IVec4> &outImage, const uint32_t glLaunchIdExtX,
1092                                       const uint32_t glLaunchIdExtY,
1093                                       const std::vector<ShaderRecordEntry> &shaderBindingTable,
1094                                       const MissShader &missShader, const std::vector<TriGeometry> &triangleGeometries,
1095                                       const std::vector<BoxGeometry> &boxGeometries) const
1096 {
1097     const tcu::Vec2 rayCoords               = imageToRay(tcu::IVec2(glLaunchIdExtX, glLaunchIdExtY));
1098     const bool includeTriangles             = (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) ||
1099                                                          (m_params.geomTypes == GeometryTypes::TriangleAndBox)));
1100     const bool includeBoxes                 = (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) ||
1101                                (m_params.geomTypes == GeometryTypes::TriangleAndBox));
1102     const uint32_t commonGroupCount         = 2; // general groups for rgen and miss
1103     const uint32_t groupsAndGapsPerInstance = computeEffectiveShaderGroupCount(m_params);
1104     const uint32_t triangleGroupCount       = includeTriangles ? (groupsAndGapsPerInstance * m_params.instCount) : 0;
1105 
1106     bool hitHappened(false);
1107     uint32_t shaderGroupIndex(~0u);
1108     tcu::IVec4 payload(rgenPayload);
1109     const tcu::Vec3 origin(rayCoords.x(), rayCoords.y(), 1.0f);
1110 
1111     if (includeTriangles)
1112     {
1113         const uint32_t recordsToSkip = commonGroupCount;
1114         for (uint32_t instance = 0; !hitHappened && (instance < m_params.instCount); ++instance)
1115         {
1116             const uint32_t instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
1117             for (uint32_t geometryIndex = 0; !hitHappened && (geometryIndex < m_params.geomCount); ++geometryIndex)
1118             {
1119                 const TriGeometry &geometry = triangleGeometries[instance * m_params.geomCount + geometryIndex];
1120                 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride +
1121                                    m_params.stbRecOffset;
1122                 if (pointInTriangle2D(origin, geometry[0], geometry[1], geometry[2]))
1123                 {
1124                     hitHappened = true;
1125                 }
1126             }
1127         }
1128     }
1129 
1130     if (includeBoxes)
1131     {
1132         const uint32_t recordsToSkip = triangleGroupCount + commonGroupCount;
1133         for (uint32_t instance = 0; !hitHappened && (instance < m_params.instCount); ++instance)
1134         {
1135             const uint32_t instanceShaderBindingTableRecordOffset = recordsToSkip + instance * groupsAndGapsPerInstance;
1136             for (uint32_t geometryIndex = 0; !hitHappened && (geometryIndex < m_params.geomCount); ++geometryIndex)
1137             {
1138                 const BoxGeometry &geometry = boxGeometries[instance * m_params.geomCount + geometryIndex];
1139                 shaderGroupIndex = instanceShaderBindingTableRecordOffset + geometryIndex * m_params.stbRecStride +
1140                                    m_params.stbRecOffset;
1141                 if (pointInRect2D(origin, geometry[0], geometry[1]))
1142                 {
1143                     hitHappened = true;
1144                 }
1145             }
1146         }
1147     }
1148 
1149     if (hitHappened)
1150     {
1151         const ShaderRecordEXT &shaderRecord = std::get<2>(shaderBindingTable[shaderGroupIndex]);
1152         const HitGroup &hitGroup            = std::get<1>(shaderBindingTable[shaderGroupIndex]);
1153         const VkShaderStageFlags flags      = std::get<0>(shaderBindingTable[shaderGroupIndex]);
1154         auto hitAttribute                   = rgenPayload;
1155         bool ignoreIsect                    = false;
1156 
1157         // check if the SBT entry was was initialized
1158         DE_ASSERT(std::get<3>(shaderBindingTable[shaderGroupIndex]));
1159 
1160         if (flags & VK_SHADER_STAGE_INTERSECTION_BIT_KHR)
1161         {
1162             hitAttribute = hitGroup.isect->invoke(IntersectionShader::dummyPayload, shaderRecord);
1163         }
1164         if (flags & VK_SHADER_STAGE_ANY_HIT_BIT_KHR)
1165         {
1166             ignoreIsect = hitGroup.ahit->ignoreIntersection(AnyHitShader::dummyPayload, shaderRecord);
1167         }
1168         if (ignoreIsect)
1169         {
1170             payload = missShader.invoke(MissShader::dummyPayload, std::get<2>(shaderBindingTable[1]));
1171         }
1172         else if (flags & VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)
1173         {
1174             payload = hitGroup.chit->invoke(hitAttribute, shaderRecord);
1175         }
1176     }
1177     else
1178     {
1179         payload = missShader.invoke(MissShader::dummyPayload, std::get<2>(shaderBindingTable[1]));
1180     }
1181 
1182     outImage[glLaunchIdExtY * m_params.width + glLaunchIdExtX] = payload;
1183 }
1184 
1185 #ifdef INTERNAL_DEBUG
printImage(const tcu::IVec4 * image) const1186 void PipelineFlagsInstance::printImage(const tcu::IVec4 *image) const
1187 {
1188     for (uint32_t y = 0; y < m_params.height; ++y)
1189     {
1190         for (uint32_t x = 0; x < m_params.width; ++x)
1191             std::cout << static_cast<char>(image[(m_params.height - y - 1) * m_params.width + x].y());
1192         std::cout << std::endl;
1193     }
1194 }
1195 #endif
1196 
verifyResult(const BufferWithMemory * resultBuffer) const1197 bool PipelineFlagsInstance::verifyResult(const BufferWithMemory *resultBuffer) const
1198 {
1199     const auto triangleGeometries = prepareTriGeometries(0.0f);
1200     const auto boxGeometries      = prepareBoxGeometries(0.0f, 0.0f);
1201 
1202     const bool includeTriangles = (!m_params.isect() && ((m_params.geomTypes == GeometryTypes::Triangle) ||
1203                                                          (m_params.geomTypes == GeometryTypes::TriangleAndBox)));
1204     const bool includeBoxes     = (m_params.isect() || (m_params.geomTypes == GeometryTypes::Box) ||
1205                                (m_params.geomTypes == GeometryTypes::TriangleAndBox));
1206 
1207     const tcu::IVec4 *resultImageData = (tcu::IVec4 *)(resultBuffer->getAllocation().getHostPtr());
1208     auto resultImageBounds            = makeStdBeginEnd(resultImageData, (m_params.width * m_params.height));
1209     const std::vector<tcu::IVec4> resultImage(resultImageBounds.first, resultImageBounds.second);
1210     std::vector<tcu::IVec4> referenceImage(m_params.width * m_params.height);
1211 
1212     const std::vector<ShaderRecordEntry> shaderBindingTable = prepareShaderBindingTable();
1213 
1214     MissShader missShader{};
1215 
1216     // perform offline ray-tracing
1217     for (uint32_t glLaunchIdExtY = 0; glLaunchIdExtY < m_params.height; ++glLaunchIdExtY)
1218     {
1219         for (uint32_t glLaunchIdExtX = 0; glLaunchIdExtX < m_params.width; ++glLaunchIdExtX)
1220         {
1221             travelRay(referenceImage, glLaunchIdExtX, glLaunchIdExtY, shaderBindingTable, missShader,
1222                       triangleGeometries, boxGeometries);
1223         }
1224     }
1225 
1226 #ifdef INTERNAL_DEBUG
1227     std::cout << "===== RES =====" << std::endl;
1228     printImage(resultImageData);
1229     std::cout << std::endl;
1230     std::cout << "===== REF =====" << std::endl;
1231     printImage(referenceImage.data());
1232     std::cout << std::endl;
1233 #endif
1234 
1235     const tcu::IVec4 floodColor(0, '*', 0, 0);
1236     std::vector<std::pair<tcu::IVec4, tcu::IVec2>> auxBuffer(referenceImage.size() * 4);
1237 
1238     if (includeTriangles)
1239     {
1240         TriGeometry tri;
1241         std::function<bool(const tcu::Vec3 &)> pointInGeometry =
1242             std::bind(pointInTriangle2D, std::placeholders::_1, std::ref(tri[0]), std::ref(tri[1]), std::ref(tri[2]));
1243 
1244         for (uint32_t instance = 0; instance < m_params.instCount; ++instance)
1245         {
1246             for (uint32_t geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
1247             {
1248                 if (!(m_params.ahit() && (geometryIndex % 2 == 1)))
1249                 {
1250                     tri = triangleGeometries[instance * m_params.geomCount + geometryIndex];
1251                     const tcu::Vec2 center((tri[0].x() + tri[1].x() + tri[2].x()) / 3.0f,
1252                                            (tri[0].y() + tri[1].y() + tri[2].y()) / 3.0f);
1253 
1254                     const tcu::IVec2 refImageCoords = rayToImage(center);
1255                     const tcu::IVec4 requiredColor =
1256                         referenceImage[refImageCoords.y() * m_params.width + refImageCoords.x()];
1257 
1258                     uint32_t resultPixelCount    = computeSamePixelCount(resultImage, center, requiredColor, floodColor,
1259                                                                          pointInGeometry, auxBuffer);
1260                     uint32_t referencePixelCount = computeSamePixelCount(referenceImage, center, requiredColor,
1261                                                                          floodColor, pointInGeometry, auxBuffer);
1262 
1263                     if (!resultPixelCount || !referencePixelCount)
1264                         return false;
1265                     if (resultPixelCount > referencePixelCount)
1266                         std::swap(resultPixelCount, referencePixelCount);
1267 
1268                     const float similarity = float(resultPixelCount) / float(referencePixelCount);
1269                     if (similarity < m_params.accuracy)
1270                         return false;
1271                 }
1272             }
1273         }
1274     }
1275 
1276     if (includeBoxes)
1277     {
1278         BoxGeometry box;
1279         std::function<bool(const tcu::Vec3 &)> pointInGeometry =
1280             std::bind(pointInRect2D, std::placeholders::_1, std::ref(box[0]), std::ref(box[1]));
1281 
1282         for (uint32_t instance = 0; instance < m_params.instCount; ++instance)
1283         {
1284             for (uint32_t geometryIndex = 0; geometryIndex < m_params.geomCount; ++geometryIndex)
1285             {
1286                 if (!(m_params.ahit() && (geometryIndex % 2 == 1)))
1287                 {
1288                     box = boxGeometries[instance * m_params.geomCount + geometryIndex];
1289                     const tcu::Vec2 center((box[0].x() + box[1].x()) / 2.0f, (box[0].y() + box[1].y()) / 2.0f);
1290 
1291                     const tcu::IVec2 refImageCoords = rayToImage(center);
1292                     const tcu::IVec4 requiredColor =
1293                         referenceImage[refImageCoords.y() * m_params.width + refImageCoords.x()];
1294 
1295                     uint32_t resultPixelCount    = computeSamePixelCount(resultImage, center, requiredColor, floodColor,
1296                                                                          pointInGeometry, auxBuffer);
1297                     uint32_t referencePixelCount = computeSamePixelCount(referenceImage, center, requiredColor,
1298                                                                          floodColor, pointInGeometry, auxBuffer);
1299 
1300                     if (!resultPixelCount || !referencePixelCount)
1301                         return false;
1302                     if (resultPixelCount > referencePixelCount)
1303                         std::swap(resultPixelCount, referencePixelCount);
1304 
1305                     const float similarity = float(resultPixelCount) / float(referencePixelCount);
1306                     if (similarity < m_params.accuracy)
1307                         return false;
1308                 }
1309             }
1310         }
1311     }
1312 
1313     return true;
1314 }
1315 
iterate(void)1316 tcu::TestStatus PipelineFlagsInstance::iterate(void)
1317 {
1318     const DeviceInterface &vkd = m_context.getDeviceInterface();
1319     const VkDevice device      = m_context.getDevice();
1320     const uint32_t familyIndex = m_context.getUniversalQueueFamilyIndex();
1321     const VkQueue queue        = m_context.getUniversalQueue();
1322     Allocator &allocator       = m_context.getDefaultAllocator();
1323 
1324     const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo();
1325     const VkImageSubresourceRange imageSubresourceRange =
1326         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
1327     const de::MovePtr<ImageWithMemory> image = de::MovePtr<ImageWithMemory>(
1328         new ImageWithMemory(vkd, device, allocator, imageCreateInfo, MemoryRequirement::Any));
1329     const Move<VkImageView> imageView =
1330         makeImageView(vkd, device, **image, VK_IMAGE_VIEW_TYPE_2D, m_format, imageSubresourceRange);
1331     const VkDescriptorImageInfo descriptorImageInfo =
1332         makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
1333 
1334     const uint32_t resultBufferSize = (m_params.width * m_params.height * mapVkFormat(m_format).getPixelSize());
1335     const VkBufferCreateInfo resultBufferCreateInfo =
1336         makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1337     const VkImageSubresourceLayers resultBufferImageSubresourceLayers =
1338         makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
1339     const VkBufferImageCopy resultBufferImageRegion =
1340         makeBufferImageCopy(makeExtent3D(m_params.width, m_params.height, 1u), resultBufferImageSubresourceLayers);
1341     de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(
1342         new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
1343 
1344     const Move<VkDescriptorSetLayout> descriptorSetLayout =
1345         DescriptorSetLayoutBuilder()
1346             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, ALL_RAY_TRACING_STAGES)
1347             .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, ALL_RAY_TRACING_STAGES)
1348             .build(vkd, device);
1349     const Move<VkDescriptorPool> descriptorPool =
1350         DescriptorPoolBuilder()
1351             .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1352             .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
1353             .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1354     const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
1355 
1356     de::MovePtr<RayTracingTestPipeline> rayTracingPipeline =
1357         de::newMovePtr<RayTracingTestPipeline>(std::ref(m_context), std::cref(*this), m_params);
1358     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, *descriptorSetLayout);
1359     Move<VkPipeline> pipeline                   = rayTracingPipeline->createPipeline(*pipelineLayout);
1360 
1361     de::SharedPtr<BufferWithMemory> raygenShaderBindingTable;
1362     VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion;
1363     std::tie(raygenShaderBindingTable, raygenShaderBindingTableRegion) =
1364         rayTracingPipeline->createRaygenShaderBindingTable(*pipeline);
1365 
1366     de::SharedPtr<BufferWithMemory> missShaderBindingTable;
1367     VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion;
1368     std::tie(missShaderBindingTable, missShaderBindingTableRegion) =
1369         rayTracingPipeline->createMissShaderBindingTable(*pipeline);
1370 
1371     de::SharedPtr<BufferWithMemory> hitShaderBindingTable;
1372     VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion;
1373     std::tie(hitShaderBindingTable, hitShaderBindingTableRegion) =
1374         rayTracingPipeline->createHitShaderBindingTable(*pipeline);
1375 
1376     const VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion =
1377         makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
1378 
1379     const Move<VkCommandPool> cmdPool = createCommandPool(vkd, device, 0, familyIndex);
1380     const Move<VkCommandBuffer> cmdBuffer =
1381         allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1382 
1383     beginCommandBuffer(vkd, *cmdBuffer);
1384 
1385     BottomLevelASPtrs blasPtrs = createBottomLevelAccelerationStructs(*cmdBuffer);
1386     TopLevelASPtr tlasPtr      = createTopLevelAccelerationStruct(*cmdBuffer, blasPtrs);
1387 
1388     VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet = {
1389         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, //  VkStructureType sType;
1390         DE_NULL,                                                           //  const void* pNext;
1391         1u,                                                                //  uint32_t accelerationStructureCount;
1392         tlasPtr->getPtr() //  const VkAccelerationStructureKHR* pAccelerationStructures;
1393     };
1394 
1395     DescriptorSetUpdateBuilder()
1396         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1397                      VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
1398         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
1399                      VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructureWriteDescriptorSet)
1400         .update(vkd, device);
1401 
1402     vkd.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1,
1403                               &descriptorSet.get(), 0, DE_NULL);
1404 
1405     vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipeline);
1406 
1407     const VkImageSubresourceRange subresourceRange =
1408         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1409     const VkImageMemoryBarrier imageMemoryBarrier =
1410         makeImageMemoryBarrier(VK_ACCESS_NONE, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1411                                VK_IMAGE_LAYOUT_GENERAL, image->get(), subresourceRange);
1412     cmdPipelineImageMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1413                                   VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &imageMemoryBarrier);
1414 
1415     cmdTraceRays(vkd, *cmdBuffer,
1416                  &raygenShaderBindingTableRegion,   // rgen
1417                  &missShaderBindingTableRegion,     // miss
1418                  &hitShaderBindingTableRegion,      // hit
1419                  &callableShaderBindingTableRegion, // call
1420                  m_params.width, m_params.height, 1);
1421 
1422     const VkMemoryBarrier postTraceMemoryBarrier =
1423         makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
1424     const VkMemoryBarrier postCopyMemoryBarrier =
1425         makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1426     cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
1427                              VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
1428 
1429     vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_GENERAL, **resultBuffer, 1u,
1430                              &resultBufferImageRegion);
1431 
1432     cmdPipelineMemoryBarrier(vkd, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
1433                              &postCopyMemoryBarrier);
1434 
1435     endCommandBuffer(vkd, *cmdBuffer);
1436 
1437     submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
1438 
1439     invalidateMappedMemoryRange(vkd, device, resultBuffer->getAllocation().getMemory(),
1440                                 resultBuffer->getAllocation().getOffset(), resultBufferSize);
1441 
1442     return verifyResult(resultBuffer.get()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
1443 }
1444 
1445 class NoNullShadersFlagGenerator
1446 {
1447 public:
1448     using FlagsSet = std::set<VkPipelineCreateFlags>;
1449     struct BitAndName
1450     {
1451         VkPipelineCreateFlagBits bit;
1452         const char *name;
1453     };
1454     static const BitAndName bits[4];
name(VkPipelineCreateFlags flags)1455     static std::string name(VkPipelineCreateFlags flags)
1456     {
1457         int count = 0;
1458         std::stringstream ss;
1459         for (auto begin = std::begin(bits), end = std::end(bits), i = begin; i != end; ++i)
1460         {
1461             if (flags & i->bit)
1462             {
1463                 if (count++)
1464                     ss << "_or_";
1465                 ss << i->name;
1466             }
1467         }
1468         return count ? ss.str() : "none";
1469     }
mask(const FlagsSet & flags)1470     static VkPipelineCreateFlags mask(const FlagsSet &flags)
1471     {
1472         VkPipelineCreateFlags result{};
1473         for (auto f : flags)
1474             result |= f;
1475         return result;
1476     }
NoNullShadersFlagGenerator()1477     NoNullShadersFlagGenerator() : m_next(0)
1478     {
1479         FlagsSet fs;
1480         for (const auto &b : bits)
1481             fs.insert(b.bit);
1482         combine(m_combs, fs);
1483     }
reset()1484     void reset()
1485     {
1486         m_next = 0;
1487     }
next(VkPipelineCreateFlags & flags)1488     bool next(VkPipelineCreateFlags &flags)
1489     {
1490         if (m_next < m_combs.size())
1491         {
1492             flags = mask(m_combs[m_next++]);
1493             return true;
1494         }
1495         return false;
1496     }
combine(std::vector<FlagsSet> & result,const FlagsSet & v)1497     void combine(std::vector<FlagsSet> &result, const FlagsSet &v)
1498     {
1499         if (v.empty() || result.end() != std::find(result.begin(), result.end(), v))
1500             return;
1501         result.push_back(v);
1502         for (uint32_t i = 0; i < v.size(); ++i)
1503         {
1504             FlagsSet w(v);
1505             w.erase(std::next(w.begin(), i));
1506             combine(result, w);
1507         }
1508     }
1509 
1510 private:
1511     size_t m_next;
1512     std::vector<FlagsSet> m_combs;
1513 };
1514 const NoNullShadersFlagGenerator::BitAndName NoNullShadersFlagGenerator::bits[] = {
1515     {VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR, "any"},
1516     {VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR, "chit"},
1517     {VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR, "isect"},
1518     {VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR, "miss"},
1519 };
1520 
1521 } // namespace
1522 
createPipelineFlagsTests(tcu::TestContext & testCtx)1523 tcu::TestCaseGroup *createPipelineFlagsTests(tcu::TestContext &testCtx)
1524 {
1525     const uint32_t strides[] = {3, 5};
1526     const uint32_t offsets[] = {7};
1527 
1528     struct
1529     {
1530         bool type;
1531         const char *name;
1532     } const processors[] = {{false, "gpu"}, {true, "cpu"}};
1533     struct
1534     {
1535         bool type;
1536         const char *name;
1537     } const libs[]{{true, "use_libs"}, {false, "no_libs"}};
1538     struct
1539     {
1540         GeometryTypes type;
1541         const char *name;
1542     } const geometries[] = {{GeometryTypes::Triangle, "triangles"},
1543                             {GeometryTypes::Box, "boxes"},
1544                             {GeometryTypes::TriangleAndBox, "tri_and_box"}};
1545 
1546     NoNullShadersFlagGenerator flagsGenerator;
1547 
1548     TestParams p;
1549 #ifdef INTERNAL_DEBUG
1550     p.width    = 30;
1551     p.height   = 8;
1552     p.accuracy = 0.80f;
1553 #else
1554     p.width    = 256;
1555     p.height   = 256;
1556     p.accuracy = 0.95f;
1557 #endif
1558     p.onHhost         = false;
1559     p.useLibs         = false;
1560     p.useMaintenance5 = false;
1561     p.flags           = 0;
1562     p.geomTypes       = GeometryTypes::None;
1563     p.instCount       = 3;
1564     p.geomCount       = 2;
1565     p.stbRecStride    = 0;
1566     p.stbRecOffset    = 0;
1567 
1568     auto group = new tcu::TestCaseGroup(testCtx, "pipeline_no_null_shaders_flag");
1569 
1570     for (auto &processor : processors)
1571     {
1572         auto processorGroup = new tcu::TestCaseGroup(testCtx, processor.name);
1573 
1574         for (auto &geometry : geometries)
1575         {
1576             auto geometryGroup = new tcu::TestCaseGroup(testCtx, geometry.name);
1577 
1578             for (auto &stride : strides)
1579             {
1580                 auto strideGroup = new tcu::TestCaseGroup(testCtx, ("stride_" + std::to_string(stride)).c_str());
1581 
1582                 for (auto &offset : offsets)
1583                 {
1584                     auto offsetGroup = new tcu::TestCaseGroup(testCtx, ("offset_" + std::to_string(offset)).c_str());
1585 
1586                     for (auto &lib : libs)
1587                     {
1588                         auto libGroup = new tcu::TestCaseGroup(testCtx, lib.name);
1589 
1590                         VkPipelineCreateFlags flags;
1591 
1592                         flagsGenerator.reset();
1593 
1594                         while (flagsGenerator.next(flags))
1595                         {
1596                             if ((VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR & flags) &&
1597                                 (GeometryTypes::Triangle == geometry.type))
1598                                 continue;
1599 
1600                             p.onHhost      = processor.type;
1601                             p.geomTypes    = geometry.type;
1602                             p.stbRecStride = stride;
1603                             p.stbRecOffset = offset;
1604                             p.flags        = flags;
1605                             p.useLibs      = lib.type;
1606 
1607                             libGroup->addChild(new PipelineFlagsCase(testCtx, flagsGenerator.name(flags), p));
1608                         }
1609                         offsetGroup->addChild(libGroup);
1610                     }
1611                     strideGroup->addChild(offsetGroup);
1612                 }
1613                 geometryGroup->addChild(strideGroup);
1614             }
1615             processorGroup->addChild(geometryGroup);
1616         }
1617         group->addChild(processorGroup);
1618     }
1619 
1620     de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(testCtx, "misc"));
1621 
1622     p.onHhost         = false;
1623     p.geomTypes       = GeometryTypes::Box;
1624     p.stbRecStride    = 3;
1625     p.stbRecOffset    = 7;
1626     p.useLibs         = true;
1627     p.useMaintenance5 = true;
1628 
1629     for (const auto flag : NoNullShadersFlagGenerator::bits)
1630     {
1631         p.flags = flag.bit;
1632         miscGroup->addChild(new PipelineFlagsCase(testCtx, std::string(flag.name) + "_maintenance5", p));
1633     }
1634 
1635     group->addChild(miscGroup.release());
1636 
1637     return group;
1638 }
1639 
1640 } // namespace RayTracing
1641 } // namespace vkt
1642