1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 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
21 * \brief Synchronization tests for resources shared between instances.
22 *//*--------------------------------------------------------------------*/
23
24#include "vktSynchronizationCrossInstanceSharingTests.hpp"
25
26#include "vkDeviceUtil.hpp"
27#include "vkPlatform.hpp"
28#include "vkBarrierUtil.hpp"
29#include "vkCmdUtil.hpp"
30#include "vktTestCaseUtil.hpp"
31#include "deSharedPtr.hpp"
32
33#include "vktSynchronizationUtil.hpp"
34#include "vktSynchronizationOperation.hpp"
35#include "vktSynchronizationOperationTestData.hpp"
36#include "vktSynchronizationOperationResources.hpp"
37#include "vktExternalMemoryUtil.hpp"
38#include "vktTestGroupUtil.hpp"
39#include "vktCustomInstancesDevices.hpp"
40
41#include "deRandom.hpp"
42
43#include "tcuResultCollector.hpp"
44#include "tcuTestLog.hpp"
45#include "tcuCommandLine.hpp"
46
47using tcu::TestLog;
48using namespace vkt::ExternalMemoryUtil;
49
50namespace vkt
51{
52namespace synchronization
53{
54namespace
55{
56using namespace vk;
57using de::SharedPtr;
58
59struct TestConfig
60{
61								TestConfig		(SynchronizationType							type_,
62												 const ResourceDescription&						resource_,
63												 vk::VkSemaphoreType							semaphoreType_,
64												 OperationName									writeOp_,
65												 OperationName									readOp_,
66												 vk::VkExternalMemoryHandleTypeFlagBits			memoryHandleType_,
67												 vk::VkExternalSemaphoreHandleTypeFlagBits		semaphoreHandleType_,
68												 bool											dedicated_)
69		: type					(type_)
70		, resource				(resource_)
71		, semaphoreType			(semaphoreType_)
72		, writeOp				(writeOp_)
73		, readOp				(readOp_)
74		, memoryHandleType		(memoryHandleType_)
75		, semaphoreHandleType	(semaphoreHandleType_)
76		, dedicated				(dedicated_)
77	{
78	}
79
80	const SynchronizationType							type;
81	const ResourceDescription							resource;
82	const vk::VkSemaphoreType							semaphoreType;
83	const OperationName									writeOp;
84	const OperationName									readOp;
85	const vk::VkExternalMemoryHandleTypeFlagBits		memoryHandleType;
86	const vk::VkExternalSemaphoreHandleTypeFlagBits		semaphoreHandleType;
87	const bool											dedicated;
88};
89
90// A helper class to test for extensions upfront and throw not supported to speed up test runtimes compared to failing only
91// after creating unnecessary vkInstances.  A common example of this is win32 platforms taking a long time to run _fd tests.
92class NotSupportedChecker
93{
94public:
95				NotSupportedChecker	(const Context&			 context,
96									 TestConfig				 config,
97									 const OperationSupport& writeOp,
98									 const OperationSupport& readOp)
99	: m_context	(context)
100	{
101		// Check instance support
102		m_context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
103
104		m_context.requireInstanceFunctionality("VK_KHR_external_semaphore_capabilities");
105		m_context.requireInstanceFunctionality("VK_KHR_external_memory_capabilities");
106
107		// Check device support
108		if (config.dedicated)
109			m_context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
110
111		m_context.requireDeviceFunctionality("VK_KHR_external_semaphore");
112		m_context.requireDeviceFunctionality("VK_KHR_external_memory");
113
114		if (config.semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE)
115			m_context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
116
117		if (config.type == SynchronizationType::SYNCHRONIZATION2)
118			m_context.requireDeviceFunctionality("VK_KHR_synchronization2");
119
120		if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
121			|| config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR
122			|| config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR)
123		{
124			m_context.requireDeviceFunctionality("VK_KHR_external_semaphore_fd");
125			m_context.requireDeviceFunctionality("VK_KHR_external_memory_fd");
126		}
127
128		if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)
129		{
130			m_context.requireDeviceFunctionality("VK_EXT_external_memory_dma_buf");
131		}
132
133		if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
134			|| config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
135			|| config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
136			|| config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
137		{
138			m_context.requireDeviceFunctionality("VK_KHR_external_semaphore_win32");
139			m_context.requireDeviceFunctionality("VK_KHR_external_memory_win32");
140		}
141
142		if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA
143			|| config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA)
144		{
145			m_context.requireDeviceFunctionality("VK_FUCHSIA_external_semaphore");
146			m_context.requireDeviceFunctionality("VK_FUCHSIA_external_memory");
147		}
148
149		TestLog&						log				= context.getTestContext().getLog();
150		const vk::InstanceInterface&	vki				= context.getInstanceInterface();
151		const vk::VkPhysicalDevice		physicalDevice	= context.getPhysicalDevice();
152
153		// Check resource support
154		if (config.resource.type == RESOURCE_TYPE_IMAGE)
155		{
156			const vk::VkPhysicalDeviceExternalImageFormatInfo	externalInfo		=
157			{
158				vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
159				DE_NULL,
160				config.memoryHandleType
161			};
162			const vk::VkPhysicalDeviceImageFormatInfo2			imageFormatInfo		=
163			{
164				vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
165				&externalInfo,
166				config.resource.imageFormat,
167				config.resource.imageType,
168				vk::VK_IMAGE_TILING_OPTIMAL,
169				readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
170				0u
171			};
172			vk::VkExternalImageFormatProperties				externalProperties	=
173			{
174				vk::VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
175				DE_NULL,
176				{ 0u, 0u, 0u }
177			};
178			vk::VkImageFormatProperties2					formatProperties	=
179			{
180				vk::VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
181				&externalProperties,
182				{
183					{ 0u, 0u, 0u },
184					0u,
185					0u,
186					0u,
187					0u,
188				}
189			};
190
191			{
192				const vk::VkResult res = vki.getPhysicalDeviceImageFormatProperties2(physicalDevice, &imageFormatInfo, &formatProperties);
193
194				if (res == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
195					TCU_THROW(NotSupportedError, "Image format not supported");
196
197				VK_CHECK(res); // Check other errors
198			}
199
200			log << TestLog::Message << "External image format properties: " << imageFormatInfo << "\n"<< externalProperties << TestLog::EndMessage;
201
202			if ((externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) == 0)
203				TCU_THROW(NotSupportedError, "Exporting image resource not supported");
204
205			if ((externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0)
206				TCU_THROW(NotSupportedError, "Importing image resource not supported");
207
208			if (!config.dedicated && (externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT) != 0)
209			{
210				TCU_THROW(NotSupportedError, "Handle requires dedicated allocation, but test uses suballocated memory");
211			}
212
213			if (!(formatProperties.imageFormatProperties.sampleCounts & config.resource.imageSamples)) {
214				TCU_THROW(NotSupportedError, "Specified sample count for format not supported");
215			}
216
217		}
218		else
219		{
220			const vk::VkPhysicalDeviceExternalBufferInfo	info	=
221			{
222				vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO,
223				DE_NULL,
224
225				0u,
226				readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
227				config.memoryHandleType
228			};
229			vk::VkExternalBufferProperties					properties			=
230			{
231				vk::VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES,
232				DE_NULL,
233				{ 0u, 0u, 0u}
234			};
235			vki.getPhysicalDeviceExternalBufferProperties(physicalDevice, &info, &properties);
236
237			log << TestLog::Message << "External buffer properties: " << info << "\n" << properties << TestLog::EndMessage;
238
239			if ((properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) == 0
240				|| (properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0)
241				TCU_THROW(NotSupportedError, "Exporting and importing memory type not supported");
242
243			if (!config.dedicated && (properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT) != 0)
244			{
245				TCU_THROW(NotSupportedError, "Handle requires dedicated allocation, but test uses suballocated memory");
246			}
247		}
248
249		// Check semaphore support
250		{
251			const vk::VkSemaphoreTypeCreateInfo			semaphoreTypeInfo	=
252			{
253				vk::VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
254				DE_NULL,
255				config.semaphoreType,
256				0,
257			};
258			const vk::VkPhysicalDeviceExternalSemaphoreInfo	info				=
259			{
260				vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
261				&semaphoreTypeInfo,
262				config.semaphoreHandleType
263			};
264
265			vk::VkExternalSemaphoreProperties				properties			=
266			{
267				vk::VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
268				DE_NULL,
269				0u,
270				0u,
271				0u
272			};
273
274			vki.getPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &info, &properties);
275
276			log << TestLog::Message << info << "\n" << properties << TestLog::EndMessage;
277
278			if ((properties.externalSemaphoreFeatures & vk::VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) == 0
279				|| (properties.externalSemaphoreFeatures & vk::VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT) == 0)
280				TCU_THROW(NotSupportedError, "Exporting and importing semaphore type not supported");
281		}
282	}
283
284private:
285
286	const Context& m_context;
287};
288
289bool checkQueueFlags (vk::VkQueueFlags availableFlags, const vk::VkQueueFlags neededFlags)
290{
291	if ((availableFlags & (vk::VK_QUEUE_GRAPHICS_BIT | vk::VK_QUEUE_COMPUTE_BIT)) != 0)
292		availableFlags |= vk::VK_QUEUE_TRANSFER_BIT;
293
294	return (availableFlags & neededFlags) != 0;
295}
296
297class SimpleAllocation : public vk::Allocation
298{
299public:
300								SimpleAllocation	(const vk::DeviceInterface&	vkd,
301													 vk::VkDevice				device,
302													 const vk::VkDeviceMemory	memory);
303								~SimpleAllocation	(void);
304
305private:
306	const vk::DeviceInterface&	m_vkd;
307	const vk::VkDevice			m_device;
308};
309
310SimpleAllocation::SimpleAllocation (const vk::DeviceInterface&	vkd,
311									vk::VkDevice				device,
312									const vk::VkDeviceMemory	memory)
313	: Allocation	(memory, 0, DE_NULL)
314	, m_vkd			(vkd)
315	, m_device		(device)
316{
317}
318
319SimpleAllocation::~SimpleAllocation (void)
320{
321	m_vkd.freeMemory(m_device, getMemory(), DE_NULL);
322}
323
324CustomInstance createTestInstance (Context& context)
325{
326	std::vector<std::string> extensions;
327	extensions.push_back("VK_KHR_get_physical_device_properties2");
328	extensions.push_back("VK_KHR_external_semaphore_capabilities");
329	extensions.push_back("VK_KHR_external_memory_capabilities");
330
331	return createCustomInstanceWithExtensions(context, extensions);
332}
333
334vk::Move<vk::VkDevice> createTestDevice (const Context&					context,
335										 const vk::PlatformInterface&	vkp,
336										 vk::VkInstance					instance,
337										 const vk::InstanceInterface&	vki,
338										 const vk::VkPhysicalDevice		physicalDevice)
339{
340	const bool										validationEnabled			= context.getTestContext().getCommandLine().isValidationEnabled();
341	const float										priority					= 0.0f;
342	const std::vector<vk::VkQueueFamilyProperties>	queueFamilyProperties		= vk::getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
343	std::vector<deUint32>							queueFamilyIndices			(queueFamilyProperties.size(), 0xFFFFFFFFu);
344
345	VkPhysicalDeviceFeatures2						createPhysicalFeature		{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, DE_NULL, context.getDeviceFeatures() };
346	VkPhysicalDeviceTimelineSemaphoreFeatures		timelineSemaphoreFeatures	{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, DE_NULL, DE_TRUE };
347	VkPhysicalDeviceSynchronization2FeaturesKHR		synchronization2Features	{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, DE_NULL, DE_TRUE };
348	void**											nextPtr						= &createPhysicalFeature.pNext;
349	std::vector<const char*>						extensions;
350
351	if (context.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
352		extensions.push_back("VK_KHR_dedicated_allocation");
353
354	if (context.isDeviceFunctionalitySupported("VK_KHR_get_memory_requirements2"))
355		extensions.push_back("VK_KHR_get_memory_requirements2");
356
357	if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore"))
358		extensions.push_back("VK_KHR_external_semaphore");
359	if (context.isDeviceFunctionalitySupported("VK_KHR_external_memory"))
360		extensions.push_back("VK_KHR_external_memory");
361
362	if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_fd"))
363		extensions.push_back("VK_KHR_external_semaphore_fd");
364	if (context.isDeviceFunctionalitySupported("VK_KHR_external_memory_fd"))
365		extensions.push_back("VK_KHR_external_memory_fd");
366
367	if (context.isDeviceFunctionalitySupported("VK_EXT_external_memory_dma_buf"))
368		extensions.push_back("VK_EXT_external_memory_dma_buf");
369
370	if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_win32"))
371		extensions.push_back("VK_KHR_external_semaphore_win32");
372	if (context.isDeviceFunctionalitySupported("VK_KHR_external_memory_win32"))
373		extensions.push_back("VK_KHR_external_memory_win32");
374
375	if (context.isDeviceFunctionalitySupported("VK_FUCHSIA_external_semaphore"))
376		extensions.push_back("VK_FUCHSIA_external_semaphore");
377	if (context.isDeviceFunctionalitySupported("VK_FUCHSIA_external_memory"))
378		extensions.push_back("VK_FUCHSIA_external_memory");
379
380	if (context.isDeviceFunctionalitySupported("VK_KHR_timeline_semaphore"))
381	{
382		extensions.push_back("VK_KHR_timeline_semaphore");
383		addToChainVulkanStructure(&nextPtr, timelineSemaphoreFeatures);
384	}
385	if (context.isDeviceFunctionalitySupported("VK_KHR_synchronization2"))
386	{
387		extensions.push_back("VK_KHR_synchronization2");
388		addToChainVulkanStructure(&nextPtr, synchronization2Features);
389	}
390
391	try
392	{
393		std::vector<vk::VkDeviceQueueCreateInfo>	queues;
394
395		for (size_t ndx = 0; ndx < queueFamilyProperties.size(); ndx++)
396		{
397			const vk::VkDeviceQueueCreateInfo	createInfo	=
398			{
399				vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
400				DE_NULL,
401				0u,
402
403				(deUint32)ndx,
404				1u,
405				&priority
406			};
407
408			queues.push_back(createInfo);
409		}
410
411		const vk::VkDeviceCreateInfo		createInfo				=
412		{
413			vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
414			&createPhysicalFeature,
415			0u,
416
417			(deUint32)queues.size(),
418			&queues[0],
419
420			0u,
421			DE_NULL,
422
423			(deUint32)extensions.size(),
424			extensions.empty() ? DE_NULL : &extensions[0],
425			0u
426		};
427
428		return vkt::createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &createInfo);
429	}
430	catch (const vk::Error& error)
431	{
432		if (error.getError() == vk::VK_ERROR_EXTENSION_NOT_PRESENT)
433			TCU_THROW(NotSupportedError, "Required extensions not supported");
434		else
435			throw;
436	}
437}
438
439// Class to wrap a singleton instance and device
440class InstanceAndDevice
441{
442	InstanceAndDevice	(Context& context)
443		: m_instance		(createTestInstance(context))
444		, m_vki				(m_instance.getDriver())
445		, m_physicalDevice	(vk::chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
446		, m_logicalDevice	(createTestDevice(context, context.getPlatformInterface(), m_instance, m_vki, m_physicalDevice))
447	{
448	}
449
450public:
451
452	static vk::VkInstance getInstanceA(Context& context)
453	{
454		if (!m_instanceA)
455			m_instanceA = SharedPtr<InstanceAndDevice>(new InstanceAndDevice(context));
456
457		return m_instanceA->m_instance;
458	}
459	static vk::VkInstance getInstanceB(Context& context)
460	{
461		if (!m_instanceB)
462			m_instanceB = SharedPtr<InstanceAndDevice>(new InstanceAndDevice(context));
463
464		return m_instanceB->m_instance;
465	}
466	static const vk::InstanceDriver& getDriverA()
467	{
468		DE_ASSERT(m_instanceA);
469		return m_instanceA->m_instance.getDriver();
470	}
471	static const vk::InstanceDriver& getDriverB()
472	{
473		DE_ASSERT(m_instanceB);
474		return m_instanceB->m_instance.getDriver();
475	}
476	static vk::VkPhysicalDevice getPhysicalDeviceA()
477	{
478		DE_ASSERT(m_instanceA);
479		return m_instanceA->m_physicalDevice;
480	}
481	static vk::VkPhysicalDevice getPhysicalDeviceB()
482	{
483		DE_ASSERT(m_instanceB);
484		return m_instanceB->m_physicalDevice;
485	}
486	static const Unique<vk::VkDevice>& getDeviceA()
487	{
488		DE_ASSERT(m_instanceA);
489		return m_instanceA->m_logicalDevice;
490	}
491	static const Unique<vk::VkDevice>& getDeviceB()
492	{
493		DE_ASSERT(m_instanceB);
494		return m_instanceB->m_logicalDevice;
495	}
496	static void collectMessagesA()
497	{
498		DE_ASSERT(m_instanceA);
499		m_instanceA->m_instance.collectMessages();
500	}
501	static void collectMessagesB()
502	{
503		DE_ASSERT(m_instanceB);
504		m_instanceB->m_instance.collectMessages();
505	}
506	static void destroy()
507	{
508		m_instanceA.clear();
509		m_instanceB.clear();
510	}
511
512private:
513	CustomInstance					m_instance;
514	const vk::InstanceDriver&		m_vki;
515	const vk::VkPhysicalDevice		m_physicalDevice;
516	const Unique<vk::VkDevice>		m_logicalDevice;
517
518	static SharedPtr<InstanceAndDevice>	m_instanceA;
519	static SharedPtr<InstanceAndDevice>	m_instanceB;
520};
521SharedPtr<InstanceAndDevice>		InstanceAndDevice::m_instanceA;
522SharedPtr<InstanceAndDevice>		InstanceAndDevice::m_instanceB;
523
524
525vk::VkQueue getQueue (const vk::DeviceInterface&	vkd,
526					  const vk::VkDevice			device,
527					  deUint32						familyIndex)
528{
529	vk::VkQueue queue;
530
531	vkd.getDeviceQueue(device, familyIndex, 0u, &queue);
532
533	return queue;
534}
535
536vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface&	vkd,
537											   vk::VkDevice					device,
538											   deUint32						queueFamilyIndex)
539{
540	const vk::VkCommandPoolCreateInfo	createInfo			=
541	{
542		vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
543		DE_NULL,
544
545		0u,
546		queueFamilyIndex
547	};
548
549	return vk::createCommandPool(vkd, device, &createInfo);
550}
551
552vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface&	vkd,
553												   vk::VkDevice					device,
554												   vk::VkCommandPool			commandPool)
555{
556	const vk::VkCommandBufferLevel			level			= vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY;
557	const vk::VkCommandBufferAllocateInfo	allocateInfo	=
558	{
559		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
560		DE_NULL,
561
562		commandPool,
563		level,
564		1u
565	};
566
567	return vk::allocateCommandBuffer(vkd, device, &allocateInfo);
568}
569
570vk::VkMemoryRequirements getMemoryRequirements(const vk::DeviceInterface&				vkd,
571											   vk::VkDevice								device,
572											   vk::VkImage								image,
573											   bool										dedicated,
574											   bool										getMemReq2Supported)
575{
576	vk::VkMemoryRequirements memoryRequirements = { 0u, 0u, 0u, };
577
578	if (getMemReq2Supported)
579	{
580		const vk::VkImageMemoryRequirementsInfo2	requirementInfo =
581		{
582			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
583			DE_NULL,
584			image
585		};
586		vk::VkMemoryDedicatedRequirements			dedicatedRequirements =
587		{
588			vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
589			DE_NULL,
590			VK_FALSE,
591			VK_FALSE
592		};
593		vk::VkMemoryRequirements2					requirements =
594		{
595			vk::VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
596			&dedicatedRequirements,
597			{ 0u, 0u, 0u, }
598		};
599		vkd.getImageMemoryRequirements2(device, &requirementInfo, &requirements);
600
601		if (!dedicated && dedicatedRequirements.requiresDedicatedAllocation)
602			TCU_THROW(NotSupportedError, "Memory requires dedicated allocation");
603
604		memoryRequirements = requirements.memoryRequirements;
605	}
606	else
607	{
608		vkd.getImageMemoryRequirements(device, image, &memoryRequirements);
609	}
610
611	return memoryRequirements;
612}
613
614vk::VkMemoryRequirements getMemoryRequirements(const vk::DeviceInterface&				vkd,
615											   vk::VkDevice								device,
616											   vk::VkBuffer								buffer,
617											   bool										dedicated,
618											   bool										getMemReq2Supported)
619{
620	vk::VkMemoryRequirements memoryRequirements = { 0u, 0u, 0u, };
621
622	if (getMemReq2Supported)
623	{
624		const vk::VkBufferMemoryRequirementsInfo2	requirementInfo =
625		{
626			vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
627			DE_NULL,
628			buffer
629		};
630		vk::VkMemoryDedicatedRequirements			dedicatedRequirements =
631		{
632			vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
633			DE_NULL,
634			VK_FALSE,
635			VK_FALSE
636		};
637		vk::VkMemoryRequirements2					requirements =
638		{
639			vk::VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
640			&dedicatedRequirements,
641			{ 0u, 0u, 0u, }
642		};
643		vkd.getBufferMemoryRequirements2(device, &requirementInfo, &requirements);
644
645		if (!dedicated && dedicatedRequirements.requiresDedicatedAllocation)
646			TCU_THROW(NotSupportedError, "Memory requires dedicated allocation");
647
648		memoryRequirements = requirements.memoryRequirements;
649	}
650	else
651	{
652		vkd.getBufferMemoryRequirements(device, buffer, &memoryRequirements);
653	}
654
655	return memoryRequirements;
656}
657
658Move<VkImage> createImage(const vk::DeviceInterface&				vkd,
659						  vk::VkDevice								device,
660						  const ResourceDescription&				resourceDesc,
661						  const vk::VkExtent3D						extent,
662						  const std::vector<deUint32>&				queueFamilyIndices,
663						  const OperationSupport&					readOp,
664						  const OperationSupport&					writeOp,
665						  vk::VkExternalMemoryHandleTypeFlagBits	externalType)
666{
667	const vk::VkExternalMemoryImageCreateInfo externalInfo =
668	{
669		vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
670		DE_NULL,
671		(vk::VkExternalMemoryHandleTypeFlags)externalType
672	};
673	const vk::VkImageCreateInfo			createInfo =
674	{
675		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
676		&externalInfo,
677		0u,
678
679		resourceDesc.imageType,
680		resourceDesc.imageFormat,
681		extent,
682		1u,
683		1u,
684		resourceDesc.imageSamples,
685		vk::VK_IMAGE_TILING_OPTIMAL,
686		readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
687		vk::VK_SHARING_MODE_EXCLUSIVE,
688
689		(deUint32)queueFamilyIndices.size(),
690		&queueFamilyIndices[0],
691		vk::VK_IMAGE_LAYOUT_UNDEFINED
692	};
693
694	return vk::createImage(vkd, device, &createInfo);
695}
696
697Move<VkBuffer> createBuffer(const vk::DeviceInterface&						vkd,
698							vk::VkDevice									device,
699							const vk::VkDeviceSize							size,
700							const vk::VkBufferUsageFlags					usage,
701							const vk::VkExternalMemoryHandleTypeFlagBits	memoryHandleType,
702							const std::vector<deUint32>&					queueFamilyIndices)
703{
704	const vk::VkExternalMemoryBufferCreateInfo	externalInfo =
705	{
706		vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
707		DE_NULL,
708		(vk::VkExternalMemoryHandleTypeFlags)memoryHandleType
709	};
710	const vk::VkBufferCreateInfo				createInfo =
711	{
712		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
713		&externalInfo,
714		0u,
715
716		size,
717		usage,
718		vk::VK_SHARING_MODE_EXCLUSIVE,
719		(deUint32)queueFamilyIndices.size(),
720		&queueFamilyIndices[0]
721	};
722	return vk::createBuffer(vkd, device, &createInfo);
723}
724
725de::MovePtr<vk::Allocation> importAndBindMemory (const vk::DeviceInterface&					vkd,
726												 vk::VkDevice								device,
727												 vk::VkBuffer								buffer,
728												 NativeHandle&								nativeHandle,
729												 vk::VkExternalMemoryHandleTypeFlagBits	externalType,
730												 deUint32									exportedMemoryTypeIndex,
731												 bool										dedicated)
732{
733	const vk::VkMemoryRequirements	requirements	= vk::getBufferMemoryRequirements(vkd, device, buffer);
734	vk::Move<vk::VkDeviceMemory>	memory			= dedicated
735													? importDedicatedMemory(vkd, device, buffer, requirements, externalType, exportedMemoryTypeIndex, nativeHandle)
736													: importMemory(vkd, device, requirements, externalType, exportedMemoryTypeIndex, nativeHandle);
737
738	VK_CHECK(vkd.bindBufferMemory(device, buffer, *memory, 0u));
739
740	return de::MovePtr<vk::Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
741}
742
743de::MovePtr<vk::Allocation> importAndBindMemory (const vk::DeviceInterface&					vkd,
744												 vk::VkDevice								device,
745												 vk::VkImage								image,
746												 NativeHandle&								nativeHandle,
747												 vk::VkExternalMemoryHandleTypeFlagBits	externalType,
748												 deUint32									exportedMemoryTypeIndex,
749												 bool										dedicated)
750{
751	const vk::VkMemoryRequirements	requirements	= vk::getImageMemoryRequirements(vkd, device, image);
752	vk::Move<vk::VkDeviceMemory>	memory			= dedicated
753													? importDedicatedMemory(vkd, device, image, requirements, externalType, exportedMemoryTypeIndex, nativeHandle)
754													: importMemory(vkd, device, requirements, externalType, exportedMemoryTypeIndex, nativeHandle);
755	VK_CHECK(vkd.bindImageMemory(device, image, *memory, 0u));
756
757	return de::MovePtr<vk::Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
758}
759
760de::MovePtr<Resource> importResource (const vk::DeviceInterface&				vkd,
761									  vk::VkDevice								device,
762									  const ResourceDescription&				resourceDesc,
763									  const std::vector<deUint32>&				queueFamilyIndices,
764									  const OperationSupport&					readOp,
765									  const OperationSupport&					writeOp,
766									  NativeHandle&								nativeHandle,
767									  vk::VkExternalMemoryHandleTypeFlagBits	externalType,
768									  deUint32									exportedMemoryTypeIndex,
769									  bool										dedicated)
770{
771	if (resourceDesc.type == RESOURCE_TYPE_IMAGE)
772	{
773		const vk::VkExtent3D				extent					=
774		{
775			(deUint32)resourceDesc.size.x(),
776			de::max(1u, (deUint32)resourceDesc.size.y()),
777			de::max(1u, (deUint32)resourceDesc.size.z())
778		};
779		const vk::VkImageSubresourceRange	subresourceRange		=
780		{
781			resourceDesc.imageAspect,
782			0u,
783			1u,
784			0u,
785			1u
786		};
787		const vk::VkImageSubresourceLayers	subresourceLayers		=
788		{
789			resourceDesc.imageAspect,
790			0u,
791			0u,
792			1u
793		};
794		const vk:: VkExternalMemoryImageCreateInfo externalInfo =
795		{
796			vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
797			DE_NULL,
798			(vk::VkExternalMemoryHandleTypeFlags)externalType
799		};
800		const vk::VkImageTiling				tiling					= vk::VK_IMAGE_TILING_OPTIMAL;
801		const vk::VkImageCreateInfo			createInfo				=
802		{
803			vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
804			&externalInfo,
805			0u,
806
807			resourceDesc.imageType,
808			resourceDesc.imageFormat,
809			extent,
810			1u,
811			1u,
812			resourceDesc.imageSamples,
813			tiling,
814			readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
815			vk::VK_SHARING_MODE_EXCLUSIVE,
816
817			(deUint32)queueFamilyIndices.size(),
818			&queueFamilyIndices[0],
819			vk::VK_IMAGE_LAYOUT_UNDEFINED
820		};
821
822		vk::Move<vk::VkImage>			image		= vk::createImage(vkd, device, &createInfo);
823		de::MovePtr<vk::Allocation>		allocation	= importAndBindMemory(vkd, device, *image, nativeHandle, externalType, exportedMemoryTypeIndex, dedicated);
824
825		return de::MovePtr<Resource>(new Resource(image, allocation, extent, resourceDesc.imageType, resourceDesc.imageFormat, subresourceRange, subresourceLayers, tiling));
826	}
827	else
828	{
829		const vk::VkDeviceSize							offset			= 0u;
830		const vk::VkDeviceSize							size			= static_cast<vk::VkDeviceSize>(resourceDesc.size.x());
831		const vk::VkBufferUsageFlags					usage			= readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags();
832		const vk:: VkExternalMemoryBufferCreateInfo	externalInfo	=
833		{
834			vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
835			DE_NULL,
836			(vk::VkExternalMemoryHandleTypeFlags)externalType
837		};
838		const vk::VkBufferCreateInfo					createInfo		=
839		{
840			vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
841			&externalInfo,
842			0u,
843
844			size,
845			usage,
846			vk::VK_SHARING_MODE_EXCLUSIVE,
847			(deUint32)queueFamilyIndices.size(),
848			&queueFamilyIndices[0]
849		};
850		vk::Move<vk::VkBuffer>		buffer		= vk::createBuffer(vkd, device, &createInfo);
851		de::MovePtr<vk::Allocation>	allocation	= importAndBindMemory(vkd, device, *buffer, nativeHandle, externalType, exportedMemoryTypeIndex, dedicated);
852
853		return de::MovePtr<Resource>(new Resource(resourceDesc.type, buffer, allocation, offset, size));
854	}
855}
856
857void recordWriteBarrier (SynchronizationWrapperPtr	synchronizationWrapper,
858						 vk::VkCommandBuffer		commandBuffer,
859						 const Resource&			resource,
860						 const SyncInfo&			writeSync,
861						 deUint32					writeQueueFamilyIndex,
862						 const SyncInfo&			readSync)
863{
864	const vk::VkPipelineStageFlags2KHR	srcStageMask	= writeSync.stageMask;
865	const vk::VkAccessFlags2KHR			srcAccessMask	= writeSync.accessMask;
866
867	const vk::VkPipelineStageFlags2KHR	dstStageMask	= readSync.stageMask;
868	const vk::VkAccessFlags2KHR			dstAccessMask	= readSync.accessMask;
869
870	if (resource.getType() == RESOURCE_TYPE_IMAGE)
871	{
872		const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
873			srcStageMask,									// VkPipelineStageFlags2KHR			srcStageMask
874			srcAccessMask,									// VkAccessFlags2KHR				srcAccessMask
875			dstStageMask,									// VkPipelineStageFlags2KHR			dstStageMask
876			dstAccessMask,									// VkAccessFlags2KHR				dstAccessMask
877			writeSync.imageLayout,							// VkImageLayout					oldLayout
878			readSync.imageLayout,							// VkImageLayout					newLayout
879			resource.getImage().handle,						// VkImage							image
880			resource.getImage().subresourceRange,			// VkImageSubresourceRange			subresourceRange
881			writeQueueFamilyIndex,							// deUint32							srcQueueFamilyIndex
882			VK_QUEUE_FAMILY_EXTERNAL						// deUint32							dstQueueFamilyIndex
883		);
884		VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2);
885		synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
886	}
887	else
888	{
889		const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
890			srcStageMask,									// VkPipelineStageFlags2KHR			srcStageMask
891			srcAccessMask,									// VkAccessFlags2KHR				srcAccessMask
892			dstStageMask,									// VkPipelineStageFlags2KHR			dstStageMask
893			dstAccessMask,									// VkAccessFlags2KHR				dstAccessMask
894			resource.getBuffer().handle,					// VkBuffer							buffer
895			0,												// VkDeviceSize						offset
896			VK_WHOLE_SIZE,									// VkDeviceSize						size
897			writeQueueFamilyIndex,							// deUint32							srcQueueFamilyIndex
898			VK_QUEUE_FAMILY_EXTERNAL						// deUint32							dstQueueFamilyIndex
899		);
900		VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2);
901		synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
902	}
903}
904
905void recordReadBarrier (SynchronizationWrapperPtr	synchronizationWrapper,
906						vk::VkCommandBuffer			commandBuffer,
907						const Resource&				resource,
908						const SyncInfo&				writeSync,
909						const SyncInfo&				readSync,
910						deUint32					readQueueFamilyIndex)
911{
912	const vk::VkPipelineStageFlags2KHR	srcStageMask	= readSync.stageMask;
913	const vk::VkAccessFlags2KHR			srcAccessMask	= readSync.accessMask;
914
915	const vk::VkPipelineStageFlags2KHR	dstStageMask	= readSync.stageMask;
916	const vk::VkAccessFlags2KHR			dstAccessMask	= readSync.accessMask;
917
918	if (resource.getType() == RESOURCE_TYPE_IMAGE)
919	{
920		const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
921			srcStageMask,										// VkPipelineStageFlags2KHR			srcStageMask
922			srcAccessMask,										// VkAccessFlags2KHR				srcAccessMask
923			dstStageMask,										// VkPipelineStageFlags2KHR			dstStageMask
924			dstAccessMask,										// VkAccessFlags2KHR				dstAccessMask
925			writeSync.imageLayout,								// VkImageLayout					oldLayout
926			readSync.imageLayout,								// VkImageLayout					newLayout
927			resource.getImage().handle,							// VkImage							image
928			resource.getImage().subresourceRange,				// VkImageSubresourceRange			subresourceRange
929			VK_QUEUE_FAMILY_EXTERNAL,							// deUint32							srcQueueFamilyIndex
930			readQueueFamilyIndex								// deUint32							dstQueueFamilyIndex
931		);
932		VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2);
933		synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
934	}
935	else
936	{
937		const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
938			srcStageMask,										// VkPipelineStageFlags2KHR			srcStageMask
939			srcAccessMask,										// VkAccessFlags2KHR				srcAccessMask
940			dstStageMask,										// VkPipelineStageFlags2KHR			dstStageMask
941			dstAccessMask,										// VkAccessFlags2KHR				dstAccessMask
942			resource.getBuffer().handle,						// VkBuffer							buffer
943			0,													// VkDeviceSize						offset
944			VK_WHOLE_SIZE,										// VkDeviceSize						size
945			VK_QUEUE_FAMILY_EXTERNAL,							// deUint32							srcQueueFamilyIndex
946			readQueueFamilyIndex								// deUint32							dstQueueFamilyIndex
947		);
948		VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2);
949		synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
950	}
951}
952
953std::vector<deUint32> getFamilyIndices (const std::vector<vk::VkQueueFamilyProperties>& properties)
954{
955	std::vector<deUint32> indices (properties.size(), 0);
956
957	for (deUint32 ndx = 0; ndx < properties.size(); ndx++)
958		indices[ndx] = ndx;
959
960	return indices;
961}
962
963class SharingTestInstance : public TestInstance
964{
965public:
966														SharingTestInstance		(Context&	context,
967																				 TestConfig	config);
968
969	virtual tcu::TestStatus								iterate					(void);
970
971private:
972	const TestConfig									m_config;
973
974	const de::UniquePtr<OperationSupport>				m_supportWriteOp;
975	const de::UniquePtr<OperationSupport>				m_supportReadOp;
976	const NotSupportedChecker							m_notSupportedChecker; // Must declare before VkInstance to effectively reduce runtimes!
977
978	const bool											m_getMemReq2Supported;
979
980	const vk::VkInstance								m_instanceA;
981	const vk::InstanceDriver&							m_vkiA;
982	const vk::VkPhysicalDevice							m_physicalDeviceA;
983	const std::vector<vk::VkQueueFamilyProperties>		m_queueFamiliesA;
984	const std::vector<deUint32>							m_queueFamilyIndicesA;
985	const vk::Unique<vk::VkDevice>&						m_deviceA;
986	const vk::DeviceDriver								m_vkdA;
987
988	const vk::VkInstance								m_instanceB;
989	const vk::InstanceDriver&							m_vkiB;
990	const vk::VkPhysicalDevice							m_physicalDeviceB;
991	const std::vector<vk::VkQueueFamilyProperties>		m_queueFamiliesB;
992	const std::vector<deUint32>							m_queueFamilyIndicesB;
993	const vk::Unique<vk::VkDevice>&						m_deviceB;
994	const vk::DeviceDriver								m_vkdB;
995
996	const vk::VkExternalSemaphoreHandleTypeFlagBits		m_semaphoreHandleType;
997	const vk::VkExternalMemoryHandleTypeFlagBits		m_memoryHandleType;
998
999	// \todo Should this be moved to the group same way as in the other tests?
1000	PipelineCacheData									m_pipelineCacheData;
1001	tcu::ResultCollector								m_resultCollector;
1002	size_t												m_queueANdx;
1003	size_t												m_queueBNdx;
1004};
1005
1006SharingTestInstance::SharingTestInstance (Context&		context,
1007										  TestConfig	config)
1008	: TestInstance				(context)
1009	, m_config					(config)
1010	, m_supportWriteOp			(makeOperationSupport(config.writeOp, config.resource))
1011	, m_supportReadOp			(makeOperationSupport(config.readOp, config.resource))
1012	, m_notSupportedChecker		(context, m_config, *m_supportWriteOp, *m_supportReadOp)
1013	, m_getMemReq2Supported		(context.isDeviceFunctionalitySupported("VK_KHR_get_memory_requirements2"))
1014
1015	, m_instanceA				(InstanceAndDevice::getInstanceA(context))
1016	, m_vkiA					(InstanceAndDevice::getDriverA())
1017	, m_physicalDeviceA			(InstanceAndDevice::getPhysicalDeviceA())
1018	, m_queueFamiliesA			(vk::getPhysicalDeviceQueueFamilyProperties(m_vkiA, m_physicalDeviceA))
1019	, m_queueFamilyIndicesA		(getFamilyIndices(m_queueFamiliesA))
1020	, m_deviceA					(InstanceAndDevice::getDeviceA())
1021	, m_vkdA					(context.getPlatformInterface(), m_instanceA, *m_deviceA, context.getUsedApiVersion())
1022
1023	, m_instanceB				(InstanceAndDevice::getInstanceB(context))
1024	, m_vkiB					(InstanceAndDevice::getDriverB())
1025	, m_physicalDeviceB			(InstanceAndDevice::getPhysicalDeviceB())
1026	, m_queueFamiliesB			(vk::getPhysicalDeviceQueueFamilyProperties(m_vkiB, m_physicalDeviceB))
1027	, m_queueFamilyIndicesB		(getFamilyIndices(m_queueFamiliesB))
1028	, m_deviceB					(InstanceAndDevice::getDeviceB())
1029	, m_vkdB					(context.getPlatformInterface(), m_instanceB, *m_deviceB, context.getUsedApiVersion())
1030
1031	, m_semaphoreHandleType		(m_config.semaphoreHandleType)
1032	, m_memoryHandleType		(m_config.memoryHandleType)
1033
1034	, m_resultCollector			(context.getTestContext().getLog())
1035	, m_queueANdx				(0)
1036	, m_queueBNdx				(0)
1037{
1038}
1039
1040tcu::TestStatus SharingTestInstance::iterate (void)
1041{
1042	TestLog&								log					(m_context.getTestContext().getLog());
1043	bool									isTimelineSemaphore (m_config.semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE_KHR);
1044	try
1045	{
1046		const deUint32						queueFamilyA		= (deUint32)m_queueANdx;
1047		const deUint32						queueFamilyB		= (deUint32)m_queueBNdx;
1048
1049		const tcu::ScopedLogSection			queuePairSection	(log,
1050																"WriteQueue-" + de::toString(queueFamilyA) + "-ReadQueue-" + de::toString(queueFamilyB),
1051																"WriteQueue-" + de::toString(queueFamilyA) + "-ReadQueue-" + de::toString(queueFamilyB));
1052
1053		const vk::Unique<vk::VkSemaphore>	semaphoreA			(createExportableSemaphoreType(m_vkdA, *m_deviceA, m_config.semaphoreType, m_semaphoreHandleType));
1054		const vk::Unique<vk::VkSemaphore>	semaphoreB			(createSemaphoreType(m_vkdB, *m_deviceB, m_config.semaphoreType));
1055
1056		const ResourceDescription&			resourceDesc		= m_config.resource;
1057		de::MovePtr<Resource>				resourceA;
1058
1059		deUint32 exportedMemoryTypeIndex = ~0U;
1060		if (resourceDesc.type == RESOURCE_TYPE_IMAGE)
1061		{
1062			const vk::VkExtent3D				extent =
1063			{
1064				(deUint32)resourceDesc.size.x(),
1065				de::max(1u, (deUint32)resourceDesc.size.y()),
1066				de::max(1u, (deUint32)resourceDesc.size.z())
1067			};
1068			const vk::VkImageSubresourceRange	subresourceRange =
1069			{
1070				resourceDesc.imageAspect,
1071				0u,
1072				1u,
1073				0u,
1074				1u
1075			};
1076			const vk::VkImageSubresourceLayers	subresourceLayers =
1077			{
1078				resourceDesc.imageAspect,
1079				0u,
1080				0u,
1081				1u
1082			};
1083
1084			vk::Move<vk::VkImage>			image					= createImage(m_vkdA, *m_deviceA, resourceDesc, extent, m_queueFamilyIndicesA,
1085																				  *m_supportReadOp, *m_supportWriteOp, m_memoryHandleType);
1086			const vk::VkImageTiling			tiling					= vk::VK_IMAGE_TILING_OPTIMAL;
1087			const vk::VkMemoryRequirements	requirements			= getMemoryRequirements(m_vkdA, *m_deviceA, *image, m_config.dedicated, m_getMemReq2Supported);
1088											exportedMemoryTypeIndex = chooseMemoryType(requirements.memoryTypeBits);
1089			vk::Move<vk::VkDeviceMemory>	memory					= allocateExportableMemory(m_vkdA, *m_deviceA, requirements.size, exportedMemoryTypeIndex, m_memoryHandleType, m_config.dedicated ? *image : (vk::VkImage)0);
1090
1091			VK_CHECK(m_vkdA.bindImageMemory(*m_deviceA, *image, *memory, 0u));
1092
1093			de::MovePtr<vk::Allocation> allocation = de::MovePtr<vk::Allocation>(new SimpleAllocation(m_vkdA, *m_deviceA, memory.disown()));
1094			resourceA = de::MovePtr<Resource>(new Resource(image, allocation, extent, resourceDesc.imageType, resourceDesc.imageFormat, subresourceRange, subresourceLayers, tiling));
1095		}
1096		else
1097		{
1098			const vk::VkDeviceSize				offset					= 0u;
1099			const vk::VkDeviceSize				size					= static_cast<vk::VkDeviceSize>(resourceDesc.size.x());
1100			const vk::VkBufferUsageFlags		usage					= m_supportReadOp->getInResourceUsageFlags() | m_supportWriteOp->getOutResourceUsageFlags();
1101			vk::Move<vk::VkBuffer>				buffer					= createBuffer(m_vkdA, *m_deviceA, size, usage, m_memoryHandleType, m_queueFamilyIndicesA);
1102			const vk::VkMemoryRequirements		requirements			= getMemoryRequirements(m_vkdA, *m_deviceA, *buffer, m_config.dedicated, m_getMemReq2Supported);
1103												exportedMemoryTypeIndex = chooseMemoryType(requirements.memoryTypeBits);
1104			vk::Move<vk::VkDeviceMemory>		memory					= allocateExportableMemory(m_vkdA, *m_deviceA, requirements.size, exportedMemoryTypeIndex, m_memoryHandleType, m_config.dedicated ? *buffer : (vk::VkBuffer)0);
1105
1106			VK_CHECK(m_vkdA.bindBufferMemory(*m_deviceA, *buffer, *memory, 0u));
1107
1108			de::MovePtr<vk::Allocation> allocation = de::MovePtr<vk::Allocation>(new SimpleAllocation(m_vkdA, *m_deviceA, memory.disown()));
1109			resourceA = de::MovePtr<Resource>(new Resource(resourceDesc.type, buffer, allocation, offset, size));
1110		}
1111
1112		NativeHandle							nativeMemoryHandle;
1113		getMemoryNative(m_vkdA, *m_deviceA, resourceA->getMemory(), m_memoryHandleType, nativeMemoryHandle);
1114
1115		const de::UniquePtr<Resource>			resourceB			(importResource(m_vkdB, *m_deviceB, resourceDesc, m_queueFamilyIndicesB, *m_supportReadOp, *m_supportWriteOp, nativeMemoryHandle, m_memoryHandleType, exportedMemoryTypeIndex, m_config.dedicated));
1116		const vk::VkQueue						queueA				(getQueue(m_vkdA, *m_deviceA, queueFamilyA));
1117		const vk::Unique<vk::VkCommandPool>		commandPoolA		(createCommandPool(m_vkdA, *m_deviceA, queueFamilyA));
1118		const vk::Unique<vk::VkCommandBuffer>	commandBufferA		(createCommandBuffer(m_vkdA, *m_deviceA, *commandPoolA));
1119		vk::SimpleAllocator						allocatorA			(m_vkdA, *m_deviceA, vk::getPhysicalDeviceMemoryProperties(m_vkiA, m_physicalDeviceA));
1120		OperationContext						operationContextA	(m_context, m_config.type, m_vkiA, m_vkdA, m_physicalDeviceA, *m_deviceA, allocatorA, m_context.getBinaryCollection(), m_pipelineCacheData);
1121
1122		if (!checkQueueFlags(m_queueFamiliesA[m_queueANdx].queueFlags , m_supportWriteOp->getQueueFlags(operationContextA)))
1123			TCU_THROW(NotSupportedError, "Operation not supported by the source queue");
1124
1125		const vk::VkQueue						queueB				(getQueue(m_vkdB, *m_deviceB, queueFamilyB));
1126		const vk::Unique<vk::VkCommandPool>		commandPoolB		(createCommandPool(m_vkdB, *m_deviceB, queueFamilyB));
1127		const vk::Unique<vk::VkCommandBuffer>	commandBufferB		(createCommandBuffer(m_vkdB, *m_deviceB, *commandPoolB));
1128		vk::SimpleAllocator						allocatorB			(m_vkdB, *m_deviceB, vk::getPhysicalDeviceMemoryProperties(m_vkiB, m_physicalDeviceB));
1129		OperationContext						operationContextB	(m_context, m_config.type, m_vkiB, m_vkdB, m_physicalDeviceB, *m_deviceB, allocatorB, m_context.getBinaryCollection(), m_pipelineCacheData);
1130
1131		if (!checkQueueFlags(m_queueFamiliesB[m_queueBNdx].queueFlags , m_supportReadOp->getQueueFlags(operationContextB)))
1132			TCU_THROW(NotSupportedError, "Operation not supported by the destination queue");
1133
1134		const de::UniquePtr<Operation>			writeOp				(m_supportWriteOp->build(operationContextA, *resourceA));
1135		const de::UniquePtr<Operation>			readOp				(m_supportReadOp->build(operationContextB, *resourceB));
1136
1137		const SyncInfo							writeSync			= writeOp->getOutSyncInfo();
1138		const SyncInfo							readSync			= readOp->getInSyncInfo();
1139		SynchronizationWrapperPtr				synchronizationWrapperA = getSynchronizationWrapper(m_config.type, m_vkdA, isTimelineSemaphore);
1140		SynchronizationWrapperPtr				synchronizationWrapperB = getSynchronizationWrapper(m_config.type, m_vkdB, isTimelineSemaphore);
1141
1142		const vk::VkPipelineStageFlags2			graphicsFlags = vk::VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | vk::VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT | vk::VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT |
1143																vk::VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT | vk::VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
1144
1145		if ((writeSync.stageMask & graphicsFlags) != 0 || (readSync.stageMask) != 0)
1146		{
1147			if (!checkQueueFlags(m_queueFamiliesA[m_queueANdx].queueFlags, VK_QUEUE_GRAPHICS_BIT))
1148				TCU_THROW(NotSupportedError, "Operation not supported by the source queue");
1149
1150			if (!checkQueueFlags(m_queueFamiliesB[m_queueBNdx].queueFlags, VK_QUEUE_GRAPHICS_BIT))
1151				TCU_THROW(NotSupportedError, "Operation not supported by the destination queue");
1152		}
1153
1154		beginCommandBuffer(m_vkdA, *commandBufferA);
1155		writeOp->recordCommands(*commandBufferA);
1156		recordWriteBarrier(synchronizationWrapperA, *commandBufferA, *resourceA, writeSync, queueFamilyA, readSync);
1157		endCommandBuffer(m_vkdA, *commandBufferA);
1158
1159		beginCommandBuffer(m_vkdB, *commandBufferB);
1160		recordReadBarrier(synchronizationWrapperB, *commandBufferB, *resourceB, writeSync, readSync, queueFamilyB);
1161		readOp->recordCommands(*commandBufferB);
1162		endCommandBuffer(m_vkdB, *commandBufferB);
1163
1164		{
1165			de::Random									rng							(1234);
1166			vk::VkCommandBufferSubmitInfoKHR			cmdBufferInfos				= makeCommonCommandBufferSubmitInfo(*commandBufferA);
1167			VkSemaphoreSubmitInfoKHR					signalSemaphoreSubmitInfo	=
1168				makeCommonSemaphoreSubmitInfo(*semaphoreA, rng.getInt(1, deIntMaxValue32(32)), VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
1169
1170			synchronizationWrapperA->addSubmitInfo(
1171				0u,
1172				DE_NULL,
1173				1u,
1174				&cmdBufferInfos,
1175				1u,
1176				&signalSemaphoreSubmitInfo,
1177				DE_FALSE,
1178				isTimelineSemaphore
1179			);
1180
1181			VK_CHECK(synchronizationWrapperA->queueSubmit(queueA, DE_NULL));
1182
1183			{
1184				NativeHandle						nativeSemaphoreHandle;
1185				const vk::VkSemaphoreImportFlags	flags = isSupportedPermanence(m_semaphoreHandleType, PERMANENCE_PERMANENT) ? (vk::VkSemaphoreImportFlagBits)0u : vk::VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
1186
1187				getSemaphoreNative(m_vkdA, *m_deviceA, *semaphoreA, m_semaphoreHandleType, nativeSemaphoreHandle);
1188				importSemaphore(m_vkdB, *m_deviceB, *semaphoreB, m_semaphoreHandleType, nativeSemaphoreHandle, flags);
1189			}
1190		}
1191		{
1192			vk::VkCommandBufferSubmitInfoKHR			cmdBufferInfos			= makeCommonCommandBufferSubmitInfo(*commandBufferB);
1193			VkSemaphoreSubmitInfoKHR					waitSemaphoreSubmitInfo =
1194				makeCommonSemaphoreSubmitInfo(*semaphoreB, 1u, readSync.stageMask);
1195
1196			synchronizationWrapperB->addSubmitInfo(
1197				1u,
1198				&waitSemaphoreSubmitInfo,
1199				1u,
1200				&cmdBufferInfos,
1201				0u,
1202				DE_NULL,
1203				isTimelineSemaphore
1204			);
1205
1206			VK_CHECK(synchronizationWrapperB->queueSubmit(queueB, DE_NULL));
1207		}
1208
1209		VK_CHECK(m_vkdA.queueWaitIdle(queueA));
1210		VK_CHECK(m_vkdB.queueWaitIdle(queueB));
1211
1212		if (m_config.semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE)
1213		{
1214			deUint64	valueA;
1215			deUint64	valueB;
1216
1217			VK_CHECK(m_vkdA.getSemaphoreCounterValue(*m_deviceA, *semaphoreA, &valueA));
1218			VK_CHECK(m_vkdB.getSemaphoreCounterValue(*m_deviceB, *semaphoreB, &valueB));
1219
1220			if (valueA != valueB)
1221				return tcu::TestStatus::fail("Inconsistent values between shared semaphores");
1222		}
1223
1224		{
1225			const Data	expected	= writeOp->getData();
1226			const Data	actual		= readOp->getData();
1227
1228			DE_ASSERT(expected.size == actual.size);
1229
1230			if (!isIndirectBuffer(m_config.resource.type))
1231			{
1232				if (0 != deMemCmp(expected.data, actual.data, expected.size))
1233				{
1234					const size_t		maxBytesLogged = 256;
1235					std::ostringstream	expectedData;
1236					std::ostringstream	actualData;
1237					size_t				byteNdx = 0;
1238
1239					// Find first byte difference
1240					for (; actual.data[byteNdx] == expected.data[byteNdx]; byteNdx++)
1241					{
1242						// Nothing
1243					}
1244
1245					log << TestLog::Message << "First different byte at offset: " << byteNdx << TestLog::EndMessage;
1246
1247					// Log 8 previous bytes before the first incorrect byte
1248					if (byteNdx > 8)
1249					{
1250						expectedData << "... ";
1251						actualData << "... ";
1252
1253						byteNdx -= 8;
1254					}
1255					else
1256						byteNdx = 0;
1257
1258					for (size_t i = 0; i < maxBytesLogged && byteNdx < expected.size; i++, byteNdx++)
1259					{
1260						expectedData << (i > 0 ? ", " : "") << (deUint32)expected.data[byteNdx];
1261						actualData << (i > 0 ? ", " : "") << (deUint32)actual.data[byteNdx];
1262					}
1263
1264					if (expected.size > byteNdx)
1265					{
1266						expectedData << "...";
1267						actualData << "...";
1268					}
1269
1270					log << TestLog::Message << "Expected data: (" << expectedData.str() << ")" << TestLog::EndMessage;
1271					log << TestLog::Message << "Actual data: (" << actualData.str() << ")" << TestLog::EndMessage;
1272
1273					m_resultCollector.fail("Memory contents don't match");
1274				}
1275			}
1276			else
1277			{
1278				const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
1279				const deUint32 actualValue   = reinterpret_cast<const deUint32*>(actual.data)[0];
1280
1281				if (actualValue < expectedValue)
1282				{
1283					log << TestLog::Message << "Expected counter value: (" << expectedValue << ")" << TestLog::EndMessage;
1284					log << TestLog::Message << "Actual counter value: (" << actualValue << ")" << TestLog::EndMessage;
1285
1286					m_resultCollector.fail("Counter value is smaller than expected");
1287				}
1288			}
1289		}
1290	}
1291	catch (const tcu::NotSupportedError& error)
1292	{
1293		log << TestLog::Message << "Not supported: " << error.getMessage() << TestLog::EndMessage;
1294	}
1295	catch (const tcu::TestError& error)
1296	{
1297		m_resultCollector.fail(std::string("Exception: ") + error.getMessage());
1298	}
1299
1300	// Collect possible validation errors.
1301	InstanceAndDevice::collectMessagesA();
1302	InstanceAndDevice::collectMessagesB();
1303
1304	// Move to next queue
1305	{
1306		m_queueBNdx++;
1307
1308		if (m_queueBNdx >= m_queueFamiliesB.size())
1309		{
1310			m_queueANdx++;
1311
1312			if (m_queueANdx >= m_queueFamiliesA.size())
1313			{
1314				return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1315			}
1316			else
1317			{
1318				m_queueBNdx = 0;
1319
1320				return tcu::TestStatus::incomplete();
1321			}
1322		}
1323		else
1324			return tcu::TestStatus::incomplete();
1325	}
1326}
1327
1328struct Progs
1329{
1330	void init (vk::SourceCollections& dst, TestConfig config) const
1331	{
1332		const de::UniquePtr<OperationSupport>	readOp	(makeOperationSupport(config.readOp, config.resource));
1333		const de::UniquePtr<OperationSupport>	writeOp	(makeOperationSupport(config.writeOp, config.resource));
1334
1335		readOp->initPrograms(dst);
1336		writeOp->initPrograms(dst);
1337	}
1338};
1339
1340} // anonymous
1341
1342static void createTests (tcu::TestCaseGroup* group, SynchronizationType type)
1343{
1344	tcu::TestContext& testCtx = group->getTestContext();
1345	const struct
1346	{
1347		vk::VkExternalMemoryHandleTypeFlagBits		memoryType;
1348		vk::VkExternalSemaphoreHandleTypeFlagBits	semaphoreType;
1349		const char*									nameSuffix;
1350	} cases[] =
1351	{
1352		{
1353			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
1354			vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1355			"_fd"
1356		},
1357		{
1358			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
1359			vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
1360			"_fence_fd"
1361		},
1362		{
1363			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
1364			vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
1365			"_win32_kmt"
1366		},
1367		{
1368			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
1369			vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT,
1370			"_win32"
1371		},
1372		{
1373			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
1374			vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1375			"_dma_buf"
1376		},
1377		{
1378			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA,
1379			vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
1380			"_zircon_handle"
1381		},
1382	};
1383
1384	const std::string semaphoreNames[vk::VK_SEMAPHORE_TYPE_LAST] =
1385	{
1386		"_binary_semaphore",
1387		"_timeline_semaphore",
1388	};
1389
1390	for (size_t dedicatedNdx = 0; dedicatedNdx < 2; dedicatedNdx++)
1391	{
1392		const bool						dedicated		(dedicatedNdx == 1);
1393		de::MovePtr<tcu::TestCaseGroup>	dedicatedGroup	(new tcu::TestCaseGroup(testCtx, dedicated ? "dedicated" : "suballocated"));
1394
1395		for (size_t writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
1396		for (size_t readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
1397		{
1398			const OperationName	writeOp		= s_writeOps[writeOpNdx];
1399			const OperationName	readOp		= s_readOps[readOpNdx];
1400			const std::string	opGroupName	= getOperationName(writeOp) + "_" + getOperationName(readOp);
1401			bool				empty		= true;
1402
1403			de::MovePtr<tcu::TestCaseGroup> opGroup	(new tcu::TestCaseGroup(testCtx, opGroupName.c_str()));
1404
1405			for (size_t resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
1406			{
1407				const ResourceDescription&	resource	= s_resources[resourceNdx];
1408
1409				for (size_t caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
1410				{
1411					for (int semaphoreType = 0; semaphoreType < vk::VK_SEMAPHORE_TYPE_LAST; semaphoreType++)
1412					{
1413						if (cases[caseNdx].semaphoreType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT &&
1414						    (vk::VkSemaphoreType)semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE)
1415						{
1416							continue;
1417						}
1418
1419						if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
1420						{
1421							const TestConfig	config (type, resource, (vk::VkSemaphoreType)semaphoreType, writeOp, readOp, cases[caseNdx].memoryType, cases[caseNdx].semaphoreType, dedicated);
1422							std::string			name	= getResourceName(resource) + semaphoreNames[semaphoreType] + cases[caseNdx].nameSuffix;
1423
1424							opGroup->addChild(new InstanceFactory1<SharingTestInstance, TestConfig, Progs>(testCtx, tcu::NODETYPE_SELF_VALIDATE,  name, Progs(), config));
1425							empty = false;
1426						}
1427					}
1428				}
1429			}
1430
1431			if (!empty)
1432				dedicatedGroup->addChild(opGroup.release());
1433		}
1434
1435		group->addChild(dedicatedGroup.release());
1436	}
1437}
1438
1439static void cleanupGroup (tcu::TestCaseGroup* group, SynchronizationType type)
1440{
1441	DE_UNREF(group);
1442	DE_UNREF(type);
1443	// Destroy singleton object
1444	InstanceAndDevice::destroy();
1445}
1446
1447tcu::TestCaseGroup* createCrossInstanceSharingTest (tcu::TestContext& testCtx, SynchronizationType type)
1448{
1449	return createTestGroup(testCtx, "cross_instance", createTests, type, cleanupGroup);
1450}
1451
1452} // synchronization
1453} // vkt
1454