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