• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file  vktGlobalPriorityQueueTests.cpp
21  * \brief Global Priority Queue Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktGlobalPriorityQueueTests.hpp"
25 #include "vktGlobalPriorityQueueUtils.hpp"
26 
27 #include "vkBarrierUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "../image/vktImageTestsUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "vkStrUtil.hpp"
36 #include "vkRefUtil.hpp"
37 
38 #include "vktTestGroupUtil.hpp"
39 #include "vktTestCase.hpp"
40 
41 #include "deDefs.h"
42 #include "deMath.h"
43 #include "deRandom.h"
44 #include "deRandom.hpp"
45 #include "deSharedPtr.hpp"
46 #include "deString.h"
47 #include "deMemory.h"
48 
49 #include "tcuStringTemplate.hpp"
50 
51 #include <string>
52 #include <sstream>
53 #include <map>
54 #include <iostream>
55 
56 using namespace vk;
57 
58 namespace vkt
59 {
60 namespace synchronization
61 {
62 namespace
63 {
64 
65 enum class SyncType
66 {
67 	None,
68 	Semaphore
69 };
70 
71 struct TestConfig
72 {
73 	VkQueueFlagBits				transitionFrom;
74 	VkQueueFlagBits				transitionTo;
75 	VkQueueGlobalPriorityKHR	priorityFrom;
76 	VkQueueGlobalPriorityKHR	priorityTo;
77 	bool						enableProtected;
78 	bool						enableSparseBinding;
79 	SyncType					syncType;
80 	deUint32					width;
81 	deUint32					height;
82 	VkFormat					format;
83 	bool selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats);
84 };
85 
selectFormat(const InstanceInterface & vk,VkPhysicalDevice dev,std::initializer_list<VkFormat> formats)86 bool TestConfig::selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats)
87 {
88 	auto doesFormatMatch = [](const VkFormat fmt) -> bool
89 	{
90 		const auto tcuFmt = mapVkFormat(fmt);
91 		return tcuFmt.order == tcu::TextureFormat::ChannelOrder::R;
92 	};
93 	VkFormatProperties2 props{};
94 	const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
95 										| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
96 	for (auto i = formats.begin(); i != formats.end(); ++i)
97 	{
98 		props.sType				= VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
99 		props.pNext				= nullptr;
100 		props.formatProperties	= {};
101 		const VkFormat		fmt = *i;
102 		vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props);
103 		if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags))
104 		{
105 			this->format = fmt;
106 			return true;
107 		}
108 	}
109 	return false;
110 }
111 
112 template<class T, class P = T(*)[1]>
begin(void * p)113 auto begin (void* p) -> decltype(std::begin(*std::declval<P>()))
114 {
115 	return std::begin(*static_cast<P>(p));
116 }
117 
118 class GPQInstanceBase : public TestInstance
119 {
120 public:
121 	typedef std::initializer_list<VkDescriptorSetLayout> DSLayouts;
122 	typedef tcu::ConstPixelBufferAccess	BufferAccess;
123 
124 					GPQInstanceBase			(Context&					ctx,
125 											 const TestConfig&			cfg);
126 	template<class PushConstant = void>
127 	auto			createPipelineLayout	(DSLayouts					setLayouts)		const -> Move<VkPipelineLayout>;
128 	auto			makeCommandPool			(deUint32					qFamilyIndex)	const -> Move<VkCommandPool>;
129 	auto			createGraphicsPipeline	(VkPipelineLayout			pipelineLayout,
130 											 VkRenderPass				renderPass)			  -> Move<VkPipeline>;
131 	auto			createComputePipeline	(VkPipelineLayout			pipelineLayout,
132 											 bool						producer)			  -> Move<VkPipeline>;
133 	auto			createImage				(VkImageUsageFlags			usage,
134 											 deUint32					queueFamilyIdx,
135 											 VkQueue					queue)			const -> de::MovePtr<ImageWithMemory>;
136 	auto			createView				(VkImage					image,
137 											 VkImageSubresourceRange&	range)			const -> Move<VkImageView>;
138 	void			submitCommands			(VkCommandBuffer			producerCmd,
139 											 VkCommandBuffer			consumerCmd)	const;
140 protected:
141 	auto createPipelineLayout			(const VkPushConstantRange*		pRange,
142 										 DSLayouts						setLayouts)		const -> Move<VkPipelineLayout>;
143 	const TestConfig			m_config;
144 	const SpecialDevice			m_device;
145 	struct NamedShader {
146 		std::string				name;
147 		Move<VkShaderModule>	handle;
148 	}							m_shaders[4];
149 };
GPQInstanceBase(Context & ctx,const TestConfig & cfg)150 GPQInstanceBase::GPQInstanceBase (Context& ctx, const TestConfig& cfg)
151 	: TestInstance	(ctx)
152 	, m_config		(cfg)
153 	, m_device		(ctx,
154 					 cfg.transitionFrom,	cfg.transitionTo,
155 					 cfg.priorityFrom,		cfg.priorityTo,
156 					 cfg.enableProtected,	cfg.enableSparseBinding)
157 	, m_shaders		()
158 {
159 	m_shaders[0].name = "vert";	// vertex
160 	m_shaders[1].name = "frag";	// fragment
161 	m_shaders[2].name = "cpyb";	// compute
162 	m_shaders[3].name = "cpyi";	// compute
163 }
164 
createImage(VkImageUsageFlags usage,deUint32 queueFamilyIdx,VkQueue queue) const165 de::MovePtr<ImageWithMemory> GPQInstanceBase::createImage (VkImageUsageFlags usage, deUint32 queueFamilyIdx, VkQueue queue) const
166 {
167 	const InstanceInterface&	vki		= m_context.getInstanceInterface();
168 	const DeviceInterface&		vkd		= m_context.getDeviceInterface();
169 	const VkPhysicalDevice		phys	= m_context.getPhysicalDevice();
170 	const VkDevice				dev		= m_device.handle;
171 	Allocator&					alloc	= m_device.getAllocator();
172 	VkImageCreateFlags			flags	= 0;
173 
174 	if (m_config.enableProtected)		flags	|= VK_IMAGE_CREATE_PROTECTED_BIT;
175 	if (m_config.enableSparseBinding)	flags	|= (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT);
176 	const MemoryRequirement				memReqs	= m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any;
177 
178 	VkImageCreateInfo imageInfo{};
179 	imageInfo.sType					= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
180 	imageInfo.pNext					= nullptr;
181 	imageInfo.flags					= flags;
182 	imageInfo.imageType				= VK_IMAGE_TYPE_2D;
183 	imageInfo.format				= m_config.format;
184 	imageInfo.extent.width			= m_config.width;
185 	imageInfo.extent.height			= m_config.height;
186 	imageInfo.extent.depth			= 1;
187 	imageInfo.mipLevels				= 1;
188 	imageInfo.arrayLayers			= 1;
189 	imageInfo.samples				= VK_SAMPLE_COUNT_1_BIT;
190 	imageInfo.tiling				= VK_IMAGE_TILING_OPTIMAL;
191 	imageInfo.usage					= usage;
192 	imageInfo.sharingMode			= VK_SHARING_MODE_EXCLUSIVE;
193 	imageInfo.queueFamilyIndexCount	= 1;
194 	imageInfo.pQueueFamilyIndices	= &queueFamilyIdx;
195 	imageInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;
196 
197 	return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vki, vkd, phys, dev, alloc, imageInfo, queue, memReqs));
198 }
199 
createView(VkImage image,VkImageSubresourceRange & range) const200 Move<VkImageView> GPQInstanceBase::createView (VkImage image, VkImageSubresourceRange& range) const
201 {
202 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
203 	const VkDevice			dev		= m_device.handle;
204 
205 	range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
206 	return makeImageView(vkd, dev, image, VK_IMAGE_VIEW_TYPE_2D, m_config.format, range);
207 }
208 
createPipelineLayout(const VkPushConstantRange * pRange,DSLayouts setLayouts) const209 Move<VkPipelineLayout>	GPQInstanceBase::createPipelineLayout (const VkPushConstantRange* pRange, DSLayouts setLayouts) const
210 {
211 	std::vector<VkDescriptorSetLayout>	layouts(setLayouts.size());
212 	auto ii = setLayouts.begin();
213 	for (auto i = ii; i != setLayouts.end(); ++i)
214 		layouts[std::distance(ii, i)] = *i;
215 
216 	VkPipelineLayoutCreateInfo		info{};
217 	info.sType					= VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
218 	info.pNext					= nullptr;
219 	info.flags					= VkPipelineLayoutCreateFlags(0);
220 	info.setLayoutCount			= static_cast<uint32_t>(layouts.size());
221 	info.pSetLayouts			= layouts.size() ? layouts.data() : nullptr;
222 	info.pushConstantRangeCount	= (pRange != nullptr && pRange->size > 0) ? 1 : 0;
223 	info.pPushConstantRanges	= (pRange != nullptr && pRange->size > 0) ? pRange : nullptr;
224 
225 	return ::vk::createPipelineLayout(m_context.getDeviceInterface(), m_device.handle, &info);
226 }
227 
createPipelineLayout(DSLayouts setLayouts) const228 template<> Move<VkPipelineLayout> DE_UNUSED_FUNCTION GPQInstanceBase::createPipelineLayout<void> (DSLayouts setLayouts) const
229 {
230 	return createPipelineLayout(nullptr, setLayouts);
231 }
232 
createPipelineLayout(DSLayouts setLayouts) const233 template<class PushConstant> Move<VkPipelineLayout>	GPQInstanceBase::createPipelineLayout (DSLayouts setLayouts) const
234 {
235 	VkPushConstantRange	range{};
236 	range.stageFlags	= VK_SHADER_STAGE_ALL;
237 	range.offset		= 0;
238 	range.size			= static_cast<uint32_t>(sizeof(PushConstant));
239 	return createPipelineLayout(&range, setLayouts);
240 }
241 
makeCommandPool(deUint32 qFamilyIndex) const242 Move<VkCommandPool> GPQInstanceBase::makeCommandPool (deUint32 qFamilyIndex) const
243 {
244 	const VkCommandPoolCreateFlags flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
245 			| (m_config.enableProtected ? VK_COMMAND_POOL_CREATE_PROTECTED_BIT : 0);
246 	const VkCommandPoolCreateInfo commandPoolParams =
247 	{
248 		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,		// VkStructureType			sType;
249 		DE_NULL,										// const void*				pNext;
250 		flags,											// VkCommandPoolCreateFlags	flags;
251 		qFamilyIndex,									// deUint32					queueFamilyIndex;
252 	};
253 
254 	return createCommandPool(m_context.getDeviceInterface(), m_device.handle, &commandPoolParams);
255 }
256 
createGraphicsPipeline(VkPipelineLayout pipelineLayout,VkRenderPass renderPass)257 Move<VkPipeline> GPQInstanceBase::createGraphicsPipeline (VkPipelineLayout pipelineLayout, VkRenderPass renderPass)
258 {
259 	const DeviceInterface&	vkd	= m_context.getDeviceInterface();
260 	const VkDevice			dev	= m_device.handle;
261 
262 	auto sh = std::find_if(std::begin(m_shaders), std::end(m_shaders), [](const NamedShader& ns){ return ns.name == "vert"; });
263 	if (*sh->handle == DE_NULL) sh->handle = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("vert"));
264 	VkShaderModule vertex = *sh->handle;
265 
266 	sh = std::find_if(std::begin(m_shaders), std::end(m_shaders), [](const NamedShader& ns){ return ns.name == "frag"; });
267 	if (*sh->handle == DE_NULL) sh->handle = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("frag"));
268 	VkShaderModule fragment = *sh->handle;
269 
270 	const std::vector<VkViewport>	viewports		{ makeViewport(m_config.width, m_config.height) };
271 	const std::vector<VkRect2D>		scissors		{ makeRect2D(m_config.width, m_config.height) };
272 	const auto						vertexBinding	= makeVertexInputBindingDescription(0u, static_cast<deUint32>(2 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX);
273 	const auto						vertexAttrib	= makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0u);
274 	const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
275 	{
276 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
277 		nullptr,														//	const void*									pNext;
278 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
279 		1u,																//	deUint32									vertexBindingDescriptionCount;
280 		&vertexBinding,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
281 		1u,																//	deUint32									vertexAttributeDescriptionCount;
282 		&vertexAttrib													//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
283 	};
284 
285 	return makeGraphicsPipeline(vkd, dev, pipelineLayout,vertex,VkShaderModule(0),
286 						 VkShaderModule(0),VkShaderModule(0),fragment,renderPass,viewports, scissors,
287 						 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,0,0,&vertexInputStateCreateInfo);
288 }
289 
createComputePipeline(VkPipelineLayout pipelineLayout,bool producer)290 Move<VkPipeline> GPQInstanceBase::createComputePipeline	(VkPipelineLayout pipelineLayout, bool producer)
291 {
292 	const DeviceInterface&	vk	= m_context.getDeviceInterface();
293 	const VkDevice			dev	= m_device.handle;
294 
295 	const std::string		compName = producer ? "cpyb" : "cpyi";
296 	auto comp = std::find_if(std::begin(m_shaders), std::end(m_shaders), [&](const NamedShader& ns){ return ns.name == compName; });
297 	if (*comp->handle == DE_NULL) comp->handle = createShaderModule(vk, dev, m_context.getBinaryCollection().get(compName));
298 	VkShaderModule compute = *comp->handle;
299 
300 	VkPipelineShaderStageCreateInfo	sci{};
301 	sci.sType				= VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
302 	sci.pNext				= nullptr;
303 	sci.flags				= VkPipelineShaderStageCreateFlags(0);
304 	sci.stage				= VK_SHADER_STAGE_COMPUTE_BIT;
305 	sci.module				= compute;
306 	sci.pName				= "main";
307 	sci.pSpecializationInfo	= nullptr;
308 
309 	VkComputePipelineCreateInfo	ci{};
310 	ci.sType				= VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
311 	ci.pNext				= nullptr;
312 	ci.flags				= VkPipelineCreateFlags(0);
313 	ci.stage				= sci;
314 	ci.layout				= pipelineLayout;
315 	ci.basePipelineHandle	= VkPipeline(0);
316 	ci.basePipelineIndex	= 0;
317 
318 	return vk::createComputePipeline(vk, dev, VkPipelineCache(0), &ci, nullptr);
319 }
320 
321 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit);
submitCommands(VkCommandBuffer producerCmd,VkCommandBuffer consumerCmd) const322 void GPQInstanceBase::submitCommands (VkCommandBuffer producerCmd, VkCommandBuffer consumerCmd) const
323 {
324 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
325 	const VkDevice			dev		= m_device.handle;
326 
327 	Move<VkSemaphore>		sem		= createSemaphore(vkd, dev);
328 	Move<VkFence>			fence	= createFence(vkd, dev);
329 
330 	VkProtectedSubmitInfo protectedSubmitInfo
331 	{
332 		VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO,	// VkStructureType	sType;
333 		nullptr,									// void*			pNext;
334 		VK_TRUE										// VkBool32			protectedSubmit;
335 	};
336 
337 	const VkSubmitInfo		producerSubmitInfo
338 	{
339 		VK_STRUCTURE_TYPE_SUBMIT_INFO,				// VkStructureType				sType;
340 		m_config.enableProtected
341 				? &protectedSubmitInfo : nullptr,	// const void*					pNext;
342 		0,											// deUint32						waitSemaphoreCount;
343 		nullptr,									// const VkSemaphore*			pWaitSemaphores;
344 		nullptr,									// const VkPipelineStageFlags*	pWaitDstStageMask;
345 		1u,											// deUint32						commandBufferCount;
346 		&producerCmd,								// const VkCommandBuffer*		pCommandBuffers;
347 		1u,											// deUint32						signalSemaphoreCount;
348 		&sem.get(),									// const VkSemaphore*			pSignalSemaphores;
349 	};
350 
351 	const VkPipelineStageFlags	dstWaitStages = VK_PIPELINE_STAGE_TRANSFER_BIT |
352 												queueFlagBitToPipelineStage(m_config.transitionTo);
353 	const VkSubmitInfo		consumerSubmitInfo
354 	{
355 		VK_STRUCTURE_TYPE_SUBMIT_INFO,				// VkStructureType				sType;
356 		m_config.enableProtected
357 				? &protectedSubmitInfo : nullptr,	// const void*					pNext;
358 		1u,											// deUint32						waitSemaphoreCount;
359 		&sem.get(),									// const VkSemaphore*			pWaitSemaphores;
360 		&dstWaitStages,								// const VkPipelineStageFlags*	pWaitDstStageMask;
361 		1u,											// deUint32						commandBufferCount;
362 		&consumerCmd,								// const VkCommandBuffer*		pCommandBuffers;
363 		0,											// deUint32						signalSemaphoreCount;
364 		nullptr,									// const VkSemaphore*			pSignalSemaphores;
365 	};
366 
367 	switch (m_config.syncType)
368 	{
369 	case SyncType::None:
370 		submitCommandsAndWait(vkd, dev, m_device.queueFrom, producerCmd);
371 		submitCommandsAndWait(vkd, dev, m_device.queueTo, consumerCmd);
372 		break;
373 	case SyncType::Semaphore:
374 		VK_CHECK(vkd.queueSubmit(m_device.queueFrom, 1u, &producerSubmitInfo, VkFence(0)));
375 		VK_CHECK(vkd.queueSubmit(m_device.queueTo, 1u, &consumerSubmitInfo, *fence));
376 		VK_CHECK(vkd.waitForFences(dev, 1u, &fence.get(), DE_TRUE, ~0ull));
377 		break;
378 	}
379 }
380 
381 template<VkQueueFlagBits, VkQueueFlagBits> class GPQInstance;
382 #define DECLARE_INSTANCE(flagsFrom_, flagsTo_)									\
383 	template<> class GPQInstance<flagsFrom_, flagsTo_> : public GPQInstanceBase	\
384 	{	public:	GPQInstance (Context& ctx, const TestConfig& cfg)				\
385 					: GPQInstanceBase(ctx, cfg)	{ }								\
386 				virtual tcu::TestStatus	iterate (void) override;				}
387 
388 DECLARE_INSTANCE(VK_QUEUE_GRAPHICS_BIT,	VK_QUEUE_COMPUTE_BIT);
389 DECLARE_INSTANCE(VK_QUEUE_COMPUTE_BIT,	VK_QUEUE_GRAPHICS_BIT);
390 
391 class GPQCase;
392 typedef TestInstance* (GPQCase::* CreateInstanceProc)(Context&) const;
393 typedef std::pair<VkQueueFlagBits,VkQueueFlagBits> CreateInstanceKey;
394 typedef std::map<CreateInstanceKey, CreateInstanceProc> CreateInstanceMap;
395 #define MAPENTRY(from_,to_) m_createInstanceMap[{from_,to_}] = &GPQCase::createInstance<from_,to_>
396 
397 class GPQCase : public TestCase
398 {
399 public:
400 					GPQCase				(tcu::TestContext&	ctx,
401 										 const std::string&	name,
402 										 const TestConfig&	cfg);
403 	void			initPrograms		(SourceCollections&	programs)	const override;
404 	TestInstance*	createInstance		(Context&			context)	const override;
405 	void			checkSupport		(Context&			context)	const override;
406 	static deUint32	testValue;
407 
408 private:
409 	template<VkQueueFlagBits, VkQueueFlagBits>
410 		TestInstance*	createInstance	(Context&			context)	const;
411 	mutable TestConfig	m_config;
412 	CreateInstanceMap	m_createInstanceMap;
413 };
414 deUint32 GPQCase::testValue = 113;
415 
GPQCase(tcu::TestContext & ctx,const std::string & name,const TestConfig & cfg)416 GPQCase::GPQCase (tcu::TestContext&		ctx,
417 				  const std::string&	name,
418 				  const TestConfig&		cfg)
419 	: TestCase				(ctx, name)
420 	, m_config				(cfg)
421 	, m_createInstanceMap	()
422 {
423 	MAPENTRY(VK_QUEUE_GRAPHICS_BIT,	VK_QUEUE_COMPUTE_BIT);
424 	MAPENTRY(VK_QUEUE_COMPUTE_BIT,	VK_QUEUE_GRAPHICS_BIT);
425 }
426 
queueFlagBitToPipelineStage(VkQueueFlagBits bit)427 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit)
428 {
429 	switch (bit) {
430 	case VK_QUEUE_COMPUTE_BIT:
431 		return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
432 	case VK_QUEUE_GRAPHICS_BIT:
433 		return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
434 	default:
435 		DE_ASSERT(VK_FALSE);
436 	}
437 	return VK_QUEUE_FLAG_BITS_MAX_ENUM;
438 }
439 
440 template<VkQueueFlagBits flagsFrom, VkQueueFlagBits flagsTo>
createInstance(Context & context) const441 TestInstance* GPQCase::createInstance (Context& context) const
442 {
443 	return new GPQInstance<flagsFrom, flagsTo>(context, m_config);
444 }
445 
createInstance(Context & context) const446 TestInstance* GPQCase::createInstance (Context& context) const
447 {
448 	const CreateInstanceKey	key(m_config.transitionFrom, m_config.transitionTo);
449 	return (this->*(m_createInstanceMap.at(key)))(context);
450 }
451 
operator <<(std::ostream & str,const VkQueueFlagBits & bit)452 std::ostream& operator<<(std::ostream& str, const VkQueueFlagBits& bit)
453 {
454 	const char* s = nullptr;
455 	const auto d = std::to_string(bit);
456 	switch (bit)
457 	{
458 		case VK_QUEUE_GRAPHICS_BIT:			s = "VK_QUEUE_GRAPHICS_BIT";		break;
459 		case VK_QUEUE_COMPUTE_BIT:			s = "VK_QUEUE_COMPUTE_BIT";			break;
460 		case VK_QUEUE_TRANSFER_BIT:			s = "VK_QUEUE_TRANSFER_BIT";		break;
461 		case VK_QUEUE_SPARSE_BINDING_BIT:	s = "VK_QUEUE_SPARSE_BINDING_BIT";	break;
462 		case VK_QUEUE_PROTECTED_BIT:		s = "VK_QUEUE_PROTECTED_BIT";		break;
463 		default:							s = d.c_str();						break;
464 	}
465 	return (str << s);
466 }
467 
checkSupport(Context & context) const468 void GPQCase::checkSupport (Context& context) const
469 {
470 	const InstanceInterface&	vki = context.getInstanceInterface();
471 	const VkPhysicalDevice		dev = context.getPhysicalDevice();
472 
473 	context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
474 	context.requireDeviceFunctionality("VK_EXT_global_priority_query");
475 	context.requireDeviceFunctionality("VK_EXT_global_priority");
476 
477 	if (!m_config.selectFormat(vki, dev, { VK_FORMAT_R32_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8_UINT }))
478 	{
479 		TCU_THROW(NotSupportedError, "Unable to find a proper format");
480 	}
481 
482 	VkPhysicalDeviceProtectedMemoryFeatures	memFeatures
483 	{
484 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
485 		nullptr,
486 		VK_FALSE
487 	};
488 	VkPhysicalDeviceFeatures2	devFeatures
489 	{
490 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
491 		&memFeatures,
492 		{}
493 	};
494 	vki.getPhysicalDeviceFeatures2(dev, &devFeatures);
495 
496 	if (m_config.enableProtected && (VK_FALSE == memFeatures.protectedMemory))
497 	{
498 		TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_PROTECTED_BIT not supported");
499 	}
500 
501 	const VkBool32 sparseEnabled = devFeatures.features.sparseBinding & devFeatures.features.sparseResidencyBuffer & devFeatures.features.sparseResidencyImage2D;
502 	if (m_config.enableSparseBinding && (VK_FALSE == sparseEnabled))
503 	{
504 		TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_SPARSE_BINDING_BIT not supported");
505 	}
506 
507 	auto assertUnavailableQueue = [](const deUint32 qIdx, VkQueueFlagBits qfb, VkQueueGlobalPriorityKHR qgp)
508 	{
509 		if (qIdx == INVALID_UINT32) {
510 			std::ostringstream buf;
511 			buf << "Unable to find queue " << qfb << " with priority " << qgp;
512 			buf.flush();
513 			TCU_THROW(NotSupportedError, buf.str());
514 		}
515 	};
516 
517 	VkQueueFlags	flagsFrom	= m_config.transitionFrom;
518 	VkQueueFlags	flagsTo		= m_config.transitionTo;
519 	if (m_config.enableProtected)
520 	{
521 		flagsFrom |= VK_QUEUE_PROTECTED_BIT;
522 		flagsTo	|= VK_QUEUE_PROTECTED_BIT;
523 	}
524 	if (m_config.enableSparseBinding)
525 	{
526 		flagsFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
527 		flagsTo	|= VK_QUEUE_SPARSE_BINDING_BIT;
528 	}
529 
530 	const deUint32 queueFromIndex	= findQueueFamilyIndex(vki, dev, m_config.priorityFrom,
531 														   flagsFrom, SpecialDevice::getColissionFlags(flagsFrom),
532 														   INVALID_UINT32);
533 	assertUnavailableQueue(queueFromIndex, m_config.transitionFrom, m_config.priorityFrom);
534 
535 	const deUint32 queueToIndex		= findQueueFamilyIndex(vki, dev, m_config.priorityTo,
536 														   flagsTo, SpecialDevice::getColissionFlags(flagsTo),
537 														   queueFromIndex);
538 	assertUnavailableQueue(queueToIndex, m_config.transitionTo, m_config.priorityTo);
539 
540 	if (queueFromIndex == queueToIndex)
541 	{
542 		std::ostringstream buf;
543 		buf << "Unable to find separate queues " << m_config.transitionFrom << " and " << m_config.transitionTo;
544 		buf.flush();
545 		TCU_THROW(NotSupportedError, buf.str());
546 	}
547 }
548 
initPrograms(SourceCollections & programs) const549 void GPQCase::initPrograms (SourceCollections& programs) const
550 {
551 	const std::string producerComp(R"glsl(
552 	#version 450
553 	layout(binding=0) buffer S { float src[]; };
554 	layout(binding=1) buffer D { float dst[]; };
555 	layout(local_size_x=1,local_size_y=1) in;
556 	void main() {
557 		dst[gl_GlobalInvocationID.x] = src[gl_GlobalInvocationID.x];
558 	}
559 	)glsl");
560 
561 	const tcu::StringTemplate consumerComp(R"glsl(
562 	#version 450
563 	layout(local_size_x=1,local_size_y=1) in;
564 	layout(${IMAGE_FORMAT}, binding=0) readonly uniform ${IMAGE_TYPE} srcImage;
565 	layout(binding=1) writeonly coherent buffer Pixels { uint data[]; } dstBuffer;
566 	void main()
567 	{
568 		ivec2 srcIdx = ivec2(gl_GlobalInvocationID.xy);
569 		int   width  = imageSize(srcImage).x;
570 		int   dstIdx = int(gl_GlobalInvocationID.y * width + gl_GlobalInvocationID.x);
571 		dstBuffer.data[dstIdx] = uint(imageLoad(srcImage, srcIdx).r) == ${TEST_VALUE} ? 1 : 0;
572 	}
573 	)glsl");
574 
575 	const std::string vert(R"glsl(
576 	#version 450
577 	layout(location = 0) in vec2 pos;
578 	void main()
579 	{
580 	   gl_Position = vec4(pos, 0.0, 1.01);
581 	}
582 	)glsl");
583 
584 	const tcu::StringTemplate frag(R"glsl(
585 	#version 450
586 	layout(location = 0) out ${COLOR_TYPE} color;
587 	void main()
588 	{
589 	   color = ${COLOR_TYPE}(${TEST_VALUE},0,0,1);
590 	}
591 	)glsl");
592 
593 	const auto format		= mapVkFormat(m_config.format);
594 	const auto imageFormat	= image::getShaderImageFormatQualifier(format);
595 	const auto imageType	= image::getShaderImageType(format, image::ImageType::IMAGE_TYPE_2D, false);
596 	const auto colorType	= image::getGlslAttachmentType(m_config.format); // ivec4
597 
598 	const std::map<std::string, std::string>	abbreviations
599 	{
600 		{ std::string("TEST_VALUE"),	std::to_string(testValue)	},
601 		{ std::string("IMAGE_FORMAT"),	std::string(imageFormat)	},
602 		{ std::string("IMAGE_TYPE"),	std::string(imageType)		},
603 		{ std::string("COLOR_TYPE"),	std::string(colorType)		},
604 	};
605 
606 	programs.glslSources.add("cpyb") << glu::ComputeSource(producerComp);
607 	programs.glslSources.add("cpyi") << glu::ComputeSource(consumerComp.specialize(abbreviations));
608 	programs.glslSources.add("vert") << glu::VertexSource(vert);
609 	programs.glslSources.add("frag") << glu::FragmentSource(frag.specialize(abbreviations));
610 }
611 
iterate(void)612 tcu::TestStatus	GPQInstance<VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT>::iterate (void)
613 {
614 	if (VK_SUCCESS != m_device.createResult)
615 	{
616 		if (VK_ERROR_NOT_PERMITTED_KHR == m_device.createResult)
617 			return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Custom device creation returned " + std::string(getResultName(m_device.createResult)));
618 		throw NotSupportedError(m_device.createResult, getResultName(m_device.createResult), m_device.createExpression, m_device.createFileName, m_device.createFileLine);
619 	}
620 
621 	const InstanceInterface&		vki					= m_context.getInstanceInterface();
622 	const DeviceInterface&			vkd					= m_context.getDeviceInterface();
623 	const VkPhysicalDevice			phys				= m_context.getPhysicalDevice();
624 	const VkDevice					device				= m_device.handle;
625 	Allocator&						allocator			= m_device.getAllocator();
626 	const deUint32					producerIndex		= m_device.queueFamilyIndexFrom;
627 	const deUint32					consumerIndex		= m_device.queueFamilyIndexTo;
628 	const std::vector<deUint32>		producerIndices		{ producerIndex };
629 	const std::vector<deUint32>		consumerIndices		{ consumerIndex };
630 	const VkQueue					producerQueue		= m_device.queueFrom;
631 	const VkQueue					consumerQueue		= m_device.queueTo;
632 
633 	// stagging buffer for vertices
634 	const std::vector<float>		positions			{ +1.f, -1.f, -1.f, -1.f, 0.f, +1.f };
635 	const VkBufferCreateInfo		posBuffInfo			= makeBufferCreateInfo(positions.size() * sizeof(float), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, producerIndices);
636 	BufferWithMemory				positionsBuffer		(vki, vkd, phys, device, allocator, posBuffInfo, MemoryRequirement::HostVisible);
637 	std::copy_n(positions.data(), positions.size(), begin<float>(positionsBuffer.getHostPtr()));
638 	const VkDescriptorBufferInfo	posDsBuffInfo		= makeDescriptorBufferInfo(positionsBuffer.get(), 0, positionsBuffer.getSize());
639 
640 	// vertex buffer
641 	VkBufferCreateFlags				vertCreateFlags		= 0;
642 	if (m_config.enableProtected)	vertCreateFlags		|= VK_BUFFER_CREATE_PROTECTED_BIT;
643 	if (m_config.enableSparseBinding) vertCreateFlags	|= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
644 	const VkBufferUsageFlags		vertBuffUsage		= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
645 	const MemoryRequirement			vertMemReqs			= (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any);
646 	const VkBufferCreateInfo		vertBuffInfo		= makeBufferCreateInfo(positionsBuffer.getSize(), vertBuffUsage, producerIndices, vertCreateFlags);
647 	const BufferWithMemory			vertexBuffer		(vki, vkd, phys, device, allocator, vertBuffInfo, vertMemReqs, producerQueue);
648 	const VkDescriptorBufferInfo	vertDsBuffInfo		= makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBuffer.getSize());
649 
650 	// descriptor set for stagging and vertex buffers
651 	Move<VkDescriptorPool>			producerDsPool		= DescriptorPoolBuilder()
652 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
653 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
654 															.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
655 	Move<VkDescriptorSetLayout>		producerDsLayout	= DescriptorSetLayoutBuilder()
656 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
657 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
658 															.build(vkd, device);
659 	Move<VkDescriptorSet>			producerDs			= makeDescriptorSet(vkd, device, *producerDsPool, *producerDsLayout);
660 	DescriptorSetUpdateBuilder()
661 		.writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &posDsBuffInfo)
662 		.writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &vertDsBuffInfo)
663 		.update(vkd, device);
664 
665 	// consumer image
666 	const uint32_t					clearComp			= 97;
667 	const VkClearValue				clearColor			= makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
668 	VkImageSubresourceRange			imageResourceRange	{};
669 	const VkImageUsageFlags			imageUsage			= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
670 	de::MovePtr<ImageWithMemory>	image				= createImage(imageUsage, consumerIndex, consumerQueue);
671 	Move<VkImageView>				view				= createView(**image, imageResourceRange);
672 	Move<VkRenderPass>				renderPass			= makeRenderPass(vkd, device, m_config.format);
673 	Move<VkFramebuffer>				framebuffer			= makeFramebuffer(vkd, device, *renderPass, *view, m_config.width, m_config.height);
674 	const VkDescriptorImageInfo		imageDsInfo			= makeDescriptorImageInfo(VkSampler(0), *view, VK_IMAGE_LAYOUT_GENERAL);
675 	const VkImageMemoryBarrier		imageReadyBarrier	= makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
676 															VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
677 															**image, imageResourceRange, consumerIndex, consumerIndex);
678 	// stagging buffer for result
679 	const VkDeviceSize				resultBuffSize		= (m_config.width * m_config.height * mapVkFormat(m_config.format).getPixelSize());
680 	const VkBufferCreateInfo		resultBuffInfo		= makeBufferCreateInfo(resultBuffSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, consumerIndices);
681 	BufferWithMemory				resultBuffer		(vki, vkd, phys, device, allocator, resultBuffInfo, MemoryRequirement::HostVisible);
682 	const VkDescriptorBufferInfo	resultDsBuffInfo	= makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBuffSize);
683 	const VkMemoryBarrier			resultReadyBarrier	= makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
684 
685 	// descriptor set for consumer image and result buffer
686 	Move<VkDescriptorPool>			consumerDsPool		= DescriptorPoolBuilder()
687 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
688 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
689 															.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
690 	Move<VkDescriptorSetLayout>		consumerDsLayout	= DescriptorSetLayoutBuilder()
691 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL)
692 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
693 															.build(vkd, device);
694 	Move<VkDescriptorSet>			consumerDs			= makeDescriptorSet(vkd, device, *consumerDsPool, *consumerDsLayout);
695 
696 	DescriptorSetUpdateBuilder()
697 		.writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageDsInfo)
698 		.writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultDsBuffInfo)
699 		.update(vkd, device);
700 
701 	Move<VkPipelineLayout>			producerLayout		= createPipelineLayout<>({ *producerDsLayout });
702 	Move<VkPipeline>				producerPipeline	= createComputePipeline(*producerLayout, true);
703 
704 	Move<VkPipelineLayout>			consumerLayout		= createPipelineLayout<>({ *consumerDsLayout });
705 	Move<VkPipeline>				consumerPipeline	= createGraphicsPipeline(*consumerLayout, *renderPass);
706 
707 	Move<VkPipelineLayout>			resultLayout		= createPipelineLayout<>({ *consumerDsLayout });
708 	Move<VkCommandPool>				resultPool			= makeCommandPool(consumerIndex);
709 	Move<VkPipeline>				resultPipeline		= createComputePipeline(*resultLayout, false);
710 
711 	Move<VkCommandPool>				producerPool		= makeCommandPool(producerIndex);
712 	Move<VkCommandPool>				consumerPool		= makeCommandPool(consumerIndex);
713 	Move<VkCommandBuffer>			producerCmd			= allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
714 	Move<VkCommandBuffer>			consumerCmd			= allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
715 
716 	beginCommandBuffer(vkd, *producerCmd);
717 		vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerPipeline);
718 		vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerLayout, 0, 1, &(*producerDs), 0, nullptr);
719 		vkd.cmdDispatch(*producerCmd, deUint32(positions.size()), 1, 1);
720 	endCommandBuffer(vkd, *producerCmd);
721 
722 	beginCommandBuffer(vkd, *consumerCmd);
723 		vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerPipeline);
724 		vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *resultPipeline);
725 		vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerLayout, 0, 1, &(*consumerDs), 0, nullptr);
726 		vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *resultLayout, 0, 1, &(*consumerDs), 0, nullptr);
727 		vkd.cmdBindVertexBuffers(*consumerCmd, 0, 1, vertexBuffer.getPtr(), &static_cast<const VkDeviceSize&>(0));
728 
729 		beginRenderPass(vkd, *consumerCmd, *renderPass, *framebuffer, makeRect2D(m_config.width, m_config.height), clearColor);
730 			vkd.cmdDraw(*consumerCmd, deUint32(positions.size()), 1, 0, 0);
731 		endRenderPass(vkd, *consumerCmd);
732 		vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u,
733 							   0u, nullptr, 0u, nullptr, 1u, &imageReadyBarrier);
734 
735 		vkd.cmdDispatch(*consumerCmd, m_config.width, m_config.height, 1);
736 		vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
737 							   1u, &resultReadyBarrier, 0u, nullptr, 0u, nullptr);
738 	endCommandBuffer(vkd, *consumerCmd);
739 
740 	submitCommands(*producerCmd, *consumerCmd);
741 
742 	resultBuffer.invalidateAlloc(vkd, device);
743 	const tcu::ConstPixelBufferAccess	resultBufferAccess(mapVkFormat(m_config.format), m_config.width, m_config.height, 1, resultBuffer.getHostPtr());
744 	const deUint32 resultValue = resultBufferAccess.getPixelUint(0, 0).x();
745 	const deUint32 expectedValue = 1;
746 	const bool ok = (resultValue == expectedValue);
747 	if (!ok)
748 	{
749 		m_context.getTestContext().getLog()
750 			<< tcu::TestLog::Message << "Expected value: " << expectedValue << ", got " << resultValue << tcu::TestLog::EndMessage;
751 	}
752 
753 	return ok ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
754 }
755 
iterate(void)756 tcu::TestStatus	GPQInstance<VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT>::iterate (void)
757 {
758 	if (VK_SUCCESS != m_device.createResult)
759 	{
760 		if (VK_ERROR_NOT_PERMITTED_KHR == m_device.createResult)
761 			return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Custom device creation returned " + std::string(getResultName(m_device.createResult)));
762 		throw NotSupportedError(m_device.createResult, getResultName(m_device.createResult), m_device.createExpression, m_device.createFileName, m_device.createFileLine);
763 	}
764 
765 	const InstanceInterface&		vki					= m_context.getInstanceInterface();
766 	const DeviceInterface&			vkd					= m_context.getDeviceInterface();
767 	const VkPhysicalDevice			phys				= m_context.getPhysicalDevice();
768 	const VkDevice					device				= m_device.handle;
769 	Allocator&						allocator			= m_device.getAllocator();
770 	const deUint32					producerIndex		= m_device.queueFamilyIndexFrom;
771 	const deUint32					consumerIndex		= m_device.queueFamilyIndexTo;
772 	const std::vector<deUint32>		producerIndices		{ producerIndex };
773 	const std::vector<deUint32>		consumerIndices		{ consumerIndex };
774 	const VkQueue					producerQueue		= m_device.queueFrom;
775 
776 	// stagging buffer for vertices
777 	const std::vector<float>		positions			{ +1.f, -1.f, -1.f, -1.f, 0.f, +1.f };
778 	const VkBufferCreateInfo		positionBuffInfo	= makeBufferCreateInfo(positions.size() * sizeof(float), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, producerIndices);
779 	BufferWithMemory				positionsBuffer		(vki, vkd, phys, device, allocator, positionBuffInfo, MemoryRequirement::HostVisible);
780 	std::copy_n(positions.data(), positions.size(), begin<float>(positionsBuffer.getHostPtr()));
781 	const VkDescriptorBufferInfo	posDsBuffInfo		= makeDescriptorBufferInfo(positionsBuffer.get(), 0, positionsBuffer.getSize());
782 
783 	// vertex buffer
784 	VkBufferCreateFlags				vertCreateFlags		= 0;
785 	if (m_config.enableProtected)	vertCreateFlags		|= VK_BUFFER_CREATE_PROTECTED_BIT;
786 	if (m_config.enableSparseBinding) vertCreateFlags	|= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
787 	const VkBufferUsageFlags		vertBuffUsage		= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
788 	const MemoryRequirement			vertMemReqs			= (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any);
789 	const VkBufferCreateInfo		vertBuffInfo		= makeBufferCreateInfo(positionsBuffer.getSize(), vertBuffUsage, producerIndices, vertCreateFlags);
790 	const BufferWithMemory			vertexBuffer		(vki, vkd, phys, device, allocator, vertBuffInfo, vertMemReqs, producerQueue);
791 	const VkDescriptorBufferInfo	vertDsBuffInfo		= makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBuffer.getSize());
792 	const VkBufferMemoryBarrier		producerReadyBarrier= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
793 																				  vertexBuffer.get(), 0, vertexBuffer.getSize(), producerIndex, producerIndex);
794 
795 	// descriptor set for stagging and vertex buffers
796 	Move<VkDescriptorPool>			producerDsPool		= DescriptorPoolBuilder()
797 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
798 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
799 															.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
800 	Move<VkDescriptorSetLayout>		producerDsLayout	= DescriptorSetLayoutBuilder()
801 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
802 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
803 															.build(vkd, device);
804 	Move<VkDescriptorSet>			producerDs			= makeDescriptorSet(vkd, device, *producerDsPool, *producerDsLayout);
805 	DescriptorSetUpdateBuilder()
806 		.writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &posDsBuffInfo)
807 		.writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &vertDsBuffInfo)
808 		.update(vkd, device);
809 
810 	// producer image
811 	const uint32_t					clearComp			= 97;
812 	const VkClearValue				clearColor			= makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
813 	VkImageSubresourceRange			imageResourceRange	{};
814 	const VkImageUsageFlags			imageUsage			= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
815 	de::MovePtr<ImageWithMemory>	image				= createImage(imageUsage, producerIndex, producerQueue);
816 	Move<VkImageView>				view				= createView(**image, imageResourceRange);
817 	Move<VkRenderPass>				renderPass			= makeRenderPass(vkd, device, m_config.format);
818 	Move<VkFramebuffer>				framebuffer			= makeFramebuffer(vkd, device, *renderPass, *view, m_config.width, m_config.height);
819 	const VkDescriptorImageInfo		imageDsInfo			= makeDescriptorImageInfo(VkSampler(0), *view, VK_IMAGE_LAYOUT_GENERAL);
820 	const VkImageMemoryBarrier		imageReadyBarrier	= makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
821 															VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
822 															**image, imageResourceRange, producerIndex, producerIndex);
823 
824 	// stagging buffer for result
825 	const VkDeviceSize				resultBufferSize	= (m_config.width * m_config.height * mapVkFormat(m_config.format).getPixelSize());
826 	const VkBufferCreateInfo		resultBufferInfo	= makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, consumerIndices);
827 	BufferWithMemory				resultBuffer		(vki, vkd, phys, device, allocator, resultBufferInfo, MemoryRequirement::HostVisible);
828 	const VkDescriptorBufferInfo	resultDsBuffInfo	= makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSize);
829 	const VkBufferMemoryBarrier		resultReadyBarrier	= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
830 																				  resultBuffer.get(), 0, resultBufferSize, consumerIndex, consumerIndex);
831 
832 	// descriptor set for consumer image and result buffer
833 	Move<VkDescriptorPool>			consumerDsPool		= DescriptorPoolBuilder()
834 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
835 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
836 															.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
837 	Move<VkDescriptorSetLayout>		consumerDsLayout	= DescriptorSetLayoutBuilder()
838 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL)
839 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
840 															.build(vkd, device);
841 	Move<VkDescriptorSet>			consumerDs			= makeDescriptorSet(vkd, device, *consumerDsPool, *consumerDsLayout);
842 
843 	DescriptorSetUpdateBuilder()
844 		.writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageDsInfo)
845 		.writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultDsBuffInfo)
846 		.update(vkd, device);
847 
848 	Move<VkPipelineLayout>			producer1Layout		= createPipelineLayout<>({ *producerDsLayout });
849 	Move<VkPipeline>				producer1Pipeline	= createComputePipeline(*producer1Layout, true);
850 	Move<VkPipelineLayout>			producer2Layout		= createPipelineLayout<>({});
851 	Move<VkPipeline>				producer2Pipeline	= createGraphicsPipeline(*producer2Layout, *renderPass);
852 
853 	Move<VkPipelineLayout>			consumerLayout		= createPipelineLayout<>({ *consumerDsLayout });
854 	Move<VkPipeline>				consumerPipeline	= createComputePipeline(*consumerLayout, false);
855 
856 	Move<VkCommandPool>				producerPool		= makeCommandPool(producerIndex);
857 	Move<VkCommandPool>				consumerPool		= makeCommandPool(consumerIndex);
858 	Move<VkCommandBuffer>			producerCmd			= allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
859 	Move<VkCommandBuffer>			consumerCmd			= allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
860 
861 
862 	beginCommandBuffer(vkd, *producerCmd);
863 		vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producer1Pipeline);
864 		vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *producer2Pipeline);
865 		vkd.cmdBindVertexBuffers(*producerCmd, 0, 1, vertexBuffer.getPtr(), &static_cast<const VkDeviceSize&>(0));
866 		vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producer1Layout, 0, 1, &producerDs.get(), 0, nullptr);
867 		vkd.cmdDispatch(*producerCmd, deUint32(positions.size()), 1, 1);
868 		vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0,
869 							   0, nullptr, 1, &producerReadyBarrier, 0, nullptr);
870 		beginRenderPass(vkd, *producerCmd, *renderPass, *framebuffer, makeRect2D(m_config.width, m_config.height), clearColor);
871 			vkd.cmdDraw(*producerCmd, deUint32(positions.size()), 1, 0, 0);
872 		endRenderPass(vkd, *producerCmd);
873 		vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0,
874 							   0u, nullptr, 0u, nullptr, 1u, &imageReadyBarrier);
875 	endCommandBuffer(vkd, *producerCmd);
876 
877 	beginCommandBuffer(vkd, *consumerCmd);
878 		vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerPipeline);
879 		vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerLayout, 0, 1, &consumerDs.get(), 0, nullptr);
880 		vkd.cmdDispatch(*consumerCmd, m_config.width, m_config.height, 1);
881 		vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
882 							   0, nullptr, 1, &resultReadyBarrier, 0, nullptr);
883 	endCommandBuffer(vkd, *consumerCmd);
884 
885 	submitCommands(*producerCmd, *consumerCmd);
886 
887 	resultBuffer.invalidateAlloc(vkd, device);
888 	const tcu::ConstPixelBufferAccess	resultBufferAccess(mapVkFormat(m_config.format), m_config.width, m_config.height, 1, resultBuffer.getHostPtr());
889 	const deUint32 resultValue = resultBufferAccess.getPixelUint(0, 0).x();
890 	const deUint32 expectedValue = 1;
891 	const bool ok = (resultValue == expectedValue);
892 	if (!ok)
893 	{
894 		m_context.getTestContext().getLog()
895 			<< tcu::TestLog::Message << "Expected value: " << expectedValue << ", got " << resultValue << tcu::TestLog::EndMessage;
896 	}
897 
898 	return ok ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
899 }
900 
901 } // anonymous
902 
createGlobalPriorityQueueTests(tcu::TestContext & testCtx)903 tcu::TestCaseGroup* createGlobalPriorityQueueTests (tcu::TestContext& testCtx)
904 {
905 	typedef std::pair<VkQueueFlagBits, const char*> TransitionItem;
906 	TransitionItem const transitions[]
907 	{
908 		{ VK_QUEUE_GRAPHICS_BIT,	"graphics"	},
909 		{ VK_QUEUE_COMPUTE_BIT,		"compute"	},
910 	};
911 
912 	auto mkGroupName = [](const TransitionItem& from, const TransitionItem& to) -> std::string
913 	{
914 		return std::string("from_") + from.second + std::string("_to_") + to.second;
915 	};
916 
917 	std::pair<VkQueueFlags, const char*>
918 			const modifiers[]
919 	{
920 		{ 0,													"no_modifiers"		},
921 		{ VK_QUEUE_SPARSE_BINDING_BIT,							"sparse"			},
922 		{ VK_QUEUE_PROTECTED_BIT,								"protected"			}
923 	};
924 
925 	std::pair<VkQueueGlobalPriorityKHR, const char*>
926 			const prios[]
927 	{
928 		{ VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR,			"low"		},
929 		{ VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR,		"medium"	},
930 		{ VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR,		"high"		},
931 		{ VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR,	"realtime"	},
932 	};
933 
934 	std::pair<SyncType, const char*>
935 			const syncs[]
936 	{
937 		{ SyncType::None,		"no_sync"	},
938 		{ SyncType::Semaphore,	"semaphore"	},
939 	};
940 
941 	const uint32_t	dim0	= 34;
942 	const uint32_t	dim1	= 25;
943 	bool			swap	= true;
944 
945 	auto rootGroup = new tcu::TestCaseGroup(testCtx, "global_priority_transition");
946 
947 	for (const auto& prio : prios)
948 	{
949 		auto prioGroup = new tcu::TestCaseGroup(testCtx, prio.second);
950 
951 		for (const auto& sync : syncs)
952 		{
953 			auto syncGroup = new tcu::TestCaseGroup(testCtx, sync.second);
954 
955 			for (const auto& mod : modifiers)
956 			{
957 				auto modGroup = new tcu::TestCaseGroup(testCtx, mod.second);
958 
959 				for (const auto& transitionFrom : transitions)
960 				{
961 					for (const auto& transitionTo : transitions)
962 					{
963 						if (transitionFrom != transitionTo)
964 						{
965 							TestConfig	cfg{};
966 							cfg.transitionFrom		= transitionFrom.first;
967 							cfg.transitionTo		= transitionTo.first;
968 							cfg.priorityFrom		= prio.first;
969 							cfg.priorityTo			= prio.first;
970 							cfg.syncType			= sync.first;
971 							cfg.enableProtected		= (mod.first & VK_QUEUE_PROTECTED_BIT) != 0;
972 							cfg.enableSparseBinding	= (mod.first & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
973 							// Note that format is changing in GPQCase::checkSupport(...)
974 							cfg.format				= VK_FORMAT_R32G32B32A32_SFLOAT;
975 							cfg.width				= swap ? dim0 : dim1;
976 							cfg.height				= swap ? dim1 : dim0;
977 
978 							swap ^= true;
979 
980 							modGroup->addChild(new GPQCase(testCtx, mkGroupName(transitionFrom, transitionTo), cfg));
981 						}
982 					}
983 				}
984 				syncGroup->addChild(modGroup);
985 			}
986 			prioGroup->addChild(syncGroup);
987 		}
988 		rootGroup->addChild(prioGroup);
989 	}
990 
991 	return rootGroup;
992 }
993 
994 } // synchronization
995 } // vkt
996