• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 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 Pipeline Bind Point Tests
23  *//*--------------------------------------------------------------------*/
24 #include "vktPipelineBindPointTests.hpp"
25 #include "vktPipelineImageUtil.hpp"
26 
27 #include "vkObjUtil.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkRayTracingUtil.hpp"
36 
37 #include "tcuVector.hpp"
38 
39 #include <algorithm>
40 #include <string>
41 #include <sstream>
42 #include <type_traits>
43 #include <utility>
44 
45 namespace vkt
46 {
47 namespace pipeline
48 {
49 
50 namespace
51 {
52 
53 using namespace vk;
54 
55 // These operations will be tried in different orders.
56 // To avoid combinatory explosions, we'll only use two pipeline types per test, which means 2 pipeline bind operations and 2 related set bind operations.
57 // The following types will be mixed: (graphics, compute), (graphics, ray tracing) and (compute, ray tracing).
58 enum class SetupOp
59 {
60 	BIND_GRAPHICS_PIPELINE		= 0,
61 	BIND_COMPUTE_PIPELINE		= 1,
62 	BIND_RAYTRACING_PIPELINE	= 2,
63 	BIND_GRAPHICS_SET			= 3,
64 	BIND_COMPUTE_SET			= 4,
65 	BIND_RAYTRACING_SET			= 5,
66 	OP_COUNT					= 6,
67 };
68 
69 // How to bind each set.
70 enum class SetUpdateType
71 {
72 	WRITE				= 0,
73 	PUSH				= 1,
74 	PUSH_WITH_TEMPLATE	= 2,
75 	TYPE_COUNT			= 3,
76 };
77 
78 // Types of operations to dispatch. They will be tried in different orders and are related to the setup sequence.
79 enum class DispatchOp
80 {
81 	DRAW		= 0,
82 	COMPUTE		= 1,
83 	TRACE_RAYS	= 2,
84 	OP_COUNT	= 3,
85 };
86 
87 constexpr auto kTestBindPoints			= 2;					// Two bind points per test.
88 constexpr auto kSetupSequenceSize		= kTestBindPoints * 2;	// For each bind point: bind pipeline and bind set.
89 constexpr auto kDispatchSequenceSize	= kTestBindPoints;		// Dispatch two types of work, matching the bind points being used.
90 
91 using SetupSequence		= tcu::Vector<SetupOp, kSetupSequenceSize>;
92 using DispatchSequence	= tcu::Vector<DispatchOp, kDispatchSequenceSize>;
93 
94 // Test parameters.
95 struct TestParams
96 {
97 	SetUpdateType		graphicsSetUpdateType;
98 	SetUpdateType		computeSetUpdateType;
99 	SetUpdateType		rayTracingSetUpdateType;
100 	SetupSequence		setupSequence;
101 	DispatchSequence	dispatchSequence;
102 
103 protected:
hasSetupOpvkt::pipeline::__anon00102b750111::TestParams104 	bool hasSetupOp (SetupOp op) const
105 	{
106 		for (int i = 0; i < decltype(setupSequence)::SIZE; ++i)
107 		{
108 			if (setupSequence[i] == op)
109 				return true;
110 		}
111 		return false;
112 	}
113 
hasAnyOfvkt::pipeline::__anon00102b750111::TestParams114 	bool hasAnyOf (const std::vector<SetupOp>& opVec) const
115 	{
116 		for (const auto& op : opVec)
117 		{
118 			if (hasSetupOp(op))
119 				return true;
120 		}
121 		return false;
122 	}
123 
124 public:
hasGraphicsvkt::pipeline::__anon00102b750111::TestParams125 	bool hasGraphics (void) const
126 	{
127 		const std::vector<SetupOp> setupOps {SetupOp::BIND_GRAPHICS_PIPELINE, SetupOp::BIND_GRAPHICS_SET};
128 		return hasAnyOf(setupOps);
129 	}
130 
hasComputevkt::pipeline::__anon00102b750111::TestParams131 	bool hasCompute (void) const
132 	{
133 		const std::vector<SetupOp> setupOps {SetupOp::BIND_COMPUTE_PIPELINE, SetupOp::BIND_COMPUTE_SET};
134 		return hasAnyOf(setupOps);
135 	}
136 
hasRayTracingvkt::pipeline::__anon00102b750111::TestParams137 	bool hasRayTracing (void) const
138 	{
139 		const std::vector<SetupOp> setupOps {SetupOp::BIND_RAYTRACING_PIPELINE, SetupOp::BIND_RAYTRACING_SET};
140 		return hasAnyOf(setupOps);
141 	}
142 
143 };
144 
145 // Expected output values in each buffer.
146 constexpr deUint32 kExpectedBufferValueGraphics		= 1u;
147 constexpr deUint32 kExpectedBufferValueCompute		= 2u;
148 constexpr deUint32 kExpectedBufferValueRayTracing	= 3u;
149 
150 class BindPointTest : public vkt::TestCase
151 {
152 public:
153 							BindPointTest		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~BindPointTest(void)154 	virtual					~BindPointTest		(void) {}
155 
156 	virtual void			checkSupport		(Context& context) const;
157 	virtual void			initPrograms		(vk::SourceCollections& programCollection) const;
158 	virtual TestInstance*	createInstance		(Context& context) const;
159 
160 protected:
161 	TestParams				m_params;
162 };
163 
164 class BindPointInstance : public vkt::TestInstance
165 {
166 public:
167 								BindPointInstance	(Context& context, const TestParams& params);
~BindPointInstance(void)168 	virtual						~BindPointInstance	(void) {}
169 
170 	virtual tcu::TestStatus		iterate				(void);
171 
172 protected:
173 	TestParams					m_params;
174 };
175 
BindPointTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)176 BindPointTest::BindPointTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
177 	: vkt::TestCase	(testCtx, name, description)
178 	, m_params		(params)
179 {}
180 
checkSupport(Context & context) const181 void BindPointTest::checkSupport (Context& context) const
182 {
183 	if ((m_params.hasGraphics() && m_params.graphicsSetUpdateType != SetUpdateType::WRITE) ||
184 		(m_params.hasCompute() && m_params.computeSetUpdateType != SetUpdateType::WRITE) ||
185 		(m_params.hasRayTracing() && m_params.rayTracingSetUpdateType != SetUpdateType::WRITE))
186 	{
187 		context.requireDeviceFunctionality("VK_KHR_push_descriptor");
188 
189 		if ((m_params.hasGraphics() && m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) ||
190 			(m_params.hasCompute() && m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) ||
191 			(m_params.hasRayTracing() && m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE))
192 		{
193 			context.requireDeviceFunctionality("VK_KHR_descriptor_update_template");
194 		}
195 	}
196 
197 	if (m_params.hasRayTracing())
198 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
199 }
200 
initPrograms(vk::SourceCollections & programCollection) const201 void BindPointTest::initPrograms (vk::SourceCollections& programCollection) const
202 {
203 	// The flags array will only have 1 element.
204 	const std::string descriptorDecl = "layout(set=0, binding=0, std430) buffer BufferBlock { uint flag[]; } outBuffer;\n";
205 
206 	if (m_params.hasGraphics())
207 	{
208 		std::ostringstream vert;
209 		vert
210 			<< "#version 450\n"
211 			<< "\n"
212 			<< "void main()\n"
213 			<< "{\n"
214 			// Full-screen clockwise triangle strip with 4 vertices.
215 			<< "	const float x = (-1.0+2.0*((gl_VertexIndex & 2)>>1));\n"
216 			<< "	const float y = ( 1.0-2.0* (gl_VertexIndex % 2));\n"
217 			<< "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
218 			<< "}\n"
219 			;
220 
221 		// Note: the color attachment will be a 1x1 image, so gl_FragCoord.xy is (0.5, 0.5).
222 		std::ostringstream frag;
223 		frag
224 			<< "#version 450\n"
225 			<< descriptorDecl
226 			<< "layout(location=0) out vec4 outColor;\n"
227 			<< "\n"
228 			<< "void main()\n"
229 			<< "{\n"
230 			<< "  const uint xCoord = uint(trunc(gl_FragCoord.x));\n"
231 			<< "  const uint yCoord = uint(trunc(gl_FragCoord.y));\n"
232 			<< "  outBuffer.flag[xCoord + yCoord] = " << kExpectedBufferValueGraphics << "u;\n"
233 			<< "  outColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
234 			<< "}\n"
235 			;
236 
237 		programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
238 		programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
239 	}
240 
241 	if (m_params.hasCompute())
242 	{
243 		// Note: we will only dispatch 1 group.
244 		std::ostringstream comp;
245 		comp
246 			<< "#version 450\n"
247 			<< descriptorDecl
248 			<< "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
249 			<< "\n"
250 			<< "void main()\n"
251 			<< "{\n"
252 			<< "  const uint index = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y + gl_GlobalInvocationID.z;\n"
253 			<< "  outBuffer.flag[index] = " << kExpectedBufferValueCompute << "u;\n"
254 			<< "}\n"
255 			;
256 
257 		programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
258 	}
259 
260 	if (m_params.hasRayTracing())
261 	{
262 		// We will only call the ray gen shader once.
263 		std::ostringstream rgen;
264 		rgen
265 			<< "#version 460\n"
266 			<< "#extension GL_EXT_ray_tracing : require\n"
267 			<< descriptorDecl
268 			<< "\n"
269 			<< "void main()\n"
270 			<< "{\n"
271 			<< "  const uint index = gl_LaunchIDEXT.x + gl_LaunchIDEXT.y + gl_LaunchIDEXT.z;\n"
272 			<< "  outBuffer.flag[index] = " << kExpectedBufferValueRayTracing << "u;\n"
273 			<< "}\n"
274 			;
275 
276 		const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
277 		programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
278 	}
279 }
280 
createInstance(Context & context) const281 vkt::TestInstance* BindPointTest::createInstance (Context& context) const
282 {
283 	return new BindPointInstance(context, m_params);
284 }
285 
BindPointInstance(Context & context,const TestParams & params)286 BindPointInstance::BindPointInstance (Context& context, const TestParams& params)
287 	: vkt::TestInstance	(context)
288 	, m_params			(params)
289 {}
290 
makeSetLayout(const DeviceInterface & vkd,VkDevice device,VkShaderStageFlags stages,bool push)291 Move<VkDescriptorSetLayout> makeSetLayout(const DeviceInterface& vkd, VkDevice device, VkShaderStageFlags stages, bool push)
292 {
293 	VkDescriptorSetLayoutCreateFlags createFlags = 0u;
294 	if (push)
295 		createFlags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
296 
297 	DescriptorSetLayoutBuilder builder;
298 	builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
299 	return builder.build(vkd, device, createFlags);
300 }
301 
zeroOutAndFlush(const DeviceInterface & vkd,VkDevice device,BufferWithMemory & buffer,VkDeviceSize bufferSize)302 void zeroOutAndFlush (const DeviceInterface& vkd, VkDevice device, BufferWithMemory& buffer, VkDeviceSize bufferSize)
303 {
304 	auto& alloc		= buffer.getAllocation();
305 	void* hostPtr	= alloc.getHostPtr();
306 
307 	deMemset(hostPtr, 0, static_cast<size_t>(bufferSize));
308 	flushAlloc(vkd, device, alloc);
309 }
310 
makePoolAndSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorSetLayout layout,Move<VkDescriptorPool> & pool,Move<VkDescriptorSet> & set)311 void makePoolAndSet (const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout layout, Move<VkDescriptorPool>& pool, Move<VkDescriptorSet>& set)
312 {
313 	DescriptorPoolBuilder poolBuilder;
314 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
315 	pool	= poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
316 	set		= makeDescriptorSet(vkd, device, pool.get(), layout);
317 }
318 
writeSetUpdate(const DeviceInterface & vkd,VkDevice device,VkBuffer buffer,VkDeviceSize offset,VkDeviceSize size,VkDescriptorSet set)319 void writeSetUpdate (const DeviceInterface& vkd, VkDevice device, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkDescriptorSet set)
320 {
321 	DescriptorSetUpdateBuilder updateBuilder;
322 	const auto bufferInfo = makeDescriptorBufferInfo(buffer, offset, size);
323 	updateBuilder.writeSingle(set, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo);
324 	updateBuilder.update(vkd, device);
325 }
326 
makeUpdateTemplate(const DeviceInterface & vkd,VkDevice device,VkDescriptorSetLayout setLayout,VkPipelineBindPoint bindPoint,VkPipelineLayout pipelineLayout)327 Move<VkDescriptorUpdateTemplate> makeUpdateTemplate (const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout setLayout, VkPipelineBindPoint bindPoint, VkPipelineLayout pipelineLayout)
328 {
329 	const auto									templateEntry		= makeDescriptorUpdateTemplateEntry(0u, 0u, 1u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, static_cast<deUintptr>(0), static_cast<deUintptr>(sizeof(VkDescriptorBufferInfo)));
330 	const VkDescriptorUpdateTemplateCreateInfo	templateCreateInfo	=
331 	{
332 		VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,	//	VkStructureType							sType;
333 		nullptr,													//	const void*								pNext;
334 		0u,															//	VkDescriptorUpdateTemplateCreateFlags	flags;
335 		1u,															//	deUint32								descriptorUpdateEntryCount;
336 		&templateEntry,												//	const VkDescriptorUpdateTemplateEntry*	pDescriptorUpdateEntries;
337 		VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR,	//	VkDescriptorUpdateTemplateType			templateType;
338 		setLayout,													//	VkDescriptorSetLayout					descriptorSetLayout;
339 		bindPoint,													//	VkPipelineBindPoint						pipelineBindPoint;
340 		pipelineLayout,												//	VkPipelineLayout						pipelineLayout;
341 		0u,															//	deUint32								set;
342 	};
343 	return createDescriptorUpdateTemplate(vkd, device, &templateCreateInfo);
344 }
345 
pushBufferDescriptor(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,VkPipelineBindPoint bindPoint,VkPipelineLayout layout,VkBuffer buffer,VkDeviceSize offset,VkDeviceSize size)346 void pushBufferDescriptor(const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineBindPoint bindPoint, VkPipelineLayout layout, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)
347 {
348 	const auto					bufferInfo	= makeDescriptorBufferInfo(buffer, offset, size);
349 	const VkWriteDescriptorSet	write		=
350 	{
351 		VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,	//	VkStructureType					sType;
352 		nullptr,								//	const void*						pNext;
353 		DE_NULL,								//	VkDescriptorSet					dstSet;
354 		0u,										//	deUint32						dstBinding;
355 		0u,										//	deUint32						dstArrayElement;
356 		1u,										//	deUint32						descriptorCount;
357 		VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,		//	VkDescriptorType				descriptorType;
358 		nullptr,								//	const VkDescriptorImageInfo*	pImageInfo;
359 		&bufferInfo,							//	const VkDescriptorBufferInfo*	pBufferInfo;
360 		nullptr,								//	const VkBufferView*				pTexelBufferView;
361 	};
362 	vkd.cmdPushDescriptorSetKHR(cmdBuffer, bindPoint, layout, 0u, 1u, &write);
363 }
364 
verifyBufferContents(const DeviceInterface & vkd,VkDevice device,const BufferWithMemory & buffer,const std::string & bufferName,deUint32 expected)365 void verifyBufferContents (const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer, const std::string& bufferName, deUint32 expected)
366 {
367 	auto&				bufferAlloc	= buffer.getAllocation();
368 	const auto			dataPtr		= reinterpret_cast<deUint32*>(bufferAlloc.getHostPtr());
369 	deUint32			data;
370 
371 	invalidateAlloc(vkd, device, bufferAlloc);
372 	deMemcpy(&data, dataPtr, sizeof(data));
373 
374 	if (data != expected)
375 	{
376 		std::ostringstream msg;
377 		msg << "Invalid value found in " << bufferName << " buffer: expected " << expected << " and found " << data;
378 		TCU_FAIL(msg.str());
379 	}
380 }
381 
makeBufferBarrier(VkBuffer buffer,VkDeviceSize offset,VkDeviceSize size)382 VkBufferMemoryBarrier makeBufferBarrier (VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)
383 {
384 	return makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, buffer, offset, size);
385 }
386 
recordBufferBarrier(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,VkPipelineStageFlagBits stage,const VkBufferMemoryBarrier & barrier)387 void recordBufferBarrier (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineStageFlagBits stage, const VkBufferMemoryBarrier& barrier)
388 {
389 	vkd.cmdPipelineBarrier(cmdBuffer, stage, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &barrier, 0u, nullptr);
390 }
391 
iterate(void)392 tcu::TestStatus BindPointInstance::iterate (void)
393 {
394 	const auto&	vki			= m_context.getInstanceInterface();
395 	const auto	physDev		= m_context.getPhysicalDevice();
396 	const auto&	vkd			= m_context.getDeviceInterface();
397 	const auto	device		= m_context.getDevice();
398 	const auto	qIndex		= m_context.getUniversalQueueFamilyIndex();
399 	const auto	queue		= m_context.getUniversalQueue();
400 	auto&		alloc		= m_context.getDefaultAllocator();
401 
402 	const auto	imageFormat		= VK_FORMAT_R8G8B8A8_UNORM;
403 	const auto	imageExtent		= makeExtent3D(1u, 1u, 1u);
404 	const auto	imageType		= VK_IMAGE_TYPE_2D;
405 	const auto	imageViewType	= VK_IMAGE_VIEW_TYPE_2D;
406 	const auto	imageUsage		= static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
407 
408 	const auto	viewport		= makeViewport(imageExtent);
409 	const auto	scissor			= makeRect2D(imageExtent);
410 
411 	const auto	hasGraphics		= m_params.hasGraphics();
412 	const auto	hasCompute		= m_params.hasCompute();
413 	const auto	hasRayTracing	= m_params.hasRayTracing();
414 
415 	// Storage buffers.
416 	const auto bufferSize		= static_cast<VkDeviceSize>(sizeof(deUint32));
417 	const auto bufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
418 
419 	using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
420 	using ImageWithMemoryPtr = de::MovePtr<ImageWithMemory>;
421 
422 	BufferWithMemoryPtr graphicsBuffer;
423 	BufferWithMemoryPtr computeBuffer;
424 	BufferWithMemoryPtr rayTracingBuffer;
425 
426 	if (hasGraphics)	graphicsBuffer		= BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
427 	if (hasCompute)		computeBuffer		= BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
428 	if (hasRayTracing)	rayTracingBuffer	= BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
429 
430 	if (hasGraphics)	zeroOutAndFlush(vkd, device, *graphicsBuffer, bufferSize);
431 	if (hasCompute)		zeroOutAndFlush(vkd, device, *computeBuffer, bufferSize);
432 	if (hasRayTracing)	zeroOutAndFlush(vkd, device, *rayTracingBuffer, bufferSize);
433 
434 	ImageWithMemoryPtr	colorAttachment;
435 	Move<VkImageView>	colorAttachmentView;
436 
437 	if (hasGraphics)
438 	{
439 		// Color attachment.
440 		const VkImageCreateInfo imageCreateInfo =
441 		{
442 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
443 			nullptr,								//	const void*				pNext;
444 			0u,										//	VkImageCreateFlags		flags;
445 			imageType,								//	VkImageType				imageType;
446 			imageFormat,							//	VkFormat				format;
447 			imageExtent,							//	VkExtent3D				extent;
448 			1u,										//	deUint32				mipLevels;
449 			1u,										//	deUint32				arrayLayers;
450 			VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
451 			VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
452 			imageUsage,								//	VkImageUsageFlags		usage;
453 			VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
454 			1u,										//	deUint32				queueFamilyIndexCount;
455 			&qIndex,								//	const deUint32*			pQueueFamilyIndices;
456 			VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
457 		};
458 
459 		const auto subresourceRange		= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
460 		colorAttachment					= ImageWithMemoryPtr(new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
461 		colorAttachmentView				= makeImageView(vkd, device, colorAttachment->get(), imageViewType, imageFormat, subresourceRange);
462 	}
463 
464 	// Command buffer and pool.
465 	const auto cmdPool		= makeCommandPool(vkd, device, qIndex);
466 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
467 	const auto cmdBuffer	= cmdBufferPtr.get();
468 
469 	// Set and pipeline layouts.
470 	Move<VkDescriptorSetLayout> graphicsSetLayout;
471 	Move<VkDescriptorSetLayout> computeSetLayout;
472 	Move<VkDescriptorSetLayout> rayTracingSetLayout;
473 
474 	if (hasGraphics)	graphicsSetLayout	= makeSetLayout(vkd, device, VK_SHADER_STAGE_FRAGMENT_BIT, (m_params.graphicsSetUpdateType != SetUpdateType::WRITE));
475 	if (hasCompute)		computeSetLayout	= makeSetLayout(vkd, device, VK_SHADER_STAGE_COMPUTE_BIT, (m_params.computeSetUpdateType != SetUpdateType::WRITE));
476 	if (hasRayTracing)	rayTracingSetLayout	= makeSetLayout(vkd, device, VK_SHADER_STAGE_RAYGEN_BIT_KHR, (m_params.rayTracingSetUpdateType != SetUpdateType::WRITE));
477 
478 	Move<VkPipelineLayout> graphicsPipelineLayout;
479 	Move<VkPipelineLayout> computePipelineLayout;
480 	Move<VkPipelineLayout> rayTracingPipelineLayout;
481 
482 	if (hasGraphics)	graphicsPipelineLayout		= makePipelineLayout(vkd, device, graphicsSetLayout.get());
483 	if (hasCompute)		computePipelineLayout		= makePipelineLayout(vkd, device, computeSetLayout.get());
484 	if (hasRayTracing)	rayTracingPipelineLayout	= makePipelineLayout(vkd, device, rayTracingSetLayout.get());
485 
486 	// Shader modules.
487 	Move<VkShaderModule> vertShader;
488 	Move<VkShaderModule> fragShader;
489 	Move<VkShaderModule> compShader;
490 	Move<VkShaderModule> rgenShader;
491 
492 	if (hasGraphics)	vertShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
493 	if (hasGraphics)	fragShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
494 	if (hasCompute)		compShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
495 	if (hasRayTracing)	rgenShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0u);
496 
497 	Move<VkRenderPass>	renderPass;
498 	Move<VkFramebuffer>	framebuffer;
499 	Move<VkPipeline>	graphicsPipeline;
500 
501 	if (hasGraphics)
502 	{
503 		// Render pass and framebuffer.
504 		renderPass	= makeRenderPass(vkd, device, imageFormat);
505 		framebuffer	= makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), imageExtent.width, imageExtent.height);
506 
507 		// Graphics pipeline.
508 		std::vector<VkViewport>	viewports(1u, viewport);
509 		std::vector<VkRect2D>	scissors(1u, scissor);
510 
511 		const VkPipelineVertexInputStateCreateInfo vertexInputState =
512 		{
513 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType                             sType
514 			nullptr,													// const void*                                 pNext
515 			0u,															// VkPipelineVertexInputStateCreateFlags       flags
516 			0u,															// deUint32                                    vertexBindingDescriptionCount
517 			nullptr,													// const VkVertexInputBindingDescription*      pVertexBindingDescriptions
518 			0u,															// deUint32                                    vertexAttributeDescriptionCount
519 			nullptr,													// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
520 		};
521 
522 		graphicsPipeline = makeGraphicsPipeline(vkd, device, graphicsPipelineLayout.get(),
523 			vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(),	// Shaders.
524 			renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u, &vertexInputState);
525 	}
526 
527 	// Compute pipeline.
528 	Move<VkPipeline> computePipeline;
529 
530 	if (hasCompute)
531 	{
532 		const VkPipelineShaderStageCreateInfo computeShaderStageInfo =
533 		{
534 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
535 			nullptr,												//	const void*							pNext;
536 			0u,														//	VkPipelineShaderStageCreateFlags	flags;
537 			VK_SHADER_STAGE_COMPUTE_BIT,							//	VkShaderStageFlagBits				stage;
538 			compShader.get(),										//	VkShaderModule						module;
539 			"main",													//	const char*							pName;
540 			nullptr,												//	const VkSpecializationInfo*			pSpecializationInfo;
541 		};
542 
543 		const VkComputePipelineCreateInfo computePipelineCreateInfo =
544 		{
545 			VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	//	VkStructureType					sType;
546 			nullptr,										//	const void*						pNext;
547 			0u,												//	VkPipelineCreateFlags			flags;
548 			computeShaderStageInfo,							//	VkPipelineShaderStageCreateInfo	stage;
549 			computePipelineLayout.get(),					//	VkPipelineLayout				layout;
550 			DE_NULL,										//	VkPipeline						basePipelineHandle;
551 			0u,												//	deInt32							basePipelineIndex;
552 		};
553 
554 		computePipeline = createComputePipeline(vkd, device, DE_NULL, &computePipelineCreateInfo);
555 	}
556 
557 	// Ray tracing pipeline and shader binding tables.
558 	using RayTracingPipelineHelperPtr = de::MovePtr<RayTracingPipeline>;
559 
560 	RayTracingPipelineHelperPtr		rayTracingPipelineHelper;
561 	Move<VkPipeline>				rayTracingPipeline;
562 	BufferWithMemoryPtr				raygenSBT;
563 
564 	VkStridedDeviceAddressRegionKHR	raygenSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
565 	VkStridedDeviceAddressRegionKHR	missSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
566 	VkStridedDeviceAddressRegionKHR	hitSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
567 	VkStridedDeviceAddressRegionKHR	callableSBTRegion	= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
568 
569 	if (hasRayTracing)
570 	{
571 		const auto rtProperties				= makeRayTracingProperties(vki, physDev);
572 		const auto shaderGroupHandleSize	= rtProperties->getShaderGroupHandleSize();
573 		const auto shaderGroupBaseAlignment	= rtProperties->getShaderGroupBaseAlignment();
574 		rayTracingPipelineHelper			= RayTracingPipelineHelperPtr(new RayTracingPipeline());
575 
576 		rayTracingPipelineHelper->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenShader, 0);
577 		rayTracingPipeline = rayTracingPipelineHelper->createPipeline(vkd, device, rayTracingPipelineLayout.get());
578 
579 		raygenSBT		= rayTracingPipelineHelper->createShaderBindingTable(vkd, device, rayTracingPipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
580 		raygenSBTRegion	= makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
581 	}
582 
583 	// Descriptor pools and sets if needed.
584 	Move<VkDescriptorPool>	graphicsDescriptorPool;
585 	Move<VkDescriptorPool>	computeDescriptorPool;
586 	Move<VkDescriptorPool>	rayTracingDescriptorPool;
587 	Move<VkDescriptorSet>	graphicsDescritorSet;
588 	Move<VkDescriptorSet>	computeDescriptorSet;
589 	Move<VkDescriptorSet>	rayTracingDescriptorSet;
590 
591 	if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE)
592 	{
593 		makePoolAndSet(vkd, device, graphicsSetLayout.get(), graphicsDescriptorPool, graphicsDescritorSet);
594 		writeSetUpdate(vkd, device, graphicsBuffer->get(), 0ull, bufferSize, graphicsDescritorSet.get());
595 	}
596 
597 	if (m_params.computeSetUpdateType == SetUpdateType::WRITE)
598 	{
599 		makePoolAndSet(vkd, device, computeSetLayout.get(), computeDescriptorPool, computeDescriptorSet);
600 		writeSetUpdate(vkd, device, computeBuffer->get(), 0ull, bufferSize, computeDescriptorSet.get());
601 	}
602 
603 	if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE)
604 	{
605 		makePoolAndSet(vkd, device, rayTracingSetLayout.get(), rayTracingDescriptorPool, rayTracingDescriptorSet);
606 		writeSetUpdate(vkd, device, rayTracingBuffer->get(), 0ull, bufferSize, rayTracingDescriptorSet.get());
607 	}
608 
609 	// Templates if needed.
610 	Move<VkDescriptorUpdateTemplate> graphicsUpdateTemplate;
611 	Move<VkDescriptorUpdateTemplate> computeUpdateTemplate;
612 	Move<VkDescriptorUpdateTemplate> rayTracingUpdateTemplate;
613 
614 	if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
615 		graphicsUpdateTemplate = makeUpdateTemplate(vkd, device, graphicsSetLayout.get(), VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get());
616 
617 	if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
618 		computeUpdateTemplate = makeUpdateTemplate(vkd, device, computeSetLayout.get(), VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get());
619 
620 	if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
621 		rayTracingUpdateTemplate = makeUpdateTemplate(vkd, device, rayTracingSetLayout.get(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get());
622 
623 	beginCommandBuffer(vkd, cmdBuffer);
624 
625 	// Helper flags to check the test has been specified properly.
626 	bool boundGraphicsPipeline		= false;
627 	bool boundGraphicsSet			= false;
628 	bool boundComputePipeline		= false;
629 	bool boundComputeSet			= false;
630 	bool boundRayTracingPipeline	= false;
631 	bool boundRayTracingSet			= false;
632 
633 	// Setup operations in desired order.
634 	for (int i = 0; i < decltype(m_params.setupSequence)::SIZE; ++i)
635 	{
636 		const auto& setupOp = m_params.setupSequence[i];
637 		switch (setupOp)
638 		{
639 		case SetupOp::BIND_GRAPHICS_PIPELINE:
640 			vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
641 			boundGraphicsPipeline = true;
642 			break;
643 
644 		case SetupOp::BIND_COMPUTE_PIPELINE:
645 			vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get());
646 			boundComputePipeline = true;
647 			break;
648 
649 		case SetupOp::BIND_RAYTRACING_PIPELINE:
650 			vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipeline.get());
651 			boundRayTracingPipeline = true;
652 			break;
653 
654 		case SetupOp::BIND_GRAPHICS_SET:
655 			if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE)
656 				vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(), 0u, 1u, &graphicsDescritorSet.get(), 0u, nullptr);
657 			else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH)
658 				pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(), graphicsBuffer->get(), 0ull, bufferSize);
659 			else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
660 			{
661 				const auto bufferInfo = makeDescriptorBufferInfo(graphicsBuffer->get(), 0ull, bufferSize);
662 				vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, graphicsUpdateTemplate.get(), graphicsPipelineLayout.get(), 0u, &bufferInfo);
663 			}
664 			else
665 				DE_ASSERT(false);
666 			boundGraphicsSet = true;
667 			break;
668 
669 		case SetupOp::BIND_COMPUTE_SET:
670 			if (m_params.computeSetUpdateType == SetUpdateType::WRITE)
671 				vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(), 0u, 1u, &computeDescriptorSet.get(), 0u, nullptr);
672 			else if (m_params.computeSetUpdateType == SetUpdateType::PUSH)
673 				pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(), computeBuffer->get(), 0ull, bufferSize);
674 			else if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
675 			{
676 				const auto bufferInfo = makeDescriptorBufferInfo(computeBuffer->get(), 0ull, bufferSize);
677 				vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, computeUpdateTemplate.get(), computePipelineLayout.get(), 0u, &bufferInfo);
678 			}
679 			else
680 				DE_ASSERT(false);
681 			boundComputeSet = true;
682 			break;
683 
684 		case SetupOp::BIND_RAYTRACING_SET:
685 			if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE)
686 				vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get(), 0u, 1u, &rayTracingDescriptorSet.get(), 0u, nullptr);
687 			else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH)
688 				pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get(), rayTracingBuffer->get(), 0ull, bufferSize);
689 			else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
690 			{
691 				const auto bufferInfo = makeDescriptorBufferInfo(rayTracingBuffer->get(), 0ull, bufferSize);
692 				vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, rayTracingUpdateTemplate.get(), rayTracingPipelineLayout.get(), 0u, &bufferInfo);
693 			}
694 			else
695 				DE_ASSERT(false);
696 			boundRayTracingSet = true;
697 			break;
698 
699 		default:
700 			DE_ASSERT(false);
701 			break;
702 		}
703 	}
704 
705 	// Avoid warning in release builds.
706 	DE_UNREF(boundGraphicsPipeline);
707 	DE_UNREF(boundGraphicsSet);
708 	DE_UNREF(boundComputePipeline);
709 	DE_UNREF(boundComputeSet);
710 	DE_UNREF(boundRayTracingPipeline);
711 	DE_UNREF(boundRayTracingSet);
712 
713 	// Dispatch operations in desired order.
714 	for (int i = 0; i < decltype(m_params.dispatchSequence)::SIZE; ++i)
715 	{
716 		const auto& dispatchOp = m_params.dispatchSequence[i];
717 		switch (dispatchOp)
718 		{
719 		case DispatchOp::DRAW:
720 			DE_ASSERT(boundGraphicsPipeline && boundGraphicsSet);
721 			beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
722 			vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u);
723 			endRenderPass(vkd, cmdBuffer);
724 			break;
725 
726 		case DispatchOp::COMPUTE:
727 			DE_ASSERT(boundComputePipeline && boundComputeSet);
728 			vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
729 			break;
730 
731 		case DispatchOp::TRACE_RAYS:
732 			DE_ASSERT(boundRayTracingPipeline && boundRayTracingSet);
733 			cmdTraceRays(vkd, cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u, 1u);
734 			break;
735 
736 		default:
737 			DE_ASSERT(false);
738 			break;
739 		}
740 	}
741 
742 	if (hasGraphics)
743 	{
744 		const auto graphicsBufferBarrier = makeBufferBarrier(graphicsBuffer->get(), 0ull, bufferSize);
745 		recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, graphicsBufferBarrier);
746 	}
747 	if (hasCompute)
748 	{
749 		const auto computeBufferBarrier = makeBufferBarrier(computeBuffer->get(), 0ull, bufferSize);
750 		recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, computeBufferBarrier);
751 	}
752 	if (hasRayTracing)
753 	{
754 		const auto rayTracingBufferBarrier = makeBufferBarrier(rayTracingBuffer->get(), 0ull, bufferSize);
755 		recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, rayTracingBufferBarrier);
756 	}
757 
758 	endCommandBuffer(vkd, cmdBuffer);
759 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
760 
761 	// Verify storage buffers.
762 	if (hasGraphics)	verifyBufferContents(vkd, device, *graphicsBuffer, "graphics", kExpectedBufferValueGraphics);
763 	if (hasCompute)		verifyBufferContents(vkd, device, *computeBuffer, "compute", kExpectedBufferValueCompute);
764 	if (hasRayTracing)	verifyBufferContents(vkd, device, *rayTracingBuffer, "raytracing", kExpectedBufferValueRayTracing);
765 
766 	// Verify color attachment.
767 	if (hasGraphics)
768 	{
769 		const auto		textureLevel	= readColorAttachment(vkd, device, queue, qIndex, alloc, colorAttachment->get(), imageFormat, tcu::UVec2(imageExtent.width, imageExtent.height));
770 		const auto		pixelBuffer		= textureLevel->getAccess();
771 		const auto		iWidth			= static_cast<int>(imageExtent.width);
772 		const auto		iHeight			= static_cast<int>(imageExtent.height);
773 		const tcu::Vec4	expectedColor	(0.0f, 1.0f, 0.0f, 1.0f);
774 
775 		for (int y = 0; y < iHeight; ++y)
776 		for (int x = 0; x < iWidth; ++x)
777 		{
778 			const auto value = pixelBuffer.getPixel(x, y);
779 			if (value != expectedColor)
780 			{
781 				std::ostringstream msg;
782 				msg << "Unexpected color found in attachment: expected " << expectedColor << " but found " << value;
783 				TCU_FAIL(msg.str());
784 			}
785 		}
786 	}
787 
788 	return tcu::TestStatus::pass("Pass");
789 }
790 
791 // Auxiliar string conversion functions.
792 
toString(SetUpdateType updateType)793 std::string toString(SetUpdateType updateType)
794 {
795 	switch (updateType)
796 	{
797 	case SetUpdateType::WRITE:				return "write";
798 	case SetUpdateType::PUSH:				return "push";
799 	case SetUpdateType::PUSH_WITH_TEMPLATE:	return "template_push";
800 	default:								DE_ASSERT(false); break;
801 	}
802 
803 	return "";
804 }
805 
toString(const SetupSequence & setupSequence)806 std::string toString(const SetupSequence& setupSequence)
807 {
808 	std::ostringstream out;
809 
810 	out << "setup";
811 	for (int i = 0; i < std::remove_reference<decltype(setupSequence)>::type::SIZE; ++i)
812 	{
813 		out << "_";
814 		switch (setupSequence[i])
815 		{
816 		case SetupOp::BIND_GRAPHICS_PIPELINE:	out << "gp";		break;
817 		case SetupOp::BIND_COMPUTE_PIPELINE:	out << "cp";		break;
818 		case SetupOp::BIND_RAYTRACING_PIPELINE:	out << "rp";		break;
819 		case SetupOp::BIND_GRAPHICS_SET:		out << "gs";		break;
820 		case SetupOp::BIND_COMPUTE_SET:			out << "cs";		break;
821 		case SetupOp::BIND_RAYTRACING_SET:		out << "rs";		break;
822 		default:								DE_ASSERT(false);	break;
823 		}
824 	}
825 
826 	return out.str();
827 }
828 
toString(const DispatchSequence & dispatchSequence)829 std::string toString(const DispatchSequence& dispatchSequence)
830 {
831 	std::ostringstream out;
832 
833 	out << "cmd";
834 	for (int i = 0; i < std::remove_reference<decltype(dispatchSequence)>::type::SIZE; ++i)
835 	{
836 		out << "_";
837 		switch (dispatchSequence[i])
838 		{
839 		case DispatchOp::COMPUTE:		out << "dispatch";	break;
840 		case DispatchOp::DRAW:			out << "draw";		break;
841 		case DispatchOp::TRACE_RAYS:	out << "tracerays";	break;
842 		default:						DE_ASSERT(false);	break;
843 		}
844 	}
845 
846 	return out.str();
847 }
848 
toString(VkPipelineBindPoint point)849 std::string toString(VkPipelineBindPoint point)
850 {
851 	if (point == VK_PIPELINE_BIND_POINT_GRAPHICS)			return "graphics";
852 	if (point == VK_PIPELINE_BIND_POINT_COMPUTE)			return "compute";
853 	if (point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)	return "raytracing";
854 
855 	DE_ASSERT(false);
856 	return "";
857 }
858 
859 } // anonymous
860 
createBindPointTests(tcu::TestContext & testCtx)861 tcu::TestCaseGroup* createBindPointTests (tcu::TestContext& testCtx)
862 {
863 	using GroupPtr		= de::MovePtr<tcu::TestCaseGroup>;
864 	using BindPointPair	= tcu::Vector<VkPipelineBindPoint, kTestBindPoints>;
865 
866 	GroupPtr bindPointGroup(new tcu::TestCaseGroup(testCtx, "bind_point", "Tests checking bind points are independent and used properly"));
867 
868 	// Bind point combinations to test.
869 	const BindPointPair testPairs[] =
870 	{
871 		BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS,	VK_PIPELINE_BIND_POINT_COMPUTE),
872 		BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS,	VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR),
873 		BindPointPair(VK_PIPELINE_BIND_POINT_COMPUTE,	VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR),
874 	};
875 
876 	for (int testPairIdx = 0; testPairIdx < DE_LENGTH_OF_ARRAY(testPairs); ++testPairIdx)
877 	{
878 		const auto& testPair = testPairs[testPairIdx];
879 
880 		// Default values. Two of them will be overwritten later.
881 		TestParams params;
882 		params.graphicsSetUpdateType	= SetUpdateType::TYPE_COUNT;
883 		params.computeSetUpdateType		= SetUpdateType::TYPE_COUNT;
884 		params.rayTracingSetUpdateType	= SetUpdateType::TYPE_COUNT;
885 
886 		// What to test based on the test pair.
887 		// Note: updateTypePtrs will tell us which of the set update type members above we need to vary (graphics, compute, ray tracing).
888 		SetUpdateType*	updateTypePtrs	[kTestBindPoints] = {	nullptr,				nullptr					};
889 		SetupOp			pipelineBinds	[kTestBindPoints] = {	SetupOp::OP_COUNT,		SetupOp::OP_COUNT		};
890 		SetupOp			setBinds		[kTestBindPoints] = {	SetupOp::OP_COUNT,		SetupOp::OP_COUNT		};
891 		DispatchOp		dispatches		[kTestBindPoints] = {	DispatchOp::OP_COUNT,	DispatchOp::OP_COUNT	};
892 
893 		for (int elemIdx = 0; elemIdx < std::remove_reference<decltype(testPair)>::type::SIZE; ++elemIdx)
894 		{
895 			if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_GRAPHICS)
896 			{
897 				updateTypePtrs[elemIdx]	= &params.graphicsSetUpdateType;	// Test different graphics set update types.
898 				pipelineBinds[elemIdx]	= SetupOp::BIND_GRAPHICS_PIPELINE;
899 				setBinds[elemIdx]		= SetupOp::BIND_GRAPHICS_SET;
900 				dispatches[elemIdx]		= DispatchOp::DRAW;
901 			}
902 			else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_COMPUTE)
903 			{
904 				updateTypePtrs[elemIdx]	= &params.computeSetUpdateType;		// Test different compute set update types.
905 				pipelineBinds[elemIdx]	= SetupOp::BIND_COMPUTE_PIPELINE;
906 				setBinds[elemIdx]		= SetupOp::BIND_COMPUTE_SET;
907 				dispatches[elemIdx]		= DispatchOp::COMPUTE;
908 			}
909 			else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)
910 			{
911 				updateTypePtrs[elemIdx]	= &params.rayTracingSetUpdateType;	// Test different ray tracing set update types.
912 				pipelineBinds[elemIdx]	= SetupOp::BIND_RAYTRACING_PIPELINE;
913 				setBinds[elemIdx]		= SetupOp::BIND_RAYTRACING_SET;
914 				dispatches[elemIdx]		= DispatchOp::TRACE_RAYS;
915 			}
916 		}
917 
918 		const std::string	pairName	= toString(testPair[0]) + "_" + toString(testPair[1]);
919 		GroupPtr			pairGroup	(new tcu::TestCaseGroup(testCtx, pairName.c_str(), ""));
920 
921 		// Combine two update types.
922 		for (int firstUpdateTypeIdx = 0; firstUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT); ++firstUpdateTypeIdx)
923 		for (int secondUpdateTypeIdx = 0; secondUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT); ++ secondUpdateTypeIdx)
924 		{
925 			const auto			firstUpdateType		= static_cast<SetUpdateType>(firstUpdateTypeIdx);
926 			const auto			secondUpdateType	= static_cast<SetUpdateType>(secondUpdateTypeIdx);
927 			const std::string	updateGroupName		= toString(firstUpdateType) + "_" + toString(secondUpdateType);
928 			GroupPtr			updateGroup			(new tcu::TestCaseGroup(testCtx, updateGroupName.c_str(), ""));
929 
930 			// Change update types of the relevant sets.
931 			*updateTypePtrs[0] = firstUpdateType;
932 			*updateTypePtrs[1] = secondUpdateType;
933 
934 			// Prepare initial permutation of test parameters.
935 			params.setupSequence[0] = pipelineBinds[0];
936 			params.setupSequence[1] = pipelineBinds[1];
937 			params.setupSequence[2] = setBinds[0];
938 			params.setupSequence[3] = setBinds[1];
939 
940 			// Permutate setup sequence and dispatch sequence.
941 			const auto ssBegin	= params.setupSequence.m_data;
942 			const auto ssEnd	= ssBegin + decltype(params.setupSequence)::SIZE;
943 			do
944 			{
945 				const auto	setupGroupName	= toString(params.setupSequence);
946 				GroupPtr	setupGroup		(new tcu::TestCaseGroup(testCtx, setupGroupName.c_str(), ""));
947 
948 				// Reset dispatch sequence permutation.
949 				params.dispatchSequence = dispatches;
950 
951 				const auto dsBegin	= params.dispatchSequence.m_data;
952 				const auto dsEnd	= dsBegin + decltype(params.dispatchSequence)::SIZE;
953 				do
954 				{
955 					const auto testName = toString(params.dispatchSequence);
956 					setupGroup->addChild(new BindPointTest(testCtx, testName, "", params));
957 				} while (std::next_permutation(dsBegin, dsEnd));
958 
959 				updateGroup->addChild(setupGroup.release());
960 
961 			} while (std::next_permutation(ssBegin, ssEnd));
962 
963 			pairGroup->addChild(updateGroup.release());
964 		}
965 
966 		bindPointGroup->addChild(pairGroup.release());
967 	}
968 
969 
970 	return bindPointGroup.release();
971 }
972 
973 } // pipeline
974 } // vkt
975 
976