| // 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, |
| const void *imageCreateInfoPNext) |
| { |
| 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.pNext = imageCreateInfoPNext; |
| externalMemoryImageCreateInfo.handleTypes = ToVulkanHandleType(mHandleType); |
| |
| VkExtent3D vkExtents; |
| uint32_t layerCount; |
| gl_vk::GetExtentsAndLayerCount(type, size, &vkExtents, &layerCount); |
| |
| // 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. There are no additional |
| // structs allowed to be chained to VkImageCreateInfo other than |
| // VkExternalMemoryImageCreateInfo. |
| bool hasProtectedContent = mProtectedMemory; |
| ANGLE_TRY(image->initExternal( |
| contextVk, type, vkExtents, vkFormat.getIntendedFormatID(), actualFormatID, 1, |
| imageUsageFlags, createFlags, vk::ImageLayout::ExternalPreInitialized, |
| &externalMemoryImageCreateInfo, gl::LevelIndex(0), static_cast<uint32_t>(levels), |
| layerCount, contextVk->isRobustResourceInitEnabled(), 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, 1, &importMemoryInfo, |
| renderer->getQueueFamilyIndex(), flags)); |
| |
| return angle::Result::Continue; |
| } |
| |
| } // namespace rx |