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 "VkDeviceMemory.hpp" |
16 | |
17 | #include "VkConfig.h" |
18 | |
19 | namespace vk |
20 | { |
21 | |
22 | // Base abstract interface for a device memory implementation. |
23 | class DeviceMemory::ExternalBase |
24 | { |
25 | public: |
26 | virtual ~ExternalBase() = default; |
27 | |
28 | // Allocate the memory according to |size|. On success return VK_SUCCESS |
29 | // and sets |*pBuffer|. |
30 | virtual VkResult allocate(size_t size, void** pBuffer) = 0; |
31 | |
32 | // Deallocate previously allocated memory at |buffer|. |
33 | virtual void deallocate(void* buffer, size_t size) = 0; |
34 | |
35 | // Return the handle type flag bit supported by this implementation. |
36 | // A value of 0 corresponds to non-external memory. |
37 | virtual VkExternalMemoryHandleTypeFlagBits getFlagBit() const = 0; |
38 | |
39 | #if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD |
40 | virtual VkResult exportFd(int* pFd) const |
41 | { |
42 | return VK_ERROR_INVALID_EXTERNAL_HANDLE; |
43 | } |
44 | #endif |
45 | |
46 | protected: |
47 | ExternalBase() = default; |
48 | }; |
49 | |
50 | // Small class describing a given DeviceMemory::ExternalBase derived class. |
51 | // |typeFlagBit| corresponds to the external memory handle type. |
52 | // |instanceSize| is the size of each class instance in bytes. |
53 | // |instanceInit| is a function pointer used to initialize an instance inplace |
54 | // according to a |pAllocateInfo| parameter. |
55 | class ExternalMemoryTraits |
56 | { |
57 | public: |
58 | VkExternalMemoryHandleTypeFlagBits typeFlagBit; |
59 | size_t instanceSize; |
60 | void (*instanceInit)(void* external, const VkMemoryAllocateInfo* pAllocateInfo); |
61 | }; |
62 | |
63 | // Template function that parses a |pAllocateInfo.pNext| chain to verify that |
64 | // it asks for the creation or import of a memory type managed by implementation |
65 | // class T. On success, return true and sets |pTraits| accordingly. Otherwise |
66 | // return false. |
67 | template <typename T> |
68 | static bool parseCreateInfo(const VkMemoryAllocateInfo* pAllocateInfo, |
69 | ExternalMemoryTraits* pTraits) |
70 | { |
71 | if (T::supportsAllocateInfo(pAllocateInfo)) |
72 | { |
73 | pTraits->typeFlagBit = T::typeFlagBit; |
74 | pTraits->instanceSize = sizeof(T); |
75 | pTraits->instanceInit = [](void* external, |
76 | const VkMemoryAllocateInfo* pAllocateInfo) { |
77 | new (external) T(pAllocateInfo); |
78 | }; |
79 | return true; |
80 | } |
81 | return false; |
82 | } |
83 | |
84 | // DeviceMemory::ExternalBase implementation that uses host memory. |
85 | // Not really external, but makes everything simpler. |
86 | class DeviceMemoryHostExternalBase : public DeviceMemory::ExternalBase |
87 | { |
88 | public: |
89 | |
90 | // Does not support any external memory type at all. |
91 | static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0; |
92 | |
93 | // Always return true as is used as a fallback in findTraits() below. |
94 | static bool supportsAllocateInfo(const VkMemoryAllocateInfo* pAllocateInfo) |
95 | { |
96 | return true; |
97 | } |
98 | |
99 | DeviceMemoryHostExternalBase(const VkMemoryAllocateInfo* pAllocateInfo) {} |
100 | |
101 | VkResult allocate(size_t size, void** pBuffer) override |
102 | { |
103 | void* buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY); |
104 | if (!buffer) |
105 | return VK_ERROR_OUT_OF_DEVICE_MEMORY; |
106 | |
107 | *pBuffer = buffer; |
108 | return VK_SUCCESS; |
109 | } |
110 | |
111 | void deallocate(void* buffer, size_t size) override |
112 | { |
113 | vk::deallocate(buffer, DEVICE_MEMORY); |
114 | } |
115 | |
116 | VkExternalMemoryHandleTypeFlagBits getFlagBit() const override |
117 | { |
118 | return typeFlagBit; |
119 | } |
120 | }; |
121 | |
122 | } // namespace vk |
123 | |
124 | #if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD |
125 | #include "VkDeviceMemoryExternalLinux.hpp" |
126 | #endif |
127 | |
128 | namespace vk |
129 | { |
130 | |
131 | static void findTraits(const VkMemoryAllocateInfo* pAllocateInfo, |
132 | ExternalMemoryTraits* pTraits) |
133 | { |
134 | #if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD |
135 | if (parseCreateInfo<LinuxMemfdExternalMemory>(pAllocateInfo, pTraits)) |
136 | { |
137 | return; |
138 | } |
139 | #endif |
140 | parseCreateInfo<DeviceMemoryHostExternalBase>(pAllocateInfo, pTraits); |
141 | } |
142 | |
143 | DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo* pAllocateInfo, void* mem) : |
144 | size(pAllocateInfo->allocationSize), memoryTypeIndex(pAllocateInfo->memoryTypeIndex), |
145 | external(reinterpret_cast<ExternalBase *>(mem)) |
146 | { |
147 | ASSERT(size); |
148 | |
149 | ExternalMemoryTraits traits; |
150 | findTraits(pAllocateInfo, &traits); |
151 | traits.instanceInit(external, pAllocateInfo); |
152 | } |
153 | |
154 | void DeviceMemory::destroy(const VkAllocationCallbacks* pAllocator) |
155 | { |
156 | if (buffer) |
157 | { |
158 | external->deallocate(buffer, size); |
159 | buffer = nullptr; |
160 | } |
161 | external->~ExternalBase(); // Call virtual destructor in place. |
162 | vk::deallocate(external, pAllocator); |
163 | } |
164 | |
165 | size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo* pAllocateInfo) |
166 | { |
167 | ExternalMemoryTraits traits; |
168 | findTraits(pAllocateInfo, &traits); |
169 | return traits.instanceSize; |
170 | } |
171 | |
172 | VkResult DeviceMemory::allocate() |
173 | { |
174 | VkResult result = VK_SUCCESS; |
175 | if (!buffer) |
176 | { |
177 | result = external->allocate(size, &buffer); |
178 | } |
179 | return result; |
180 | } |
181 | |
182 | VkResult DeviceMemory::map(VkDeviceSize pOffset, VkDeviceSize pSize, void** ppData) |
183 | { |
184 | *ppData = getOffsetPointer(pOffset); |
185 | |
186 | return VK_SUCCESS; |
187 | } |
188 | |
189 | VkDeviceSize DeviceMemory::getCommittedMemoryInBytes() const |
190 | { |
191 | return size; |
192 | } |
193 | |
194 | void* DeviceMemory::getOffsetPointer(VkDeviceSize pOffset) const |
195 | { |
196 | ASSERT(buffer); |
197 | |
198 | return reinterpret_cast<char*>(buffer) + pOffset; |
199 | } |
200 | |
201 | bool DeviceMemory::checkExternalMemoryHandleType( |
202 | VkExternalMemoryHandleTypeFlags supportedHandleTypes) const |
203 | { |
204 | if (!supportedHandleTypes) |
205 | { |
206 | // This image or buffer does not need to be stored on external |
207 | // memory, so this check should always pass. |
208 | return true; |
209 | } |
210 | VkExternalMemoryHandleTypeFlagBits handle_type_bit = external->getFlagBit(); |
211 | if (!handle_type_bit) |
212 | { |
213 | // This device memory is not external and can accomodate |
214 | // any image or buffer as well. |
215 | return true; |
216 | } |
217 | // Return true only if the external memory type is compatible with the |
218 | // one specified during VkCreate{Image,Buffer}(), through a |
219 | // VkExternalMemory{Image,Buffer}AllocateInfo struct. |
220 | return (supportedHandleTypes & handle_type_bit) != 0; |
221 | } |
222 | |
223 | #if SWIFTSHADER_EXTERNAL_MEMORY_LINUX_MEMFD |
224 | VkResult DeviceMemory::exportFd(int* pFd) const |
225 | { |
226 | return external->exportFd(pFd); |
227 | } |
228 | #endif |
229 | |
230 | } // namespace vk |
231 | |