1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Test procedural geometry with complex bouding box sets
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRayQueryProceduralGeometryTests.hpp"
25 #include "vkDefs.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vkCmdUtil.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkBarrierUtil.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkImageWithMemory.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkRayTracingUtil.hpp"
37 #include "tcuVectorUtil.hpp"
38 #include "tcuTexture.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuFloat.hpp"
42 
43 namespace vkt
44 {
45 namespace RayQuery
46 {
47 namespace
48 {
49 using namespace vk;
50 using namespace vkt;
51 
52 enum class TestType
53 {
54     OBJECT_BEHIND_BOUNDING_BOX = 0,
55     TRIANGLE_IN_BETWEEN
56 };
57 
58 class RayQueryProceduralGeometryTestBase : public TestInstance
59 {
60 public:
61     RayQueryProceduralGeometryTestBase(Context &context);
62     ~RayQueryProceduralGeometryTestBase(void) = default;
63 
64     tcu::TestStatus iterate(void) override;
65 
66 protected:
67     virtual void setupAccelerationStructures() = 0;
68 
69 private:
70     VkWriteDescriptorSetAccelerationStructureKHR makeASWriteDescriptorSet(
71         const VkAccelerationStructureKHR *pAccelerationStructure);
72     void clearBuffer(de::SharedPtr<BufferWithMemory> buffer, VkDeviceSize bufferSize);
73 
74 protected:
75     Move<VkCommandPool> m_cmdPool;
76     Move<VkCommandBuffer> m_cmdBuffer;
77 
78     std::vector<de::SharedPtr<BottomLevelAccelerationStructure>> m_blasVect;
79     de::SharedPtr<TopLevelAccelerationStructure> m_referenceTLAS;
80     de::SharedPtr<TopLevelAccelerationStructure> m_resultTLAS;
81 };
82 
RayQueryProceduralGeometryTestBase(Context & context)83 RayQueryProceduralGeometryTestBase::RayQueryProceduralGeometryTestBase(Context &context)
84     : vkt::TestInstance(context)
85     , m_referenceTLAS(makeTopLevelAccelerationStructure().release())
86     , m_resultTLAS(makeTopLevelAccelerationStructure().release())
87 {
88 }
89 
iterate(void)90 tcu::TestStatus RayQueryProceduralGeometryTestBase::iterate(void)
91 {
92     const DeviceInterface &vkd      = m_context.getDeviceInterface();
93     const VkDevice device           = m_context.getDevice();
94     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
95     const VkQueue queue             = m_context.getUniversalQueue();
96     Allocator &allocator            = m_context.getDefaultAllocator();
97     const uint32_t imageSize        = 64u;
98 
99     const Move<VkDescriptorPool> descriptorPool =
100         DescriptorPoolBuilder()
101             .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 2u)
102             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
103             .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
104 
105     Move<VkDescriptorSetLayout> descriptorSetLayout =
106         DescriptorSetLayoutBuilder()
107             .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
108                               VK_SHADER_STAGE_COMPUTE_BIT) // as with single/four aabb's
109             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
110                               VK_SHADER_STAGE_COMPUTE_BIT) // ssbo with result/reference values
111             .build(vkd, device);
112 
113     const Move<VkDescriptorSet> referenceDescriptorSet =
114         makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
115     const Move<VkDescriptorSet> resultDescriptorSet =
116         makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout);
117 
118     const VkDeviceSize resultBufferSize = imageSize * imageSize * sizeof(int);
119     const VkBufferCreateInfo resultBufferCreateInfo =
120         makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
121     de::SharedPtr<BufferWithMemory> referenceBuffer = de::SharedPtr<BufferWithMemory>(
122         new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
123     de::SharedPtr<BufferWithMemory> resultBuffer = de::SharedPtr<BufferWithMemory>(
124         new BufferWithMemory(vkd, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
125 
126     Move<VkShaderModule> shaderModule =
127         createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
128     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
129     const VkComputePipelineCreateInfo pipelineCreateInfo{
130         VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType                        sType
131         DE_NULL,                                        // const void*                            pNext
132         0u,                                             // VkPipelineCreateFlags                flags
133         {                                               // VkPipelineShaderStageCreateInfo        stage
134          VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, (VkPipelineShaderStageCreateFlags)0,
135          VK_SHADER_STAGE_COMPUTE_BIT, *shaderModule, "main", DE_NULL},
136         *pipelineLayout, // VkPipelineLayout                        layout
137         DE_NULL,         // VkPipeline                            basePipelineHandle
138         0,               // int32_t                                basePipelineIndex
139     };
140     Move<VkPipeline> pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineCreateInfo);
141 
142     m_cmdPool   = createCommandPool(vkd, device, 0, queueFamilyIndex);
143     m_cmdBuffer = allocateCommandBuffer(vkd, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
144 
145     // clear result and reference buffers
146     clearBuffer(resultBuffer, resultBufferSize);
147     clearBuffer(referenceBuffer, resultBufferSize);
148 
149     beginCommandBuffer(vkd, *m_cmdBuffer, 0u);
150     {
151         setupAccelerationStructures();
152 
153         // update descriptor sets
154         {
155             typedef DescriptorSetUpdateBuilder::Location DSL;
156 
157             const VkWriteDescriptorSetAccelerationStructureKHR referenceAS =
158                 makeASWriteDescriptorSet(m_referenceTLAS->getPtr());
159             const VkDescriptorBufferInfo referenceSSBO = makeDescriptorBufferInfo(**referenceBuffer, 0u, VK_WHOLE_SIZE);
160             DescriptorSetUpdateBuilder()
161                 .writeSingle(*referenceDescriptorSet, DSL::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
162                              &referenceAS)
163                 .writeSingle(*referenceDescriptorSet, DSL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
164                              &referenceSSBO)
165                 .update(vkd, device);
166 
167             const VkWriteDescriptorSetAccelerationStructureKHR resultAS =
168                 makeASWriteDescriptorSet(m_resultTLAS->getPtr());
169             const VkDescriptorBufferInfo resultSSBO = makeDescriptorBufferInfo(**resultBuffer, 0u, VK_WHOLE_SIZE);
170             DescriptorSetUpdateBuilder()
171                 .writeSingle(*resultDescriptorSet, DSL::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
172                              &resultAS)
173                 .writeSingle(*resultDescriptorSet, DSL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultSSBO)
174                 .update(vkd, device);
175         }
176 
177         // wait for data transfers
178         const VkMemoryBarrier bufferUploadBarrier =
179             makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
180         cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
181                                  VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, &bufferUploadBarrier, 1u);
182 
183         // wait for as build
184         const VkMemoryBarrier asBuildBarrier =
185             makeMemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_SHADER_READ_BIT);
186         cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
187                                  VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, &asBuildBarrier, 1u);
188 
189         vkd.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
190 
191         // generate reference
192         vkd.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1,
193                                   &referenceDescriptorSet.get(), 0, DE_NULL);
194         vkd.cmdDispatch(*m_cmdBuffer, imageSize, imageSize, 1);
195 
196         // generate result
197         vkd.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1,
198                                   &resultDescriptorSet.get(), 0, DE_NULL);
199         vkd.cmdDispatch(*m_cmdBuffer, imageSize, imageSize, 1);
200 
201         const VkMemoryBarrier postTraceMemoryBarrier =
202             makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
203         cmdPipelineMemoryBarrier(vkd, *m_cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
204                                  VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
205     }
206     endCommandBuffer(vkd, *m_cmdBuffer);
207 
208     submitCommandsAndWait(vkd, device, queue, m_cmdBuffer.get());
209 
210     // verify result buffer
211     auto referenceAllocation = referenceBuffer->getAllocation();
212     invalidateMappedMemoryRange(vkd, device, referenceAllocation.getMemory(), referenceAllocation.getOffset(),
213                                 resultBufferSize);
214 
215     auto resultAllocation = resultBuffer->getAllocation();
216     invalidateMappedMemoryRange(vkd, device, resultAllocation.getMemory(), resultAllocation.getOffset(),
217                                 resultBufferSize);
218 
219     tcu::TextureFormat imageFormat(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
220     tcu::PixelBufferAccess referenceAccess(imageFormat, imageSize, imageSize, 1, referenceAllocation.getHostPtr());
221     tcu::PixelBufferAccess resultAccess(imageFormat, imageSize, imageSize, 1, resultAllocation.getHostPtr());
222 
223     if (tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Result comparison", "", referenceAccess,
224                                  resultAccess, tcu::UVec4(0), tcu::COMPARE_LOG_EVERYTHING))
225         return tcu::TestStatus::pass("Pass");
226     return tcu::TestStatus::fail("Fail");
227 }
228 
makeASWriteDescriptorSet(const VkAccelerationStructureKHR * pAccelerationStructure)229 VkWriteDescriptorSetAccelerationStructureKHR RayQueryProceduralGeometryTestBase::makeASWriteDescriptorSet(
230     const VkAccelerationStructureKHR *pAccelerationStructure)
231 {
232     return {
233         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType                        sType
234         DE_NULL,               // const void*                            pNext
235         1u,                    // uint32_t                                accelerationStructureCount
236         pAccelerationStructure // const VkAccelerationStructureKHR*    pAccelerationStructures
237     };
238 }
239 
clearBuffer(de::SharedPtr<BufferWithMemory> buffer,VkDeviceSize bufferSize)240 void RayQueryProceduralGeometryTestBase::clearBuffer(de::SharedPtr<BufferWithMemory> buffer, VkDeviceSize bufferSize)
241 {
242     const DeviceInterface &vkd = m_context.getDeviceInterface();
243     const VkDevice device      = m_context.getDevice();
244     auto &bufferAlloc          = buffer->getAllocation();
245     void *bufferPtr            = bufferAlloc.getHostPtr();
246 
247     deMemset(bufferPtr, 1, static_cast<size_t>(bufferSize));
248     vk::flushAlloc(vkd, device, bufferAlloc);
249 }
250 
251 class ObjectBehindBoundingBoxInstance : public RayQueryProceduralGeometryTestBase
252 {
253 public:
254     ObjectBehindBoundingBoxInstance(Context &context);
255     void setupAccelerationStructures() override;
256 };
257 
ObjectBehindBoundingBoxInstance(Context & context)258 ObjectBehindBoundingBoxInstance::ObjectBehindBoundingBoxInstance(Context &context)
259     : RayQueryProceduralGeometryTestBase(context)
260 {
261 }
262 
setupAccelerationStructures()263 void ObjectBehindBoundingBoxInstance::setupAccelerationStructures()
264 {
265     const DeviceInterface &vkd = m_context.getDeviceInterface();
266     const VkDevice device      = m_context.getDevice();
267     Allocator &allocator       = m_context.getDefaultAllocator();
268 
269     // build reference acceleration structure - single aabb big enough to fit whole procedural geometry
270     de::SharedPtr<BottomLevelAccelerationStructure> referenceBLAS(makeBottomLevelAccelerationStructure().release());
271     referenceBLAS->setGeometryData(
272         {
273             {0.0, 0.0, -64.0},
274             {64.0, 64.0, -16.0},
275         },
276         false, 0);
277     referenceBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
278     m_blasVect.push_back(referenceBLAS);
279 
280     m_referenceTLAS->setInstanceCount(1);
281     m_referenceTLAS->addInstance(m_blasVect.back());
282     m_referenceTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
283 
284     // build result acceleration structure - wall of 4 aabb's and generated object is actualy behind it (as it is just 1.0 unit thick)
285     de::SharedPtr<BottomLevelAccelerationStructure> resultBLAS(makeBottomLevelAccelerationStructure().release());
286     resultBLAS->setGeometryData(
287         {
288             {0.0, 0.0, 0.0},   // |  |
289             {32.0, 32.0, 1.0}, // |* |
290             {32.0, 0.0, 0.0},  //    |  |
291             {64.0, 32.0, 1.0}, //    | *|
292             {0.0, 32.0, 0.0},  // |* |
293             {32.0, 64.0, 1.0}, // |  |
294             {32.0, 32.0, 0.0}, //    | *|
295             {64.0, 64.0, 1.0}, //    |  |
296         },
297         false, 0);
298     resultBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
299     m_blasVect.push_back(resultBLAS);
300 
301     m_resultTLAS->setInstanceCount(1);
302     m_resultTLAS->addInstance(m_blasVect.back());
303     m_resultTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
304 }
305 
306 class TriangleInBeteenInstance : public RayQueryProceduralGeometryTestBase
307 {
308 public:
309     TriangleInBeteenInstance(Context &context);
310     void setupAccelerationStructures() override;
311 };
312 
TriangleInBeteenInstance(Context & context)313 TriangleInBeteenInstance::TriangleInBeteenInstance(Context &context) : RayQueryProceduralGeometryTestBase(context)
314 {
315 }
316 
setupAccelerationStructures()317 void TriangleInBeteenInstance::setupAccelerationStructures()
318 {
319     const DeviceInterface &vkd = m_context.getDeviceInterface();
320     const VkDevice device      = m_context.getDevice();
321     Allocator &allocator       = m_context.getDefaultAllocator();
322 
323     de::SharedPtr<BottomLevelAccelerationStructure> triangleBLAS(makeBottomLevelAccelerationStructure().release());
324     triangleBLAS->setGeometryData(
325         {
326             {16.0, 16.0, -8.0},
327             {56.0, 32.0, -8.0},
328             {32.0, 48.0, -8.0},
329         },
330         true, VK_GEOMETRY_OPAQUE_BIT_KHR);
331     triangleBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
332     m_blasVect.push_back(triangleBLAS);
333 
334     de::SharedPtr<BottomLevelAccelerationStructure> fullElipsoidBLAS(makeBottomLevelAccelerationStructure().release());
335     fullElipsoidBLAS->setGeometryData(
336         {
337             {0.0, 0.0, -64.0},
338             {64.0, 64.0, -16.0},
339         },
340         false, 0);
341     fullElipsoidBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
342     m_blasVect.push_back(fullElipsoidBLAS);
343 
344     // build reference acceleration structure - triangle and a single aabb big enough to fit whole procedural geometry
345     m_referenceTLAS->setInstanceCount(2);
346     m_referenceTLAS->addInstance(fullElipsoidBLAS);
347     m_referenceTLAS->addInstance(triangleBLAS);
348     m_referenceTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
349 
350     de::SharedPtr<BottomLevelAccelerationStructure> elipsoidWallBLAS(makeBottomLevelAccelerationStructure().release());
351     elipsoidWallBLAS->setGeometryData(
352         {
353             {0.0, 0.0, 0.0}, // |*  |
354             {20.0, 64.0, 1.0},
355             {20.0, 0.0, 0.0}, // | * |
356             {44.0, 64.0, 1.0},
357             {44.0, 0.0, 0.0}, // |  *|
358             {64.0, 64.0, 1.0},
359         },
360         false, 0);
361     elipsoidWallBLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
362     m_blasVect.push_back(elipsoidWallBLAS);
363 
364     // build result acceleration structure - triangle and a three aabb's (they are in front of triangle but generate intersections behind it)
365     m_resultTLAS->setInstanceCount(2);
366     m_resultTLAS->addInstance(elipsoidWallBLAS);
367     m_resultTLAS->addInstance(triangleBLAS);
368     m_resultTLAS->createAndBuild(vkd, device, *m_cmdBuffer, allocator);
369 }
370 
371 class RayQueryProceduralGeometryTestCase : public TestCase
372 {
373 public:
374     RayQueryProceduralGeometryTestCase(tcu::TestContext &context, const char *name, TestType testType);
375     ~RayQueryProceduralGeometryTestCase(void) = default;
376 
377     void checkSupport(Context &context) const override;
378     void initPrograms(SourceCollections &programCollection) const override;
379     TestInstance *createInstance(Context &context) const override;
380 
381 protected:
382     TestType m_testType;
383 };
384 
RayQueryProceduralGeometryTestCase(tcu::TestContext & context,const char * name,TestType testType)385 RayQueryProceduralGeometryTestCase::RayQueryProceduralGeometryTestCase(tcu::TestContext &context, const char *name,
386                                                                        TestType testType)
387     : TestCase(context, name)
388     , m_testType(testType)
389 {
390 }
391 
checkSupport(Context & context) const392 void RayQueryProceduralGeometryTestCase::checkSupport(Context &context) const
393 {
394     context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
395     context.requireDeviceFunctionality("VK_KHR_ray_query");
396 
397     if (!context.getRayQueryFeatures().rayQuery)
398         TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayQueryFeaturesKHR.rayQuery");
399 
400     if (!context.getAccelerationStructureFeatures().accelerationStructure)
401         TCU_THROW(TestError, "Requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
402 }
403 
initPrograms(SourceCollections & programCollection) const404 void RayQueryProceduralGeometryTestCase::initPrograms(SourceCollections &programCollection) const
405 {
406     const vk::ShaderBuildOptions glslBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
407 
408     std::string compSource =
409         "#version 460 core\n"
410         "#extension GL_EXT_ray_query : require\n"
411 
412         "layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;\n"
413         "layout(set = 0, binding = 1, std430) writeonly buffer Result {\n"
414         "    int value[];\n"
415         "} result;\n"
416 
417         "void main()\n"
418         "{\n"
419         "  float tmin          = 0.0;\n"
420         "  float tmax          = 50.0;\n"
421         "  vec3  rayOrigin     = vec3(float(gl_GlobalInvocationID.x) + 0.5f, float(gl_GlobalInvocationID.y) + 0.5f, "
422         "2.0);\n"
423         "  vec3  rayDir        = vec3(0.0,0.0,-1.0);\n"
424         "  uint  resultIndex   = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * gl_NumWorkGroups.x;\n"
425         "  int   payload       = 30;\n"
426 
427         // elipsoid center and radii
428         "  vec3 elipsoidOrigin = vec3(32.0, 32.0, -30.0);\n"
429         "  vec3 elipsoidRadii  = vec3(30.0, 15.0, 5.0);\n"
430 
431         "  rayQueryEXT rq;\n"
432         "  rayQueryInitializeEXT(rq, tlas, gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, rayOrigin, tmin, rayDir, "
433         "tmax);\n"
434 
435         "  while (rayQueryProceedEXT(rq))\n"
436         "  {\n"
437         "    uint intersectionType = rayQueryGetIntersectionTypeEXT(rq, false);\n"
438         "    if (intersectionType == gl_RayQueryCandidateIntersectionAABBEXT)\n"
439         "    {\n"
440         // simplify to ray sphere intersection
441         "      vec3  eliDir = rayOrigin - elipsoidOrigin;\n"
442         "      vec3  eliS   = eliDir / elipsoidRadii;\n"
443         "      vec3  rayS   = rayDir / elipsoidRadii;\n"
444 
445         "      float a = dot(rayS, rayS);\n"
446         "      float b = dot(eliS, rayS);\n"
447         "      float c = dot(eliS, eliS);\n"
448         "      float h = b * b - a * (c - 1.0);\n"
449         "      if (h >= 0.0)\n"
450         "        rayQueryGenerateIntersectionEXT(rq, (-b - sqrt(h)) / a);\n"
451         "    }\n"
452         "    else if (intersectionType == gl_RayQueryCandidateIntersectionTriangleEXT)\n"
453         "    {\n"
454         "      payload = 250;\n"
455         "      rayQueryConfirmIntersectionEXT(rq);\n"
456         "    }\n"
457         "  }\n"
458         "  if (rayQueryGetIntersectionTypeEXT(rq, true) != gl_RayQueryCommittedIntersectionNoneEXT)\n"
459         "  {\n"
460         "    int instanceId = rayQueryGetIntersectionInstanceIdEXT(rq, true);\n"
461         "    if (instanceId > -1)\n"
462         "    {\n"
463         "      float hitT      = rayQueryGetIntersectionTEXT(rq, true);\n"
464         "      vec3  lightDir  = normalize(vec3(0.0, 0.0, 1.0));\n"
465         "      vec3  hitPos    = rayOrigin + hitT * rayDir;\n"
466         "      vec3  hitNormal = normalize((hitPos - elipsoidOrigin) / elipsoidRadii);\n"
467         "      payload = 50 + int(200.0 * clamp(dot(hitNormal, lightDir), 0.0, 1.0));\n"
468         "    }\n"
469         "  }\n"
470 
471         // to be able to display result in cherry this is interpreated as r8g8b8a8 during verification
472         // we are using only red but we need to add alpha (note: r and a may be swapped depending on endianness)
473         "  result.value[resultIndex] = payload + 0xFF000000;\n"
474         "};\n";
475     programCollection.glslSources.add("comp") << glu::ComputeSource(compSource) << glslBuildOptions;
476 }
477 
createInstance(Context & context) const478 TestInstance *RayQueryProceduralGeometryTestCase::createInstance(Context &context) const
479 {
480     if (m_testType == TestType::TRIANGLE_IN_BETWEEN)
481         return new TriangleInBeteenInstance(context);
482 
483     // TestType::OBJECT_BEHIND_BOUNDING_BOX
484     return new ObjectBehindBoundingBoxInstance(context);
485 }
486 
487 } // namespace
488 
createProceduralGeometryTests(tcu::TestContext & testCtx)489 tcu::TestCaseGroup *createProceduralGeometryTests(tcu::TestContext &testCtx)
490 {
491     // Test procedural geometry with complex bouding box sets
492     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "procedural_geometry"));
493 
494     group->addChild(new RayQueryProceduralGeometryTestCase(testCtx, "object_behind_bounding_boxes",
495                                                            TestType::OBJECT_BEHIND_BOUNDING_BOX));
496     group->addChild(
497         new RayQueryProceduralGeometryTestCase(testCtx, "triangle_in_between", TestType::TRIANGLE_IN_BETWEEN));
498 
499     return group.release();
500 }
501 
502 } // namespace RayQuery
503 
504 } // namespace vkt
505