• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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