Add getHostPtr() to vk::Allocation
authorPyry Haulos <phaulos@google.com>
Tue, 1 Sep 2015 21:52:56 +0000 (14:52 -0700)
committerPyry Haulos <phaulos@google.com>
Wed, 2 Sep 2015 17:16:59 +0000 (10:16 -0700)
Since there can exist only one memory mapping for any VkDeviceMemory
and vkUmapMemory() unmaps all pages, current Allocator interface doesn't
extend to sub-allocators properly. To make sub-allocation work,
Allocator must be responsible of managing memory mappings.

The new behavior is to always map any host-visible allocations and
provide host pointer as part of Allocation.

Change-Id: I83a28b1387b282a373604cb112757ffdd75b20b3

external/vulkancts/framework/vulkan/vkMemUtil.cpp
external/vulkancts/framework/vulkan/vkMemUtil.hpp
external/vulkancts/modules/vulkan/api/vktApiSmokeTests.cpp

index a3038e6..1116140 100644 (file)
 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++)
@@ -61,13 +98,20 @@ deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& devic
        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)
 {
 }
 
@@ -115,16 +159,18 @@ MemoryRequirement::MemoryRequirement (deUint32 flags)
 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)
 {
 }
 
@@ -142,7 +188,14 @@ SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, co
 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)
@@ -156,7 +209,16 @@ MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memRe
                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
index 1d3f102..e2525f6 100644 (file)
 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
@@ -71,8 +96,15 @@ public:
                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);
 
index 8ff02aa..8fd1710 100644 (file)
@@ -665,7 +665,7 @@ tcu::TestStatus renderTriangleTest (Context& context)
 
        // Upload vertex data
        {
-               const VkMappedMemoryRange       range   =
+               const VkMappedMemoryRange       range                   =
                {
                        VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  //      VkStructureType sType;
                        DE_NULL,                                                                //      const void*             pNext;
@@ -673,12 +673,10 @@ tcu::TestStatus renderTriangleTest (Context& context)
                        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
@@ -695,9 +693,9 @@ tcu::TestStatus renderTriangleTest (Context& context)
                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;
@@ -705,12 +703,10 @@ tcu::TestStatus renderTriangleTest (Context& context)
                        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");