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
33namespace vk
34{
35
36using de::UniquePtr;
37using de::MovePtr;
38
39namespace
40{
41
42class HostPtr
43{
44public:
45								HostPtr		(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags);
46								~HostPtr	(void);
47
48	void*						get			(void) const { return m_ptr; }
49
50private:
51	const DeviceInterface&		m_vkd;
52	const VkDevice				m_device;
53	const VkDeviceMemory		m_memory;
54	void* const					m_ptr;
55};
56
57HostPtr::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
65HostPtr::~HostPtr (void)
66{
67	m_vkd.unmapMemory(m_device, m_memory);
68}
69
70deUint32 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
81bool 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
91Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
92	: m_memory	(memory)
93	, m_offset	(offset)
94	, m_hostPtr	(hostPtr)
95{
96}
97
98Allocation::~Allocation (void)
99{
100}
101
102// MemoryRequirement
103
104const MemoryRequirement MemoryRequirement::Any				= MemoryRequirement(0x0u);
105const MemoryRequirement MemoryRequirement::HostVisible		= MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE);
106const MemoryRequirement MemoryRequirement::Coherent			= MemoryRequirement(MemoryRequirement::FLAG_COHERENT);
107const MemoryRequirement MemoryRequirement::LazilyAllocated	= MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION);
108
109bool MemoryRequirement::matchesHeap (VkMemoryPropertyFlags heapFlags) const
110{
111	// sanity check
112	if ((m_flags & FLAG_COHERENT) && !(m_flags & FLAG_HOST_VISIBLE))
113		DE_FATAL("Coherent memory must be host-visible");
114	if ((m_flags & FLAG_HOST_VISIBLE) && (m_flags & FLAG_LAZY_ALLOCATION))
115		DE_FATAL("Lazily allocated memory cannot be mappable");
116
117	// host-visible
118	if ((m_flags & FLAG_HOST_VISIBLE) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
119		return false;
120
121	// coherent
122	if ((m_flags & FLAG_COHERENT) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
123		return false;
124
125	// lazy
126	if ((m_flags & FLAG_LAZY_ALLOCATION) && !(heapFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT))
127		return false;
128
129	return true;
130}
131
132MemoryRequirement::MemoryRequirement (deUint32 flags)
133	: m_flags(flags)
134{
135}
136
137// SimpleAllocator
138
139class SimpleAllocation : public Allocation
140{
141public:
142									SimpleAllocation	(Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
143	virtual							~SimpleAllocation	(void);
144
145private:
146	const Unique<VkDeviceMemory>	m_memHolder;
147	const UniquePtr<HostPtr>		m_hostPtr;
148};
149
150SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr)
151	: Allocation	(*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL)
152	, m_memHolder	(mem)
153	, m_hostPtr		(hostPtr)
154{
155}
156
157SimpleAllocation::~SimpleAllocation (void)
158{
159}
160
161SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps)
162	: m_vk		(vk)
163	, m_device	(device)
164	, m_memProps(deviceMemProps)
165{
166}
167
168MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment)
169{
170	DE_UNREF(alignment);
171
172	Move<VkDeviceMemory>	mem		= allocateMemory(m_vk, m_device, &allocInfo);
173	MovePtr<HostPtr>		hostPtr;
174
175	if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex))
176		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
177
178	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
179}
180
181MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement)
182{
183	const deUint32				memoryTypeNdx	= selectMatchingMemoryType(m_memProps, memReqs.memoryTypeBits, requirement);
184	const VkMemoryAllocateInfo	allocInfo		=
185	{
186		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	//	VkStructureType			sType;
187		DE_NULL,								//	const void*				pNext;
188		memReqs.size,							//	VkDeviceSize			allocationSize;
189		memoryTypeNdx,							//	deUint32				memoryTypeIndex;
190	};
191
192	Move<VkDeviceMemory>		mem				= allocateMemory(m_vk, m_device, &allocInfo);
193	MovePtr<HostPtr>			hostPtr;
194
195	if (requirement & MemoryRequirement::HostVisible)
196	{
197		DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex));
198		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
199	}
200
201	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
202}
203
204static MovePtr<Allocation> allocateDedicated (const InstanceInterface&		vki,
205											  const DeviceInterface&		vkd,
206											  const VkPhysicalDevice&		physDevice,
207											  const VkDevice				device,
208											  const VkMemoryRequirements&	memReqs,
209											  const MemoryRequirement		requirement,
210											  const void*					pNext)
211{
212	const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vki, physDevice);
213	const deUint32							memoryTypeNdx		= selectMatchingMemoryType(memoryProperties, memReqs.memoryTypeBits, requirement);
214	const VkMemoryAllocateInfo				allocInfo			=
215	{
216		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	//	VkStructureType	sType
217		pNext,									//	const void*		pNext
218		memReqs.size,							//	VkDeviceSize	allocationSize
219		memoryTypeNdx,							//	deUint32		memoryTypeIndex
220	};
221	Move<VkDeviceMemory>					mem					= allocateMemory(vkd, device, &allocInfo);
222	MovePtr<HostPtr>						hostPtr;
223
224	if (requirement & MemoryRequirement::HostVisible)
225	{
226		DE_ASSERT(isHostVisibleMemory(memoryProperties, allocInfo.memoryTypeIndex));
227		hostPtr = MovePtr<HostPtr>(new HostPtr(vkd, device, *mem, 0u, allocInfo.allocationSize, 0u));
228	}
229
230	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
231}
232
233de::MovePtr<Allocation> allocateDedicated (const InstanceInterface&	vki,
234										   const DeviceInterface&	vkd,
235										   const VkPhysicalDevice&	physDevice,
236										   const VkDevice			device,
237										   const VkBuffer			buffer,
238										   MemoryRequirement		requirement)
239{
240	const VkMemoryRequirements					memoryRequirements		= getBufferMemoryRequirements(vkd, device, buffer);
241	const VkMemoryDedicatedAllocateInfoKHR		dedicatedAllocationInfo	=
242	{
243		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,				// VkStructureType		sType
244		DE_NULL,															// const void*			pNext
245		DE_NULL,															// VkImage				image
246		buffer																// VkBuffer				buffer
247	};
248
249	return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo);
250}
251
252de::MovePtr<Allocation> allocateDedicated (const InstanceInterface&	vki,
253										   const DeviceInterface&	vkd,
254										   const VkPhysicalDevice&	physDevice,
255										   const VkDevice			device,
256										   const VkImage			image,
257										   MemoryRequirement		requirement)
258{
259	const VkMemoryRequirements				memoryRequirements		= getImageMemoryRequirements(vkd, device, image);
260	const VkMemoryDedicatedAllocateInfoKHR	dedicatedAllocationInfo	=
261	{
262		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,			// VkStructureType		sType
263		DE_NULL,														// const void*			pNext
264		image,															// VkImage				image
265		DE_NULL															// VkBuffer				buffer
266	};
267
268	return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo);
269}
270
271void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
272{
273	void* hostPtr = DE_NULL;
274	VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr));
275	TCU_CHECK(hostPtr);
276	return hostPtr;
277}
278
279void flushMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
280{
281	const VkMappedMemoryRange	range	=
282	{
283		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
284		DE_NULL,
285		memory,
286		offset,
287		size
288	};
289
290	VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &range));
291}
292
293void invalidateMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
294{
295	const VkMappedMemoryRange	range	=
296	{
297		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
298		DE_NULL,
299		memory,
300		offset,
301		size
302	};
303
304	VK_CHECK(vkd.invalidateMappedMemoryRanges(device, 1u, &range));
305}
306
307deUint32 getCompatibleMemoryTypes (const VkPhysicalDeviceMemoryProperties& deviceMemProps, MemoryRequirement requirement)
308{
309	deUint32	compatibleTypes	= 0u;
310
311	for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
312	{
313		if (requirement.matchesHeap(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags))
314			compatibleTypes |= (1u << memoryTypeNdx);
315	}
316
317	return compatibleTypes;
318}
319
320void bindImagePlaneMemory (const DeviceInterface&	vkd,
321						   VkDevice					device,
322						   VkImage					image,
323						   VkDeviceMemory			memory,
324						   VkDeviceSize				memoryOffset,
325						   VkImageAspectFlagBits	planeAspect)
326{
327	const VkBindImagePlaneMemoryInfoKHR	planeInfo	=
328	{
329		VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR,
330		DE_NULL,
331		planeAspect
332	};
333	const VkBindImageMemoryInfoKHR		coreInfo	=
334	{
335		VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR,
336		&planeInfo,
337		image,
338		memory,
339		memoryOffset,
340	};
341
342	VK_CHECK(vkd.bindImageMemory2KHR(device, 1u, &coreInfo));
343}
344
345} // vk
346