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