1 #ifndef _VKMEMUTIL_HPP
2 #define _VKMEMUTIL_HPP
3 /*-------------------------------------------------------------------------
4  * Vulkan CTS Framework
5  * --------------------
6  *
7  * Copyright (c) 2019 Google Inc.
8  * Copyright (c) 2019 The Khronos Group Inc.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Memory management utilities.
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vkDefs.hpp"
28 #include "tcuMaybe.hpp"
29 #include "deUniquePtr.hpp"
30 #include "deSharedPtr.hpp"
31 #include <vector>
32 
33 namespace vk
34 {
35 
36 /*--------------------------------------------------------------------*//*!
37  * \brief Memory allocation interface
38  *
39  * Allocation represents block of device memory and is allocated by
40  * Allocator implementation. Test code should use Allocator for allocating
41  * memory, unless there is a reason not to (for example testing vkAllocMemory).
42  *
43  * Allocation doesn't necessarily correspond to a whole VkDeviceMemory, but
44  * instead it may represent sub-allocation. Thus whenever VkDeviceMemory
45  * (getMemory()) managed by Allocation is passed to Vulkan API calls,
46  * offset given by getOffset() must be used.
47  *
48  * If host-visible memory was requested, host pointer to the memory can
49  * be queried with getHostPtr(). No offset is needed when accessing host
50  * pointer, i.e. the pointer is already adjusted in case of sub-allocation.
51  *
52  * Memory mappings are managed solely by Allocation, i.e. unmapping or
53  * re-mapping VkDeviceMemory owned by Allocation is not allowed.
54  *//*--------------------------------------------------------------------*/
55 class Allocation
56 {
57 public:
58 	virtual					~Allocation		(void);
59 
60 	//! Get VkDeviceMemory backing this allocation
getMemory(void) const61 	VkDeviceMemory			getMemory		(void) const { return m_memory;							}
62 
63 	//! Get offset in VkDeviceMemory for this allocation
getOffset(void) const64 	VkDeviceSize			getOffset		(void) const { return m_offset;							}
65 
66 	//! Get host pointer for this allocation. Only available for host-visible allocations
getHostPtr(void) const67 	void*					getHostPtr		(void) const { DE_ASSERT(m_hostPtr); return m_hostPtr;	}
68 
69 protected:
70 							Allocation		(VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr);
71 
72 private:
73 	const VkDeviceMemory	m_memory;
74 	const VkDeviceSize		m_offset;
75 	void* const				m_hostPtr;
76 };
77 
78 void	flushAlloc		(const DeviceInterface& vkd, VkDevice device, const Allocation& alloc);
79 void	invalidateAlloc	(const DeviceInterface& vkd, VkDevice device, const Allocation& alloc);
80 
81 //! Memory allocation requirements
82 class MemoryRequirement
83 {
84 public:
85 	static const MemoryRequirement	Any;
86 	static const MemoryRequirement	HostVisible;
87 	static const MemoryRequirement	Coherent;
88 	static const MemoryRequirement	LazilyAllocated;
89 	static const MemoryRequirement	Protected;
90 	static const MemoryRequirement	Local;
91 	static const MemoryRequirement	Cached;
92 	static const MemoryRequirement	NonLocal;
93 	static const MemoryRequirement	DeviceAddress;
94 	static const MemoryRequirement	DeviceAddressCaptureReplay;
95 
operator |(MemoryRequirement requirement) const96 	inline MemoryRequirement		operator|			(MemoryRequirement requirement) const
97 	{
98 		return MemoryRequirement(m_flags | requirement.m_flags);
99 	}
100 
operator &(MemoryRequirement requirement) const101 	inline MemoryRequirement		operator&			(MemoryRequirement requirement) const
102 	{
103 		return MemoryRequirement(m_flags & requirement.m_flags);
104 	}
105 
106 	bool							matchesHeap			(VkMemoryPropertyFlags heapFlags) const;
107 
operator bool(void) const108 	inline operator					bool				(void) const { return m_flags != 0u; }
109 
110 private:
111 	explicit						MemoryRequirement	(deUint32 flags);
112 
113 	const deUint32					m_flags;
114 
115 	enum Flags
116 	{
117 		FLAG_HOST_VISIBLE					= 1u << 0u,
118 		FLAG_COHERENT						= 1u << 1u,
119 		FLAG_LAZY_ALLOCATION				= 1u << 2u,
120 		FLAG_PROTECTED						= 1u << 3u,
121 		FLAG_LOCAL							= 1u << 4u,
122 		FLAG_CACHED							= 1u << 5u,
123 		FLAG_NON_LOCAL						= 1u << 6u,
124 		FLAG_DEVICE_ADDRESS					= 1u << 7u,
125 		FLAG_DEVICE_ADDRESS_CAPTURE_REPLAY	= 1u << 8u,
126 	};
127 };
128 
129 //! Memory allocator interface
130 class Allocator
131 {
132 public:
Allocator(void)133 									Allocator	(void) {}
~Allocator(void)134 	virtual							~Allocator	(void) {}
135 
136 	virtual de::MovePtr<Allocation>	allocate	(const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment) = 0;
137 	virtual de::MovePtr<Allocation>	allocate	(const VkMemoryRequirements& memRequirements, MemoryRequirement requirement) = 0;
138 };
139 
140 //! Allocator that backs every allocation with its own VkDeviceMemory
141 class SimpleAllocator : public Allocator
142 {
143 public:
144 	struct OffsetParams
145 	{
146 		const vk::VkDeviceSize nonCoherentAtomSize;
147 		const vk::VkDeviceSize offset;
148 	};
149 	typedef tcu::Maybe<OffsetParams> OptionalOffsetParams;
150 
151 											SimpleAllocator	(const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps, const OptionalOffsetParams& offsetParams = tcu::Nothing);
152 
153 	de::MovePtr<Allocation>					allocate		(const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment);
154 	de::MovePtr<Allocation>					allocate		(const VkMemoryRequirements& memRequirements, MemoryRequirement requirement);
155 
156 private:
157 	const DeviceInterface&					m_vk;
158 	const VkDevice							m_device;
159 	const VkPhysicalDeviceMemoryProperties	m_memProps;
160 	const tcu::Maybe<OffsetParams>			m_offsetParams;
161 };
162 
163 de::MovePtr<Allocation>	allocateExtended			(const InstanceInterface& vki, const DeviceInterface& vkd, const VkPhysicalDevice& physDevice, const VkDevice device, const VkMemoryRequirements& memReqs, const MemoryRequirement requirement, const void* pNext);
164 de::MovePtr<Allocation>	allocateDedicated			(const InstanceInterface& vki, const DeviceInterface& vkd, const VkPhysicalDevice& physDevice, const VkDevice device, const VkBuffer buffer, MemoryRequirement requirement);
165 de::MovePtr<Allocation>	allocateDedicated			(const InstanceInterface& vki, const DeviceInterface& vkd, const VkPhysicalDevice& physDevice, const VkDevice device, const VkImage image, MemoryRequirement requirement);
166 
167 void*					mapMemory					(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags);
168 void					flushMappedMemoryRange		(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size);
169 void					invalidateMappedMemoryRange	(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size);
170 
171 deUint32				selectMatchingMemoryType	(const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement);
172 deUint32				getCompatibleMemoryTypes	(const VkPhysicalDeviceMemoryProperties& deviceMemProps, MemoryRequirement requirement);
173 #ifdef CTS_USES_VULKANSC
174 deUint32				getSEUSafeMemoryTypes		(const VkPhysicalDeviceMemoryProperties& deviceMemProps);
175 #endif // CTS_USES_VULKANSC
176 
177 void					bindImagePlanesMemory		(const vk::DeviceInterface&					vkd,
178 													 const vk::VkDevice							device,
179 													 const vk::VkImage							image,
180 													 const deUint32								numPlanes,
181 													 std::vector<de::SharedPtr<Allocation> >&	allocations,
182 													 vk::Allocator&								allocator,
183 													 const vk::MemoryRequirement				requirement);
184 
185 de::MovePtr<Allocation>	bindImage					(const DeviceInterface&		vk,
186 													 const VkDevice				device,
187 													 Allocator&					allocator,
188 													 const VkImage				image,
189 													 const MemoryRequirement	requirement);
190 
191 de::MovePtr<Allocation>	bindBuffer					(const DeviceInterface&		vk,
192 													 const VkDevice				device,
193 													 Allocator&					allocator,
194 													 const VkBuffer				buffer,
195 													 const MemoryRequirement	requirement);
196 
197 void					zeroBuffer					(const DeviceInterface&	vk,
198 													 const VkDevice			device,
199 													 const Allocation&		alloc,
200 													 const VkDeviceSize		size);
201 
202 } // vk
203 
204 #endif // _VKMEMUTIL_HPP
205