1 // Copyright 2021 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "VkTimelineSemaphore.hpp"
16 #include "VkSemaphore.hpp"
17
18 #include "marl/blockingcall.h"
19 #include "marl/conditionvariable.h"
20
21 #include <vector>
22
23 namespace vk {
24
TimelineSemaphore(const VkSemaphoreCreateInfo * pCreateInfo,void * mem,const VkAllocationCallbacks * pAllocator)25 TimelineSemaphore::TimelineSemaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem, const VkAllocationCallbacks *pAllocator)
26 : Semaphore(VK_SEMAPHORE_TYPE_TIMELINE)
27 {
28 SemaphoreCreateInfo info(pCreateInfo);
29 ASSERT(info.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE);
30 type = info.semaphoreType;
31 shared = marl::Allocator::Default->make_shared<TimelineSemaphore::Shared>(marl::Allocator::Default, info.initialPayload);
32 }
33
TimelineSemaphore()34 TimelineSemaphore::TimelineSemaphore()
35 : Semaphore(VK_SEMAPHORE_TYPE_TIMELINE)
36 {
37 type = VK_SEMAPHORE_TYPE_TIMELINE;
38 shared = marl::Allocator::Default->make_shared<TimelineSemaphore::Shared>(marl::Allocator::Default, 0);
39 }
40
ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo * pCreateInfo)41 size_t TimelineSemaphore::ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo)
42 {
43 return 0;
44 }
45
destroy(const VkAllocationCallbacks * pAllocator)46 void TimelineSemaphore::destroy(const VkAllocationCallbacks *pAllocator)
47 {
48 }
49
signal(uint64_t value)50 void TimelineSemaphore::signal(uint64_t value)
51 {
52 return shared->signal(value);
53 }
54
signal(uint64_t value)55 void TimelineSemaphore::Shared::signal(uint64_t value)
56 {
57 marl::lock lock(mutex);
58 if(counter < value)
59 {
60 counter = value;
61 cv.notify_all();
62 for(auto dep : deps)
63 {
64 dep->signal(id, counter);
65 }
66 }
67 }
68
wait(uint64_t value)69 void TimelineSemaphore::wait(uint64_t value)
70 {
71 shared->wait(value);
72 }
73
wait(uint64_t value)74 void TimelineSemaphore::Shared::wait(uint64_t value)
75 {
76 marl::lock lock(mutex);
77 cv.wait(lock, [&]() { return counter >= value; });
78 }
79
getCounterValue()80 uint64_t TimelineSemaphore::getCounterValue()
81 {
82 return shared->getCounterValue();
83 }
84
getCounterValue()85 uint64_t TimelineSemaphore::Shared::getCounterValue()
86 {
87 marl::lock lock(mutex);
88 return counter;
89 }
90
91 std::atomic<int> TimelineSemaphore::Shared::nextId;
92
Shared(marl::Allocator * allocator,uint64_t initialState)93 TimelineSemaphore::Shared::Shared(marl::Allocator *allocator, uint64_t initialState)
94 : cv(allocator)
95 , counter(initialState)
96 , id(nextId++)
97 {
98 }
99
signal(int parentId,uint64_t value)100 void TimelineSemaphore::Shared::signal(int parentId, uint64_t value)
101 {
102 marl::lock lock(mutex);
103 auto it = waitMap.find(parentId);
104 // Either we aren't waiting for a signal, or parentId is not something we're waiting for
105 // Reject any signals that we aren't waiting on
106 if(counter == 0 && it != waitMap.end() && value == it->second)
107 {
108 // Stop waiting on all parents once we find a signal
109 waitMap.clear();
110 counter = 1;
111 cv.notify_all();
112 for(auto dep : deps)
113 {
114 dep->signal(id, counter);
115 }
116 }
117 }
118
addDependent(TimelineSemaphore & other,uint64_t waitValue)119 void TimelineSemaphore::addDependent(TimelineSemaphore &other, uint64_t waitValue)
120 {
121 shared->addDependent(other);
122 other.addDependency(shared->id, waitValue);
123 }
124
addDependent(TimelineSemaphore & other)125 void TimelineSemaphore::Shared::addDependent(TimelineSemaphore &other)
126 {
127 marl::lock lock(mutex);
128 deps.push_back(other.shared);
129 }
130
addDependency(int id,uint64_t waitValue)131 void TimelineSemaphore::addDependency(int id, uint64_t waitValue)
132 {
133 shared->addDependency(id, waitValue);
134 }
135
addDependency(int id,uint64_t waitValue)136 void TimelineSemaphore::Shared::addDependency(int id, uint64_t waitValue)
137 {
138 marl::lock lock(mutex);
139 auto mapPos = waitMap.find(id);
140 ASSERT(mapPos == waitMap.end());
141
142 waitMap.insert(mapPos, std::make_pair(id, waitValue));
143 }
144
145 } // namespace vk
146