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