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 counter = info.initialPayload;
32 }
33
TimelineSemaphore()34 TimelineSemaphore::TimelineSemaphore()
35 : Semaphore(VK_SEMAPHORE_TYPE_TIMELINE)
36 , counter(0)
37 {
38 type = VK_SEMAPHORE_TYPE_TIMELINE;
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 marl::lock lock(mutex);
53 if(counter < value)
54 {
55 counter = value;
56 cv.notify_all();
57 for(auto &[waitObject, waitValue] : any_waits)
58 {
59 if(counter >= waitValue)
60 {
61 waitObject->signal();
62 }
63 }
64 }
65 }
66
wait(uint64_t value)67 void TimelineSemaphore::wait(uint64_t value)
68 {
69 marl::lock lock(mutex);
70 cv.wait(lock, [&]() { return counter >= value; });
71 }
72
getCounterValue()73 uint64_t TimelineSemaphore::getCounterValue()
74 {
75 marl::lock lock(mutex);
76 return counter;
77 }
78
WaitForAny(const VkSemaphoreWaitInfo * pWaitInfo)79 TimelineSemaphore::WaitForAny::WaitForAny(const VkSemaphoreWaitInfo *pWaitInfo)
80 {
81 for(uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++)
82 {
83 TimelineSemaphore *semaphore = DynamicCast<TimelineSemaphore>(pWaitInfo->pSemaphores[i]);
84 uint64_t waitValue = pWaitInfo->pValues[i];
85 switch(semaphore->addWait(this, waitValue))
86 {
87 case AddWaitResult::kWaitAdded:
88 semaphores.push_back(semaphore);
89 break;
90 case AddWaitResult::kValueAlreadySignaled:
91 signal();
92 break;
93 case AddWaitResult::kWaitUpdated:
94 // Do nothing.
95 break;
96 }
97 }
98 }
99
~WaitForAny()100 TimelineSemaphore::WaitForAny::~WaitForAny()
101 {
102 for(TimelineSemaphore *semaphore : semaphores)
103 {
104 semaphore->removeWait(this);
105 }
106 }
107
108 TimelineSemaphore::AddWaitResult
addWait(WaitForAny * waitObject,uint64_t waitValue)109 TimelineSemaphore::addWait(WaitForAny *waitObject, uint64_t waitValue)
110 {
111 // Lock the semaphore's mutex, so that its current state can be checked and,
112 // if necessary, its list of waits can be updated.
113 marl::lock lock(mutex);
114 if(counter >= waitValue)
115 {
116 return AddWaitResult::kValueAlreadySignaled;
117 }
118
119 auto it = any_waits.find(waitObject);
120 if(it == any_waits.end())
121 {
122 any_waits[waitObject] = waitValue;
123 return AddWaitResult::kWaitAdded;
124 }
125
126 // If the same dependency is added more than once, only wait for the
127 // lowest expected value provided.
128 it->second = std::min(it->second, waitValue);
129 return AddWaitResult::kWaitUpdated;
130 }
131
removeWait(WaitForAny * waitObject)132 void TimelineSemaphore::removeWait(WaitForAny *waitObject)
133 {
134 marl::lock lock(mutex);
135 any_waits.erase(waitObject);
136 }
137
wait()138 void TimelineSemaphore::WaitForAny::wait()
139 {
140 marl::lock lock(mutex);
141 cv.wait(lock, [&]() { return is_signaled; });
142 }
143
signal()144 void TimelineSemaphore::WaitForAny::signal()
145 {
146 marl::lock lock(mutex);
147 if(!is_signaled)
148 {
149 is_signaled = true;
150 cv.notify_all();
151 }
152 }
153
154 } // namespace vk
155