blob: ce2529bff5064891158c2d4a0d935009f4a31500 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Synchronization semaphore basic tests
*//*--------------------------------------------------------------------*/
#include "vktSynchronizationBasicSemaphoreTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktSynchronizationUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "vkDefs.hpp"
#include "vkPlatform.hpp"
#include "vkQueryUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkDeviceUtil.hpp"
#include "vkRef.hpp"
#include "vkSafetyCriticalUtil.hpp"
#include <thread>
#include "tcuCommandLine.hpp"
namespace vkt
{
namespace synchronization
{
namespace
{
using namespace vk;
struct TestConfig
{
bool useTypeCreate;
VkSemaphoreType semaphoreType;
SynchronizationType type;
};
static const int basicChainLength = 32768;
Move<VkSemaphore> createTestSemaphore(Context& context, const DeviceInterface& vk, const VkDevice device, const TestConfig& config)
{
if (config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE && !context.getTimelineSemaphoreFeatures().timelineSemaphore)
TCU_THROW(NotSupportedError, "Timeline semaphore not supported");
return Move<VkSemaphore>(config.useTypeCreate ? createSemaphoreType(vk, device, config.semaphoreType) : createSemaphore(vk, device));
}
#define FENCE_WAIT ~0ull
tcu::TestStatus basicOneQueueCase (Context& context, const TestConfig config)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
const VkQueue queue = context.getUniversalQueue();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
const Unique<VkSemaphore> semaphore (createTestSemaphore(context, vk, device, config));
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
const VkCommandBufferBeginInfo info {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, // VkCommandBufferUsageFlags flags;
DE_NULL, // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
};
const deUint64 timelineValue = 1u;
const Unique<VkFence> fence (createFence(vk, device));
bool usingTimelineSemaphores = config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE;
VkCommandBufferSubmitInfoKHR commandBufferInfo = makeCommonCommandBufferSubmitInfo(*cmdBuffer);
SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(config.type, vk, usingTimelineSemaphores, 2u);
VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(semaphore.get(), timelineValue, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR);
VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(semaphore.get(), timelineValue, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR);
synchronizationWrapper->addSubmitInfo(
0u, // deUint32 waitSemaphoreInfoCount
DE_NULL, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
1u, // deUint32 commandBufferInfoCount
&commandBufferInfo, // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
1u, // deUint32 signalSemaphoreInfoCount
&signalSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
DE_FALSE,
usingTimelineSemaphores
);
synchronizationWrapper->addSubmitInfo(
1u, // deUint32 waitSemaphoreInfoCount
&waitSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
1u, // deUint32 commandBufferInfoCount
&commandBufferInfo, // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
0u, // deUint32 signalSemaphoreInfoCount
DE_NULL, // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
usingTimelineSemaphores,
DE_FALSE
);
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &info));
endCommandBuffer(vk, *cmdBuffer);
VK_CHECK(synchronizationWrapper->queueSubmit(queue, *fence));
if (VK_SUCCESS != vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, FENCE_WAIT))
return tcu::TestStatus::fail("Basic semaphore tests with one queue failed");
return tcu::TestStatus::pass("Basic semaphore tests with one queue passed");
}
tcu::TestStatus basicChainCase(Context & context, TestConfig config)
{
VkResult err = VK_SUCCESS;
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice& device = context.getDevice();
const VkQueue queue = context.getUniversalQueue();
VkSemaphoreCreateInfo sci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, DE_NULL, 0 };
VkFenceCreateInfo fci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, DE_NULL, 0 };
VkFence fence;
std::vector<VkSemaphoreSubmitInfoKHR> waitSemaphoreSubmitInfos (basicChainLength, makeCommonSemaphoreSubmitInfo(0u, 0u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR));
std::vector<VkSemaphoreSubmitInfoKHR> signalSemaphoreSubmitInfos (basicChainLength, makeCommonSemaphoreSubmitInfo(0u, 0u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR));
VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfo = DE_NULL;
VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfo = signalSemaphoreSubmitInfos.data();
for (int i = 0; err == VK_SUCCESS && i < basicChainLength; i++)
{
err = vk.createSemaphore(device, &sci, DE_NULL, &pSignalSemaphoreInfo->semaphore);
if (err != VK_SUCCESS)
continue;
SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(config.type, vk, DE_FALSE);
synchronizationWrapper->addSubmitInfo(
!!pWaitSemaphoreInfo, // deUint32 waitSemaphoreInfoCount
pWaitSemaphoreInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
0u, // deUint32 commandBufferInfoCount
DE_NULL, // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
1u, // deUint32 signalSemaphoreInfoCount
pSignalSemaphoreInfo // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
);
err = synchronizationWrapper->queueSubmit(queue, 0);
pWaitSemaphoreInfo = &waitSemaphoreSubmitInfos[i];
pWaitSemaphoreInfo->semaphore = pSignalSemaphoreInfo->semaphore;
pSignalSemaphoreInfo++;
}
VK_CHECK(vk.createFence(device, &fci, DE_NULL, &fence));
{
SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(config.type, vk, DE_FALSE);
synchronizationWrapper->addSubmitInfo(1, pWaitSemaphoreInfo, 0, DE_NULL, 0, DE_NULL);
VK_CHECK(synchronizationWrapper->queueSubmit(queue, fence));
}
vk.waitForFences(device, 1, &fence, VK_TRUE, ~(0ull));
vk.destroyFence(device, fence, DE_NULL);
for (const auto& s : signalSemaphoreSubmitInfos)
vk.destroySemaphore(device, s.semaphore, DE_NULL);
if (err == VK_SUCCESS)
return tcu::TestStatus::pass("Basic semaphore chain test passed");
return tcu::TestStatus::fail("Basic semaphore chain test failed");
}
tcu::TestStatus basicChainTimelineCase (Context& context, TestConfig config)
{
VkResult err = VK_SUCCESS;
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice& device = context.getDevice();
const VkQueue queue = context.getUniversalQueue();
VkSemaphoreTypeCreateInfo scti = { VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, DE_NULL, VK_SEMAPHORE_TYPE_TIMELINE, 0 };
VkSemaphoreCreateInfo sci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, &scti, 0 };
VkFenceCreateInfo fci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, DE_NULL, 0 };
VkSemaphore semaphore;
VkFence fence;
VK_CHECK(vk.createSemaphore(device, &sci, DE_NULL, &semaphore));
std::vector<VkSemaphoreSubmitInfoKHR> waitSemaphoreSubmitInfos (basicChainLength, makeCommonSemaphoreSubmitInfo(semaphore, 0u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR));
std::vector<VkSemaphoreSubmitInfoKHR> signalSemaphoreSubmitInfos (basicChainLength, makeCommonSemaphoreSubmitInfo(semaphore, 0u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR));
VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfo = DE_NULL;
VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfo = signalSemaphoreSubmitInfos.data();
for (int i = 0; err == VK_SUCCESS && i < basicChainLength; i++)
{
pSignalSemaphoreInfo->value = static_cast<deUint64>(i+1);
SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(config.type, vk, DE_TRUE);
synchronizationWrapper->addSubmitInfo(
!!pWaitSemaphoreInfo, // deUint32 waitSemaphoreInfoCount
pWaitSemaphoreInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
0u, // deUint32 commandBufferInfoCount
DE_NULL, // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
1u, // deUint32 signalSemaphoreInfoCount
pSignalSemaphoreInfo, // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
!!pWaitSemaphoreInfo,
DE_TRUE
);
err = synchronizationWrapper->queueSubmit(queue, 0);
pWaitSemaphoreInfo = &waitSemaphoreSubmitInfos[i];
pWaitSemaphoreInfo->value = static_cast<deUint64>(i);
pSignalSemaphoreInfo++;
}
pWaitSemaphoreInfo->value = basicChainLength;
SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(config.type, vk, DE_TRUE);
synchronizationWrapper->addSubmitInfo(
1u, // deUint32 waitSemaphoreInfoCount
pWaitSemaphoreInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
0u, // deUint32 commandBufferInfoCount
DE_NULL, // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
0u, // deUint32 signalSemaphoreInfoCount
DE_NULL, // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
DE_TRUE
);
VK_CHECK(vk.createFence(device, &fci, DE_NULL, &fence));
VK_CHECK(synchronizationWrapper->queueSubmit(queue, fence));
vk.waitForFences(device, 1, &fence, VK_TRUE, ~(0ull));
vk.destroyFence(device, fence, DE_NULL);
vk.destroySemaphore(device, semaphore, DE_NULL);
if (err == VK_SUCCESS)
return tcu::TestStatus::pass("Basic semaphore chain test passed");
return tcu::TestStatus::fail("Basic semaphore chain test failed");
}
tcu::TestStatus basicThreadTimelineCase(Context& context, TestConfig)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice& device = context.getDevice();
const VkSemaphoreTypeCreateInfo scti = { VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, DE_NULL, VK_SEMAPHORE_TYPE_TIMELINE, 0 };
const VkSemaphoreCreateInfo sci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, &scti, 0 };
const VkFenceCreateInfo fci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, DE_NULL, 0 };
const vk::Unique<vk::VkSemaphore> semaphore (createSemaphore(vk, device, &sci));
const Unique<VkFence> fence (createFence(vk, device, &fci));
const deUint64 waitTimeout = 50ull * 1000000ull; // miliseconds
VkResult threadResult = VK_SUCCESS;
// helper creating VkSemaphoreSignalInfo
auto makeSemaphoreSignalInfo = [&semaphore](deUint64 value) -> VkSemaphoreSignalInfo
{
return
{
VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
*semaphore, // VkSemaphore semaphore
value // deUint64 value
};
};
// helper creating VkSemaphoreWaitInfo
auto makeSemaphoreWaitInfo = [&semaphore](deUint64* valuePtr) -> VkSemaphoreWaitInfo
{
return
{
VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
VK_SEMAPHORE_WAIT_ANY_BIT, // VkSemaphoreWaitFlags flags;
1u, // deUint32 semaphoreCount;
&*semaphore, // const VkSemaphore* pSemaphores;
valuePtr // const deUint64* pValues;
};
};
// start thread - semaphore has value 0
de::MovePtr<std::thread> thread(new std::thread([=, &vk, &threadResult]
{
// wait till semaphore has value 1
deUint64 waitValue = 1;
VkSemaphoreWaitInfo waitOne = makeSemaphoreWaitInfo(&waitValue);
threadResult = vk.waitSemaphores(device, &waitOne, waitTimeout);
if (threadResult == VK_SUCCESS)
{
// signal semaphore with value 2
VkSemaphoreSignalInfo signalTwo = makeSemaphoreSignalInfo(2);
threadResult = vk.signalSemaphore(device, &signalTwo);
}
}));
// wait some time to give thread chance to start
deSleep(1); // milisecond
// signal semaphore with value 1
VkSemaphoreSignalInfo signalOne = makeSemaphoreSignalInfo(1);
vk.signalSemaphore(device, &signalOne);
// wait till semaphore has value 2
deUint64 waitValue = 2;
VkSemaphoreWaitInfo waitTwo = makeSemaphoreWaitInfo(&waitValue);
VkResult mainResult = vk.waitSemaphores(device, &waitTwo, waitTimeout);
thread->join();
if (mainResult == VK_SUCCESS)
return tcu::TestStatus::pass("Pass");
if ((mainResult == VK_TIMEOUT) || (threadResult == VK_TIMEOUT))
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Reached wait timeout");
return tcu::TestStatus::fail("Fail");
}
tcu::TestStatus basicMultiQueueCase(Context& context, TestConfig config)
{
enum { NO_MATCH_FOUND = ~((deUint32)0) };
enum QueuesIndexes { FIRST = 0, SECOND, COUNT };
struct Queues
{
VkQueue queue;
deUint32 queueFamilyIndex;
};
const CustomInstance instance (createCustomInstanceFromContext(context));
const InstanceDriver& instanceDriver (instance.getDriver());
const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine());
// const DeviceInterface& vk = context.getDeviceInterface();
// const InstanceInterface& instance = context.getInstanceInterface();
// const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
vk::Move<vk::VkDevice> logicalDevice;
std::vector<VkQueueFamilyProperties> queueFamilyProperties;
VkDeviceCreateInfo deviceInfo;
VkPhysicalDeviceFeatures deviceFeatures;
const float queuePriorities[COUNT] = { 1.0f, 1.0f };
VkDeviceQueueCreateInfo queueInfos[COUNT];
Queues queues[COUNT] =
{
{DE_NULL, (deUint32)NO_MATCH_FOUND},
{DE_NULL, (deUint32)NO_MATCH_FOUND}
};
const VkCommandBufferBeginInfo info =
{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, // VkCommandBufferUsageFlags flags;
DE_NULL, // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
};
bool isTimelineSemaphore = config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE;
queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice);
for (deUint32 queueNdx = 0; queueNdx < queueFamilyProperties.size(); ++queueNdx)
{
if (NO_MATCH_FOUND == queues[FIRST].queueFamilyIndex)
queues[FIRST].queueFamilyIndex = queueNdx;
if (queues[FIRST].queueFamilyIndex != queueNdx || queueFamilyProperties[queueNdx].queueCount > 1u)
{
queues[SECOND].queueFamilyIndex = queueNdx;
break;
}
}
if (queues[FIRST].queueFamilyIndex == NO_MATCH_FOUND || queues[SECOND].queueFamilyIndex == NO_MATCH_FOUND)
TCU_THROW(NotSupportedError, "Queues couldn't be created");
for (int queueNdx = 0; queueNdx < COUNT; ++queueNdx)
{
VkDeviceQueueCreateInfo queueInfo;
deMemset(&queueInfo, 0, sizeof(queueInfo));
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo.pNext = DE_NULL;
queueInfo.flags = (VkDeviceQueueCreateFlags)0u;
queueInfo.queueFamilyIndex = queues[queueNdx].queueFamilyIndex;
queueInfo.queueCount = (queues[FIRST].queueFamilyIndex == queues[SECOND].queueFamilyIndex) ? 2 : 1;
queueInfo.pQueuePriorities = queuePriorities;
queueInfos[queueNdx] = queueInfo;
if (queues[FIRST].queueFamilyIndex == queues[SECOND].queueFamilyIndex)
break;
}
deMemset(&deviceInfo, 0, sizeof(deviceInfo));
instanceDriver.getPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
VkPhysicalDeviceFeatures2 createPhysicalFeature { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, DE_NULL, deviceFeatures };
VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreFeatures { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, DE_NULL, DE_TRUE };
VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, DE_NULL, DE_TRUE };
void** nextPtr = &createPhysicalFeature.pNext;
std::vector<const char*> deviceExtensions;
if (isTimelineSemaphore)
{
if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_timeline_semaphore"))
deviceExtensions.push_back("VK_KHR_timeline_semaphore");
addToChainVulkanStructure(&nextPtr, timelineSemaphoreFeatures);
}
if (config.type == SynchronizationType::SYNCHRONIZATION2)
{
deviceExtensions.push_back("VK_KHR_synchronization2");
addToChainVulkanStructure(&nextPtr, synchronization2Features);
}
void* pNext = &createPhysicalFeature;
#ifdef CTS_USES_VULKANSC
VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ? context.getResourceInterface()->getStatMax() : resetDeviceObjectReservationCreateInfo();
memReservationInfo.pNext = pNext;
pNext = &memReservationInfo;
VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
sc10Features.pNext = pNext;
pNext = &sc10Features;
VkPipelineCacheCreateInfo pcCI;
std::vector<VkPipelinePoolSize> poolSizes;
if (context.getTestContext().getCommandLine().isSubProcess())
{
if (context.getResourceInterface()->getCacheDataSize() > 0)
{
pcCI =
{
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
context.getResourceInterface()->getCacheDataSize(), // deUintptr initialDataSize;
context.getResourceInterface()->getCacheData() // const void* pInitialData;
};
memReservationInfo.pipelineCacheCreateInfoCount = 1;
memReservationInfo.pPipelineCacheCreateInfos = &pcCI;
}
poolSizes = context.getResourceInterface()->getPipelinePoolSizes();
if (!poolSizes.empty())
{
memReservationInfo.pipelinePoolSizeCount = deUint32(poolSizes.size());
memReservationInfo.pPipelinePoolSizes = poolSizes.data();
}
}
#endif // CTS_USES_VULKANSC
deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceInfo.pNext = pNext;
deviceInfo.enabledExtensionCount = static_cast<deUint32>(deviceExtensions.size());
deviceInfo.ppEnabledExtensionNames = deviceExtensions.empty() ? DE_NULL : deviceExtensions.data();
deviceInfo.enabledLayerCount = 0u;
deviceInfo.ppEnabledLayerNames = DE_NULL;
deviceInfo.pEnabledFeatures = 0u;
deviceInfo.queueCreateInfoCount = (queues[FIRST].queueFamilyIndex == queues[SECOND].queueFamilyIndex) ? 1 : COUNT;
deviceInfo.pQueueCreateInfos = queueInfos;
logicalDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instance, instanceDriver, physicalDevice, &deviceInfo);
#ifndef CTS_USES_VULKANSC
de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), instance, *logicalDevice));
#else
de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver = de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(new DeviceDriverSC(context.getPlatformInterface(), instance, *logicalDevice, context.getTestContext().getCommandLine(), context.getResourceInterface(), context.getDeviceVulkanSC10Properties()), vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *logicalDevice));
#endif // CTS_USES_VULKANSC
const DeviceInterface& vk = *deviceDriver;
for (deUint32 queueReqNdx = 0; queueReqNdx < COUNT; ++queueReqNdx)
{
if (queues[FIRST].queueFamilyIndex == queues[SECOND].queueFamilyIndex)
vk.getDeviceQueue(*logicalDevice, queues[queueReqNdx].queueFamilyIndex, queueReqNdx, &queues[queueReqNdx].queue);
else
vk.getDeviceQueue(*logicalDevice, queues[queueReqNdx].queueFamilyIndex, 0u, &queues[queueReqNdx].queue);
}
Move<VkSemaphore> semaphore;
Move<VkCommandPool> cmdPool[COUNT];
Move<VkCommandBuffer> cmdBuffer[COUNT];
deUint64 timelineValues[COUNT] = { 1ull, 2ull };
Move<VkFence> fence[COUNT];
semaphore = (createTestSemaphore(context, vk, *logicalDevice, config));
cmdPool[FIRST] = (createCommandPool(vk, *logicalDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queues[FIRST].queueFamilyIndex));
cmdPool[SECOND] = (createCommandPool(vk, *logicalDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queues[SECOND].queueFamilyIndex));
cmdBuffer[FIRST] = (makeCommandBuffer(vk, *logicalDevice, *cmdPool[FIRST]));
cmdBuffer[SECOND] = (makeCommandBuffer(vk, *logicalDevice, *cmdPool[SECOND]));
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer[FIRST], &info));
endCommandBuffer(vk, *cmdBuffer[FIRST]);
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer[SECOND], &info));
endCommandBuffer(vk, *cmdBuffer[SECOND]);
fence[FIRST] = (createFence(vk, *logicalDevice));
fence[SECOND] = (createFence(vk, *logicalDevice));
VkCommandBufferSubmitInfoKHR commandBufferInfo[]
{
makeCommonCommandBufferSubmitInfo(*cmdBuffer[FIRST]),
makeCommonCommandBufferSubmitInfo(*cmdBuffer[SECOND])
};
VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo[]
{
makeCommonSemaphoreSubmitInfo(semaphore.get(), timelineValues[FIRST], VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR),
makeCommonSemaphoreSubmitInfo(semaphore.get(), timelineValues[SECOND], VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR)
};
VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo =
makeCommonSemaphoreSubmitInfo(semaphore.get(), timelineValues[FIRST], VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR);
{
SynchronizationWrapperPtr synchronizationWrapper[]
{
getSynchronizationWrapper(config.type, vk, isTimelineSemaphore),
getSynchronizationWrapper(config.type, vk, isTimelineSemaphore)
};
synchronizationWrapper[FIRST]->addSubmitInfo(
0u, // deUint32 waitSemaphoreInfoCount
DE_NULL, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
1u, // deUint32 commandBufferInfoCount
&commandBufferInfo[FIRST], // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
1u, // deUint32 signalSemaphoreInfoCount
&signalSemaphoreSubmitInfo[FIRST], // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
DE_FALSE,
isTimelineSemaphore
);
synchronizationWrapper[SECOND]->addSubmitInfo(
1u, // deUint32 waitSemaphoreInfoCount
&waitSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
1u, // deUint32 commandBufferInfoCount
&commandBufferInfo[SECOND], // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
1u, // deUint32 signalSemaphoreInfoCount
&signalSemaphoreSubmitInfo[SECOND], // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
isTimelineSemaphore,
isTimelineSemaphore
);
VK_CHECK(synchronizationWrapper[FIRST]->queueSubmit(queues[FIRST].queue, *fence[FIRST]));
VK_CHECK(synchronizationWrapper[SECOND]->queueSubmit(queues[SECOND].queue, *fence[SECOND]));
}
if (VK_SUCCESS != vk.waitForFences(*logicalDevice, 1u, &fence[FIRST].get(), DE_TRUE, FENCE_WAIT))
return tcu::TestStatus::fail("Basic semaphore tests with multi queue failed");
if (VK_SUCCESS != vk.waitForFences(*logicalDevice, 1u, &fence[SECOND].get(), DE_TRUE, FENCE_WAIT))
return tcu::TestStatus::fail("Basic semaphore tests with multi queue failed");
if (isTimelineSemaphore)
{
signalSemaphoreSubmitInfo[FIRST].value = 3ull;
signalSemaphoreSubmitInfo[SECOND].value = 4ull;
waitSemaphoreSubmitInfo.value = 3ull;
}
// swap semaphore info compared to above submits
{
SynchronizationWrapperPtr synchronizationWrapper[]
{
getSynchronizationWrapper(config.type, vk, isTimelineSemaphore),
getSynchronizationWrapper(config.type, vk, isTimelineSemaphore)
};
synchronizationWrapper[FIRST]->addSubmitInfo(
1u, // deUint32 waitSemaphoreInfoCount
&waitSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
1u, // deUint32 commandBufferInfoCount
&commandBufferInfo[FIRST], // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
1u, // deUint32 signalSemaphoreInfoCount
&signalSemaphoreSubmitInfo[SECOND], // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
isTimelineSemaphore,
isTimelineSemaphore
);
synchronizationWrapper[SECOND]->addSubmitInfo(
isTimelineSemaphore ? 0u : 1u, // deUint32 waitSemaphoreInfoCount
isTimelineSemaphore ? DE_NULL : &waitSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos
1u, // deUint32 commandBufferInfoCount
&commandBufferInfo[SECOND], // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos
1u, // deUint32 signalSemaphoreInfoCount
&signalSemaphoreSubmitInfo[FIRST], // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos
DE_FALSE,
isTimelineSemaphore
);
VK_CHECK(vk.resetFences(*logicalDevice, 1u, &fence[FIRST].get()));
VK_CHECK(vk.resetFences(*logicalDevice, 1u, &fence[SECOND].get()));
VK_CHECK(synchronizationWrapper[SECOND]->queueSubmit(queues[SECOND].queue, *fence[SECOND]));
VK_CHECK(synchronizationWrapper[FIRST]->queueSubmit(queues[FIRST].queue, *fence[FIRST]));
}
if (VK_SUCCESS != vk.waitForFences(*logicalDevice, 1u, &fence[FIRST].get(), DE_TRUE, FENCE_WAIT))
return tcu::TestStatus::fail("Basic semaphore tests with multi queue failed");
if (VK_SUCCESS != vk.waitForFences(*logicalDevice, 1u, &fence[SECOND].get(), DE_TRUE, FENCE_WAIT))
return tcu::TestStatus::fail("Basic semaphore tests with multi queue failed");
return tcu::TestStatus::pass("Basic semaphore tests with multi queue passed");
}
void checkSupport(Context& context, TestConfig config)
{
if (config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE)
context.requireDeviceFunctionality("VK_KHR_timeline_semaphore");
if (config.type == SynchronizationType::SYNCHRONIZATION2)
context.requireDeviceFunctionality("VK_KHR_synchronization2");
}
void checkCommandBufferSimultaneousUseSupport(Context& context, TestConfig config)
{
checkSupport(context, config);
#ifdef CTS_USES_VULKANSC
if (context.getDeviceVulkanSC10Properties().commandBufferSimultaneousUse == VK_FALSE)
TCU_THROW(NotSupportedError, "commandBufferSimultaneousUse is not supported");
#endif
}
} // anonymous
tcu::TestCaseGroup* createBasicBinarySemaphoreTests (tcu::TestContext& testCtx, SynchronizationType type)
{
de::MovePtr<tcu::TestCaseGroup> basicTests(new tcu::TestCaseGroup(testCtx, "binary_semaphore", "Basic semaphore tests"));
TestConfig config =
{
0,
VK_SEMAPHORE_TYPE_BINARY,
type,
};
for (deUint32 typedCreate = 0; typedCreate < 2; typedCreate++)
{
config.useTypeCreate = (typedCreate != 0);
const std::string createName = config.useTypeCreate ? "_typed" : "";
addFunctionCase(basicTests.get(), "one_queue" + createName, "Basic binary semaphore tests with one queue", checkCommandBufferSimultaneousUseSupport, basicOneQueueCase, config);
addFunctionCase(basicTests.get(), "multi_queue" + createName, "Basic binary semaphore tests with multi queue", checkCommandBufferSimultaneousUseSupport, basicMultiQueueCase, config);
}
addFunctionCase(basicTests.get(), "chain", "Binary semaphore chain test", checkSupport, basicChainCase, config);
return basicTests.release();
}
tcu::TestCaseGroup* createBasicTimelineSemaphoreTests (tcu::TestContext& testCtx, SynchronizationType type)
{
de::MovePtr<tcu::TestCaseGroup> basicTests(new tcu::TestCaseGroup(testCtx, "timeline_semaphore", "Basic timeline semaphore tests"));
const TestConfig config =
{
true,
VK_SEMAPHORE_TYPE_TIMELINE,
type,
};
addFunctionCase(basicTests.get(), "one_queue", "Basic timeline semaphore tests with one queue", checkCommandBufferSimultaneousUseSupport, basicOneQueueCase, config);
addFunctionCase(basicTests.get(), "multi_queue", "Basic timeline semaphore tests with multi queue", checkCommandBufferSimultaneousUseSupport, basicMultiQueueCase, config);
addFunctionCase(basicTests.get(), "chain", "Timeline semaphore chain test", checkSupport, basicChainTimelineCase, config);
// dont repeat this test for synchronization2
if (type == SynchronizationType::LEGACY)
addFunctionCase(basicTests.get(), "two_threads","Timeline semaphore used by two threads", checkSupport, basicThreadTimelineCase, config);
return basicTests.release();
}
} // synchronization
} // vkt