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