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