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
39using tcu::TestLog;
40using namespace vkt::ExternalMemoryUtil;
41
42namespace vkt
43{
44namespace synchronization
45{
46namespace
47{
48
49struct 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.
76class NotSupportedChecker
77{
78public:
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
230private:
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
246bool 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
254class SimpleAllocation : public vk::Allocation
255{
256public:
257								SimpleAllocation	(const vk::DeviceInterface&	vkd,
258													 vk::VkDevice				device,
259													 const vk::VkDeviceMemory	memory);
260								~SimpleAllocation	(void);
261
262private:
263	const vk::DeviceInterface&	m_vkd;
264	const vk::VkDevice			m_device;
265};
266
267SimpleAllocation::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
276SimpleAllocation::~SimpleAllocation (void)
277{
278	m_vkd.freeMemory(m_device, getMemory(), DE_NULL);
279}
280
281class DeviceId
282{
283public:
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
292private:
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
299DeviceId::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
310bool 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
327DeviceId 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
346vk::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
369vk::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
376vk::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
391vk::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
482vk::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
493vk::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
509vk::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
527de::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
577de::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
626de::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
722de::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
740de::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
757de::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
853void 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
912void 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
971std::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
981class SharingTestInstance : public TestInstance
982{
983public:
984														SharingTestInstance		(Context&	context,
985																				 TestConfig	config);
986
987	virtual tcu::TestStatus								iterate					(void);
988
989private:
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
1025SharingTestInstance::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
1061tcu::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
1258struct 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
1272tcu::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