Edit

kc3-lang/angle/src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-09-02 22:41:40
    Hash : 458389f2
    Message : Vulkan: Support Linux dma-bufs This change adds support for EGL_EXT_image_dma_buf_import and EGL_EXT_image_dma_buf_import_modifiers on top of Vulkan's VK_EXT_external_memory_dma_buf and VK_EXT_image_drm_format_modifier. Bug: angleproject:6248 Change-Id: I581987f88e9ddcf351dc721f499f63912dca05f9 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3145610 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp
  • // Copyright 2019 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // MemoryObjectVk.cpp: Defines the class interface for MemoryObjectVk, implementing
    // MemoryObjectImpl.
    
    #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
    
    #include "common/debug.h"
    #include "common/vulkan/vk_headers.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/renderer/vulkan/ContextVk.h"
    #include "libANGLE/renderer/vulkan/RendererVk.h"
    #include "vulkan/vulkan_fuchsia_ext.h"
    
    #if !defined(ANGLE_PLATFORM_WINDOWS)
    #    include <unistd.h>
    #else
    #    include <io.h>
    #endif
    
    #if defined(ANGLE_PLATFORM_FUCHSIA)
    #    include <zircon/status.h>
    #    include <zircon/syscalls.h>
    #endif
    
    namespace rx
    {
    
    namespace
    {
    
    #if defined(ANGLE_PLATFORM_WINDOWS)
    int close(int fd)
    {
        return _close(fd);
    }
    #endif
    
    void CloseZirconVmo(zx_handle_t handle)
    {
    #if defined(ANGLE_PLATFORM_FUCHSIA)
        zx_handle_close(handle);
    #else
        UNREACHABLE();
    #endif
    }
    
    angle::Result DuplicateZirconVmo(ContextVk *contextVk, zx_handle_t handle, zx_handle_t *duplicate)
    {
    #if defined(ANGLE_PLATFORM_FUCHSIA)
        zx_status_t status = zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, duplicate);
        ANGLE_VK_CHECK(contextVk, status == ZX_OK, VK_ERROR_INVALID_EXTERNAL_HANDLE);
        return angle::Result::Continue;
    #else
        UNREACHABLE();
        return angle::Result::Stop;
    #endif
    }
    
    VkExternalMemoryHandleTypeFlagBits ToVulkanHandleType(gl::HandleType handleType)
    {
        switch (handleType)
        {
            case gl::HandleType::OpaqueFd:
                return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
            case gl::HandleType::ZirconVmo:
                return VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
            default:
                // Not a memory handle type.
                UNREACHABLE();
                return VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
        }
    }
    
    }  // namespace
    
    MemoryObjectVk::MemoryObjectVk() {}
    
    MemoryObjectVk::~MemoryObjectVk() = default;
    
    void MemoryObjectVk::onDestroy(const gl::Context *context)
    {
        if (mFd != kInvalidFd)
        {
            close(mFd);
            mFd = kInvalidFd;
        }
    
        if (mZirconHandle != ZX_HANDLE_INVALID)
        {
            CloseZirconVmo(mZirconHandle);
            mZirconHandle = ZX_HANDLE_INVALID;
        }
    }
    
    angle::Result MemoryObjectVk::setDedicatedMemory(const gl::Context *context, bool dedicatedMemory)
    {
        mDedicatedMemory = dedicatedMemory;
        return angle::Result::Continue;
    }
    
    angle::Result MemoryObjectVk::setProtectedMemory(const gl::Context *context, bool protectedMemory)
    {
        mProtectedMemory = protectedMemory;
        return angle::Result::Continue;
    }
    
    angle::Result MemoryObjectVk::importFd(gl::Context *context,
                                           GLuint64 size,
                                           gl::HandleType handleType,
                                           GLint fd)
    {
        ContextVk *contextVk = vk::GetImpl(context);
    
        switch (handleType)
        {
            case gl::HandleType::OpaqueFd:
                return importOpaqueFd(contextVk, size, fd);
    
            default:
                UNREACHABLE();
                return angle::Result::Stop;
        }
    }
    
    angle::Result MemoryObjectVk::importZirconHandle(gl::Context *context,
                                                     GLuint64 size,
                                                     gl::HandleType handleType,
                                                     GLuint handle)
    {
        ContextVk *contextVk = vk::GetImpl(context);
    
        switch (handleType)
        {
            case gl::HandleType::ZirconVmo:
                return importZirconVmo(contextVk, size, handle);
    
            default:
                UNREACHABLE();
                return angle::Result::Stop;
        }
    }
    
    angle::Result MemoryObjectVk::importOpaqueFd(ContextVk *contextVk, GLuint64 size, GLint fd)
    {
        ASSERT(mHandleType == gl::HandleType::InvalidEnum);
        ASSERT(mFd == kInvalidFd);
        ASSERT(fd != kInvalidFd);
        mHandleType = gl::HandleType::OpaqueFd;
        mFd         = fd;
        mSize       = size;
        return angle::Result::Continue;
    }
    
    angle::Result MemoryObjectVk::importZirconVmo(ContextVk *contextVk, GLuint64 size, GLuint handle)
    {
        ASSERT(mHandleType == gl::HandleType::InvalidEnum);
        ASSERT(mZirconHandle == ZX_HANDLE_INVALID);
        ASSERT(handle != ZX_HANDLE_INVALID);
        mHandleType   = gl::HandleType::ZirconVmo;
        mZirconHandle = handle;
        mSize         = size;
        return angle::Result::Continue;
    }
    
    angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
                                              gl::TextureType type,
                                              size_t levels,
                                              GLenum internalFormat,
                                              const gl::Extents &size,
                                              GLuint64 offset,
                                              vk::ImageHelper *image,
                                              GLbitfield createFlags,
                                              GLbitfield usageFlags)
    {
        RendererVk *renderer = contextVk->getRenderer();
    
        const vk::Format &vkFormat     = renderer->getFormat(internalFormat);
        angle::FormatID actualFormatID = vkFormat.getActualRenderableImageFormatID();
    
        // EXT_external_objects issue 13 says that all supported usage flags must be specified.
        // However, ANGLE_external_objects_flags allows these flags to be masked.  Note that the GL enum
        // values constituting the bits of |usageFlags| are identical to their corresponding Vulkan
        // value.
        const VkImageUsageFlags imageUsageFlags =
            vk::GetMaximalImageUsageFlags(renderer, actualFormatID) & usageFlags;
    
        VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
        externalMemoryImageCreateInfo.sType       = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
        externalMemoryImageCreateInfo.handleTypes = ToVulkanHandleType(mHandleType);
    
        VkExtent3D vkExtents;
        uint32_t layerCount;
        gl_vk::GetExtentsAndLayerCount(type, size, &vkExtents, &layerCount);
    
        // Initialize VkImage with initial layout of VK_IMAGE_LAYOUT_UNDEFINED.
        //
        // Binding a VkImage with an initial layout of VK_IMAGE_LAYOUT_UNDEFINED to external memory
        // whose content has already been defined does not make the content undefined (see 11.7.1.
        // External Resource Sharing).
        //
        // If the content is already defined, the ownership rules imply that the first operation on the
        // texture must be a call to glWaitSemaphoreEXT that grants ownership of the image and informs
        // us of the true layout.
        //
        // If the content is not already defined, the first operation may not be a glWaitSemaphore, but
        // in this case undefined layout is appropriate.
        //
        // ANGLE_external_objects_flags allows create flags to be specified by the application instead
        // of getting defaulted to zero.  Note that the GL enum values constituting the bits of
        // |createFlags| are identical to their corresponding Vulkan value.
        bool hasProtectedContent = mProtectedMemory;
        ANGLE_TRY(image->initExternal(
            contextVk, type, vkExtents, vkFormat.getIntendedFormatID(), actualFormatID, 1,
            imageUsageFlags, createFlags, vk::ImageLayout::Undefined, &externalMemoryImageCreateInfo,
            gl::LevelIndex(0), static_cast<uint32_t>(levels), layerCount,
            contextVk->isRobustResourceInitEnabled(), nullptr, hasProtectedContent));
    
        VkMemoryRequirements externalMemoryRequirements;
        image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
    
        const void *importMemoryInfo                              = nullptr;
        VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {};
        if (mDedicatedMemory)
        {
            memoryDedicatedAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
            memoryDedicatedAllocateInfo.image = image->getImage().getHandle();
            importMemoryInfo                  = &memoryDedicatedAllocateInfo;
        }
    
        VkImportMemoryFdInfoKHR importMemoryFdInfo                         = {};
        VkImportMemoryZirconHandleInfoFUCHSIA importMemoryZirconHandleInfo = {};
        switch (mHandleType)
        {
            case gl::HandleType::OpaqueFd:
                ASSERT(mFd != kInvalidFd);
                importMemoryFdInfo.sType      = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
                importMemoryFdInfo.pNext      = importMemoryInfo;
                importMemoryFdInfo.handleType = ToVulkanHandleType(mHandleType);
                importMemoryFdInfo.fd         = dup(mFd);
                importMemoryInfo              = &importMemoryFdInfo;
                break;
            case gl::HandleType::ZirconVmo:
                ASSERT(mZirconHandle != ZX_HANDLE_INVALID);
                importMemoryZirconHandleInfo.sType =
                    VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA;
                importMemoryZirconHandleInfo.pNext      = importMemoryInfo;
                importMemoryZirconHandleInfo.handleType = ToVulkanHandleType(mHandleType);
                ANGLE_TRY(
                    DuplicateZirconVmo(contextVk, mZirconHandle, &importMemoryZirconHandleInfo.handle));
                importMemoryInfo = &importMemoryZirconHandleInfo;
                break;
            default:
                UNREACHABLE();
        }
    
        // TODO(jmadill, spang): Memory sub-allocation. http://anglebug.com/2162
        ASSERT(offset == 0);
        ASSERT(externalMemoryRequirements.size == mSize);
    
        VkMemoryPropertyFlags flags = hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0;
        ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(),
                                            externalMemoryRequirements, nullptr, 1, &importMemoryInfo,
                                            renderer->getQueueFamilyIndex(), flags));
    
        return angle::Result::Continue;
    }
    
    }  // namespace rx