1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2023 Advanced Micro Devices, Inc.
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 multiple rayQuery objects for VK_KHR_ray_query utility functions
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktRayQueryMultipleRayQueries.hpp"
26 #include "vkRayTracingUtil.hpp"
27 #include "tcuTestCase.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "tcuSurface.hpp"
31
32 namespace vkt
33 {
34 namespace RayQuery
35 {
36
37 namespace
38 {
39
40 using namespace vk;
41 constexpr float MAX_T_VALUE = 10000000.0;
42
43 struct ResultData
44 {
ResultDatavkt::RayQuery::__anon9a137c920111::ResultData45 ResultData() : x(0.f), y(0.f), z(0.f), w(0.f)
46 {
47 }
ResultDatavkt::RayQuery::__anon9a137c920111::ResultData48 ResultData(const float ix) : x(ix), y(ix), z(ix), w(ix)
49 {
50 }
ResultDatavkt::RayQuery::__anon9a137c920111::ResultData51 ResultData(const float ix, const float iy, const float iz, const float iw) : x(ix), y(iy), z(iz), w(iw)
52 {
53 }
equalvkt::RayQuery::__anon9a137c920111::ResultData54 bool equal(ResultData other)
55 {
56 const float epsilon = 0.000001f;
57 return ((abs(other.x - x) < epsilon) && (abs(other.y - y) < epsilon) && (abs(other.z - z) < epsilon) &&
58 (abs(other.w - w) < epsilon));
59 }
60
61 float x;
62 float y;
63 float z;
64 float w;
65 };
66
computeExpectedResults()67 static std::vector<ResultData> computeExpectedResults()
68 {
69 std::vector<ResultData> expectedResults;
70 expectedResults.push_back(ResultData{0, 3, 6, 0});
71 expectedResults.push_back(ResultData{1, 4, 7, 0});
72 expectedResults.push_back(ResultData{2, 5, 8, 0});
73 expectedResults.push_back(ResultData{10, 13, 16, 0});
74 expectedResults.push_back(ResultData{11, 14, 17, 0});
75 expectedResults.push_back(ResultData{12, 15, 18, 0});
76 return expectedResults;
77 }
78
79 class MultipleRayQueriesCase : public TestCase
80 {
81 public:
82 MultipleRayQueriesCase(tcu::TestContext &testCtx, const std::string &name, const RayQueryTestParams ¶ms);
~MultipleRayQueriesCase(void)83 virtual ~MultipleRayQueriesCase(void)
84 {
85 }
86
87 virtual void checkSupport(Context &context) const;
88 virtual void initPrograms(vk::SourceCollections &programCollection) const;
89 virtual TestInstance *createInstance(Context &context) const;
90
91 protected:
92 RayQueryTestParams m_params;
93 };
94
95 class MultipleRayQueriesInstance : public TestInstance
96 {
97 public:
98 MultipleRayQueriesInstance(Context &context, const RayQueryTestParams ¶ms);
~MultipleRayQueriesInstance(void)99 virtual ~MultipleRayQueriesInstance(void)
100 {
101 }
102
103 virtual tcu::TestStatus iterate(void);
104
105 protected:
106 RayQueryTestParams m_params;
107 };
108
MultipleRayQueriesCase(tcu::TestContext & testCtx,const std::string & name,const RayQueryTestParams & params)109 MultipleRayQueriesCase::MultipleRayQueriesCase(tcu::TestContext &testCtx, const std::string &name,
110 const RayQueryTestParams ¶ms)
111 : TestCase(testCtx, name)
112 , m_params(params)
113 {
114 }
115
checkSupport(Context & context) const116 void MultipleRayQueriesCase::checkSupport(Context &context) const
117 {
118 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
119 context.requireDeviceFunctionality("VK_KHR_ray_query");
120
121 const VkPhysicalDeviceRayQueryFeaturesKHR &rayQueryFeaturesKHR = context.getRayQueryFeatures();
122 if (rayQueryFeaturesKHR.rayQuery == false)
123 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayQueryFeaturesKHR.rayQuery");
124
125 const VkPhysicalDeviceAccelerationStructureFeaturesKHR &accelerationStructureFeaturesKHR =
126 context.getAccelerationStructureFeatures();
127 if (accelerationStructureFeaturesKHR.accelerationStructure == false)
128 TCU_THROW(TestError,
129 "VK_KHR_ray_query requires VkPhysicalDeviceAccelerationStructureFeaturesKHR.accelerationStructure");
130
131 const VkPhysicalDeviceFeatures2 &features2 = context.getDeviceFeatures2();
132
133 if ((m_params.shaderSourceType == RayQueryShaderSourceType::TESSELLATION_CONTROL ||
134 m_params.shaderSourceType == RayQueryShaderSourceType::TESSELLATION_EVALUATION) &&
135 features2.features.tessellationShader == false)
136 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceFeatures2.tessellationShader");
137
138 if (m_params.shaderSourceType == RayQueryShaderSourceType::GEOMETRY && features2.features.geometryShader == false)
139 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceFeatures2.geometryShader");
140
141 switch (m_params.shaderSourceType)
142 {
143 case RayQueryShaderSourceType::VERTEX:
144 case RayQueryShaderSourceType::TESSELLATION_CONTROL:
145 case RayQueryShaderSourceType::TESSELLATION_EVALUATION:
146 case RayQueryShaderSourceType::GEOMETRY:
147 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
148 break;
149 default:
150 break;
151 }
152
153 if (m_params.shaderSourceType == RayQueryShaderSourceType::RAY_GENERATION ||
154 m_params.shaderSourceType == RayQueryShaderSourceType::INTERSECTION ||
155 m_params.shaderSourceType == RayQueryShaderSourceType::ANY_HIT ||
156 m_params.shaderSourceType == RayQueryShaderSourceType::CLOSEST_HIT ||
157 m_params.shaderSourceType == RayQueryShaderSourceType::MISS ||
158 m_params.shaderSourceType == RayQueryShaderSourceType::CALLABLE)
159 {
160 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
161
162 const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
163 context.getRayTracingPipelineFeatures();
164
165 if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
166 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
167 }
168 }
169
initPrograms(vk::SourceCollections & programCollection) const170 void MultipleRayQueriesCase::initPrograms(vk::SourceCollections &programCollection) const
171 {
172 std::string rayQueryPart = "";
173 std::string ifPart = "";
174 std::string elsePart = "";
175 std::ostringstream src;
176
177 // This is rayQueryEXT array version
178 src << " const int rayQueryCount = 3;\n"
179 " Ray ray[rayQueryCount];\n"
180 " ray[0] = rays[index];\n"
181 " ray[1] = rays[index];\n"
182 " ray[2] = rays[index];\n"
183 " ray[1].pos.x += 3.0;\n"
184 " ray[2].pos.x += 6.0;\n"
185 " float x = 0;\n"
186 " float y = 0;\n"
187 " float z = 0;\n"
188 " float w = 0;\n"
189 " float tempResults[] = {0, 0, 0};\n"
190 " rayQueryEXT rqs[rayQueryCount];\n"
191 " bool prcds[] = {true, true, true};\n"
192 "\n"
193 " for (int idx=0;idx<rayQueryCount;++idx)\n"
194 " {\n"
195 " rayQueryInitializeEXT(rqs[idx], scene, "
196 << m_params.rayFlags
197 << ", 0xFF, ray[idx].pos, ray[idx].tmin, ray[idx].dir, ray[idx].tmax);\n"
198 " }\n"
199 "\n"
200 " bool proceed = true;\n"
201 " while (proceed)\n" // traverse all rayQueries in parallel to verify rayQueryCount issues
202 " {\n"
203 " proceed = false;\n"
204 " for (int idx=0;idx<rayQueryCount;++idx)\n"
205 " {\n"
206 " prcds[idx] = prcds[idx] && rayQueryProceedEXT(rqs[idx]);\n"
207 " if (prcds[idx])\n"
208 " {\n"
209 " if (rayQueryGetIntersectionTypeEXT(rqs[idx], true) == "
210 "gl_RayQueryCommittedIntersectionGeneratedEXT)\n"
211 " {\n"
212 " prcds[idx] = false;\n"
213 " }\n"
214 " else if (rayQueryGetIntersectionTypeEXT(rqs[idx], false) == "
215 "gl_RayQueryCandidateIntersectionTriangleEXT)\n"
216 " {\n"
217 " rayQueryConfirmIntersectionEXT(rqs[idx]);\n"
218 " }\n"
219 " else if (rayQueryGetIntersectionTypeEXT(rqs[idx], false) == "
220 "gl_RayQueryCandidateIntersectionAABBEXT)\n"
221 " {\n"
222 " rayQueryGenerateIntersectionEXT(rqs[idx], 5.f + ((3 * idx) + (index - 3)) * 10.f );\n"
223 " }\n"
224 " }\n"
225 " proceed = proceed || prcds[idx];\n"
226 " }\n"
227 " }\n"
228 " for (int idx=0;idx<rayQueryCount;++idx)\n"
229 " {\n"
230 " if ((rayQueryGetIntersectionTypeEXT(rqs[idx], true) == "
231 "gl_RayQueryCommittedIntersectionTriangleEXT) ||\n"
232 " (rayQueryGetIntersectionTypeEXT(rqs[idx], true) == "
233 "gl_RayQueryCommittedIntersectionGeneratedEXT))\n"
234 " {\n"
235 " uint instIdx = rayQueryGetIntersectionInstanceIdEXT(rqs[idx], true);\n"
236 " uint primIndex = rayQueryGetIntersectionPrimitiveIndexEXT(rqs[idx], true);\n"
237 " tempResults[idx] = float(instIdx) * 10.f + float(primIndex);\n"
238 " }\n"
239 " rayQueryTerminateEXT(rqs[idx]);\n"
240 " }\n"
241 "\n"
242 " x = tempResults[0];\n"
243 " y = tempResults[1];\n"
244 " z = tempResults[2];\n";
245
246 rayQueryPart = src.str();
247 generateRayQueryShaders(programCollection, m_params, rayQueryPart, MAX_T_VALUE);
248 }
249
createInstance(Context & context) const250 TestInstance *MultipleRayQueriesCase::createInstance(Context &context) const
251 {
252 return new MultipleRayQueriesInstance(context, m_params);
253 }
254
MultipleRayQueriesInstance(Context & context,const RayQueryTestParams & params)255 MultipleRayQueriesInstance::MultipleRayQueriesInstance(Context &context, const RayQueryTestParams ¶ms)
256 : vkt::TestInstance(context)
257 , m_params(params)
258 {
259 }
260
iterate(void)261 tcu::TestStatus MultipleRayQueriesInstance::iterate(void)
262 {
263 std::vector<tcu::Vec3> emptyVerts;
264
265 m_params.rays = {Ray{tcu::Vec3(-2.5f, 0.5f, 0.0f), 0.0f, tcu::Vec3(0.0f, 0.0f, 1.0f), MAX_T_VALUE},
266 Ray{tcu::Vec3(-2.5f, -0.5f, 0.0f), 1.0f, tcu::Vec3(0.0f, 0.0f, 1.0f), MAX_T_VALUE},
267 Ray{tcu::Vec3(-1.5f, 0.5f, 0.0f), 2.0f, tcu::Vec3(0.0f, 0.0f, 1.0f), MAX_T_VALUE},
268 Ray{tcu::Vec3(-2.5f, 0.0f, 95.0f), 3.0f, tcu::Vec3(0.0f, 0.0f, 1.0f), MAX_T_VALUE},
269 Ray{tcu::Vec3(-1.5f, 0.0f, 95.0f), 4.0f, tcu::Vec3(0.0f, 0.0f, 1.0f), MAX_T_VALUE},
270 Ray{tcu::Vec3(-0.5f, 0.0f, 95.0f), 5.0f, tcu::Vec3(0.0f, 0.0f, 1.0f), MAX_T_VALUE}};
271
272 const uint32_t width = static_cast<uint32_t>(m_params.rays.size());
273 const uint32_t height = 1;
274
275 // instance 0
276 //(-3,1) (-2,1) (-1,1) (0,1) (1,1) (2,1) (3,1) (4,1) (5,1)
277 // X------X------X X------X------X X------X------X
278 // | {A} /| {C} / | {D} /| {F} / | {G} /| {I} /
279 // | rq1/ | rq1/ | rq2/ | rq2/ | rq3/ | rq3/
280 // | / | / | / | / | / | /
281 // | / | / | / | / | / | /
282 // | / {B}| / | / {E}| / | / {H}| /
283 // |/ rq1 |/ |/ rq2 |/ |/ rq3|/
284 // X------X X------X X------X
285 //(-3,-1) (-2,-1) (0,-1) (1,-1) (3,-1) (4,-1)
286 //
287
288 // instance 1
289 // (-3,1) (-2,1) (-1,1) (0,1) (1,1) (2,1) (3,1) (4,1) (5,1) (6,1)
290 // X------X------X------X------X------X------X------X------X------X
291 // | | | | | | | | | |
292 // | | | | | | | | | |
293 // | | | | | | | | | |
294 // | {J} | {K} | {L} | {M} | {N} | {O} | {P} | {Q} | {R} |
295 // | rq1 | rq1 | rq1 | rq2 | rq2 | rq2 | rq3 | rq3 | rq3 |
296 // | | | | | | | | | |
297 // X------X------X------X------X------X------X------X------X------X
298 // (-3,-1)(-2,-1) (-1,-1)(0,-1) (1,-1) (2,-1) (3,-1) (4,-1) (5,-1) (6,-1)
299 //
300
301 std::vector<tcu::Vec3> instance1 = {{-3.0f, 1.0f, 10.f}, // (A) - prim 0
302 {-2.0f, 1.0f, 10.f}, {-3.0f, -1.0f, 10.f}, {-3.0f, -1.0f, 20.f}, // (B) - prim 1
303 {-2.0f, 1.0f, 20.f}, {-2.0f, -1.0f, 20.f}, {-2.0f, 1.0f, 30.f}, // (C) - prim 2
304 {-1.0f, 1.0f, 30.f}, {-2.0f, -1.0f, 30.f}, {0.0f, 1.0f, 40.f}, // (D) - prim 3
305 {1.0f, 1.0f, 40.f}, {0.0f, -1.0f, 40.f}, {0.0f, -1.0f, 50.f}, // (E) - prim 4
306 {1.0f, 1.0f, 50.f}, {1.0f, -1.0f, 50.f}, {1.0f, 1.0f, 60.f}, // (F) - prim 5
307 {2.0f, 1.0f, 60.f}, {1.0f, -1.0f, 60.f}, {3.0f, 1.0f, 70.f}, // (G) - prim 6
308 {4.0f, 1.0f, 70.f}, {3.0f, -1.0f, 70.f}, {3.0f, -1.0f, 80.f}, // (H) - prim 7
309 {4.0f, 1.0f, 80.f}, {4.0f, -1.0f, 80.f}, {4.0f, 1.0f, 90.f}, // (I) - prim 8
310 {5.0f, 1.0f, 90.f}, {4.0f, -1.0f, 90.f}};
311
312 std::vector<tcu::Vec3> instance2 = {{-3.0f, -1.0f, 100.f}, // (J) - prim 0
313 {-2.0f, 1.0f, 100.f}, {-2.0f, -1.0f, 110.f}, // (K) - prim 1
314 {-1.0f, 1.0f, 110.f}, {-1.0f, -1.0f, 120.f}, // (L) - prim 2
315 {0.0f, 1.0f, 120.f}, {0.0f, -1.0f, 130.f}, // (M) - prim 3
316 {1.0f, 1.0f, 130.f}, {1.0f, -1.0f, 140.f}, // (N) - prim 4
317 {2.0f, 1.0f, 140.f}, {2.0f, -1.0f, 150.f}, // (O) - prim 5
318 {3.0f, 1.0f, 150.f}, {3.0f, -1.0f, 160.f}, // (P) - prim 6
319 {4.0f, 1.0f, 160.f}, {4.0f, -1.0f, 170.f}, // (Q) - prim 7
320 {5.0f, 1.0f, 170.f}, {5.0f, -1.0f, 180.f}, // (R) - prim 8
321 {6.0f, 1.0f, 180.f}};
322
323 m_params.verts.push_back(instance1);
324 m_params.verts.push_back(emptyVerts);
325 m_params.aabbs.push_back(emptyVerts);
326 m_params.aabbs.push_back(instance2);
327
328 std::vector<ResultData> expectedResults = computeExpectedResults();
329
330 std::vector<ResultData> resultData;
331
332 switch (m_params.pipelineType)
333 {
334 case RayQueryShaderSourcePipeline::COMPUTE:
335 {
336 resultData = rayQueryComputeTestSetup<ResultData>(
337 m_context.getDeviceInterface(), m_context.getDevice(), m_context.getDefaultAllocator(),
338 m_context.getInstanceInterface(), m_context.getPhysicalDevice(), m_context.getBinaryCollection(),
339 m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(), m_params);
340 break;
341 }
342 case RayQueryShaderSourcePipeline::RAYTRACING:
343 {
344 m_context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
345 const VkPhysicalDeviceRayTracingPipelineFeaturesKHR &rayTracingPipelineFeaturesKHR =
346 m_context.getRayTracingPipelineFeatures();
347
348 if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == false)
349 TCU_THROW(NotSupportedError, "Requires VkPhysicalDeviceRayTracingPipelineFeaturesKHR.rayTracingPipeline");
350
351 resultData = rayQueryRayTracingTestSetup<ResultData>(
352 m_context.getDeviceInterface(), m_context.getDevice(), m_context.getDefaultAllocator(),
353 m_context.getInstanceInterface(), m_context.getPhysicalDevice(), m_context.getBinaryCollection(),
354 m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(), m_params);
355 break;
356 }
357 case RayQueryShaderSourcePipeline::GRAPHICS:
358 {
359 resultData = rayQueryGraphicsTestSetup<ResultData>(
360 m_context.getDeviceInterface(), m_context.getDevice(), m_context.getUniversalQueueFamilyIndex(),
361 m_context.getDefaultAllocator(), m_context.getBinaryCollection(), m_context.getUniversalQueue(),
362 m_context.getInstanceInterface(), m_context.getPhysicalDevice(), m_params);
363 break;
364 }
365 default:
366 {
367 TCU_FAIL("Invalid shader type!");
368 }
369 }
370
371 bool mismatch = false;
372
373 tcu::Surface resultImage(width, height);
374 for (uint32_t x = 0; x < static_cast<uint32_t>(resultImage.getWidth()); ++x)
375 {
376 for (uint32_t y = 0; y < static_cast<uint32_t>(resultImage.getHeight()); ++y)
377 {
378 uint32_t index = x * resultImage.getHeight() + y;
379 if (resultData[index].equal(expectedResults[index]))
380 {
381 resultImage.setPixel(x, y, tcu::RGBA(255, 0, 0, 255));
382 }
383 else
384 {
385 mismatch = true;
386 resultImage.setPixel(x, y, tcu::RGBA(0, 0, 0, 255));
387 }
388 }
389 }
390
391 // Write Image
392 m_context.getTestContext().getLog() << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
393 << tcu::TestLog::Image("Result", "Result", resultImage)
394 << tcu::TestLog::EndImageSet;
395
396 if (mismatch)
397 TCU_FAIL("Result data did not match expected output");
398
399 return tcu::TestStatus::pass("pass");
400 }
401
402 } // anonymous namespace
403
createMultipleRayQueryTests(tcu::TestContext & testCtx)404 tcu::TestCaseGroup *createMultipleRayQueryTests(tcu::TestContext &testCtx)
405 {
406 struct ShaderSourceTypeData
407 {
408 RayQueryShaderSourceType shaderSourceType;
409 RayQueryShaderSourcePipeline shaderSourcePipeline;
410 const char *name;
411 } shaderSourceTypes[] = {
412 {RayQueryShaderSourceType::VERTEX, RayQueryShaderSourcePipeline::GRAPHICS, "vertex_shader"},
413 {RayQueryShaderSourceType::TESSELLATION_CONTROL, RayQueryShaderSourcePipeline::GRAPHICS, "tess_control_shader"},
414 {RayQueryShaderSourceType::TESSELLATION_EVALUATION, RayQueryShaderSourcePipeline::GRAPHICS,
415 "tess_evaluation_shader"},
416 {
417 RayQueryShaderSourceType::GEOMETRY,
418 RayQueryShaderSourcePipeline::GRAPHICS,
419 "geometry_shader",
420 },
421 {
422 RayQueryShaderSourceType::FRAGMENT,
423 RayQueryShaderSourcePipeline::GRAPHICS,
424 "fragment_shader",
425 },
426 {
427 RayQueryShaderSourceType::COMPUTE,
428 RayQueryShaderSourcePipeline::COMPUTE,
429 "compute_shader",
430 },
431 {
432 RayQueryShaderSourceType::RAY_GENERATION,
433 RayQueryShaderSourcePipeline::RAYTRACING,
434 "rgen_shader",
435 },
436 {
437 RayQueryShaderSourceType::INTERSECTION,
438 RayQueryShaderSourcePipeline::RAYTRACING,
439 "isect_shader",
440 },
441 {
442 RayQueryShaderSourceType::ANY_HIT,
443 RayQueryShaderSourcePipeline::RAYTRACING,
444 "ahit_shader",
445 },
446 {
447 RayQueryShaderSourceType::CLOSEST_HIT,
448 RayQueryShaderSourcePipeline::RAYTRACING,
449 "chit_shader",
450 },
451 {
452 RayQueryShaderSourceType::MISS,
453 RayQueryShaderSourcePipeline::RAYTRACING,
454 "miss_shader",
455 },
456 {
457 RayQueryShaderSourceType::CALLABLE,
458 RayQueryShaderSourcePipeline::RAYTRACING,
459 "call_shader",
460 },
461 };
462
463 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "multiple_ray_queries"));
464
465 for (size_t shaderSourceNdx = 0; shaderSourceNdx < DE_LENGTH_OF_ARRAY(shaderSourceTypes); ++shaderSourceNdx)
466 {
467 RayQueryTestParams testParams{};
468 testParams.shaderSourceType = shaderSourceTypes[shaderSourceNdx].shaderSourceType;
469 testParams.pipelineType = shaderSourceTypes[shaderSourceNdx].shaderSourcePipeline;
470 group->addChild(
471 new MultipleRayQueriesCase(group->getTestContext(), shaderSourceTypes[shaderSourceNdx].name, testParams));
472 }
473
474 return group.release();
475 }
476
477 } // namespace RayQuery
478 } // namespace vkt
479