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