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