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