1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 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 between instances.
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktSynchronizationCrossInstanceSharingTests.hpp"
25
26 #include "vkDeviceUtil.hpp"
27 #include "vkPlatform.hpp"
28 #include "vkBarrierUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vktTestCaseUtil.hpp"
31 #include "deSharedPtr.hpp"
32
33 #include "vktSynchronizationUtil.hpp"
34 #include "vktSynchronizationOperation.hpp"
35 #include "vktSynchronizationOperationTestData.hpp"
36 #include "vktSynchronizationOperationResources.hpp"
37 #include "vktExternalMemoryUtil.hpp"
38 #include "vktTestGroupUtil.hpp"
39 #include "vktCustomInstancesDevices.hpp"
40
41 #include "deRandom.hpp"
42
43 #include "tcuResultCollector.hpp"
44 #include "tcuTestLog.hpp"
45 #include "tcuCommandLine.hpp"
46
47 using tcu::TestLog;
48 using namespace vkt::ExternalMemoryUtil;
49
50 namespace vkt
51 {
52 namespace synchronization
53 {
54 namespace
55 {
56 using namespace vk;
57 using de::SharedPtr;
58
59 struct TestConfig
60 {
TestConfigvkt::synchronization::__anon824781910111::TestConfig61 TestConfig (SynchronizationType type_,
62 const ResourceDescription& resource_,
63 vk::VkSemaphoreType semaphoreType_,
64 OperationName writeOp_,
65 OperationName readOp_,
66 vk::VkExternalMemoryHandleTypeFlagBits memoryHandleType_,
67 vk::VkExternalSemaphoreHandleTypeFlagBits semaphoreHandleType_,
68 bool dedicated_)
69 : type (type_)
70 , resource (resource_)
71 , semaphoreType (semaphoreType_)
72 , writeOp (writeOp_)
73 , readOp (readOp_)
74 , memoryHandleType (memoryHandleType_)
75 , semaphoreHandleType (semaphoreHandleType_)
76 , dedicated (dedicated_)
77 {
78 }
79
80 const SynchronizationType type;
81 const ResourceDescription resource;
82 const vk::VkSemaphoreType semaphoreType;
83 const OperationName writeOp;
84 const OperationName readOp;
85 const vk::VkExternalMemoryHandleTypeFlagBits memoryHandleType;
86 const vk::VkExternalSemaphoreHandleTypeFlagBits semaphoreHandleType;
87 const bool dedicated;
88 };
89
90 // A helper class to test for extensions upfront and throw not supported to speed up test runtimes compared to failing only
91 // after creating unnecessary vkInstances. A common example of this is win32 platforms taking a long time to run _fd tests.
92 class NotSupportedChecker
93 {
94 public:
NotSupportedChecker(const Context & context,TestConfig config,const OperationSupport & writeOp,const OperationSupport & readOp)95 NotSupportedChecker (const Context& context,
96 TestConfig config,
97 const OperationSupport& writeOp,
98 const OperationSupport& readOp)
99 : m_context (context)
100 {
101 // Check instance support
102 m_context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
103
104 m_context.requireInstanceFunctionality("VK_KHR_external_semaphore_capabilities");
105 m_context.requireInstanceFunctionality("VK_KHR_external_memory_capabilities");
106
107 // Check device support
108 if (config.dedicated)
109 m_context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
110
111 m_context.requireDeviceFunctionality("VK_KHR_external_semaphore");
112 m_context.requireDeviceFunctionality("VK_KHR_external_memory");
113
114 if (config.semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE)
115 m_context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
116
117 if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
118 || config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
119 || config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT)
120 if (config.type == SynchronizationType::SYNCHRONIZATION2)
121 m_context.requireDeviceFunctionality("VK_KHR_synchronization2");
122
123 if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
124 || config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR
125 || config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR)
126 {
127 m_context.requireDeviceFunctionality("VK_KHR_external_semaphore_fd");
128 m_context.requireDeviceFunctionality("VK_KHR_external_memory_fd");
129 }
130
131 if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)
132 {
133 m_context.requireDeviceFunctionality("VK_EXT_external_memory_dma_buf");
134 }
135
136 if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
137 || config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
138 || config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
139 || config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)
140 {
141 m_context.requireDeviceFunctionality("VK_KHR_external_semaphore_win32");
142 m_context.requireDeviceFunctionality("VK_KHR_external_memory_win32");
143 }
144
145 if (config.memoryHandleType == vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA
146 || config.semaphoreHandleType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA)
147 {
148 m_context.requireDeviceFunctionality("VK_FUCHSIA_external_semaphore");
149 m_context.requireDeviceFunctionality("VK_FUCHSIA_external_memory");
150 }
151
152 TestLog& log = context.getTestContext().getLog();
153 const vk::InstanceInterface& vki = context.getInstanceInterface();
154 const vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
155
156 // Check resource support
157 if (config.resource.type == RESOURCE_TYPE_IMAGE)
158 {
159 const vk::VkPhysicalDeviceExternalImageFormatInfo externalInfo =
160 {
161 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
162 DE_NULL,
163 config.memoryHandleType
164 };
165 const vk::VkPhysicalDeviceImageFormatInfo2 imageFormatInfo =
166 {
167 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
168 &externalInfo,
169 config.resource.imageFormat,
170 config.resource.imageType,
171 vk::VK_IMAGE_TILING_OPTIMAL,
172 readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
173 0u
174 };
175 vk::VkExternalImageFormatProperties externalProperties =
176 {
177 vk::VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
178 DE_NULL,
179 { 0u, 0u, 0u }
180 };
181 vk::VkImageFormatProperties2 formatProperties =
182 {
183 vk::VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
184 &externalProperties,
185 {
186 { 0u, 0u, 0u },
187 0u,
188 0u,
189 0u,
190 0u,
191 }
192 };
193
194 {
195 const vk::VkResult res = vki.getPhysicalDeviceImageFormatProperties2(physicalDevice, &imageFormatInfo, &formatProperties);
196
197 if (res == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
198 TCU_THROW(NotSupportedError, "Image format not supported");
199
200 VK_CHECK(res); // Check other errors
201 }
202
203 log << TestLog::Message << "External image format properties: " << imageFormatInfo << "\n"<< externalProperties << TestLog::EndMessage;
204
205 if ((externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) == 0)
206 TCU_THROW(NotSupportedError, "Exporting image resource not supported");
207
208 if ((externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0)
209 TCU_THROW(NotSupportedError, "Importing image resource not supported");
210
211 if (!config.dedicated && (externalProperties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT) != 0)
212 {
213 TCU_THROW(NotSupportedError, "Handle requires dedicated allocation, but test uses suballocated memory");
214 }
215
216 if (!(formatProperties.imageFormatProperties.sampleCounts & config.resource.imageSamples)) {
217 TCU_THROW(NotSupportedError, "Specified sample count for format not supported");
218 }
219
220 }
221 else
222 {
223 const vk::VkPhysicalDeviceExternalBufferInfo info =
224 {
225 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO,
226 DE_NULL,
227
228 0u,
229 readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
230 config.memoryHandleType
231 };
232 vk::VkExternalBufferProperties properties =
233 {
234 vk::VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES,
235 DE_NULL,
236 { 0u, 0u, 0u}
237 };
238 vki.getPhysicalDeviceExternalBufferProperties(physicalDevice, &info, &properties);
239
240 log << TestLog::Message << "External buffer properties: " << info << "\n" << properties << TestLog::EndMessage;
241
242 if ((properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) == 0
243 || (properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0)
244 TCU_THROW(NotSupportedError, "Exporting and importing memory type not supported");
245
246 if (!config.dedicated && (properties.externalMemoryProperties.externalMemoryFeatures & vk::VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT) != 0)
247 {
248 TCU_THROW(NotSupportedError, "Handle requires dedicated allocation, but test uses suballocated memory");
249 }
250 }
251
252 // Check semaphore support
253 {
254 const vk::VkSemaphoreTypeCreateInfo semaphoreTypeInfo =
255 {
256 vk::VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
257 DE_NULL,
258 config.semaphoreType,
259 0,
260 };
261 const vk::VkPhysicalDeviceExternalSemaphoreInfo info =
262 {
263 vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
264 &semaphoreTypeInfo,
265 config.semaphoreHandleType
266 };
267
268 vk::VkExternalSemaphoreProperties properties =
269 {
270 vk::VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
271 DE_NULL,
272 0u,
273 0u,
274 0u
275 };
276
277 vki.getPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &info, &properties);
278
279 log << TestLog::Message << info << "\n" << properties << TestLog::EndMessage;
280
281 if ((properties.externalSemaphoreFeatures & vk::VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) == 0
282 || (properties.externalSemaphoreFeatures & vk::VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT) == 0)
283 TCU_THROW(NotSupportedError, "Exporting and importing semaphore type not supported");
284 }
285 }
286
287 private:
288
289 const Context& m_context;
290 };
291
checkQueueFlags(vk::VkQueueFlags availableFlags,const vk::VkQueueFlags neededFlags)292 bool checkQueueFlags (vk::VkQueueFlags availableFlags, const vk::VkQueueFlags neededFlags)
293 {
294 if ((availableFlags & (vk::VK_QUEUE_GRAPHICS_BIT | vk::VK_QUEUE_COMPUTE_BIT)) != 0)
295 availableFlags |= vk::VK_QUEUE_TRANSFER_BIT;
296
297 return (availableFlags & neededFlags) != 0;
298 }
299
300 class SimpleAllocation : public vk::Allocation
301 {
302 public:
303 SimpleAllocation (const vk::DeviceInterface& vkd,
304 vk::VkDevice device,
305 const vk::VkDeviceMemory memory);
306 ~SimpleAllocation (void);
307
308 private:
309 const vk::DeviceInterface& m_vkd;
310 const vk::VkDevice m_device;
311 };
312
SimpleAllocation(const vk::DeviceInterface & vkd,vk::VkDevice device,const vk::VkDeviceMemory memory)313 SimpleAllocation::SimpleAllocation (const vk::DeviceInterface& vkd,
314 vk::VkDevice device,
315 const vk::VkDeviceMemory memory)
316 : Allocation (memory, 0, DE_NULL)
317 , m_vkd (vkd)
318 , m_device (device)
319 {
320 }
321
~SimpleAllocation(void)322 SimpleAllocation::~SimpleAllocation (void)
323 {
324 m_vkd.freeMemory(m_device, getMemory(), DE_NULL);
325 }
326
createTestInstance(Context & context)327 CustomInstance createTestInstance (Context& context)
328 {
329 std::vector<std::string> extensions;
330 extensions.push_back("VK_KHR_get_physical_device_properties2");
331 extensions.push_back("VK_KHR_external_semaphore_capabilities");
332 extensions.push_back("VK_KHR_external_memory_capabilities");
333
334 return createCustomInstanceWithExtensions(context, extensions);
335 }
336
createTestDevice(const Context & context,const vk::PlatformInterface & vkp,vk::VkInstance instance,const vk::InstanceInterface & vki,const vk::VkPhysicalDevice physicalDevice)337 vk::Move<vk::VkDevice> createTestDevice (const Context& context,
338 const vk::PlatformInterface& vkp,
339 vk::VkInstance instance,
340 const vk::InstanceInterface& vki,
341 const vk::VkPhysicalDevice physicalDevice)
342 {
343 const bool validationEnabled = context.getTestContext().getCommandLine().isValidationEnabled();
344 const float priority = 0.0f;
345 const std::vector<vk::VkQueueFamilyProperties> queueFamilyProperties = vk::getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
346 std::vector<deUint32> queueFamilyIndices (queueFamilyProperties.size(), 0xFFFFFFFFu);
347
348 VkPhysicalDeviceFeatures2 createPhysicalFeature { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, DE_NULL, context.getDeviceFeatures() };
349 VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreFeatures { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, DE_NULL, DE_TRUE };
350 VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, DE_NULL, DE_TRUE };
351 void** nextPtr = &createPhysicalFeature.pNext;
352 std::vector<const char*> extensions;
353
354 if (context.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
355 extensions.push_back("VK_KHR_dedicated_allocation");
356
357 if (context.isDeviceFunctionalitySupported("VK_KHR_get_memory_requirements2"))
358 extensions.push_back("VK_KHR_get_memory_requirements2");
359
360 if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore"))
361 extensions.push_back("VK_KHR_external_semaphore");
362 if (context.isDeviceFunctionalitySupported("VK_KHR_external_memory"))
363 extensions.push_back("VK_KHR_external_memory");
364
365 if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_fd"))
366 extensions.push_back("VK_KHR_external_semaphore_fd");
367 if (context.isDeviceFunctionalitySupported("VK_KHR_external_memory_fd"))
368 extensions.push_back("VK_KHR_external_memory_fd");
369
370 if (context.isDeviceFunctionalitySupported("VK_EXT_external_memory_dma_buf"))
371 extensions.push_back("VK_EXT_external_memory_dma_buf");
372
373 if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_win32"))
374 extensions.push_back("VK_KHR_external_semaphore_win32");
375 if (context.isDeviceFunctionalitySupported("VK_KHR_external_memory_win32"))
376 extensions.push_back("VK_KHR_external_memory_win32");
377
378 if (context.isDeviceFunctionalitySupported("VK_FUCHSIA_external_semaphore"))
379 extensions.push_back("VK_FUCHSIA_external_semaphore");
380 if (context.isDeviceFunctionalitySupported("VK_FUCHSIA_external_memory"))
381 extensions.push_back("VK_FUCHSIA_external_memory");
382
383 if (context.isDeviceFunctionalitySupported("VK_KHR_timeline_semaphore"))
384 {
385 extensions.push_back("VK_KHR_timeline_semaphore");
386 addToChainVulkanStructure(&nextPtr, timelineSemaphoreFeatures);
387 }
388 if (context.isDeviceFunctionalitySupported("VK_KHR_synchronization2"))
389 {
390 extensions.push_back("VK_KHR_synchronization2");
391 addToChainVulkanStructure(&nextPtr, synchronization2Features);
392 }
393
394 try
395 {
396 std::vector<vk::VkDeviceQueueCreateInfo> queues;
397
398 for (size_t ndx = 0; ndx < queueFamilyProperties.size(); ndx++)
399 {
400 const vk::VkDeviceQueueCreateInfo createInfo =
401 {
402 vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
403 DE_NULL,
404 0u,
405
406 (deUint32)ndx,
407 1u,
408 &priority
409 };
410
411 queues.push_back(createInfo);
412 }
413
414 const vk::VkDeviceCreateInfo createInfo =
415 {
416 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
417 &createPhysicalFeature,
418 0u,
419
420 (deUint32)queues.size(),
421 &queues[0],
422
423 0u,
424 DE_NULL,
425
426 (deUint32)extensions.size(),
427 extensions.empty() ? DE_NULL : &extensions[0],
428 0u
429 };
430
431 return vkt::createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &createInfo);
432 }
433 catch (const vk::Error& error)
434 {
435 if (error.getError() == vk::VK_ERROR_EXTENSION_NOT_PRESENT)
436 TCU_THROW(NotSupportedError, "Required extensions not supported");
437 else
438 throw;
439 }
440 }
441
442 // Class to wrap a singleton instance and device
443 class InstanceAndDevice
444 {
InstanceAndDevice(Context & context)445 InstanceAndDevice (Context& context)
446 : m_instance (createTestInstance(context))
447 , m_vki (m_instance.getDriver())
448 , m_physicalDevice (vk::chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
449 , m_logicalDevice (createTestDevice(context, context.getPlatformInterface(), m_instance, m_vki, m_physicalDevice))
450 {
451 }
452
453 public:
454
getInstanceA(Context & context)455 static vk::VkInstance getInstanceA(Context& context)
456 {
457 if (!m_instanceA)
458 m_instanceA = SharedPtr<InstanceAndDevice>(new InstanceAndDevice(context));
459
460 return m_instanceA->m_instance;
461 }
getInstanceB(Context & context)462 static vk::VkInstance getInstanceB(Context& context)
463 {
464 if (!m_instanceB)
465 m_instanceB = SharedPtr<InstanceAndDevice>(new InstanceAndDevice(context));
466
467 return m_instanceB->m_instance;
468 }
getDriverA()469 static const vk::InstanceDriver& getDriverA()
470 {
471 DE_ASSERT(m_instanceA);
472 return m_instanceA->m_instance.getDriver();
473 }
getDriverB()474 static const vk::InstanceDriver& getDriverB()
475 {
476 DE_ASSERT(m_instanceB);
477 return m_instanceB->m_instance.getDriver();
478 }
getPhysicalDeviceA()479 static vk::VkPhysicalDevice getPhysicalDeviceA()
480 {
481 DE_ASSERT(m_instanceA);
482 return m_instanceA->m_physicalDevice;
483 }
getPhysicalDeviceB()484 static vk::VkPhysicalDevice getPhysicalDeviceB()
485 {
486 DE_ASSERT(m_instanceB);
487 return m_instanceB->m_physicalDevice;
488 }
getDeviceA()489 static const Unique<vk::VkDevice>& getDeviceA()
490 {
491 DE_ASSERT(m_instanceA);
492 return m_instanceA->m_logicalDevice;
493 }
getDeviceB()494 static const Unique<vk::VkDevice>& getDeviceB()
495 {
496 DE_ASSERT(m_instanceB);
497 return m_instanceB->m_logicalDevice;
498 }
collectMessagesA()499 static void collectMessagesA()
500 {
501 DE_ASSERT(m_instanceA);
502 m_instanceA->m_instance.collectMessages();
503 }
collectMessagesB()504 static void collectMessagesB()
505 {
506 DE_ASSERT(m_instanceB);
507 m_instanceB->m_instance.collectMessages();
508 }
destroy()509 static void destroy()
510 {
511 m_instanceA.clear();
512 m_instanceB.clear();
513 }
514
515 private:
516 CustomInstance m_instance;
517 const vk::InstanceDriver& m_vki;
518 const vk::VkPhysicalDevice m_physicalDevice;
519 const Unique<vk::VkDevice> m_logicalDevice;
520
521 static SharedPtr<InstanceAndDevice> m_instanceA;
522 static SharedPtr<InstanceAndDevice> m_instanceB;
523 };
524 SharedPtr<InstanceAndDevice> InstanceAndDevice::m_instanceA;
525 SharedPtr<InstanceAndDevice> InstanceAndDevice::m_instanceB;
526
527
getQueue(const vk::DeviceInterface & vkd,const vk::VkDevice device,deUint32 familyIndex)528 vk::VkQueue getQueue (const vk::DeviceInterface& vkd,
529 const vk::VkDevice device,
530 deUint32 familyIndex)
531 {
532 vk::VkQueue queue;
533
534 vkd.getDeviceQueue(device, familyIndex, 0u, &queue);
535
536 return queue;
537 }
538
createCommandPool(const vk::DeviceInterface & vkd,vk::VkDevice device,deUint32 queueFamilyIndex)539 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface& vkd,
540 vk::VkDevice device,
541 deUint32 queueFamilyIndex)
542 {
543 const vk::VkCommandPoolCreateInfo createInfo =
544 {
545 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
546 DE_NULL,
547
548 0u,
549 queueFamilyIndex
550 };
551
552 return vk::createCommandPool(vkd, device, &createInfo);
553 }
554
createCommandBuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool)555 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface& vkd,
556 vk::VkDevice device,
557 vk::VkCommandPool commandPool)
558 {
559 const vk::VkCommandBufferLevel level = vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY;
560 const vk::VkCommandBufferAllocateInfo allocateInfo =
561 {
562 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
563 DE_NULL,
564
565 commandPool,
566 level,
567 1u
568 };
569
570 return vk::allocateCommandBuffer(vkd, device, &allocateInfo);
571 }
572
getMemoryRequirements(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkImage image,bool dedicated,bool getMemReq2Supported)573 vk::VkMemoryRequirements getMemoryRequirements(const vk::DeviceInterface& vkd,
574 vk::VkDevice device,
575 vk::VkImage image,
576 bool dedicated,
577 bool getMemReq2Supported)
578 {
579 vk::VkMemoryRequirements memoryRequirements = { 0u, 0u, 0u, };
580
581 if (getMemReq2Supported)
582 {
583 const vk::VkImageMemoryRequirementsInfo2 requirementInfo =
584 {
585 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
586 DE_NULL,
587 image
588 };
589 vk::VkMemoryDedicatedRequirements dedicatedRequirements =
590 {
591 vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
592 DE_NULL,
593 VK_FALSE,
594 VK_FALSE
595 };
596 vk::VkMemoryRequirements2 requirements =
597 {
598 vk::VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
599 &dedicatedRequirements,
600 { 0u, 0u, 0u, }
601 };
602 vkd.getImageMemoryRequirements2(device, &requirementInfo, &requirements);
603
604 if (!dedicated && dedicatedRequirements.requiresDedicatedAllocation)
605 TCU_THROW(NotSupportedError, "Memory requires dedicated allocation");
606
607 memoryRequirements = requirements.memoryRequirements;
608 }
609 else
610 {
611 vkd.getImageMemoryRequirements(device, image, &memoryRequirements);
612 }
613
614 return memoryRequirements;
615 }
616
getMemoryRequirements(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkBuffer buffer,bool dedicated,bool getMemReq2Supported)617 vk::VkMemoryRequirements getMemoryRequirements(const vk::DeviceInterface& vkd,
618 vk::VkDevice device,
619 vk::VkBuffer buffer,
620 bool dedicated,
621 bool getMemReq2Supported)
622 {
623 vk::VkMemoryRequirements memoryRequirements = { 0u, 0u, 0u, };
624
625 if (getMemReq2Supported)
626 {
627 const vk::VkBufferMemoryRequirementsInfo2 requirementInfo =
628 {
629 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
630 DE_NULL,
631 buffer
632 };
633 vk::VkMemoryDedicatedRequirements dedicatedRequirements =
634 {
635 vk::VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
636 DE_NULL,
637 VK_FALSE,
638 VK_FALSE
639 };
640 vk::VkMemoryRequirements2 requirements =
641 {
642 vk::VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
643 &dedicatedRequirements,
644 { 0u, 0u, 0u, }
645 };
646 vkd.getBufferMemoryRequirements2(device, &requirementInfo, &requirements);
647
648 if (!dedicated && dedicatedRequirements.requiresDedicatedAllocation)
649 TCU_THROW(NotSupportedError, "Memory requires dedicated allocation");
650
651 memoryRequirements = requirements.memoryRequirements;
652 }
653 else
654 {
655 vkd.getBufferMemoryRequirements(device, buffer, &memoryRequirements);
656 }
657
658 return memoryRequirements;
659 }
660
createImage(const vk::DeviceInterface & vkd,vk::VkDevice device,const ResourceDescription & resourceDesc,const vk::VkExtent3D extent,const std::vector<deUint32> & queueFamilyIndices,const OperationSupport & readOp,const OperationSupport & writeOp,vk::VkExternalMemoryHandleTypeFlagBits externalType)661 Move<VkImage> createImage(const vk::DeviceInterface& vkd,
662 vk::VkDevice device,
663 const ResourceDescription& resourceDesc,
664 const vk::VkExtent3D extent,
665 const std::vector<deUint32>& queueFamilyIndices,
666 const OperationSupport& readOp,
667 const OperationSupport& writeOp,
668 vk::VkExternalMemoryHandleTypeFlagBits externalType)
669 {
670 const vk::VkExternalMemoryImageCreateInfo externalInfo =
671 {
672 vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
673 DE_NULL,
674 (vk::VkExternalMemoryHandleTypeFlags)externalType
675 };
676 const vk::VkImageCreateInfo createInfo =
677 {
678 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
679 &externalInfo,
680 0u,
681
682 resourceDesc.imageType,
683 resourceDesc.imageFormat,
684 extent,
685 1u,
686 1u,
687 resourceDesc.imageSamples,
688 vk::VK_IMAGE_TILING_OPTIMAL,
689 readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
690 vk::VK_SHARING_MODE_EXCLUSIVE,
691
692 (deUint32)queueFamilyIndices.size(),
693 &queueFamilyIndices[0],
694 vk::VK_IMAGE_LAYOUT_UNDEFINED
695 };
696
697 return vk::createImage(vkd, device, &createInfo);
698 }
699
createBuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,const vk::VkDeviceSize size,const vk::VkBufferUsageFlags usage,const vk::VkExternalMemoryHandleTypeFlagBits memoryHandleType,const std::vector<deUint32> & queueFamilyIndices)700 Move<VkBuffer> createBuffer(const vk::DeviceInterface& vkd,
701 vk::VkDevice device,
702 const vk::VkDeviceSize size,
703 const vk::VkBufferUsageFlags usage,
704 const vk::VkExternalMemoryHandleTypeFlagBits memoryHandleType,
705 const std::vector<deUint32>& queueFamilyIndices)
706 {
707 const vk::VkExternalMemoryBufferCreateInfo externalInfo =
708 {
709 vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
710 DE_NULL,
711 (vk::VkExternalMemoryHandleTypeFlags)memoryHandleType
712 };
713 const vk::VkBufferCreateInfo createInfo =
714 {
715 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
716 &externalInfo,
717 0u,
718
719 size,
720 usage,
721 vk::VK_SHARING_MODE_EXCLUSIVE,
722 (deUint32)queueFamilyIndices.size(),
723 &queueFamilyIndices[0]
724 };
725 return vk::createBuffer(vkd, device, &createInfo);
726 }
727
importAndBindMemory(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkBuffer buffer,NativeHandle & nativeHandle,vk::VkExternalMemoryHandleTypeFlagBits externalType,deUint32 exportedMemoryTypeIndex,bool dedicated)728 de::MovePtr<vk::Allocation> importAndBindMemory (const vk::DeviceInterface& vkd,
729 vk::VkDevice device,
730 vk::VkBuffer buffer,
731 NativeHandle& nativeHandle,
732 vk::VkExternalMemoryHandleTypeFlagBits externalType,
733 deUint32 exportedMemoryTypeIndex,
734 bool dedicated)
735 {
736 const vk::VkMemoryRequirements requirements = vk::getBufferMemoryRequirements(vkd, device, buffer);
737 vk::Move<vk::VkDeviceMemory> memory = dedicated
738 ? importDedicatedMemory(vkd, device, buffer, requirements, externalType, exportedMemoryTypeIndex, nativeHandle)
739 : importMemory(vkd, device, requirements, externalType, exportedMemoryTypeIndex, nativeHandle);
740
741 VK_CHECK(vkd.bindBufferMemory(device, buffer, *memory, 0u));
742
743 return de::MovePtr<vk::Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
744 }
745
importAndBindMemory(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkImage image,NativeHandle & nativeHandle,vk::VkExternalMemoryHandleTypeFlagBits externalType,deUint32 exportedMemoryTypeIndex,bool dedicated)746 de::MovePtr<vk::Allocation> importAndBindMemory (const vk::DeviceInterface& vkd,
747 vk::VkDevice device,
748 vk::VkImage image,
749 NativeHandle& nativeHandle,
750 vk::VkExternalMemoryHandleTypeFlagBits externalType,
751 deUint32 exportedMemoryTypeIndex,
752 bool dedicated)
753 {
754 const vk::VkMemoryRequirements requirements = vk::getImageMemoryRequirements(vkd, device, image);
755 vk::Move<vk::VkDeviceMemory> memory = dedicated
756 ? importDedicatedMemory(vkd, device, image, requirements, externalType, exportedMemoryTypeIndex, nativeHandle)
757 : importMemory(vkd, device, requirements, externalType, exportedMemoryTypeIndex, nativeHandle);
758 VK_CHECK(vkd.bindImageMemory(device, image, *memory, 0u));
759
760 return de::MovePtr<vk::Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
761 }
762
importResource(const vk::DeviceInterface & vkd,vk::VkDevice device,const ResourceDescription & resourceDesc,const std::vector<deUint32> & queueFamilyIndices,const OperationSupport & readOp,const OperationSupport & writeOp,NativeHandle & nativeHandle,vk::VkExternalMemoryHandleTypeFlagBits externalType,deUint32 exportedMemoryTypeIndex,bool dedicated)763 de::MovePtr<Resource> importResource (const vk::DeviceInterface& vkd,
764 vk::VkDevice device,
765 const ResourceDescription& resourceDesc,
766 const std::vector<deUint32>& queueFamilyIndices,
767 const OperationSupport& readOp,
768 const OperationSupport& writeOp,
769 NativeHandle& nativeHandle,
770 vk::VkExternalMemoryHandleTypeFlagBits externalType,
771 deUint32 exportedMemoryTypeIndex,
772 bool dedicated)
773 {
774 if (resourceDesc.type == RESOURCE_TYPE_IMAGE)
775 {
776 const vk::VkExtent3D extent =
777 {
778 (deUint32)resourceDesc.size.x(),
779 de::max(1u, (deUint32)resourceDesc.size.y()),
780 de::max(1u, (deUint32)resourceDesc.size.z())
781 };
782 const vk::VkImageSubresourceRange subresourceRange =
783 {
784 resourceDesc.imageAspect,
785 0u,
786 1u,
787 0u,
788 1u
789 };
790 const vk::VkImageSubresourceLayers subresourceLayers =
791 {
792 resourceDesc.imageAspect,
793 0u,
794 0u,
795 1u
796 };
797 const vk:: VkExternalMemoryImageCreateInfo externalInfo =
798 {
799 vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
800 DE_NULL,
801 (vk::VkExternalMemoryHandleTypeFlags)externalType
802 };
803 const vk::VkImageTiling tiling = vk::VK_IMAGE_TILING_OPTIMAL;
804 const vk::VkImageCreateInfo createInfo =
805 {
806 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
807 &externalInfo,
808 0u,
809
810 resourceDesc.imageType,
811 resourceDesc.imageFormat,
812 extent,
813 1u,
814 1u,
815 resourceDesc.imageSamples,
816 tiling,
817 readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
818 vk::VK_SHARING_MODE_EXCLUSIVE,
819
820 (deUint32)queueFamilyIndices.size(),
821 &queueFamilyIndices[0],
822 vk::VK_IMAGE_LAYOUT_UNDEFINED
823 };
824
825 vk::Move<vk::VkImage> image = vk::createImage(vkd, device, &createInfo);
826 de::MovePtr<vk::Allocation> allocation = importAndBindMemory(vkd, device, *image, nativeHandle, externalType, exportedMemoryTypeIndex, dedicated);
827
828 return de::MovePtr<Resource>(new Resource(image, allocation, extent, resourceDesc.imageType, resourceDesc.imageFormat, subresourceRange, subresourceLayers, tiling));
829 }
830 else
831 {
832 const vk::VkDeviceSize offset = 0u;
833 const vk::VkDeviceSize size = static_cast<vk::VkDeviceSize>(resourceDesc.size.x());
834 const vk::VkBufferUsageFlags usage = readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags();
835 const vk:: VkExternalMemoryBufferCreateInfo externalInfo =
836 {
837 vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
838 DE_NULL,
839 (vk::VkExternalMemoryHandleTypeFlags)externalType
840 };
841 const vk::VkBufferCreateInfo createInfo =
842 {
843 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
844 &externalInfo,
845 0u,
846
847 size,
848 usage,
849 vk::VK_SHARING_MODE_EXCLUSIVE,
850 (deUint32)queueFamilyIndices.size(),
851 &queueFamilyIndices[0]
852 };
853 vk::Move<vk::VkBuffer> buffer = vk::createBuffer(vkd, device, &createInfo);
854 de::MovePtr<vk::Allocation> allocation = importAndBindMemory(vkd, device, *buffer, nativeHandle, externalType, exportedMemoryTypeIndex, dedicated);
855
856 return de::MovePtr<Resource>(new Resource(resourceDesc.type, buffer, allocation, offset, size));
857 }
858 }
859
recordWriteBarrier(SynchronizationWrapperPtr synchronizationWrapper,vk::VkCommandBuffer commandBuffer,const Resource & resource,const SyncInfo & writeSync,deUint32 writeQueueFamilyIndex,const SyncInfo & readSync)860 void recordWriteBarrier (SynchronizationWrapperPtr synchronizationWrapper,
861 vk::VkCommandBuffer commandBuffer,
862 const Resource& resource,
863 const SyncInfo& writeSync,
864 deUint32 writeQueueFamilyIndex,
865 const SyncInfo& readSync)
866 {
867 const vk::VkPipelineStageFlags2KHR srcStageMask = writeSync.stageMask;
868 const vk::VkAccessFlags2KHR srcAccessMask = writeSync.accessMask;
869
870 const vk::VkPipelineStageFlags2KHR dstStageMask = readSync.stageMask;
871 const vk::VkAccessFlags2KHR dstAccessMask = readSync.accessMask;
872
873 if (resource.getType() == RESOURCE_TYPE_IMAGE)
874 {
875 const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
876 srcStageMask, // VkPipelineStageFlags2KHR srcStageMask
877 srcAccessMask, // VkAccessFlags2KHR srcAccessMask
878 dstStageMask, // VkPipelineStageFlags2KHR dstStageMask
879 dstAccessMask, // VkAccessFlags2KHR dstAccessMask
880 writeSync.imageLayout, // VkImageLayout oldLayout
881 readSync.imageLayout, // VkImageLayout newLayout
882 resource.getImage().handle, // VkImage image
883 resource.getImage().subresourceRange, // VkImageSubresourceRange subresourceRange
884 writeQueueFamilyIndex, // deUint32 srcQueueFamilyIndex
885 VK_QUEUE_FAMILY_EXTERNAL // deUint32 dstQueueFamilyIndex
886 );
887 VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2);
888 synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
889 }
890 else
891 {
892 const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
893 srcStageMask, // VkPipelineStageFlags2KHR srcStageMask
894 srcAccessMask, // VkAccessFlags2KHR srcAccessMask
895 dstStageMask, // VkPipelineStageFlags2KHR dstStageMask
896 dstAccessMask, // VkAccessFlags2KHR dstAccessMask
897 resource.getBuffer().handle, // VkBuffer buffer
898 0, // VkDeviceSize offset
899 VK_WHOLE_SIZE, // VkDeviceSize size
900 writeQueueFamilyIndex, // deUint32 srcQueueFamilyIndex
901 VK_QUEUE_FAMILY_EXTERNAL // deUint32 dstQueueFamilyIndex
902 );
903 VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2);
904 synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
905 }
906 }
907
recordReadBarrier(SynchronizationWrapperPtr synchronizationWrapper,vk::VkCommandBuffer commandBuffer,const Resource & resource,const SyncInfo & writeSync,const SyncInfo & readSync,deUint32 readQueueFamilyIndex)908 void recordReadBarrier (SynchronizationWrapperPtr synchronizationWrapper,
909 vk::VkCommandBuffer commandBuffer,
910 const Resource& resource,
911 const SyncInfo& writeSync,
912 const SyncInfo& readSync,
913 deUint32 readQueueFamilyIndex)
914 {
915 const vk::VkPipelineStageFlags2KHR srcStageMask = readSync.stageMask;
916 const vk::VkAccessFlags2KHR srcAccessMask = readSync.accessMask;
917
918 const vk::VkPipelineStageFlags2KHR dstStageMask = readSync.stageMask;
919 const vk::VkAccessFlags2KHR dstAccessMask = readSync.accessMask;
920
921 if (resource.getType() == RESOURCE_TYPE_IMAGE)
922 {
923 const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
924 srcStageMask, // VkPipelineStageFlags2KHR srcStageMask
925 srcAccessMask, // VkAccessFlags2KHR srcAccessMask
926 dstStageMask, // VkPipelineStageFlags2KHR dstStageMask
927 dstAccessMask, // VkAccessFlags2KHR dstAccessMask
928 writeSync.imageLayout, // VkImageLayout oldLayout
929 readSync.imageLayout, // VkImageLayout newLayout
930 resource.getImage().handle, // VkImage image
931 resource.getImage().subresourceRange, // VkImageSubresourceRange subresourceRange
932 VK_QUEUE_FAMILY_EXTERNAL, // deUint32 srcQueueFamilyIndex
933 readQueueFamilyIndex // deUint32 dstQueueFamilyIndex
934 );
935 VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2);
936 synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
937 }
938 else
939 {
940 const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
941 srcStageMask, // VkPipelineStageFlags2KHR srcStageMask
942 srcAccessMask, // VkAccessFlags2KHR srcAccessMask
943 dstStageMask, // VkPipelineStageFlags2KHR dstStageMask
944 dstAccessMask, // VkAccessFlags2KHR dstAccessMask
945 resource.getBuffer().handle, // VkBuffer buffer
946 0, // VkDeviceSize offset
947 VK_WHOLE_SIZE, // VkDeviceSize size
948 VK_QUEUE_FAMILY_EXTERNAL, // deUint32 srcQueueFamilyIndex
949 readQueueFamilyIndex // deUint32 dstQueueFamilyIndex
950 );
951 VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, &bufferMemoryBarrier2);
952 synchronizationWrapper->cmdPipelineBarrier(commandBuffer, &dependencyInfo);
953 }
954 }
955
getFamilyIndices(const std::vector<vk::VkQueueFamilyProperties> & properties)956 std::vector<deUint32> getFamilyIndices (const std::vector<vk::VkQueueFamilyProperties>& properties)
957 {
958 std::vector<deUint32> indices (properties.size(), 0);
959
960 for (deUint32 ndx = 0; ndx < properties.size(); ndx++)
961 indices[ndx] = ndx;
962
963 return indices;
964 }
965
966 class SharingTestInstance : public TestInstance
967 {
968 public:
969 SharingTestInstance (Context& context,
970 TestConfig config);
971
972 virtual tcu::TestStatus iterate (void);
973
974 private:
975 const TestConfig m_config;
976
977 const de::UniquePtr<OperationSupport> m_supportWriteOp;
978 const de::UniquePtr<OperationSupport> m_supportReadOp;
979 const NotSupportedChecker m_notSupportedChecker; // Must declare before VkInstance to effectively reduce runtimes!
980
981 const bool m_getMemReq2Supported;
982
983 const vk::VkInstance m_instanceA;
984 const vk::InstanceDriver& m_vkiA;
985 const vk::VkPhysicalDevice m_physicalDeviceA;
986 const std::vector<vk::VkQueueFamilyProperties> m_queueFamiliesA;
987 const std::vector<deUint32> m_queueFamilyIndicesA;
988 const vk::Unique<vk::VkDevice>& m_deviceA;
989 const vk::DeviceDriver m_vkdA;
990
991 const vk::VkInstance m_instanceB;
992 const vk::InstanceDriver& m_vkiB;
993 const vk::VkPhysicalDevice m_physicalDeviceB;
994 const std::vector<vk::VkQueueFamilyProperties> m_queueFamiliesB;
995 const std::vector<deUint32> m_queueFamilyIndicesB;
996 const vk::Unique<vk::VkDevice>& m_deviceB;
997 const vk::DeviceDriver m_vkdB;
998
999 const vk::VkExternalSemaphoreHandleTypeFlagBits m_semaphoreHandleType;
1000 const vk::VkExternalMemoryHandleTypeFlagBits m_memoryHandleType;
1001
1002 // \todo Should this be moved to the group same way as in the other tests?
1003 PipelineCacheData m_pipelineCacheData;
1004 tcu::ResultCollector m_resultCollector;
1005 size_t m_queueANdx;
1006 size_t m_queueBNdx;
1007 };
1008
SharingTestInstance(Context & context,TestConfig config)1009 SharingTestInstance::SharingTestInstance (Context& context,
1010 TestConfig config)
1011 : TestInstance (context)
1012 , m_config (config)
1013 , m_supportWriteOp (makeOperationSupport(config.writeOp, config.resource))
1014 , m_supportReadOp (makeOperationSupport(config.readOp, config.resource))
1015 , m_notSupportedChecker (context, m_config, *m_supportWriteOp, *m_supportReadOp)
1016 , m_getMemReq2Supported (context.isDeviceFunctionalitySupported("VK_KHR_get_memory_requirements2"))
1017
1018 , m_instanceA (InstanceAndDevice::getInstanceA(context))
1019 , m_vkiA (InstanceAndDevice::getDriverA())
1020 , m_physicalDeviceA (InstanceAndDevice::getPhysicalDeviceA())
1021 , m_queueFamiliesA (vk::getPhysicalDeviceQueueFamilyProperties(m_vkiA, m_physicalDeviceA))
1022 , m_queueFamilyIndicesA (getFamilyIndices(m_queueFamiliesA))
1023 , m_deviceA (InstanceAndDevice::getDeviceA())
1024 , m_vkdA (context.getPlatformInterface(), m_instanceA, *m_deviceA)
1025
1026 , m_instanceB (InstanceAndDevice::getInstanceB(context))
1027 , m_vkiB (InstanceAndDevice::getDriverB())
1028 , m_physicalDeviceB (InstanceAndDevice::getPhysicalDeviceB())
1029 , m_queueFamiliesB (vk::getPhysicalDeviceQueueFamilyProperties(m_vkiB, m_physicalDeviceB))
1030 , m_queueFamilyIndicesB (getFamilyIndices(m_queueFamiliesB))
1031 , m_deviceB (InstanceAndDevice::getDeviceB())
1032 , m_vkdB (context.getPlatformInterface(), m_instanceB, *m_deviceB)
1033
1034 , m_semaphoreHandleType (m_config.semaphoreHandleType)
1035 , m_memoryHandleType (m_config.memoryHandleType)
1036
1037 , m_resultCollector (context.getTestContext().getLog())
1038 , m_queueANdx (0)
1039 , m_queueBNdx (0)
1040 {
1041 }
1042
iterate(void)1043 tcu::TestStatus SharingTestInstance::iterate (void)
1044 {
1045 TestLog& log (m_context.getTestContext().getLog());
1046 bool isTimelineSemaphore (m_config.semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE_KHR);
1047 try
1048 {
1049 const deUint32 queueFamilyA = (deUint32)m_queueANdx;
1050 const deUint32 queueFamilyB = (deUint32)m_queueBNdx;
1051
1052 const tcu::ScopedLogSection queuePairSection (log,
1053 "WriteQueue-" + de::toString(queueFamilyA) + "-ReadQueue-" + de::toString(queueFamilyB),
1054 "WriteQueue-" + de::toString(queueFamilyA) + "-ReadQueue-" + de::toString(queueFamilyB));
1055
1056 const vk::Unique<vk::VkSemaphore> semaphoreA (createExportableSemaphoreType(m_vkdA, *m_deviceA, m_config.semaphoreType, m_semaphoreHandleType));
1057 const vk::Unique<vk::VkSemaphore> semaphoreB (createSemaphoreType(m_vkdB, *m_deviceB, m_config.semaphoreType));
1058
1059 const ResourceDescription& resourceDesc = m_config.resource;
1060 de::MovePtr<Resource> resourceA;
1061
1062 deUint32 exportedMemoryTypeIndex = ~0U;
1063 if (resourceDesc.type == RESOURCE_TYPE_IMAGE)
1064 {
1065 const vk::VkExtent3D extent =
1066 {
1067 (deUint32)resourceDesc.size.x(),
1068 de::max(1u, (deUint32)resourceDesc.size.y()),
1069 de::max(1u, (deUint32)resourceDesc.size.z())
1070 };
1071 const vk::VkImageSubresourceRange subresourceRange =
1072 {
1073 resourceDesc.imageAspect,
1074 0u,
1075 1u,
1076 0u,
1077 1u
1078 };
1079 const vk::VkImageSubresourceLayers subresourceLayers =
1080 {
1081 resourceDesc.imageAspect,
1082 0u,
1083 0u,
1084 1u
1085 };
1086
1087 vk::Move<vk::VkImage> image = createImage(m_vkdA, *m_deviceA, resourceDesc, extent, m_queueFamilyIndicesA,
1088 *m_supportReadOp, *m_supportWriteOp, m_memoryHandleType);
1089 const vk::VkImageTiling tiling = vk::VK_IMAGE_TILING_OPTIMAL;
1090 const vk::VkMemoryRequirements requirements = getMemoryRequirements(m_vkdA, *m_deviceA, *image, m_config.dedicated, m_getMemReq2Supported);
1091 exportedMemoryTypeIndex = chooseMemoryType(requirements.memoryTypeBits);
1092 vk::Move<vk::VkDeviceMemory> memory = allocateExportableMemory(m_vkdA, *m_deviceA, requirements.size, exportedMemoryTypeIndex, m_memoryHandleType, m_config.dedicated ? *image : (vk::VkImage)0);
1093
1094 VK_CHECK(m_vkdA.bindImageMemory(*m_deviceA, *image, *memory, 0u));
1095
1096 de::MovePtr<vk::Allocation> allocation = de::MovePtr<vk::Allocation>(new SimpleAllocation(m_vkdA, *m_deviceA, memory.disown()));
1097 resourceA = de::MovePtr<Resource>(new Resource(image, allocation, extent, resourceDesc.imageType, resourceDesc.imageFormat, subresourceRange, subresourceLayers, tiling));
1098 }
1099 else
1100 {
1101 const vk::VkDeviceSize offset = 0u;
1102 const vk::VkDeviceSize size = static_cast<vk::VkDeviceSize>(resourceDesc.size.x());
1103 const vk::VkBufferUsageFlags usage = m_supportReadOp->getInResourceUsageFlags() | m_supportWriteOp->getOutResourceUsageFlags();
1104 vk::Move<vk::VkBuffer> buffer = createBuffer(m_vkdA, *m_deviceA, size, usage, m_memoryHandleType, m_queueFamilyIndicesA);
1105 const vk::VkMemoryRequirements requirements = getMemoryRequirements(m_vkdA, *m_deviceA, *buffer, m_config.dedicated, m_getMemReq2Supported);
1106 exportedMemoryTypeIndex = chooseMemoryType(requirements.memoryTypeBits);
1107 vk::Move<vk::VkDeviceMemory> memory = allocateExportableMemory(m_vkdA, *m_deviceA, requirements.size, exportedMemoryTypeIndex, m_memoryHandleType, m_config.dedicated ? *buffer : (vk::VkBuffer)0);
1108
1109 VK_CHECK(m_vkdA.bindBufferMemory(*m_deviceA, *buffer, *memory, 0u));
1110
1111 de::MovePtr<vk::Allocation> allocation = de::MovePtr<vk::Allocation>(new SimpleAllocation(m_vkdA, *m_deviceA, memory.disown()));
1112 resourceA = de::MovePtr<Resource>(new Resource(resourceDesc.type, buffer, allocation, offset, size));
1113 }
1114
1115 NativeHandle nativeMemoryHandle;
1116 getMemoryNative(m_vkdA, *m_deviceA, resourceA->getMemory(), m_memoryHandleType, nativeMemoryHandle);
1117
1118 const de::UniquePtr<Resource> resourceB (importResource(m_vkdB, *m_deviceB, resourceDesc, m_queueFamilyIndicesB, *m_supportReadOp, *m_supportWriteOp, nativeMemoryHandle, m_memoryHandleType, exportedMemoryTypeIndex, m_config.dedicated));
1119 const vk::VkQueue queueA (getQueue(m_vkdA, *m_deviceA, queueFamilyA));
1120 const vk::Unique<vk::VkCommandPool> commandPoolA (createCommandPool(m_vkdA, *m_deviceA, queueFamilyA));
1121 const vk::Unique<vk::VkCommandBuffer> commandBufferA (createCommandBuffer(m_vkdA, *m_deviceA, *commandPoolA));
1122 vk::SimpleAllocator allocatorA (m_vkdA, *m_deviceA, vk::getPhysicalDeviceMemoryProperties(m_vkiA, m_physicalDeviceA));
1123 OperationContext operationContextA (m_context, m_config.type, m_vkiA, m_vkdA, m_physicalDeviceA, *m_deviceA, allocatorA, m_context.getBinaryCollection(), m_pipelineCacheData);
1124
1125 if (!checkQueueFlags(m_queueFamiliesA[m_queueANdx].queueFlags , m_supportWriteOp->getQueueFlags(operationContextA)))
1126 TCU_THROW(NotSupportedError, "Operation not supported by the source queue");
1127
1128 const vk::VkQueue queueB (getQueue(m_vkdB, *m_deviceB, queueFamilyB));
1129 const vk::Unique<vk::VkCommandPool> commandPoolB (createCommandPool(m_vkdB, *m_deviceB, queueFamilyB));
1130 const vk::Unique<vk::VkCommandBuffer> commandBufferB (createCommandBuffer(m_vkdB, *m_deviceB, *commandPoolB));
1131 vk::SimpleAllocator allocatorB (m_vkdB, *m_deviceB, vk::getPhysicalDeviceMemoryProperties(m_vkiB, m_physicalDeviceB));
1132 OperationContext operationContextB (m_context, m_config.type, m_vkiB, m_vkdB, m_physicalDeviceB, *m_deviceB, allocatorB, m_context.getBinaryCollection(), m_pipelineCacheData);
1133
1134 if (!checkQueueFlags(m_queueFamiliesB[m_queueBNdx].queueFlags , m_supportReadOp->getQueueFlags(operationContextB)))
1135 TCU_THROW(NotSupportedError, "Operation not supported by the destination queue");
1136
1137 const de::UniquePtr<Operation> writeOp (m_supportWriteOp->build(operationContextA, *resourceA));
1138 const de::UniquePtr<Operation> readOp (m_supportReadOp->build(operationContextB, *resourceB));
1139
1140 const SyncInfo writeSync = writeOp->getOutSyncInfo();
1141 const SyncInfo readSync = readOp->getInSyncInfo();
1142 SynchronizationWrapperPtr synchronizationWrapperA = getSynchronizationWrapper(m_config.type, m_vkdA, isTimelineSemaphore);
1143 SynchronizationWrapperPtr synchronizationWrapperB = getSynchronizationWrapper(m_config.type, m_vkdB, isTimelineSemaphore);
1144
1145 beginCommandBuffer(m_vkdA, *commandBufferA);
1146 writeOp->recordCommands(*commandBufferA);
1147 recordWriteBarrier(synchronizationWrapperA, *commandBufferA, *resourceA, writeSync, queueFamilyA, readSync);
1148 endCommandBuffer(m_vkdA, *commandBufferA);
1149
1150 beginCommandBuffer(m_vkdB, *commandBufferB);
1151 recordReadBarrier(synchronizationWrapperB, *commandBufferB, *resourceB, writeSync, readSync, queueFamilyB);
1152 readOp->recordCommands(*commandBufferB);
1153 endCommandBuffer(m_vkdB, *commandBufferB);
1154
1155 {
1156 de::Random rng (1234);
1157 vk::VkCommandBufferSubmitInfoKHR cmdBufferInfos = makeCommonCommandBufferSubmitInfo(*commandBufferA);
1158 VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo =
1159 makeCommonSemaphoreSubmitInfo(*semaphoreA, rng.getInt(1, deIntMaxValue32(32)), VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
1160
1161 synchronizationWrapperA->addSubmitInfo(
1162 0u,
1163 DE_NULL,
1164 1u,
1165 &cmdBufferInfos,
1166 1u,
1167 &signalSemaphoreSubmitInfo,
1168 DE_FALSE,
1169 isTimelineSemaphore
1170 );
1171
1172 VK_CHECK(synchronizationWrapperA->queueSubmit(queueA, DE_NULL));
1173
1174 {
1175 NativeHandle nativeSemaphoreHandle;
1176 const vk::VkSemaphoreImportFlags flags = isSupportedPermanence(m_semaphoreHandleType, PERMANENCE_PERMANENT) ? (vk::VkSemaphoreImportFlagBits)0u : vk::VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
1177
1178 getSemaphoreNative(m_vkdA, *m_deviceA, *semaphoreA, m_semaphoreHandleType, nativeSemaphoreHandle);
1179 importSemaphore(m_vkdB, *m_deviceB, *semaphoreB, m_semaphoreHandleType, nativeSemaphoreHandle, flags);
1180 }
1181 }
1182 {
1183 vk::VkCommandBufferSubmitInfoKHR cmdBufferInfos = makeCommonCommandBufferSubmitInfo(*commandBufferB);
1184 VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo =
1185 makeCommonSemaphoreSubmitInfo(*semaphoreB, 1u, readSync.stageMask);
1186
1187 synchronizationWrapperB->addSubmitInfo(
1188 1u,
1189 &waitSemaphoreSubmitInfo,
1190 1u,
1191 &cmdBufferInfos,
1192 0u,
1193 DE_NULL,
1194 isTimelineSemaphore
1195 );
1196
1197 VK_CHECK(synchronizationWrapperB->queueSubmit(queueB, DE_NULL));
1198 }
1199
1200 VK_CHECK(m_vkdA.queueWaitIdle(queueA));
1201 VK_CHECK(m_vkdB.queueWaitIdle(queueB));
1202
1203 if (m_config.semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE)
1204 {
1205 deUint64 valueA;
1206 deUint64 valueB;
1207
1208 VK_CHECK(m_vkdA.getSemaphoreCounterValue(*m_deviceA, *semaphoreA, &valueA));
1209 VK_CHECK(m_vkdB.getSemaphoreCounterValue(*m_deviceB, *semaphoreB, &valueB));
1210
1211 if (valueA != valueB)
1212 return tcu::TestStatus::fail("Inconsistent values between shared semaphores");
1213 }
1214
1215 {
1216 const Data expected = writeOp->getData();
1217 const Data actual = readOp->getData();
1218
1219 DE_ASSERT(expected.size == actual.size);
1220
1221 if (!isIndirectBuffer(m_config.resource.type))
1222 {
1223 if (0 != deMemCmp(expected.data, actual.data, expected.size))
1224 {
1225 const size_t maxBytesLogged = 256;
1226 std::ostringstream expectedData;
1227 std::ostringstream actualData;
1228 size_t byteNdx = 0;
1229
1230 // Find first byte difference
1231 for (; actual.data[byteNdx] == expected.data[byteNdx]; byteNdx++)
1232 {
1233 // Nothing
1234 }
1235
1236 log << TestLog::Message << "First different byte at offset: " << byteNdx << TestLog::EndMessage;
1237
1238 // Log 8 previous bytes before the first incorrect byte
1239 if (byteNdx > 8)
1240 {
1241 expectedData << "... ";
1242 actualData << "... ";
1243
1244 byteNdx -= 8;
1245 }
1246 else
1247 byteNdx = 0;
1248
1249 for (size_t i = 0; i < maxBytesLogged && byteNdx < expected.size; i++, byteNdx++)
1250 {
1251 expectedData << (i > 0 ? ", " : "") << (deUint32)expected.data[byteNdx];
1252 actualData << (i > 0 ? ", " : "") << (deUint32)actual.data[byteNdx];
1253 }
1254
1255 if (expected.size > byteNdx)
1256 {
1257 expectedData << "...";
1258 actualData << "...";
1259 }
1260
1261 log << TestLog::Message << "Expected data: (" << expectedData.str() << ")" << TestLog::EndMessage;
1262 log << TestLog::Message << "Actual data: (" << actualData.str() << ")" << TestLog::EndMessage;
1263
1264 m_resultCollector.fail("Memory contents don't match");
1265 }
1266 }
1267 else
1268 {
1269 const deUint32 expectedValue = reinterpret_cast<const deUint32*>(expected.data)[0];
1270 const deUint32 actualValue = reinterpret_cast<const deUint32*>(actual.data)[0];
1271
1272 if (actualValue < expectedValue)
1273 {
1274 log << TestLog::Message << "Expected counter value: (" << expectedValue << ")" << TestLog::EndMessage;
1275 log << TestLog::Message << "Actual counter value: (" << actualValue << ")" << TestLog::EndMessage;
1276
1277 m_resultCollector.fail("Counter value is smaller than expected");
1278 }
1279 }
1280 }
1281 }
1282 catch (const tcu::NotSupportedError& error)
1283 {
1284 log << TestLog::Message << "Not supported: " << error.getMessage() << TestLog::EndMessage;
1285 }
1286 catch (const tcu::TestError& error)
1287 {
1288 m_resultCollector.fail(std::string("Exception: ") + error.getMessage());
1289 }
1290
1291 // Collect possible validation errors.
1292 InstanceAndDevice::collectMessagesA();
1293 InstanceAndDevice::collectMessagesB();
1294
1295 // Move to next queue
1296 {
1297 m_queueBNdx++;
1298
1299 if (m_queueBNdx >= m_queueFamiliesB.size())
1300 {
1301 m_queueANdx++;
1302
1303 if (m_queueANdx >= m_queueFamiliesA.size())
1304 {
1305 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1306 }
1307 else
1308 {
1309 m_queueBNdx = 0;
1310
1311 return tcu::TestStatus::incomplete();
1312 }
1313 }
1314 else
1315 return tcu::TestStatus::incomplete();
1316 }
1317 }
1318
1319 struct Progs
1320 {
initvkt::synchronization::__anon824781910111::Progs1321 void init (vk::SourceCollections& dst, TestConfig config) const
1322 {
1323 const de::UniquePtr<OperationSupport> readOp (makeOperationSupport(config.readOp, config.resource));
1324 const de::UniquePtr<OperationSupport> writeOp (makeOperationSupport(config.writeOp, config.resource));
1325
1326 readOp->initPrograms(dst);
1327 writeOp->initPrograms(dst);
1328 }
1329 };
1330
1331 } // anonymous
1332
createTests(tcu::TestCaseGroup * group,SynchronizationType type)1333 static void createTests (tcu::TestCaseGroup* group, SynchronizationType type)
1334 {
1335 tcu::TestContext& testCtx = group->getTestContext();
1336 const struct
1337 {
1338 vk::VkExternalMemoryHandleTypeFlagBits memoryType;
1339 vk::VkExternalSemaphoreHandleTypeFlagBits semaphoreType;
1340 const char* nameSuffix;
1341 } cases[] =
1342 {
1343 {
1344 vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
1345 vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1346 "_fd"
1347 },
1348 {
1349 vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
1350 vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
1351 "_fence_fd"
1352 },
1353 {
1354 vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
1355 vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
1356 "_win32_kmt"
1357 },
1358 {
1359 vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
1360 vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT,
1361 "_win32"
1362 },
1363 {
1364 vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
1365 vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1366 "_dma_buf"
1367 },
1368 {
1369 vk::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA,
1370 vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
1371 "_zircon_handle"
1372 },
1373 };
1374
1375 const std::string semaphoreNames[vk::VK_SEMAPHORE_TYPE_LAST] =
1376 {
1377 "_binary_semaphore",
1378 "_timeline_semaphore",
1379 };
1380
1381 for (size_t dedicatedNdx = 0; dedicatedNdx < 2; dedicatedNdx++)
1382 {
1383 const bool dedicated (dedicatedNdx == 1);
1384 de::MovePtr<tcu::TestCaseGroup> dedicatedGroup (new tcu::TestCaseGroup(testCtx, dedicated ? "dedicated" : "suballocated", ""));
1385
1386 for (size_t writeOpNdx = 0; writeOpNdx < DE_LENGTH_OF_ARRAY(s_writeOps); ++writeOpNdx)
1387 for (size_t readOpNdx = 0; readOpNdx < DE_LENGTH_OF_ARRAY(s_readOps); ++readOpNdx)
1388 {
1389 const OperationName writeOp = s_writeOps[writeOpNdx];
1390 const OperationName readOp = s_readOps[readOpNdx];
1391 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
1392 bool empty = true;
1393
1394 de::MovePtr<tcu::TestCaseGroup> opGroup (new tcu::TestCaseGroup(testCtx, opGroupName.c_str(), ""));
1395
1396 for (size_t resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
1397 {
1398 const ResourceDescription& resource = s_resources[resourceNdx];
1399
1400 for (size_t caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
1401 {
1402 for (int semaphoreType = 0; semaphoreType < vk::VK_SEMAPHORE_TYPE_LAST; semaphoreType++)
1403 {
1404 if (cases[caseNdx].semaphoreType == vk::VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT &&
1405 (vk::VkSemaphoreType)semaphoreType == vk::VK_SEMAPHORE_TYPE_TIMELINE)
1406 {
1407 continue;
1408 }
1409
1410 if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
1411 {
1412 const TestConfig config (type, resource, (vk::VkSemaphoreType)semaphoreType, writeOp, readOp, cases[caseNdx].memoryType, cases[caseNdx].semaphoreType, dedicated);
1413 std::string name = getResourceName(resource) + semaphoreNames[semaphoreType] + cases[caseNdx].nameSuffix;
1414
1415 opGroup->addChild(new InstanceFactory1<SharingTestInstance, TestConfig, Progs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, "", Progs(), config));
1416 empty = false;
1417 }
1418 }
1419 }
1420 }
1421
1422 if (!empty)
1423 dedicatedGroup->addChild(opGroup.release());
1424 }
1425
1426 group->addChild(dedicatedGroup.release());
1427 }
1428 }
1429
cleanupGroup(tcu::TestCaseGroup * group,SynchronizationType type)1430 static void cleanupGroup (tcu::TestCaseGroup* group, SynchronizationType type)
1431 {
1432 DE_UNREF(group);
1433 DE_UNREF(type);
1434 // Destroy singleton object
1435 InstanceAndDevice::destroy();
1436 }
1437
createCrossInstanceSharingTest(tcu::TestContext & testCtx,SynchronizationType type)1438 tcu::TestCaseGroup* createCrossInstanceSharingTest (tcu::TestContext& testCtx, SynchronizationType type)
1439 {
1440 return createTestGroup(testCtx, "cross_instance", "", createTests, type, cleanupGroup);
1441 }
1442
1443 } // synchronization
1444 } // vkt
1445