| /*------------------------------------------------------------------------ |
| * 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 |