blob: 7aa85db5518a8b5f97ae7f323e3a824364155ab7 [file] [log] [blame]
// 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