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