• 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 #ifndef VK_DEVICE_HPP_
16 #define VK_DEVICE_HPP_
17 
18 #include "VkImageView.hpp"
19 #include "VkSampler.hpp"
20 #include "Pipeline/Constants.hpp"
21 #include "Reactor/Routine.hpp"
22 #include "System/LRUCache.hpp"
23 
24 #include "marl/mutex.h"
25 #include "marl/tsa.h"
26 
27 #include <map>
28 #include <memory>
29 #include <unordered_map>
30 #include <unordered_set>
31 
32 namespace marl {
33 class Scheduler;
34 }
35 namespace sw {
36 class Blitter;
37 }
38 
39 namespace vk {
40 
41 class PhysicalDevice;
42 class Queue;
43 
44 namespace dbg {
45 class Context;
46 class Server;
47 }  // namespace dbg
48 
49 class Device
50 {
51 public:
GetAllocationScope()52 	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; }
53 
54 	Device(const VkDeviceCreateInfo *pCreateInfo, void *mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, const std::shared_ptr<marl::Scheduler> &scheduler);
55 	void destroy(const VkAllocationCallbacks *pAllocator);
56 
57 	static size_t ComputeRequiredAllocationSize(const VkDeviceCreateInfo *pCreateInfo);
58 
59 	bool hasExtension(const char *extensionName) const;
60 	VkQueue getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const;
61 	VkResult waitForFences(uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout);
62 	VkResult waitForSemaphores(const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout);
63 	VkResult waitIdle();
64 	void getDescriptorSetLayoutSupport(const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
65 	                                   VkDescriptorSetLayoutSupport *pSupport) const;
getPhysicalDevice() const66 	PhysicalDevice *getPhysicalDevice() const { return physicalDevice; }
67 	void updateDescriptorSets(uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites,
68 	                          uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies);
69 	void getRequirements(VkMemoryDedicatedRequirements *requirements) const;
getEnabledFeatures() const70 	const VkPhysicalDeviceFeatures &getEnabledFeatures() const { return enabledFeatures; }
getBlitter() const71 	sw::Blitter *getBlitter() const { return blitter.get(); }
72 
73 	void registerImageView(ImageView *imageView);
74 	void unregisterImageView(ImageView *imageView);
75 	void prepareForSampling(ImageView *imageView);
76 	void contentsChanged(ImageView *imageView, Image::ContentsChangedContext context);
77 
78 	class SamplingRoutineCache
79 	{
80 	public:
SamplingRoutineCache()81 		SamplingRoutineCache()
82 		    : cache(1024)
83 		{}
~SamplingRoutineCache()84 		~SamplingRoutineCache() {}
85 
86 		struct Key
87 		{
88 			uint32_t instruction;
89 			uint32_t sampler;
90 			uint32_t imageView;
91 
92 			inline bool operator==(const Key &rhs) const;
93 
94 			struct Hash
95 			{
96 				inline std::size_t operator()(const Key &key) const noexcept;
97 			};
98 		};
99 
100 		// getOrCreate() queries the cache for a Routine with the given key.
101 		// If one is found, it is returned, otherwise createRoutine(key) is
102 		// called, the returned Routine is added to the cache, and it is
103 		// returned.
104 		// Function must be a function of the signature:
105 		//     std::shared_ptr<rr::Routine>(const Key &)
106 		template<typename Function>
getOrCreate(const Key & key,Function && createRoutine)107 		std::shared_ptr<rr::Routine> getOrCreate(const Key &key, Function &&createRoutine)
108 		{
109 			auto it = snapshot.find(key);
110 			if(it != snapshot.end()) { return it->second; }
111 
112 			marl::lock lock(mutex);
113 			if(auto existingRoutine = cache.lookup(key))
114 			{
115 				return existingRoutine;
116 			}
117 
118 			std::shared_ptr<rr::Routine> newRoutine = createRoutine(key);
119 			cache.add(key, newRoutine);
120 			snapshotNeedsUpdate = true;
121 
122 			return newRoutine;
123 		}
124 
125 		void updateSnapshot();
126 
127 	private:
128 		bool snapshotNeedsUpdate = false;
129 		std::unordered_map<Key, std::shared_ptr<rr::Routine>, Key::Hash> snapshot;
130 
131 		marl::mutex mutex;
132 		sw::LRUCache<Key, std::shared_ptr<rr::Routine>, Key::Hash> cache GUARDED_BY(mutex);
133 	};
134 
135 	SamplingRoutineCache *getSamplingRoutineCache() const;
136 	void updateSamplingRoutineSnapshotCache();
137 
138 	class SamplerIndexer
139 	{
140 	public:
141 		~SamplerIndexer();
142 
143 		uint32_t index(const SamplerState &samplerState);
144 		void remove(const SamplerState &samplerState);
145 		const SamplerState *find(uint32_t id);
146 
147 	private:
148 		struct Identifier
149 		{
150 			uint32_t id;
151 			uint32_t count;  // Number of samplers sharing this state identifier.
152 		};
153 
154 		marl::mutex mutex;
155 		std::map<SamplerState, Identifier> map GUARDED_BY(mutex);
156 
157 		uint32_t nextID = 0;
158 	};
159 
160 	uint32_t indexSampler(const SamplerState &samplerState);
161 	void removeSampler(const SamplerState &samplerState);
162 	const SamplerState *findSampler(uint32_t samplerId) const;
163 
getDebuggerContext() const164 	std::shared_ptr<vk::dbg::Context> getDebuggerContext() const
165 	{
166 #ifdef ENABLE_VK_DEBUGGER
167 		return debugger.context;
168 #else
169 		return nullptr;
170 #endif  // ENABLE_VK_DEBUGGER
171 	}
172 
173 	VkResult setDebugUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo);
174 	VkResult setDebugUtilsObjectTag(const VkDebugUtilsObjectTagInfoEXT *pTagInfo);
175 
176 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
177 	void emitDeviceMemoryReport(VkDeviceMemoryReportEventTypeEXT type, uint64_t memoryObjectId, VkDeviceSize size, VkObjectType objectType, uint64_t objectHandle, uint32_t heapIndex = 0);
178 #endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
179 
180 	const sw::Constants constants;
181 
182 private:
183 	PhysicalDevice *const physicalDevice = nullptr;
184 	Queue *const queues = nullptr;
185 	uint32_t queueCount = 0;
186 	std::unique_ptr<sw::Blitter> blitter;
187 	uint32_t enabledExtensionCount = 0;
188 	typedef char ExtensionName[VK_MAX_EXTENSION_NAME_SIZE];
189 	ExtensionName *extensions = nullptr;
190 	const VkPhysicalDeviceFeatures enabledFeatures = {};
191 
192 	std::shared_ptr<marl::Scheduler> scheduler;
193 	std::unique_ptr<SamplingRoutineCache> samplingRoutineCache;
194 	std::unique_ptr<SamplerIndexer> samplerIndexer;
195 
196 	marl::mutex imageViewSetMutex;
197 	std::unordered_set<ImageView *> imageViewSet GUARDED_BY(imageViewSetMutex);
198 
199 #ifdef ENABLE_VK_DEBUGGER
200 	struct
201 	{
202 		std::shared_ptr<vk::dbg::Context> context;
203 		std::shared_ptr<vk::dbg::Server> server;
204 	} debugger;
205 #endif  // ENABLE_VK_DEBUGGER
206 
207 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
208 	std::vector<std::pair<PFN_vkDeviceMemoryReportCallbackEXT, void *>> deviceMemoryReportCallbacks;
209 #endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
210 };
211 
212 using DispatchableDevice = DispatchableObject<Device, VkDevice>;
213 
Cast(VkDevice object)214 static inline Device *Cast(VkDevice object)
215 {
216 	return DispatchableDevice::Cast(object);
217 }
218 
operator ==(const Key & rhs) const219 inline bool vk::Device::SamplingRoutineCache::Key::operator==(const Key &rhs) const
220 {
221 	return instruction == rhs.instruction && sampler == rhs.sampler && imageView == rhs.imageView;
222 }
223 
operator ()(const Key & key) const224 inline std::size_t vk::Device::SamplingRoutineCache::Key::Hash::operator()(const Key &key) const noexcept
225 {
226 	// Combine three 32-bit integers into a 64-bit hash.
227 	// 2642239 is the largest prime which when cubed is smaller than 2^64.
228 	uint64_t hash = key.instruction;
229 	hash = (hash * 2642239) ^ key.sampler;
230 	hash = (hash * 2642239) ^ key.imageView;
231 	return static_cast<std::size_t>(hash);  // Truncates to 32-bits on 32-bit platforms.
232 }
233 
234 }  // namespace vk
235 
236 #endif  // VK_DEVICE_HPP_
237