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