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 
mapMemory(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory mem,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags)57 void* 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 
HostPtr(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory memory,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags)65 HostPtr::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 
~HostPtr(void)73 HostPtr::~HostPtr (void)
74 {
75 	m_vkd.unmapMemory(m_device, m_memory);
76 }
77 
selectMatchingMemoryType(const VkPhysicalDeviceMemoryProperties & deviceMemProps,deUint32 allowedMemTypeBits,MemoryRequirement requirement)78 deUint32 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 
isHostVisibleMemory(const VkPhysicalDeviceMemoryProperties & deviceMemProps,deUint32 memoryTypeNdx)90 bool 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 
Allocation(VkDeviceMemory memory,VkDeviceSize offset,void * hostPtr)100 Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
101 	: m_memory	(memory)
102 	, m_offset	(offset)
103 	, m_hostPtr	(hostPtr)
104 {
105 }
106 
~Allocation(void)107 Allocation::~Allocation (void)
108 {
109 }
110 
111 // MemoryRequirement
112 
113 const MemoryRequirement MemoryRequirement::Any				= MemoryRequirement(0x0u);
114 const MemoryRequirement MemoryRequirement::HostVisible		= MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE);
115 const MemoryRequirement MemoryRequirement::Coherent			= MemoryRequirement(MemoryRequirement::FLAG_COHERENT);
116 const MemoryRequirement MemoryRequirement::LazilyAllocated	= MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION);
117 
matchesHeap(VkMemoryPropertyFlags heapFlags) const118 bool 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 
MemoryRequirement(deUint32 flags)141 MemoryRequirement::MemoryRequirement (deUint32 flags)
142 	: m_flags(flags)
143 {
144 }
145 
146 // SimpleAllocator
147 
148 class SimpleAllocation : public Allocation
149 {
150 public:
151 									SimpleAllocation	(Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
152 	virtual							~SimpleAllocation	(void);
153 
154 private:
155 	const Unique<VkDeviceMemory>	m_memHolder;
156 	const UniquePtr<HostPtr>		m_hostPtr;
157 };
158 
SimpleAllocation(Move<VkDeviceMemory> mem,MovePtr<HostPtr> hostPtr)159 SimpleAllocation::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 
~SimpleAllocation(void)166 SimpleAllocation::~SimpleAllocation (void)
167 {
168 }
169 
SimpleAllocator(const DeviceInterface & vk,VkDevice device,const VkPhysicalDeviceMemoryProperties & deviceMemProps)170 SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps)
171 	: m_vk		(vk)
172 	, m_device	(device)
173 	, m_memProps(deviceMemProps)
174 {
175 }
176 
allocate(const VkMemoryAllocateInfo & allocInfo,VkDeviceSize alignment)177 MovePtr<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 
allocate(const VkMemoryRequirements & memReqs,MemoryRequirement requirement)190 MovePtr<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 
flushMappedMemoryRange(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory memory,VkDeviceSize offset,VkDeviceSize size)213 void 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 
invalidateMappedMemoryRange(const DeviceInterface & vkd,VkDevice device,VkDeviceMemory memory,VkDeviceSize offset,VkDeviceSize size)227 void 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