1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Ray Query miscellaneous tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktRayQueryMiscTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28
29 #include "vkRayTracingUtil.hpp"
30 #include "vkBufferWithMemory.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkImageWithMemory.hpp"
37 #include "vkImageUtil.hpp"
38
39 #include "tcuVector.hpp"
40 #include "tcuStringTemplate.hpp"
41 #include "tcuImageCompare.hpp"
42
43 #include "deUniquePtr.hpp"
44 #include "deRandom.hpp"
45
46 #include <sstream>
47 #include <limits>
48 #include <vector>
49 #include <map>
50
51 namespace vkt
52 {
53 namespace RayQuery
54 {
55
56 namespace
57 {
58
59 using namespace vk;
60
61 class DynamicIndexingCase : public vkt::TestCase
62 {
63 public:
64 DynamicIndexingCase(tcu::TestContext &testCtx, const std::string &name);
~DynamicIndexingCase(void)65 virtual ~DynamicIndexingCase(void)
66 {
67 }
68
69 virtual void initPrograms(vk::SourceCollections &programCollection) const override;
70 virtual void checkSupport(Context &context) const override;
71 virtual TestInstance *createInstance(Context &context) const override;
72
73 // Constants and data types.
74 static constexpr uint32_t kLocalSizeX = 48u;
75 static constexpr uint32_t kNumQueries = 48u;
76
77 // This must match the shader.
78 struct InputData
79 {
80 uint32_t goodQueryIndex;
81 uint32_t proceedQueryIndex;
82 };
83 };
84
85 class DynamicIndexingInstance : public vkt::TestInstance
86 {
87 public:
88 DynamicIndexingInstance(Context &context);
~DynamicIndexingInstance(void)89 virtual ~DynamicIndexingInstance(void)
90 {
91 }
92
93 virtual tcu::TestStatus iterate(void);
94 };
95
DynamicIndexingCase(tcu::TestContext & testCtx,const std::string & name)96 DynamicIndexingCase::DynamicIndexingCase(tcu::TestContext &testCtx, const std::string &name)
97 : vkt::TestCase(testCtx, name)
98 {
99 }
100
initPrograms(vk::SourceCollections & programCollection) const101 void DynamicIndexingCase::initPrograms(vk::SourceCollections &programCollection) const
102 {
103 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
104
105 std::ostringstream src;
106
107 src << "#version 460\n"
108 << "#extension GL_EXT_ray_query : require\n"
109 << "#extension GL_EXT_ray_tracing : require\n"
110 << "\n"
111 << "layout (local_size_x=" << kLocalSizeX << ", local_size_y=1, local_size_z=1) in; \n"
112 << "\n"
113 << "struct InputData {\n"
114 << " uint goodQueryIndex;\n"
115 << " uint proceedQueryIndex; // Note: same index as the one above in practice.\n"
116 << "};\n"
117 << "\n"
118 << "layout (set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
119 << "layout (set=0, binding=1, std430) buffer InputBlock {\n"
120 << " InputData inputData[];\n"
121 << "} inputBlock;\n"
122 << "layout (set=0, binding=2, std430) buffer OutputBlock {\n"
123 << " uint outputData[];\n"
124 << "} outputBlock;\n"
125 << "\n"
126 << "void main()\n"
127 << "{\n"
128 << " const uint numQueries = " << kNumQueries << ";\n"
129 << "\n"
130 << " const uint rayFlags = 0u; \n"
131 << " const uint cullMask = 0xFFu;\n"
132 << " const float tmin = 0.1;\n"
133 << " const float tmax = 10.0;\n"
134 << " const vec3 direct = vec3(0, 0, 1); \n"
135 << "\n"
136 << " rayQueryEXT rayQueries[numQueries];\n"
137 << " vec3 origin;\n"
138 << "\n"
139 << " InputData inputValues = inputBlock.inputData[gl_LocalInvocationID.x];\n"
140 << "\n"
141 << " // Initialize all queries. Only goodQueryIndex will have the right origin for a hit.\n"
142 << " for (int i = 0; i < numQueries; i++) {\n"
143 << " origin = ((i == inputValues.goodQueryIndex) ? vec3(0, 0, 0) : vec3(5, 5, 0));\n"
144 << " rayQueryInitializeEXT(rayQueries[i], topLevelAS, rayFlags, cullMask, origin, tmin, direct, tmax);\n"
145 << " }\n"
146 << "\n"
147 << " // Attempt to proceed with the good query to confirm a hit.\n"
148 << " while (rayQueryProceedEXT(rayQueries[inputValues.proceedQueryIndex]))\n"
149 << " outputBlock.outputData[gl_LocalInvocationID.x] = 1u; \n"
150 << "}\n";
151
152 programCollection.glslSources.add("comp") << glu::ComputeSource(updateRayTracingGLSL(src.str())) << buildOptions;
153 }
154
checkSupport(Context & context) const155 void DynamicIndexingCase::checkSupport(Context &context) const
156 {
157 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
158 context.requireDeviceFunctionality("VK_KHR_ray_query");
159
160 const auto &rayQueryFeaturesKHR = context.getRayQueryFeatures();
161 if (!rayQueryFeaturesKHR.rayQuery)
162 TCU_THROW(NotSupportedError, "Ray queries not supported");
163
164 const auto &accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
165 if (!accelerationStructureFeaturesKHR.accelerationStructure)
166 TCU_FAIL("Acceleration structures not supported but ray queries supported");
167 }
168
createInstance(Context & context) const169 vkt::TestInstance *DynamicIndexingCase::createInstance(Context &context) const
170 {
171 return new DynamicIndexingInstance(context);
172 }
173
DynamicIndexingInstance(Context & context)174 DynamicIndexingInstance::DynamicIndexingInstance(Context &context) : vkt::TestInstance(context)
175 {
176 }
177
getRndIndex(de::Random & rng,uint32_t size)178 uint32_t getRndIndex(de::Random &rng, uint32_t size)
179 {
180 DE_ASSERT(size > 0u);
181 DE_ASSERT(size <= static_cast<uint32_t>(std::numeric_limits<int>::max()));
182
183 const int iMin = 0;
184 const int iMax = static_cast<int>(size) - 1;
185
186 return static_cast<uint32_t>(rng.getInt(iMin, iMax));
187 }
188
iterate(void)189 tcu::TestStatus DynamicIndexingInstance::iterate(void)
190 {
191 using InputData = DynamicIndexingCase::InputData;
192 constexpr auto kLocalSizeX = DynamicIndexingCase::kLocalSizeX;
193 constexpr auto kNumQueries = DynamicIndexingCase::kNumQueries;
194
195 const auto &vkd = m_context.getDeviceInterface();
196 const auto device = m_context.getDevice();
197 auto &alloc = m_context.getDefaultAllocator();
198 const auto queue = m_context.getUniversalQueue();
199 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
200
201 de::Random rng(1604936737u);
202 InputData inputDataArray[kLocalSizeX];
203 uint32_t outputDataArray[kLocalSizeX];
204
205 // Prepare input buffer.
206 for (int i = 0; i < DE_LENGTH_OF_ARRAY(inputDataArray); ++i)
207 {
208 // The two values will contain the same query index.
209 inputDataArray[i].goodQueryIndex = getRndIndex(rng, kNumQueries);
210 inputDataArray[i].proceedQueryIndex = inputDataArray[i].goodQueryIndex;
211 }
212
213 const auto inputBufferSize = static_cast<VkDeviceSize>(sizeof(inputDataArray));
214 const auto inputBufferInfo = makeBufferCreateInfo(inputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
215 BufferWithMemory inputBuffer(vkd, device, alloc, inputBufferInfo, MemoryRequirement::HostVisible);
216 auto &inputBufferAlloc = inputBuffer.getAllocation();
217 void *inputBufferPtr = inputBufferAlloc.getHostPtr();
218
219 deMemcpy(inputBufferPtr, inputDataArray, static_cast<size_t>(inputBufferSize));
220 flushAlloc(vkd, device, inputBufferAlloc);
221
222 // Prepare output buffer.
223 const auto outputBufferSize = static_cast<VkDeviceSize>(sizeof(outputDataArray));
224 const auto outputBufferInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
225 BufferWithMemory outputBuffer(vkd, device, alloc, outputBufferInfo, MemoryRequirement::HostVisible);
226 auto &outputBufferAlloc = outputBuffer.getAllocation();
227 void *outputBufferPtr = outputBufferAlloc.getHostPtr();
228
229 deMemset(outputBufferPtr, 0, static_cast<size_t>(outputBufferSize));
230 flushAlloc(vkd, device, outputBufferAlloc);
231
232 // Prepare acceleration structures.
233 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
234 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
235 const auto cmdBuffer = cmdBufferPtr.get();
236 beginCommandBuffer(vkd, cmdBuffer);
237
238 de::SharedPtr<TopLevelAccelerationStructure> topLevelAS(makeTopLevelAccelerationStructure().release());
239 de::SharedPtr<BottomLevelAccelerationStructure> bottomLevelAS(makeBottomLevelAccelerationStructure().release());
240
241 // These need to match the origin and direction in the shader for a hit.
242 const std::vector<tcu::Vec3> vertices = {
243 tcu::Vec3(-1.0f, -1.0f, 1.0f), tcu::Vec3(-1.0f, 1.0f, 1.0f), tcu::Vec3(1.0f, -1.0f, 1.0f),
244
245 tcu::Vec3(-1.0f, 1.0f, 1.0f), tcu::Vec3(1.0f, 1.0f, 1.0f), tcu::Vec3(1.0f, -1.0f, 1.0f),
246 };
247
248 bottomLevelAS->addGeometry(vertices, /*triangles*/ true, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
249 bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
250
251 topLevelAS->addInstance(bottomLevelAS);
252 topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
253
254 // Descriptor set layout.
255 const VkShaderStageFlagBits stageBit = VK_SHADER_STAGE_COMPUTE_BIT;
256
257 DescriptorSetLayoutBuilder layoutBuilder;
258 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stageBit);
259 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
260 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
261 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
262
263 // Shader module.
264 const auto shaderModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
265
266 // Pipeline layout.
267 const auto pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
268
269 const VkPipelineShaderStageCreateInfo shaderStageInfo = {
270 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
271 nullptr, // const void* pNext;
272 0u, // VkPipelineShaderStageCreateFlags flags;
273 stageBit, // VkShaderStageFlagBits stage;
274 shaderModule.get(), // VkShaderModule module;
275 "main", // const char* pName;
276 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
277 };
278
279 const VkComputePipelineCreateInfo pipelineInfo = {
280 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
281 nullptr, // const void* pNext;
282 0u, // VkPipelineCreateFlags flags;
283 shaderStageInfo, // VkPipelineShaderStageCreateInfo stage;
284 pipelineLayout.get(), // VkPipelineLayout layout;
285 VK_NULL_HANDLE, // VkPipeline basePipelineHandle;
286 0, // int32_t basePipelineIndex;
287 };
288
289 const auto pipeline = createComputePipeline(vkd, device, VK_NULL_HANDLE, &pipelineInfo);
290
291 // Create and update descriptor set.
292 DescriptorPoolBuilder poolBuilder;
293 poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
294 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u);
295
296 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
297 const auto descriptorSetPtr = makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
298 const auto descriptorSet = descriptorSetPtr.get();
299
300 const VkWriteDescriptorSetAccelerationStructureKHR asWrite = {
301 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
302 nullptr, // const void* pNext;
303 1u, // uint32_t accelerationStructureCount;
304 topLevelAS->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures;
305 };
306
307 const auto inputBufferWriteInfo = makeDescriptorBufferInfo(inputBuffer.get(), 0ull, inputBufferSize);
308 const auto outputBufferWriteInfo = makeDescriptorBufferInfo(outputBuffer.get(), 0ull, outputBufferSize);
309
310 DescriptorSetUpdateBuilder updateBuilder;
311 updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
312 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &asWrite);
313 updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
314 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputBufferWriteInfo);
315 updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u),
316 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferWriteInfo);
317 updateBuilder.update(vkd, device);
318
319 // Use pipeline.
320 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
321 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet,
322 0u, nullptr);
323 vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
324
325 const auto memBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
326 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u,
327 &memBarrier, 0u, nullptr, 0u, nullptr);
328
329 // Submit recorded commands.
330 endCommandBuffer(vkd, cmdBuffer);
331 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
332
333 // Check output buffer.
334 invalidateAlloc(vkd, device, outputBufferAlloc);
335 deMemcpy(outputDataArray, outputBufferPtr, static_cast<size_t>(outputBufferSize));
336
337 for (int i = 0; i < DE_LENGTH_OF_ARRAY(outputDataArray); ++i)
338 {
339 constexpr auto expected = 1u;
340 const auto &value = outputDataArray[i];
341
342 if (value != expected)
343 {
344 std::ostringstream msg;
345 msg << "Unexpected value found at position " << i << " in the output buffer: expected " << expected
346 << " but found " << value;
347 TCU_FAIL(msg.str());
348 }
349 }
350
351 return tcu::TestStatus::pass("Pass");
352 }
353
354 using namespace tcu;
355
356 struct HelperInvocationsParamDefs
357 {
358 enum DfStyle
359 {
360 Regular,
361 Coarse,
362 Fine
363 };
364
365 enum FuncType
366 {
367 LINEAR,
368 QUADRATIC,
369 CUBIC
370 };
371
372 typedef float (*F1D)(float);
373 struct func2D_t
374 {
375 F1D first;
376 F1D second;
377 };
378 struct func2D_mask
379 {
380 FuncType first;
381 FuncType second;
382 };
383 struct test_mode_t
384 {
385 func2D_t funcs;
386 func2D_mask types;
387 };
388
linearvkt::RayQuery::__anon32f5a9fb0111::HelperInvocationsParamDefs389 static float linear(float x)
390 {
391 return x;
392 }
quadraticvkt::RayQuery::__anon32f5a9fb0111::HelperInvocationsParamDefs393 static float quadratic(float x)
394 {
395 return (x * x);
396 }
cubicvkt::RayQuery::__anon32f5a9fb0111::HelperInvocationsParamDefs397 static float cubic(float x)
398 {
399 return (x * x * x * 0.5f);
400 }
401
combinevkt::RayQuery::__anon32f5a9fb0111::HelperInvocationsParamDefs402 static float combine(const func2D_t &f2D, float x, float y)
403 {
404 DE_ASSERT((f2D.first) && (f2D.second));
405 const float z = ((*f2D.first)(x) + (*f2D.second)(y)) / 2.0f;
406 return z;
407 }
408
409 static constexpr func2D_t FUNC_LINEAR_QUADRATIC = {linear, quadratic};
410 static constexpr func2D_t FUNC_LINEAR_CUBIC = {linear, cubic};
411 static constexpr func2D_t FUNC_CUBIC_QUADRATIC = {cubic, quadratic};
412 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
413 static constexpr func2D_t FUNC_LINEAR_LINEAR = {linear, linear};
414 static constexpr func2D_t FUNC_QUADRATIC_LINEAR = {quadratic, linear};
415 static constexpr func2D_t FUNC_QUADRATIC_QUADRATIC = {quadratic, quadratic};
416 static constexpr func2D_t FUNC_QUADRATIC_CUBIC = {quadratic, cubic};
417 static constexpr func2D_t FUNC_CUBIC_LINEAR = {cubic, linear};
418 static constexpr func2D_t FUNC_CUBIC_CUBIC = {cubic, cubic};
419 #endif
420
421 static constexpr func2D_mask MASK_LINEAR_QUADRATIC = {LINEAR, QUADRATIC};
422 static constexpr func2D_mask MASK_LINEAR_CUBIC = {LINEAR, CUBIC};
423 static constexpr func2D_mask MASK_CUBIC_QUADRATIC = {CUBIC, QUADRATIC};
424 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
425 static constexpr func2D_mask MASK_LINEAR_LINEAR = {LINEAR, LINEAR};
426 static constexpr func2D_mask MASK_QUADRATIC_LINEAR = {QUADRATIC, LINEAR};
427 static constexpr func2D_mask MASK_QUADRATIC_QUADRATIC = {QUADRATIC, QUADRATIC};
428 static constexpr func2D_mask MASK_QUADRATIC_CUBIC = {QUADRATIC, CUBIC};
429 static constexpr func2D_mask MASK_CUBIC_LINEAR = {CUBIC, LINEAR};
430 static constexpr func2D_mask MASK_CUBIC_CUBIC = {CUBIC, CUBIC};
431 #endif
432
433 static constexpr test_mode_t MODE_LINEAR_QUADRATIC = {FUNC_LINEAR_QUADRATIC, MASK_LINEAR_QUADRATIC};
434 static constexpr test_mode_t MODE_LINEAR_CUBIC = {FUNC_LINEAR_CUBIC, MASK_LINEAR_CUBIC};
435 static constexpr test_mode_t MODE_CUBIC_QUADRATIC = {FUNC_CUBIC_QUADRATIC, MASK_CUBIC_QUADRATIC};
436 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
437 static constexpr test_mode_t MODE_LINEAR_LINEAR = {FUNC_LINEAR_LINEAR, MASK_LINEAR_LINEAR};
438 static constexpr test_mode_t MODE_QUADRATIC_LINEAR = {FUNC_QUADRATIC_LINEAR, MASK_QUADRATIC_LINEAR};
439 static constexpr test_mode_t MODE_QUADRATIC_QUADRATIC = {FUNC_QUADRATIC_QUADRATIC, MASK_QUADRATIC_QUADRATIC};
440 static constexpr test_mode_t MODE_QUADRATIC_CUBIC = {FUNC_QUADRATIC_CUBIC, MASK_QUADRATIC_CUBIC};
441 static constexpr test_mode_t MODE_CUBIC_LINEAR = {FUNC_CUBIC_LINEAR, MASK_CUBIC_LINEAR};
442 static constexpr test_mode_t MODE_CUBIC_CUBIC = {FUNC_CUBIC_CUBIC, MASK_CUBIC_CUBIC};
443 #endif
444 };
445
446 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_QUADRATIC;
447 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_CUBIC;
448 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_QUADRATIC;
449 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
450 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_LINEAR;
451 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_LINEAR;
452 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_QUADRATIC;
453 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_CUBIC;
454 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_LINEAR;
455 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_CUBIC;
456 #endif
457
458 struct HelperInvocationsParams : HelperInvocationsParamDefs
459 {
460 test_mode_t mode;
461 std::pair<uint32_t, uint32_t> screen;
462 std::pair<uint32_t, uint32_t> model;
463 DfStyle style;
464 bool buildGPU;
465 };
466
467 class HelperInvocationsCase : public TestCase
468 {
469 public:
470 HelperInvocationsCase(TestContext &testCtx, const HelperInvocationsParams ¶ms, const std::string &name);
471 virtual void initPrograms(SourceCollections &programs) const override;
472 virtual TestInstance *createInstance(Context &context) const override;
473 virtual void checkSupport(Context &context) const override;
474
475 private:
476 HelperInvocationsParams m_params;
477 };
478
479 class HelperInvocationsInstance : public TestInstance
480 {
481 public:
482 typedef de::MovePtr<TopLevelAccelerationStructure> TopLevelAccelerationStructurePtr;
483 enum Points
484 {
485 Vertices,
486 Coords,
487 Centers
488 };
489
490 HelperInvocationsInstance(Context &context, const HelperInvocationsParams ¶ms);
491 virtual TestStatus iterate(void) override;
492 static auto createSurface(const Points points, const uint32_t divX, const uint32_t divY,
493 const HelperInvocationsParams::func2D_t &f2D, bool clockWise = false)
494 -> std::vector<Vec3>;
495 VkImageCreateInfo makeImgInfo(uint32_t queueFamilyIndexCount, const uint32_t *pQueueFamilyIndices) const;
496 Move<VkPipeline> makePipeline(const DeviceInterface &vk, const VkDevice device,
497 const VkPipelineLayout pipelineLayout, const VkShaderModule vertexShader,
498 const VkShaderModule fragmentShader, const VkRenderPass renderPass) const;
499 auto makeResultBuff(const DeviceInterface &vk, const VkDevice device, Allocator &allocator) const
500 -> de::MovePtr<BufferWithMemory>;
501 auto makeAttribBuff(const DeviceInterface &vk, const VkDevice device, Allocator &allocator,
502 const std::vector<Vec3> &vertices, const std::vector<Vec3> &coords,
503 const std::vector<Vec3> ¢ers) const -> de::MovePtr<BufferWithMemory>;
504 auto createAccStructs(const DeviceInterface &vk, const VkDevice device, Allocator &allocator,
505 const VkCommandBuffer cmdBuffer, const std::vector<Vec3> coords) const
506 -> TopLevelAccelerationStructurePtr;
507
508 protected:
509 bool verifyResult(const DeviceInterface &vk, const VkDevice device, const BufferWithMemory &buffer) const;
510 bool onlyPipeline();
511
512 private:
513 VkFormat m_format;
514 HelperInvocationsParams m_params;
515 };
516
HelperInvocationsCase(TestContext & testCtx,const HelperInvocationsParams & params,const std::string & name)517 HelperInvocationsCase::HelperInvocationsCase(TestContext &testCtx, const HelperInvocationsParams ¶ms,
518 const std::string &name)
519 : TestCase(testCtx, name)
520 , m_params(params)
521 {
522 }
523
createInstance(Context & context) const524 TestInstance *HelperInvocationsCase::createInstance(Context &context) const
525 {
526 return new HelperInvocationsInstance(context, m_params);
527 }
528
checkSupport(Context & context) const529 void HelperInvocationsCase::checkSupport(Context &context) const
530 {
531 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
532 context.requireDeviceFunctionality("VK_KHR_ray_query");
533
534 const auto &rayQueryFeaturesKHR = context.getRayQueryFeatures();
535 const auto &accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
536
537 if (!rayQueryFeaturesKHR.rayQuery)
538 TCU_THROW(NotSupportedError, "Ray queries not supported");
539
540 if (!accelerationStructureFeaturesKHR.accelerationStructure)
541 TCU_THROW(NotSupportedError, "Acceleration structures not supported but ray queries supported");
542
543 if (m_params.buildGPU == false && accelerationStructureFeaturesKHR.accelerationStructureHostCommands == false)
544 TCU_THROW(NotSupportedError,
545 "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR::accelerationStructureHostCommands");
546 }
547
initPrograms(SourceCollections & programs) const548 void HelperInvocationsCase::initPrograms(SourceCollections &programs) const
549 {
550 const ShaderBuildOptions buildOptions(programs.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
551
552 std::string vertexCode(
553 R"(
554 #version 460
555 #extension GL_EXT_ray_query : require
556 #extension GL_EXT_ray_tracing : require
557
558 layout(location = 0) in vec3 pos;
559 layout(location = 1) in vec3 inCoord;
560 layout(location = 2) in vec3 inCenter;
561 layout(location = 0) out vec3 outCoord;
562 layout(location = 1) out vec3 outCenter;
563
564 void main()
565 {
566 gl_PointSize = 1.0;
567 gl_Position = vec4(pos.xyz, 1.0);
568 outCoord = inCoord;
569 outCenter = inCenter;
570 }
571 )");
572 programs.glslSources.add("vert") << glu::VertexSource(vertexCode) << buildOptions;
573
574 StringTemplate fragmentCode(
575 R"(
576 #version 460
577 #extension GL_EXT_ray_query : require
578 #extension GL_EXT_ray_tracing : require
579
580 #define LINEAR 0
581 #define QUADRATIC 1
582 #define CUBIC 2
583
584 layout(push_constant) uniform PC {
585 int fun_x;
586 int fun_y;
587 float width;
588 float height;
589 } params;
590 layout(location = 0) in vec3 coord;
591 layout(location = 1) in vec3 center;
592 layout(location = 0) out vec4 color;
593 layout(set = 0, binding = 0) uniform accelerationStructureEXT topLevelAS;
594
595 float d_linear (in float t) { return 0.5; } // (x/2)'
596 float d_quadratic(in float t) { return t; } // (x^2/2)'
597 float d_cubic (in float t) { return 0.75 * t * t; } // (x^3/4)'
598
599 float derivate(in int fun, in float u)
600 {
601 switch (fun)
602 {
603 case LINEAR: return d_linear(u);
604 case QUADRATIC: return d_quadratic(u);
605 case CUBIC: return d_cubic(u);
606 }
607 return -1.0;
608 }
609 void main()
610 {
611 const uint rayFlags = 0u;
612 const uint cullMask = 0xFFu;
613 const float tmin = 0.0;
614 const float tmax = 10.0;
615 const vec3 direct = vec3(0.0, 0.0, 1.0);
616 const vec3 origin = vec3(center.x, center.y, -1.0);
617
618 rayQueryEXT query;
619 rayQueryInitializeEXT(query, topLevelAS, rayFlags, cullMask, origin, tmin, direct, tmax);
620
621 color = vec4(-1.0, -1.0, -1.0, -1.0);
622
623 while (rayQueryProceedEXT(query)) {
624 if (rayQueryGetIntersectionTypeEXT(query, false)
625 == gl_RayQueryCandidateIntersectionTriangleEXT)
626 {
627 float vx = derivate(params.fun_x, coord.x);
628 float vy = derivate(params.fun_y, coord.y);
629 float dx = ${DFDX}(coord.x);
630 float dy = ${DFDY}(coord.y);
631 float dzx = ${DFDX}(coord.z);
632 float dzy = ${DFDY}(coord.z);
633 float dfx = dzx / dx;
634 float dfy = dzy / dy;
635 float cx = dfx - vx;
636 float cy = dfy - vy;
637
638 color = vec4(cx, cy, sign(dx-abs(cx)), sign(dy-abs(cy)));
639 }
640 else
641 {
642 color = vec4(0.0, 0.0, -1.0, -1.0);
643 }
644 rayQueryConfirmIntersectionEXT(query);
645 }
646 })");
647
648 std::map<std::string, std::string> m;
649 switch (m_params.style)
650 {
651 case HelperInvocationsParams::DfStyle::Regular:
652 m["DFDX"] = "dFdx";
653 m["DFDY"] = "dFdy";
654 break;
655 case HelperInvocationsParams::DfStyle::Coarse:
656 m["DFDX"] = "dFdxCoarse";
657 m["DFDY"] = "dFdyCoarse";
658 break;
659 case HelperInvocationsParams::DfStyle::Fine:
660 m["DFDX"] = "dFdxFine";
661 m["DFDY"] = "dFdyFine";
662 break;
663 }
664
665 programs.glslSources.add("frag") << glu::FragmentSource(fragmentCode.specialize(m)) << buildOptions;
666 }
667
HelperInvocationsInstance(Context & context,const HelperInvocationsParams & params)668 HelperInvocationsInstance::HelperInvocationsInstance(Context &context, const HelperInvocationsParams ¶ms)
669 : TestInstance(context)
670 , m_format(VK_FORMAT_R32G32B32A32_SFLOAT)
671 , m_params(params)
672 {
673 }
674
createSurface(const Points points,const uint32_t divX,const uint32_t divY,const HelperInvocationsParams::func2D_t & f2D,bool clockWise)675 std::vector<Vec3> HelperInvocationsInstance::createSurface(const Points points, const uint32_t divX,
676 const uint32_t divY,
677 const HelperInvocationsParams::func2D_t &f2D, bool clockWise)
678 {
679 std::vector<Vec3> s;
680 const float dx = (points == Points::Vertices ? 2.0f : 1.0f) / float(divX);
681 const float dy = (points == Points::Vertices ? 2.0f : 1.0f) / float(divY);
682 // Z is always scaled to range (0,1)
683 auto z = [&](const uint32_t n, const uint32_t m) -> float
684 {
685 const float x = float(n) / float(divX);
686 const float y = float(m) / float(divY);
687 return HelperInvocationsParams::combine(f2D, x, y);
688 };
689 float y = (points == Points::Vertices) ? -1.0f : 0.0f;
690 for (uint32_t j = 0; j < divY; ++j)
691 {
692 const float ny = ((j + 1) < divY) ? (y + dy) : 1.f;
693 float x = (points == Points::Vertices) ? -1.0f : 0.0f;
694
695 for (uint32_t i = 0; i < divX; ++i)
696 {
697 const float nx = ((i + 1) < divX) ? (x + dx) : 1.f;
698
699 const Vec3 p0(x, y, z(i, j));
700 const Vec3 p1(nx, y, z(i + 1, j));
701 const Vec3 p2(nx, ny, z(i + 1, j + 1));
702 const Vec3 p3(x, ny, z(i, j + 1));
703
704 if (points == Points::Centers)
705 {
706 const float cx1 = (p0.x() + p1.x() + p2.x()) / 3.0f;
707 const float cy1 = (p0.y() + p1.y() + p2.y()) / 3.0f;
708 const float cz1 = (p0.z() + p1.z() + p2.z()) / 3.0f;
709 const float cx2 = (p0.x() + p2.x() + p3.x()) / 3.0f;
710 const float cy2 = (p0.y() + p2.y() + p3.y()) / 3.0f;
711 const float cz2 = (p0.z() + p2.z() + p3.z()) / 3.0f;
712
713 s.emplace_back(cx1, cy1, cz1);
714 s.emplace_back(cx1, cy1, cz1);
715 s.emplace_back(cx1, cy1, cz1);
716 s.emplace_back(cx2, cy2, cz2);
717 s.emplace_back(cx2, cy2, cz2);
718 s.emplace_back(cx2, cy2, cz2);
719 }
720 else if (clockWise)
721 {
722 s.push_back(p0);
723 s.push_back(p3);
724 s.push_back(p2);
725 s.push_back(p0);
726 s.push_back(p2);
727 s.push_back(p1);
728 }
729 else
730 {
731 s.push_back(p0);
732 s.push_back(p1);
733 s.push_back(p2);
734 s.push_back(p2);
735 s.push_back(p3);
736 s.push_back(p0);
737 }
738
739 x = nx;
740 }
741 y = ny;
742 }
743 return s;
744 }
745
makeImgInfo(uint32_t queueFamilyIndexCount,const uint32_t * pQueueFamilyIndices) const746 VkImageCreateInfo HelperInvocationsInstance::makeImgInfo(uint32_t queueFamilyIndexCount,
747 const uint32_t *pQueueFamilyIndices) const
748 {
749 const VkImageUsageFlags usage =
750 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
751 return {
752 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType;
753 nullptr, // pNext;
754 VkImageCreateFlags(0), // flags;
755 VK_IMAGE_TYPE_2D, // imageType;
756 m_format, // format;
757 {m_params.screen.first, m_params.screen.second, 1u}, // extent;
758 1u, // mipLevels;
759 1u, // arrayLayers;
760 VK_SAMPLE_COUNT_1_BIT, // samples;
761 VK_IMAGE_TILING_OPTIMAL, // tiling;
762 usage, // usage;
763 VK_SHARING_MODE_EXCLUSIVE, // sharingMode;
764 queueFamilyIndexCount, // queueFamilyIndexCount;
765 pQueueFamilyIndices, // pQueueFamilyIndices;
766 VK_IMAGE_LAYOUT_UNDEFINED // initialLayout;
767 };
768 }
769
makePipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkShaderModule vertexShader,const VkShaderModule fragmentShader,const VkRenderPass renderPass) const770 Move<VkPipeline> HelperInvocationsInstance::makePipeline(const DeviceInterface &vk, const VkDevice device,
771 const VkPipelineLayout pipelineLayout,
772 const VkShaderModule vertexShader,
773 const VkShaderModule fragmentShader,
774 const VkRenderPass renderPass) const
775 {
776 DE_ASSERT(sizeof(Vec3) == mapVkFormat(VK_FORMAT_R32G32B32_SFLOAT).getPixelSize());
777
778 const std::vector<VkViewport> viewports{makeViewport(m_params.screen.first, m_params.screen.second)};
779 const std::vector<VkRect2D> scissors{makeRect2D(m_params.screen.first, m_params.screen.second)};
780
781 const VkVertexInputBindingDescription vertexInputBindingDescription{
782 0u, // uint32_t binding
783 uint32_t(sizeof(Vec3) * 3u), // uint32_t stride
784 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate
785 };
786
787 const VkVertexInputAttributeDescription vertexInputAttributeDescription[]{
788 {
789 0u, // uint32_t location
790 0u, // uint32_t binding
791 VK_FORMAT_R32G32B32_SFLOAT, // VkFormat format
792 0u // uint32_t offset
793 }, // vertices
794 {
795 1u, // uint32_t location
796 0u, // uint32_t binding
797 VK_FORMAT_R32G32B32_SFLOAT, // VkFormat format
798 uint32_t(sizeof(Vec3)) // uint32_t offset
799 }, // coords
800 {
801 2u, // uint32_t location
802 0u, // uint32_t binding
803 VK_FORMAT_R32G32B32_SFLOAT, // VkFormat format
804 uint32_t(sizeof(Vec3) * 2u) // uint32_t offset
805 } // centers
806 };
807
808 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
809 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
810 nullptr, // const void* pNext
811 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags
812 1u, // uint32_t vertexBindingDescriptionCount
813 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
814 DE_LENGTH_OF_ARRAY(
815 vertexInputAttributeDescription), // uint32_t vertexAttributeDescriptionCount
816 vertexInputAttributeDescription // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
817 };
818
819 return makeGraphicsPipeline(vk, device, pipelineLayout, vertexShader, VK_NULL_HANDLE, VK_NULL_HANDLE,
820 VK_NULL_HANDLE, fragmentShader, renderPass, viewports, scissors,
821 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, &vertexInputStateCreateInfo);
822 }
823
createAccStructs(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const VkCommandBuffer cmdBuffer,const std::vector<Vec3> coords) const824 de::MovePtr<TopLevelAccelerationStructure> HelperInvocationsInstance::createAccStructs(
825 const DeviceInterface &vk, const VkDevice device, Allocator &allocator, const VkCommandBuffer cmdBuffer,
826 const std::vector<Vec3> coords) const
827 {
828 const VkAccelerationStructureBuildTypeKHR buildType = m_params.buildGPU ?
829 VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR :
830 VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR;
831 de::MovePtr<TopLevelAccelerationStructure> tlas = makeTopLevelAccelerationStructure();
832 de::MovePtr<BottomLevelAccelerationStructure> blas = makeBottomLevelAccelerationStructure();
833
834 blas->setBuildType(buildType);
835 blas->addGeometry(coords, true, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
836 blas->createAndBuild(vk, device, cmdBuffer, allocator);
837
838 tlas->setBuildType(buildType);
839 tlas->addInstance(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
840 tlas->createAndBuild(vk, device, cmdBuffer, allocator);
841
842 return tlas;
843 }
844
makeAttribBuff(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const std::vector<Vec3> & vertices,const std::vector<Vec3> & coords,const std::vector<Vec3> & centers) const845 de::MovePtr<BufferWithMemory> HelperInvocationsInstance::makeAttribBuff(const DeviceInterface &vk,
846 const VkDevice device, Allocator &allocator,
847 const std::vector<Vec3> &vertices,
848 const std::vector<Vec3> &coords,
849 const std::vector<Vec3> ¢ers) const
850 {
851 DE_ASSERT(sizeof(Vec3) == mapVkFormat(VK_FORMAT_R32G32B32_SFLOAT).getPixelSize());
852 const uint32_t count = uint32_t(vertices.size());
853 DE_ASSERT(count && (count == coords.size()) && (count == centers.size()));
854 const VkDeviceSize bufferSize = 3 * count * sizeof(Vec3);
855 const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
856 de::MovePtr<BufferWithMemory> buffer(new BufferWithMemory(
857 vk, device, allocator, bufferCreateInfo, MemoryRequirement::Coherent | MemoryRequirement::HostVisible));
858
859 Allocation &allocation = buffer->getAllocation();
860 Vec3 *data = static_cast<Vec3 *>(allocation.getHostPtr());
861 for (uint32_t c = 0; c < count; ++c)
862 {
863 data[3 * c] = vertices.at(c);
864 data[3 * c + 1] = coords.at(c);
865 data[3 * c + 2] = centers.at(c);
866 }
867 flushMappedMemoryRange(vk, device, allocation.getMemory(), 0u, bufferSize);
868
869 return buffer;
870 }
871
makeResultBuff(const DeviceInterface & vk,const VkDevice device,Allocator & allocator) const872 de::MovePtr<BufferWithMemory> HelperInvocationsInstance::makeResultBuff(const DeviceInterface &vk,
873 const VkDevice device,
874 Allocator &allocator) const
875 {
876 const TextureFormat texFormat = mapVkFormat(m_format);
877 const VkDeviceSize bufferSize = (m_params.screen.first * m_params.screen.second * texFormat.getPixelSize());
878 const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
879 de::MovePtr<BufferWithMemory> buffer(new BufferWithMemory(
880 vk, device, allocator, bufferCreateInfo, MemoryRequirement::Coherent | MemoryRequirement::HostVisible));
881
882 Allocation &allocation = buffer->getAllocation();
883 PixelBufferAccess pixels(texFormat, m_params.screen.first, m_params.screen.second, 1u, allocation.getHostPtr());
884
885 for (uint32_t y = 0; y < m_params.screen.second; ++y)
886 {
887 for (uint32_t x = 0; x < m_params.screen.first; ++x)
888 {
889 pixels.setPixel(Vec4(0.0f, 0.0f, 0.0f, -1.0f), x, y);
890 }
891 }
892 flushMappedMemoryRange(vk, device, allocation.getMemory(), 0u, bufferSize);
893
894 return buffer;
895 }
896
verifyResult(const DeviceInterface & vk,const VkDevice device,const BufferWithMemory & buffer) const897 bool HelperInvocationsInstance::verifyResult(const DeviceInterface &vk, const VkDevice device,
898 const BufferWithMemory &buffer) const
899 {
900 int invalid = 0;
901 Allocation &alloc = buffer.getAllocation();
902 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), 0u, VK_WHOLE_SIZE);
903 ConstPixelBufferAccess pixels(mapVkFormat(m_format), m_params.screen.first, m_params.screen.second, 1u,
904 alloc.getHostPtr());
905
906 for (uint32_t y = 0; y < m_params.screen.second; ++y)
907 {
908 for (uint32_t x = 0; x < m_params.screen.first; ++x)
909 {
910 const Vec4 px = pixels.getPixel(x, y);
911 if (px.z() < 0.0f || px.w() < 0.0f)
912 invalid += 1;
913 }
914 }
915
916 return (0 == invalid);
917 }
918
makeAccStructDescriptorWrite(const VkAccelerationStructureKHR * ptr,uint32_t count=1u)919 VkWriteDescriptorSetAccelerationStructureKHR makeAccStructDescriptorWrite(const VkAccelerationStructureKHR *ptr,
920 uint32_t count = 1u)
921 {
922 return {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
923 nullptr, // const void* pNext;
924 count, // uint32_t accelerationStructureCount;
925 ptr}; // const VkAccelerationStructureKHR* pAccelerationStructures;
926 };
927
iterate(void)928 TestStatus HelperInvocationsInstance::iterate(void)
929 {
930 const VkDevice device = m_context.getDevice();
931 const DeviceInterface &vk = m_context.getDeviceInterface();
932 Allocator &allocator = m_context.getDefaultAllocator();
933 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
934 const VkQueue queue = m_context.getUniversalQueue();
935
936 const VkRect2D renderArea = makeRect2D(m_params.screen.first, m_params.screen.second);
937 const VkImageCreateInfo imageCreateInfo = makeImgInfo(1, &queueFamilyIndex);
938 const de::MovePtr<ImageWithMemory> image(
939 new ImageWithMemory(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
940 const VkImageSubresourceRange imageSubresourceRange =
941 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
942 const Move<VkImageView> view =
943 makeImageView(vk, device, **image, VK_IMAGE_VIEW_TYPE_2D, m_format, imageSubresourceRange);
944 const Move<VkRenderPass> renderPass = makeRenderPass(vk, device, m_format);
945 const Move<VkFramebuffer> frameBuffer =
946 makeFramebuffer(vk, device, *renderPass, *view, m_params.screen.first, m_params.screen.second);
947 const de::MovePtr<BufferWithMemory> resultBuffer = makeResultBuff(vk, device, allocator);
948 const VkImageSubresourceLayers imageSubresourceLayers =
949 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
950 const VkBufferImageCopy bufferCopyImageRegion = makeBufferImageCopy(
951 makeExtent3D(UVec3(m_params.screen.first, m_params.screen.second, 1u)), imageSubresourceLayers);
952
953 const HelperInvocationsParams::func2D_t funcs = m_params.mode.funcs;
954 struct PushConstants
955 {
956 int fun_x, fun_y;
957 float width, height;
958 } const pushConstants{m_params.mode.types.first, m_params.mode.types.second, (float)m_params.screen.first,
959 (float)m_params.screen.second};
960 const VkPushConstantRange pushConstantRange{VK_SHADER_STAGE_FRAGMENT_BIT, 0u, uint32_t(sizeof(pushConstants))};
961 const std::vector<Vec3> vertices =
962 createSurface(Points::Vertices, m_params.model.first, m_params.model.second, funcs);
963 const std::vector<Vec3> coords = createSurface(Points::Coords, m_params.model.first, m_params.model.second, funcs);
964 const std::vector<Vec3> centers =
965 createSurface(Points::Centers, m_params.model.first, m_params.model.second, funcs);
966 const de::MovePtr<BufferWithMemory> attribBuffer = makeAttribBuff(vk, device, allocator, vertices, coords, centers);
967
968 TopLevelAccelerationStructurePtr topAccStruct{};
969 Move<VkDescriptorSetLayout> descriptorLayout =
970 DescriptorSetLayoutBuilder()
971 .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_FRAGMENT_BIT)
972 .build(vk, device);
973 Move<VkDescriptorPool> descriptorPool =
974 DescriptorPoolBuilder()
975 .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
976 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
977 Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorLayout);
978
979 Move<VkShaderModule> vertexShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
980 Move<VkShaderModule> fragmentShader =
981 createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
982 Move<VkPipelineLayout> pipelineLayout =
983 makePipelineLayout(vk, device, 1u, &descriptorLayout.get(), 1u, &pushConstantRange);
984 Move<VkPipeline> pipeline = makePipeline(vk, device, *pipelineLayout, *vertexShader, *fragmentShader, *renderPass);
985 const Move<VkCommandPool> cmdPool =
986 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
987 const Move<VkCommandBuffer> cmdBuffer =
988 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
989
990 const Vec4 clearColor(0.1f, 0.2f, 0.3f, 0.4f);
991 const VkImageMemoryBarrier postDrawImageBarrier = makeImageMemoryBarrier(
992 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
993 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **image, imageSubresourceRange);
994 const VkMemoryBarrier postCopyMemoryBarrier =
995 makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
996
997 beginCommandBuffer(vk, *cmdBuffer, 0u);
998
999 topAccStruct = createAccStructs(vk, device, allocator, *cmdBuffer, coords);
1000 const auto accStructWrite = makeAccStructDescriptorWrite(topAccStruct->getPtr());
1001 DescriptorSetUpdateBuilder()
1002 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1003 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accStructWrite)
1004 .update(vk, device);
1005
1006 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1007 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &static_cast<const VkBuffer &>(**attribBuffer),
1008 &static_cast<const VkDeviceSize &>(0u));
1009 vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, uint32_t(sizeof(pushConstants)),
1010 &pushConstants);
1011 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(),
1012 0u, nullptr);
1013
1014 beginRenderPass(vk, *cmdBuffer, *renderPass, *frameBuffer, renderArea, clearColor);
1015 vk.cmdDraw(*cmdBuffer, uint32_t(vertices.size()), 1u, 0u, 0u);
1016 endRenderPass(vk, *cmdBuffer);
1017
1018 cmdPipelineImageMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1019 &postDrawImageBarrier);
1020 vk.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer, 1u,
1021 &bufferCopyImageRegion);
1022 cmdPipelineMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
1023 &postCopyMemoryBarrier);
1024
1025 endCommandBuffer(vk, *cmdBuffer);
1026
1027 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1028
1029 return verifyResult(vk, device, *resultBuffer) ? TestStatus::pass("") : TestStatus::fail("");
1030 }
1031
checkReuseScratchBufferSupport(Context & context)1032 void checkReuseScratchBufferSupport(Context &context)
1033 {
1034 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
1035 context.requireDeviceFunctionality("VK_KHR_ray_query");
1036 }
1037
initReuseScratchBufferPrograms(vk::SourceCollections & programCollection)1038 void initReuseScratchBufferPrograms(vk::SourceCollections &programCollection)
1039 {
1040 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
1041
1042 std::ostringstream vert;
1043 vert << "#version 460\n"
1044 << "layout (location=0) in vec4 inPos;\n"
1045 << "void main(void) {\n"
1046 << " gl_Position = inPos;\n"
1047 << "}\n";
1048 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str()) << buildOptions;
1049
1050 std::ostringstream frag;
1051 frag << "#version 460\n"
1052 << "#extension GL_EXT_ray_query : enable\n"
1053 << "layout (location=0) out vec4 outColor;\n"
1054 << "layout (set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
1055 << "void main(void) {\n"
1056 << " const float tMin = 1.0;\n"
1057 << " const float tMax = 10.0;\n"
1058 << " const uint cullMask = 0xFFu;\n"
1059 << " const vec3 origin = vec3(gl_FragCoord.xy, 0.0);\n"
1060 << " const vec3 direction = vec3(0.0, 0.0, 1.0);\n"
1061 << " const uint rayFlags = gl_RayFlagsNoneEXT;\n"
1062 << " vec4 colorValue = vec4(0.0, 0.0, 0.0, 1.0);\n"
1063 << " bool intersectionFound = false;\n"
1064 << " rayQueryEXT query;\n"
1065 << " rayQueryInitializeEXT(query, topLevelAS, rayFlags, cullMask, origin, tMin, direction, tMax);\n"
1066 << " while (rayQueryProceedEXT(query)) {\n"
1067 << " const uint candidateType = rayQueryGetIntersectionTypeEXT(query, false);\n"
1068 << " if (candidateType == gl_RayQueryCandidateIntersectionTriangleEXT ||\n"
1069 << " candidateType == gl_RayQueryCandidateIntersectionAABBEXT) {\n"
1070 << " intersectionFound = true;\n"
1071 << " }\n"
1072 << " }\n"
1073 << " if (intersectionFound) {\n"
1074 << " colorValue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1075 << " }\n"
1076 << " outColor = colorValue;\n"
1077 << "}\n";
1078 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()) << buildOptions;
1079 }
1080
reuseScratchBufferInstance(Context & context)1081 tcu::TestStatus reuseScratchBufferInstance(Context &context)
1082 {
1083 const auto ctx = context.getContextCommonData();
1084 const tcu::IVec3 extent(256, 256, 1);
1085 const auto extentU = extent.asUint();
1086 const auto pixelCount = extentU.x() * extentU.y() * extentU.z();
1087 const auto apiExtent = makeExtent3D(extent);
1088 const uint32_t blasCount = 2u; // Number of bottom-level acceleration structures.
1089 const uint32_t rowsPerAS = extentU.y() / blasCount; // The last one could be larger but not in practice.
1090 const float coordMargin = 0.25f;
1091 const uint32_t perTriangleVertices = 3u;
1092 const uint32_t randomSeed = 1722347394u;
1093 const float geometryZ = 5.0f; // Must be between tMin and tMax in the shaders.
1094
1095 const CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
1096 const auto cmdBuffer = *cmd.cmdBuffer;
1097 beginCommandBuffer(ctx.vkd, cmdBuffer);
1098
1099 // Create a pseudorandom mask for coverage.
1100 de::Random rnd(randomSeed);
1101 std::vector<bool> coverageMask;
1102 coverageMask.reserve(pixelCount);
1103 for (int y = 0; y < extent.y(); ++y)
1104 for (int x = 0; x < extent.x(); ++x)
1105 coverageMask.push_back(rnd.getBool());
1106
1107 // Each bottom level AS will contain a number of rows.
1108 DE_ASSERT(blasCount > 0u);
1109 BottomLevelAccelerationStructurePool blasPool;
1110 for (uint32_t a = 0u; a < blasCount; ++a)
1111 {
1112 const auto prevRows = rowsPerAS * a;
1113 const auto rowCount = ((a < blasCount - 1u) ? rowsPerAS : (extentU.y() - prevRows));
1114 std::vector<tcu::Vec3> triangles;
1115 triangles.reserve(rowCount * extentU.x() * perTriangleVertices);
1116
1117 for (uint32_t y = 0u; y < rowCount; ++y)
1118 for (uint32_t x = 0u; x < extentU.x(); ++x)
1119 {
1120 const auto row = y + prevRows;
1121 const auto col = x;
1122 const auto maskIndex = row * extentU.x() + col;
1123
1124 if (!coverageMask.at(maskIndex))
1125 continue;
1126
1127 const float xCenter = static_cast<float>(col) + 0.5f;
1128 const float yCenter = static_cast<float>(row) + 0.5f;
1129
1130 triangles.push_back(tcu::Vec3(xCenter - coordMargin, yCenter + coordMargin, geometryZ));
1131 triangles.push_back(tcu::Vec3(xCenter + coordMargin, yCenter + coordMargin, geometryZ));
1132 triangles.push_back(tcu::Vec3(xCenter, yCenter - coordMargin, geometryZ));
1133 }
1134
1135 const auto blas = blasPool.add();
1136 blas->addGeometry(triangles, true /* triangles */);
1137 }
1138
1139 blasPool.batchCreateAdjust(ctx.vkd, ctx.device, ctx.allocator, ~0ull, false /* scratch buffer is host visible */);
1140 blasPool.batchBuild(ctx.vkd, ctx.device, cmdBuffer);
1141
1142 const auto tlas = makeTopLevelAccelerationStructure();
1143 tlas->setInstanceCount(blasCount);
1144 for (const auto &blas : blasPool.structures())
1145 tlas->addInstance(blas, identityMatrix3x4, 0, 0xFFu, 0u,
1146 VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR);
1147 tlas->createAndBuild(ctx.vkd, ctx.device, cmdBuffer, ctx.allocator);
1148
1149 // Create color buffer.
1150 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM; // Must match the shader declaration.
1151 const auto colorUsage =
1152 (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
1153 const auto colorSSR = makeDefaultImageSubresourceRange();
1154 ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, apiExtent, colorFormat, colorUsage,
1155 VK_IMAGE_TYPE_2D, colorSSR);
1156
1157 // Descriptor pool and set.
1158 DescriptorPoolBuilder poolBuilder;
1159 poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, blasCount);
1160 const auto descritorPool =
1161 poolBuilder.build(ctx.vkd, ctx.device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1162
1163 DescriptorSetLayoutBuilder setLayoutBuilder;
1164 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_FRAGMENT_BIT);
1165 const auto setLayout = setLayoutBuilder.build(ctx.vkd, ctx.device);
1166 const auto descriptorSet = makeDescriptorSet(ctx.vkd, ctx.device, *descritorPool, *setLayout);
1167 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device, *setLayout);
1168
1169 DescriptorSetUpdateBuilder setUpdateBuilder;
1170 using Location = DescriptorSetUpdateBuilder::Location;
1171 {
1172 const VkWriteDescriptorSetAccelerationStructureKHR accelerationStructure = {
1173 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
1174 nullptr,
1175 1u,
1176 tlas->getPtr(),
1177 };
1178 setUpdateBuilder.writeSingle(*descriptorSet, Location::binding(0u),
1179 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelerationStructure);
1180 }
1181 setUpdateBuilder.update(ctx.vkd, ctx.device);
1182
1183 const auto &binaries = context.getBinaryCollection();
1184 auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"), 0);
1185 auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"), 0);
1186
1187 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat);
1188 const auto framebuffer = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, colorBuffer.getImageView(),
1189 apiExtent.width, apiExtent.height);
1190
1191 const std::vector<VkViewport> viewports(1u, makeViewport(extent));
1192 const std::vector<VkRect2D> scissors(1u, makeRect2D(extent));
1193
1194 // Pipeline.
1195 const auto pipeline = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, VK_NULL_HANDLE,
1196 VK_NULL_HANDLE, VK_NULL_HANDLE, *fragModule, *renderPass, viewports,
1197 scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
1198
1199 // Draw a full screen quad so the frag shader is invoked for every fragment.
1200 std::vector<tcu::Vec4> vertices;
1201 vertices.reserve(4u);
1202 vertices.emplace_back(-1.0f, -1.0f, 0.0f, 1.0f);
1203 vertices.emplace_back(-1.0f, 1.0f, 0.0f, 1.0f);
1204 vertices.emplace_back(1.0f, -1.0f, 0.0f, 1.0f);
1205 vertices.emplace_back(1.0f, 1.0f, 0.0f, 1.0f);
1206
1207 const auto vertexBufferInfo = makeBufferCreateInfo(de::dataSize(vertices), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1208 const VkDeviceSize vertexBufferOffset = 0ull;
1209 BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vertexBufferInfo, MemoryRequirement::HostVisible);
1210 {
1211 auto &allocation = vertexBuffer.getAllocation();
1212 void *dataPtr = allocation.getHostPtr();
1213 deMemcpy(dataPtr, de::dataOrNull(vertices), de::dataSize(vertices));
1214 }
1215
1216 // Draw and trace rays.
1217 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 0.0f); // Notice this is none of the colors used in the frag shader.
1218 const tcu::Vec4 missColor(0.0f, 0.0f, 0.0f, 1.0f); // These match the frag shader colors.
1219 const tcu::Vec4 hitColor(0.0f, 0.0f, 1.0f, 1.0f);
1220
1221 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1222 ctx.vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, nullptr);
1223 ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1224 beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, scissors.at(0u), clearColor);
1225 ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
1226 ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
1227 endRenderPass(ctx.vkd, cmdBuffer);
1228 copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), extent.swizzle(0, 1));
1229 endCommandBuffer(ctx.vkd, cmdBuffer);
1230 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
1231
1232 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
1233
1234 // These must match the frag shader.
1235
1236 const auto tcuFormat = mapVkFormat(colorFormat);
1237 tcu::TextureLevel referenceLevel(tcuFormat, extent.x(), extent.y(), extent.z());
1238 tcu::PixelBufferAccess referenceAccess = referenceLevel.getAccess();
1239
1240 for (int y = 0; y < extent.y(); ++y)
1241 for (int x = 0; x < extent.x(); ++x)
1242 {
1243 const auto maskIdx = static_cast<uint32_t>(y * extent.x() + x);
1244 const auto &color = (coverageMask.at(maskIdx) ? hitColor : missColor);
1245 referenceAccess.setPixel(color, x, y);
1246 }
1247
1248 tcu::ConstPixelBufferAccess resultAccess(tcuFormat, extent, colorBuffer.getBufferAllocation().getHostPtr());
1249
1250 const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // Only 1.0 and 0.0 so we expect exact results.
1251 auto &log = context.getTestContext().getLog();
1252 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
1253 tcu::COMPARE_LOG_ON_ERROR))
1254 return tcu::TestStatus::fail("Failed; check log for details");
1255 return tcu::TestStatus::pass("Pass");
1256 }
1257
1258 } // namespace
1259
addHelperInvocationsTests(TestContext & testCtx)1260 TestCaseGroup *addHelperInvocationsTests(TestContext &testCtx)
1261 {
1262 std::pair<bool, const char *> const builds[]{{true, "gpu"}, {false, "cpu"}};
1263
1264 std::pair<HelperInvocationsParams::DfStyle, const char *> const styles[]{
1265 {HelperInvocationsParams::Regular, "regular"},
1266 {HelperInvocationsParams::Coarse, "coarse"},
1267 {HelperInvocationsParams::Fine, "fine"}};
1268
1269 std::pair<HelperInvocationsParams::test_mode_t, const char *> const modes[] = {
1270 {HelperInvocationsParams::MODE_LINEAR_QUADRATIC, "linear_quadratic"},
1271 {HelperInvocationsParams::MODE_LINEAR_CUBIC, "linear_cubic"},
1272 {HelperInvocationsParams::MODE_CUBIC_QUADRATIC, "cubic_quadratic"},
1273 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
1274 {HelperInvocationsParams::MODE_LINEAR_LINEAR, "linear_linear"},
1275 {HelperInvocationsParams::MODE_QUADRATIC_LINEAR, "quadratic_linear"},
1276 {HelperInvocationsParams::MODE_QUADRATIC_QUADRATIC, "quadratic_quadratic"},
1277 {HelperInvocationsParams::MODE_QUADRATIC_CUBIC, "quadratic_cubic"},
1278 {HelperInvocationsParams::MODE_CUBIC_LINEAR, "cubic_linear"},
1279 {HelperInvocationsParams::MODE_CUBIC_CUBIC, "cubic_cubic"},
1280 #endif
1281 };
1282
1283 std::pair<uint32_t, uint32_t> const screens[]{{64, 64}, {32, 64}};
1284
1285 std::pair<uint32_t, uint32_t> const models[]{{64, 64}, {64, 32}};
1286
1287 auto makeTestName = [](const std::pair<uint32_t, uint32_t> &d) -> std::string
1288 { return std::to_string(d.first) + "x" + std::to_string(d.second); };
1289
1290 auto rootGroup = new TestCaseGroup(testCtx, "helper_invocations");
1291 for (auto &build : builds)
1292 {
1293 auto buildGroup = new tcu::TestCaseGroup(testCtx, build.second);
1294 for (auto &style : styles)
1295 {
1296 auto styleGroup = new tcu::TestCaseGroup(testCtx, style.second);
1297 for (auto &mode : modes)
1298 {
1299 auto modeGroup = new tcu::TestCaseGroup(testCtx, mode.second);
1300 for (auto &screen : screens)
1301 {
1302 auto screenGroup = new TestCaseGroup(testCtx, makeTestName(screen).c_str());
1303 for (auto &model : models)
1304 {
1305 HelperInvocationsParams p;
1306 p.mode = mode.first;
1307 p.screen = screen;
1308 p.model = model;
1309 p.style = style.first;
1310 p.buildGPU = build.first;
1311
1312 screenGroup->addChild(new HelperInvocationsCase(testCtx, p, makeTestName(model)));
1313 }
1314 modeGroup->addChild(screenGroup);
1315 }
1316 styleGroup->addChild(modeGroup);
1317 }
1318 buildGroup->addChild(styleGroup);
1319 }
1320 rootGroup->addChild(buildGroup);
1321 }
1322 return rootGroup;
1323 }
1324
createMiscTests(tcu::TestContext & testCtx)1325 tcu::TestCaseGroup *createMiscTests(tcu::TestContext &testCtx)
1326 {
1327 // Miscellaneous ray query tests
1328 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "misc"));
1329
1330 // Dynamic indexing of ray queries
1331 group->addChild(new DynamicIndexingCase(testCtx, "dynamic_indexing"));
1332
1333 addFunctionCaseWithPrograms(group.get(), "reuse_scratch_buffer", checkReuseScratchBufferSupport,
1334 initReuseScratchBufferPrograms, reuseScratchBufferInstance);
1335
1336 return group.release();
1337 }
1338
1339 } // namespace RayQuery
1340 } // namespace vkt
1341