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