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
36 #include "tcuVector.hpp"
37
38 #include "deUniquePtr.hpp"
39 #include "deRandom.hpp"
40
41 #include <sstream>
42 #include <limits>
43 #include <vector>
44
45 namespace vkt
46 {
47 namespace RayQuery
48 {
49
50 namespace
51 {
52
53 using namespace vk;
54
55 class DynamicIndexingCase : public vkt::TestCase
56 {
57 public:
58 DynamicIndexingCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description);
~DynamicIndexingCase(void)59 virtual ~DynamicIndexingCase (void) {}
60
61 virtual void initPrograms (vk::SourceCollections& programCollection) const override;
62 virtual void checkSupport (Context& context) const override;
63 virtual TestInstance* createInstance (Context& context) const override;
64
65 // Constants and data types.
66 static constexpr deUint32 kLocalSizeX = 48u;
67 static constexpr deUint32 kNumQueries = 48u;
68
69 // This must match the shader.
70 struct InputData
71 {
72 deUint32 goodQueryIndex;
73 deUint32 proceedQueryIndex;
74 };
75 };
76
77 class DynamicIndexingInstance : public vkt::TestInstance
78 {
79 public:
80 DynamicIndexingInstance (Context& context);
~DynamicIndexingInstance(void)81 virtual ~DynamicIndexingInstance (void) {}
82
83 virtual tcu::TestStatus iterate (void);
84 };
85
DynamicIndexingCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description)86 DynamicIndexingCase::DynamicIndexingCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
87 : vkt::TestCase (testCtx, name, description)
88 {}
89
initPrograms(vk::SourceCollections & programCollection) const90 void DynamicIndexingCase::initPrograms (vk::SourceCollections& programCollection) const
91 {
92 const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
93
94 std::ostringstream src;
95
96 src
97 << "#version 460\n"
98 << "#extension GL_EXT_ray_query : require\n"
99 << "#extension GL_EXT_ray_tracing : require\n"
100 << "\n"
101 << "layout (local_size_x=" << kLocalSizeX << ", local_size_y=1, local_size_z=1) in; \n"
102 << "\n"
103 << "struct InputData {\n"
104 << " uint goodQueryIndex;\n"
105 << " uint proceedQueryIndex; // Note: same index as the one above in practice.\n"
106 << "};\n"
107 << "\n"
108 << "layout (set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
109 << "layout (set=0, binding=1, std430) buffer InputBlock {\n"
110 << " InputData inputData[];\n"
111 << "} inputBlock;\n"
112 << "layout (set=0, binding=2, std430) buffer OutputBlock {\n"
113 << " uint outputData[];\n"
114 << "} outputBlock;\n"
115 << "\n"
116 << "void main()\n"
117 << "{\n"
118 << " const uint numQueries = " << kNumQueries << ";\n"
119 << "\n"
120 << " const uint rayFlags = 0u; \n"
121 << " const uint cullMask = 0xFFu;\n"
122 << " const float tmin = 0.1;\n"
123 << " const float tmax = 10.0;\n"
124 << " const vec3 direct = vec3(0, 0, 1); \n"
125 << "\n"
126 << " rayQueryEXT rayQueries[numQueries];\n"
127 << " vec3 origin;\n"
128 << "\n"
129 << " InputData inputValues = inputBlock.inputData[gl_LocalInvocationID.x];\n"
130 << "\n"
131 << " // Initialize all queries. Only goodQueryIndex will have the right origin for a hit.\n"
132 << " for (int i = 0; i < numQueries; i++) {\n"
133 << " origin = ((i == inputValues.goodQueryIndex) ? vec3(0, 0, 0) : vec3(5, 5, 0));\n"
134 << " rayQueryInitializeEXT(rayQueries[i], topLevelAS, rayFlags, cullMask, origin, tmin, direct, tmax);\n"
135 << " }\n"
136 << "\n"
137 << " // Attempt to proceed with the good query to confirm a hit.\n"
138 << " while (rayQueryProceedEXT(rayQueries[inputValues.proceedQueryIndex]))\n"
139 << " outputBlock.outputData[gl_LocalInvocationID.x] = 1u; \n"
140 << "}\n"
141 ;
142
143 programCollection.glslSources.add("comp") << glu::ComputeSource(updateRayTracingGLSL(src.str())) << buildOptions;
144 }
145
checkSupport(Context & context) const146 void DynamicIndexingCase::checkSupport (Context& context) const
147 {
148 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
149 context.requireDeviceFunctionality("VK_KHR_ray_query");
150
151 const auto& rayQueryFeaturesKHR = context.getRayQueryFeatures();
152 if (!rayQueryFeaturesKHR.rayQuery)
153 TCU_THROW(NotSupportedError, "Ray queries not supported");
154
155 const auto& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures();
156 if (!accelerationStructureFeaturesKHR.accelerationStructure)
157 TCU_FAIL("Acceleration structures not supported but ray queries supported");
158 }
159
createInstance(Context & context) const160 vkt::TestInstance* DynamicIndexingCase::createInstance (Context& context) const
161 {
162 return new DynamicIndexingInstance(context);
163 }
164
DynamicIndexingInstance(Context & context)165 DynamicIndexingInstance::DynamicIndexingInstance (Context& context)
166 : vkt::TestInstance(context)
167 {}
168
getRndIndex(de::Random & rng,deUint32 size)169 deUint32 getRndIndex (de::Random& rng, deUint32 size)
170 {
171 DE_ASSERT(size > 0u);
172 DE_ASSERT(size <= static_cast<deUint32>(std::numeric_limits<int>::max()));
173
174 const int iMin = 0;
175 const int iMax = static_cast<int>(size) - 1;
176
177 return static_cast<deUint32>(rng.getInt(iMin, iMax));
178 }
179
iterate(void)180 tcu::TestStatus DynamicIndexingInstance::iterate (void)
181 {
182 using InputData = DynamicIndexingCase::InputData;
183 constexpr auto kLocalSizeX = DynamicIndexingCase::kLocalSizeX;
184 constexpr auto kNumQueries = DynamicIndexingCase::kNumQueries;
185
186 const auto& vkd = m_context.getDeviceInterface();
187 const auto device = m_context.getDevice();
188 auto& alloc = m_context.getDefaultAllocator();
189 const auto queue = m_context.getUniversalQueue();
190 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
191
192 de::Random rng (1604936737u);
193 InputData inputDataArray[kLocalSizeX];
194 deUint32 outputDataArray[kLocalSizeX];
195
196 // Prepare input buffer.
197 for (int i = 0; i < DE_LENGTH_OF_ARRAY(inputDataArray); ++i)
198 {
199 // The two values will contain the same query index.
200 inputDataArray[i].goodQueryIndex = getRndIndex(rng, kNumQueries);
201 inputDataArray[i].proceedQueryIndex = inputDataArray[i].goodQueryIndex;
202 }
203
204 const auto inputBufferSize = static_cast<VkDeviceSize>(sizeof(inputDataArray));
205 const auto inputBufferInfo = makeBufferCreateInfo(inputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
206 BufferWithMemory inputBuffer (vkd, device, alloc, inputBufferInfo, MemoryRequirement::HostVisible);
207 auto& inputBufferAlloc = inputBuffer.getAllocation();
208 void* inputBufferPtr = inputBufferAlloc.getHostPtr();
209
210 deMemcpy(inputBufferPtr, inputDataArray, static_cast<size_t>(inputBufferSize));
211 flushAlloc(vkd, device, inputBufferAlloc);
212
213 // Prepare output buffer.
214 const auto outputBufferSize = static_cast<VkDeviceSize>(sizeof(outputDataArray));
215 const auto outputBufferInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
216 BufferWithMemory outputBuffer (vkd, device, alloc, outputBufferInfo, MemoryRequirement::HostVisible);
217 auto& outputBufferAlloc = outputBuffer.getAllocation();
218 void* outputBufferPtr = outputBufferAlloc.getHostPtr();
219
220 deMemset(outputBufferPtr, 0, static_cast<size_t>(outputBufferSize));
221 flushAlloc(vkd, device, outputBufferAlloc);
222
223 // Prepare acceleration structures.
224 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
225 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
226 const auto cmdBuffer = cmdBufferPtr.get();
227 beginCommandBuffer(vkd, cmdBuffer);
228
229 de::SharedPtr<TopLevelAccelerationStructure> topLevelAS (makeTopLevelAccelerationStructure().release());
230 de::SharedPtr<BottomLevelAccelerationStructure> bottomLevelAS (makeBottomLevelAccelerationStructure().release());
231
232 // These need to match the origin and direction in the shader for a hit.
233 const std::vector<tcu::Vec3> vertices =
234 {
235 tcu::Vec3(-1.0f, -1.0f, 1.0f),
236 tcu::Vec3(-1.0f, 1.0f, 1.0f),
237 tcu::Vec3( 1.0f, -1.0f, 1.0f),
238
239 tcu::Vec3(-1.0f, 1.0f, 1.0f),
240 tcu::Vec3( 1.0f, 1.0f, 1.0f),
241 tcu::Vec3( 1.0f, -1.0f, 1.0f),
242 };
243
244 bottomLevelAS->addGeometry(vertices, /*triangles*/true, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
245 bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
246
247 topLevelAS->addInstance(bottomLevelAS);
248 topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
249
250 // Descriptor set layout.
251 const VkShaderStageFlagBits stageBit = VK_SHADER_STAGE_COMPUTE_BIT;
252
253 DescriptorSetLayoutBuilder layoutBuilder;
254 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stageBit);
255 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
256 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageBit);
257 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
258
259 // Shader module.
260 const auto shaderModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
261
262 // Pipeline layout.
263 const auto pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
264
265 const VkPipelineShaderStageCreateInfo shaderStageInfo =
266 {
267 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
268 nullptr, // const void* pNext;
269 0u, // VkPipelineShaderStageCreateFlags flags;
270 stageBit, // VkShaderStageFlagBits stage;
271 shaderModule.get(), // VkShaderModule module;
272 "main", // const char* pName;
273 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
274 };
275
276 const VkComputePipelineCreateInfo pipelineInfo =
277 {
278 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
279 nullptr, // const void* pNext;
280 0u, // VkPipelineCreateFlags flags;
281 shaderStageInfo, // VkPipelineShaderStageCreateInfo stage;
282 pipelineLayout.get(), // VkPipelineLayout layout;
283 DE_NULL, // VkPipeline basePipelineHandle;
284 0, // deInt32 basePipelineIndex;
285 };
286
287 const auto pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineInfo);
288
289 // Create and update descriptor set.
290 DescriptorPoolBuilder poolBuilder;
291 poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
292 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u);
293
294 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
295 const auto descriptorSetPtr = makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
296 const auto descriptorSet = descriptorSetPtr.get();
297
298 const VkWriteDescriptorSetAccelerationStructureKHR asWrite =
299 {
300 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
301 nullptr, // const void* pNext;
302 1u, // deUint32 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), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &asWrite);
311 updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputBufferWriteInfo);
312 updateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferWriteInfo);
313 updateBuilder.update(vkd, device);
314
315 // Use pipeline.
316 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
317 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet, 0u, nullptr);
318 vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
319
320 const auto memBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
321 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &memBarrier, 0u, nullptr, 0u, nullptr);
322
323 // Submit recorded commands.
324 endCommandBuffer(vkd, cmdBuffer);
325 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
326
327 // Check output buffer.
328 invalidateAlloc(vkd, device, outputBufferAlloc);
329 deMemcpy(outputDataArray, outputBufferPtr, static_cast<size_t>(outputBufferSize));
330
331 for (int i = 0; i < DE_LENGTH_OF_ARRAY(outputDataArray); ++i)
332 {
333 constexpr auto expected = 1u;
334 const auto& value = outputDataArray[i];
335
336 if (value != expected)
337 {
338 std::ostringstream msg;
339 msg << "Unexpected value found at position " << i << " in the output buffer: expected " << expected << " but found " << value;
340 TCU_FAIL(msg.str());
341 }
342 }
343
344 return tcu::TestStatus::pass("Pass");
345 }
346
347 } // anonymous
348
createMiscTests(tcu::TestContext & testCtx)349 tcu::TestCaseGroup* createMiscTests (tcu::TestContext& testCtx)
350 {
351 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "misc", "Miscellaneous ray query tests"));
352
353 group->addChild(new DynamicIndexingCase(testCtx, "dynamic_indexing", "Dynamic indexing of ray queries"));
354
355 return group.release();
356 }
357
358 } // RayQuery
359 } // vkt
360
361