• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params, 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 &params);
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> &centers) 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 &params,
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 &params)
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> &centers) 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