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