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