| // Copyright 2021 The SwiftShader Authors. All Rights Reserved. |
| // |
| // 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. |
| |
| #include "VkTimelineSemaphore.hpp" |
| #include "VkSemaphore.hpp" |
| |
| #include "marl/blockingcall.h" |
| #include "marl/conditionvariable.h" |
| |
| #include <vector> |
| |
| namespace vk { |
| |
| TimelineSemaphore::TimelineSemaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem, const VkAllocationCallbacks *pAllocator) |
| : Semaphore(VK_SEMAPHORE_TYPE_TIMELINE) |
| { |
| SemaphoreCreateInfo info(pCreateInfo); |
| ASSERT(info.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE); |
| type = info.semaphoreType; |
| counter = info.initialPayload; |
| } |
| |
| TimelineSemaphore::TimelineSemaphore() |
| : Semaphore(VK_SEMAPHORE_TYPE_TIMELINE) |
| , counter(0) |
| { |
| type = VK_SEMAPHORE_TYPE_TIMELINE; |
| } |
| |
| size_t TimelineSemaphore::ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo) |
| { |
| return 0; |
| } |
| |
| void TimelineSemaphore::destroy(const VkAllocationCallbacks *pAllocator) |
| { |
| } |
| |
| void TimelineSemaphore::signal(uint64_t value) |
| { |
| marl::lock lock(mutex); |
| if(counter < value) |
| { |
| counter = value; |
| cv.notify_all(); |
| for(auto &[waitObject, waitValue] : any_waits) |
| { |
| if(counter >= waitValue) |
| { |
| waitObject->signal(); |
| } |
| } |
| } |
| } |
| |
| void TimelineSemaphore::wait(uint64_t value) |
| { |
| marl::lock lock(mutex); |
| cv.wait(lock, [&]() { return counter >= value; }); |
| } |
| |
| uint64_t TimelineSemaphore::getCounterValue() |
| { |
| marl::lock lock(mutex); |
| return counter; |
| } |
| |
| TimelineSemaphore::WaitForAny::WaitForAny(const VkSemaphoreWaitInfo *pWaitInfo) |
| { |
| for(uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) |
| { |
| TimelineSemaphore *semaphore = DynamicCast<TimelineSemaphore>(pWaitInfo->pSemaphores[i]); |
| uint64_t waitValue = pWaitInfo->pValues[i]; |
| switch(semaphore->addWait(this, waitValue)) |
| { |
| case AddWaitResult::kWaitAdded: |
| semaphores.push_back(semaphore); |
| break; |
| case AddWaitResult::kValueAlreadySignaled: |
| signal(); |
| break; |
| case AddWaitResult::kWaitUpdated: |
| // Do nothing. |
| break; |
| } |
| } |
| } |
| |
| TimelineSemaphore::WaitForAny::~WaitForAny() |
| { |
| for(TimelineSemaphore *semaphore : semaphores) |
| { |
| semaphore->removeWait(this); |
| } |
| } |
| |
| TimelineSemaphore::AddWaitResult |
| TimelineSemaphore::addWait(WaitForAny *waitObject, uint64_t waitValue) |
| { |
| // Lock the semaphore's mutex, so that its current state can be checked and, |
| // if necessary, its list of waits can be updated. |
| marl::lock lock(mutex); |
| if(counter >= waitValue) |
| { |
| return AddWaitResult::kValueAlreadySignaled; |
| } |
| |
| auto it = any_waits.find(waitObject); |
| if(it == any_waits.end()) |
| { |
| any_waits[waitObject] = waitValue; |
| return AddWaitResult::kWaitAdded; |
| } |
| |
| // If the same dependency is added more than once, only wait for the |
| // lowest expected value provided. |
| it->second = std::min(it->second, waitValue); |
| return AddWaitResult::kWaitUpdated; |
| } |
| |
| void TimelineSemaphore::removeWait(WaitForAny *waitObject) |
| { |
| marl::lock lock(mutex); |
| any_waits.erase(waitObject); |
| } |
| |
| void TimelineSemaphore::WaitForAny::wait() |
| { |
| marl::lock lock(mutex); |
| cv.wait(lock, [&]() { return is_signaled; }); |
| } |
| |
| void TimelineSemaphore::WaitForAny::signal() |
| { |
| marl::lock lock(mutex); |
| if(!is_signaled) |
| { |
| is_signaled = true; |
| cv.notify_all(); |
| } |
| } |
| |
| } // namespace vk |