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