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 
55 using namespace vk;
56 
57 namespace vkt
58 {
59 namespace synchronization
60 {
61 namespace
62 {
63 
64 enum class SyncType
65 {
66 	None,
67 	Semaphore
68 };
69 
70 struct TestConfig
71 {
72 	VkQueueFlagBits				transitionFrom;
73 	VkQueueFlagBits				transitionTo;
74 	VkQueueGlobalPriorityKHR	priorityFrom;
75 	VkQueueGlobalPriorityKHR	priorityTo;
76 	bool						enableProtected;
77 	bool						enableSparseBinding;
78 	SyncType					syncType;
79 	deUint32					width;
80 	deUint32					height;
81 	VkFormat					format;
82 	bool selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats);
83 };
84 
selectFormat(const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats)85 bool TestConfig::selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats)
86 {
87 	auto doesFormatMatch = [](const VkFormat fmt) -> bool
88 	{
89 		const auto tcuFmt = mapVkFormat(fmt);
90 		return tcuFmt.order == tcu::TextureFormat::ChannelOrder::R;
91 	};
92 	VkFormatProperties2 props{};
93 	const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
94 										| VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
95 	for (auto i = formats.begin(); i != formats.end(); ++i)
96 	{
97 		props.sType				= VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
98 		props.pNext				= nullptr;
99 		props.formatProperties	= {};
100 		const VkFormat		fmt = *i;
101 		vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props);
102 		if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags))
103 		{
104 			this->format = fmt;
105 			return true;
106 		}
107 	}
108 	return false;
109 }
110 
111 struct CheckerboardBuilder
112 {
CheckerboardBuildervkt::synchronization::__anon29962::CheckerboardBuilder113 	CheckerboardBuilder (uint32_t width, uint32_t height)
114 		: m_width(width), m_height(height) {}
115 
blackFieldCountvkt::synchronization::__anon29962::CheckerboardBuilder116 	static uint32_t blackFieldCount (uint32_t w, uint32_t h)
117 	{
118 		return ((w+1)/2)*((h+1)/2)+(w/2)*(h/2);
119 	}
120 
blackFieldCountvkt::synchronization::__anon29962::CheckerboardBuilder121 	uint32_t blackFieldCount () const
122 	{
123 		return blackFieldCount(m_width, m_height);
124 	}
125 
fieldIndexvkt::synchronization::__anon29962::CheckerboardBuilder126 	uint32_t fieldIndex (uint32_t x, uint32_t y) const
127 	{
128 		return blackFieldCount(m_width, y) + (x / 2);
129 	}
130 
buildVerticesAndIndicesvkt::synchronization::__anon29962::CheckerboardBuilder131 	void buildVerticesAndIndices (std::vector<float>& vertices, std::vector<uint32_t>& indices) const
132 	{
133 		const uint32_t	vertPerQuad		= 4;
134 		const uint32_t	indexPerQuad	= 6;
135 		const uint32_t	quadCount		= blackFieldCount();
136 		const uint32_t	compPerQuad		= vertPerQuad * 2;
137 		const uint32_t	vertCount		= quadCount * vertPerQuad;
138 		const uint32_t	indexCount		= quadCount * indexPerQuad;
139 
140 		vertices.resize(vertCount * 2);
141 		indices.resize(indexCount);
142 
143 		for (uint32_t z = 0; z < 2; ++z)
144 		for (uint32_t y = 0; y < m_height; ++y)
145 		for (uint32_t x = 0; x < m_width; ++x)
146 		{
147 			if (((x + y) % 2) == 1)
148 				continue;
149 
150 			const float x1 = float(x) / float(m_width);
151 			const float y1 = float(y) / float(m_height);
152 			const float x2 = (float(x) + 1.0f) / float(m_width);
153 			const float y2 = (float(y) + 1.0f) / float(m_height);
154 
155 			const float xx1 = x1 * 2.0f - 1.0f;
156 			const float yy1 = y1 * 2.0f - 1.0f;
157 			const float xx2 = x2 * 2.0f - 1.0f;
158 			const float yy2 = y2 * 2.0f - 1.0f;
159 
160 			const uint32_t quad = fieldIndex(x, y);
161 
162 			if (z == 0)
163 			{
164 				vertices[ quad * compPerQuad  + 0 ] = xx1;
165 				vertices[ quad * compPerQuad  + 1 ] = yy1;
166 				vertices[ quad * compPerQuad  + 2 ] = xx2;
167 				vertices[ quad * compPerQuad  + 3 ] = yy1;
168 
169 				indices[ quad * indexPerQuad + 0 ] = quad * vertPerQuad + 0;
170 				indices[ quad * indexPerQuad + 1 ] = quad * vertPerQuad + 1;
171 				indices[ quad * indexPerQuad + 2 ] = quad * vertPerQuad + 2;
172 			}
173 			else
174 			{
175 				vertices[ quad * compPerQuad  + 4 ] = xx2;
176 				vertices[ quad * compPerQuad  + 5 ] = yy2;
177 				vertices[ quad * compPerQuad  + 6 ] = xx1;
178 				vertices[ quad * compPerQuad  + 7 ] = yy2;
179 
180 				indices[ quad * indexPerQuad + 3 ] = quad * vertPerQuad + 2;
181 				indices[ quad * indexPerQuad + 4 ] = quad * vertPerQuad + 3;
182 				indices[ quad * indexPerQuad + 5 ] = quad * vertPerQuad + 0;
183 			}
184 		}
185 	}
186 
187 private:
188 	uint32_t	m_width;
189 	uint32_t	m_height;
190 };
191 
192 template<class T, class P = T(*)[1]>
decltype(std::begin(std::declval<P>()))193 auto begin (void* p) -> decltype(std::begin(*std::declval<P>()))
194 {
195 	return std::begin(*static_cast<P>(p));
196 }
197 
198 class GPQInstanceBase : public TestInstance
199 {
200 public:
201 	typedef std::initializer_list<VkDescriptorSetLayout> DSLayouts;
202 	typedef tcu::ConstPixelBufferAccess	BufferAccess;
203 
204 					GPQInstanceBase			(Context&					ctx,
205 											 const TestConfig&			cfg);
206 	template<class PushConstant = void>
207 		auto		createPipelineLayout	(DSLayouts					setLayouts)		const -> Move<VkPipelineLayout>;
208 	auto			createGraphicsPipeline	(VkPipelineLayout			pipelineLayout,
209 											 VkRenderPass				renderPass)			  -> Move<VkPipeline>;
210 	auto			createComputePipeline	(VkPipelineLayout			pipelineLayout)		  -> Move<VkPipeline>;
211 	auto			createImage				(VkImageUsageFlags			usage,
212 											 deUint32					queueFamilyIdx,
213 											 VkQueue					queue)			const -> de::MovePtr<ImageWithMemory>;
214 	auto			createView				(VkImage					image,
215 											 VkImageSubresourceRange&	range)			const -> Move<VkImageView>;
216 	void			submitCommands			(VkCommandBuffer			producerCmd,
217 											 VkCommandBuffer			consumerCmd)	const;
218 	bool			verify					(const BufferAccess&		result,
219 											 deUint32					blackColor,
220 											 deUint32					whiteColor)		const;
221 protected:
222 	auto createPipelineLayout			(const VkPushConstantRange*		pRange,
223 										 DSLayouts						setLayouts)		const -> Move<VkPipelineLayout>;
224 	const TestConfig		m_config;
225 	const SpecialDevice		m_device;
226 	Move<VkShaderModule>	m_vertex;
227 	Move<VkShaderModule>	m_fragment;
228 	Move<VkShaderModule>	m_compute;
229 };
GPQInstanceBase(Context& ctx, const TestConfig& cfg)230 GPQInstanceBase::GPQInstanceBase (Context& ctx, const TestConfig& cfg)
231 	: TestInstance	(ctx)
232 	, m_config		(cfg)
233 	, m_device		(ctx,
234 					 cfg.transitionFrom,	cfg.transitionTo,
235 					 cfg.priorityFrom,		cfg.priorityTo,
236 					 cfg.enableProtected,	cfg.enableSparseBinding)
237 	, m_vertex		()
238 	, m_fragment	()
239 	, m_compute		()
240 {
241 }
242 
createImage(VkImageUsageFlags usage, deUint32 queueFamilyIdx, VkQueue queue) const243 de::MovePtr<ImageWithMemory> GPQInstanceBase::createImage (VkImageUsageFlags usage, deUint32 queueFamilyIdx, VkQueue queue) const
244 {
245 	const InstanceInterface&	vki		= m_context.getInstanceInterface();
246 	const DeviceInterface&		vkd		= m_context.getDeviceInterface();
247 	const VkPhysicalDevice		phys	= m_context.getPhysicalDevice();
248 	const VkDevice				dev		= m_device.device;
249 	Allocator&					alloc	= m_device.getAllocator();
250 	VkImageCreateFlags			flags	= 0;
251 
252 	if (m_config.enableProtected)		flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
253 	if (m_config.enableSparseBinding)	flags |= (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT);
254 
255 	VkImageCreateInfo imageInfo{};
256 	imageInfo.sType					= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
257 	imageInfo.pNext					= nullptr;
258 	imageInfo.flags					= flags;
259 	imageInfo.imageType				= VK_IMAGE_TYPE_2D;
260 	imageInfo.format				= m_config.format;
261 	imageInfo.extent.width			= m_config.width;
262 	imageInfo.extent.height			= m_config.height;
263 	imageInfo.extent.depth			= 1;
264 	imageInfo.mipLevels				= 1;
265 	imageInfo.arrayLayers			= 1;
266 	imageInfo.samples				= VK_SAMPLE_COUNT_1_BIT;
267 	imageInfo.tiling				= VK_IMAGE_TILING_OPTIMAL;
268 	imageInfo.usage					= usage;
269 	imageInfo.sharingMode			= VK_SHARING_MODE_EXCLUSIVE;
270 	imageInfo.queueFamilyIndexCount	= 1;
271 	imageInfo.pQueueFamilyIndices	= &queueFamilyIdx;
272 	imageInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;
273 
274 	return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vki, vkd, phys, dev, alloc, imageInfo, queue));
275 }
276 
createView(VkImage image, VkImageSubresourceRange& range) const277 Move<VkImageView> GPQInstanceBase::createView	(VkImage image, VkImageSubresourceRange& range) const
278 {
279 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
280 	const VkDevice			dev		= m_device.device;
281 
282 	range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
283 	return makeImageView(vkd, dev, image, VK_IMAGE_VIEW_TYPE_2D, m_config.format, range);
284 }
285 
createPipelineLayout(const VkPushConstantRange* pRange, DSLayouts setLayouts) const286 Move<VkPipelineLayout>	GPQInstanceBase::createPipelineLayout (const VkPushConstantRange* pRange, DSLayouts setLayouts) const
287 {
288 	std::vector<VkDescriptorSetLayout>	layouts(setLayouts.size());
289 	auto ii = setLayouts.begin();
290 	for (auto i = ii; i != setLayouts.end(); ++i)
291 		layouts[std::distance(ii, i)] = *i;
292 
293 	VkPipelineLayoutCreateInfo		info{};
294 	info.sType					= VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
295 	info.pNext					= nullptr;
296 	info.flags					= VkPipelineLayoutCreateFlags(0);
297 	info.setLayoutCount			= static_cast<uint32_t>(layouts.size());
298 	info.pSetLayouts			= layouts.size() ? layouts.data() : nullptr;
299 	info.pushConstantRangeCount	= pRange ? 1 : 0;
300 	info.pPushConstantRanges	= pRange;
301 
302 	return ::vk::createPipelineLayout(m_context.getDeviceInterface(), m_device.device, &info);
303 }
304 
createPipelineLayout(DSLayouts setLayouts) const305 template<> Move<VkPipelineLayout> DE_UNUSED_FUNCTION GPQInstanceBase::createPipelineLayout<void> (DSLayouts setLayouts) const
306 {
307 	return createPipelineLayout(nullptr, setLayouts);
308 }
309 
createPipelineLayout(DSLayouts setLayouts) const310 template<class PushConstant> Move<VkPipelineLayout>	GPQInstanceBase::createPipelineLayout (DSLayouts setLayouts) const
311 {
312 	VkPushConstantRange	range{};
313 	range.stageFlags	= VK_SHADER_STAGE_ALL;
314 	range.offset		= 0;
315 	range.size			= static_cast<uint32_t>(sizeof(PushConstant));
316 	return createPipelineLayout(&range, setLayouts);
317 }
318 
createGraphicsPipeline(VkPipelineLayout pipelineLayout, VkRenderPass renderPass)319 Move<VkPipeline> GPQInstanceBase::createGraphicsPipeline (VkPipelineLayout pipelineLayout, VkRenderPass renderPass)
320 {
321 	const DeviceInterface&	vkd	= m_context.getDeviceInterface();
322 	const VkDevice			dev	= m_device.device;
323 
324 	m_vertex	= createShaderModule(vkd, dev, m_context.getBinaryCollection().get("vert"));
325 	m_fragment	= createShaderModule(vkd, dev, m_context.getBinaryCollection().get("frag"));
326 
327 	const std::vector<VkViewport>	viewports		{ makeViewport(m_config.width, m_config.height) };
328 	const std::vector<VkRect2D>		scissors		{ makeRect2D(m_config.width, m_config.height) };
329 	const auto						vertexBinding	= makeVertexInputBindingDescription(0u, static_cast<deUint32>(2 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX);
330 	const auto						vertexAttrib	= makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0u);
331 	const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
332 	{
333 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
334 		nullptr,														//	const void*									pNext;
335 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
336 		1u,																//	deUint32									vertexBindingDescriptionCount;
337 		&vertexBinding,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
338 		1u,																//	deUint32									vertexAttributeDescriptionCount;
339 		&vertexAttrib													//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
340 	};
341 
342 	return makeGraphicsPipeline(vkd, dev, pipelineLayout,*m_vertex,VkShaderModule(0),
343 						 VkShaderModule(0),VkShaderModule(0),*m_fragment,renderPass,viewports, scissors,
344 						 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,0,0,&vertexInputStateCreateInfo);
345 
346 
347 }
348 
createComputePipeline(VkPipelineLayout pipelineLayout)349 Move<VkPipeline> GPQInstanceBase::createComputePipeline	(VkPipelineLayout	pipelineLayout)
350 {
351 	const DeviceInterface&	vk	= m_context.getDeviceInterface();
352 	const VkDevice			dev	= m_device.device;
353 
354 	m_compute = createShaderModule(vk, dev, m_context.getBinaryCollection().get("comp"));
355 
356 	VkPipelineShaderStageCreateInfo	sci{};
357 	sci.sType				= VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
358 	sci.pNext				= nullptr;
359 	sci.flags				= VkPipelineShaderStageCreateFlags(0);
360 	sci.stage				= VK_SHADER_STAGE_COMPUTE_BIT;
361 	sci.module				= *m_compute;
362 	sci.pName				= "main";
363 	sci.pSpecializationInfo	= nullptr;
364 
365 	VkComputePipelineCreateInfo	ci{};
366 	ci.sType				= VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
367 	ci.pNext				= nullptr;
368 	ci.flags				= VkPipelineCreateFlags(0);
369 	ci.stage				= sci;
370 	ci.layout				= pipelineLayout;
371 	ci.basePipelineHandle	= VkPipeline(0);
372 	ci.basePipelineIndex	= 0;
373 
374 	return vk::createComputePipeline(vk, dev, VkPipelineCache(0), &ci, nullptr);
375 }
376 
377 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit);
submitCommands(VkCommandBuffer producerCmd, VkCommandBuffer consumerCmd) const378 void GPQInstanceBase::submitCommands (VkCommandBuffer producerCmd, VkCommandBuffer consumerCmd) const
379 {
380 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
381 	const VkDevice			dev		= m_device.device;
382 
383 	Move<VkSemaphore>		sem		= createSemaphore(vkd, dev);
384 	Move<VkFence>			fence	= createFence(vkd, dev);
385 
386 	const VkSubmitInfo		semSubmitProducer
387 	{
388 		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType				sType;
389 		nullptr,						// const void*					pNext;
390 		0,								// deUint32						waitSemaphoreCount;
391 		nullptr,						// const VkSemaphore*			pWaitSemaphores;
392 		nullptr,						// const VkPipelineStageFlags*	pWaitDstStageMask;
393 		1u,								// deUint32						commandBufferCount;
394 		&producerCmd,					// const VkCommandBuffer*		pCommandBuffers;
395 		1u,								// deUint32						signalSemaphoreCount;
396 		&sem.get(),						// const VkSemaphore*			pSignalSemaphores;
397 	};
398 
399 	const VkPipelineStageFlags	dstWaitStages = VK_PIPELINE_STAGE_TRANSFER_BIT |
400 											    queueFlagBitToPipelineStage(m_config.transitionTo);
401 	const VkSubmitInfo		semSubmitConsumer
402 	{
403 		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType				sType;
404 		nullptr,						// const void*					pNext;
405 		1u,								// deUint32						waitSemaphoreCount;
406 		&(*sem),						// const VkSemaphore*			pWaitSemaphores;
407 		&dstWaitStages,					// const VkPipelineStageFlags*	pWaitDstStageMask;
408 		1u,								// deUint32						commandBufferCount;
409 		&consumerCmd,					// const VkCommandBuffer*		pCommandBuffers;
410 		0,								// deUint32						signalSemaphoreCount;
411 		nullptr,						// const VkSemaphore*			pSignalSemaphores;
412 	};
413 
414 	switch (m_config.syncType)
415 	{
416 	case SyncType::None:
417 		submitCommandsAndWait(vkd, dev, m_device.queueFrom, producerCmd);
418 		submitCommandsAndWait(vkd, dev, m_device.queueTo, consumerCmd);
419 		break;
420 	case SyncType::Semaphore:
421 		VK_CHECK(vkd.queueSubmit(m_device.queueFrom, 1u, &semSubmitProducer, VkFence(0)));
422 		VK_CHECK(vkd.queueSubmit(m_device.queueTo, 1u, &semSubmitConsumer, *fence));
423 		VK_CHECK(vkd.waitForFences(dev, 1u, &fence.get(), DE_TRUE, ~0ull));
424 		break;
425 	}
426 }
427 
428 template<VkQueueFlagBits, VkQueueFlagBits> class GPQInstance;
429 #define DECLARE_INSTANCE(flagsFrom_, flagsTo_)									\
430 	template<> class GPQInstance<flagsFrom_, flagsTo_> : public GPQInstanceBase	\
431 	{	public:	GPQInstance (Context& ctx, const TestConfig& cfg)				\
432 					: GPQInstanceBase(ctx, cfg)	{ }								\
433 				virtual tcu::TestStatus	iterate (void) override;				}
434 
435 DECLARE_INSTANCE(VK_QUEUE_GRAPHICS_BIT,	VK_QUEUE_COMPUTE_BIT);
436 DECLARE_INSTANCE(VK_QUEUE_COMPUTE_BIT,	VK_QUEUE_GRAPHICS_BIT);
437 
438 class GPQCase;
439 typedef TestInstance* (GPQCase::* CreateInstanceProc)(Context&) const;
440 typedef std::pair<VkQueueFlagBits,VkQueueFlagBits> CreateInstanceKey;
441 typedef std::map<CreateInstanceKey, CreateInstanceProc> CreateInstanceMap;
442 #define MAPENTRY(from_,to_) m_createInstanceMap[{from_,to_}] = &GPQCase::createInstance<from_,to_>
443 
444 class GPQCase : public TestCase
445 {
446 public:
447 					GPQCase				(tcu::TestContext&	ctx,
448 										 const std::string&	name,
449 										 const TestConfig&	cfg,
450 										 const std::string&	desc = {});
451 	void			initPrograms		(SourceCollections&	programs)	const override;
452 	TestInstance*	createInstance		(Context&			context)	const override;
453 	void			checkSupport		(Context&			context)	const override;
454 	static deUint32	testValue;
455 
456 private:
457 	template<VkQueueFlagBits, VkQueueFlagBits>
458 		TestInstance*	createInstance	(Context&			context)	const;
459 	mutable TestConfig	m_config;
460 	CreateInstanceMap	m_createInstanceMap;
461 };
462 deUint32 GPQCase::testValue = 113;
463 
GPQCase(tcu::TestContext& ctx, const std::string& name, const TestConfig& cfg, const std::string& desc)464 GPQCase::GPQCase (tcu::TestContext&		ctx,
465 				  const std::string&	name,
466 				  const TestConfig&		cfg,
467 				  const std::string&	desc)
468 	: TestCase				(ctx, name, desc)
469 	, m_config				(cfg)
470 	, m_createInstanceMap	()
471 {
472 	MAPENTRY(VK_QUEUE_GRAPHICS_BIT,	VK_QUEUE_COMPUTE_BIT);
473 	MAPENTRY(VK_QUEUE_COMPUTE_BIT,	VK_QUEUE_GRAPHICS_BIT);
474 }
475 
queueFlagBitToPipelineStage(VkQueueFlagBits bit)476 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit)
477 {
478 	switch (bit) {
479 	case VK_QUEUE_COMPUTE_BIT:
480 		return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
481 	case VK_QUEUE_GRAPHICS_BIT:
482 		return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
483 	default:
484 		DE_ASSERT(VK_FALSE);
485 	}
486 	return VK_QUEUE_FLAG_BITS_MAX_ENUM;
487 }
488 
489 template<VkQueueFlagBits flagsFrom, VkQueueFlagBits flagsTo>
createInstance(Context& context) const490 TestInstance* GPQCase::createInstance (Context& context) const
491 {
492 	return new GPQInstance<flagsFrom, flagsTo>(context, m_config);
493 }
494 
createInstance(Context& context) const495 TestInstance* GPQCase::createInstance (Context& context) const
496 {
497 	const CreateInstanceKey	key(m_config.transitionFrom, m_config.transitionTo);
498 	return (this->*(m_createInstanceMap.at(key)))(context);
499 }
500 
operator <<(std::ostream& str, const VkQueueFlagBits& bit)501 std::ostream& operator<<(std::ostream& str, const VkQueueFlagBits& bit)
502 {
503 	const char* s = nullptr;
504 	const auto d = std::to_string(bit);
505 	switch (bit)
506 	{
507 		case VK_QUEUE_GRAPHICS_BIT:			s = "VK_QUEUE_GRAPHICS_BIT";		break;
508 		case VK_QUEUE_COMPUTE_BIT:			s = "VK_QUEUE_COMPUTE_BIT";			break;
509 		case VK_QUEUE_TRANSFER_BIT:			s = "VK_QUEUE_TRANSFER_BIT";		break;
510 		case VK_QUEUE_SPARSE_BINDING_BIT:	s = "VK_QUEUE_SPARSE_BINDING_BIT";	break;
511 		case VK_QUEUE_PROTECTED_BIT:		s = "VK_QUEUE_PROTECTED_BIT";		break;
512 		default:							s = d.c_str();						break;
513 	}
514 	return (str << s);
515 }
516 
checkSupport(Context& context) const517 void GPQCase::checkSupport (Context& context) const
518 {
519 	const InstanceInterface&	vki = context.getInstanceInterface();
520 	const VkPhysicalDevice		dev = context.getPhysicalDevice();
521 
522 	context.requireDeviceFunctionality("VK_EXT_global_priority");
523 
524 	if (!m_config.selectFormat(vki, dev, { VK_FORMAT_R32_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8_UINT }))
525 	{
526 		TCU_THROW(NotSupportedError, "Unable to find a proper format");
527 	}
528 
529 	VkPhysicalDeviceProtectedMemoryFeatures	memFeatures
530 	{
531 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
532 		nullptr,
533 		VK_FALSE
534 	};
535 	VkPhysicalDeviceFeatures2	devFeatures
536 	{
537 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
538 		&memFeatures,
539 		{}
540 	};
541 	vki.getPhysicalDeviceFeatures2(dev, &devFeatures);
542 
543 	if (m_config.enableProtected && (VK_FALSE == memFeatures.protectedMemory))
544 	{
545 		TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_PROTECTED_BIT not supported");
546 	}
547 
548 	const VkBool32 sparseEnabled = devFeatures.features.sparseBinding & devFeatures.features.sparseResidencyBuffer & devFeatures.features.sparseResidencyImage2D;
549 	if (m_config.enableSparseBinding && (VK_FALSE == sparseEnabled))
550 	{
551 		TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_SPARSE_BINDING_BIT not supported");
552 	}
553 
554 	auto assertUnavailableQueue = [](const deUint32 qIdx, VkQueueFlagBits qfb, VkQueueGlobalPriorityKHR qgp)
555 	{
556 		if (qIdx == INVALID_UINT32) {
557 			std::ostringstream buf;
558 			buf << "Unable to create a queue " << qfb << " with a priority " << qgp;
559 			buf.flush();
560 			TCU_THROW(NotSupportedError, buf.str());
561 		}
562 	};
563 
564 	const bool priorityQueryEnabled = context.isDeviceFunctionalitySupported("VK_EXT_global_priority_query");
565 
566 	VkQueueFlags	flagFrom	= m_config.transitionFrom;
567 	VkQueueFlags	flagTo		= m_config.transitionTo;
568 	if (m_config.enableProtected)
569 	{
570 		flagFrom |= VK_QUEUE_PROTECTED_BIT;
571 		flagTo	|= VK_QUEUE_PROTECTED_BIT;
572 	}
573 	if (m_config.enableSparseBinding)
574 	{
575 		flagFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
576 		flagTo	|= VK_QUEUE_SPARSE_BINDING_BIT;
577 	}
578 
579 	const deUint32 queueFromIndex	= findQueueFamilyIndex(vki, dev, flagFrom,
580 														   SpecialDevice::getColissionFlags(m_config.transitionFrom),
581 														   priorityQueryEnabled,
582 														   QueueGlobalPriorities({m_config.priorityFrom}));
583 	assertUnavailableQueue(queueFromIndex, m_config.transitionFrom, m_config.priorityFrom);
584 
585 	const deUint32 queueToIndex		= findQueueFamilyIndex(vki, dev, flagTo,
586 														   SpecialDevice::getColissionFlags(m_config.transitionTo),
587 														   priorityQueryEnabled,
588 														   QueueGlobalPriorities({m_config.priorityTo}));
589 	assertUnavailableQueue(queueToIndex, m_config.transitionTo, m_config.priorityTo);
590 
591 	if (queueFromIndex == queueToIndex)
592 	{
593 		std::ostringstream buf;
594 		buf << "Unable to find separate queues " << m_config.transitionFrom << " and " << m_config.transitionTo;
595 		buf.flush();
596 		TCU_THROW(NotSupportedError, buf.str());
597 	}
598 }
599 
getShaderImageBufferType(const tcu::TextureFormat& format)600 std::string getShaderImageBufferType (const tcu::TextureFormat& format)
601 {
602 	return image::getFormatPrefix(format) + "imageBuffer";
603 }
604 
initPrograms(SourceCollections& programs) const605 void GPQCase::initPrograms (SourceCollections& programs) const
606 {
607 	const std::string producerComp(R"glsl(
608 	#version 450
609 	layout(std430, push_constant) uniform PC
610 		{ uint width, height; } pc;
611 	struct Index { uint k; };
612 	struct Quad { vec2 c[4]; };
613 	layout(set=0, binding=0) buffer Quads
614 		{ Quad data[]; } quads;
615 	layout(set=0, binding=1) buffer Indices
616 		{ Index data[]; } indices;
617 	uint fieldCount (uint w, uint h) {
618 		return ((w+1)/2)*((h+1)/2)+(w/2)*(h/2);
619 	}
620 	uint fieldIndex () {
621 		return	fieldCount(pc.width, gl_GlobalInvocationID.y) + (gl_GlobalInvocationID.x / 2);
622 	}
623 	void main() {
624 		float x1 = float(gl_GlobalInvocationID.x) / float(pc.width);
625 		float y1 = float(gl_GlobalInvocationID.y) / float(pc.height);
626 		float x2 = (float(gl_GlobalInvocationID.x) + 1.0) / float(pc.width);
627 		float y2 = (float(gl_GlobalInvocationID.y) + 1.0) / float(pc.height);
628 
629 		float xx1 = x1 * 2.0 - 1.0;
630 		float yy1 = y1 * 2.0 - 1.0;
631 		float xx2 = x2 * 2.0 - 1.0;
632 		float yy2 = y2 * 2.0 - 1.0;
633 
634 		if (((gl_GlobalInvocationID.x + gl_GlobalInvocationID.y) % 2) == 0)
635 		{
636 			uint at = fieldIndex();
637 
638 			if (gl_GlobalInvocationID.z == 0)
639 			{
640 				quads.data[at].c[0] = vec2(xx1, yy1);
641 				quads.data[at].c[1] = vec2(xx2, yy1);
642 				indices.data[at*6+0].k = at * 4 + 0;
643 				indices.data[at*6+1].k = at * 4 + 1;
644 				indices.data[at*6+2].k = at * 4 + 2;
645 			}
646 			else
647 			{
648 				quads.data[at].c[2] = vec2(xx2, yy2);
649 				quads.data[at].c[3] = vec2(xx1, yy2);
650 				indices.data[at*6+3].k = at * 4 + 2;
651 				indices.data[at*6+4].k = at * 4 + 3;
652 				indices.data[at*6+5].k = at * 4 + 0;
653 			}
654 		}
655 	}
656 	)glsl");
657 
658 	const tcu::StringTemplate consumerComp(R"glsl(
659 	#version 450
660 	layout(std430, push_constant) uniform PC
661 		{ uint width, height; } pc;
662 	struct Pixel { uint k; };
663 	layout(${IMAGE_FORMAT}, set=0, binding=0) readonly uniform ${IMAGE_TYPE} srcImage;
664 	layout(binding=1) writeonly coherent buffer Pixels { Pixel data[]; } pixels;
665 	void main()
666 	{
667 		ivec2 pos2 = ivec2(gl_GlobalInvocationID.xy);
668 		int   pos1 = int(gl_GlobalInvocationID.y * pc.width + gl_GlobalInvocationID.x);
669 		pixels.data[pos1].k = uint(imageLoad(srcImage, pos2).r) + 1;
670 	}
671 	)glsl");
672 
673 	const std::string vert(R"glsl(
674 	#version 450
675 	layout(location = 0) in vec2 pos;
676 	void main()
677 	{
678 	   gl_Position = vec4(pos, 0, 1);
679 	}
680 	)glsl");
681 
682 	const tcu::StringTemplate frag(R"glsl(
683 	#version 450
684 	layout(location = 0) out ${COLOR_TYPE} color;
685 	void main()
686 	{
687 	   color = ${COLOR_TYPE}(${TEST_VALUE},0,0,1);
688 	}
689 	)glsl");
690 
691 	const auto format		= mapVkFormat(m_config.format);
692 	const auto imageFormat	= image::getShaderImageFormatQualifier(format);
693 	const auto imageType	= image::getShaderImageType(format, image::ImageType::IMAGE_TYPE_2D, false);
694 	const auto imageBuffer	= getShaderImageBufferType(format);
695 	const auto colorType	= image::getGlslAttachmentType(m_config.format); // ivec4
696 
697 	const std::map<std::string, std::string>	abbreviations
698 	{
699 		{ std::string("TEST_VALUE"),	std::to_string(testValue)	},
700 		{ std::string("IMAGE_FORMAT"),	std::string(imageFormat)	},
701 		{ std::string("IMAGE_TYPE"),	std::string(imageType)		},
702 		{ std::string("IMAGE_BUFFER"),	std::string(imageBuffer)	},
703 		{ std::string("COLOR_TYPE"),	std::string(colorType)		},
704 	};
705 
706 	programs.glslSources.add("comp") << glu::ComputeSource(
707 											m_config.transitionFrom == VK_QUEUE_COMPUTE_BIT
708 												? producerComp
709 												: consumerComp.specialize(abbreviations));
710 	programs.glslSources.add("vert") << glu::VertexSource(vert);
711 	programs.glslSources.add("frag") << glu::FragmentSource(frag.specialize(abbreviations));
712 }
713 
714 
iterate(void)715 tcu::TestStatus	GPQInstance<VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT>::iterate (void)
716 {
717 	VkResult						deviceStatus		= VK_SUCCESS;
718 	if (!m_device.isValid(deviceStatus))
719 	{
720 		if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus)
721 			return tcu::TestStatus::pass(getResultName(deviceStatus));
722 		TCU_CHECK(deviceStatus);
723 	}
724 
725 	const InstanceInterface&		vki					= m_context.getInstanceInterface();
726 	const DeviceInterface&			vkd					= m_context.getDeviceInterface();
727 	const VkPhysicalDevice			phys				= m_context.getPhysicalDevice();
728 	const VkDevice					device				= m_device.device;
729 	Allocator&						allocator			= m_device.getAllocator();
730 	const deUint32					producerIndex		= m_device.queueFamilyIndexFrom;
731 	const deUint32					consumerIndex		= m_device.queueFamilyIndexTo;
732 	const VkQueue					producerQueue		= m_device.queueFrom;	DE_UNREF(producerQueue);
733 	const VkQueue					consumerQueue		= m_device.queueTo;		DE_UNREF(consumerQueue);
734 
735 	const uint32_t					width				= m_config.width;
736 	const uint32_t					height				= m_config.height;
737 	const uint32_t					clearComp			= 97;
738 	const VkClearValue				clearColor			= makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
739 	const uint32_t					quadCount			= CheckerboardBuilder::blackFieldCount(width, height);
740 	const uint32_t					vertexCount			= 4 * quadCount;
741 	const uint32_t					indexCount			= 6 * quadCount;
742 	const MemoryRequirement			memReqs				= (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any);
743 
744 	VkBufferCreateFlags				buffsCreateFlags	= 0;
745 	if (m_config.enableProtected)	buffsCreateFlags	|= VK_BUFFER_CREATE_PROTECTED_BIT;
746 	if (m_config.enableSparseBinding) buffsCreateFlags	|= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
747 	const VkBufferUsageFlags		vertBuffUsage		= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
748 	const VkBufferUsageFlags		indexBuffUsage		= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
749 	const VkDeviceSize				vertBuffSize		= vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize();
750 	const VkDeviceSize				indexBuffSize		= indexCount * sizeof(uint32_t);
751 	const VkDeviceSize				resultBuffSize		= (width * height * mapVkFormat(m_config.format).getPixelSize());
752 	const VkBufferCreateInfo		vertBuffInfo		= makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, buffsCreateFlags);
753 	const VkBufferCreateInfo		indexBuffInfo		= makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, buffsCreateFlags);
754 	const VkBufferCreateInfo		resultBuffInfo		= makeBufferCreateInfo(resultBuffSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
755 	BufferWithMemory				vertexBuffer		(vki, vkd, phys, device, allocator, vertBuffInfo, memReqs, producerQueue);
756 	BufferWithMemory				indexBuffer			(vki, vkd, phys, device, allocator, indexBuffInfo, memReqs, producerQueue);
757 	BufferWithMemory				resultBuffer		(vki, vkd, phys, device, allocator, resultBuffInfo, MemoryRequirement::HostVisible);
758 
759 	const VkDescriptorBufferInfo	dsVertInfo			= makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertBuffSize);
760 	const VkDescriptorBufferInfo	dsIndexInfo			= makeDescriptorBufferInfo(indexBuffer.get(), 0ull, indexBuffSize);
761 	Move<VkDescriptorPool>			dsPool				= DescriptorPoolBuilder()
762 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
763 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
764 															.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
765 	Move<VkDescriptorSetLayout>		dsLayout			= DescriptorSetLayoutBuilder()
766 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
767 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
768 															.build(vkd, device);
769 	Move<VkDescriptorSet>			descriptorSet		= makeDescriptorSet(vkd, device, *dsPool, *dsLayout);
770 	DescriptorSetUpdateBuilder()
771 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsVertInfo)
772 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsIndexInfo)
773 		.update(vkd, device);
774 
775 	VkImageSubresourceRange			colorResourceRange	{};
776 	const VkImageUsageFlags			imageUsage			= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
777 	de::MovePtr<ImageWithMemory>	image				= this->createImage(imageUsage, consumerIndex, consumerQueue);
778 	Move<VkImageView>				view				= createView(**image, colorResourceRange);
779 	Move<VkRenderPass>				renderPass			= makeRenderPass(vkd, device, m_config.format);
780 	Move<VkFramebuffer>				framebuffer			= makeFramebuffer(vkd, device, *renderPass, *view, width, height);
781 	const VkImageMemoryBarrier		colorReadyBarrier	= makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
782 															VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
783 															**image, colorResourceRange);
784 	const VkBufferImageCopy			colorCopyRegion		= makeBufferImageCopy(makeExtent3D(width, height, 1),
785 																			  makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
786 	const VkMemoryBarrier			resultReadyBarrier	= makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
787 	struct PushConstant
788 	{ uint32_t width, height; }		pc					{ width, height };
789 	Move<VkPipelineLayout>			pipelineLayout		= createPipelineLayout<PushConstant>({ *dsLayout });
790 	Move<VkPipeline>				producerPipeline	= createComputePipeline(*pipelineLayout);
791 	Move<VkPipeline>				consumerPipeline	= createGraphicsPipeline(*pipelineLayout, *renderPass);
792 
793 	Move<VkCommandPool>				producerPool		= makeCommandPool(vkd, device, producerIndex);
794 	Move<VkCommandPool>				consumerPool		= makeCommandPool(vkd, device, consumerIndex);
795 	Move<VkCommandBuffer>			producerCmd			= allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
796 	Move<VkCommandBuffer>			consumerCmd			= allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
797 
798 	beginCommandBuffer(vkd, *producerCmd);
799 		vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &(*descriptorSet), 0, nullptr);
800 		vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerPipeline);
801 		vkd.cmdPushConstants(*producerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc);
802 		vkd.cmdDispatch(*producerCmd, width, height, 2);
803 	endCommandBuffer(vkd, *producerCmd);
804 
805 	beginCommandBuffer(vkd, *consumerCmd);
806 		vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerPipeline);
807 		vkd.cmdBindIndexBuffer(*consumerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32);
808 		vkd.cmdBindVertexBuffers(*consumerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0));
809 		beginRenderPass(vkd, *consumerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor);
810 			vkd.cmdDrawIndexed(*consumerCmd, indexCount, 1, 0, 0, 0);
811 		endRenderPass(vkd, *consumerCmd);
812 		vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorReadyBarrier);
813 		vkd.cmdCopyImageToBuffer(*consumerCmd, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *resultBuffer, 1u, &colorCopyRegion);
814 		vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &resultReadyBarrier, 0u, nullptr, 0u, nullptr);
815 	endCommandBuffer(vkd, *consumerCmd);
816 
817 	submitCommands(*producerCmd, *consumerCmd);
818 
819 	resultBuffer.invalidateAlloc(vkd, device);
820 	const tcu::ConstPixelBufferAccess	resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, resultBuffer.getHostPtr());
821 
822 	return verify(resultBufferAccess, GPQCase::testValue, clearComp) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
823 }
824 
iterate(void)825 tcu::TestStatus	GPQInstance<VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT>::iterate (void)
826 {
827 	VkResult						deviceStatus		= VK_SUCCESS;
828 	if (!m_device.isValid(deviceStatus))
829 	{
830 		if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus)
831 			return tcu::TestStatus::pass(getResultName(deviceStatus));
832 		TCU_CHECK(deviceStatus);
833 	}
834 
835 	const InstanceInterface&		vki					= m_context.getInstanceInterface();
836 	const DeviceInterface&			vkd					= m_context.getDeviceInterface();
837 	const VkPhysicalDevice			phys				= m_context.getPhysicalDevice();
838 	const VkDevice					device				= m_device.device;
839 	Allocator&						allocator			= m_device.getAllocator();
840 	const deUint32					producerIndex		= m_device.queueFamilyIndexFrom;
841 	const deUint32					consumerIndex		= m_device.queueFamilyIndexTo;
842 	const VkQueue					producerQueue		= m_device.queueFrom;	DE_UNREF(producerQueue);
843 	const VkQueue					consumerQueue		= m_device.queueTo;		DE_UNREF(consumerQueue);
844 
845 	const uint32_t					width				= m_config.width;
846 	const uint32_t					height				= m_config.height;
847 	const uint32_t					clearComp			= GPQCase::testValue - 11;
848 	const VkClearValue				clearColor			= makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
849 	const uint32_t					quadCount			= CheckerboardBuilder::blackFieldCount(width, height);
850 	const uint32_t					vertexCount			= 4 * quadCount;
851 	const uint32_t					indexCount			= 6 * quadCount;
852 
853 	const VkBufferCreateFlags		graphCreateFlags	= 0;
854 	const MemoryRequirement			graphBuffsMemReqs	= (MemoryRequirement::HostVisible);
855 
856 	const VkBufferUsageFlags		vertBuffUsage		= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
857 	const VkDeviceSize				vertBuffSize		= vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize();
858 	const VkBufferCreateInfo		vertBuffInfo		= makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, graphCreateFlags);
859 	BufferWithMemory				vertexBuffer		(vki, vkd, phys, device, allocator, vertBuffInfo, graphBuffsMemReqs, producerQueue);
860 
861 	const VkBufferUsageFlags		indexBuffUsage		= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
862 	const VkDeviceSize				indexBuffSize		= indexCount * sizeof(uint32_t);
863 	const VkBufferCreateInfo		indexBuffInfo		= makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, graphCreateFlags);
864 	BufferWithMemory				indexBuffer			(vki, vkd, phys, device, allocator, indexBuffInfo, graphBuffsMemReqs, producerQueue);
865 
866 	VkImageSubresourceRange			producerResRange	{};
867 	const VkImageUsageFlags			producerUsage		= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
868 	de::MovePtr<ImageWithMemory>	producerImage		= this->createImage(producerUsage, producerIndex, producerQueue);
869 	Move<VkImageView>				producerView		= createView(**producerImage, producerResRange);
870 	const VkDescriptorImageInfo		producerImageInfo	= makeDescriptorImageInfo(VkSampler(0), *producerView, VK_IMAGE_LAYOUT_GENERAL);
871 
872 	const VkBufferCreateFlags		consumerCreateFlags	= graphCreateFlags;
873 	const MemoryRequirement			consumerMemReqs		= MemoryRequirement::HostVisible | MemoryRequirement::Coherent;
874 	const VkBufferUsageFlags		consumerUsage		= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
875 	const VkDeviceSize				consumerBuffSize	= (width * height * sizeof(uint32_t));
876 	const VkBufferCreateInfo		consumerBuffInfo	= makeBufferCreateInfo(consumerBuffSize, consumerUsage, {consumerIndex}, consumerCreateFlags);
877 	BufferWithMemory				consumerBuffer		(vki, vkd, phys, device, allocator, consumerBuffInfo, consumerMemReqs, consumerQueue);
878 	const VkDescriptorBufferInfo	consumerInfo		= makeDescriptorBufferInfo(*consumerBuffer, 0, consumerBuffSize);
879 
880 	const VkBufferCreateFlags		tmpCreateFlags		= graphCreateFlags;
881 	const MemoryRequirement			tmpMemReqs			= MemoryRequirement::HostVisible | MemoryRequirement::Coherent;
882 	const VkBufferUsageFlags		tmpUsage			= (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
883 	const VkDeviceSize				tmpBuffSize			= (width * height * sizeof(uint32_t));
884 	const VkBufferCreateInfo		tmpBuffInfo			= makeBufferCreateInfo(tmpBuffSize, tmpUsage, {consumerIndex}, tmpCreateFlags);
885 	BufferWithMemory				tmpBuffer			(vki, vkd, phys, device, allocator, tmpBuffInfo, tmpMemReqs, consumerQueue);
886 	const VkBufferImageCopy			tmpCopyRegion		= makeBufferImageCopy(makeExtent3D(width, height, 1),
887 																			  makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
888 
889 	Move<VkDescriptorPool>			dsPool				= DescriptorPoolBuilder()
890 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
891 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
892 															.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
893 	Move<VkDescriptorSetLayout>		dsLayout			= DescriptorSetLayoutBuilder()
894 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL)
895 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
896 															.build(vkd, device);
897 	Move<VkDescriptorSet>			descriptorSet		= makeDescriptorSet(vkd, device, *dsPool, *dsLayout);
898 
899 	DescriptorSetUpdateBuilder()
900 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &producerImageInfo)
901 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &consumerInfo)
902 		.update(vkd, device);
903 
904 	Move<VkRenderPass>				renderPass			= makeRenderPass(vkd, device, m_config.format);
905 	Move<VkFramebuffer>				framebuffer			= makeFramebuffer(vkd, device, *renderPass, *producerView, width, height);
906 
907 	const VkImageMemoryBarrier		producerReadyBarrier= makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
908 															VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
909 															**producerImage, producerResRange);
910 //	const VkBufferMemoryBarrier		consumerReadyBarrier= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
911 //																				  *consumerBuffer, 0, consumerBuffSize,
912 //																				  consumerIndex, consumerIndex);
913 	//const VkMemoryBarrier			tmpReadyBarrier		= makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
914 //	const VkBufferMemoryBarrier		tmpReadyBarrier		= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
915 //																				  *tmpBuffer, 0, tmpBuffSize,
916 //																				  consumerIndex, consumerIndex);
917 	const VkBufferMemoryBarrier		consumerBarriers[]	{	makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
918 																					*consumerBuffer, 0, consumerBuffSize,
919 																					consumerIndex, consumerIndex),
920 															makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
921 																					*tmpBuffer, 0, tmpBuffSize,
922 																					consumerIndex, consumerIndex) };
923 	struct PushConstant
924 	{ uint32_t width, height; }		pc					{ width, height };
925 	Move<VkPipelineLayout>			pipelineLayout		= createPipelineLayout<PushConstant>({ *dsLayout });
926 	Move<VkPipeline>				producerPipeline	= createGraphicsPipeline(*pipelineLayout, *renderPass);
927 	Move<VkPipeline>				consumerPipeline	= createComputePipeline(*pipelineLayout);
928 
929 	Move<VkCommandPool>				producerPool		= makeCommandPool(vkd, device, producerIndex);
930 	Move<VkCommandPool>				consumerPool		= makeCommandPool(vkd, device, consumerIndex);
931 	Move<VkCommandBuffer>			producerCmd			= allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
932 	Move<VkCommandBuffer>			consumerCmd			= allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
933 
934 	{
935 		std::vector<float>		vertices;
936 		std::vector<uint32_t>	indices;
937 		CheckerboardBuilder	builder(width, height);
938 		builder.buildVerticesAndIndices(vertices, indices);
939 		DE_ASSERT(vertices.size() == (vertexCount * 2));
940 		DE_ASSERT(indices.size() == indexCount);
941 		std::copy(vertices.begin(), vertices.end(), begin<float>(vertexBuffer.getHostPtr()));
942 		std::copy(indices.begin(), indices.end(), begin<uint32_t>(indexBuffer.getHostPtr()));
943 		vertexBuffer.flushAlloc(vkd, device);
944 		indexBuffer.flushAlloc(vkd, device);
945 	}
946 
947 	beginCommandBuffer(vkd, *producerCmd);
948 		vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *producerPipeline);
949 		vkd.cmdBindVertexBuffers(*producerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0));
950 		vkd.cmdBindIndexBuffer(*producerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32);
951 		beginRenderPass(vkd, *producerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor);
952 			vkd.cmdDrawIndexed(*producerCmd, indexCount, 1, 0, 0, 0);
953 		endRenderPass(vkd, *producerCmd);
954 		vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VkDependencyFlags(0),
955 							   0u, nullptr, 0u, nullptr, 1u, &producerReadyBarrier);
956 	endCommandBuffer(vkd, *producerCmd);
957 
958 	beginCommandBuffer(vkd, *consumerCmd);
959 		vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerPipeline);
960 		vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, nullptr);
961 		vkd.cmdCopyImageToBuffer(*consumerCmd, **producerImage, VK_IMAGE_LAYOUT_GENERAL, *tmpBuffer, 1u, &tmpCopyRegion);
962 		vkd.cmdPushConstants(*consumerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc);
963 		vkd.cmdDispatch(*consumerCmd, width, height, 1);
964 		vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkDependencyFlags(0),
965 							   0, nullptr, DE_LENGTH_OF_ARRAY(consumerBarriers), consumerBarriers, 0, nullptr);
966 	endCommandBuffer(vkd, *consumerCmd);
967 
968 	submitCommands(*producerCmd, *consumerCmd);
969 
970 	tmpBuffer.invalidateAlloc(vkd, device);
971 	const tcu::ConstPixelBufferAccess	tmpBufferAccess(mapVkFormat(m_config.format), width, height, 1, tmpBuffer.getHostPtr());
972 	const bool tmpRes = verify(tmpBufferAccess, GPQCase::testValue, clearComp);
973 
974 	consumerBuffer.invalidateAlloc(vkd, device);
975 	const tcu::ConstPixelBufferAccess	resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, consumerBuffer.getHostPtr());
976 
977 	return (tmpRes && verify(resultBufferAccess, (GPQCase::testValue + 1), (clearComp + 1))) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
978 }
979 
verify(const BufferAccess& result, deUint32 blackColor, deUint32 whiteColor) const980 bool GPQInstanceBase::verify (const BufferAccess& result, deUint32 blackColor, deUint32 whiteColor) const
981 {
982 	bool ok = true;
983 
984 	for (deUint32 y = 0; ok && y < m_config.height; ++y)
985 	{
986 		for (deUint32 x = 0; ok && x < m_config.width; ++x)
987 		{
988 			const deUint32 color = result.getPixelT<deUint32>(x, y).x();
989 			if (((x + y) % 2) == 0)
990 			{
991 				ok = color == blackColor;
992 			}
993 			else
994 			{
995 				ok = color == whiteColor;
996 			}
997 		}
998 	}
999 	return ok;
1000 }
1001 
1002 } // anonymous
1003 
createGlobalPriorityQueueTests(tcu::TestContext& testCtx)1004 tcu::TestCaseGroup* createGlobalPriorityQueueTests (tcu::TestContext& testCtx)
1005 {
1006 	typedef std::pair<VkQueueFlagBits, const char*> TransitionItem;
1007 	TransitionItem const transitions[]
1008 	{
1009 		{ VK_QUEUE_GRAPHICS_BIT,	"graphics"	},
1010 		{ VK_QUEUE_COMPUTE_BIT,		"compute"	},
1011 	};
1012 
1013 	auto mkGroupName = [](const TransitionItem& from, const TransitionItem& to) -> std::string
1014 	{
1015 		return std::string("from_") + from.second + std::string("_to_") + to.second;
1016 	};
1017 
1018 	std::pair<VkQueueFlags, const char*>
1019 			const modifiers[]
1020 	{
1021 		{ 0,													"no_modifiers"		},
1022 		{ VK_QUEUE_SPARSE_BINDING_BIT,							"sparse"			},
1023 		{ VK_QUEUE_PROTECTED_BIT,								"protected"			},
1024 		{ VK_QUEUE_SPARSE_BINDING_BIT|VK_QUEUE_PROTECTED_BIT,	"sparse_protected"	},
1025 	};
1026 
1027 	std::pair<VkQueueGlobalPriorityKHR, const char*>
1028 			const prios[]
1029 	{
1030 		{ VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR,			"low"		},
1031 		{ VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR,		"medium"	},
1032 		{ VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR,		"high"		},
1033 		{ VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR,	"realtime"	},
1034 	};
1035 
1036 	std::pair<SyncType, const char*>
1037 			const syncs[]
1038 	{
1039 		{ SyncType::None,		"no_sync"	},
1040 		{ SyncType::Semaphore,	"semaphore"	},
1041 	};
1042 
1043 	const uint32_t	dim0	= 34;
1044 	const uint32_t	dim1	= 25;
1045 	bool			swap	= true;
1046 
1047 	auto rootGroup = new tcu::TestCaseGroup(testCtx, "global_priority_transition", "Global Priority Queue Tests");
1048 
1049 	for (const auto& prio : prios)
1050 	{
1051 		auto prioGroup = new tcu::TestCaseGroup(testCtx, prio.second, "");
1052 
1053 		for (const auto& sync : syncs)
1054 		{
1055 			auto syncGroup = new tcu::TestCaseGroup(testCtx, sync.second, "");
1056 
1057 			for (const auto& mod : modifiers)
1058 			{
1059 				auto modGroup = new tcu::TestCaseGroup(testCtx, mod.second, "");
1060 
1061 				for (const auto& transitionFrom : transitions)
1062 				{
1063 					for (const auto& transitionTo : transitions)
1064 					{
1065 						if (transitionFrom != transitionTo)
1066 						{
1067 							TestConfig	cfg{};
1068 							cfg.transitionFrom		= transitionFrom.first;
1069 							cfg.transitionTo		= transitionTo.first;
1070 							cfg.priorityFrom		= prio.first;
1071 							cfg.priorityTo			= prio.first;
1072 							cfg.syncType			= sync.first;
1073 							cfg.enableProtected		= (mod.first & VK_QUEUE_PROTECTED_BIT) != 0;
1074 							cfg.enableSparseBinding	= (mod.first & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
1075 							// Note that format is changing in GPQCase::checkSupport(...)
1076 							cfg.format				= VK_FORMAT_R32G32B32A32_SFLOAT;
1077 							cfg.width				= swap ? dim0 : dim1;
1078 							cfg.height				= swap ? dim1 : dim0;
1079 
1080 							swap ^= true;
1081 
1082 							modGroup->addChild(new GPQCase(testCtx, mkGroupName(transitionFrom, transitionTo), cfg));
1083 						}
1084 					}
1085 				}
1086 				syncGroup->addChild(modGroup);
1087 			}
1088 			prioGroup->addChild(syncGroup);
1089 		}
1090 		rootGroup->addChild(prioGroup);
1091 	}
1092 
1093 	return rootGroup;
1094 }
1095 
1096 } // synchronization
1097 } // vkt
1098