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
57void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
58{
59	void* hostPtr = DE_NULL;
60	VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr));
61	TCU_CHECK(hostPtr);
62	return hostPtr;
63}
64
65HostPtr::HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
66	: m_vkd		(vkd)
67	, m_device	(device)
68	, m_memory	(memory)
69	, m_ptr		(mapMemory(vkd, device, memory, offset, size, flags))
70{
71}
72
73HostPtr::~HostPtr (void)
74{
75	m_vkd.unmapMemory(m_device, m_memory);
76}
77
78deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement)
79{
80	for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
81	{
82		if ((allowedMemTypeBits & (1u << memoryTypeNdx)) != 0 &&
83			requirement.matchesHeap(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags))
84			return memoryTypeNdx;
85	}
86
87	TCU_THROW(NotSupportedError, "No compatible memory type found");
88}
89
90bool isHostVisibleMemory (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 memoryTypeNdx)
91{
92	DE_ASSERT(memoryTypeNdx < deviceMemProps.memoryTypeCount);
93	return (deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0u;
94}
95
96} // anonymous
97
98// Allocation
99
100Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
101	: m_memory	(memory)
102	, m_offset	(offset)
103	, m_hostPtr	(hostPtr)
104{
105}
106
107Allocation::~Allocation (void)
108{
109}
110
111// MemoryRequirement
112
113const MemoryRequirement MemoryRequirement::Any				= MemoryRequirement(0x0u);
114const MemoryRequirement MemoryRequirement::HostVisible		= MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE);
115const MemoryRequirement MemoryRequirement::Coherent			= MemoryRequirement(MemoryRequirement::FLAG_COHERENT);
116const MemoryRequirement MemoryRequirement::LazilyAllocated	= MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION);
117
118bool MemoryRequirement::matchesHeap (VkMemoryPropertyFlags heapFlags) const
119{
120	// sanity check
121	if ((m_flags & FLAG_COHERENT) && !(m_flags & FLAG_HOST_VISIBLE))
122		DE_FATAL("Coherent memory must be host-visible");
123	if ((m_flags & FLAG_HOST_VISIBLE) && (m_flags & FLAG_LAZY_ALLOCATION))
124		DE_FATAL("Lazily allocated memory cannot be mappable");
125
126	// host-visible
127	if ((m_flags & FLAG_HOST_VISIBLE) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
128		return false;
129
130	// coherent
131	if ((m_flags & FLAG_COHERENT) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
132		return false;
133
134	// lazy
135	if ((m_flags & FLAG_LAZY_ALLOCATION) && !(heapFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT))
136		return false;
137
138	return true;
139}
140
141MemoryRequirement::MemoryRequirement (deUint32 flags)
142	: m_flags(flags)
143{
144}
145
146// SimpleAllocator
147
148class SimpleAllocation : public Allocation
149{
150public:
151									SimpleAllocation	(Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
152	virtual							~SimpleAllocation	(void);
153
154private:
155	const Unique<VkDeviceMemory>	m_memHolder;
156	const UniquePtr<HostPtr>		m_hostPtr;
157};
158
159SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr)
160	: Allocation	(*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL)
161	, m_memHolder	(mem)
162	, m_hostPtr		(hostPtr)
163{
164}
165
166SimpleAllocation::~SimpleAllocation (void)
167{
168}
169
170SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps)
171	: m_vk		(vk)
172	, m_device	(device)
173	, m_memProps(deviceMemProps)
174{
175}
176
177MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment)
178{
179	DE_UNREF(alignment);
180
181	Move<VkDeviceMemory>	mem		= allocateMemory(m_vk, m_device, &allocInfo);
182	MovePtr<HostPtr>		hostPtr;
183
184	if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex))
185		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
186
187	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
188}
189
190MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement)
191{
192	const deUint32				memoryTypeNdx	= selectMatchingMemoryType(m_memProps, memReqs.memoryTypeBits, requirement);
193	const VkMemoryAllocateInfo	allocInfo		=
194	{
195		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	//	VkStructureType			sType;
196		DE_NULL,								//	const void*				pNext;
197		memReqs.size,							//	VkDeviceSize			allocationSize;
198		memoryTypeNdx,							//	deUint32				memoryTypeIndex;
199	};
200
201	Move<VkDeviceMemory>		mem				= allocateMemory(m_vk, m_device, &allocInfo);
202	MovePtr<HostPtr>			hostPtr;
203
204	if (requirement & MemoryRequirement::HostVisible)
205	{
206		DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex));
207		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
208	}
209
210	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
211}
212
213void flushMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
214{
215	const VkMappedMemoryRange	range	=
216	{
217		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
218		DE_NULL,
219		memory,
220		offset,
221		size
222	};
223
224	VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &range));
225}
226
227void invalidateMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
228{
229	const VkMappedMemoryRange	range	=
230	{
231		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
232		DE_NULL,
233		memory,
234		offset,
235		size
236	};
237
238	VK_CHECK(vkd.invalidateMappedMemoryRanges(device, 1u, &range));
239}
240
241} // vk
242