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 ¢er, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms)
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 ¶ms)
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 ¶ms,
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