| // 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; |
| shared = marl::Allocator::Default->make_shared<TimelineSemaphore::Shared>(marl::Allocator::Default, info.initialPayload); |
| } |
| |
| TimelineSemaphore::TimelineSemaphore() |
| : Semaphore(VK_SEMAPHORE_TYPE_TIMELINE) |
| { |
| type = VK_SEMAPHORE_TYPE_TIMELINE; |
| shared = marl::Allocator::Default->make_shared<TimelineSemaphore::Shared>(marl::Allocator::Default, 0); |
| } |
| |
| size_t TimelineSemaphore::ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo) |
| { |
| return 0; |
| } |
| |
| void TimelineSemaphore::destroy(const VkAllocationCallbacks *pAllocator) |
| { |
| } |
| |
| void TimelineSemaphore::signal(uint64_t value) |
| { |
| return shared->signal(value); |
| } |
| |
| void TimelineSemaphore::Shared::signal(uint64_t value) |
| { |
| marl::lock lock(mutex); |
| if(counter < value) |
| { |
| counter = value; |
| cv.notify_all(); |
| for(auto dep : deps) |
| { |
| dep->signal(id, counter); |
| } |
| } |
| } |
| |
| void TimelineSemaphore::wait(uint64_t value) |
| { |
| shared->wait(value); |
| } |
| |
| void TimelineSemaphore::Shared::wait(uint64_t value) |
| { |
| marl::lock lock(mutex); |
| cv.wait(lock, [&]() { return counter >= value; }); |
| } |
| |
| uint64_t TimelineSemaphore::getCounterValue() |
| { |
| return shared->getCounterValue(); |
| } |
| |
| uint64_t TimelineSemaphore::Shared::getCounterValue() |
| { |
| marl::lock lock(mutex); |
| return counter; |
| } |
| |
| std::atomic<int> TimelineSemaphore::Shared::nextId; |
| |
| TimelineSemaphore::Shared::Shared(marl::Allocator *allocator, uint64_t initialState) |
| : cv(allocator) |
| , counter(initialState) |
| , id(nextId++) |
| { |
| } |
| |
| void TimelineSemaphore::Shared::signal(int parentId, uint64_t value) |
| { |
| marl::lock lock(mutex); |
| auto it = waitMap.find(parentId); |
| // Either we aren't waiting for a signal, or parentId is not something we're waiting for |
| // Reject any signals that we aren't waiting on |
| if(counter == 0 && it != waitMap.end() && value == it->second) |
| { |
| // Stop waiting on all parents once we find a signal |
| waitMap.clear(); |
| counter = 1; |
| cv.notify_all(); |
| for(auto dep : deps) |
| { |
| dep->signal(id, counter); |
| } |
| } |
| } |
| |
| void TimelineSemaphore::addDependent(TimelineSemaphore &other, uint64_t waitValue) |
| { |
| shared->addDependent(other); |
| other.addDependency(shared->id, waitValue); |
| } |
| |
| void TimelineSemaphore::Shared::addDependent(TimelineSemaphore &other) |
| { |
| marl::lock lock(mutex); |
| deps.push_back(other.shared); |
| } |
| |
| void TimelineSemaphore::addDependency(int id, uint64_t waitValue) |
| { |
| shared->addDependency(id, waitValue); |
| } |
| |
| void TimelineSemaphore::Shared::addDependency(int id, uint64_t waitValue) |
| { |
| marl::lock lock(mutex); |
| auto mapPos = waitMap.find(id); |
| ASSERT(mapPos == waitMap.end()); |
| |
| waitMap.insert(mapPos, std::make_pair(id, waitValue)); |
| } |
| |
| } // namespace vk |