1 /*-------------------------------------------------------------------------
2 * Vulkan CTS Framework
3 * --------------------
4 *
5 * Copyright (c) 2015 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Memory management utilities.
22 *//*--------------------------------------------------------------------*/
23
24 #include "vkMemUtil.hpp"
25 #include "vkStrUtil.hpp"
26 #include "vkQueryUtil.hpp"
27 #include "vkRef.hpp"
28 #include "vkRefUtil.hpp"
29 #include "deInt32.h"
30
31 #include <sstream>
32
33 namespace vk
34 {
35
36 using de::UniquePtr;
37 using de::MovePtr;
38
39 namespace
40 {
41
42 class HostPtr
43 {
44 public:
45 HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags);
46 ~HostPtr (void);
47
get(void) const48 void* get (void) const { return m_ptr; }
49
50 private:
51 const DeviceInterface& m_vkd;
52 const VkDevice m_device;
53 const VkDeviceMemory m_memory;
54 void* const m_ptr;
55 };
56
HostPtr(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory memory,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags)57 HostPtr::HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
58 : m_vkd (vkd)
59 , m_device (device)
60 , m_memory (memory)
61 , m_ptr (mapMemory(vkd, device, memory, offset, size, flags))
62 {
63 }
64
~HostPtr(void)65 HostPtr::~HostPtr (void)
66 {
67 m_vkd.unmapMemory(m_device, m_memory);
68 }
69
selectMatchingMemoryType(const VkPhysicalDeviceMemoryProperties & deviceMemProps,deUint32 allowedMemTypeBits,MemoryRequirement requirement)70 deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement)
71 {
72 const deUint32 compatibleTypes = getCompatibleMemoryTypes(deviceMemProps, requirement);
73 const deUint32 candidates = allowedMemTypeBits & compatibleTypes;
74
75 if (candidates == 0)
76 TCU_THROW(NotSupportedError, "No compatible memory type found");
77
78 return (deUint32)deCtz32(candidates);
79 }
80
isHostVisibleMemory(const VkPhysicalDeviceMemoryProperties & deviceMemProps,deUint32 memoryTypeNdx)81 bool isHostVisibleMemory (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 memoryTypeNdx)
82 {
83 DE_ASSERT(memoryTypeNdx < deviceMemProps.memoryTypeCount);
84 return (deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0u;
85 }
86
87 } // anonymous
88
89 // Allocation
90
Allocation(VkDeviceMemory memory,VkDeviceSize offset,void * hostPtr)91 Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
92 : m_memory (memory)
93 , m_offset (offset)
94 , m_hostPtr (hostPtr)
95 {
96 }
97
~Allocation(void)98 Allocation::~Allocation (void)
99 {
100 }
101
flushAlloc(const DeviceInterface & vkd,VkDevice device,const Allocation & alloc)102 void flushAlloc (const DeviceInterface& vkd, VkDevice device, const Allocation& alloc)
103 {
104 flushMappedMemoryRange(vkd, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
105 }
106
invalidateAlloc(const DeviceInterface & vkd,VkDevice device,const Allocation & alloc)107 void invalidateAlloc (const DeviceInterface& vkd, VkDevice device, const Allocation& alloc)
108 {
109 invalidateMappedMemoryRange(vkd, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
110 }
111
112 // MemoryRequirement
113
114 const MemoryRequirement MemoryRequirement::Any = MemoryRequirement(0x0u);
115 const MemoryRequirement MemoryRequirement::HostVisible = MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE);
116 const MemoryRequirement MemoryRequirement::Coherent = MemoryRequirement(MemoryRequirement::FLAG_COHERENT);
117 const MemoryRequirement MemoryRequirement::LazilyAllocated = MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION);
118 const MemoryRequirement MemoryRequirement::Protected = MemoryRequirement(MemoryRequirement::FLAG_PROTECTED);
119 const MemoryRequirement MemoryRequirement::Local = MemoryRequirement(MemoryRequirement::FLAG_LOCAL);
120 const MemoryRequirement MemoryRequirement::Cached = MemoryRequirement(MemoryRequirement::FLAG_CACHED);
121 const MemoryRequirement MemoryRequirement::NonLocal = MemoryRequirement(MemoryRequirement::FLAG_NON_LOCAL);
122
matchesHeap(VkMemoryPropertyFlags heapFlags) const123 bool MemoryRequirement::matchesHeap (VkMemoryPropertyFlags heapFlags) const
124 {
125 // sanity check
126 if ((m_flags & FLAG_COHERENT) && !(m_flags & FLAG_HOST_VISIBLE))
127 DE_FATAL("Coherent memory must be host-visible");
128 if ((m_flags & FLAG_HOST_VISIBLE) && (m_flags & FLAG_LAZY_ALLOCATION))
129 DE_FATAL("Lazily allocated memory cannot be mappable");
130 if ((m_flags & FLAG_PROTECTED) && (m_flags & FLAG_HOST_VISIBLE))
131 DE_FATAL("Protected memory cannot be mappable");
132
133 // host-visible
134 if ((m_flags & FLAG_HOST_VISIBLE) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
135 return false;
136
137 // coherent
138 if ((m_flags & FLAG_COHERENT) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
139 return false;
140
141 // lazy
142 if ((m_flags & FLAG_LAZY_ALLOCATION) && !(heapFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT))
143 return false;
144
145 // protected
146 if ((m_flags & FLAG_PROTECTED) && !(heapFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT))
147 return false;
148
149 // local
150 if ((m_flags & FLAG_LOCAL) && !(heapFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
151 return false;
152
153 // cached
154 if ((m_flags & FLAG_CACHED) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT))
155 return false;
156
157 // non-local
158 if ((m_flags & FLAG_NON_LOCAL) && (heapFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
159 return false;
160
161 return true;
162 }
163
MemoryRequirement(deUint32 flags)164 MemoryRequirement::MemoryRequirement (deUint32 flags)
165 : m_flags(flags)
166 {
167 }
168
169 // SimpleAllocator
170
171 class SimpleAllocation : public Allocation
172 {
173 public:
174 SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
175 virtual ~SimpleAllocation (void);
176
177 private:
178 const Unique<VkDeviceMemory> m_memHolder;
179 const UniquePtr<HostPtr> m_hostPtr;
180 };
181
SimpleAllocation(Move<VkDeviceMemory> mem,MovePtr<HostPtr> hostPtr)182 SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr)
183 : Allocation (*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL)
184 , m_memHolder (mem)
185 , m_hostPtr (hostPtr)
186 {
187 }
188
~SimpleAllocation(void)189 SimpleAllocation::~SimpleAllocation (void)
190 {
191 }
192
SimpleAllocator(const DeviceInterface & vk,VkDevice device,const VkPhysicalDeviceMemoryProperties & deviceMemProps)193 SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps)
194 : m_vk (vk)
195 , m_device (device)
196 , m_memProps(deviceMemProps)
197 {
198 }
199
allocate(const VkMemoryAllocateInfo & allocInfo,VkDeviceSize alignment)200 MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment)
201 {
202 DE_UNREF(alignment);
203
204 Move<VkDeviceMemory> mem = allocateMemory(m_vk, m_device, &allocInfo);
205 MovePtr<HostPtr> hostPtr;
206
207 if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex))
208 hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
209
210 return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
211 }
212
allocate(const VkMemoryRequirements & memReqs,MemoryRequirement requirement)213 MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement)
214 {
215 const deUint32 memoryTypeNdx = selectMatchingMemoryType(m_memProps, memReqs.memoryTypeBits, requirement);
216 const VkMemoryAllocateInfo allocInfo =
217 {
218 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType;
219 DE_NULL, // const void* pNext;
220 memReqs.size, // VkDeviceSize allocationSize;
221 memoryTypeNdx, // deUint32 memoryTypeIndex;
222 };
223
224 Move<VkDeviceMemory> mem = allocateMemory(m_vk, m_device, &allocInfo);
225 MovePtr<HostPtr> hostPtr;
226
227 if (requirement & MemoryRequirement::HostVisible)
228 {
229 DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex));
230 hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
231 }
232
233 return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
234 }
235
allocateDedicated(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkMemoryRequirements & memReqs,const MemoryRequirement requirement,const void * pNext)236 static MovePtr<Allocation> allocateDedicated (const InstanceInterface& vki,
237 const DeviceInterface& vkd,
238 const VkPhysicalDevice& physDevice,
239 const VkDevice device,
240 const VkMemoryRequirements& memReqs,
241 const MemoryRequirement requirement,
242 const void* pNext)
243 {
244 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice);
245 const deUint32 memoryTypeNdx = selectMatchingMemoryType(memoryProperties, memReqs.memoryTypeBits, requirement);
246 const VkMemoryAllocateInfo allocInfo =
247 {
248 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
249 pNext, // const void* pNext
250 memReqs.size, // VkDeviceSize allocationSize
251 memoryTypeNdx, // deUint32 memoryTypeIndex
252 };
253 Move<VkDeviceMemory> mem = allocateMemory(vkd, device, &allocInfo);
254 MovePtr<HostPtr> hostPtr;
255
256 if (requirement & MemoryRequirement::HostVisible)
257 {
258 DE_ASSERT(isHostVisibleMemory(memoryProperties, allocInfo.memoryTypeIndex));
259 hostPtr = MovePtr<HostPtr>(new HostPtr(vkd, device, *mem, 0u, allocInfo.allocationSize, 0u));
260 }
261
262 return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
263 }
264
allocateDedicated(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkBuffer buffer,MemoryRequirement requirement)265 de::MovePtr<Allocation> allocateDedicated (const InstanceInterface& vki,
266 const DeviceInterface& vkd,
267 const VkPhysicalDevice& physDevice,
268 const VkDevice device,
269 const VkBuffer buffer,
270 MemoryRequirement requirement)
271 {
272 const VkMemoryRequirements memoryRequirements = getBufferMemoryRequirements(vkd, device, buffer);
273 const VkMemoryDedicatedAllocateInfo dedicatedAllocationInfo =
274 {
275 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, // VkStructureType sType
276 DE_NULL, // const void* pNext
277 DE_NULL, // VkImage image
278 buffer // VkBuffer buffer
279 };
280
281 return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo);
282 }
283
allocateDedicated(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkImage image,MemoryRequirement requirement)284 de::MovePtr<Allocation> allocateDedicated (const InstanceInterface& vki,
285 const DeviceInterface& vkd,
286 const VkPhysicalDevice& physDevice,
287 const VkDevice device,
288 const VkImage image,
289 MemoryRequirement requirement)
290 {
291 const VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vkd, device, image);
292 const VkMemoryDedicatedAllocateInfo dedicatedAllocationInfo =
293 {
294 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, // VkStructureType sType
295 DE_NULL, // const void* pNext
296 image, // VkImage image
297 DE_NULL // VkBuffer buffer
298 };
299
300 return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo);
301 }
302
mapMemory(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory mem,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags)303 void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
304 {
305 void* hostPtr = DE_NULL;
306 VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr));
307 TCU_CHECK(hostPtr);
308 return hostPtr;
309 }
310
flushMappedMemoryRange(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory memory,VkDeviceSize offset,VkDeviceSize size)311 void flushMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
312 {
313 const VkMappedMemoryRange range =
314 {
315 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
316 DE_NULL,
317 memory,
318 offset,
319 size
320 };
321
322 VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &range));
323 }
324
invalidateMappedMemoryRange(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory memory,VkDeviceSize offset,VkDeviceSize size)325 void invalidateMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
326 {
327 const VkMappedMemoryRange range =
328 {
329 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
330 DE_NULL,
331 memory,
332 offset,
333 size
334 };
335
336 VK_CHECK(vkd.invalidateMappedMemoryRanges(device, 1u, &range));
337 }
338
getCompatibleMemoryTypes(const VkPhysicalDeviceMemoryProperties & deviceMemProps,MemoryRequirement requirement)339 deUint32 getCompatibleMemoryTypes (const VkPhysicalDeviceMemoryProperties& deviceMemProps, MemoryRequirement requirement)
340 {
341 deUint32 compatibleTypes = 0u;
342
343 for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
344 {
345 if (requirement.matchesHeap(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags))
346 compatibleTypes |= (1u << memoryTypeNdx);
347 }
348
349 return compatibleTypes;
350 }
351
bindImagePlaneMemory(const DeviceInterface & vkd,VkDevice device,VkImage image,VkDeviceMemory memory,VkDeviceSize memoryOffset,VkImageAspectFlagBits planeAspect)352 void bindImagePlaneMemory (const DeviceInterface& vkd,
353 VkDevice device,
354 VkImage image,
355 VkDeviceMemory memory,
356 VkDeviceSize memoryOffset,
357 VkImageAspectFlagBits planeAspect)
358 {
359 const VkBindImagePlaneMemoryInfo planeInfo =
360 {
361 VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR,
362 DE_NULL,
363 planeAspect
364 };
365 const VkBindImageMemoryInfo coreInfo =
366 {
367 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR,
368 &planeInfo,
369 image,
370 memory,
371 memoryOffset,
372 };
373
374 VK_CHECK(vkd.bindImageMemory2(device, 1u, &coreInfo));
375 }
376
377 } // vk
378