• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*------------------------------------------------------------------------
3  * Vulkan Conformance Tests
4  * ------------------------
5  *
6  * Copyright (c) 2019 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Signal ordering tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktSynchronizationSignalOrderTests.hpp"
26 #include "vktSynchronizationOperation.hpp"
27 #include "vktSynchronizationOperationTestData.hpp"
28 #include "vktSynchronizationOperationResources.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktSynchronizationUtil.hpp"
31 #include "vktExternalMemoryUtil.hpp"
32 #include "vktCustomInstancesDevices.hpp"
33 #include "vkBarrierUtil.hpp"
34 
35 #include "vkDefs.hpp"
36 #include "vkPlatform.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkCmdUtil.hpp"
39 #include "vkImageUtil.hpp"
40 #include "vkRef.hpp"
41 #include "vkTypeUtil.hpp"
42 
43 #include "tcuTestLog.hpp"
44 #include "tcuCommandLine.hpp"
45 
46 #include "deRandom.hpp"
47 #include "deThread.hpp"
48 #include "deUniquePtr.hpp"
49 
50 #include <limits>
51 #include <set>
52 
53 namespace vkt
54 {
55 namespace synchronization
56 {
57 namespace
58 {
59 
60 using namespace vk;
61 using namespace vkt::ExternalMemoryUtil;
62 using de::MovePtr;
63 using de::SharedPtr;
64 using de::UniquePtr;
65 
66 template <typename T>
makeVkSharedPtr(Move<T> move)67 inline SharedPtr<Move<T>> makeVkSharedPtr(Move<T> move)
68 {
69     return SharedPtr<Move<T>>(new Move<T>(move));
70 }
71 
72 template <typename T>
makeSharedPtr(de::MovePtr<T> move)73 inline SharedPtr<T> makeSharedPtr(de::MovePtr<T> move)
74 {
75     return SharedPtr<T>(move.release());
76 }
77 
78 template <typename T>
makeSharedPtr(T * ptr)79 inline SharedPtr<T> makeSharedPtr(T *ptr)
80 {
81     return SharedPtr<T>(ptr);
82 }
83 
hostSignal(const DeviceInterface & vk,const VkDevice & device,VkSemaphore semaphore,const uint64_t timelineValue)84 void hostSignal(const DeviceInterface &vk, const VkDevice &device, VkSemaphore semaphore, const uint64_t timelineValue)
85 {
86     VkSemaphoreSignalInfoKHR ssi = {
87         VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, // VkStructureType sType;
88         nullptr,                                 // const void* pNext;
89         semaphore,                               // VkSemaphore semaphore;
90         timelineValue,                           // uint64_t value;
91     };
92 
93     VK_CHECK(vk.signalSemaphore(device, &ssi));
94 }
95 
96 // Waits for the device to be idle when destroying the guard object.
97 class DeviceWaitIdleGuard
98 {
99 public:
DeviceWaitIdleGuard(const DeviceInterface & vkd,const VkDevice device)100     DeviceWaitIdleGuard(const DeviceInterface &vkd, const VkDevice device) : m_vkd(vkd), m_device(device)
101     {
102     }
103 
~DeviceWaitIdleGuard()104     ~DeviceWaitIdleGuard()
105     {
106         VK_CHECK(m_vkd.deviceWaitIdle(m_device));
107     }
108 
109 protected:
110     const DeviceInterface &m_vkd;
111     const VkDevice m_device;
112 };
113 
createTestDevice(const Context & context)114 Move<VkDevice> createTestDevice(const Context &context)
115 {
116     const float priority = 0.0f;
117     const std::vector<VkQueueFamilyProperties> queueFamilyProperties =
118         getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
119     std::vector<uint32_t> queueFamilyIndices(queueFamilyProperties.size(), 0xFFFFFFFFu);
120     std::vector<const char *> extensions;
121 
122     VkPhysicalDeviceFeatures2 createPhysicalFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, nullptr,
123                                                     context.getDeviceFeatures()};
124     VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreFeatures{
125         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, nullptr, true};
126     VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features{
127         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, nullptr, true};
128     void **nextPtr = &createPhysicalFeature.pNext;
129 
130     if (context.isDeviceFunctionalitySupported("VK_KHR_timeline_semaphore"))
131     {
132         extensions.push_back("VK_KHR_timeline_semaphore");
133         addToChainVulkanStructure(&nextPtr, timelineSemaphoreFeatures);
134     }
135 
136     if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_external_semaphore"))
137         extensions.push_back("VK_KHR_external_semaphore");
138     if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_external_memory"))
139         extensions.push_back("VK_KHR_external_memory");
140 
141     if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_fd"))
142         extensions.push_back("VK_KHR_external_semaphore_fd");
143 
144     if (context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_win32"))
145         extensions.push_back("VK_KHR_external_semaphore_win32");
146 
147     if (context.isDeviceFunctionalitySupported("VK_KHR_external_memory_win32"))
148         extensions.push_back("VK_KHR_external_memory_win32");
149 
150     if (context.isDeviceFunctionalitySupported("VK_KHR_synchronization2"))
151     {
152         extensions.push_back("VK_KHR_synchronization2");
153         addToChainVulkanStructure(&nextPtr, synchronization2Features);
154     }
155 
156     try
157     {
158         uint32_t maxQueueCount = 1;
159         for (const VkQueueFamilyProperties &qfp : queueFamilyProperties)
160             maxQueueCount = deMaxu32(qfp.queueCount, maxQueueCount);
161 
162         std::vector<float> queuePriorities(maxQueueCount, priority);
163         std::vector<VkDeviceQueueCreateInfo> queues;
164 
165         for (size_t ndx = 0; ndx < queueFamilyProperties.size(); ndx++)
166         {
167             const VkDeviceQueueCreateInfo createInfo = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
168                                                         nullptr,
169                                                         0u,
170 
171                                                         (uint32_t)ndx,
172                                                         queueFamilyProperties[ndx].queueCount,
173                                                         queuePriorities.data()};
174 
175             queues.push_back(createInfo);
176         }
177 
178         const VkDeviceCreateInfo createInfo = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
179                                                &createPhysicalFeature,
180                                                0u,
181 
182                                                (uint32_t)queues.size(),
183                                                &queues[0],
184 
185                                                0u,
186                                                nullptr,
187 
188                                                (uint32_t)extensions.size(),
189                                                extensions.empty() ? nullptr : &extensions[0],
190                                                0u};
191 
192         const auto validation = context.getTestContext().getCommandLine().isValidationEnabled();
193         return createCustomDevice(validation, context.getPlatformInterface(), context.getInstance(),
194                                   context.getInstanceInterface(), context.getPhysicalDevice(), &createInfo);
195     }
196     catch (const vk::Error &error)
197     {
198         if (error.getError() == VK_ERROR_EXTENSION_NOT_PRESENT)
199             TCU_THROW(NotSupportedError, "Required extensions not supported");
200         else
201             throw;
202     }
203 }
204 
205 // Class to wrap a singleton instance and device
206 class SingletonDevice
207 {
SingletonDevice(const Context & context)208     SingletonDevice(const Context &context) : m_logicalDevice(createTestDevice(context))
209     {
210     }
211 
212 public:
getDevice(const Context & context)213     static const Unique<vk::VkDevice> &getDevice(const Context &context)
214     {
215         if (!m_singletonDevice)
216             m_singletonDevice = SharedPtr<SingletonDevice>(new SingletonDevice(context));
217 
218         DE_ASSERT(m_singletonDevice);
219         return m_singletonDevice->m_logicalDevice;
220     }
221 
destroy()222     static void destroy()
223     {
224         m_singletonDevice.clear();
225     }
226 
227 private:
228     const Unique<vk::VkDevice> m_logicalDevice;
229 
230     static SharedPtr<SingletonDevice> m_singletonDevice;
231 };
232 SharedPtr<SingletonDevice> SingletonDevice::m_singletonDevice;
233 
cleanupGroup()234 static void cleanupGroup()
235 {
236     // Destroy singleton object
237     SingletonDevice::destroy();
238 }
239 
240 class SimpleAllocation : public Allocation
241 {
242 public:
243     SimpleAllocation(const DeviceInterface &vkd, VkDevice device, const VkDeviceMemory memory);
244     ~SimpleAllocation(void);
245 
246 private:
247     const DeviceInterface &m_vkd;
248     const VkDevice m_device;
249 };
250 
SimpleAllocation(const DeviceInterface & vkd,VkDevice device,const VkDeviceMemory memory)251 SimpleAllocation::SimpleAllocation(const DeviceInterface &vkd, VkDevice device, const VkDeviceMemory memory)
252     : Allocation(memory, 0, nullptr)
253     , m_vkd(vkd)
254     , m_device(device)
255 {
256 }
257 
~SimpleAllocation(void)258 SimpleAllocation::~SimpleAllocation(void)
259 {
260     m_vkd.freeMemory(m_device, getMemory(), nullptr);
261 }
262 
getMemoryRequirements(const DeviceInterface & vkd,VkDevice device,VkBuffer buffer)263 vk::VkMemoryRequirements getMemoryRequirements(const DeviceInterface &vkd, VkDevice device, VkBuffer buffer)
264 {
265     const VkBufferMemoryRequirementsInfo2 requirementInfo = {VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
266                                                              nullptr, buffer};
267     VkMemoryRequirements2 requirements                    = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
268                                                              nullptr,
269                                                              {
270                                               0u,
271                                               0u,
272                                               0u,
273                                           }};
274     vkd.getBufferMemoryRequirements2(device, &requirementInfo, &requirements);
275     return requirements.memoryRequirements;
276 }
277 
getMemoryRequirements(const DeviceInterface & vkd,VkDevice device,VkImage image)278 vk::VkMemoryRequirements getMemoryRequirements(const DeviceInterface &vkd, VkDevice device, VkImage image)
279 {
280     const VkImageMemoryRequirementsInfo2 requirementInfo = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, nullptr,
281                                                             image};
282     VkMemoryRequirements2 requirements                   = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
283                                                             nullptr,
284                                                             {
285                                               0u,
286                                               0u,
287                                               0u,
288                                           }};
289     vkd.getImageMemoryRequirements2(device, &requirementInfo, &requirements);
290 
291     return requirements.memoryRequirements;
292 }
293 
importAndBindMemory(const DeviceInterface & vkd,VkDevice device,VkBuffer buffer,NativeHandle & nativeHandle,VkExternalMemoryHandleTypeFlagBits externalType,const uint32_t exportedMemoryTypeIndex)294 MovePtr<Allocation> importAndBindMemory(const DeviceInterface &vkd, VkDevice device, VkBuffer buffer,
295                                         NativeHandle &nativeHandle, VkExternalMemoryHandleTypeFlagBits externalType,
296                                         const uint32_t exportedMemoryTypeIndex)
297 {
298     const VkMemoryRequirements requirements = getBufferMemoryRequirements(vkd, device, buffer);
299     Move<VkDeviceMemory> memory;
300 
301     if (!!buffer)
302         memory = importDedicatedMemory(vkd, device, buffer, requirements, externalType, exportedMemoryTypeIndex,
303                                        nativeHandle);
304     else
305         memory = importMemory(vkd, device, requirements, externalType, exportedMemoryTypeIndex, nativeHandle);
306 
307     VK_CHECK(vkd.bindBufferMemory(device, buffer, *memory, 0u));
308 
309     return MovePtr<Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
310 }
311 
importAndBindMemory(const DeviceInterface & vkd,VkDevice device,VkImage image,NativeHandle & nativeHandle,VkExternalMemoryHandleTypeFlagBits externalType,uint32_t exportedMemoryTypeIndex)312 MovePtr<Allocation> importAndBindMemory(const DeviceInterface &vkd, VkDevice device, VkImage image,
313                                         NativeHandle &nativeHandle, VkExternalMemoryHandleTypeFlagBits externalType,
314                                         uint32_t exportedMemoryTypeIndex)
315 {
316     const VkMemoryRequirements requirements = getImageMemoryRequirements(vkd, device, image);
317     Move<VkDeviceMemory> memory;
318 
319     if (!!image)
320         memory = importDedicatedMemory(vkd, device, image, requirements, externalType, exportedMemoryTypeIndex,
321                                        nativeHandle);
322     else
323         memory = importMemory(vkd, device, requirements, externalType, exportedMemoryTypeIndex, nativeHandle);
324 
325     VK_CHECK(vkd.bindImageMemory(device, image, *memory, 0u));
326 
327     return MovePtr<Allocation>(new SimpleAllocation(vkd, device, memory.disown()));
328 }
329 
330 struct QueueTimelineIteration
331 {
QueueTimelineIterationvkt::synchronization::__anon927627aa0111::QueueTimelineIteration332     QueueTimelineIteration(const SharedPtr<OperationSupport> &_opSupport, uint64_t lastValue, VkQueue _queue,
333                            uint32_t _queueFamilyIdx, de::Random &rng)
334         : opSupport(_opSupport)
335         , queue(_queue)
336         , queueFamilyIdx(_queueFamilyIdx)
337     {
338         timelineValue = lastValue + rng.getInt(1, 100);
339     }
~QueueTimelineIterationvkt::synchronization::__anon927627aa0111::QueueTimelineIteration340     ~QueueTimelineIteration()
341     {
342     }
343 
344     SharedPtr<OperationSupport> opSupport;
345     VkQueue queue;
346     uint32_t queueFamilyIdx;
347     uint64_t timelineValue;
348     SharedPtr<Operation> op;
349 };
350 
importResource(const DeviceInterface & vkd,VkDevice device,const ResourceDescription & resourceDesc,const uint32_t queueFamilyIndex,const OperationSupport & readOp,const OperationSupport & writeOp,NativeHandle & nativeHandle,VkExternalMemoryHandleTypeFlagBits externalType,uint32_t exportedMemoryTypeIndex)351 de::MovePtr<Resource> importResource(const DeviceInterface &vkd, VkDevice device,
352                                      const ResourceDescription &resourceDesc, const uint32_t queueFamilyIndex,
353                                      const OperationSupport &readOp, const OperationSupport &writeOp,
354                                      NativeHandle &nativeHandle, VkExternalMemoryHandleTypeFlagBits externalType,
355                                      uint32_t exportedMemoryTypeIndex)
356 {
357     if (resourceDesc.type == RESOURCE_TYPE_IMAGE)
358     {
359         const VkExtent3D extent = {(uint32_t)resourceDesc.size.x(), de::max(1u, (uint32_t)resourceDesc.size.y()),
360                                    de::max(1u, (uint32_t)resourceDesc.size.z())};
361         const VkImageSubresourceRange subresourceRange     = {resourceDesc.imageAspect, 0u, 1u, 0u, 1u};
362         const VkImageSubresourceLayers subresourceLayers   = {resourceDesc.imageAspect, 0u, 0u, 1u};
363         const VkExternalMemoryImageCreateInfo externalInfo = {VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
364                                                               nullptr, (VkExternalMemoryHandleTypeFlags)externalType};
365         const VkImageTiling tiling                         = VK_IMAGE_TILING_OPTIMAL;
366         const VkImageCreateInfo createInfo                 = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
367                                                               &externalInfo,
368                                                               0u,
369 
370                                                               resourceDesc.imageType,
371                                                               resourceDesc.imageFormat,
372                                                               extent,
373                                                               1u,
374                                                               1u,
375                                                               resourceDesc.imageSamples,
376                                                               tiling,
377                                                               readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags(),
378                                                               VK_SHARING_MODE_EXCLUSIVE,
379 
380                                                               1u,
381                                                               &queueFamilyIndex,
382                                                               VK_IMAGE_LAYOUT_UNDEFINED};
383 
384         Move<VkImage> image = createImage(vkd, device, &createInfo);
385         MovePtr<Allocation> allocation =
386             importAndBindMemory(vkd, device, *image, nativeHandle, externalType, exportedMemoryTypeIndex);
387 
388         return MovePtr<Resource>(new Resource(image, allocation, extent, resourceDesc.imageType,
389                                               resourceDesc.imageFormat, subresourceRange, subresourceLayers, tiling));
390     }
391     else
392     {
393         const VkDeviceSize offset      = 0u;
394         const VkDeviceSize size        = static_cast<VkDeviceSize>(resourceDesc.size.x());
395         const VkBufferUsageFlags usage = readOp.getInResourceUsageFlags() | writeOp.getOutResourceUsageFlags();
396         const VkExternalMemoryBufferCreateInfo externalInfo = {VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
397                                                                nullptr, (VkExternalMemoryHandleTypeFlags)externalType};
398         const VkBufferCreateInfo createInfo                 = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
399                                                                &externalInfo,
400                                                                0u,
401 
402                                                                size,
403                                                                usage,
404                                                                VK_SHARING_MODE_EXCLUSIVE,
405                                                                1u,
406                                                                &queueFamilyIndex};
407         Move<VkBuffer> buffer                               = createBuffer(vkd, device, &createInfo);
408         MovePtr<Allocation> allocation =
409             importAndBindMemory(vkd, device, *buffer, nativeHandle, externalType, exportedMemoryTypeIndex);
410 
411         return MovePtr<Resource>(new Resource(resourceDesc.type, buffer, allocation, offset, size));
412     }
413 }
414 
415 struct QueueSubmitOrderSharedIteration
416 {
QueueSubmitOrderSharedIterationvkt::synchronization::__anon927627aa0111::QueueSubmitOrderSharedIteration417     QueueSubmitOrderSharedIteration()
418     {
419     }
~QueueSubmitOrderSharedIterationvkt::synchronization::__anon927627aa0111::QueueSubmitOrderSharedIteration420     ~QueueSubmitOrderSharedIteration()
421     {
422     }
423 
424     SharedPtr<Resource> resourceA;
425     SharedPtr<Resource> resourceB;
426 
427     SharedPtr<Operation> writeOp;
428     SharedPtr<Operation> readOp;
429 };
430 
431 // Verifies the signaling order of the semaphores in multiple
432 // VkSubmitInfo given to vkQueueSubmit() with queueA & queueB from a
433 // different VkDevice.
434 //
435 // vkQueueSubmit(queueA, [write0, write1, write2, ..., write6])
436 // vkQueueSubmit(queueB, [read0-6])
437 //
438 // With read0-6 waiting on write6, all the data should be available
439 // for reading given that signal operations are supposed to happen in
440 // order.
441 class QueueSubmitSignalOrderSharedTestInstance : public TestInstance
442 {
443 public:
QueueSubmitSignalOrderSharedTestInstance(Context & context,SynchronizationType type,const SharedPtr<OperationSupport> writeOpSupport,const SharedPtr<OperationSupport> readOpSupport,const ResourceDescription & resourceDesc,VkExternalMemoryHandleTypeFlagBits memoryHandleType,VkSemaphoreType semaphoreType,VkExternalSemaphoreHandleTypeFlagBits semaphoreHandleType,PipelineCacheData & pipelineCacheData)444     QueueSubmitSignalOrderSharedTestInstance(
445         Context &context, SynchronizationType type, const SharedPtr<OperationSupport> writeOpSupport,
446         const SharedPtr<OperationSupport> readOpSupport, const ResourceDescription &resourceDesc,
447         VkExternalMemoryHandleTypeFlagBits memoryHandleType, VkSemaphoreType semaphoreType,
448         VkExternalSemaphoreHandleTypeFlagBits semaphoreHandleType, PipelineCacheData &pipelineCacheData)
449         : TestInstance(context)
450         , m_type(type)
451         , m_writeOpSupport(writeOpSupport)
452         , m_readOpSupport(readOpSupport)
453         , m_resourceDesc(resourceDesc)
454         , m_memoryHandleType(memoryHandleType)
455         , m_semaphoreType(semaphoreType)
456         , m_semaphoreHandleType(semaphoreHandleType)
457         , m_pipelineCacheData(pipelineCacheData)
458         , m_rng(1234)
459 
460     {
461         const InstanceInterface &vki                         = context.getInstanceInterface();
462         const VkSemaphoreTypeCreateInfoKHR semaphoreTypeInfo = {
463             VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR,
464             nullptr,
465             semaphoreType,
466             0,
467         };
468         const VkPhysicalDeviceExternalSemaphoreInfo info = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
469                                                             &semaphoreTypeInfo, semaphoreHandleType};
470         VkExternalSemaphoreProperties properties = {VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0u, 0u,
471                                                     0u};
472 
473         vki.getPhysicalDeviceExternalSemaphoreProperties(context.getPhysicalDevice(), &info, &properties);
474 
475         if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR &&
476             !context.getTimelineSemaphoreFeatures().timelineSemaphore)
477             TCU_THROW(NotSupportedError, "Timeline semaphore not supported");
478 
479         if ((properties.externalSemaphoreFeatures & vk::VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR) == 0 ||
480             (properties.externalSemaphoreFeatures & vk::VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR) == 0)
481             TCU_THROW(NotSupportedError, "Exporting and importing semaphore type not supported");
482 
483         if (!isResourceExportable())
484             TCU_THROW(NotSupportedError, "Resource not exportable");
485     }
486 
createImage(const vk::DeviceInterface & vkd,vk::VkDevice device,const vk::VkExtent3D & extent,uint32_t queueFamilyIndex,vk::VkImageTiling tiling)487     Move<VkImage> createImage(const vk::DeviceInterface &vkd, vk::VkDevice device, const vk::VkExtent3D &extent,
488                               uint32_t queueFamilyIndex, vk::VkImageTiling tiling)
489     {
490         const VkExternalMemoryImageCreateInfo externalInfo = {VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
491                                                               nullptr,
492                                                               (VkExternalMemoryHandleTypeFlags)m_memoryHandleType};
493         const VkImageCreateInfo createInfo                 = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
494                                                               &externalInfo,
495                                                               0u,
496 
497                                                               m_resourceDesc.imageType,
498                                                               m_resourceDesc.imageFormat,
499                                                               extent,
500                                                               1u,
501                                                               1u,
502                                                               m_resourceDesc.imageSamples,
503                                                               tiling,
504                                                               m_readOpSupport->getInResourceUsageFlags() |
505                                                                   m_writeOpSupport->getOutResourceUsageFlags(),
506                                                               VK_SHARING_MODE_EXCLUSIVE,
507 
508                                                               1u,
509                                                               &queueFamilyIndex,
510                                                               VK_IMAGE_LAYOUT_UNDEFINED};
511 
512         return vk::createImage(vkd, device, &createInfo);
513     }
514 
createBuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,const vk::VkDeviceSize & size,uint32_t queueFamilyIndex)515     Move<VkBuffer> createBuffer(const vk::DeviceInterface &vkd, vk::VkDevice device, const vk::VkDeviceSize &size,
516                                 uint32_t queueFamilyIndex)
517     {
518         const VkExternalMemoryBufferCreateInfo externalInfo = {VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
519                                                                nullptr,
520                                                                (VkExternalMemoryHandleTypeFlags)m_memoryHandleType};
521         const VkBufferCreateInfo createInfo                 = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
522                                                                &externalInfo,
523                                                                0u,
524 
525                                                                size,
526                                                                m_readOpSupport->getInResourceUsageFlags() |
527                                                                    m_writeOpSupport->getOutResourceUsageFlags(),
528                                                                VK_SHARING_MODE_EXCLUSIVE,
529                                                                1u,
530                                                                &queueFamilyIndex};
531         return vk::createBuffer(vkd, device, &createInfo);
532     }
533 
iterate(void)534     tcu::TestStatus iterate(void)
535     {
536         // We're using 2 devices to make sure we have 2 queues even on
537         // implementations that only have a single queue.
538         const bool isTimelineSemaphore(m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR);
539         const VkDevice &deviceA = m_context.getDevice();
540         const Unique<VkDevice> &deviceB(SingletonDevice::getDevice(m_context));
541         const DeviceInterface &vkA = m_context.getDeviceInterface();
542         const DeviceDriver vkB(m_context.getPlatformInterface(), m_context.getInstance(), *deviceB,
543                                m_context.getUsedApiVersion(), m_context.getTestContext().getCommandLine());
544         UniquePtr<SimpleAllocator> allocatorA(new SimpleAllocator(
545             vkA, deviceA,
546             vk::getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice())));
547         UniquePtr<SimpleAllocator> allocatorB(new SimpleAllocator(
548             vkB, *deviceB,
549             vk::getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice())));
550         UniquePtr<OperationContext> operationContextA(
551             new OperationContext(m_context, m_type, vkA, deviceA, *allocatorA, m_pipelineCacheData));
552         UniquePtr<OperationContext> operationContextB(
553             new OperationContext(m_context, m_type, vkB, *deviceB, *allocatorB, m_pipelineCacheData));
554         const uint32_t universalQueueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
555         const VkQueue queueA                     = m_context.getUniversalQueue();
556         const VkQueue queueB = getDeviceQueue(vkB, *deviceB, m_context.getUniversalQueueFamilyIndex(), 0);
557         Unique<VkFence> fenceA(createFence(vkA, deviceA));
558         Unique<VkFence> fenceB(createFence(vkB, *deviceB));
559         const Unique<VkCommandPool> cmdPoolA(createCommandPool(
560             vkA, deviceA, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, universalQueueFamilyIndex));
561         const Unique<VkCommandPool> cmdPoolB(createCommandPool(
562             vkB, *deviceB, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, universalQueueFamilyIndex));
563         std::vector<SharedPtr<Move<VkCommandBuffer>>> ptrCmdBuffersA;
564         SharedPtr<Move<VkCommandBuffer>> ptrCmdBufferB;
565         std::vector<VkCommandBuffer> cmdBuffersA;
566         VkCommandBuffer cmdBufferB;
567         std::vector<Move<VkSemaphore>> semaphoresA;
568         std::vector<Move<VkSemaphore>> semaphoresB;
569         std::vector<VkSemaphore> semaphoreHandlesA;
570         std::vector<VkSemaphore> semaphoreHandlesB;
571         std::vector<uint64_t> timelineValuesA;
572         std::vector<uint64_t> timelineValuesB;
573         std::vector<QueueSubmitOrderSharedIteration> iterations(12);
574         std::vector<VkPipelineStageFlags2KHR> stageBits;
575 
576         // These guards will wait for the device to be idle before tearing down the resources above.
577         const DeviceWaitIdleGuard idleGuardA(vkA, deviceA);
578         const DeviceWaitIdleGuard idleGuardB(vkB, *deviceB);
579 
580         // Create a dozen of set of write/read operations.
581         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
582         {
583             QueueSubmitOrderSharedIteration &iter = iterations[iterIdx];
584             uint32_t memoryTypeIndex;
585             NativeHandle nativeMemoryHandle;
586 
587             if (m_resourceDesc.type == RESOURCE_TYPE_IMAGE)
588             {
589                 const VkExtent3D extent                          = {(uint32_t)m_resourceDesc.size.x(),
590                                                                     de::max(1u, (uint32_t)m_resourceDesc.size.y()),
591                                                                     de::max(1u, (uint32_t)m_resourceDesc.size.z())};
592                 const VkImageSubresourceRange subresourceRange   = {m_resourceDesc.imageAspect, 0u, 1u, 0u, 1u};
593                 const VkImageSubresourceLayers subresourceLayers = {m_resourceDesc.imageAspect, 0u, 0u, 1u};
594 
595                 const vk::VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
596                 Move<VkImage> image            = createImage(vkA, deviceA, extent, universalQueueFamilyIndex, tiling);
597                 const vk::VkMemoryRequirements requirements = getMemoryRequirements(vkA, deviceA, *image);
598                 memoryTypeIndex                             = chooseMemoryType(requirements.memoryTypeBits);
599                 vk::Move<vk::VkDeviceMemory> memory         = allocateExportableMemory(
600                     vkA, deviceA, requirements.size, memoryTypeIndex, m_memoryHandleType, *image);
601 
602                 VK_CHECK(vkA.bindImageMemory(deviceA, *image, *memory, 0u));
603 
604                 MovePtr<Allocation> allocation(new SimpleAllocation(vkA, deviceA, memory.disown()));
605                 iter.resourceA = makeSharedPtr(new Resource(image, allocation, extent, m_resourceDesc.imageType,
606                                                             m_resourceDesc.imageFormat, subresourceRange,
607                                                             subresourceLayers, tiling));
608             }
609             else
610             {
611                 const VkDeviceSize offset = 0u;
612                 const VkDeviceSize size   = static_cast<VkDeviceSize>(m_resourceDesc.size.x());
613                 Move<VkBuffer> buffer     = createBuffer(vkA, deviceA, size, universalQueueFamilyIndex);
614                 const vk::VkMemoryRequirements requirements = getMemoryRequirements(vkA, deviceA, *buffer);
615                 memoryTypeIndex                             = chooseMemoryType(requirements.memoryTypeBits);
616                 vk::Move<vk::VkDeviceMemory> memory         = allocateExportableMemory(
617                     vkA, deviceA, requirements.size, memoryTypeIndex, m_memoryHandleType, *buffer);
618 
619                 VK_CHECK(vkA.bindBufferMemory(deviceA, *buffer, *memory, 0u));
620 
621                 MovePtr<Allocation> allocation(new SimpleAllocation(vkA, deviceA, memory.disown()));
622                 iter.resourceA = makeSharedPtr(new Resource(m_resourceDesc.type, buffer, allocation, offset, size));
623             }
624 
625             getMemoryNative(vkA, deviceA, iter.resourceA->getMemory(), m_memoryHandleType, nativeMemoryHandle);
626             iter.resourceB = makeSharedPtr(importResource(vkB, *deviceB, m_resourceDesc, universalQueueFamilyIndex,
627                                                           *m_readOpSupport, *m_writeOpSupport, nativeMemoryHandle,
628                                                           m_memoryHandleType, memoryTypeIndex));
629 
630             iter.writeOp = makeSharedPtr(m_writeOpSupport->build(*operationContextA, *iter.resourceA));
631             iter.readOp  = makeSharedPtr(m_readOpSupport->build(*operationContextB, *iter.resourceB));
632         }
633 
634         // Record each write operation into its own command buffer.
635         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
636         {
637             QueueSubmitOrderSharedIteration &iter = iterations[iterIdx];
638             const Resource &resource              = *iter.resourceA;
639             const SyncInfo writeSync              = iter.writeOp->getOutSyncInfo();
640             const SyncInfo readSync               = iter.readOp->getInSyncInfo();
641 
642             ptrCmdBuffersA.push_back(makeVkSharedPtr(makeCommandBuffer(vkA, deviceA, *cmdPoolA)));
643 
644             cmdBuffersA.push_back(**(ptrCmdBuffersA.back()));
645 
646             beginCommandBuffer(vkA, cmdBuffersA.back());
647 
648             iter.writeOp->recordCommands(cmdBuffersA.back());
649 
650             {
651                 SynchronizationWrapperPtr synchronizationWrapper =
652                     getSynchronizationWrapper(m_type, vkA, isTimelineSemaphore);
653 
654                 if (resource.getType() == RESOURCE_TYPE_IMAGE)
655                 {
656                     DE_ASSERT(writeSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
657                     DE_ASSERT(readSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
658 
659                     const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
660                         writeSync.stageMask,                 // VkPipelineStageFlags2KHR            srcStageMask
661                         writeSync.accessMask,                // VkAccessFlags2KHR                srcAccessMask
662                         readSync.stageMask,                  // VkPipelineStageFlags2KHR            dstStageMask
663                         readSync.accessMask,                 // VkAccessFlags2KHR                dstAccessMask
664                         writeSync.imageLayout,               // VkImageLayout                    oldLayout
665                         readSync.imageLayout,                // VkImageLayout                    newLayout
666                         resource.getImage().handle,          // VkImage                            image
667                         resource.getImage().subresourceRange // VkImageSubresourceRange            subresourceRange
668                     );
669                     VkDependencyInfoKHR dependencyInfo =
670                         makeCommonDependencyInfo(nullptr, nullptr, &imageMemoryBarrier2);
671                     synchronizationWrapper->cmdPipelineBarrier(cmdBuffersA.back(), &dependencyInfo);
672                 }
673                 else
674                 {
675                     const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
676                         writeSync.stageMask,         // VkPipelineStageFlags2KHR            srcStageMask
677                         writeSync.accessMask,        // VkAccessFlags2KHR                srcAccessMask
678                         readSync.stageMask,          // VkPipelineStageFlags2KHR            dstStageMask
679                         readSync.accessMask,         // VkAccessFlags2KHR                dstAccessMask
680                         resource.getBuffer().handle, // VkBuffer                            buffer
681                         0,                           // VkDeviceSize                        offset
682                         VK_WHOLE_SIZE                // VkDeviceSize                        size
683                     );
684                     VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(nullptr, &bufferMemoryBarrier2);
685                     synchronizationWrapper->cmdPipelineBarrier(cmdBuffersA.back(), &dependencyInfo);
686                 }
687 
688                 stageBits.push_back(writeSync.stageMask);
689             }
690 
691             endCommandBuffer(vkA, cmdBuffersA.back());
692 
693             addSemaphore(vkA, deviceA, semaphoresA, semaphoreHandlesA, timelineValuesA,
694                          iterIdx == (iterations.size() - 1), 2u);
695         }
696 
697         DE_ASSERT(stageBits.size() == iterations.size());
698         DE_ASSERT(semaphoreHandlesA.size() == iterations.size());
699 
700         // Record all read operations into a single command buffer and record the union of their stage masks.
701         VkPipelineStageFlags2KHR readStages = 0;
702         ptrCmdBufferB                       = makeVkSharedPtr(makeCommandBuffer(vkB, *deviceB, *cmdPoolB));
703         cmdBufferB                          = **(ptrCmdBufferB);
704         beginCommandBuffer(vkB, cmdBufferB);
705         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
706         {
707             QueueSubmitOrderSharedIteration &iter = iterations[iterIdx];
708             readStages |= iter.readOp->getInSyncInfo().stageMask;
709             iter.readOp->recordCommands(cmdBufferB);
710         }
711         endCommandBuffer(vkB, cmdBufferB);
712 
713         // Export the last semaphore for use on deviceB and create another semaphore to signal on deviceB.
714         {
715             VkSemaphore lastSemaphoreA = semaphoreHandlesA.back();
716             NativeHandle nativeSemaphoreHandle;
717 
718             addSemaphore(vkB, *deviceB, semaphoresB, semaphoreHandlesB, timelineValuesB, true, timelineValuesA.back());
719 
720             getSemaphoreNative(vkA, deviceA, lastSemaphoreA, m_semaphoreHandleType, nativeSemaphoreHandle);
721             importSemaphore(vkB, *deviceB, semaphoreHandlesB.back(), m_semaphoreHandleType, nativeSemaphoreHandle, 0u);
722 
723             addSemaphore(vkB, *deviceB, semaphoresB, semaphoreHandlesB, timelineValuesB, false, timelineValuesA.back());
724         }
725 
726         // Submit writes, each in its own VkSubmitInfo. With binary
727         // semaphores, submission don't wait on anything, with
728         // timeline semaphores, submissions wait on a host signal
729         // operation done below.
730         {
731             std::vector<VkCommandBufferSubmitInfoKHR> cmdBuffersInfo(iterations.size(),
732                                                                      makeCommonCommandBufferSubmitInfo(0u));
733             std::vector<VkSemaphoreSubmitInfoKHR> waitSemaphoreSubmitInfos(
734                 iterations.size(),
735                 makeCommonSemaphoreSubmitInfo(VK_NULL_HANDLE, 1u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR));
736             std::vector<VkSemaphoreSubmitInfoKHR> signalSemaphoreSubmitInfos(
737                 iterations.size(),
738                 makeCommonSemaphoreSubmitInfo(VK_NULL_HANDLE, 0u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR));
739             SynchronizationWrapperPtr synchronizationWrapper =
740                 getSynchronizationWrapper(m_type, vkA, isTimelineSemaphore, static_cast<uint32_t>(iterations.size()));
741 
742             for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
743             {
744                 waitSemaphoreSubmitInfos[iterIdx].semaphore   = semaphoreHandlesA.front();
745                 waitSemaphoreSubmitInfos[iterIdx].stageMask   = stageBits[iterIdx];
746                 signalSemaphoreSubmitInfos[iterIdx].semaphore = semaphoreHandlesA[iterIdx];
747                 signalSemaphoreSubmitInfos[iterIdx].value     = timelineValuesA[iterIdx];
748                 cmdBuffersInfo[iterIdx].commandBuffer         = cmdBuffersA[iterIdx];
749 
750                 synchronizationWrapper->addSubmitInfo(
751                     isTimelineSemaphore, isTimelineSemaphore ? &waitSemaphoreSubmitInfos[iterIdx] : nullptr, 1u,
752                     &cmdBuffersInfo[iterIdx], 1u, &signalSemaphoreSubmitInfos[iterIdx], isTimelineSemaphore,
753                     isTimelineSemaphore);
754             }
755 
756             VK_CHECK(synchronizationWrapper->queueSubmit(queueA, *fenceA));
757         }
758 
759         // Submit reads, only waiting waiting on the last write
760         // operations, ordering of signaling should guarantee that
761         // when read operations kick in all writes have completed.
762         {
763             VkCommandBufferSubmitInfoKHR cmdBuffersInfo = makeCommonCommandBufferSubmitInfo(cmdBufferB);
764             VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo =
765                 makeCommonSemaphoreSubmitInfo(semaphoreHandlesB.front(), timelineValuesA.back(), readStages);
766             VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(
767                 semaphoreHandlesB.back(), timelineValuesB.back(), VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
768             SynchronizationWrapperPtr synchronizationWrapper =
769                 getSynchronizationWrapper(m_type, vkB, isTimelineSemaphore);
770 
771             synchronizationWrapper->addSubmitInfo(1u, &waitSemaphoreSubmitInfo, 1u, &cmdBuffersInfo, 1u,
772                                                   &signalSemaphoreSubmitInfo, isTimelineSemaphore, isTimelineSemaphore);
773 
774             VK_CHECK(synchronizationWrapper->queueSubmit(queueB, *fenceB));
775 
776             if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
777             {
778                 const VkSemaphoreWaitInfo waitInfo = {
779                     VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType;
780                     nullptr,                               // const void* pNext;
781                     0u,                                    // VkSemaphoreWaitFlagsKHR flags;
782                     1u,                                    // uint32_t semaphoreCount;
783                     &semaphoreHandlesB.back(),             // const VkSemaphore* pSemaphores;
784                     &timelineValuesB.back(),               // const uint64_t* pValues;
785                 };
786 
787                 // Unblock the whole lot.
788                 hostSignal(vkA, deviceA, semaphoreHandlesA.front(), 2);
789 
790                 VK_CHECK(vkB.waitSemaphores(*deviceB, &waitInfo, ~0ull));
791             }
792             else
793             {
794                 VK_CHECK(vkB.waitForFences(*deviceB, 1, &fenceB.get(), VK_TRUE, ~0ull));
795             }
796         }
797 
798         // Verify the result of the operations.
799         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
800         {
801             QueueSubmitOrderSharedIteration &iter = iterations[iterIdx];
802             const Data expected                   = iter.writeOp->getData();
803             const Data actual                     = iter.readOp->getData();
804 
805             if (isIndirectBuffer(iter.resourceA->getType()))
806             {
807                 const uint32_t expectedValue = reinterpret_cast<const uint32_t *>(expected.data)[0];
808                 const uint32_t actualValue   = reinterpret_cast<const uint32_t *>(actual.data)[0];
809 
810                 if (actualValue < expectedValue)
811                     return tcu::TestStatus::fail("Counter value is smaller than expected");
812             }
813             else
814             {
815                 if (0 != deMemCmp(expected.data, actual.data, expected.size))
816                     return tcu::TestStatus::fail("Memory contents don't match");
817             }
818         }
819 
820         return tcu::TestStatus::pass("Success");
821     }
822 
823 private:
addSemaphore(const DeviceInterface & vk,VkDevice device,std::vector<Move<VkSemaphore>> & semaphores,std::vector<VkSemaphore> & semaphoreHandles,std::vector<uint64_t> & timelineValues,bool exportable,uint64_t firstTimelineValue)824     void addSemaphore(const DeviceInterface &vk, VkDevice device, std::vector<Move<VkSemaphore>> &semaphores,
825                       std::vector<VkSemaphore> &semaphoreHandles, std::vector<uint64_t> &timelineValues,
826                       bool exportable, uint64_t firstTimelineValue)
827     {
828         Move<VkSemaphore> semaphore;
829 
830         if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
831         {
832             // Only allocate a single exportable semaphore.
833             if (semaphores.empty())
834             {
835                 semaphores.push_back(createExportableSemaphoreType(vk, device, m_semaphoreType, m_semaphoreHandleType));
836             }
837         }
838         else
839         {
840             if (exportable)
841                 semaphores.push_back(createExportableSemaphoreType(vk, device, m_semaphoreType, m_semaphoreHandleType));
842             else
843                 semaphores.push_back(createSemaphoreType(vk, device, m_semaphoreType));
844         }
845 
846         semaphoreHandles.push_back(*semaphores.back());
847         timelineValues.push_back((timelineValues.empty() ? firstTimelineValue : timelineValues.back()) +
848                                  m_rng.getInt(1, 100));
849     }
850 
isResourceExportable()851     bool isResourceExportable()
852     {
853         const InstanceInterface &vki    = m_context.getInstanceInterface();
854         VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
855 
856         if (m_resourceDesc.type == RESOURCE_TYPE_IMAGE)
857         {
858             const VkPhysicalDeviceExternalImageFormatInfo externalInfo = {
859                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, nullptr, m_memoryHandleType};
860             const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {
861                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
862                 &externalInfo,
863                 m_resourceDesc.imageFormat,
864                 m_resourceDesc.imageType,
865                 VK_IMAGE_TILING_OPTIMAL,
866                 m_readOpSupport->getInResourceUsageFlags() | m_writeOpSupport->getOutResourceUsageFlags(),
867                 0u};
868             VkExternalImageFormatProperties externalProperties = {
869                 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, nullptr, {0u, 0u, 0u}};
870             VkImageFormatProperties2 formatProperties = {VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
871                                                          &externalProperties,
872                                                          {
873                                                              {0u, 0u, 0u},
874                                                              0u,
875                                                              0u,
876                                                              0u,
877                                                              0u,
878                                                          }};
879 
880             {
881                 const VkResult res =
882                     vki.getPhysicalDeviceImageFormatProperties2(physicalDevice, &imageFormatInfo, &formatProperties);
883 
884                 if (res == VK_ERROR_FORMAT_NOT_SUPPORTED)
885                     return false;
886 
887                 VK_CHECK(res); // Check other errors
888             }
889 
890             if ((externalProperties.externalMemoryProperties.externalMemoryFeatures &
891                  VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR) == 0)
892                 return false;
893 
894             if ((externalProperties.externalMemoryProperties.externalMemoryFeatures &
895                  VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) == 0)
896                 return false;
897 
898             return true;
899         }
900         else
901         {
902             const VkPhysicalDeviceExternalBufferInfo info = {
903                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, nullptr,
904 
905                 0u, m_readOpSupport->getInResourceUsageFlags() | m_writeOpSupport->getOutResourceUsageFlags(),
906                 m_memoryHandleType};
907             VkExternalBufferProperties properties = {
908                 VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES, nullptr, {0u, 0u, 0u}};
909             vki.getPhysicalDeviceExternalBufferProperties(physicalDevice, &info, &properties);
910 
911             if ((properties.externalMemoryProperties.externalMemoryFeatures &
912                  VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR) == 0 ||
913                 (properties.externalMemoryProperties.externalMemoryFeatures &
914                  VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) == 0)
915                 return false;
916 
917             return true;
918         }
919     }
920 
921     SynchronizationType m_type;
922     SharedPtr<OperationSupport> m_writeOpSupport;
923     SharedPtr<OperationSupport> m_readOpSupport;
924     const ResourceDescription &m_resourceDesc;
925     VkExternalMemoryHandleTypeFlagBits m_memoryHandleType;
926     VkSemaphoreType m_semaphoreType;
927     VkExternalSemaphoreHandleTypeFlagBits m_semaphoreHandleType;
928     PipelineCacheData &m_pipelineCacheData;
929     de::Random m_rng;
930 };
931 
932 class QueueSubmitSignalOrderSharedTestCase : public TestCase
933 {
934 public:
QueueSubmitSignalOrderSharedTestCase(tcu::TestContext & testCtx,SynchronizationType type,const std::string & name,OperationName writeOp,OperationName readOp,const ResourceDescription & resourceDesc,VkExternalMemoryHandleTypeFlagBits memoryHandleType,VkSemaphoreType semaphoreType,VkExternalSemaphoreHandleTypeFlagBits semaphoreHandleType,PipelineCacheData & pipelineCacheData)935     QueueSubmitSignalOrderSharedTestCase(tcu::TestContext &testCtx, SynchronizationType type, const std::string &name,
936                                          OperationName writeOp, OperationName readOp,
937                                          const ResourceDescription &resourceDesc,
938                                          VkExternalMemoryHandleTypeFlagBits memoryHandleType,
939                                          VkSemaphoreType semaphoreType,
940                                          VkExternalSemaphoreHandleTypeFlagBits semaphoreHandleType,
941                                          PipelineCacheData &pipelineCacheData)
942         : TestCase(testCtx, name.c_str())
943         , m_type(type)
944         , m_writeOpSupport(makeOperationSupport(writeOp, resourceDesc).release())
945         , m_readOpSupport(makeOperationSupport(readOp, resourceDesc).release())
946         , m_resourceDesc(resourceDesc)
947         , m_memoryHandleType(memoryHandleType)
948         , m_semaphoreType(semaphoreType)
949         , m_semaphoreHandleType(semaphoreHandleType)
950         , m_pipelineCacheData(pipelineCacheData)
951     {
952     }
953 
checkSupport(Context & context) const954     virtual void checkSupport(Context &context) const
955     {
956         if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR &&
957             !context.getTimelineSemaphoreFeatures().timelineSemaphore)
958             TCU_THROW(NotSupportedError, "Timeline semaphore not supported");
959 
960         if ((m_semaphoreHandleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT ||
961              m_semaphoreHandleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) &&
962             !context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_fd"))
963             TCU_THROW(NotSupportedError, "VK_KHR_external_semaphore_fd not supported");
964 
965         if ((m_semaphoreHandleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT ||
966              m_semaphoreHandleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) &&
967             !context.isDeviceFunctionalitySupported("VK_KHR_external_semaphore_win32"))
968             TCU_THROW(NotSupportedError, "VK_KHR_external_semaphore_win32 not supported");
969 
970         if (m_type == SynchronizationType::SYNCHRONIZATION2)
971             context.requireDeviceFunctionality("VK_KHR_synchronization2");
972     }
973 
createInstance(Context & context) const974     TestInstance *createInstance(Context &context) const
975     {
976         return new QueueSubmitSignalOrderSharedTestInstance(context, m_type, m_writeOpSupport, m_readOpSupport,
977                                                             m_resourceDesc, m_memoryHandleType, m_semaphoreType,
978                                                             m_semaphoreHandleType, m_pipelineCacheData);
979     }
980 
initPrograms(SourceCollections & programCollection) const981     void initPrograms(SourceCollections &programCollection) const
982     {
983         m_writeOpSupport->initPrograms(programCollection);
984         m_readOpSupport->initPrograms(programCollection);
985     }
986 
987 private:
988     SynchronizationType m_type;
989     SharedPtr<OperationSupport> m_writeOpSupport;
990     SharedPtr<OperationSupport> m_readOpSupport;
991     const ResourceDescription &m_resourceDesc;
992     VkExternalMemoryHandleTypeFlagBits m_memoryHandleType;
993     VkSemaphoreType m_semaphoreType;
994     VkExternalSemaphoreHandleTypeFlagBits m_semaphoreHandleType;
995     PipelineCacheData &m_pipelineCacheData;
996 };
997 
998 class QueueSubmitSignalOrderSharedTests : public tcu::TestCaseGroup
999 {
1000 public:
QueueSubmitSignalOrderSharedTests(tcu::TestContext & testCtx,SynchronizationType type,VkSemaphoreType semaphoreType,const char * name)1001     QueueSubmitSignalOrderSharedTests(tcu::TestContext &testCtx, SynchronizationType type,
1002                                       VkSemaphoreType semaphoreType, const char *name)
1003         : tcu::TestCaseGroup(testCtx, name)
1004         , m_type(type)
1005         , m_semaphoreType(semaphoreType)
1006     {
1007     }
1008 
init(void)1009     void init(void)
1010     {
1011         static const OperationName writeOps[] = {
1012             OPERATION_NAME_WRITE_COPY_BUFFER,
1013             OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE,
1014             OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER,
1015             OPERATION_NAME_WRITE_COPY_IMAGE,
1016             OPERATION_NAME_WRITE_BLIT_IMAGE,
1017             OPERATION_NAME_WRITE_SSBO_VERTEX,
1018             OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL,
1019             OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION,
1020             OPERATION_NAME_WRITE_SSBO_GEOMETRY,
1021             OPERATION_NAME_WRITE_SSBO_FRAGMENT,
1022             OPERATION_NAME_WRITE_SSBO_COMPUTE,
1023             OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT,
1024             OPERATION_NAME_WRITE_IMAGE_VERTEX,
1025             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL,
1026             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION,
1027             OPERATION_NAME_WRITE_IMAGE_GEOMETRY,
1028             OPERATION_NAME_WRITE_IMAGE_FRAGMENT,
1029             OPERATION_NAME_WRITE_IMAGE_COMPUTE,
1030             OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT,
1031         };
1032         static const OperationName readOps[] = {
1033             OPERATION_NAME_READ_COPY_BUFFER,
1034             OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE,
1035             OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER,
1036             OPERATION_NAME_READ_COPY_IMAGE,
1037             OPERATION_NAME_READ_BLIT_IMAGE,
1038             OPERATION_NAME_READ_UBO_VERTEX,
1039             OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL,
1040             OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION,
1041             OPERATION_NAME_READ_UBO_GEOMETRY,
1042             OPERATION_NAME_READ_UBO_FRAGMENT,
1043             OPERATION_NAME_READ_UBO_COMPUTE,
1044             OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT,
1045             OPERATION_NAME_READ_SSBO_VERTEX,
1046             OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL,
1047             OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION,
1048             OPERATION_NAME_READ_SSBO_GEOMETRY,
1049             OPERATION_NAME_READ_SSBO_FRAGMENT,
1050             OPERATION_NAME_READ_SSBO_COMPUTE,
1051             OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT,
1052             OPERATION_NAME_READ_IMAGE_VERTEX,
1053             OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL,
1054             OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION,
1055             OPERATION_NAME_READ_IMAGE_GEOMETRY,
1056             OPERATION_NAME_READ_IMAGE_FRAGMENT,
1057             OPERATION_NAME_READ_IMAGE_COMPUTE,
1058             OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT,
1059             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW,
1060             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED,
1061             OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH,
1062             OPERATION_NAME_READ_VERTEX_INPUT,
1063         };
1064         static const struct
1065         {
1066             VkExternalMemoryHandleTypeFlagBits memoryType;
1067             VkExternalSemaphoreHandleTypeFlagBits semaphoreType;
1068         } exportCases[] = {
1069             // Only semaphore handle types having reference semantic
1070             // are valid for this test.
1071             {
1072                 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
1073                 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
1074             },
1075             {
1076                 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
1077                 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
1078             },
1079             {
1080                 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
1081                 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT,
1082             },
1083         };
1084 
1085         for (uint32_t writeOpIdx = 0; writeOpIdx < DE_LENGTH_OF_ARRAY(writeOps); writeOpIdx++)
1086             for (uint32_t readOpIdx = 0; readOpIdx < DE_LENGTH_OF_ARRAY(readOps); readOpIdx++)
1087             {
1088                 const OperationName writeOp   = writeOps[writeOpIdx];
1089                 const OperationName readOp    = readOps[readOpIdx];
1090                 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
1091                 bool empty                    = true;
1092 
1093                 de::MovePtr<tcu::TestCaseGroup> opGroup(new tcu::TestCaseGroup(m_testCtx, opGroupName.c_str()));
1094 
1095                 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
1096                 {
1097                     const ResourceDescription &resource = s_resources[resourceNdx];
1098 
1099                     if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
1100                     {
1101                         for (uint32_t exportIdx = 0; exportIdx < DE_LENGTH_OF_ARRAY(exportCases); exportIdx++)
1102                         {
1103                             std::string caseName = getResourceName(resource) + "_" +
1104                                                    externalSemaphoreTypeToName(exportCases[exportIdx].semaphoreType);
1105 
1106                             opGroup->addChild(new QueueSubmitSignalOrderSharedTestCase(
1107                                 m_testCtx, m_type, caseName, writeOp, readOp, resource,
1108                                 exportCases[exportIdx].memoryType, m_semaphoreType,
1109                                 exportCases[exportIdx].semaphoreType, m_pipelineCacheData));
1110                             empty = false;
1111                         }
1112                     }
1113                 }
1114                 if (!empty)
1115                     addChild(opGroup.release());
1116             }
1117     }
1118 
deinit(void)1119     void deinit(void)
1120     {
1121         cleanupGroup();
1122     }
1123 
1124 private:
1125     SynchronizationType m_type;
1126     VkSemaphoreType m_semaphoreType;
1127     // synchronization.op tests share pipeline cache data to speed up test
1128     // execution.
1129     PipelineCacheData m_pipelineCacheData;
1130 };
1131 
1132 struct QueueSubmitOrderIteration
1133 {
QueueSubmitOrderIterationvkt::synchronization::__anon927627aa0111::QueueSubmitOrderIteration1134     QueueSubmitOrderIteration()
1135     {
1136     }
~QueueSubmitOrderIterationvkt::synchronization::__anon927627aa0111::QueueSubmitOrderIteration1137     ~QueueSubmitOrderIteration()
1138     {
1139     }
1140 
1141     SharedPtr<Resource> resource;
1142 
1143     SharedPtr<Operation> writeOp;
1144     SharedPtr<Operation> readOp;
1145 };
1146 
1147 // Verifies the signaling order of the semaphores in multiple
1148 // VkSubmitInfo given to vkQueueSubmit() with queueA & queueB from the
1149 // same VkDevice.
1150 //
1151 // vkQueueSubmit(queueA, [write0, write1, write2, ..., write6])
1152 // vkQueueSubmit(queueB, [read0-6])
1153 //
1154 // With read0-6 waiting on write6, all the data should be available
1155 // for reading given that signal operations are supposed to happen in
1156 // order.
1157 class QueueSubmitSignalOrderTestInstance : public TestInstance
1158 {
1159 public:
QueueSubmitSignalOrderTestInstance(Context & context,SynchronizationType type,const SharedPtr<OperationSupport> writeOpSupport,const SharedPtr<OperationSupport> readOpSupport,const ResourceDescription & resourceDesc,VkSemaphoreType semaphoreType,PipelineCacheData & pipelineCacheData)1160     QueueSubmitSignalOrderTestInstance(Context &context, SynchronizationType type,
1161                                        const SharedPtr<OperationSupport> writeOpSupport,
1162                                        const SharedPtr<OperationSupport> readOpSupport,
1163                                        const ResourceDescription &resourceDesc, VkSemaphoreType semaphoreType,
1164                                        PipelineCacheData &pipelineCacheData)
1165         : TestInstance(context)
1166         , m_type(type)
1167         , m_writeOpSupport(writeOpSupport)
1168         , m_readOpSupport(readOpSupport)
1169         , m_resourceDesc(resourceDesc)
1170         , m_semaphoreType(semaphoreType)
1171         , m_device(SingletonDevice::getDevice(context))
1172         , m_deviceInterface(context.getPlatformInterface(), context.getInstance(), *m_device,
1173                             context.getUsedApiVersion(), context.getTestContext().getCommandLine())
1174         , m_allocator(new SimpleAllocator(
1175               m_deviceInterface, *m_device,
1176               getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())))
1177         , m_operationContext(
1178               new OperationContext(context, type, m_deviceInterface, *m_device, *m_allocator, pipelineCacheData))
1179         , m_queueA(nullptr)
1180         , m_queueB(nullptr)
1181         , m_rng(1234)
1182 
1183     {
1184         const std::vector<VkQueueFamilyProperties> queueFamilyProperties =
1185             getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
1186 
1187         if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR &&
1188             !context.getTimelineSemaphoreFeatures().timelineSemaphore)
1189             TCU_THROW(NotSupportedError, "Timeline semaphore not supported");
1190 
1191         VkQueueFlags writeOpQueueFlags = m_writeOpSupport->getQueueFlags(*m_operationContext);
1192         for (uint32_t familyIdx = 0; familyIdx < queueFamilyProperties.size(); familyIdx++)
1193         {
1194             if (((queueFamilyProperties[familyIdx].queueFlags & writeOpQueueFlags) == writeOpQueueFlags) ||
1195                 ((writeOpQueueFlags == VK_QUEUE_TRANSFER_BIT) &&
1196                  (((queueFamilyProperties[familyIdx].queueFlags & VK_QUEUE_GRAPHICS_BIT) == VK_QUEUE_GRAPHICS_BIT) ||
1197                   ((queueFamilyProperties[familyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) == VK_QUEUE_COMPUTE_BIT))))
1198             {
1199                 m_queueA            = getDeviceQueue(m_deviceInterface, *m_device, familyIdx, 0);
1200                 m_queueFamilyIndexA = familyIdx;
1201                 break;
1202             }
1203         }
1204         if (m_queueA == nullptr)
1205             TCU_THROW(NotSupportedError, "No queue supporting write operation");
1206 
1207         VkQueueFlags readOpQueueFlags = m_readOpSupport->getQueueFlags(*m_operationContext);
1208         for (uint32_t familyIdx = 0; familyIdx < queueFamilyProperties.size(); familyIdx++)
1209         {
1210             if (((queueFamilyProperties[familyIdx].queueFlags & readOpQueueFlags) == readOpQueueFlags) ||
1211                 ((readOpQueueFlags == VK_QUEUE_TRANSFER_BIT) &&
1212                  (((queueFamilyProperties[familyIdx].queueFlags & VK_QUEUE_GRAPHICS_BIT) == VK_QUEUE_GRAPHICS_BIT) ||
1213                   ((queueFamilyProperties[familyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) == VK_QUEUE_COMPUTE_BIT))))
1214             {
1215                 for (uint32_t queueIdx = 0; queueIdx < queueFamilyProperties[familyIdx].queueCount; queueIdx++)
1216                 {
1217                     VkQueue queue = getDeviceQueue(m_deviceInterface, *m_device, familyIdx, queueIdx);
1218 
1219                     if (queue == m_queueA)
1220                         continue;
1221 
1222                     m_queueB            = queue;
1223                     m_queueFamilyIndexB = familyIdx;
1224                     break;
1225                 }
1226 
1227                 if (m_queueB != nullptr)
1228                     break;
1229             }
1230         }
1231         if (m_queueB == nullptr)
1232             TCU_THROW(NotSupportedError, "No queue supporting read operation");
1233     }
1234 
iterate(void)1235     tcu::TestStatus iterate(void)
1236     {
1237         const bool isTimelineSemaphore = (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR);
1238         const VkDevice &device         = *m_device;
1239         const DeviceInterface &vk      = m_deviceInterface;
1240         Unique<VkFence> fence(createFence(vk, device));
1241         const Unique<VkCommandPool> cmdPoolA(
1242             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_queueFamilyIndexA));
1243         const Unique<VkCommandPool> cmdPoolB(
1244             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_queueFamilyIndexB));
1245         std::vector<SharedPtr<Move<VkCommandBuffer>>> ptrCmdBuffersA;
1246         SharedPtr<Move<VkCommandBuffer>> ptrCmdBufferB;
1247         std::vector<VkCommandBuffer> cmdBuffersA;
1248         VkCommandBuffer cmdBufferB;
1249         std::vector<Move<VkSemaphore>> semaphoresA;
1250         std::vector<Move<VkSemaphore>> semaphoresB;
1251         std::vector<VkSemaphore> semaphoreHandlesA;
1252         std::vector<VkSemaphore> semaphoreHandlesB;
1253         std::vector<uint64_t> timelineValuesA;
1254         std::vector<uint64_t> timelineValuesB;
1255         std::vector<QueueSubmitOrderIteration> iterations;
1256         std::vector<VkPipelineStageFlags2KHR> stageBits;
1257         std::vector<uint32_t> queueFamilies;
1258         SynchronizationWrapperPtr syncWrapper = getSynchronizationWrapper(m_type, vk, isTimelineSemaphore);
1259 
1260         // This guard will wait for the device to be idle before tearing down the resources above.
1261         const DeviceWaitIdleGuard idleGuard(vk, device);
1262 
1263         queueFamilies.push_back(m_queueFamilyIndexA);
1264         queueFamilies.push_back(m_queueFamilyIndexB);
1265 
1266         // Create a dozen of set of write/read operations.
1267         iterations.resize(12);
1268         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
1269         {
1270             QueueSubmitOrderIteration &iter = iterations[iterIdx];
1271 
1272             iter.resource = makeSharedPtr(
1273                 new Resource(*m_operationContext, m_resourceDesc,
1274                              m_writeOpSupport->getOutResourceUsageFlags() | m_readOpSupport->getInResourceUsageFlags(),
1275                              VK_SHARING_MODE_EXCLUSIVE, queueFamilies));
1276 
1277             iter.writeOp = makeSharedPtr(m_writeOpSupport->build(*m_operationContext, *iter.resource));
1278             iter.readOp  = makeSharedPtr(m_readOpSupport->build(*m_operationContext, *iter.resource));
1279         }
1280 
1281         // Record each write operation into its own command buffer.
1282         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
1283         {
1284             QueueSubmitOrderIteration &iter = iterations[iterIdx];
1285 
1286             ptrCmdBuffersA.push_back(makeVkSharedPtr(makeCommandBuffer(vk, device, *cmdPoolA)));
1287             cmdBuffersA.push_back(**(ptrCmdBuffersA.back()));
1288 
1289             beginCommandBuffer(vk, cmdBuffersA.back());
1290             iter.writeOp->recordCommands(cmdBuffersA.back());
1291 
1292             {
1293                 SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(m_type, vk, false);
1294                 const SyncInfo writeSync                         = iter.writeOp->getOutSyncInfo();
1295                 const SyncInfo readSync                          = iter.readOp->getInSyncInfo();
1296                 const Resource &resource                         = *iter.resource;
1297 
1298                 if (resource.getType() == RESOURCE_TYPE_IMAGE)
1299                 {
1300                     DE_ASSERT(writeSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
1301                     DE_ASSERT(readSync.imageLayout != VK_IMAGE_LAYOUT_UNDEFINED);
1302 
1303                     const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
1304                         writeSync.stageMask,                 // VkPipelineStageFlags2KHR            srcStageMask
1305                         writeSync.accessMask,                // VkAccessFlags2KHR                srcAccessMask
1306                         readSync.stageMask,                  // VkPipelineStageFlags2KHR            dstStageMask
1307                         readSync.accessMask,                 // VkAccessFlags2KHR                dstAccessMask
1308                         writeSync.imageLayout,               // VkImageLayout                    oldLayout
1309                         readSync.imageLayout,                // VkImageLayout                    newLayout
1310                         resource.getImage().handle,          // VkImage                            image
1311                         resource.getImage().subresourceRange // VkImageSubresourceRange            subresourceRange
1312                     );
1313                     VkDependencyInfoKHR dependencyInfo =
1314                         makeCommonDependencyInfo(nullptr, nullptr, &imageMemoryBarrier2);
1315                     synchronizationWrapper->cmdPipelineBarrier(cmdBuffersA.back(), &dependencyInfo);
1316                 }
1317                 else
1318                 {
1319                     const VkBufferMemoryBarrier2KHR bufferMemoryBarrier2 = makeBufferMemoryBarrier2(
1320                         writeSync.stageMask,         // VkPipelineStageFlags2KHR            srcStageMask
1321                         writeSync.accessMask,        // VkAccessFlags2KHR                srcAccessMask
1322                         readSync.stageMask,          // VkPipelineStageFlags2KHR            dstStageMask
1323                         readSync.accessMask,         // VkAccessFlags2KHR                dstAccessMask
1324                         resource.getBuffer().handle, // VkBuffer                            buffer
1325                         0,                           // VkDeviceSize                        offset
1326                         VK_WHOLE_SIZE                // VkDeviceSize                        size
1327                     );
1328                     VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(nullptr, &bufferMemoryBarrier2);
1329                     synchronizationWrapper->cmdPipelineBarrier(cmdBuffersA.back(), &dependencyInfo);
1330                 }
1331 
1332                 stageBits.push_back(writeSync.stageMask);
1333             }
1334 
1335             endCommandBuffer(vk, cmdBuffersA.back());
1336 
1337             addSemaphore(vk, device, semaphoresA, semaphoreHandlesA, timelineValuesA, 2u);
1338         }
1339 
1340         DE_ASSERT(stageBits.size() == iterations.size());
1341         DE_ASSERT(semaphoreHandlesA.size() == iterations.size());
1342 
1343         // Record all read operations into a single command buffer and track the union of their execution stages.
1344         ptrCmdBufferB = makeVkSharedPtr(makeCommandBuffer(vk, device, *cmdPoolB));
1345         cmdBufferB    = **(ptrCmdBufferB);
1346         beginCommandBuffer(vk, cmdBufferB);
1347         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
1348         {
1349             QueueSubmitOrderIteration &iter = iterations[iterIdx];
1350             iter.readOp->recordCommands(cmdBufferB);
1351         }
1352         endCommandBuffer(vk, cmdBufferB);
1353 
1354         addSemaphore(vk, device, semaphoresB, semaphoreHandlesB, timelineValuesB, timelineValuesA.back());
1355 
1356         // Submit writes, each in its own VkSubmitInfo. With binary
1357         // semaphores, submission don't wait on anything, with
1358         // timeline semaphores, submissions wait on a host signal
1359         // operation done below.
1360         {
1361             VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo =
1362                 makeCommonSemaphoreSubmitInfo(semaphoreHandlesA.front(), 1u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR);
1363             std::vector<VkSemaphoreSubmitInfoKHR> signalSemaphoreSubmitInfo(
1364                 iterations.size(),
1365                 makeCommonSemaphoreSubmitInfo(VK_NULL_HANDLE, 0u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR));
1366             std::vector<VkCommandBufferSubmitInfoKHR> commandBufferSubmitInfos(iterations.size(),
1367                                                                                makeCommonCommandBufferSubmitInfo(0));
1368             SynchronizationWrapperPtr synchronizationWrapper =
1369                 getSynchronizationWrapper(m_type, vk, isTimelineSemaphore, (uint32_t)iterations.size());
1370 
1371             for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
1372             {
1373                 commandBufferSubmitInfos[iterIdx].commandBuffer = cmdBuffersA[iterIdx];
1374                 signalSemaphoreSubmitInfo[iterIdx].semaphore    = semaphoreHandlesA[iterIdx];
1375                 signalSemaphoreSubmitInfo[iterIdx].value        = timelineValuesA[iterIdx];
1376 
1377                 synchronizationWrapper->addSubmitInfo(
1378                     isTimelineSemaphore, isTimelineSemaphore ? &waitSemaphoreSubmitInfo : nullptr, 1u,
1379                     &commandBufferSubmitInfos[iterIdx], 1u, &signalSemaphoreSubmitInfo[iterIdx], isTimelineSemaphore,
1380                     isTimelineSemaphore);
1381             }
1382 
1383             VK_CHECK(synchronizationWrapper->queueSubmit(m_queueA, VK_NULL_HANDLE));
1384         }
1385 
1386         // Submit reads, only waiting waiting on the last write
1387         // operations, ordering of signaling should guarantee that
1388         // when read operations kick in all writes have completed.
1389         {
1390             VkCommandBufferSubmitInfoKHR commandBufferSubmitInfos = makeCommonCommandBufferSubmitInfo(cmdBufferB);
1391             VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo      = makeCommonSemaphoreSubmitInfo(
1392                 semaphoreHandlesA.back(), timelineValuesA.back(), VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR);
1393             VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(
1394                 semaphoreHandlesB.back(), timelineValuesB.back(), VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
1395             SynchronizationWrapperPtr synchronizationWrapper =
1396                 getSynchronizationWrapper(m_type, vk, isTimelineSemaphore);
1397 
1398             synchronizationWrapper->addSubmitInfo(
1399                 1u,                         // uint32_t                                waitSemaphoreInfoCount
1400                 &waitSemaphoreSubmitInfo,   // const VkSemaphoreSubmitInfoKHR*        pWaitSemaphoreInfos
1401                 1u,                         // uint32_t                                commandBufferInfoCount
1402                 &commandBufferSubmitInfos,  // const VkCommandBufferSubmitInfoKHR*    pCommandBufferInfos
1403                 1u,                         // uint32_t                                signalSemaphoreInfoCount
1404                 &signalSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR*        pSignalSemaphoreInfos
1405                 isTimelineSemaphore, isTimelineSemaphore);
1406 
1407             VK_CHECK(synchronizationWrapper->queueSubmit(m_queueB, *fence));
1408 
1409             if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
1410             {
1411                 const VkSemaphoreWaitInfo waitInfo = {
1412                     VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType;
1413                     nullptr,                               // const void* pNext;
1414                     0u,                                    // VkSemaphoreWaitFlagsKHR flags;
1415                     1u,                                    // uint32_t semaphoreCount;
1416                     &semaphoreHandlesB.back(),             // const VkSemaphore* pSemaphores;
1417                     &timelineValuesB.back(),               // const uint64_t* pValues;
1418                 };
1419 
1420                 // Unblock the whole lot.
1421                 hostSignal(vk, device, semaphoreHandlesA.front(), 1);
1422 
1423                 VK_CHECK(vk.waitSemaphores(device, &waitInfo, ~0ull));
1424             }
1425             else
1426             {
1427                 VK_CHECK(vk.waitForFences(device, 1, &fence.get(), VK_TRUE, ~0ull));
1428             }
1429         }
1430 
1431         // Verify the result of the operations.
1432         for (uint32_t iterIdx = 0; iterIdx < iterations.size(); iterIdx++)
1433         {
1434             QueueSubmitOrderIteration &iter = iterations[iterIdx];
1435             const Data expected             = iter.writeOp->getData();
1436             const Data actual               = iter.readOp->getData();
1437 
1438             if (isIndirectBuffer(iter.resource->getType()))
1439             {
1440                 const uint32_t expectedValue = reinterpret_cast<const uint32_t *>(expected.data)[0];
1441                 const uint32_t actualValue   = reinterpret_cast<const uint32_t *>(actual.data)[0];
1442 
1443                 if (actualValue < expectedValue)
1444                     return tcu::TestStatus::fail("Counter value is smaller than expected");
1445             }
1446             else
1447             {
1448                 if (0 != deMemCmp(expected.data, actual.data, expected.size))
1449                     return tcu::TestStatus::fail("Memory contents don't match");
1450             }
1451         }
1452 
1453         return tcu::TestStatus::pass("Success");
1454     }
1455 
1456 private:
addSemaphore(const DeviceInterface & vk,VkDevice device,std::vector<Move<VkSemaphore>> & semaphores,std::vector<VkSemaphore> & semaphoreHandles,std::vector<uint64_t> & timelineValues,uint64_t firstTimelineValue)1457     void addSemaphore(const DeviceInterface &vk, VkDevice device, std::vector<Move<VkSemaphore>> &semaphores,
1458                       std::vector<VkSemaphore> &semaphoreHandles, std::vector<uint64_t> &timelineValues,
1459                       uint64_t firstTimelineValue)
1460     {
1461         Move<VkSemaphore> semaphore;
1462 
1463         if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
1464         {
1465             // Only allocate a single exportable semaphore.
1466             if (semaphores.empty())
1467             {
1468                 semaphores.push_back(createSemaphoreType(vk, device, m_semaphoreType));
1469             }
1470         }
1471         else
1472         {
1473             semaphores.push_back(createSemaphoreType(vk, device, m_semaphoreType));
1474         }
1475 
1476         semaphoreHandles.push_back(*semaphores.back());
1477         timelineValues.push_back((timelineValues.empty() ? firstTimelineValue : timelineValues.back()) +
1478                                  m_rng.getInt(1, 100));
1479     }
1480 
1481     SynchronizationType m_type;
1482     SharedPtr<OperationSupport> m_writeOpSupport;
1483     SharedPtr<OperationSupport> m_readOpSupport;
1484     const ResourceDescription &m_resourceDesc;
1485     VkSemaphoreType m_semaphoreType;
1486     const Unique<VkDevice> &m_device;
1487     const DeviceDriver m_deviceInterface;
1488     UniquePtr<SimpleAllocator> m_allocator;
1489     UniquePtr<OperationContext> m_operationContext;
1490     VkQueue m_queueA;
1491     VkQueue m_queueB;
1492     uint32_t m_queueFamilyIndexA;
1493     uint32_t m_queueFamilyIndexB;
1494     de::Random m_rng;
1495 };
1496 
1497 class QueueSubmitSignalOrderTestCase : public TestCase
1498 {
1499 public:
QueueSubmitSignalOrderTestCase(tcu::TestContext & testCtx,SynchronizationType type,const std::string & name,OperationName writeOp,OperationName readOp,const ResourceDescription & resourceDesc,VkSemaphoreType semaphoreType,PipelineCacheData & pipelineCacheData)1500     QueueSubmitSignalOrderTestCase(tcu::TestContext &testCtx, SynchronizationType type, const std::string &name,
1501                                    OperationName writeOp, OperationName readOp, const ResourceDescription &resourceDesc,
1502                                    VkSemaphoreType semaphoreType, PipelineCacheData &pipelineCacheData)
1503         : TestCase(testCtx, name.c_str())
1504         , m_type(type)
1505         , m_writeOpSupport(makeOperationSupport(writeOp, resourceDesc).release())
1506         , m_readOpSupport(makeOperationSupport(readOp, resourceDesc).release())
1507         , m_resourceDesc(resourceDesc)
1508         , m_semaphoreType(semaphoreType)
1509         , m_pipelineCacheData(pipelineCacheData)
1510     {
1511     }
1512 
checkSupport(Context & context) const1513     virtual void checkSupport(Context &context) const
1514     {
1515         if (m_semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE_KHR &&
1516             !context.getTimelineSemaphoreFeatures().timelineSemaphore)
1517             TCU_THROW(NotSupportedError, "Timeline semaphore not supported");
1518         if (m_type == SynchronizationType::SYNCHRONIZATION2)
1519             context.requireDeviceFunctionality("VK_KHR_synchronization2");
1520     }
1521 
createInstance(Context & context) const1522     TestInstance *createInstance(Context &context) const
1523     {
1524         return new QueueSubmitSignalOrderTestInstance(context, m_type, m_writeOpSupport, m_readOpSupport,
1525                                                       m_resourceDesc, m_semaphoreType, m_pipelineCacheData);
1526     }
1527 
initPrograms(SourceCollections & programCollection) const1528     void initPrograms(SourceCollections &programCollection) const
1529     {
1530         m_writeOpSupport->initPrograms(programCollection);
1531         m_readOpSupport->initPrograms(programCollection);
1532     }
1533 
1534 private:
1535     SynchronizationType m_type;
1536     SharedPtr<OperationSupport> m_writeOpSupport;
1537     SharedPtr<OperationSupport> m_readOpSupport;
1538     const ResourceDescription &m_resourceDesc;
1539     VkSemaphoreType m_semaphoreType;
1540     PipelineCacheData &m_pipelineCacheData;
1541 };
1542 
1543 class QueueSubmitSignalOrderTests : public tcu::TestCaseGroup
1544 {
1545 public:
QueueSubmitSignalOrderTests(tcu::TestContext & testCtx,SynchronizationType type,VkSemaphoreType semaphoreType,const char * name)1546     QueueSubmitSignalOrderTests(tcu::TestContext &testCtx, SynchronizationType type, VkSemaphoreType semaphoreType,
1547                                 const char *name)
1548         : tcu::TestCaseGroup(testCtx, name)
1549         , m_type(type)
1550         , m_semaphoreType(semaphoreType)
1551     {
1552     }
1553 
init(void)1554     void init(void)
1555     {
1556         static const OperationName writeOps[] = {
1557             OPERATION_NAME_WRITE_COPY_BUFFER,
1558             OPERATION_NAME_WRITE_COPY_BUFFER_TO_IMAGE,
1559             OPERATION_NAME_WRITE_COPY_IMAGE_TO_BUFFER,
1560             OPERATION_NAME_WRITE_COPY_IMAGE,
1561             OPERATION_NAME_WRITE_BLIT_IMAGE,
1562             OPERATION_NAME_WRITE_SSBO_VERTEX,
1563             OPERATION_NAME_WRITE_SSBO_TESSELLATION_CONTROL,
1564             OPERATION_NAME_WRITE_SSBO_TESSELLATION_EVALUATION,
1565             OPERATION_NAME_WRITE_SSBO_GEOMETRY,
1566             OPERATION_NAME_WRITE_SSBO_FRAGMENT,
1567             OPERATION_NAME_WRITE_SSBO_COMPUTE,
1568             OPERATION_NAME_WRITE_SSBO_COMPUTE_INDIRECT,
1569             OPERATION_NAME_WRITE_IMAGE_VERTEX,
1570             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_CONTROL,
1571             OPERATION_NAME_WRITE_IMAGE_TESSELLATION_EVALUATION,
1572             OPERATION_NAME_WRITE_IMAGE_GEOMETRY,
1573             OPERATION_NAME_WRITE_IMAGE_FRAGMENT,
1574             OPERATION_NAME_WRITE_IMAGE_COMPUTE,
1575             OPERATION_NAME_WRITE_IMAGE_COMPUTE_INDIRECT,
1576         };
1577         static const OperationName readOps[] = {
1578             OPERATION_NAME_READ_COPY_BUFFER,
1579             OPERATION_NAME_READ_COPY_BUFFER_TO_IMAGE,
1580             OPERATION_NAME_READ_COPY_IMAGE_TO_BUFFER,
1581             OPERATION_NAME_READ_COPY_IMAGE,
1582             OPERATION_NAME_READ_BLIT_IMAGE,
1583             OPERATION_NAME_READ_UBO_VERTEX,
1584             OPERATION_NAME_READ_UBO_TESSELLATION_CONTROL,
1585             OPERATION_NAME_READ_UBO_TESSELLATION_EVALUATION,
1586             OPERATION_NAME_READ_UBO_GEOMETRY,
1587             OPERATION_NAME_READ_UBO_FRAGMENT,
1588             OPERATION_NAME_READ_UBO_COMPUTE,
1589             OPERATION_NAME_READ_UBO_COMPUTE_INDIRECT,
1590             OPERATION_NAME_READ_SSBO_VERTEX,
1591             OPERATION_NAME_READ_SSBO_TESSELLATION_CONTROL,
1592             OPERATION_NAME_READ_SSBO_TESSELLATION_EVALUATION,
1593             OPERATION_NAME_READ_SSBO_GEOMETRY,
1594             OPERATION_NAME_READ_SSBO_FRAGMENT,
1595             OPERATION_NAME_READ_SSBO_COMPUTE,
1596             OPERATION_NAME_READ_SSBO_COMPUTE_INDIRECT,
1597             OPERATION_NAME_READ_IMAGE_VERTEX,
1598             OPERATION_NAME_READ_IMAGE_TESSELLATION_CONTROL,
1599             OPERATION_NAME_READ_IMAGE_TESSELLATION_EVALUATION,
1600             OPERATION_NAME_READ_IMAGE_GEOMETRY,
1601             OPERATION_NAME_READ_IMAGE_FRAGMENT,
1602             OPERATION_NAME_READ_IMAGE_COMPUTE,
1603             OPERATION_NAME_READ_IMAGE_COMPUTE_INDIRECT,
1604             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW,
1605             OPERATION_NAME_READ_INDIRECT_BUFFER_DRAW_INDEXED,
1606             OPERATION_NAME_READ_INDIRECT_BUFFER_DISPATCH,
1607             OPERATION_NAME_READ_VERTEX_INPUT,
1608         };
1609 
1610         for (uint32_t writeOpIdx = 0; writeOpIdx < DE_LENGTH_OF_ARRAY(writeOps); writeOpIdx++)
1611             for (uint32_t readOpIdx = 0; readOpIdx < DE_LENGTH_OF_ARRAY(readOps); readOpIdx++)
1612             {
1613                 const OperationName writeOp   = writeOps[writeOpIdx];
1614                 const OperationName readOp    = readOps[readOpIdx];
1615                 const std::string opGroupName = getOperationName(writeOp) + "_" + getOperationName(readOp);
1616                 bool empty                    = true;
1617 
1618                 de::MovePtr<tcu::TestCaseGroup> opGroup(new tcu::TestCaseGroup(m_testCtx, opGroupName.c_str()));
1619 
1620                 for (int resourceNdx = 0; resourceNdx < DE_LENGTH_OF_ARRAY(s_resources); ++resourceNdx)
1621                 {
1622                     const ResourceDescription &resource = s_resources[resourceNdx];
1623 
1624                     if (isResourceSupported(writeOp, resource) && isResourceSupported(readOp, resource))
1625                     {
1626                         opGroup->addChild(
1627                             new QueueSubmitSignalOrderTestCase(m_testCtx, m_type, getResourceName(resource), writeOp,
1628                                                                readOp, resource, m_semaphoreType, m_pipelineCacheData));
1629                         empty = false;
1630                     }
1631                 }
1632                 if (!empty)
1633                     addChild(opGroup.release());
1634             }
1635     }
1636 
deinit(void)1637     void deinit(void)
1638     {
1639         cleanupGroup();
1640     }
1641 
1642 private:
1643     SynchronizationType m_type;
1644     VkSemaphoreType m_semaphoreType;
1645     // synchronization.op tests share pipeline cache data to speed up test
1646     // execution.
1647     PipelineCacheData m_pipelineCacheData;
1648 };
1649 
1650 } // namespace
1651 
createSignalOrderTests(tcu::TestContext & testCtx,SynchronizationType type)1652 tcu::TestCaseGroup *createSignalOrderTests(tcu::TestContext &testCtx, SynchronizationType type)
1653 {
1654     de::MovePtr<tcu::TestCaseGroup> orderingTests(new tcu::TestCaseGroup(testCtx, "signal_order"));
1655 
1656     orderingTests->addChild(
1657         new QueueSubmitSignalOrderTests(testCtx, type, VK_SEMAPHORE_TYPE_BINARY_KHR, "binary_semaphore"));
1658     orderingTests->addChild(
1659         new QueueSubmitSignalOrderTests(testCtx, type, VK_SEMAPHORE_TYPE_TIMELINE_KHR, "timeline_semaphore"));
1660     orderingTests->addChild(
1661         new QueueSubmitSignalOrderSharedTests(testCtx, type, VK_SEMAPHORE_TYPE_BINARY_KHR, "shared_binary_semaphore"));
1662     orderingTests->addChild(new QueueSubmitSignalOrderSharedTests(testCtx, type, VK_SEMAPHORE_TYPE_TIMELINE_KHR,
1663                                                                   "shared_timeline_semaphore"));
1664 
1665     return orderingTests.release();
1666 }
1667 
1668 } // namespace synchronization
1669 } // namespace vkt
1670