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