blob: b4ccca9cd952920fd6e7ca5930f0f08039dc8047 [file] [log] [blame]
// 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::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);
// 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, vkFormat.actualImageFormatID) & 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.
ANGLE_TRY(image->initExternal(contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags,
createFlags, vk::ImageLayout::Undefined,
&externalMemoryImageCreateInfo, gl::LevelIndex(0),
static_cast<uint32_t>(levels), layerCount,
contextVk->isRobustResourceInitEnabled(), nullptr, false));
VkMemoryRequirements externalMemoryRequirements;
image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
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 = 0;
ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(),
externalMemoryRequirements, nullptr, importMemoryInfo,
renderer->getQueueFamilyIndex(), flags));
return angle::Result::Continue;
}
} // namespace rx