1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 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 with DX11 keyed mutex
22 *//*--------------------------------------------------------------------*/
23
24#include "vktSynchronizationWin32KeyedMutexTests.hpp"
25
26#include "vkDeviceUtil.hpp"
27#include "vkPlatform.hpp"
28
29#include "vktTestCaseUtil.hpp"
30
31#include "vktSynchronizationUtil.hpp"
32#include "vktSynchronizationOperation.hpp"
33#include "vktSynchronizationOperationTestData.hpp"
34#include "vktExternalMemoryUtil.hpp"
35
36#include "tcuResultCollector.hpp"
37#include "tcuTestLog.hpp"
38
39#if (DE_OS == DE_OS_WIN32)
40#	define WIN32_LEAN_AND_MEAN
41#	define NOMINMAX
42#	include <windows.h>
43#	include <aclapi.h>
44#	include "VersionHelpers.h"
45#	include "d3d11_2.h"
46#	include "d3dcompiler.h"
47
48typedef HRESULT				(WINAPI * LPD3DX11COMPILEFROMMEMORY)(LPCSTR,
49																 SIZE_T,
50																 LPCSTR,
51																 CONST D3D10_SHADER_MACRO*,
52																 LPD3D10INCLUDE,
53																 LPCSTR,
54																 LPCSTR,
55																 UINT,
56																 UINT,
57																 void*, /* ID3DX11ThreadPump */
58																 ID3D10Blob** ,
59																 ID3D10Blob** ,
60																 HRESULT*);
61#endif
62
63using tcu::TestLog;
64using namespace vkt::ExternalMemoryUtil;
65
66namespace vkt
67{
68using namespace vk;
69namespace synchronization
70{
71namespace
72{
73
74static const ResourceDescription s_resourcesWin32KeyedMutex[] =
75{
76	{ RESOURCE_TYPE_BUFFER,	tcu::IVec4( 0x4000, 0, 0, 0),	vk::VK_IMAGE_TYPE_LAST,	vk::VK_FORMAT_UNDEFINED,			(vk::VkImageAspectFlags)0	  },	// 16 KiB (min max UBO range)
77	{ RESOURCE_TYPE_BUFFER,	tcu::IVec4(0x40000, 0, 0, 0),	vk::VK_IMAGE_TYPE_LAST,	vk::VK_FORMAT_UNDEFINED,			(vk::VkImageAspectFlags)0	  },	// 256 KiB
78
79	{ RESOURCE_TYPE_IMAGE,	tcu::IVec4(128, 128, 0, 0),		vk::VK_IMAGE_TYPE_2D,	vk::VK_FORMAT_R8_UNORM,				vk::VK_IMAGE_ASPECT_COLOR_BIT },
80	{ RESOURCE_TYPE_IMAGE,	tcu::IVec4(128, 128, 0, 0),		vk::VK_IMAGE_TYPE_2D,	vk::VK_FORMAT_R16_UINT,				vk::VK_IMAGE_ASPECT_COLOR_BIT },
81	{ RESOURCE_TYPE_IMAGE,	tcu::IVec4(128, 128, 0, 0),		vk::VK_IMAGE_TYPE_2D,	vk::VK_FORMAT_R8G8B8A8_UNORM,		vk::VK_IMAGE_ASPECT_COLOR_BIT },
82	{ RESOURCE_TYPE_IMAGE,	tcu::IVec4(128, 128, 0, 0),		vk::VK_IMAGE_TYPE_2D,	vk::VK_FORMAT_R16G16B16A16_UINT,	vk::VK_IMAGE_ASPECT_COLOR_BIT },
83	{ RESOURCE_TYPE_IMAGE,	tcu::IVec4(128, 128, 0, 0),		vk::VK_IMAGE_TYPE_2D,	vk::VK_FORMAT_R32G32B32A32_SFLOAT,	vk::VK_IMAGE_ASPECT_COLOR_BIT },
84};
85
86struct TestConfig
87{
88								TestConfig		(const ResourceDescription&					resource_,
89												 OperationName								writeOp_,
90												 OperationName								readOp_,
91												 vk::VkExternalMemoryHandleTypeFlagBits		memoryHandleTypeBuffer_,
92												 vk::VkExternalMemoryHandleTypeFlagBits		memoryHandleTypeImage_)
93		: resource					(resource_)
94		, writeOp					(writeOp_)
95		, readOp					(readOp_)
96		, memoryHandleTypeBuffer	(memoryHandleTypeBuffer_)
97		, memoryHandleTypeImage		(memoryHandleTypeImage_)
98	{
99	}
100
101	const ResourceDescription							resource;
102	const OperationName									writeOp;
103	const OperationName									readOp;
104	const vk::VkExternalMemoryHandleTypeFlagBits		memoryHandleTypeBuffer;
105	const vk::VkExternalMemoryHandleTypeFlagBits		memoryHandleTypeImage;
106};
107
108bool checkQueueFlags (vk::VkQueueFlags availableFlags, const vk::VkQueueFlags neededFlags)
109{
110	if ((availableFlags & (vk::VK_QUEUE_GRAPHICS_BIT | vk::VK_QUEUE_COMPUTE_BIT)) != 0)
111		availableFlags |= vk::VK_QUEUE_TRANSFER_BIT;
112
113	return (availableFlags & neededFlags) != 0;
114}
115
116class SimpleAllocation : public vk::Allocation
117{
118public:
119								SimpleAllocation	(const vk::DeviceInterface&	vkd,
120													 vk::VkDevice				device,
121													 const vk::VkDeviceMemory	memory);
122								~SimpleAllocation	(void);
123
124private:
125	const vk::DeviceInterface&	m_vkd;
126	const vk::VkDevice			m_device;
127};
128
129SimpleAllocation::SimpleAllocation (const vk::DeviceInterface&	vkd,
130									vk::VkDevice				device,
131									const vk::VkDeviceMemory	memory)
132	: Allocation	(memory, 0, DE_NULL)
133	, m_vkd			(vkd)
134	, m_device		(device)
135{
136}
137
138SimpleAllocation::~SimpleAllocation (void)
139{
140	m_vkd.freeMemory(m_device, getMemory(), DE_NULL);
141}
142
143vk::Move<vk::VkInstance> createInstance (const vk::PlatformInterface& vkp, deUint32 version)
144{
145	try
146	{
147		std::vector<std::string> extensions;
148		if (!isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2"))
149			extensions.push_back("VK_KHR_get_physical_device_properties2");
150		if (!isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2"))
151			extensions.push_back("VK_KHR_external_memory_capabilities");
152
153		return vk::createDefaultInstance(vkp, version, std::vector<std::string>(), extensions);
154	}
155	catch (const vk::Error& error)
156	{
157		if (error.getError() == vk::VK_ERROR_EXTENSION_NOT_PRESENT)
158			TCU_THROW(NotSupportedError, "Required external memory extensions not supported by the instance");
159		else
160			throw;
161	}
162}
163
164vk::VkPhysicalDevice getPhysicalDevice (const vk::InstanceInterface&	vki,
165										vk::VkInstance					instance,
166										const tcu::CommandLine&			cmdLine)
167{
168	return vk::chooseDevice(vki, instance, cmdLine);
169}
170
171vk::Move<vk::VkDevice> createDevice (const deUint32									apiVersion,
172									 const vk::InstanceInterface&					vki,
173									 vk::VkPhysicalDevice							physicalDevice)
174{
175	const float										priority				= 0.0f;
176	const std::vector<vk::VkQueueFamilyProperties>	queueFamilyProperties	= vk::getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
177	std::vector<deUint32>							queueFamilyIndices		(queueFamilyProperties.size(), 0xFFFFFFFFu);
178	std::vector<const char*>						extensions;
179
180	if (!isCoreDeviceExtension(apiVersion, "VK_KHR_external_memory"))
181		extensions.push_back("VK_KHR_external_memory");
182	if (!isCoreDeviceExtension(apiVersion, "VK_KHR_dedicated_allocation"))
183		extensions.push_back("VK_KHR_dedicated_allocation");
184	if (!isCoreDeviceExtension(apiVersion, "VK_KHR_get_memory_requirements2"))
185		extensions.push_back("VK_KHR_get_memory_requirements2");
186
187	extensions.push_back("VK_KHR_external_memory_win32");
188	extensions.push_back("VK_KHR_win32_keyed_mutex");
189
190	try
191	{
192		std::vector<vk::VkDeviceQueueCreateInfo>	queues;
193
194		for (size_t ndx = 0; ndx < queueFamilyProperties.size(); ndx++)
195		{
196			const vk::VkDeviceQueueCreateInfo	createInfo	=
197			{
198				vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
199				DE_NULL,
200				0u,
201
202				(deUint32)ndx,
203				1u,
204				&priority
205			};
206
207			queues.push_back(createInfo);
208		}
209
210		const vk::VkDeviceCreateInfo		createInfo			=
211		{
212			vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
213			DE_NULL,
214			0u,
215
216			(deUint32)queues.size(),
217			&queues[0],
218
219			0u,
220			DE_NULL,
221
222			(deUint32)extensions.size(),
223			extensions.empty() ? DE_NULL : &extensions[0],
224			0u
225		};
226
227		return vk::createDevice(vki, physicalDevice, &createInfo);
228	}
229	catch (const vk::Error& error)
230	{
231		if (error.getError() == vk::VK_ERROR_EXTENSION_NOT_PRESENT)
232			TCU_THROW(NotSupportedError, "Required extensions not supported");
233		else
234			throw;
235	}
236}
237
238deUint32 chooseMemoryType (deUint32 bits)
239{
240	DE_ASSERT(bits != 0);
241
242	for (deUint32 memoryTypeIndex = 0; (1u << memoryTypeIndex) <= bits; memoryTypeIndex++)
243	{
244		if ((bits & (1u << memoryTypeIndex)) != 0)
245			return memoryTypeIndex;
246	}
247
248	DE_FATAL("No supported memory types");
249	return -1;
250}
251
252vk::Move<vk::VkDeviceMemory> importMemory (const vk::DeviceInterface&				vkd,
253										   vk::VkDevice								device,
254										   const vk::VkMemoryRequirements&			requirements,
255										   vk::VkExternalMemoryHandleTypeFlagBits	externalType,
256										   NativeHandle&							handle,
257										   bool										requiresDedicated,
258										   vk::VkBuffer								buffer,
259										   vk::VkImage								image)
260{
261	const vk::VkMemoryDedicatedAllocateInfo	dedicatedInfo	=
262	{
263		vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
264		DE_NULL,
265		image,
266		buffer,
267	};
268	const vk::VkImportMemoryWin32HandleInfoKHR	importInfo		=
269	{
270		vk::VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
271		(requiresDedicated) ? &dedicatedInfo : DE_NULL,
272		externalType,
273		handle.getWin32Handle(),
274        NULL
275	};
276
277	const vk::VkMemoryAllocateInfo				info			=
278	{
279		vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
280		&importInfo,
281		requirements.size,
282		chooseMemoryType(requirements.memoryTypeBits)
283	};
284
285	vk::Move<vk::VkDeviceMemory> memory (vk::allocateMemory(vkd, device, &info));
286
287	handle.disown();
288
289	return memory;
290}
291
292de::MovePtr<vk::Allocation> importAndBindMemory (const vk::DeviceInterface&					vkd,
293												 vk::VkDevice								device,
294												 vk::VkBuffer								buffer,
295												 NativeHandle&								nativeHandle,
296												 vk::VkExternalMemoryHandleTypeFlagBits		externalType)
297{
298	const vk::VkBufferMemoryRequirementsInfo2	requirementsInfo		=
299	{
300		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
301		DE_NULL,
302		buffer,
303	};
304	vk::VkMemoryDedicatedRequirements			dedicatedRequirements	=
305	{
306		vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
307		DE_NULL,
308		VK_FALSE,
309		VK_FALSE,
310	};
311	vk::VkMemoryRequirements2					requirements			=
312	{
313		vk::VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
314		&dedicatedRequirements,
315		{ 0u, 0u, 0u, },
316	};
317	vkd.getBufferMemoryRequirements2(device, &requirementsInfo, &requirements);
318
319	vk::Move<vk::VkDeviceMemory> memory = importMemory(vkd, device, requirements.memoryRequirements, externalType, nativeHandle, !!dedicatedRequirements.requiresDedicatedAllocation, buffer, DE_NULL);
320	VK_CHECK(vkd.bindBufferMemory(device, buffer, *memory, 0u));
321
322	return de::MovePtr<vk::Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
323}
324
325de::MovePtr<vk::Allocation> importAndBindMemory (const vk::DeviceInterface&						vkd,
326												 vk::VkDevice									device,
327												 vk::VkImage									image,
328												 NativeHandle&									nativeHandle,
329												 vk::VkExternalMemoryHandleTypeFlagBits			externalType)
330{
331	const vk::VkImageMemoryRequirementsInfo2	requirementsInfo		=
332	{
333		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
334		DE_NULL,
335		image,
336	};
337	vk::VkMemoryDedicatedRequirements			dedicatedRequirements	=
338	{
339		vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
340		DE_NULL,
341		VK_FALSE,
342		VK_FALSE,
343	};
344	vk::VkMemoryRequirements2					requirements			=
345	{
346		vk::VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
347		&dedicatedRequirements,
348		{ 0u, 0u, 0u, },
349	};
350	vkd.getImageMemoryRequirements2(device, &requirementsInfo, &requirements);
351
352	vk::Move<vk::VkDeviceMemory> memory = importMemory(vkd, device, requirements.memoryRequirements, externalType, nativeHandle, !!dedicatedRequirements.requiresDedicatedAllocation, DE_NULL, image);
353	VK_CHECK(vkd.bindImageMemory(device, image, *memory, 0u));
354
355	return de::MovePtr<vk::Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
356}
357
358de::MovePtr<Resource> importResource (const vk::DeviceInterface&				vkd,
359									  vk::VkDevice								device,
360									  const ResourceDescription&				resourceDesc,
361									  const std::vector<deUint32>&				queueFamilyIndices,
362									  const OperationSupport&					readOp,
363									  const OperationSupport&					writeOp,
364									  NativeHandle&								nativeHandle,
365									  vk::VkExternalMemoryHandleTypeFlagBits	externalType)
366{
367	if (resourceDesc.type == RESOURCE_TYPE_IMAGE)
368	{
369		const vk::VkExtent3D								extent					=
370		{
371			(deUint32)resourceDesc.size.x(),
372			de::max(1u, (deUint32)resourceDesc.size.y()),
373			de::max(1u, (deUint32)resourceDesc.size.z())
374		};
375		const vk::VkImageSubresourceRange					subresourceRange		=
376		{
377			resourceDesc.imageAspect,
378			0u,
379			1u,
380			0u,
381			1u
382		};
383		const vk::VkImageSubresourceLayers					subresourceLayers		=
384		{
385			resourceDesc.imageAspect,
386			0u,
387			0u,
388			1u
389		};
390		const vk::VkExternalMemoryImageCreateInfo			externalInfo			=
391		{
392			vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
393			DE_NULL,
394			(vk::VkExternalMemoryHandleTypeFlags)externalType
395		};
396		const vk::VkImageCreateInfo							createInfo				=
397		{
398			vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
399			&externalInfo,
400			0u,
401
402			resourceDesc.imageType,
403			resourceDesc.imageFormat,
404			extent,
405			1u,
406			1u,
407			vk::VK_SAMPLE_COUNT_1_BIT,
408			vk::VK_IMAGE_TILING_OPTIMAL,
409			readOp.getResourceUsageFlags() | writeOp.getResourceUsageFlags(),
410			vk::VK_SHARING_MODE_EXCLUSIVE,
411
412			(deUint32)queueFamilyIndices.size(),
413			&queueFamilyIndices[0],
414			vk::VK_IMAGE_LAYOUT_UNDEFINED
415		};
416
417		vk::Move<vk::VkImage>								image					= vk::createImage(vkd, device, &createInfo);
418		de::MovePtr<vk::Allocation>							allocation				= importAndBindMemory(vkd, device, *image, nativeHandle, externalType);
419
420		return de::MovePtr<Resource>(new Resource(image, allocation, extent, resourceDesc.imageType, resourceDesc.imageFormat, subresourceRange, subresourceLayers));
421	}
422	else
423	{
424		const vk::VkDeviceSize								offset					= 0u;
425		const vk::VkDeviceSize								size					= static_cast<vk::VkDeviceSize>(resourceDesc.size.x());
426		const vk::VkBufferUsageFlags						usage					= readOp.getResourceUsageFlags() | writeOp.getResourceUsageFlags();
427		const vk::VkExternalMemoryBufferCreateInfo			externalInfo			=
428		{
429			vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
430			DE_NULL,
431			(vk::VkExternalMemoryHandleTypeFlags)externalType
432		};
433		const vk::VkBufferCreateInfo						createInfo				=
434		{
435			vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
436			&externalInfo,
437			0u,
438
439			size,
440			usage,
441			vk::VK_SHARING_MODE_EXCLUSIVE,
442			(deUint32)queueFamilyIndices.size(),
443			&queueFamilyIndices[0]
444		};
445		vk::Move<vk::VkBuffer>								buffer					= vk::createBuffer(vkd, device, &createInfo);
446		de::MovePtr<vk::Allocation>							allocation				= importAndBindMemory(vkd, device, *buffer, nativeHandle, externalType);
447
448		return de::MovePtr<Resource>(new Resource(resourceDesc.type, buffer, allocation, offset, size));
449	}
450}
451
452void recordWriteBarrier (const vk::DeviceInterface&	vkd,
453						 vk::VkCommandBuffer		commandBuffer,
454						 const Resource&			resource,
455						 const SyncInfo&			writeSync,
456						 deUint32					writeQueueFamilyIndex,
457						 const SyncInfo&			readSync)
458{
459	const vk::VkPipelineStageFlags		srcStageMask		= writeSync.stageMask;
460	const vk::VkAccessFlags				srcAccessMask		= writeSync.accessMask;
461
462	const vk::VkPipelineStageFlags		dstStageMask		= readSync.stageMask;
463	const vk::VkAccessFlags				dstAccessMask		= readSync.accessMask;
464
465	const vk::VkDependencyFlags			dependencyFlags		= 0;
466
467	if (resource.getType() == RESOURCE_TYPE_IMAGE)
468	{
469		const vk::VkImageMemoryBarrier	barrier				=
470		{
471			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
472			DE_NULL,
473
474			srcAccessMask,
475			dstAccessMask,
476
477			writeSync.imageLayout,
478			readSync.imageLayout,
479
480			writeQueueFamilyIndex,
481			VK_QUEUE_FAMILY_EXTERNAL,
482
483			resource.getImage().handle,
484			resource.getImage().subresourceRange
485		};
486
487		vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0u, (const vk::VkMemoryBarrier*)DE_NULL, 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1u, (const vk::VkImageMemoryBarrier*)&barrier);
488	}
489	else
490	{
491		const vk::VkBufferMemoryBarrier	barrier				=
492		{
493			vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
494			DE_NULL,
495
496			srcAccessMask,
497			dstAccessMask,
498
499			writeQueueFamilyIndex,
500			VK_QUEUE_FAMILY_EXTERNAL,
501
502			resource.getBuffer().handle,
503			0u,
504			VK_WHOLE_SIZE
505		};
506
507		vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0u, (const vk::VkMemoryBarrier*)DE_NULL, 1u, (const vk::VkBufferMemoryBarrier*)&barrier, 0u, (const vk::VkImageMemoryBarrier*)DE_NULL);
508	}
509}
510
511void recordReadBarrier (const vk::DeviceInterface&	vkd,
512						vk::VkCommandBuffer			commandBuffer,
513						const Resource&				resource,
514						const SyncInfo&				writeSync,
515						const SyncInfo&				readSync,
516						deUint32					readQueueFamilyIndex)
517{
518	const vk::VkPipelineStageFlags		srcStageMask		= readSync.stageMask;
519	const vk::VkAccessFlags				srcAccessMask		= readSync.accessMask;
520
521	const vk::VkPipelineStageFlags		dstStageMask		= readSync.stageMask;
522	const vk::VkAccessFlags				dstAccessMask		= readSync.accessMask;
523
524	const vk::VkDependencyFlags			dependencyFlags		= 0;
525
526	if (resource.getType() == RESOURCE_TYPE_IMAGE)
527	{
528		const vk::VkImageMemoryBarrier	barrier				=
529		{
530			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
531			DE_NULL,
532
533			srcAccessMask,
534			dstAccessMask,
535
536			writeSync.imageLayout,
537			readSync.imageLayout,
538
539			VK_QUEUE_FAMILY_EXTERNAL,
540			readQueueFamilyIndex,
541
542			resource.getImage().handle,
543			resource.getImage().subresourceRange
544		};
545
546		vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0u, (const vk::VkMemoryBarrier*)DE_NULL, 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1u, (const vk::VkImageMemoryBarrier*)&barrier);
547	}
548	else
549	{
550		const vk::VkBufferMemoryBarrier	barrier				=
551		{
552			vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
553			DE_NULL,
554
555			srcAccessMask,
556			dstAccessMask,
557
558			VK_QUEUE_FAMILY_EXTERNAL,
559			readQueueFamilyIndex,
560
561			resource.getBuffer().handle,
562			0u,
563			VK_WHOLE_SIZE
564		};
565
566		vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0u, (const vk::VkMemoryBarrier*)DE_NULL, 1u, (const vk::VkBufferMemoryBarrier*)&barrier, 0u, (const vk::VkImageMemoryBarrier*)DE_NULL);
567	}
568}
569
570std::vector<deUint32> getFamilyIndices (const std::vector<vk::VkQueueFamilyProperties>& properties)
571{
572	std::vector<deUint32> indices (properties.size(), 0);
573
574	for (deUint32 ndx = 0; ndx < properties.size(); ndx++)
575		indices[ndx] = ndx;
576
577	return indices;
578}
579
580class DX11Operation
581{
582public:
583	enum Buffer
584	{
585		BUFFER_VK_WRITE,
586		BUFFER_VK_READ,
587		BUFFER_COUNT,
588	};
589
590	enum KeyedMutex
591	{
592		KEYED_MUTEX_INIT		= 0,
593		KEYED_MUTEX_VK_WRITE	= 1,
594		KEYED_MUTEX_DX_COPY		= 2,
595		KEYED_MUTEX_VK_VERIFY	= 3,
596		KEYED_MUTEX_DONE		= 4,
597	};
598
599#if (DE_OS == DE_OS_WIN32)
600	DX11Operation (const ResourceDescription&					resourceDesc,
601				   vk::VkExternalMemoryHandleTypeFlagBits		memoryHandleType,
602				   ID3D11Device*								pDevice,
603				   ID3D11DeviceContext*							pContext,
604				   LPD3DX11COMPILEFROMMEMORY					fnD3DX11CompileFromMemory,
605				   pD3DCompile									fnD3DCompile)
606		: m_resourceDesc				(resourceDesc)
607
608		, m_pDevice						(pDevice)
609		, m_pContext					(pContext)
610		, m_fnD3DX11CompileFromMemory	(fnD3DX11CompileFromMemory)
611		, m_fnD3DCompile				(fnD3DCompile)
612
613		, m_pRenderTargetView			(0)
614		, m_pVertexShader				(0)
615		, m_pPixelShader				(0)
616		, m_pVertexBuffer				(0)
617		, m_pTextureRV					(0)
618		, m_pSamplerLinear				(0)
619		, m_numFrames					(0)
620	{
621		HRESULT	hr;
622
623		if (memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT ||
624			memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT)
625
626			m_isMemNtHandle = true;
627		else
628			m_isMemNtHandle = false;
629
630		m_securityAttributes.lpSecurityDescriptor = 0;
631
632		for (UINT i = 0; i < BUFFER_COUNT; i++)
633		{
634			m_pTexture[i] = NULL;
635			m_pBuffer[i] = NULL;
636			m_keyedMutex[i] = NULL;
637		}
638
639		if (m_resourceDesc.type == RESOURCE_TYPE_BUFFER)
640		{
641			// SHARED_NTHANDLE is not supported with CreateBuffer().
642			TCU_CHECK_INTERNAL(!m_isMemNtHandle);
643
644			D3D11_BUFFER_DESC descBuf = { };
645			descBuf.ByteWidth = (UINT)m_resourceDesc.size.x();
646			descBuf.Usage = D3D11_USAGE_DEFAULT;
647			descBuf.BindFlags = 0;
648			descBuf.CPUAccessFlags = 0;
649			descBuf.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
650			descBuf.StructureByteStride = 0;
651
652			for (UINT i = 0; i < BUFFER_COUNT; ++i)
653			{
654				hr = m_pDevice->CreateBuffer(&descBuf, NULL, &m_pBuffer[i]);
655				if (FAILED(hr))
656					TCU_FAIL("Failed to create a buffer");
657
658				m_sharedMemHandle[i] = 0;
659
660				IDXGIResource* tempResource = NULL;
661				hr = m_pBuffer[i]->QueryInterface(__uuidof(IDXGIResource), (void**)&tempResource);
662				if (FAILED(hr))
663					TCU_FAIL("Query interface of IDXGIResource failed");
664				hr = tempResource->GetSharedHandle(&m_sharedMemHandle[i]);
665				tempResource->Release();
666				if (FAILED(hr))
667					TCU_FAIL("Failed to get DX shared handle");
668
669				hr = m_pBuffer[i]->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&m_keyedMutex[i]);
670				if (FAILED(hr))
671					TCU_FAIL("Query interface of IDXGIKeyedMutex failed");
672
673				// Take ownership of the lock.
674				m_keyedMutex[i]->AcquireSync(KEYED_MUTEX_INIT, INFINITE);
675			}
676
677			// Release the buffer write lock for Vulkan to write into.
678			m_keyedMutex[BUFFER_VK_WRITE]->ReleaseSync(KEYED_MUTEX_VK_WRITE);
679
680			m_sharedMemSize = descBuf.ByteWidth;
681			m_sharedMemOffset = 0;
682		}
683		else
684		{
685			DE_ASSERT(m_resourceDesc.type == RESOURCE_TYPE_IMAGE);
686
687			for (UINT i = 0; i < BUFFER_COUNT; ++i)
688			{
689				D3D11_TEXTURE2D_DESC descColor = { };
690				descColor.Width = m_resourceDesc.size.x();
691				descColor.Height = m_resourceDesc.size.y();
692				descColor.MipLevels = 1;
693				descColor.ArraySize = 1;
694				descColor.Format = getDxgiFormat(m_resourceDesc.imageFormat);
695				descColor.SampleDesc.Count = 1;
696				descColor.SampleDesc.Quality = 0;
697				descColor.Usage = D3D11_USAGE_DEFAULT;
698				descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
699				descColor.CPUAccessFlags = 0;
700
701				if (m_isMemNtHandle)
702					descColor.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
703				else
704					descColor.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
705
706				hr = m_pDevice->CreateTexture2D(&descColor, NULL, &m_pTexture[i]);
707				if (FAILED(hr))
708					TCU_FAIL("Unable to create DX11 texture");
709
710				m_sharedMemHandle[i] = 0;
711
712				if (m_isMemNtHandle)
713				{
714					IDXGIResource1* tempResource1 = NULL;
715					hr = m_pTexture[i]->QueryInterface(__uuidof(IDXGIResource1), (void**)&tempResource1);
716					if (FAILED(hr))
717						TCU_FAIL("Unable to query IDXGIResource1 interface");
718
719					hr = tempResource1->CreateSharedHandle(getSecurityAttributes(), DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, /*lpName*/NULL, &m_sharedMemHandle[i]);
720					tempResource1->Release();
721					if (FAILED(hr))
722						TCU_FAIL("Enable to get DX shared handle");
723				}
724				else
725				{
726					IDXGIResource* tempResource = NULL;
727					hr = m_pTexture[i]->QueryInterface(__uuidof(IDXGIResource), (void**)&tempResource);
728					if (FAILED(hr))
729						TCU_FAIL("Query interface of IDXGIResource failed");
730					hr = tempResource->GetSharedHandle(&m_sharedMemHandle[i]);
731					tempResource->Release();
732					if (FAILED(hr))
733						TCU_FAIL("Failed to get DX shared handle");
734				}
735
736				hr = m_pTexture[i]->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&m_keyedMutex[i]);
737				if (FAILED(hr))
738					TCU_FAIL("Unable to query DX11 keyed mutex interface");
739
740				// Take ownership of the lock.
741				m_keyedMutex[i]->AcquireSync(KEYED_MUTEX_INIT, INFINITE);
742			}
743
744			m_sharedMemSize = 0;
745			m_sharedMemOffset = 0;
746
747			hr = m_pDevice->CreateRenderTargetView(m_pTexture[BUFFER_VK_READ], NULL, &m_pRenderTargetView);
748			if (FAILED(hr))
749				TCU_FAIL("Unable to create DX11 render target view");
750
751			m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, NULL);
752
753			// Setup the viewport
754			D3D11_VIEWPORT vp;
755			vp.Width = (FLOAT)m_resourceDesc.size.x();
756			vp.Height = (FLOAT)m_resourceDesc.size.y();
757			vp.MinDepth = 0.0f;
758			vp.MaxDepth = 1.0f;
759			vp.TopLeftX = 0;
760			vp.TopLeftY = 0;
761			m_pContext->RSSetViewports(1, &vp);
762
763			// Compile the vertex shader
764			LPCSTR shader =
765				"Texture2D txDiffuse : register(t0);\n"
766				"SamplerState samLinear : register(s0);\n"
767				"struct VS_INPUT\n"
768				"{\n"
769				"    float4 Pos : POSITION;\n"
770				"    float2 Tex : TEXCOORD0;\n"
771				"};\n"
772				"struct PS_INPUT\n"
773				"{\n"
774				"    float4 Pos : SV_POSITION;\n"
775				"    float2 Tex : TEXCOORD0;\n"
776				"};\n"
777				"PS_INPUT VS(VS_INPUT input)\n"
778				"{\n"
779				"    PS_INPUT output = (PS_INPUT)0;\n"
780				"    output.Pos = input.Pos;\n"
781				"    output.Tex = input.Tex;\n"
782				"\n"
783				"    return output;\n"
784				"}\n"
785				"float4 PS(PS_INPUT input) : SV_Target\n"
786				"{\n"
787				"    return txDiffuse.Sample(samLinear, input.Tex);\n"
788				"}\n";
789
790			// Define the input layout
791			D3D11_INPUT_ELEMENT_DESC layout[] =
792			{
793				{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
794				{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
795			};
796
797			createShaders(shader, "VS", "vs_4_0", ARRAYSIZE(layout), layout, &m_pVertexShader, "PS", "ps_4_0", &m_pPixelShader);
798
799			struct SimpleVertex
800			{
801				float Pos[3];
802				float Tex[2];
803			};
804
805			SimpleVertex vertices[] =
806			{
807				{ { -1.f, -1.f, 0.0f }, { 0.0f, 1.0f } },
808				{ { -1.f,  1.f, 0.0f }, { 0.0f, 0.0f } },
809				{ {  1.f, -1.f, 0.0f }, { 1.0f, 1.0f } },
810				{ {  1.f,  1.f, 0.0f }, { 1.0f, 0.0f } },
811			};
812
813			D3D11_BUFFER_DESC bd = { };
814			bd.Usage = D3D11_USAGE_DEFAULT;
815			bd.ByteWidth = sizeof (vertices);
816			bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
817			bd.CPUAccessFlags = 0;
818			D3D11_SUBRESOURCE_DATA InitData = { };
819			InitData.pSysMem = vertices;
820			hr = m_pDevice->CreateBuffer(&bd, &InitData, &m_pVertexBuffer);
821			if (FAILED(hr))
822				TCU_FAIL("Failed to create DX11 vertex buffer");
823
824			// Set vertex buffer
825			UINT stride = sizeof (SimpleVertex);
826			UINT offset = 0;
827			m_pContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &stride, &offset);
828
829			// Set primitive topology
830			m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
831
832			m_pTextureRV = NULL;
833
834			D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = { };
835			SRVDesc.Format = getDxgiFormat(m_resourceDesc.imageFormat);
836			SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
837			SRVDesc.Texture2D.MipLevels = 1;
838
839			hr = m_pDevice->CreateShaderResourceView(m_pTexture[BUFFER_VK_WRITE], &SRVDesc, &m_pTextureRV);
840			if (FAILED(hr))
841				TCU_FAIL("Failed to create DX11 resource view");
842
843			// Create the sample state
844			D3D11_SAMPLER_DESC sampDesc = { };
845			sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
846			sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
847			sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
848			sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
849			sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
850			sampDesc.MinLOD = 0;
851			sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
852			hr = m_pDevice->CreateSamplerState(&sampDesc, &m_pSamplerLinear);
853			if (FAILED(hr))
854				TCU_FAIL("Failed to create DX11 sampler state");
855
856			// Release the lock for VK to write into the texture.
857			m_keyedMutex[BUFFER_VK_WRITE]->ReleaseSync(KEYED_MUTEX_VK_WRITE);
858		}
859	}
860
861	~DX11Operation ()
862	{
863		cleanup();
864	}
865#endif // #if (DE_OS == DE_OS_WIN32)
866
867	NativeHandle getNativeHandle (Buffer buffer)
868	{
869#if (DE_OS == DE_OS_WIN32)
870		return NativeHandle((m_isMemNtHandle) ? NativeHandle::WIN32HANDLETYPE_NT : NativeHandle::WIN32HANDLETYPE_KMT, vk::pt::Win32Handle(m_sharedMemHandle[buffer]));
871#else
872		DE_UNREF(buffer);
873		return NativeHandle();
874#endif
875	}
876
877	void copyMemory ()
878	{
879#if (DE_OS == DE_OS_WIN32)
880		m_keyedMutex[BUFFER_VK_WRITE]->AcquireSync(KEYED_MUTEX_DX_COPY, INFINITE);
881
882		if (m_resourceDesc.type == RESOURCE_TYPE_BUFFER) {
883			m_pContext->CopySubresourceRegion(m_pBuffer[BUFFER_VK_READ], 0, 0, 0, 0, m_pBuffer[BUFFER_VK_WRITE], 0, NULL);
884		} else {
885			m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, NULL);
886
887			const FLOAT gray[] = { 0.f, 0.f, 1.f, 1.f };
888			m_pContext->ClearRenderTargetView(m_pRenderTargetView, gray);
889
890			m_pContext->VSSetShader(m_pVertexShader, NULL, 0);
891			m_pContext->PSSetShader(m_pPixelShader, NULL, 0);
892			m_pContext->PSSetShaderResources(0, 1, &m_pTextureRV);
893			m_pContext->PSSetSamplers(0, 1, &m_pSamplerLinear);
894			m_pContext->Draw(4, 0);
895		}
896
897		m_keyedMutex[BUFFER_VK_WRITE]->ReleaseSync(KEYED_MUTEX_DONE);
898		m_keyedMutex[BUFFER_VK_READ]->ReleaseSync(KEYED_MUTEX_VK_VERIFY);
899#endif // #if (DE_OS == DE_OS_WIN32)
900	}
901
902#if (DE_OS == DE_OS_WIN32)
903	void d3dx11CompileShader (const char* shaderCode, const char * entryPoint, const char* shaderModel, ID3D10Blob** ppBlobOut)
904	{
905		HRESULT hr;
906
907		ID3D10Blob* pErrorBlob;
908		hr = m_fnD3DX11CompileFromMemory (shaderCode,
909										  strlen(shaderCode),
910										  "Memory",
911										  NULL,
912										  NULL,
913										  entryPoint,
914										  shaderModel,
915										  0,
916										  0,
917										  NULL,
918										  ppBlobOut,
919										  &pErrorBlob,
920										  NULL);
921		if (pErrorBlob)
922			pErrorBlob->Release();
923
924		if (FAILED(hr))
925			TCU_FAIL("D3DX11CompileFromMemory failed to compile shader");
926	}
927
928	void d3dCompileShader (const char* shaderCode, const char * entryPoint, const char* shaderModel, ID3DBlob** ppBlobOut)
929	{
930		HRESULT hr;
931
932		ID3DBlob* pErrorBlob;
933		hr = m_fnD3DCompile (shaderCode,
934							 strlen(shaderCode),
935							 NULL,
936							 NULL,
937							 NULL,
938							 entryPoint,
939							 shaderModel,
940							 0,
941							 0,
942							 ppBlobOut,
943							 &pErrorBlob);
944		if (pErrorBlob)
945			pErrorBlob->Release();
946
947		if (FAILED(hr))
948			TCU_FAIL("D3DCompile failed to compile shader");
949	}
950
951	void createShaders (const char* shaderSrc,
952						const char* vsEntryPoint,
953						const char* vsShaderModel,
954						UINT numLayoutDesc,
955						D3D11_INPUT_ELEMENT_DESC* pLayoutDesc,
956						ID3D11VertexShader** pVertexShader,
957						const char* psEntryPoint,
958						const char* psShaderModel,
959						ID3D11PixelShader** pPixelShader)
960{
961		HRESULT	hr;
962
963		if (m_fnD3DX11CompileFromMemory) {
964			// VS
965			ID3D10Blob* pVSBlob;
966			d3dx11CompileShader(shaderSrc, vsEntryPoint, vsShaderModel, &pVSBlob);
967
968			hr = m_pDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, pVertexShader);
969			if (FAILED(hr))
970				TCU_FAIL("Failed to create DX11 vertex shader");
971
972			ID3D11InputLayout *pVertexLayout;
973			hr = m_pDevice->CreateInputLayout(pLayoutDesc, numLayoutDesc, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &pVertexLayout);
974			if (FAILED(hr))
975				TCU_FAIL("Failed to create vertex input layout");
976
977			m_pContext->IASetInputLayout(pVertexLayout);
978			pVertexLayout->Release();
979			pVSBlob->Release();
980
981			// PS
982			ID3D10Blob* pPSBlob;
983			d3dx11CompileShader(shaderSrc, psEntryPoint, psShaderModel, &pPSBlob);
984
985			hr = m_pDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, pPixelShader);
986			if (FAILED(hr))
987				TCU_FAIL("Failed to create DX11 pixel shader");
988		} else {
989			// VS
990			ID3DBlob* pVSBlob;
991			d3dCompileShader(shaderSrc, vsEntryPoint, vsShaderModel, &pVSBlob);
992
993			hr = m_pDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, pVertexShader);
994			if (FAILED(hr))
995				TCU_FAIL("Failed to create DX11 vertex shader");
996
997			ID3D11InputLayout *pVertexLayout;
998			hr = m_pDevice->CreateInputLayout(pLayoutDesc, numLayoutDesc, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &pVertexLayout);
999			if (FAILED(hr))
1000				TCU_FAIL("Failed to create vertex input layout");
1001
1002			m_pContext->IASetInputLayout(pVertexLayout);
1003			pVertexLayout->Release();
1004			pVSBlob->Release();
1005
1006			// PS
1007			ID3DBlob* pPSBlob;
1008			d3dCompileShader(shaderSrc, psEntryPoint, psShaderModel, &pPSBlob);
1009
1010			hr = m_pDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, pPixelShader);
1011			if (FAILED(hr))
1012				TCU_FAIL("Failed to create DX11 pixel shader");
1013		}
1014	}
1015#endif // #if (DE_OS == DE_OS_WIN32)
1016
1017private:
1018#if (DE_OS == DE_OS_WIN32)
1019	void cleanup ()
1020	{
1021		if (m_securityAttributes.lpSecurityDescriptor)
1022		{
1023			freeSecurityDescriptor(m_securityAttributes.lpSecurityDescriptor);
1024			m_securityAttributes.lpSecurityDescriptor = NULL;
1025		}
1026
1027		if (m_pContext)
1028			m_pContext->ClearState();
1029
1030		if (m_pRenderTargetView)
1031		{
1032			m_pRenderTargetView->Release();
1033			m_pRenderTargetView = NULL;
1034		}
1035
1036		if (m_pSamplerLinear)
1037		{
1038			m_pSamplerLinear->Release();
1039			m_pSamplerLinear = NULL;
1040		}
1041
1042		if (m_pTextureRV)
1043		{
1044			m_pTextureRV->Release();
1045			m_pTextureRV = NULL;
1046		}
1047
1048		if (m_pVertexBuffer)
1049		{
1050			m_pVertexBuffer->Release();
1051			m_pVertexBuffer = NULL;
1052		}
1053
1054		if (m_pVertexShader)
1055		{
1056			m_pVertexShader->Release();
1057			m_pVertexShader = NULL;
1058		}
1059
1060		if (m_pPixelShader)
1061		{
1062			m_pPixelShader->Release();
1063			m_pPixelShader = NULL;
1064		}
1065
1066		for (int i = 0; i < BUFFER_COUNT; i++)
1067		{
1068			if (m_keyedMutex[i])
1069			{
1070				m_keyedMutex[i]->AcquireSync(KEYED_MUTEX_DONE, INFINITE);
1071				m_keyedMutex[i]->Release();
1072				m_keyedMutex[i] = NULL;
1073			}
1074
1075			if (m_isMemNtHandle && m_sharedMemHandle[i]) {
1076				CloseHandle(m_sharedMemHandle[i]);
1077				m_sharedMemHandle[i] = 0;
1078			}
1079
1080			if (m_pBuffer[i]) {
1081				m_pBuffer[i]->Release();
1082				m_pBuffer[i] = NULL;
1083			}
1084
1085			if (m_pTexture[i]) {
1086				m_pTexture[i]->Release();
1087				m_pTexture[i] = NULL;
1088			}
1089		}
1090	}
1091
1092	static void* getSecurityDescriptor ()
1093	{
1094		PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)deCalloc(SECURITY_DESCRIPTOR_MIN_LENGTH + 2 * sizeof (void**));
1095
1096		if (pSD)
1097		{
1098			PSID*	ppEveryoneSID	= (PSID*)((PBYTE)pSD + SECURITY_DESCRIPTOR_MIN_LENGTH);
1099			PACL*	ppACL			= (PACL*)((PBYTE)ppEveryoneSID + sizeof(PSID*));
1100
1101			InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
1102
1103			SID_IDENTIFIER_AUTHORITY	SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
1104			AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, ppEveryoneSID);
1105
1106			EXPLICIT_ACCESS	ea = { };
1107			ea.grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
1108			ea.grfAccessMode = SET_ACCESS;
1109			ea.grfInheritance = INHERIT_ONLY;
1110			ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
1111			ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
1112			ea.Trustee.ptstrName = (LPTSTR)*ppEveryoneSID;
1113
1114			SetEntriesInAcl(1, &ea, NULL, ppACL);
1115
1116			SetSecurityDescriptorDacl(pSD, TRUE, *ppACL, FALSE);
1117		}
1118
1119		return pSD;
1120	}
1121
1122	static void freeSecurityDescriptor (void* pSD)
1123	{
1124		if (pSD)
1125		{
1126			PSID*	ppEveryoneSID	= (PSID*)((PBYTE)pSD + SECURITY_DESCRIPTOR_MIN_LENGTH);
1127			PACL*	ppACL			= (PACL*)((PBYTE)ppEveryoneSID + sizeof(PSID*));
1128
1129			if (*ppEveryoneSID)
1130				FreeSid(*ppEveryoneSID);
1131
1132			if (*ppACL)
1133				LocalFree(*ppACL);
1134
1135			deFree(pSD);
1136		}
1137	}
1138
1139	static DXGI_FORMAT getDxgiFormat (vk::VkFormat format)
1140	{
1141		switch (format)
1142		{
1143			case vk::VK_FORMAT_R8_UNORM:
1144				return DXGI_FORMAT_R8_UNORM;
1145			case vk::VK_FORMAT_R16_UINT:
1146				return DXGI_FORMAT_R16_UINT;
1147			case vk::VK_FORMAT_R8G8B8A8_UNORM:
1148				return DXGI_FORMAT_R8G8B8A8_UNORM;
1149			case vk::VK_FORMAT_R16G16B16A16_UINT:
1150				return DXGI_FORMAT_R16G16B16A16_UINT;
1151			case vk::VK_FORMAT_R32G32B32A32_SFLOAT:
1152				return DXGI_FORMAT_R32G32B32A32_FLOAT;
1153			case vk::VK_FORMAT_D16_UNORM:
1154				return DXGI_FORMAT_D16_UNORM;
1155			case vk::VK_FORMAT_D32_SFLOAT:
1156				return DXGI_FORMAT_D32_FLOAT;
1157			default:
1158				TCU_CHECK_INTERNAL(!"Unsupported DXGI format");
1159				return DXGI_FORMAT_UNKNOWN;
1160		}
1161	}
1162
1163	ResourceDescription			m_resourceDesc;
1164
1165	deUint64					m_sharedMemSize;
1166	deUint64					m_sharedMemOffset;
1167	HANDLE						m_sharedMemHandle[BUFFER_COUNT];
1168	bool						m_isMemNtHandle;
1169
1170	ID3D11Device*				m_pDevice;
1171	ID3D11DeviceContext*		m_pContext;
1172	LPD3DX11COMPILEFROMMEMORY	m_fnD3DX11CompileFromMemory;
1173	pD3DCompile					m_fnD3DCompile;
1174
1175	ID3D11RenderTargetView*		m_pRenderTargetView;
1176	ID3D11VertexShader*			m_pVertexShader;
1177	ID3D11PixelShader*			m_pPixelShader;
1178	ID3D11Buffer*				m_pVertexBuffer;
1179	ID3D11ShaderResourceView*	m_pTextureRV;
1180	ID3D11SamplerState*			m_pSamplerLinear;
1181
1182	ID3D11Texture2D*			m_pTexture[BUFFER_COUNT];
1183	ID3D11Buffer*				m_pBuffer[BUFFER_COUNT];
1184	IDXGIKeyedMutex*			m_keyedMutex[BUFFER_COUNT];
1185	UINT						m_numFrames;
1186	SECURITY_ATTRIBUTES			m_securityAttributes;
1187
1188	SECURITY_ATTRIBUTES* getSecurityAttributes ()
1189	{
1190		m_securityAttributes.nLength = sizeof (SECURITY_ATTRIBUTES);
1191		m_securityAttributes.bInheritHandle = TRUE;
1192		if (!m_securityAttributes.lpSecurityDescriptor)
1193			m_securityAttributes.lpSecurityDescriptor = getSecurityDescriptor();
1194
1195		return &m_securityAttributes;
1196	}
1197#endif // #if (DE_OS == DE_OS_WIN32)
1198};
1199
1200class DX11OperationSupport
1201{
1202public:
1203	DX11OperationSupport (const vk::InstanceInterface&	vki,
1204						  vk::VkPhysicalDevice			physicalDevice,
1205						  const ResourceDescription&	resourceDesc)
1206		: m_resourceDesc			(resourceDesc)
1207#if (DE_OS == DE_OS_WIN32)
1208		, m_hD3D11Lib					(0)
1209		, m_hD3DX11Lib					(0)
1210		, m_hD3DCompilerLib				(0)
1211		, m_hDxgiLib					(0)
1212		, m_fnD3D11CreateDevice			(0)
1213		, m_fnD3DX11CompileFromMemory	(0)
1214		, m_fnD3DCompile				(0)
1215#endif
1216	{
1217#if (DE_OS == DE_OS_WIN32)
1218		HRESULT										hr;
1219
1220		vk::VkPhysicalDeviceIDProperties		propertiesId = { vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES };
1221		vk::VkPhysicalDeviceProperties2			properties = { vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
1222
1223		properties.pNext = &propertiesId;
1224
1225		vki.getPhysicalDeviceProperties2(physicalDevice, &properties);
1226		if (!propertiesId.deviceLUIDValid)
1227			TCU_FAIL("Physical device deviceLUIDValid is not valid");
1228
1229
1230		m_hD3D11Lib = LoadLibrary("d3d11.dll");
1231		if (!m_hD3D11Lib)
1232			TCU_FAIL("Failed to load d3d11.dll");
1233
1234
1235		m_fnD3D11CreateDevice = (LPD3D11CREATEDEVICE) GetProcAddress(m_hD3D11Lib, "D3D11CreateDevice");
1236		if (!m_fnD3D11CreateDevice)
1237			TCU_FAIL("Unable to find D3D11CreateDevice() function");
1238
1239		m_hD3DX11Lib = LoadLibrary("d3dx11_42.dll");
1240		if (m_hD3DX11Lib)
1241			m_fnD3DX11CompileFromMemory =  (LPD3DX11COMPILEFROMMEMORY) GetProcAddress(m_hD3DX11Lib, "D3DX11CompileFromMemory");
1242		else
1243		{
1244			m_hD3DCompilerLib = LoadLibrary("d3dcompiler_43.dll");
1245			if (!m_hD3DCompilerLib)
1246				m_hD3DCompilerLib = LoadLibrary("d3dcompiler_47.dll");
1247			if (!m_hD3DCompilerLib)
1248				TCU_FAIL("Unable to load DX11 d3dcompiler_43.dll or d3dcompiler_47.dll");
1249
1250			m_fnD3DCompile = (pD3DCompile)GetProcAddress(m_hD3DCompilerLib, "D3DCompile");
1251			if (!m_fnD3DCompile)
1252				TCU_FAIL("Unable to load find D3DCompile");
1253		}
1254
1255		m_hDxgiLib = LoadLibrary("dxgi.dll");
1256		if (!m_hDxgiLib)
1257			TCU_FAIL("Unable to load DX11 dxgi.dll");
1258
1259		typedef HRESULT (WINAPI *LPCREATEDXGIFACTORY1)(REFIID riid, void** ppFactory);
1260		LPCREATEDXGIFACTORY1 CreateDXGIFactory1 = (LPCREATEDXGIFACTORY1)GetProcAddress(m_hDxgiLib, "CreateDXGIFactory1");
1261		if (!CreateDXGIFactory1)
1262			TCU_FAIL("Unable to load find CreateDXGIFactory1");
1263
1264		IDXGIFactory1* pFactory = NULL;
1265		hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), (void**)&pFactory);
1266		if (FAILED(hr))
1267			TCU_FAIL("Unable to create IDXGIFactory interface");
1268
1269		IDXGIAdapter *pAdapter = NULL;
1270		for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
1271		{
1272			DXGI_ADAPTER_DESC desc;
1273			pAdapter->GetDesc(&desc);
1274
1275			if (deMemCmp(&desc.AdapterLuid, propertiesId.deviceLUID, VK_LUID_SIZE_KHR) == 0)
1276				break;
1277		}
1278		pFactory->Release();
1279
1280		D3D_FEATURE_LEVEL fLevel[] = {D3D_FEATURE_LEVEL_11_0};
1281		UINT devflags = D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS | // no separate D3D11 worker thread
1282#if 0
1283						D3D11_CREATE_DEVICE_DEBUG | // useful for diagnosing DX failures
1284#endif
1285						D3D11_CREATE_DEVICE_SINGLETHREADED;
1286
1287		hr = m_fnD3D11CreateDevice (pAdapter,
1288									pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE,
1289									NULL,
1290									devflags,
1291									fLevel,
1292									DE_LENGTH_OF_ARRAY(fLevel),
1293									D3D11_SDK_VERSION,
1294									&m_pDevice,
1295									NULL,
1296									&m_pContext);
1297
1298		if (pAdapter) {
1299			pAdapter->Release();
1300		}
1301
1302		if (!m_pDevice)
1303			TCU_FAIL("Failed to created DX11 device");
1304		if (!m_pContext)
1305			TCU_FAIL("Failed to created DX11 context");
1306#else
1307		DE_UNREF(vki);
1308		DE_UNREF(physicalDevice);
1309		TCU_THROW(NotSupportedError, "OS not supported");
1310#endif
1311	}
1312
1313	~DX11OperationSupport ()
1314	{
1315#if (DE_OS == DE_OS_WIN32)
1316		cleanup ();
1317#endif
1318	}
1319
1320#if (DE_OS == DE_OS_WIN32)
1321	void cleanup ()
1322	{
1323		if (m_pContext) {
1324			m_pContext->Release();
1325			m_pContext = 0;
1326		}
1327
1328		if (m_pDevice) {
1329			m_pDevice->Release();
1330			m_pDevice = 0;
1331		}
1332
1333		if (m_hDxgiLib)
1334		{
1335			FreeLibrary(m_hDxgiLib);
1336			m_hDxgiLib = 0;
1337		}
1338
1339		if (m_hD3DCompilerLib)
1340		{
1341			FreeLibrary(m_hD3DCompilerLib);
1342			m_hD3DCompilerLib = 0;
1343		}
1344
1345		if (m_hD3DX11Lib)
1346		{
1347			FreeLibrary(m_hD3DX11Lib);
1348			m_hD3DX11Lib = 0;
1349		}
1350
1351		if (m_hD3D11Lib)
1352		{
1353			FreeLibrary(m_hD3D11Lib);
1354			m_hD3D11Lib = 0;
1355		}
1356	}
1357
1358#endif
1359
1360	virtual de::MovePtr<DX11Operation> build (const ResourceDescription& resourceDesc, vk::VkExternalMemoryHandleTypeFlagBits memoryHandleType) const
1361	{
1362#if (DE_OS == DE_OS_WIN32)
1363		return de::MovePtr<DX11Operation>(new DX11Operation(resourceDesc, memoryHandleType, m_pDevice, m_pContext, m_fnD3DX11CompileFromMemory, m_fnD3DCompile));
1364#else
1365		DE_UNREF(resourceDesc);
1366		DE_UNREF(memoryHandleType);
1367		TCU_THROW(NotSupportedError, "OS not supported");
1368#endif
1369	}
1370
1371private:
1372	const ResourceDescription	m_resourceDesc;
1373
1374#if (DE_OS == DE_OS_WIN32)
1375	typedef HRESULT				(WINAPI *LPD3D11CREATEDEVICE)(IDXGIAdapter*,
1376															  D3D_DRIVER_TYPE,
1377															  HMODULE,
1378															  UINT,
1379															  const D3D_FEATURE_LEVEL*,
1380															  UINT,
1381															  UINT,
1382															  ID3D11Device **,
1383															  D3D_FEATURE_LEVEL*,
1384															  ID3D11DeviceContext**);
1385
1386	HMODULE						m_hD3D11Lib;
1387	HMODULE						m_hD3DX11Lib;
1388	HMODULE						m_hD3DCompilerLib;
1389	HMODULE						m_hDxgiLib;
1390	LPD3D11CREATEDEVICE			m_fnD3D11CreateDevice;
1391	LPD3DX11COMPILEFROMMEMORY	m_fnD3DX11CompileFromMemory;
1392	pD3DCompile					m_fnD3DCompile;
1393	ID3D11Device*				m_pDevice;
1394	ID3D11DeviceContext*		m_pContext;
1395#endif
1396};
1397
1398class Win32KeyedMutexTestInstance : public TestInstance
1399{
1400public:
1401														Win32KeyedMutexTestInstance	(Context&	context,
1402																					 TestConfig	config);
1403
1404	virtual tcu::TestStatus								iterate					(void);
1405
1406private:
1407	const TestConfig									m_config;
1408	const de::UniquePtr<OperationSupport>				m_supportWriteOp;
1409	const de::UniquePtr<OperationSupport>				m_supportReadOp;
1410
1411	const vk::Unique<vk::VkInstance>					m_instance;
1412
1413	const vk::InstanceDriver							m_vki;
1414	const vk::VkPhysicalDevice							m_physicalDevice;
1415	const std::vector<vk::VkQueueFamilyProperties>		m_queueFamilies;
1416	const std::vector<deUint32>							m_queueFamilyIndices;
1417	const vk::Unique<vk::VkDevice>						m_device;
1418	const vk::DeviceDriver								m_vkd;
1419
1420	const de::UniquePtr<DX11OperationSupport>			m_supportDX11;
1421
1422	const vk::VkExternalMemoryHandleTypeFlagBits		m_memoryHandleType;
1423
1424	// \todo Should this be moved to the group same way as in the other tests?
1425	PipelineCacheData									m_pipelineCacheData;
1426	tcu::ResultCollector								m_resultCollector;
1427	size_t												m_queueNdx;
1428
1429	bool												m_useDedicatedAllocation;
1430};
1431
1432Win32KeyedMutexTestInstance::Win32KeyedMutexTestInstance	(Context&		context,
1433															 TestConfig		config)
1434	: TestInstance				(context)
1435	, m_config					(config)
1436	, m_supportWriteOp			(makeOperationSupport(config.writeOp, config.resource))
1437	, m_supportReadOp			(makeOperationSupport(config.readOp, config.resource))
1438
1439	, m_instance				(createInstance(context.getPlatformInterface(), context.getUsedApiVersion()))
1440
1441	, m_vki						(context.getPlatformInterface(), *m_instance)
1442	, m_physicalDevice			(getPhysicalDevice(m_vki, *m_instance, context.getTestContext().getCommandLine()))
1443	, m_queueFamilies			(vk::getPhysicalDeviceQueueFamilyProperties(m_vki, m_physicalDevice))
1444	, m_queueFamilyIndices		(getFamilyIndices(m_queueFamilies))
1445	, m_device					(createDevice(context.getUsedApiVersion(), m_vki, m_physicalDevice))
1446	, m_vkd						(m_vki, *m_device)
1447
1448	, m_supportDX11				(new DX11OperationSupport(m_vki, m_physicalDevice, config.resource))
1449
1450	, m_memoryHandleType		((m_config.resource.type == RESOURCE_TYPE_IMAGE) ? m_config.memoryHandleTypeImage : m_config.memoryHandleTypeBuffer)
1451
1452	, m_resultCollector			(context.getTestContext().getLog())
1453	, m_queueNdx				(0)
1454
1455	, m_useDedicatedAllocation	(false)
1456{
1457#if (DE_OS == DE_OS_WIN32)
1458	TestLog& log = m_context.getTestContext().getLog();
1459
1460	// Check resource support
1461	if (m_config.resource.type == RESOURCE_TYPE_IMAGE)
1462	{
1463		if (m_memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT && !IsWindows8OrGreater())
1464			TCU_THROW(NotSupportedError, "Memory handle type not supported by this OS");
1465
1466		const vk::VkPhysicalDeviceExternalImageFormatInfo	externalInfo		=
1467		{
1468			vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
1469			DE_NULL,
1470			m_memoryHandleType
1471		};
1472		const vk::VkPhysicalDeviceImageFormatInfo2			imageFormatInfo		=
1473		{
1474			vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
1475			&externalInfo,
1476			m_config.resource.imageFormat,
1477			m_config.resource.imageType,
1478			vk::VK_IMAGE_TILING_OPTIMAL,
1479			m_supportReadOp->getResourceUsageFlags() | m_supportWriteOp->getResourceUsageFlags(),
1480			0u
1481		};
1482		vk::VkExternalImageFormatProperties					externalProperties	=
1483		{
1484			vk::VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
1485			DE_NULL,
1486			{ 0u, 0u, 0u }
1487		};
1488		vk::VkImageFormatProperties2						formatProperties	=
1489		{
1490			vk::VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
1491			&externalProperties,
1492			{
1493				{ 0u, 0u, 0u },
1494				0u,
1495				0u,
1496				0u,
1497				0u,
1498			}
1499		};
1500		VK_CHECK(m_vki.getPhysicalDeviceImageFormatProperties2(m_physicalDevice, &imageFormatInfo, &formatProperties));
1501
1502		// \todo How to log this nicely?
1503		log << TestLog::Message << "External image format properties: " << imageFormatInfo << "\n"<< externalProperties << TestLog::EndMessage;
1504
1505		if ((externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0)
1506			TCU_THROW(NotSupportedError, "Importing image resource not supported");
1507
1508		if (externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT)
1509			m_useDedicatedAllocation = true;
1510	}
1511	else
1512	{
1513		if (m_memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT && !IsWindows8OrGreater())
1514			TCU_THROW(NotSupportedError, "Memory handle type not supported by this OS");
1515
1516		const vk::VkPhysicalDeviceExternalBufferInfo		info	=
1517		{
1518			vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO,
1519			DE_NULL,
1520
1521			0u,
1522			m_supportReadOp->getResourceUsageFlags() | m_supportWriteOp->getResourceUsageFlags(),
1523			m_memoryHandleType
1524		};
1525		vk::VkExternalBufferProperties						properties			=
1526		{
1527			vk::VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES,
1528			DE_NULL,
1529			{ 0u, 0u, 0u}
1530		};
1531		m_vki.getPhysicalDeviceExternalBufferProperties(m_physicalDevice, &info, &properties);
1532
1533		log << TestLog::Message << "External buffer properties: " << info << "\n" << properties << TestLog::EndMessage;
1534
1535		if ((properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0)
1536			TCU_THROW(NotSupportedError, "Importing memory type not supported");
1537
1538		if (properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT)
1539			m_useDedicatedAllocation = true;
1540	}
1541#else
1542	DE_UNREF(m_useDedicatedAllocation);
1543	TCU_THROW(NotSupportedError, "OS not supported");
1544#endif
1545}
1546
1547tcu::TestStatus Win32KeyedMutexTestInstance::iterate (void)
1548{
1549	TestLog&									log					(m_context.getTestContext().getLog());
1550
1551	try
1552	{
1553		const deUint32							queueFamily			= (deUint32)m_queueNdx;
1554
1555		const tcu::ScopedLogSection				queuePairSection	(log, "Queue-" + de::toString(queueFamily), "Queue-" + de::toString(queueFamily));
1556
1557		const vk::VkQueue						queue				(getDeviceQueue(m_vkd, *m_device, queueFamily, 0u));
1558		const vk::Unique<vk::VkCommandPool>		commandPool			(createCommandPool(m_vkd, *m_device, 0u, queueFamily));
1559		const vk::Unique<vk::VkCommandBuffer>	commandBufferWrite	(allocateCommandBuffer(m_vkd, *m_device, *commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1560		const vk::Unique<vk::VkCommandBuffer>	commandBufferRead	(allocateCommandBuffer(m_vkd, *m_device, *commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1561		vk::SimpleAllocator						allocator			(m_vkd, *m_device, vk::getPhysicalDeviceMemoryProperties(m_vki, m_physicalDevice));
1562		const std::vector<std::string>			deviceExtensions;
1563		OperationContext						operationContext	(m_context.getUsedApiVersion(), m_vki, m_vkd, m_physicalDevice, *m_device, allocator, deviceExtensions, m_context.getBinaryCollection(), m_pipelineCacheData);
1564
1565		if (!checkQueueFlags(m_queueFamilies[m_queueNdx].queueFlags, vk::VK_QUEUE_GRAPHICS_BIT))
1566			TCU_THROW(NotSupportedError, "Operation not supported by the source queue");
1567
1568		const de::UniquePtr<DX11Operation>		dx11Op				(m_supportDX11->build(m_config.resource, m_memoryHandleType));
1569
1570		NativeHandle nativeHandleWrite = dx11Op->getNativeHandle(DX11Operation::BUFFER_VK_WRITE);
1571		const de::UniquePtr<Resource>			resourceWrite		(importResource(m_vkd, *m_device, m_config.resource, m_queueFamilyIndices, *m_supportReadOp, *m_supportWriteOp, nativeHandleWrite, m_memoryHandleType));
1572
1573		NativeHandle nativeHandleRead = dx11Op->getNativeHandle(DX11Operation::BUFFER_VK_READ);
1574		const de::UniquePtr<Resource>			resourceRead		(importResource(m_vkd, *m_device, m_config.resource, m_queueFamilyIndices, *m_supportReadOp, *m_supportWriteOp, nativeHandleRead, m_memoryHandleType));
1575
1576		const de::UniquePtr<Operation>			writeOp				(m_supportWriteOp->build(operationContext, *resourceWrite));
1577		const de::UniquePtr<Operation>			readOp				(m_supportReadOp->build(operationContext, *resourceRead));
1578
1579		const SyncInfo							writeSync			= writeOp->getSyncInfo();
1580		const SyncInfo							readSync			= readOp->getSyncInfo();
1581
1582		beginCommandBuffer(m_vkd, *commandBufferWrite);
1583		writeOp->recordCommands(*commandBufferWrite);
1584		recordWriteBarrier(m_vkd, *commandBufferWrite, *resourceWrite, writeSync, queueFamily, readSync);
1585		endCommandBuffer(m_vkd, *commandBufferWrite);
1586
1587		beginCommandBuffer(m_vkd, *commandBufferRead);
1588		recordReadBarrier(m_vkd, *commandBufferRead, *resourceRead, writeSync, readSync, queueFamily);
1589		readOp->recordCommands(*commandBufferRead);
1590		endCommandBuffer(m_vkd, *commandBufferRead);
1591
1592		{
1593			vk::VkDeviceMemory							memory			= resourceWrite->getMemory();
1594			deUint64									keyInit			= DX11Operation::KEYED_MUTEX_VK_WRITE;
1595			deUint32									timeout			= 0xFFFFFFFF; // INFINITE
1596			deUint64									keyExternal		= DX11Operation::KEYED_MUTEX_DX_COPY;
1597			vk::VkWin32KeyedMutexAcquireReleaseInfoKHR	keyedMutexInfo	=
1598			{
1599				vk::VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR,
1600				DE_NULL,
1601
1602				1,
1603				&memory,
1604				&keyInit,
1605				&timeout,
1606
1607				1,
1608				&memory,
1609				&keyExternal,
1610			};
1611
1612			const vk::VkCommandBuffer	commandBuffer	= *commandBufferWrite;
1613			const vk::VkSubmitInfo		submitInfo			=
1614			{
1615				vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1616				&keyedMutexInfo,
1617
1618				0u,
1619				DE_NULL,
1620				DE_NULL,
1621
1622				1u,
1623				&commandBuffer,
1624				0u,
1625				DE_NULL
1626			};
1627
1628			VK_CHECK(m_vkd.queueSubmit(queue, 1u, &submitInfo, DE_NULL));
1629		}
1630
1631		dx11Op->copyMemory();
1632
1633		{
1634			vk::VkDeviceMemory							memory			= resourceRead->getMemory();
1635			deUint64									keyInternal		= DX11Operation::KEYED_MUTEX_VK_VERIFY;
1636			deUint32									timeout			= 0xFFFFFFFF; // INFINITE
1637			deUint64									keyExternal		= DX11Operation::KEYED_MUTEX_DONE;
1638			vk::VkWin32KeyedMutexAcquireReleaseInfoKHR	keyedMutexInfo	=
1639			{
1640				vk::VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR,
1641				DE_NULL,
1642
1643				1,
1644				&memory,
1645				&keyInternal,
1646				&timeout,
1647
1648				1,
1649				&memory,
1650				&keyExternal,
1651			};
1652
1653			const vk::VkCommandBuffer	commandBuffer	= *commandBufferRead;
1654			const vk::VkSubmitInfo		submitInfo			=
1655			{
1656				vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1657				&keyedMutexInfo,
1658
1659				0u,
1660				DE_NULL,
1661				DE_NULL,
1662
1663				1u,
1664				&commandBuffer,
1665				0u,
1666				DE_NULL
1667			};
1668
1669			VK_CHECK(m_vkd.queueSubmit(queue, 1u, &submitInfo, DE_NULL));
1670		}
1671
1672		VK_CHECK(m_vkd.queueWaitIdle(queue));
1673
1674		{
1675			const Data	expected	= writeOp->getData();
1676			const Data	actual		= readOp->getData();
1677
1678			DE_ASSERT(expected.size == actual.size);
1679
1680			if (0 != deMemCmp(expected.data, actual.data, expected.size))
1681			{
1682				const size_t		maxBytesLogged	= 256;
1683				std::ostringstream	expectedData;
1684				std::ostringstream	actualData;
1685				size_t				byteNdx			= 0;
1686
1687				// Find first byte difference
1688				for (; actual.data[byteNdx] == expected.data[byteNdx]; byteNdx++)
1689				{
1690					// Nothing
1691				}
1692
1693				log << TestLog::Message << "First different byte at offset: " << byteNdx << TestLog::EndMessage;
1694
1695				// Log 8 previous bytes before the first incorrect byte
1696				if (byteNdx > 8)
1697				{
1698					expectedData << "... ";
1699					actualData << "... ";
1700
1701					byteNdx -= 8;
1702				}
1703				else
1704					byteNdx = 0;
1705
1706				for (size_t i = 0; i < maxBytesLogged && byteNdx < expected.size; i++, byteNdx++)
1707				{
1708					expectedData << (i > 0 ? ", " : "") << (deUint32)expected.data[byteNdx];
1709					actualData << (i > 0 ? ", " : "") << (deUint32)actual.data[byteNdx];
1710				}
1711
1712				if (expected.size > byteNdx)
1713				{
1714					expectedData << "...";
1715					actualData << "...";
1716				}
1717
1718				log << TestLog::Message << "Expected data: (" << expectedData.str() << ")" << TestLog::EndMessage;
1719				log << TestLog::Message << "Actual data: (" << actualData.str() << ")" << TestLog::EndMessage;
1720
1721				m_resultCollector.fail("Memory contents don't match");
1722			}
1723		}
1724	}
1725	catch (const tcu::NotSupportedError& error)
1726	{
1727		log << TestLog::Message << "Not supported: " << error.getMessage() << TestLog::EndMessage;
1728	}
1729	catch (const tcu::TestError& error)
1730	{
1731		m_resultCollector.fail(std::string("Exception: ") + error.getMessage());
1732	}
1733
1734	// Move to next queue
1735	{
1736		m_queueNdx++;
1737
1738		if (m_queueNdx >= m_queueFamilies.size())
1739		{
1740			return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1741		}
1742		else
1743		{
1744			return tcu::TestStatus::incomplete();
1745		}
1746	}
1747}
1748
1749struct Progs
1750{
1751	void init (vk::SourceCollections& dst, TestConfig config) const
1752	{
1753		const de::UniquePtr<OperationSupport>	readOp	(makeOperationSupport(config.readOp, config.resource));
1754		const de::UniquePtr<OperationSupport>	writeOp	(makeOperationSupport(config.writeOp, config.resource));
1755
1756		readOp->initPrograms(dst);
1757		writeOp->initPrograms(dst);
1758	}
1759};
1760
1761} // anonymous
1762
1763tcu::TestCaseGroup* createWin32KeyedMutexTest (tcu::TestContext& testCtx)
1764{
1765	const struct
1766	{
1767		vk::VkExternalMemoryHandleTypeFlagBits			memoryHandleTypeBuffer;
1768		vk::VkExternalMemoryHandleTypeFlagBits			memoryHandleTypeImage;
1769		const char*										nameSuffix;
1770	} cases[] =
1771	{
1772		{
1773			(vk::VkExternalMemoryHandleTypeFlagBits)0u,				// DX11 doesn't support buffers with an NT handle
1774			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT,
1775			"_nt"
1776		},
1777		{
1778			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
1779			vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT,
1780			"_kmt"
1781		},
1782	};
1783	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "win32_keyed_mutex", ""));
1784
1785	for (size_t writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
1786	for (size_t readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
1787	{
1788		const OperationName	writeOp		= s_writeOps[writeOpNdx];
1789		const OperationName	readOp		= s_readOps[readOpNdx];
1790		const std::string	opGroupName	= getOperationName(writeOp) + "_" + getOperationName(readOp);
1791		bool				empty		= true;
1792
1793		de::MovePtr<tcu::TestCaseGroup> opGroup	(new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
1794
1795		for (size_t resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resourcesWin32KeyedMutex); ++resourceNdx)
1796		{
1797			const ResourceDescription&	resource	= s_resourcesWin32KeyedMutex[resourceNdx];
1798
1799			for (size_t caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
1800			{
1801				if (resource.type == RESOURCE_TYPE_BUFFER && !cases[caseNdx].memoryHandleTypeBuffer)
1802					continue;
1803
1804				if (resource.type == RESOURCE_TYPE_IMAGE && !cases[caseNdx].memoryHandleTypeImage)
1805					continue;
1806
1807				std::string	name	= getResourceName(resource) + cases[caseNdx].nameSuffix;
1808
1809				if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
1810				{
1811					const TestConfig config (resource, writeOp, readOp, cases[caseNdx].memoryHandleTypeBuffer, cases[caseNdx].memoryHandleTypeImage);
1812
1813					opGroup->addChild(new InstanceFactory1<Win32KeyedMutexTestInstance, TestConfig, Progs>(testCtx, tcu::NODETYPE_SELF_VALIDATE,  name, "", Progs(), config));
1814					empty = false;
1815				}
1816			}
1817		}
1818
1819		if (!empty)
1820			group->addChild(opGroup.release());
1821	}
1822
1823	return group.release();
1824}
1825
1826} // synchronization
1827} // vkt
1828