From: Ricardo Garcia Date: Thu, 28 May 2020 15:15:01 +0000 (+0200) Subject: Test vkQueueBindSparse with timeline semaphores X-Git-Tag: upstream/1.3.5~1340 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c593ee17aebac96e72812a3dfd76f730c6be0439;p=platform%2Fupstream%2FVK-GL-CTS.git Test vkQueueBindSparse with timeline semaphores Add tests to check vkQueueBindSparse properly uses timeline semaphores, waiting or signaling them as requested. New tests: dEQP-VK.synchronization.timeline_semaphore.sparse_bind.* Components: Vulkan VK-GL-CTS issue: 2357 Change-Id: I31baf0bbed5c080347196101888b5dbfd7539330 --- diff --git a/android/cts/master/vk-master-2020-03-01.txt b/android/cts/master/vk-master-2020-03-01.txt index fc07bfe..59900b0 100644 --- a/android/cts/master/vk-master-2020-03-01.txt +++ b/android/cts/master/vk-master-2020-03-01.txt @@ -160213,6 +160213,11 @@ dEQP-VK.synchronization.timeline_semaphore.wait.one_signal_from_device dEQP-VK.synchronization.timeline_semaphore.wait.all_signal_from_host dEQP-VK.synchronization.timeline_semaphore.wait.one_signal_from_host dEQP-VK.synchronization.timeline_semaphore.wait.host_wait_before_signal +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.no_sems +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.no_wait_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_no_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_and_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_and_sig_2 dEQP-VK.synchronization.op.single_queue.timeline_semaphore.write_fill_buffer_read_copy_buffer.buffer_16384 dEQP-VK.synchronization.op.single_queue.timeline_semaphore.write_fill_buffer_read_copy_buffer.buffer_262144 dEQP-VK.synchronization.op.single_queue.timeline_semaphore.write_fill_buffer_read_copy_buffer_to_image.buffer_16384 diff --git a/android/cts/master/vk-master.txt b/android/cts/master/vk-master.txt index 35eb4fe..8ad1796 100644 --- a/android/cts/master/vk-master.txt +++ b/android/cts/master/vk-master.txt @@ -484651,6 +484651,11 @@ dEQP-VK.synchronization.timeline_semaphore.wait.one_signal_from_device dEQP-VK.synchronization.timeline_semaphore.wait.all_signal_from_host dEQP-VK.synchronization.timeline_semaphore.wait.one_signal_from_host dEQP-VK.synchronization.timeline_semaphore.wait.host_wait_before_signal +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.no_sems +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.no_wait_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_no_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_and_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_and_sig_2 dEQP-VK.synchronization.op.single_queue.fence.write_fill_buffer_read_copy_buffer.buffer_16384 dEQP-VK.synchronization.op.single_queue.fence.write_fill_buffer_read_copy_buffer.buffer_262144 dEQP-VK.synchronization.op.single_queue.fence.write_fill_buffer_read_copy_buffer_to_image.buffer_16384 diff --git a/external/vulkancts/modules/vulkan/synchronization/vktSynchronizationTimelineSemaphoreTests.cpp b/external/vulkancts/modules/vulkan/synchronization/vktSynchronizationTimelineSemaphoreTests.cpp index 00966d8..ac491fa 100644 --- a/external/vulkancts/modules/vulkan/synchronization/vktSynchronizationTimelineSemaphoreTests.cpp +++ b/external/vulkancts/modules/vulkan/synchronization/vktSynchronizationTimelineSemaphoreTests.cpp @@ -48,6 +48,9 @@ #include #include +#include +#include +#include namespace vkt { @@ -2038,6 +2041,273 @@ private: PipelineCacheData m_pipelineCacheData; }; +// Make a nonzero initial value for a semaphore. semId is assigned to each semaphore by callers. +deUint64 getInitialValue (deUint32 semId) +{ + return (semId + 1ull) * 1000ull; +} + +struct SparseBindParams +{ + deUint32 numWaitSems; + deUint32 numSignalSems; +}; + +class SparseBindCase : public vkt::TestCase +{ +public: + SparseBindCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const SparseBindParams& params); + virtual ~SparseBindCase (void) {} + + virtual TestInstance* createInstance (Context& context) const; + virtual void checkSupport (Context& context) const; + +private: + SparseBindParams m_params; +}; + +class SparseBindInstance : public vkt::TestInstance +{ +public: + SparseBindInstance (Context& context, const SparseBindParams& params); + virtual ~SparseBindInstance (void) {} + + virtual tcu::TestStatus iterate (void); + +private: + SparseBindParams m_params; +}; + +SparseBindCase::SparseBindCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const SparseBindParams& params) + : vkt::TestCase (testCtx, name, description) + , m_params (params) +{} + +TestInstance* SparseBindCase::createInstance (Context& context) const +{ + return new SparseBindInstance(context, m_params); +} + +void SparseBindCase::checkSupport (Context& context) const +{ + // Check support for sparse binding and timeline semaphores. + context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING); + context.requireDeviceFunctionality("VK_KHR_timeline_semaphore"); +} + +SparseBindInstance::SparseBindInstance (Context& context, const SparseBindParams& params) + : vkt::TestInstance (context) + , m_params (params) +{ +} + +void queueBindSparse (const vk::DeviceInterface& vkd, vk::VkQueue queue, deUint32 bindInfoCount, const vk::VkBindSparseInfo *pBindInfo) +{ + VK_CHECK(vkd.queueBindSparse(queue, bindInfoCount, pBindInfo, DE_NULL)); +} + +struct SemaphoreWithInitial +{ + vk::Move semaphore; + deUint64 initialValue; + + SemaphoreWithInitial (vk::Move&& sem, deUint64 initVal) + : semaphore (sem) + , initialValue (initVal) + {} + + SemaphoreWithInitial (SemaphoreWithInitial&& other) + : semaphore (other.semaphore) + , initialValue (other.initialValue) + {} +}; + +using SemaphoreVec = std::vector; +using PlainSemVec = std::vector; +using ValuesVec = std::vector; + +PlainSemVec getHandles (const SemaphoreVec& semVec) +{ + PlainSemVec handlesVec; + handlesVec.reserve(semVec.size()); + + const auto conversion = [](const SemaphoreWithInitial& s) { return s.semaphore.get(); }; + std::transform(begin(semVec), end(semVec), std::back_inserter(handlesVec), conversion); + + return handlesVec; +} + +ValuesVec getInitialValues (const SemaphoreVec& semVec) +{ + ValuesVec initialValues; + initialValues.reserve(semVec.size()); + + const auto conversion = [](const SemaphoreWithInitial& s) { return s.initialValue; }; + std::transform(begin(semVec), end(semVec), std::back_inserter(initialValues), conversion); + + return initialValues; +} + +// Increases values in the vector by one. +ValuesVec getNextValues (const ValuesVec& values) +{ + ValuesVec nextValues; + nextValues.reserve(values.size()); + + std::transform(begin(values), end(values), std::back_inserter(nextValues), [](deUint64 v) { return v + 1ull; }); + return nextValues; +} + +SemaphoreWithInitial createTimelineSemaphore (const vk::DeviceInterface& vkd, vk::VkDevice device, deUint32 semId) +{ + const auto initialValue = getInitialValue(semId); + return SemaphoreWithInitial(createSemaphoreType(vkd, device, vk::VK_SEMAPHORE_TYPE_TIMELINE, 0u, initialValue), initialValue); +} + +// Signal the given semaphores with the corresponding values. +void hostSignal (const vk::DeviceInterface& vkd, vk::VkDevice device, const PlainSemVec& semaphores, const ValuesVec& signalValues) +{ + DE_ASSERT(semaphores.size() == signalValues.size()); + + for (size_t i = 0; i < semaphores.size(); ++i) + hostSignal(vkd, device, semaphores[i], signalValues[i]); +} + +// Wait for the given semaphores and their corresponding values. +void hostWait (const vk::DeviceInterface& vkd, vk::VkDevice device, const PlainSemVec& semaphores, const ValuesVec& waitValues) +{ + DE_ASSERT(semaphores.size() == waitValues.size() && !semaphores.empty()); + + constexpr deUint64 kTimeout = 10000000000ull; // 10 seconds in nanoseconds. + + const vk::VkSemaphoreWaitInfo waitInfo = + { + vk::VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, // VkStructureType sType; + nullptr, // const void* pNext; + 0u, // VkSemaphoreWaitFlags flags; + static_cast(semaphores.size()), // deUint32 semaphoreCount; + semaphores.data(), // const VkSemaphore* pSemaphores; + waitValues.data(), // const deUint64* pValues; + }; + VK_CHECK(vkd.waitSemaphores(device, &waitInfo, kTimeout)); +} + +tcu::TestStatus SparseBindInstance::iterate (void) +{ + const auto& vkd = m_context.getDeviceInterface(); + const auto device = m_context.getDevice(); + const auto queue = m_context.getSparseQueue(); + + SemaphoreVec waitSemaphores; + SemaphoreVec signalSemaphores; + + // Create as many semaphores as needed to wait and signal. + for (deUint32 i = 0; i < m_params.numWaitSems; ++i) + waitSemaphores.emplace_back(createTimelineSemaphore(vkd, device, i)); + for (deUint32 i = 0; i < m_params.numSignalSems; ++i) + signalSemaphores.emplace_back(createTimelineSemaphore(vkd, device, i + m_params.numWaitSems)); + + // Get handles for all semaphores. + const auto waitSemHandles = getHandles(waitSemaphores); + const auto signalSemHandles = getHandles(signalSemaphores); + + // Get initial values for all semaphores. + const auto waitSemValues = getInitialValues(waitSemaphores); + const auto signalSemValues = getInitialValues(signalSemaphores); + + // Get next expected values for all semaphores. + const auto waitNextValues = getNextValues(waitSemValues); + const auto signalNextValues = getNextValues(signalSemValues); + + const vk::VkTimelineSemaphoreSubmitInfo timeLineSubmitInfo = + { + vk::VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, // VkStructureType sType; + nullptr, // const void* pNext; + static_cast(waitNextValues.size()), // deUint32 waitSemaphoreValueCount; + (waitNextValues.empty() ? nullptr : waitNextValues.data()), // const deUint64* pWaitSemaphoreValues; + static_cast(signalNextValues.size()), // deUint32 signalSemaphoreValueCount; + (signalNextValues.empty() ? nullptr : signalNextValues.data()), // const deUint64* pSignalSemaphoreValues; + }; + + const vk::VkBindSparseInfo bindInfo = + { + vk::VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // VkStructureType sType; + &timeLineSubmitInfo, // const void* pNext; + static_cast(waitSemHandles.size()), // deUint32 waitSemaphoreCount; + (waitSemHandles.empty() ? nullptr : waitSemHandles.data()), // const VkSemaphore* pWaitSemaphores; + 0u, // deUint32 bufferBindCount; + nullptr, // const VkSparseBufferMemoryBindInfo* pBufferBinds; + 0u, // deUint32 imageOpaqueBindCount; + nullptr, // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; + 0u, // deUint32 imageBindCount; + nullptr, // const VkSparseImageMemoryBindInfo* pImageBinds; + static_cast(signalSemHandles.size()), // deUint32 signalSemaphoreCount; + (signalSemHandles.empty() ? nullptr : signalSemHandles.data()), // const VkSemaphore* pSignalSemaphores; + }; + queueBindSparse(vkd, queue, 1u, &bindInfo); + + // If the device needs to wait and signal, check the signal semaphores have not been signaled yet. + if (!waitSemaphores.empty() && !signalSemaphores.empty()) + { + deUint64 value; + for (size_t i = 0; i < signalSemaphores.size(); ++i) + { + value = 0; + VK_CHECK(vkd.getSemaphoreCounterValue(device, signalSemHandles[i], &value)); + + if (!value) + TCU_FAIL("Invalid value obtained from vkGetSemaphoreCounterValue()"); + + if (value != signalSemValues[i]) + { + std::ostringstream msg; + msg << "vkQueueBindSparse() may not have waited before signaling semaphore " << i + << " (expected value " << signalSemValues[i] << " but obtained " << value << ")"; + TCU_FAIL(msg.str()); + } + } + } + + // Signal semaphores the sparse bind command is waiting on. + hostSignal(vkd, device, waitSemHandles, waitNextValues); + + // Wait for semaphores the sparse bind command is supposed to signal. + if (!signalSemaphores.empty()) + hostWait(vkd, device, signalSemHandles, signalNextValues); + + VK_CHECK(vkd.deviceWaitIdle(device)); + return tcu::TestStatus::pass("Pass"); +} + +class SparseBindGroup : public tcu::TestCaseGroup +{ +public: + SparseBindGroup (tcu::TestContext& testCtx) + : tcu::TestCaseGroup (testCtx, "sparse_bind", "vkQueueBindSparse combined with timeline semaphores") + {} + + virtual void init (void) + { + static const struct + { + deUint32 waitSems; + deUint32 sigSems; + std::string name; + std::string desc; + } kSparseBindCases[] = + { + { 0u, 0u, "no_sems", "No semaphores to wait for or signal" }, + { 0u, 1u, "no_wait_sig", "Signal semaphore without waiting for any other" }, + { 1u, 0u, "wait_no_sig", "Wait for semaphore but do not signal any other" }, + { 1u, 1u, "wait_and_sig", "Wait for semaphore and signal a second one" }, + { 2u, 2u, "wait_and_sig_2", "Wait for two semaphores and signal two other ones" }, + }; + + for (int i = 0; i < DE_LENGTH_OF_ARRAY(kSparseBindCases); ++i) + addChild(new SparseBindCase(m_testCtx, kSparseBindCases[i].name, kSparseBindCases[i].desc, SparseBindParams{kSparseBindCases[i].waitSems, kSparseBindCases[i].sigSems})); + } +}; + } // anonymous tcu::TestCaseGroup* createTimelineSemaphoreTests (tcu::TestContext& testCtx) @@ -2048,6 +2318,7 @@ tcu::TestCaseGroup* createTimelineSemaphoreTests (tcu::TestContext& testCtx) basicTests->addChild(new OneToNTests(testCtx)); basicTests->addChild(new WaitBeforeSignalTests(testCtx)); basicTests->addChild(new WaitTests(testCtx)); + basicTests->addChild(new SparseBindGroup(testCtx)); return basicTests.release(); } diff --git a/external/vulkancts/mustpass/master/vk-default.txt b/external/vulkancts/mustpass/master/vk-default.txt index dd1ecd3..0483b2b 100644 --- a/external/vulkancts/mustpass/master/vk-default.txt +++ b/external/vulkancts/mustpass/master/vk-default.txt @@ -486617,6 +486617,11 @@ dEQP-VK.synchronization.timeline_semaphore.wait.one_signal_from_device dEQP-VK.synchronization.timeline_semaphore.wait.all_signal_from_host dEQP-VK.synchronization.timeline_semaphore.wait.one_signal_from_host dEQP-VK.synchronization.timeline_semaphore.wait.host_wait_before_signal +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.no_sems +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.no_wait_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_no_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_and_sig +dEQP-VK.synchronization.timeline_semaphore.sparse_bind.wait_and_sig_2 dEQP-VK.synchronization.op.single_queue.fence.write_fill_buffer_read_copy_buffer.buffer_16384 dEQP-VK.synchronization.op.single_queue.fence.write_fill_buffer_read_copy_buffer.buffer_262144 dEQP-VK.synchronization.op.single_queue.fence.write_fill_buffer_read_copy_buffer_to_image.buffer_16384