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