1 // Copyright 2018 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 "VkDevice.hpp"
16
17 #include "VkConfig.h"
18 #include "VkDescriptorSetLayout.hpp"
19 #include "VkFence.hpp"
20 #include "VkQueue.hpp"
21 #include "Debug/Context.hpp"
22 #include "Debug/Server.hpp"
23 #include "Device/Blitter.hpp"
24 #include "System/Debug.hpp"
25
26 #include <chrono>
27 #include <climits>
28 #include <new> // Must #include this to use "placement new"
29
30 namespace {
31
now()32 std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> now()
33 {
34 return std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now());
35 }
36
37 } // anonymous namespace
38
39 namespace vk {
40
query(const vk::Device::SamplingRoutineCache::Key & key) const41 std::shared_ptr<rr::Routine> Device::SamplingRoutineCache::query(const vk::Device::SamplingRoutineCache::Key &key) const
42 {
43 return cache.query(key);
44 }
45
add(const vk::Device::SamplingRoutineCache::Key & key,const std::shared_ptr<rr::Routine> & routine)46 void Device::SamplingRoutineCache::add(const vk::Device::SamplingRoutineCache::Key &key, const std::shared_ptr<rr::Routine> &routine)
47 {
48 ASSERT(routine);
49 cache.add(key, routine);
50 }
51
queryConst(const vk::Device::SamplingRoutineCache::Key & key) const52 rr::Routine *Device::SamplingRoutineCache::queryConst(const vk::Device::SamplingRoutineCache::Key &key) const
53 {
54 return cache.queryConstCache(key).get();
55 }
56
updateConstCache()57 void Device::SamplingRoutineCache::updateConstCache()
58 {
59 cache.updateConstCache();
60 }
61
Device(const VkDeviceCreateInfo * pCreateInfo,void * mem,PhysicalDevice * physicalDevice,const VkPhysicalDeviceFeatures * enabledFeatures,const std::shared_ptr<marl::Scheduler> & scheduler)62 Device::Device(const VkDeviceCreateInfo *pCreateInfo, void *mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, const std::shared_ptr<marl::Scheduler> &scheduler)
63 : physicalDevice(physicalDevice)
64 , queues(reinterpret_cast<Queue *>(mem))
65 , enabledExtensionCount(pCreateInfo->enabledExtensionCount)
66 , enabledFeatures(enabledFeatures ? *enabledFeatures : VkPhysicalDeviceFeatures{})
67 , // "Setting pEnabledFeatures to NULL and not including a VkPhysicalDeviceFeatures2 in the pNext member of VkDeviceCreateInfo is equivalent to setting all members of the structure to VK_FALSE."
68 scheduler(scheduler)
69 {
70 for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
71 {
72 const VkDeviceQueueCreateInfo &queueCreateInfo = pCreateInfo->pQueueCreateInfos[i];
73 queueCount += queueCreateInfo.queueCount;
74 }
75
76 uint32_t queueID = 0;
77 for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
78 {
79 const VkDeviceQueueCreateInfo &queueCreateInfo = pCreateInfo->pQueueCreateInfos[i];
80
81 for(uint32_t j = 0; j < queueCreateInfo.queueCount; j++, queueID++)
82 {
83 new(&queues[queueID]) Queue(this, scheduler.get());
84 }
85 }
86
87 extensions = reinterpret_cast<ExtensionName *>(static_cast<uint8_t *>(mem) + (sizeof(Queue) * queueCount));
88 for(uint32_t i = 0; i < enabledExtensionCount; i++)
89 {
90 strncpy(extensions[i], pCreateInfo->ppEnabledExtensionNames[i], VK_MAX_EXTENSION_NAME_SIZE);
91 }
92
93 if(pCreateInfo->enabledLayerCount)
94 {
95 // "The ppEnabledLayerNames and enabledLayerCount members of VkDeviceCreateInfo are deprecated and their values must be ignored by implementations."
96 UNSUPPORTED("enabledLayerCount");
97 }
98
99 // FIXME (b/119409619): use an allocator here so we can control all memory allocations
100 blitter.reset(new sw::Blitter());
101 samplingRoutineCache.reset(new SamplingRoutineCache());
102
103 #ifdef ENABLE_VK_DEBUGGER
104 static auto port = getenv("VK_DEBUGGER_PORT");
105 if(port)
106 {
107 // Construct the debugger context and server - this may block for a
108 // debugger connection, allowing breakpoints to be set before they're
109 // executed.
110 debugger.context = vk::dbg::Context::create();
111 debugger.server = vk::dbg::Server::create(debugger.context, atoi(port));
112 }
113 #endif // ENABLE_VK_DEBUGGER
114 }
115
destroy(const VkAllocationCallbacks * pAllocator)116 void Device::destroy(const VkAllocationCallbacks *pAllocator)
117 {
118 for(uint32_t i = 0; i < queueCount; i++)
119 {
120 queues[i].~Queue();
121 }
122
123 vk::deallocate(queues, pAllocator);
124 }
125
ComputeRequiredAllocationSize(const VkDeviceCreateInfo * pCreateInfo)126 size_t Device::ComputeRequiredAllocationSize(const VkDeviceCreateInfo *pCreateInfo)
127 {
128 uint32_t queueCount = 0;
129 for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
130 {
131 queueCount += pCreateInfo->pQueueCreateInfos[i].queueCount;
132 }
133
134 return (sizeof(Queue) * queueCount) + (pCreateInfo->enabledExtensionCount * sizeof(ExtensionName));
135 }
136
hasExtension(const char * extensionName) const137 bool Device::hasExtension(const char *extensionName) const
138 {
139 for(uint32_t i = 0; i < enabledExtensionCount; i++)
140 {
141 if(strncmp(extensions[i], extensionName, VK_MAX_EXTENSION_NAME_SIZE) == 0)
142 {
143 return true;
144 }
145 }
146 return false;
147 }
148
getQueue(uint32_t queueFamilyIndex,uint32_t queueIndex) const149 VkQueue Device::getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const
150 {
151 ASSERT(queueFamilyIndex == 0);
152
153 return queues[queueIndex];
154 }
155
waitForFences(uint32_t fenceCount,const VkFence * pFences,VkBool32 waitAll,uint64_t timeout)156 VkResult Device::waitForFences(uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout)
157 {
158 using time_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>;
159 const time_point start = now();
160 const uint64_t max_timeout = (LLONG_MAX - start.time_since_epoch().count());
161 bool infiniteTimeout = (timeout > max_timeout);
162 const time_point end_ns = start + std::chrono::nanoseconds(std::min(max_timeout, timeout));
163
164 if(waitAll != VK_FALSE) // All fences must be signaled
165 {
166 for(uint32_t i = 0; i < fenceCount; i++)
167 {
168 if(timeout == 0)
169 {
170 if(Cast(pFences[i])->getStatus() != VK_SUCCESS) // At least one fence is not signaled
171 {
172 return VK_TIMEOUT;
173 }
174 }
175 else if(infiniteTimeout)
176 {
177 if(Cast(pFences[i])->wait() != VK_SUCCESS) // At least one fence is not signaled
178 {
179 return VK_TIMEOUT;
180 }
181 }
182 else
183 {
184 if(Cast(pFences[i])->wait(end_ns) != VK_SUCCESS) // At least one fence is not signaled
185 {
186 return VK_TIMEOUT;
187 }
188 }
189 }
190
191 return VK_SUCCESS;
192 }
193 else // At least one fence must be signaled
194 {
195 marl::containers::vector<marl::Event, 8> events;
196 for(uint32_t i = 0; i < fenceCount; i++)
197 {
198 events.push_back(Cast(pFences[i])->getEvent());
199 }
200
201 auto any = marl::Event::any(events.begin(), events.end());
202
203 if(timeout == 0)
204 {
205 return any.isSignalled() ? VK_SUCCESS : VK_TIMEOUT;
206 }
207 else if(infiniteTimeout)
208 {
209 any.wait();
210 return VK_SUCCESS;
211 }
212 else
213 {
214 return any.wait_until(end_ns) ? VK_SUCCESS : VK_TIMEOUT;
215 }
216 }
217 }
218
waitIdle()219 VkResult Device::waitIdle()
220 {
221 for(uint32_t i = 0; i < queueCount; i++)
222 {
223 queues[i].waitIdle();
224 }
225
226 return VK_SUCCESS;
227 }
228
getDescriptorSetLayoutSupport(const VkDescriptorSetLayoutCreateInfo * pCreateInfo,VkDescriptorSetLayoutSupport * pSupport) const229 void Device::getDescriptorSetLayoutSupport(const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
230 VkDescriptorSetLayoutSupport *pSupport) const
231 {
232 // From Vulkan Spec 13.2.1 Descriptor Set Layout, in description of vkGetDescriptorSetLayoutSupport:
233 // "This command does not consider other limits such as maxPerStageDescriptor*, and so a descriptor
234 // set layout that is supported according to this command must still satisfy the pipeline layout limits
235 // such as maxPerStageDescriptor* in order to be used in a pipeline layout."
236
237 // We have no "strange" limitations to enforce beyond the device limits, so we can safely always claim support.
238 pSupport->supported = VK_TRUE;
239 }
240
updateDescriptorSets(uint32_t descriptorWriteCount,const VkWriteDescriptorSet * pDescriptorWrites,uint32_t descriptorCopyCount,const VkCopyDescriptorSet * pDescriptorCopies)241 void Device::updateDescriptorSets(uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites,
242 uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies)
243 {
244 for(uint32_t i = 0; i < descriptorWriteCount; i++)
245 {
246 DescriptorSetLayout::WriteDescriptorSet(this, pDescriptorWrites[i]);
247 }
248
249 for(uint32_t i = 0; i < descriptorCopyCount; i++)
250 {
251 DescriptorSetLayout::CopyDescriptorSet(pDescriptorCopies[i]);
252 }
253 }
254
getRequirements(VkMemoryDedicatedRequirements * requirements) const255 void Device::getRequirements(VkMemoryDedicatedRequirements *requirements) const
256 {
257 requirements->prefersDedicatedAllocation = VK_FALSE;
258 requirements->requiresDedicatedAllocation = VK_FALSE;
259 }
260
getSamplingRoutineCache() const261 Device::SamplingRoutineCache *Device::getSamplingRoutineCache() const
262 {
263 return samplingRoutineCache.get();
264 }
265
findInConstCache(const SamplingRoutineCache::Key & key) const266 rr::Routine *Device::findInConstCache(const SamplingRoutineCache::Key &key) const
267 {
268 return samplingRoutineCache->queryConst(key);
269 }
270
updateSamplingRoutineConstCache()271 void Device::updateSamplingRoutineConstCache()
272 {
273 std::unique_lock<std::mutex> lock(samplingRoutineCacheMutex);
274 samplingRoutineCache->updateConstCache();
275 }
276
getSamplingRoutineCacheMutex()277 std::mutex &Device::getSamplingRoutineCacheMutex()
278 {
279 return samplingRoutineCacheMutex;
280 }
281
282 } // namespace vk
283