• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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