xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/ray_query/vktRayQueryMiscTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 
28 #include "vkRayTracingUtil.hpp"
29 #include "vkBufferWithMemory.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkImageUtil.hpp"
37 
38 #include "tcuVector.hpp"
39 #include "tcuStringTemplate.hpp"
40 #include "tcuTextureUtil.hpp"
41 
42 #include "deUniquePtr.hpp"
43 #include "deRandom.hpp"
44 
45 #include <sstream>
46 #include <limits>
47 #include <vector>
48 #include <map>
49 
50 namespace vkt
51 {
52 namespace RayQuery
53 {
54 
55 namespace
56 {
57 
58 using namespace vk;
59 
60 class DynamicIndexingCase : public vkt::TestCase
61 {
62 public:
63     DynamicIndexingCase(tcu::TestContext &testCtx, const std::string &name);
~DynamicIndexingCase(void)64     virtual ~DynamicIndexingCase(void)
65     {
66     }
67 
68     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
69     virtual void checkSupport(Context &context) const override;
70     virtual TestInstance *createInstance(Context &context) const override;
71 
72     // Constants and data types.
73     static constexpr uint32_t kLocalSizeX = 48u;
74     static constexpr uint32_t kNumQueries = 48u;
75 
76     // This must match the shader.
77     struct InputData
78     {
79         uint32_t goodQueryIndex;
80         uint32_t proceedQueryIndex;
81     };
82 };
83 
84 class DynamicIndexingInstance : public vkt::TestInstance
85 {
86 public:
87     DynamicIndexingInstance(Context &context);
~DynamicIndexingInstance(void)88     virtual ~DynamicIndexingInstance(void)
89     {
90     }
91 
92     virtual tcu::TestStatus iterate(void);
93 };
94 
DynamicIndexingCase(tcu::TestContext & testCtx,const std::string & name)95 DynamicIndexingCase::DynamicIndexingCase(tcu::TestContext &testCtx, const std::string &name)
96     : vkt::TestCase(testCtx, name)
97 {
98 }
99 
initPrograms(vk::SourceCollections & programCollection) const100 void DynamicIndexingCase::initPrograms(vk::SourceCollections &programCollection) const
101 {
102     const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
103 
104     std::ostringstream src;
105 
106     src << "#version 460\n"
107         << "#extension GL_EXT_ray_query : require\n"
108         << "#extension GL_EXT_ray_tracing : require\n"
109         << "\n"
110         << "layout (local_size_x=" << kLocalSizeX << ", local_size_y=1, local_size_z=1) in; \n"
111         << "\n"
112         << "struct InputData {\n"
113         << "    uint goodQueryIndex;\n"
114         << "    uint proceedQueryIndex; // Note: same index as the one above in practice.\n"
115         << "};\n"
116         << "\n"
117         << "layout (set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
118         << "layout (set=0, binding=1, std430) buffer InputBlock {\n"
119         << "    InputData inputData[];\n"
120         << "} inputBlock;\n"
121         << "layout (set=0, binding=2, std430) buffer OutputBlock {\n"
122         << "    uint outputData[];\n"
123         << "} outputBlock;\n"
124         << "\n"
125         << "void main()\n"
126         << "{\n"
127         << "    const uint numQueries = " << kNumQueries << ";\n"
128         << "\n"
129         << "    const uint rayFlags = 0u; \n"
130         << "    const uint cullMask = 0xFFu;\n"
131         << "    const float tmin = 0.1;\n"
132         << "    const float tmax = 10.0;\n"
133         << "    const vec3 direct = vec3(0, 0, 1); \n"
134         << "\n"
135         << "    rayQueryEXT rayQueries[numQueries];\n"
136         << "    vec3 origin;\n"
137         << "\n"
138         << "    InputData inputValues = inputBlock.inputData[gl_LocalInvocationID.x];\n"
139         << "\n"
140         << "    // Initialize all queries. Only goodQueryIndex will have the right origin for a hit.\n"
141         << "    for (int i = 0; i < numQueries; i++) {\n"
142         << "        origin = ((i == inputValues.goodQueryIndex) ? vec3(0, 0, 0) : vec3(5, 5, 0));\n"
143         << "        rayQueryInitializeEXT(rayQueries[i], topLevelAS, rayFlags, cullMask, origin, tmin, direct, tmax);\n"
144         << "    }\n"
145         << "\n"
146         << "    // Attempt to proceed with the good query to confirm a hit.\n"
147         << "    while (rayQueryProceedEXT(rayQueries[inputValues.proceedQueryIndex]))\n"
148         << "        outputBlock.outputData[gl_LocalInvocationID.x] = 1u; \n"
149         << "}\n";
150 
151     programCollection.glslSources.add("comp") << glu::ComputeSource(updateRayTracingGLSL(src.str())) << buildOptions;
152 }
153 
checkSupport(Context & context) const154 void DynamicIndexingCase::checkSupport(Context &context) const
155 {
156     context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
157     context.requireDeviceFunctionality("VK_KHR_ray_query");
158 
159     const auto &rayQueryFeaturesKHR = context.getRayQueryFeatures();
160     if (!rayQueryFeaturesKHR.rayQuery)
161         TCU_THROW(NotSupportedError, "Ray queries not supported");
162 
163     const auto &accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
164     if (!accelerationStructureFeaturesKHR.accelerationStructure)
165         TCU_FAIL("Acceleration structures not supported but ray queries supported");
166 }
167 
createInstance(Context & context) const168 vkt::TestInstance *DynamicIndexingCase::createInstance(Context &context) const
169 {
170     return new DynamicIndexingInstance(context);
171 }
172 
DynamicIndexingInstance(Context & context)173 DynamicIndexingInstance::DynamicIndexingInstance(Context &context) : vkt::TestInstance(context)
174 {
175 }
176 
getRndIndex(de::Random & rng,uint32_t size)177 uint32_t getRndIndex(de::Random &rng, uint32_t size)
178 {
179     DE_ASSERT(size > 0u);
180     DE_ASSERT(size <= static_cast<uint32_t>(std::numeric_limits<int>::max()));
181 
182     const int iMin = 0;
183     const int iMax = static_cast<int>(size) - 1;
184 
185     return static_cast<uint32_t>(rng.getInt(iMin, iMax));
186 }
187 
iterate(void)188 tcu::TestStatus DynamicIndexingInstance::iterate(void)
189 {
190     using InputData            = DynamicIndexingCase::InputData;
191     constexpr auto kLocalSizeX = DynamicIndexingCase::kLocalSizeX;
192     constexpr auto kNumQueries = DynamicIndexingCase::kNumQueries;
193 
194     const auto &vkd   = m_context.getDeviceInterface();
195     const auto device = m_context.getDevice();
196     auto &alloc       = m_context.getDefaultAllocator();
197     const auto queue  = m_context.getUniversalQueue();
198     const auto qIndex = m_context.getUniversalQueueFamilyIndex();
199 
200     de::Random rng(1604936737u);
201     InputData inputDataArray[kLocalSizeX];
202     uint32_t outputDataArray[kLocalSizeX];
203 
204     // Prepare input buffer.
205     for (int i = 0; i < DE_LENGTH_OF_ARRAY(inputDataArray); ++i)
206     {
207         // The two values will contain the same query index.
208         inputDataArray[i].goodQueryIndex    = getRndIndex(rng, kNumQueries);
209         inputDataArray[i].proceedQueryIndex = inputDataArray[i].goodQueryIndex;
210     }
211 
212     const auto inputBufferSize = static_cast<VkDeviceSize>(sizeof(inputDataArray));
213     const auto inputBufferInfo = makeBufferCreateInfo(inputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
214     BufferWithMemory inputBuffer(vkd, device, alloc, inputBufferInfo, MemoryRequirement::HostVisible);
215     auto &inputBufferAlloc = inputBuffer.getAllocation();
216     void *inputBufferPtr   = inputBufferAlloc.getHostPtr();
217 
218     deMemcpy(inputBufferPtr, inputDataArray, static_cast<size_t>(inputBufferSize));
219     flushAlloc(vkd, device, inputBufferAlloc);
220 
221     // Prepare output buffer.
222     const auto outputBufferSize = static_cast<VkDeviceSize>(sizeof(outputDataArray));
223     const auto outputBufferInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
224     BufferWithMemory outputBuffer(vkd, device, alloc, outputBufferInfo, MemoryRequirement::HostVisible);
225     auto &outputBufferAlloc = outputBuffer.getAllocation();
226     void *outputBufferPtr   = outputBufferAlloc.getHostPtr();
227 
228     deMemset(outputBufferPtr, 0, static_cast<size_t>(outputBufferSize));
229     flushAlloc(vkd, device, outputBufferAlloc);
230 
231     // Prepare acceleration structures.
232     const auto cmdPool      = makeCommandPool(vkd, device, qIndex);
233     const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
234     const auto cmdBuffer    = cmdBufferPtr.get();
235     beginCommandBuffer(vkd, cmdBuffer);
236 
237     de::SharedPtr<TopLevelAccelerationStructure> topLevelAS(makeTopLevelAccelerationStructure().release());
238     de::SharedPtr<BottomLevelAccelerationStructure> bottomLevelAS(makeBottomLevelAccelerationStructure().release());
239 
240     // These need to match the origin and direction in the shader for a hit.
241     const std::vector<tcu::Vec3> vertices = {
242         tcu::Vec3(-1.0f, -1.0f, 1.0f), tcu::Vec3(-1.0f, 1.0f, 1.0f), tcu::Vec3(1.0f, -1.0f, 1.0f),
243 
244         tcu::Vec3(-1.0f, 1.0f, 1.0f),  tcu::Vec3(1.0f, 1.0f, 1.0f),  tcu::Vec3(1.0f, -1.0f, 1.0f),
245     };
246 
247     bottomLevelAS->addGeometry(vertices, /*triangles*/ true, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
248     bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
249 
250     topLevelAS->addInstance(bottomLevelAS);
251     topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
252 
253     // Descriptor set layout.
254     const VkShaderStageFlagBits stageBit = VK_SHADER_STAGE_COMPUTE_BIT;
255 
256     DescriptorSetLayoutBuilder layoutBuilder;
257     layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stageBit);
258     layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
259     layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
260     const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
261 
262     // Shader module.
263     const auto shaderModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
264 
265     // Pipeline layout.
266     const auto pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
267 
268     const VkPipelineShaderStageCreateInfo shaderStageInfo = {
269         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
270         nullptr,                                             // const void* pNext;
271         0u,                                                  // VkPipelineShaderStageCreateFlags flags;
272         stageBit,                                            // VkShaderStageFlagBits stage;
273         shaderModule.get(),                                  // VkShaderModule module;
274         "main",                                              // const char* pName;
275         nullptr,                                             // const VkSpecializationInfo* pSpecializationInfo;
276     };
277 
278     const VkComputePipelineCreateInfo pipelineInfo = {
279         VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
280         nullptr,                                        // const void* pNext;
281         0u,                                             // VkPipelineCreateFlags flags;
282         shaderStageInfo,                                // VkPipelineShaderStageCreateInfo stage;
283         pipelineLayout.get(),                           // VkPipelineLayout layout;
284         DE_NULL,                                        // VkPipeline basePipelineHandle;
285         0,                                              // int32_t basePipelineIndex;
286     };
287 
288     const auto pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineInfo);
289 
290     // Create and update descriptor set.
291     DescriptorPoolBuilder poolBuilder;
292     poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
293     poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u);
294 
295     const auto descriptorPool   = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
296     const auto descriptorSetPtr = makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
297     const auto descriptorSet    = descriptorSetPtr.get();
298 
299     const VkWriteDescriptorSetAccelerationStructureKHR asWrite = {
300         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
301         nullptr,                                                           // const void* pNext;
302         1u,                                                                // uint32_t accelerationStructureCount;
303         topLevelAS->getPtr(), // const VkAccelerationStructureKHR* pAccelerationStructures;
304     };
305 
306     const auto inputBufferWriteInfo  = makeDescriptorBufferInfo(inputBuffer.get(), 0ull, inputBufferSize);
307     const auto outputBufferWriteInfo = makeDescriptorBufferInfo(outputBuffer.get(), 0ull, outputBufferSize);
308 
309     DescriptorSetUpdateBuilder updateBuilder;
310     updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
311                               VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &asWrite);
312     updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
313                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputBufferWriteInfo);
314     updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u),
315                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferWriteInfo);
316     updateBuilder.update(vkd, device);
317 
318     // Use pipeline.
319     vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
320     vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet,
321                               0u, nullptr);
322     vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
323 
324     const auto memBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
325     vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u,
326                            &memBarrier, 0u, nullptr, 0u, nullptr);
327 
328     // Submit recorded commands.
329     endCommandBuffer(vkd, cmdBuffer);
330     submitCommandsAndWait(vkd, device, queue, cmdBuffer);
331 
332     // Check output buffer.
333     invalidateAlloc(vkd, device, outputBufferAlloc);
334     deMemcpy(outputDataArray, outputBufferPtr, static_cast<size_t>(outputBufferSize));
335 
336     for (int i = 0; i < DE_LENGTH_OF_ARRAY(outputDataArray); ++i)
337     {
338         constexpr auto expected = 1u;
339         const auto &value       = outputDataArray[i];
340 
341         if (value != expected)
342         {
343             std::ostringstream msg;
344             msg << "Unexpected value found at position " << i << " in the output buffer: expected " << expected
345                 << " but found " << value;
346             TCU_FAIL(msg.str());
347         }
348     }
349 
350     return tcu::TestStatus::pass("Pass");
351 }
352 
353 using namespace tcu;
354 
355 struct HelperInvocationsParamDefs
356 {
357     enum DfStyle
358     {
359         Regular,
360         Coarse,
361         Fine
362     };
363 
364     enum FuncType
365     {
366         LINEAR,
367         QUADRATIC,
368         CUBIC
369     };
370 
371     typedef float (*F1D)(float);
372     struct func2D_t
373     {
374         F1D first;
375         F1D second;
376     };
377     struct func2D_mask
378     {
379         FuncType first;
380         FuncType second;
381     };
382     struct test_mode_t
383     {
384         func2D_t funcs;
385         func2D_mask types;
386     };
387 
linearvkt::RayQuery::__anond480ef7b0111::HelperInvocationsParamDefs388     static float linear(float x)
389     {
390         return x;
391     }
quadraticvkt::RayQuery::__anond480ef7b0111::HelperInvocationsParamDefs392     static float quadratic(float x)
393     {
394         return (x * x);
395     }
cubicvkt::RayQuery::__anond480ef7b0111::HelperInvocationsParamDefs396     static float cubic(float x)
397     {
398         return (x * x * x * 0.5f);
399     }
400 
combinevkt::RayQuery::__anond480ef7b0111::HelperInvocationsParamDefs401     static float combine(const func2D_t &f2D, float x, float y)
402     {
403         DE_ASSERT((f2D.first) && (f2D.second));
404         const float z = ((*f2D.first)(x) + (*f2D.second)(y)) / 2.0f;
405         return z;
406     }
407 
408     static constexpr func2D_t FUNC_LINEAR_QUADRATIC = {linear, quadratic};
409     static constexpr func2D_t FUNC_LINEAR_CUBIC     = {linear, cubic};
410     static constexpr func2D_t FUNC_CUBIC_QUADRATIC  = {cubic, quadratic};
411 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
412     static constexpr func2D_t FUNC_LINEAR_LINEAR       = {linear, linear};
413     static constexpr func2D_t FUNC_QUADRATIC_LINEAR    = {quadratic, linear};
414     static constexpr func2D_t FUNC_QUADRATIC_QUADRATIC = {quadratic, quadratic};
415     static constexpr func2D_t FUNC_QUADRATIC_CUBIC     = {quadratic, cubic};
416     static constexpr func2D_t FUNC_CUBIC_LINEAR        = {cubic, linear};
417     static constexpr func2D_t FUNC_CUBIC_CUBIC         = {cubic, cubic};
418 #endif
419 
420     static constexpr func2D_mask MASK_LINEAR_QUADRATIC = {LINEAR, QUADRATIC};
421     static constexpr func2D_mask MASK_LINEAR_CUBIC     = {LINEAR, CUBIC};
422     static constexpr func2D_mask MASK_CUBIC_QUADRATIC  = {CUBIC, QUADRATIC};
423 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
424     static constexpr func2D_mask MASK_LINEAR_LINEAR       = {LINEAR, LINEAR};
425     static constexpr func2D_mask MASK_QUADRATIC_LINEAR    = {QUADRATIC, LINEAR};
426     static constexpr func2D_mask MASK_QUADRATIC_QUADRATIC = {QUADRATIC, QUADRATIC};
427     static constexpr func2D_mask MASK_QUADRATIC_CUBIC     = {QUADRATIC, CUBIC};
428     static constexpr func2D_mask MASK_CUBIC_LINEAR        = {CUBIC, LINEAR};
429     static constexpr func2D_mask MASK_CUBIC_CUBIC         = {CUBIC, CUBIC};
430 #endif
431 
432     static constexpr test_mode_t MODE_LINEAR_QUADRATIC = {FUNC_LINEAR_QUADRATIC, MASK_LINEAR_QUADRATIC};
433     static constexpr test_mode_t MODE_LINEAR_CUBIC     = {FUNC_LINEAR_CUBIC, MASK_LINEAR_CUBIC};
434     static constexpr test_mode_t MODE_CUBIC_QUADRATIC  = {FUNC_CUBIC_QUADRATIC, MASK_CUBIC_QUADRATIC};
435 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
436     static constexpr test_mode_t MODE_LINEAR_LINEAR       = {FUNC_LINEAR_LINEAR, MASK_LINEAR_LINEAR};
437     static constexpr test_mode_t MODE_QUADRATIC_LINEAR    = {FUNC_QUADRATIC_LINEAR, MASK_QUADRATIC_LINEAR};
438     static constexpr test_mode_t MODE_QUADRATIC_QUADRATIC = {FUNC_QUADRATIC_QUADRATIC, MASK_QUADRATIC_QUADRATIC};
439     static constexpr test_mode_t MODE_QUADRATIC_CUBIC     = {FUNC_QUADRATIC_CUBIC, MASK_QUADRATIC_CUBIC};
440     static constexpr test_mode_t MODE_CUBIC_LINEAR        = {FUNC_CUBIC_LINEAR, MASK_CUBIC_LINEAR};
441     static constexpr test_mode_t MODE_CUBIC_CUBIC         = {FUNC_CUBIC_CUBIC, MASK_CUBIC_CUBIC};
442 #endif
443 };
444 
445 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_QUADRATIC;
446 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_CUBIC;
447 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_QUADRATIC;
448 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
449 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_LINEAR_LINEAR;
450 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_LINEAR;
451 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_QUADRATIC;
452 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_QUADRATIC_CUBIC;
453 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_LINEAR;
454 constexpr HelperInvocationsParamDefs::test_mode_t HelperInvocationsParamDefs::MODE_CUBIC_CUBIC;
455 #endif
456 
457 struct HelperInvocationsParams : HelperInvocationsParamDefs
458 {
459     test_mode_t mode;
460     std::pair<uint32_t, uint32_t> screen;
461     std::pair<uint32_t, uint32_t> model;
462     DfStyle style;
463     bool buildGPU;
464 };
465 
466 class HelperInvocationsCase : public TestCase
467 {
468 public:
469     HelperInvocationsCase(TestContext &testCtx, const HelperInvocationsParams &params, const std::string &name);
470     virtual void initPrograms(SourceCollections &programs) const override;
471     virtual TestInstance *createInstance(Context &context) const override;
472     virtual void checkSupport(Context &context) const override;
473 
474 private:
475     HelperInvocationsParams m_params;
476 };
477 
478 class HelperInvocationsInstance : public TestInstance
479 {
480 public:
481     typedef de::MovePtr<TopLevelAccelerationStructure> TopLevelAccelerationStructurePtr;
482     enum Points
483     {
484         Vertices,
485         Coords,
486         Centers
487     };
488 
489     HelperInvocationsInstance(Context &context, const HelperInvocationsParams &params);
490     virtual TestStatus iterate(void) override;
491     static auto createSurface(const Points points, const uint32_t divX, const uint32_t divY,
492                               const HelperInvocationsParams::func2D_t &f2D, bool clockWise = false)
493         -> std::vector<Vec3>;
494     VkImageCreateInfo makeImgInfo(uint32_t queueFamilyIndexCount, const uint32_t *pQueueFamilyIndices) const;
495     Move<VkPipeline> makePipeline(const DeviceInterface &vk, const VkDevice device,
496                                   const VkPipelineLayout pipelineLayout, const VkShaderModule vertexShader,
497                                   const VkShaderModule fragmentShader, const VkRenderPass renderPass) const;
498     auto makeResultBuff(const DeviceInterface &vk, const VkDevice device, Allocator &allocator) const
499         -> de::MovePtr<BufferWithMemory>;
500     auto makeAttribBuff(const DeviceInterface &vk, const VkDevice device, Allocator &allocator,
501                         const std::vector<Vec3> &vertices, const std::vector<Vec3> &coords,
502                         const std::vector<Vec3> &centers) const -> de::MovePtr<BufferWithMemory>;
503     auto createAccStructs(const DeviceInterface &vk, const VkDevice device, Allocator &allocator,
504                           const VkCommandBuffer cmdBuffer, const std::vector<Vec3> coords) const
505         -> TopLevelAccelerationStructurePtr;
506 
507 protected:
508     bool verifyResult(const DeviceInterface &vk, const VkDevice device, const BufferWithMemory &buffer) const;
509     bool onlyPipeline();
510 
511 private:
512     VkFormat m_format;
513     HelperInvocationsParams m_params;
514 };
515 
HelperInvocationsCase(TestContext & testCtx,const HelperInvocationsParams & params,const std::string & name)516 HelperInvocationsCase::HelperInvocationsCase(TestContext &testCtx, const HelperInvocationsParams &params,
517                                              const std::string &name)
518     : TestCase(testCtx, name)
519     , m_params(params)
520 {
521 }
522 
createInstance(Context & context) const523 TestInstance *HelperInvocationsCase::createInstance(Context &context) const
524 {
525     return new HelperInvocationsInstance(context, m_params);
526 }
527 
checkSupport(Context & context) const528 void HelperInvocationsCase::checkSupport(Context &context) const
529 {
530     context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
531     context.requireDeviceFunctionality("VK_KHR_ray_query");
532 
533     const auto &rayQueryFeaturesKHR              = context.getRayQueryFeatures();
534     const auto &accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
535 
536     if (!rayQueryFeaturesKHR.rayQuery)
537         TCU_THROW(NotSupportedError, "Ray queries not supported");
538 
539     if (!accelerationStructureFeaturesKHR.accelerationStructure)
540         TCU_THROW(NotSupportedError, "Acceleration structures not supported but ray queries supported");
541 
542     if (m_params.buildGPU == false && accelerationStructureFeaturesKHR.accelerationStructureHostCommands == false)
543         TCU_THROW(NotSupportedError,
544                   "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR::accelerationStructureHostCommands");
545 }
546 
initPrograms(SourceCollections & programs) const547 void HelperInvocationsCase::initPrograms(SourceCollections &programs) const
548 {
549     const ShaderBuildOptions buildOptions(programs.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
550 
551     std::string vertexCode(
552         R"(
553     #version 460
554     #extension GL_EXT_ray_query : require
555     #extension GL_EXT_ray_tracing : require
556 
557     layout(location = 0) in vec3 pos;
558     layout(location = 1) in vec3 inCoord;
559     layout(location = 2) in vec3 inCenter;
560     layout(location = 0) out vec3 outCoord;
561     layout(location = 1) out vec3 outCenter;
562 
563     void main()
564     {
565         gl_PointSize = 1.0;
566         gl_Position = vec4(pos.xyz, 1.0);
567         outCoord = inCoord;
568         outCenter = inCenter;
569     }
570     )");
571     programs.glslSources.add("vert") << glu::VertexSource(vertexCode) << buildOptions;
572 
573     StringTemplate fragmentCode(
574         R"(
575     #version 460
576     #extension GL_EXT_ray_query : require
577     #extension GL_EXT_ray_tracing : require
578 
579     #define LINEAR    0
580     #define QUADRATIC 1
581     #define CUBIC     2
582 
583     layout(push_constant) uniform PC {
584         int fun_x;
585         int fun_y;
586         float width;
587         float height;
588     } params;
589     layout(location = 0) in vec3 coord;
590     layout(location = 1) in vec3 center;
591     layout(location = 0) out vec4 color;
592     layout(set = 0, binding = 0) uniform accelerationStructureEXT topLevelAS;
593 
594     float d_linear   (in float t) { return 0.5; }            // (x/2)'
595     float d_quadratic(in float t) { return t; }                // (x^2/2)'
596     float d_cubic    (in float t) { return 0.75 * t * t; }  // (x^3/4)'
597 
598     float derivate(in int fun, in float u)
599     {
600         switch (fun)
601         {
602             case LINEAR: return d_linear(u);
603             case QUADRATIC: return d_quadratic(u);
604             case CUBIC: return d_cubic(u);
605         }
606         return -1.0;
607     }
608     void main()
609     {
610         const uint rayFlags = 0u;
611         const uint cullMask = 0xFFu;
612         const float tmin = 0.0;
613         const float tmax = 10.0;
614         const vec3 direct = vec3(0.0, 0.0, 1.0);
615         const vec3 origin = vec3(center.x, center.y, -1.0);
616 
617         rayQueryEXT query;
618         rayQueryInitializeEXT(query, topLevelAS, rayFlags, cullMask, origin, tmin, direct, tmax);
619 
620         color = vec4(-1.0, -1.0, -1.0, -1.0);
621 
622         while (rayQueryProceedEXT(query)) {
623             if (rayQueryGetIntersectionTypeEXT(query, false)
624  == gl_RayQueryCandidateIntersectionTriangleEXT)
625             {
626                 float vx = derivate(params.fun_x, coord.x);
627                 float vy = derivate(params.fun_y, coord.y);
628                 float dx = ${DFDX}(coord.x);
629                 float dy = ${DFDY}(coord.y);
630                 float dzx = ${DFDX}(coord.z);
631                 float dzy = ${DFDY}(coord.z);
632                 float dfx = dzx / dx;
633                 float dfy = dzy / dy;
634                 float cx = dfx - vx;
635                 float cy = dfy - vy;
636 
637                 color = vec4(cx, cy, sign(dx-abs(cx)), sign(dy-abs(cy)));
638             }
639             else
640             {
641                 color = vec4(0.0, 0.0, -1.0, -1.0);
642             }
643             rayQueryConfirmIntersectionEXT(query);
644         }
645     })");
646 
647     std::map<std::string, std::string> m;
648     switch (m_params.style)
649     {
650     case HelperInvocationsParams::DfStyle::Regular:
651         m["DFDX"] = "dFdx";
652         m["DFDY"] = "dFdy";
653         break;
654     case HelperInvocationsParams::DfStyle::Coarse:
655         m["DFDX"] = "dFdxCoarse";
656         m["DFDY"] = "dFdyCoarse";
657         break;
658     case HelperInvocationsParams::DfStyle::Fine:
659         m["DFDX"] = "dFdxFine";
660         m["DFDY"] = "dFdyFine";
661         break;
662     }
663 
664     programs.glslSources.add("frag") << glu::FragmentSource(fragmentCode.specialize(m)) << buildOptions;
665 }
666 
HelperInvocationsInstance(Context & context,const HelperInvocationsParams & params)667 HelperInvocationsInstance::HelperInvocationsInstance(Context &context, const HelperInvocationsParams &params)
668     : TestInstance(context)
669     , m_format(VK_FORMAT_R32G32B32A32_SFLOAT)
670     , m_params(params)
671 {
672 }
673 
createSurface(const Points points,const uint32_t divX,const uint32_t divY,const HelperInvocationsParams::func2D_t & f2D,bool clockWise)674 std::vector<Vec3> HelperInvocationsInstance::createSurface(const Points points, const uint32_t divX,
675                                                            const uint32_t divY,
676                                                            const HelperInvocationsParams::func2D_t &f2D, bool clockWise)
677 {
678     std::vector<Vec3> s;
679     const float dx = (points == Points::Vertices ? 2.0f : 1.0f) / float(divX);
680     const float dy = (points == Points::Vertices ? 2.0f : 1.0f) / float(divY);
681     // Z is always scaled to range (0,1)
682     auto z = [&](const uint32_t n, const uint32_t m) -> float
683     {
684         const float x = float(n) / float(divX);
685         const float y = float(m) / float(divY);
686         return HelperInvocationsParams::combine(f2D, x, y);
687     };
688     float y = (points == Points::Vertices) ? -1.0f : 0.0f;
689     for (uint32_t j = 0; j < divY; ++j)
690     {
691         const float ny = ((j + 1) < divY) ? (y + dy) : 1.f;
692         float x        = (points == Points::Vertices) ? -1.0f : 0.0f;
693 
694         for (uint32_t i = 0; i < divX; ++i)
695         {
696             const float nx = ((i + 1) < divX) ? (x + dx) : 1.f;
697 
698             const Vec3 p0(x, y, z(i, j));
699             const Vec3 p1(nx, y, z(i + 1, j));
700             const Vec3 p2(nx, ny, z(i + 1, j + 1));
701             const Vec3 p3(x, ny, z(i, j + 1));
702 
703             if (points == Points::Centers)
704             {
705                 const float cx1 = (p0.x() + p1.x() + p2.x()) / 3.0f;
706                 const float cy1 = (p0.y() + p1.y() + p2.y()) / 3.0f;
707                 const float cz1 = (p0.z() + p1.z() + p2.z()) / 3.0f;
708                 const float cx2 = (p0.x() + p2.x() + p3.x()) / 3.0f;
709                 const float cy2 = (p0.y() + p2.y() + p3.y()) / 3.0f;
710                 const float cz2 = (p0.z() + p2.z() + p3.z()) / 3.0f;
711 
712                 s.emplace_back(cx1, cy1, cz1);
713                 s.emplace_back(cx1, cy1, cz1);
714                 s.emplace_back(cx1, cy1, cz1);
715                 s.emplace_back(cx2, cy2, cz2);
716                 s.emplace_back(cx2, cy2, cz2);
717                 s.emplace_back(cx2, cy2, cz2);
718             }
719             else if (clockWise)
720             {
721                 s.push_back(p0);
722                 s.push_back(p3);
723                 s.push_back(p2);
724                 s.push_back(p0);
725                 s.push_back(p2);
726                 s.push_back(p1);
727             }
728             else
729             {
730                 s.push_back(p0);
731                 s.push_back(p1);
732                 s.push_back(p2);
733                 s.push_back(p2);
734                 s.push_back(p3);
735                 s.push_back(p0);
736             }
737 
738             x = nx;
739         }
740         y = ny;
741     }
742     return s;
743 }
744 
makeImgInfo(uint32_t queueFamilyIndexCount,const uint32_t * pQueueFamilyIndices) const745 VkImageCreateInfo HelperInvocationsInstance::makeImgInfo(uint32_t queueFamilyIndexCount,
746                                                          const uint32_t *pQueueFamilyIndices) const
747 {
748     const VkImageUsageFlags usage =
749         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
750     return {
751         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                 // sType;
752         nullptr,                                             // pNext;
753         VkImageCreateFlags(0),                               // flags;
754         VK_IMAGE_TYPE_2D,                                    // imageType;
755         m_format,                                            // format;
756         {m_params.screen.first, m_params.screen.second, 1u}, // extent;
757         1u,                                                  // mipLevels;
758         1u,                                                  // arrayLayers;
759         VK_SAMPLE_COUNT_1_BIT,                               // samples;
760         VK_IMAGE_TILING_OPTIMAL,                             // tiling;
761         usage,                                               // usage;
762         VK_SHARING_MODE_EXCLUSIVE,                           // sharingMode;
763         queueFamilyIndexCount,                               // queueFamilyIndexCount;
764         pQueueFamilyIndices,                                 // pQueueFamilyIndices;
765         VK_IMAGE_LAYOUT_UNDEFINED                            // initialLayout;
766     };
767 }
768 
makePipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkShaderModule vertexShader,const VkShaderModule fragmentShader,const VkRenderPass renderPass) const769 Move<VkPipeline> HelperInvocationsInstance::makePipeline(const DeviceInterface &vk, const VkDevice device,
770                                                          const VkPipelineLayout pipelineLayout,
771                                                          const VkShaderModule vertexShader,
772                                                          const VkShaderModule fragmentShader,
773                                                          const VkRenderPass renderPass) const
774 {
775     DE_ASSERT(sizeof(Vec3) == mapVkFormat(VK_FORMAT_R32G32B32_SFLOAT).getPixelSize());
776 
777     const std::vector<VkViewport> viewports{makeViewport(m_params.screen.first, m_params.screen.second)};
778     const std::vector<VkRect2D> scissors{makeRect2D(m_params.screen.first, m_params.screen.second)};
779 
780     const VkVertexInputBindingDescription vertexInputBindingDescription{
781         0u,                          // uint32_t             binding
782         uint32_t(sizeof(Vec3) * 3u), // uint32_t             stride
783         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate    inputRate
784     };
785 
786     const VkVertexInputAttributeDescription vertexInputAttributeDescription[]{
787         {
788             0u,                         // uint32_t    location
789             0u,                         // uint32_t    binding
790             VK_FORMAT_R32G32B32_SFLOAT, // VkFormat    format
791             0u                          // uint32_t    offset
792         },                              // vertices
793         {
794             1u,                         // uint32_t    location
795             0u,                         // uint32_t    binding
796             VK_FORMAT_R32G32B32_SFLOAT, // VkFormat    format
797             uint32_t(sizeof(Vec3))      // uint32_t    offset
798         },                              // coords
799         {
800             2u,                         // uint32_t    location
801             0u,                         // uint32_t    binding
802             VK_FORMAT_R32G32B32_SFLOAT, // VkFormat    format
803             uint32_t(sizeof(Vec3) * 2u) // uint32_t    offset
804         }                               // centers
805     };
806 
807     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
808         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType
809         nullptr,                                                   // const void*                                 pNext
810         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags       flags
811         1u,                             // uint32_t                                    vertexBindingDescriptionCount
812         &vertexInputBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions
813         DE_LENGTH_OF_ARRAY(
814             vertexInputAttributeDescription), // uint32_t                                    vertexAttributeDescriptionCount
815         vertexInputAttributeDescription // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
816     };
817 
818     return makeGraphicsPipeline(vk, device, pipelineLayout, vertexShader, DE_NULL, DE_NULL, DE_NULL, fragmentShader,
819                                 renderPass, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
820                                 &vertexInputStateCreateInfo);
821 }
822 
createAccStructs(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const VkCommandBuffer cmdBuffer,const std::vector<Vec3> coords) const823 de::MovePtr<TopLevelAccelerationStructure> HelperInvocationsInstance::createAccStructs(
824     const DeviceInterface &vk, const VkDevice device, Allocator &allocator, const VkCommandBuffer cmdBuffer,
825     const std::vector<Vec3> coords) const
826 {
827     const VkAccelerationStructureBuildTypeKHR buildType = m_params.buildGPU ?
828                                                               VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR :
829                                                               VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR;
830     de::MovePtr<TopLevelAccelerationStructure> tlas     = makeTopLevelAccelerationStructure();
831     de::MovePtr<BottomLevelAccelerationStructure> blas  = makeBottomLevelAccelerationStructure();
832 
833     blas->setBuildType(buildType);
834     blas->addGeometry(coords, true, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
835     blas->createAndBuild(vk, device, cmdBuffer, allocator);
836 
837     tlas->setBuildType(buildType);
838     tlas->addInstance(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
839     tlas->createAndBuild(vk, device, cmdBuffer, allocator);
840 
841     return tlas;
842 }
843 
makeAttribBuff(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const std::vector<Vec3> & vertices,const std::vector<Vec3> & coords,const std::vector<Vec3> & centers) const844 de::MovePtr<BufferWithMemory> HelperInvocationsInstance::makeAttribBuff(const DeviceInterface &vk,
845                                                                         const VkDevice device, Allocator &allocator,
846                                                                         const std::vector<Vec3> &vertices,
847                                                                         const std::vector<Vec3> &coords,
848                                                                         const std::vector<Vec3> &centers) const
849 {
850     DE_ASSERT(sizeof(Vec3) == mapVkFormat(VK_FORMAT_R32G32B32_SFLOAT).getPixelSize());
851     const uint32_t count = uint32_t(vertices.size());
852     DE_ASSERT(count && (count == coords.size()) && (count == centers.size()));
853     const VkDeviceSize bufferSize             = 3 * count * sizeof(Vec3);
854     const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
855     de::MovePtr<BufferWithMemory> buffer(new BufferWithMemory(
856         vk, device, allocator, bufferCreateInfo, MemoryRequirement::Coherent | MemoryRequirement::HostVisible));
857 
858     Allocation &allocation = buffer->getAllocation();
859     Vec3 *data             = static_cast<Vec3 *>(allocation.getHostPtr());
860     for (uint32_t c = 0; c < count; ++c)
861     {
862         data[3 * c]     = vertices.at(c);
863         data[3 * c + 1] = coords.at(c);
864         data[3 * c + 2] = centers.at(c);
865     }
866     flushMappedMemoryRange(vk, device, allocation.getMemory(), 0u, bufferSize);
867 
868     return buffer;
869 }
870 
makeResultBuff(const DeviceInterface & vk,const VkDevice device,Allocator & allocator) const871 de::MovePtr<BufferWithMemory> HelperInvocationsInstance::makeResultBuff(const DeviceInterface &vk,
872                                                                         const VkDevice device,
873                                                                         Allocator &allocator) const
874 {
875     const TextureFormat texFormat = mapVkFormat(m_format);
876     const VkDeviceSize bufferSize = (m_params.screen.first * m_params.screen.second * texFormat.getPixelSize());
877     const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
878     de::MovePtr<BufferWithMemory> buffer(new BufferWithMemory(
879         vk, device, allocator, bufferCreateInfo, MemoryRequirement::Coherent | MemoryRequirement::HostVisible));
880 
881     Allocation &allocation = buffer->getAllocation();
882     PixelBufferAccess pixels(texFormat, m_params.screen.first, m_params.screen.second, 1u, allocation.getHostPtr());
883 
884     for (uint32_t y = 0; y < m_params.screen.second; ++y)
885     {
886         for (uint32_t x = 0; x < m_params.screen.first; ++x)
887         {
888             pixels.setPixel(Vec4(0.0f, 0.0f, 0.0f, -1.0f), x, y);
889         }
890     }
891     flushMappedMemoryRange(vk, device, allocation.getMemory(), 0u, bufferSize);
892 
893     return buffer;
894 }
895 
verifyResult(const DeviceInterface & vk,const VkDevice device,const BufferWithMemory & buffer) const896 bool HelperInvocationsInstance::verifyResult(const DeviceInterface &vk, const VkDevice device,
897                                              const BufferWithMemory &buffer) const
898 {
899     int invalid       = 0;
900     Allocation &alloc = buffer.getAllocation();
901     invalidateMappedMemoryRange(vk, device, alloc.getMemory(), 0u, VK_WHOLE_SIZE);
902     ConstPixelBufferAccess pixels(mapVkFormat(m_format), m_params.screen.first, m_params.screen.second, 1u,
903                                   alloc.getHostPtr());
904 
905     for (uint32_t y = 0; y < m_params.screen.second; ++y)
906     {
907         for (uint32_t x = 0; x < m_params.screen.first; ++x)
908         {
909             const Vec4 px = pixels.getPixel(x, y);
910             if (px.z() < 0.0f || px.w() < 0.0f)
911                 invalid += 1;
912         }
913     }
914 
915     return (0 == invalid);
916 }
917 
makeAccStructDescriptorWrite(const VkAccelerationStructureKHR * ptr,uint32_t count=1u)918 VkWriteDescriptorSetAccelerationStructureKHR makeAccStructDescriptorWrite(const VkAccelerationStructureKHR *ptr,
919                                                                           uint32_t count = 1u)
920 {
921     return {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
922             nullptr,                                                           // const void* pNext;
923             count,                                                             // uint32_t accelerationStructureCount;
924             ptr}; // const VkAccelerationStructureKHR* pAccelerationStructures;
925 };
926 
iterate(void)927 TestStatus HelperInvocationsInstance::iterate(void)
928 {
929     const VkDevice device           = m_context.getDevice();
930     const DeviceInterface &vk       = m_context.getDeviceInterface();
931     Allocator &allocator            = m_context.getDefaultAllocator();
932     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
933     const VkQueue queue             = m_context.getUniversalQueue();
934 
935     const VkRect2D renderArea               = makeRect2D(m_params.screen.first, m_params.screen.second);
936     const VkImageCreateInfo imageCreateInfo = makeImgInfo(1, &queueFamilyIndex);
937     const de::MovePtr<ImageWithMemory> image(
938         new ImageWithMemory(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
939     const VkImageSubresourceRange imageSubresourceRange =
940         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u);
941     const Move<VkImageView> view =
942         makeImageView(vk, device, **image, VK_IMAGE_VIEW_TYPE_2D, m_format, imageSubresourceRange);
943     const Move<VkRenderPass> renderPass = makeRenderPass(vk, device, m_format);
944     const Move<VkFramebuffer> frameBuffer =
945         makeFramebuffer(vk, device, *renderPass, *view, m_params.screen.first, m_params.screen.second);
946     const de::MovePtr<BufferWithMemory> resultBuffer = makeResultBuff(vk, device, allocator);
947     const VkImageSubresourceLayers imageSubresourceLayers =
948         makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
949     const VkBufferImageCopy bufferCopyImageRegion = makeBufferImageCopy(
950         makeExtent3D(UVec3(m_params.screen.first, m_params.screen.second, 1u)), imageSubresourceLayers);
951 
952     const HelperInvocationsParams::func2D_t funcs = m_params.mode.funcs;
953     struct PushConstants
954     {
955         int fun_x, fun_y;
956         float width, height;
957     } const pushConstants{m_params.mode.types.first, m_params.mode.types.second, (float)m_params.screen.first,
958                           (float)m_params.screen.second};
959     const VkPushConstantRange pushConstantRange{VK_SHADER_STAGE_FRAGMENT_BIT, 0u, uint32_t(sizeof(pushConstants))};
960     const std::vector<Vec3> vertices =
961         createSurface(Points::Vertices, m_params.model.first, m_params.model.second, funcs);
962     const std::vector<Vec3> coords = createSurface(Points::Coords, m_params.model.first, m_params.model.second, funcs);
963     const std::vector<Vec3> centers =
964         createSurface(Points::Centers, m_params.model.first, m_params.model.second, funcs);
965     const de::MovePtr<BufferWithMemory> attribBuffer = makeAttribBuff(vk, device, allocator, vertices, coords, centers);
966 
967     TopLevelAccelerationStructurePtr topAccStruct{};
968     Move<VkDescriptorSetLayout> descriptorLayout =
969         DescriptorSetLayoutBuilder()
970             .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_FRAGMENT_BIT)
971             .build(vk, device);
972     Move<VkDescriptorPool> descriptorPool =
973         DescriptorPoolBuilder()
974             .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
975             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
976     Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorLayout);
977 
978     Move<VkShaderModule> vertexShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
979     Move<VkShaderModule> fragmentShader =
980         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
981     Move<VkPipelineLayout> pipelineLayout =
982         makePipelineLayout(vk, device, 1u, &descriptorLayout.get(), 1u, &pushConstantRange);
983     Move<VkPipeline> pipeline = makePipeline(vk, device, *pipelineLayout, *vertexShader, *fragmentShader, *renderPass);
984     const Move<VkCommandPool> cmdPool =
985         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
986     const Move<VkCommandBuffer> cmdBuffer =
987         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
988 
989     const Vec4 clearColor(0.1f, 0.2f, 0.3f, 0.4f);
990     const VkImageMemoryBarrier postDrawImageBarrier = makeImageMemoryBarrier(
991         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
992         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **image, imageSubresourceRange);
993     const VkMemoryBarrier postCopyMemoryBarrier =
994         makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
995 
996     beginCommandBuffer(vk, *cmdBuffer, 0u);
997 
998     topAccStruct              = createAccStructs(vk, device, allocator, *cmdBuffer, coords);
999     const auto accStructWrite = makeAccStructDescriptorWrite(topAccStruct->getPtr());
1000     DescriptorSetUpdateBuilder()
1001         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1002                      VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accStructWrite)
1003         .update(vk, device);
1004 
1005     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1006     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &static_cast<const VkBuffer &>(**attribBuffer),
1007                             &static_cast<const VkDeviceSize &>(0u));
1008     vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, uint32_t(sizeof(pushConstants)),
1009                         &pushConstants);
1010     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(),
1011                              0u, nullptr);
1012 
1013     beginRenderPass(vk, *cmdBuffer, *renderPass, *frameBuffer, renderArea, clearColor);
1014     vk.cmdDraw(*cmdBuffer, uint32_t(vertices.size()), 1u, 0u, 0u);
1015     endRenderPass(vk, *cmdBuffer);
1016 
1017     cmdPipelineImageMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1018                                   &postDrawImageBarrier);
1019     vk.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer, 1u,
1020                             &bufferCopyImageRegion);
1021     cmdPipelineMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
1022                              &postCopyMemoryBarrier);
1023 
1024     endCommandBuffer(vk, *cmdBuffer);
1025 
1026     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1027 
1028     return verifyResult(vk, device, *resultBuffer) ? TestStatus::pass("") : TestStatus::fail("");
1029 }
1030 
1031 } // namespace
1032 
addHelperInvocationsTests(TestContext & testCtx)1033 TestCaseGroup *addHelperInvocationsTests(TestContext &testCtx)
1034 {
1035     std::pair<bool, const char *> const builds[]{{true, "gpu"}, {false, "cpu"}};
1036 
1037     std::pair<HelperInvocationsParams::DfStyle, const char *> const styles[]{
1038         {HelperInvocationsParams::Regular, "regular"},
1039         {HelperInvocationsParams::Coarse, "coarse"},
1040         {HelperInvocationsParams::Fine, "fine"}};
1041 
1042     std::pair<HelperInvocationsParams::test_mode_t, const char *> const modes[] = {
1043         {HelperInvocationsParams::MODE_LINEAR_QUADRATIC, "linear_quadratic"},
1044         {HelperInvocationsParams::MODE_LINEAR_CUBIC, "linear_cubic"},
1045         {HelperInvocationsParams::MODE_CUBIC_QUADRATIC, "cubic_quadratic"},
1046 #ifdef ENABLE_ALL_HELPER_COMBINATIONS
1047         {HelperInvocationsParams::MODE_LINEAR_LINEAR, "linear_linear"},
1048         {HelperInvocationsParams::MODE_QUADRATIC_LINEAR, "quadratic_linear"},
1049         {HelperInvocationsParams::MODE_QUADRATIC_QUADRATIC, "quadratic_quadratic"},
1050         {HelperInvocationsParams::MODE_QUADRATIC_CUBIC, "quadratic_cubic"},
1051         {HelperInvocationsParams::MODE_CUBIC_LINEAR, "cubic_linear"},
1052         {HelperInvocationsParams::MODE_CUBIC_CUBIC, "cubic_cubic"},
1053 #endif
1054     };
1055 
1056     std::pair<uint32_t, uint32_t> const screens[]{{64, 64}, {32, 64}};
1057 
1058     std::pair<uint32_t, uint32_t> const models[]{{64, 64}, {64, 32}};
1059 
1060     auto makeTestName = [](const std::pair<uint32_t, uint32_t> &d) -> std::string
1061     { return std::to_string(d.first) + "x" + std::to_string(d.second); };
1062 
1063     auto rootGroup = new TestCaseGroup(testCtx, "helper_invocations");
1064     for (auto &build : builds)
1065     {
1066         auto buildGroup = new tcu::TestCaseGroup(testCtx, build.second);
1067         for (auto &style : styles)
1068         {
1069             auto styleGroup = new tcu::TestCaseGroup(testCtx, style.second);
1070             for (auto &mode : modes)
1071             {
1072                 auto modeGroup = new tcu::TestCaseGroup(testCtx, mode.second);
1073                 for (auto &screen : screens)
1074                 {
1075                     auto screenGroup = new TestCaseGroup(testCtx, makeTestName(screen).c_str());
1076                     for (auto &model : models)
1077                     {
1078                         HelperInvocationsParams p;
1079                         p.mode     = mode.first;
1080                         p.screen   = screen;
1081                         p.model    = model;
1082                         p.style    = style.first;
1083                         p.buildGPU = build.first;
1084 
1085                         screenGroup->addChild(new HelperInvocationsCase(testCtx, p, makeTestName(model)));
1086                     }
1087                     modeGroup->addChild(screenGroup);
1088                 }
1089                 styleGroup->addChild(modeGroup);
1090             }
1091             buildGroup->addChild(styleGroup);
1092         }
1093         rootGroup->addChild(buildGroup);
1094     }
1095     return rootGroup;
1096 }
1097 
createMiscTests(tcu::TestContext & testCtx)1098 tcu::TestCaseGroup *createMiscTests(tcu::TestContext &testCtx)
1099 {
1100     // Miscellaneous ray query tests
1101     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "misc"));
1102 
1103     // Dynamic indexing of ray queries
1104     group->addChild(new DynamicIndexingCase(testCtx, "dynamic_indexing"));
1105 
1106     return group.release();
1107 }
1108 
1109 } // namespace RayQuery
1110 } // namespace vkt
1111