| // 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 "libANGLE/Context.h" |
| #include "libANGLE/renderer/vulkan/ContextVk.h" |
| #include "libANGLE/renderer/vulkan/RendererVk.h" |
| #include "volk.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_TEMP_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::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) |
| { |
| RendererVk *renderer = contextVk->getRenderer(); |
| |
| const vk::Format &vkFormat = renderer->getFormat(internalFormat); |
| |
| // All supported usage flags must be specified. |
| // See EXT_external_objects issue 13. |
| VkImageUsageFlags imageUsageFlags = |
| vk::GetMaximalImageUsageFlags(renderer, vkFormat.vkImageFormat); |
| |
| 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); |
| |
| ANGLE_TRY(image->initExternal( |
| contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags, |
| vk::ImageLayout::ExternalPreInitialized, &externalMemoryImageCreateInfo, 0, |
| static_cast<uint32_t>(levels) - 1, static_cast<uint32_t>(levels), layerCount)); |
| |
| VkMemoryRequirements externalMemoryRequirements; |
| image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements); |
| |
| void *importMemoryInfo = nullptr; |
| VkImportMemoryFdInfoKHR importMemoryFdInfo = {}; |
| VkImportMemoryZirconHandleInfoFUCHSIA importMemoryZirconHandleInfo = {}; |
| switch (mHandleType) |
| { |
| case gl::HandleType::OpaqueFd: |
| ASSERT(mFd != kInvalidFd); |
| importMemoryFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; |
| 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_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA; |
| 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 = 0; |
| ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(), |
| externalMemoryRequirements, importMemoryInfo, |
| VK_QUEUE_FAMILY_EXTERNAL, flags)); |
| |
| return angle::Result::Continue; |
| } |
| |
| } // namespace rx |