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