namespace vk
{
+using de::UniquePtr;
using de::MovePtr;
namespace
{
+class HostPtr
+{
+public:
+ HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags);
+ ~HostPtr (void);
+
+ void* get (void) const { return m_ptr; }
+
+private:
+ const DeviceInterface& m_vkd;
+ const VkDevice m_device;
+ const VkDeviceMemory m_memory;
+ void* const m_ptr;
+};
+
+void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
+{
+ void* hostPtr = DE_NULL;
+ VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr));
+ TCU_CHECK(hostPtr);
+ return hostPtr;
+}
+
+HostPtr::HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
+ : m_vkd (vkd)
+ , m_device (device)
+ , m_memory (memory)
+ , m_ptr (mapMemory(vkd, device, memory, offset, size, flags))
+{
+}
+
+HostPtr::~HostPtr (void)
+{
+ m_vkd.unmapMemory(m_device, m_memory);
+}
+
deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement)
{
for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
TCU_THROW(NotSupportedError, "No compatible memory type found");
}
+bool isHostVisibleMemory (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 memoryTypeNdx)
+{
+ DE_ASSERT(memoryTypeNdx < deviceMemProps.memoryTypeCount);
+ return (deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0u;
+}
+
} // anonymous
// Allocation
-Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset)
+Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
: m_memory (memory)
, m_offset (offset)
+ , m_hostPtr (hostPtr)
{
}
class SimpleAllocation : public Allocation
{
public:
- SimpleAllocation (Move<VkDeviceMemory> mem);
+ SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
virtual ~SimpleAllocation (void);
private:
const Unique<VkDeviceMemory> m_memHolder;
+ const UniquePtr<HostPtr> m_hostPtr;
};
-SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem)
- : Allocation (*mem, (VkDeviceSize)0)
+SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr)
+ : Allocation (*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL)
, m_memHolder (mem)
+ , m_hostPtr (hostPtr)
{
}
MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocInfo& allocInfo, VkDeviceSize alignment)
{
DE_UNREF(alignment);
- return MovePtr<Allocation>(new SimpleAllocation(allocMemory(m_vk, m_device, &allocInfo)));
+
+ Move<VkDeviceMemory> mem = allocMemory(m_vk, m_device, &allocInfo);
+ MovePtr<HostPtr> hostPtr;
+
+ if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex))
+ hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
+
+ return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
}
MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement)
memoryTypeNdx, // deUint32 memoryTypeIndex;
};
- return allocate(allocInfo, memReqs.alignment);
+ Move<VkDeviceMemory> mem = allocMemory(m_vk, m_device, &allocInfo);
+ MovePtr<HostPtr> hostPtr;
+
+ if (requirement & MemoryRequirement::HostVisible)
+ {
+ DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex));
+ hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
+ }
+
+ return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
}
} // vk
namespace vk
{
-//! Memory allocation interface
+/*--------------------------------------------------------------------*//*!
+ * \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);
- VkDeviceMemory getMemory (void) const { return m_memory; }
- VkDeviceSize getOffset (void) const { return m_offset; }
+ //! 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);
+ Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr);
private:
const VkDeviceMemory m_memory;
const VkDeviceSize m_offset;
+ void* const m_hostPtr;
};
//! Memory allocation requirements
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 (deUint32 flags);
// Upload vertex data
{
- const VkMappedMemoryRange range =
+ const VkMappedMemoryRange range =
{
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // VkDeviceSize offset;
(VkDeviceSize)sizeof(vertices), // VkDeviceSize size;
};
- void* vertexBufPtr = DE_NULL;
+ void* vertexBufPtr = vertexBufferMemory->getHostPtr();
- VK_CHECK(vk.mapMemory(vkDevice, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset(), (VkDeviceSize)sizeof(vertices), 0u, &vertexBufPtr));
deMemcpy(vertexBufPtr, &vertices[0], sizeof(vertices));
VK_CHECK(vk.flushMappedMemoryRanges(vkDevice, 1u, &range));
- VK_CHECK(vk.unmapMemory(vkDevice, vertexBufferMemory->getMemory()));
}
// Submit & wait for completion
VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), DE_TRUE, ~0ull));
}
- // Map & log image
+ // Log image
{
- const VkMappedMemoryRange range =
+ const VkMappedMemoryRange range =
{
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // VkDeviceSize offset;
imageSizeBytes, // VkDeviceSize size;
};
- void* imagePtr = DE_NULL;
+ void* imagePtr = readImageBufferMemory->getHostPtr();
- VK_CHECK(vk.mapMemory(vkDevice, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset(), imageSizeBytes, 0u, &imagePtr));
VK_CHECK(vk.invalidateMappedMemoryRanges(vkDevice, 1u, &range));
context.getTestContext().getLog() << TestLog::Image("Result", "Result", tcu::ConstPixelBufferAccess(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), renderSize.x(), renderSize.y(), 1, imagePtr));
- VK_CHECK(vk.unmapMemory(vkDevice, readImageBufferMemory->getMemory()));
}
return tcu::TestStatus::pass("Rendering succeeded");