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