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