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 ¶ms, 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 ¶ms);
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> ¢ers) 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 ¶ms,
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 ¶ms)
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> ¢ers) 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