blob: 7a3d823f20565c17d5a43e8eb17f1513670f60f0 [file] [log] [blame]
#ifndef _VKMEMUTIL_HPP
#define _VKMEMUTIL_HPP
/*-------------------------------------------------------------------------
* Vulkan CTS Framework
* --------------------
*
* Copyright (c) 2019 Google Inc.
* Copyright (c) 2019 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Memory management utilities.
*//*--------------------------------------------------------------------*/
#include "vkDefs.hpp"
#include "deUniquePtr.hpp"
#include "deSharedPtr.hpp"
#include <vector>
namespace vk
{
/*--------------------------------------------------------------------*//*!
* \brief Memory allocation interface
*
* Allocation represents block of device memory and is allocated by
* Allocator implementation. Test code should use Allocator for allocating
* memory, unless there is a reason not to (for example testing vkAllocMemory).
*
* Allocation doesn't necessarily correspond to a whole VkDeviceMemory, but
* instead it may represent sub-allocation. Thus whenever VkDeviceMemory
* (getMemory()) managed by Allocation is passed to Vulkan API calls,
* offset given by getOffset() must be used.
*
* If host-visible memory was requested, host pointer to the memory can
* be queried with getHostPtr(). No offset is needed when accessing host
* pointer, i.e. the pointer is already adjusted in case of sub-allocation.
*
* Memory mappings are managed solely by Allocation, i.e. unmapping or
* re-mapping VkDeviceMemory owned by Allocation is not allowed.
*//*--------------------------------------------------------------------*/
class Allocation
{
public:
virtual ~Allocation(void);
//! Get VkDeviceMemory backing this allocation
VkDeviceMemory getMemory(void) const
{
return m_memory;
}
//! Get offset in VkDeviceMemory for this allocation
VkDeviceSize getOffset(void) const
{
return m_offset;
}
//! Get host pointer for this allocation. Only available for host-visible allocations
void *getHostPtr(void) const
{
DE_ASSERT(m_hostPtr);
return m_hostPtr;
}
protected:
Allocation(VkDeviceMemory memory, VkDeviceSize offset, void *hostPtr);
private:
const VkDeviceMemory m_memory;
const VkDeviceSize m_offset;
void *const m_hostPtr;
};
void flushAlloc(const DeviceInterface &vkd, VkDevice device, const Allocation &alloc);
void invalidateAlloc(const DeviceInterface &vkd, VkDevice device, const Allocation &alloc);
//! Memory allocation requirements
class MemoryRequirement
{
public:
static const MemoryRequirement Any;
static const MemoryRequirement HostVisible;
static const MemoryRequirement Coherent;
static const MemoryRequirement LazilyAllocated;
static const MemoryRequirement Protected;
static const MemoryRequirement Local;
static const MemoryRequirement Cached;
static const MemoryRequirement NonLocal;
static const MemoryRequirement DeviceAddress;
inline MemoryRequirement operator|(MemoryRequirement requirement) const
{
return MemoryRequirement(m_flags | requirement.m_flags);
}
inline MemoryRequirement operator&(MemoryRequirement requirement) const
{
return MemoryRequirement(m_flags & requirement.m_flags);
}
bool matchesHeap(VkMemoryPropertyFlags heapFlags) const;
inline operator bool(void) const
{
return m_flags != 0u;
}
private:
explicit MemoryRequirement(uint32_t flags);
const uint32_t m_flags;
enum Flags
{
FLAG_HOST_VISIBLE = 1u << 0u,
FLAG_COHERENT = 1u << 1u,
FLAG_LAZY_ALLOCATION = 1u << 2u,
FLAG_PROTECTED = 1u << 3u,
FLAG_LOCAL = 1u << 4u,
FLAG_CACHED = 1u << 5u,
FLAG_NON_LOCAL = 1u << 6u,
FLAG_DEVICE_ADDRESS = 1u << 7u,
};
};
//! Memory allocator interface
class Allocator
{
public:
Allocator(void)
{
}
virtual ~Allocator(void)
{
}
virtual de::MovePtr<Allocation> allocate(const VkMemoryAllocateInfo &allocInfo, VkDeviceSize alignment) = 0;
virtual de::MovePtr<Allocation> allocate(const VkMemoryRequirements &memRequirements,
MemoryRequirement requirement) = 0;
};
//! Allocator that backs every allocation with its own VkDeviceMemory
class SimpleAllocator : public Allocator
{
public:
SimpleAllocator(const DeviceInterface &vk, VkDevice device, const VkPhysicalDeviceMemoryProperties &deviceMemProps);
de::MovePtr<Allocation> allocate(const VkMemoryAllocateInfo &allocInfo, VkDeviceSize alignment);
de::MovePtr<Allocation> allocate(const VkMemoryRequirements &memRequirements, MemoryRequirement requirement);
private:
const DeviceInterface &m_vk;
const VkDevice m_device;
const VkPhysicalDeviceMemoryProperties m_memProps;
};
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);
de::MovePtr<Allocation> allocateDedicated(const InstanceInterface &vki, const DeviceInterface &vkd,
const VkPhysicalDevice &physDevice, const VkDevice device,
const VkBuffer buffer, MemoryRequirement requirement);
de::MovePtr<Allocation> allocateDedicated(const InstanceInterface &vki, const DeviceInterface &vkd,
const VkPhysicalDevice &physDevice, const VkDevice device,
const VkImage image, MemoryRequirement requirement);
void *mapMemory(const DeviceInterface &vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
VkMemoryMapFlags flags);
void flushMappedMemoryRange(const DeviceInterface &vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset,
VkDeviceSize size);
void invalidateMappedMemoryRange(const DeviceInterface &vkd, VkDevice device, VkDeviceMemory memory,
VkDeviceSize offset, VkDeviceSize size);
uint32_t selectMatchingMemoryType(const VkPhysicalDeviceMemoryProperties &deviceMemProps, uint32_t allowedMemTypeBits,
MemoryRequirement requirement);
uint32_t getCompatibleMemoryTypes(const VkPhysicalDeviceMemoryProperties &deviceMemProps,
MemoryRequirement requirement);
#ifdef CTS_USES_VULKANSC
uint32_t getSEUSafeMemoryTypes(const VkPhysicalDeviceMemoryProperties &deviceMemProps);
#endif // CTS_USES_VULKANSC
void bindImagePlanesMemory(const vk::DeviceInterface &vkd, const vk::VkDevice device, const vk::VkImage image,
const uint32_t numPlanes, std::vector<de::SharedPtr<Allocation>> &allocations,
vk::Allocator &allocator, const vk::MemoryRequirement requirement);
de::MovePtr<Allocation> bindImage(const DeviceInterface &vk, const VkDevice device, Allocator &allocator,
const VkImage image, const MemoryRequirement requirement);
de::MovePtr<Allocation> bindBuffer(const DeviceInterface &vk, const VkDevice device, Allocator &allocator,
const VkBuffer buffer, const MemoryRequirement requirement);
void zeroBuffer(const DeviceInterface &vk, const VkDevice device, const Allocation &alloc, const VkDeviceSize size);
} // namespace vk
#endif // _VKMEMUTIL_HPP