Commit 3b2c6bfd by Michael Spang Committed by Commit Bot

Vulkan: Implement glImportMemoryFdEXT

Allow importing opaque file descriptors into memory objects on linux. Currently this just holds onto the file descriptor rather than calling vkAllocateMemory immediately. The latter will be easier once we have support for suballocation (anglebug.com/2162). Bug: angleproject:3289 Change-Id: Ia80ce07b2a9ec95b9063feb9bfeb24ffe77fa40e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1552028 Commit-Queue: Michael Spang <spang@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 20a71631
...@@ -7186,7 +7186,9 @@ void Context::bufferStorageMem(TextureType target, GLsizeiptr size, GLuint memor ...@@ -7186,7 +7186,9 @@ void Context::bufferStorageMem(TextureType target, GLsizeiptr size, GLuint memor
void Context::importMemoryFd(GLuint memory, GLuint64 size, HandleType handleType, GLint fd) void Context::importMemoryFd(GLuint memory, GLuint64 size, HandleType handleType, GLint fd)
{ {
UNIMPLEMENTED(); MemoryObject *memoryObject = getMemoryObject(memory);
ASSERT(memoryObject != nullptr);
ANGLE_CONTEXT_TRY(memoryObject->importFd(this, size, handleType, fd));
} }
void Context::genSemaphores(GLsizei n, GLuint *semaphores) void Context::genSemaphores(GLsizei n, GLuint *semaphores)
......
...@@ -216,6 +216,7 @@ MSG kInvalidFramebufferLayer = "Framebuffer layer cannot be less than 0 or great ...@@ -216,6 +216,7 @@ MSG kInvalidFramebufferLayer = "Framebuffer layer cannot be less than 0 or great
MSG kInvalidFramebufferName = "name is not a valid framebuffer."; MSG kInvalidFramebufferName = "name is not a valid framebuffer.";
MSG kInvalidFramebufferTarget = "Invalid framebuffer target."; MSG kInvalidFramebufferTarget = "Invalid framebuffer target.";
MSG kInvalidFramebufferTextureLevel = "Mipmap level must be 0 when attaching a texture."; MSG kInvalidFramebufferTextureLevel = "Mipmap level must be 0 when attaching a texture.";
MSG kInvalidHandleType = "Invalid handle type.";
MSG kInvalidImageAccess = "access is not one of the supported tokens."; MSG kInvalidImageAccess = "access is not one of the supported tokens.";
MSG kInvalidImageFormat = "format is not one of supported image unit formats."; MSG kInvalidImageFormat = "format is not one of supported image unit formats.";
MSG kInvalidIndentifier = "Invalid identifier."; MSG kInvalidIndentifier = "Invalid identifier.";
......
...@@ -25,4 +25,12 @@ void MemoryObject::onDestroy(const Context *context) ...@@ -25,4 +25,12 @@ void MemoryObject::onDestroy(const Context *context)
mImplementation->onDestroy(context); mImplementation->onDestroy(context);
} }
angle::Result MemoryObject::importFd(Context *context,
GLuint64 size,
HandleType handleType,
GLint fd)
{
return mImplementation->importFd(context, size, handleType, fd);
}
} // namespace gl } // namespace gl
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define LIBANGLE_MEMORYOBJECT_H_ #define LIBANGLE_MEMORYOBJECT_H_
#include "angle_gl.h" #include "angle_gl.h"
#include "common/PackedEnums.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/RefCountObject.h" #include "libANGLE/RefCountObject.h"
...@@ -21,6 +22,7 @@ class MemoryObjectImpl; ...@@ -21,6 +22,7 @@ class MemoryObjectImpl;
namespace gl namespace gl
{ {
class Context;
class MemoryObject final : public RefCountObject class MemoryObject final : public RefCountObject
{ {
...@@ -30,6 +32,8 @@ class MemoryObject final : public RefCountObject ...@@ -30,6 +32,8 @@ class MemoryObject final : public RefCountObject
void onDestroy(const Context *context) override; void onDestroy(const Context *context) override;
angle::Result importFd(Context *context, GLuint64 size, HandleType handleType, GLint fd);
private: private:
std::unique_ptr<rx::MemoryObjectImpl> mImplementation; std::unique_ptr<rx::MemoryObjectImpl> mImplementation;
}; };
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define LIBANGLE_RENDERER_MEMORYOBJECTIMPL_H_ #define LIBANGLE_RENDERER_MEMORYOBJECTIMPL_H_
#include "angle_gl.h" #include "angle_gl.h"
#include "common/PackedEnums.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
...@@ -27,6 +28,11 @@ class MemoryObjectImpl : angle::NonCopyable ...@@ -27,6 +28,11 @@ class MemoryObjectImpl : angle::NonCopyable
virtual ~MemoryObjectImpl() {} virtual ~MemoryObjectImpl() {}
virtual void onDestroy(const gl::Context *context) = 0; virtual void onDestroy(const gl::Context *context) = 0;
virtual angle::Result importFd(gl::Context *context,
GLuint64 size,
gl::HandleType handleType,
GLint fd) = 0;
}; };
} // namespace rx } // namespace rx
......
...@@ -7,13 +7,71 @@ ...@@ -7,13 +7,71 @@
#include "libANGLE/renderer/vulkan/MemoryObjectVk.h" #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
#include <vulkan/vulkan.h>
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#if !defined(ANGLE_PLATFORM_WINDOWS)
# include <unistd.h>
#else
# include <io.h>
#endif
namespace rx namespace rx
{ {
MemoryObjectVk::MemoryObjectVk() {} namespace
{
constexpr int kInvalidFd = -1;
#if defined(ANGLE_PLATFORM_WINDOWS)
int close(int fd)
{
return _close(fd);
}
#endif
} // namespace
MemoryObjectVk::MemoryObjectVk() : mSize(0), mFd(kInvalidFd) {}
MemoryObjectVk::~MemoryObjectVk() = default; MemoryObjectVk::~MemoryObjectVk() = default;
void MemoryObjectVk::onDestroy(const gl::Context *context) {} void MemoryObjectVk::onDestroy(const gl::Context *context)
{
if (mFd != kInvalidFd)
{
close(mFd);
mFd = kInvalidFd;
}
}
angle::Result MemoryObjectVk::importFd(gl::Context *context,
GLuint64 size,
gl::HandleType handleType,
GLint fd)
{
switch (handleType)
{
case gl::HandleType::OpaqueFd:
return importOpaqueFd(context, size, fd);
default:
UNREACHABLE();
return angle::Result::Stop;
}
}
angle::Result MemoryObjectVk::importOpaqueFd(gl::Context *context, GLuint64 size, GLint fd)
{
ASSERT(mFd == kInvalidFd);
mFd = fd;
mSize = size;
return angle::Result::Continue;
}
} // namespace rx } // namespace rx
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#define LIBANGLE_RENDERER_VULKAN_MEMORYOBJECTVK_H_ #define LIBANGLE_RENDERER_VULKAN_MEMORYOBJECTVK_H_
#include "libANGLE/renderer/MemoryObjectImpl.h" #include "libANGLE/renderer/MemoryObjectImpl.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
#include "libANGLE/renderer/vulkan/vk_wrapper.h"
namespace rx namespace rx
{ {
...@@ -20,6 +22,17 @@ class MemoryObjectVk : public MemoryObjectImpl ...@@ -20,6 +22,17 @@ class MemoryObjectVk : public MemoryObjectImpl
~MemoryObjectVk() override; ~MemoryObjectVk() override;
void onDestroy(const gl::Context *context) override; void onDestroy(const gl::Context *context) override;
angle::Result importFd(gl::Context *context,
GLuint64 size,
gl::HandleType handleType,
GLint fd) override;
private:
angle::Result importOpaqueFd(gl::Context *context, GLuint64 size, GLint fd);
GLuint64 mSize;
int mFd;
}; };
} // namespace rx } // namespace rx
......
...@@ -3193,8 +3193,16 @@ bool ValidateImportMemoryFdEXT(Context *context, ...@@ -3193,8 +3193,16 @@ bool ValidateImportMemoryFdEXT(Context *context,
return false; return false;
} }
UNIMPLEMENTED(); switch (handleType)
return false; {
case HandleType::OpaqueFd:
break;
default:
context->validationError(GL_INVALID_ENUM, kInvalidHandleType);
return false;
}
return true;
} }
bool ValidateDeleteSemaphoresEXT(Context *context, GLsizei n, const GLuint *semaphores) bool ValidateDeleteSemaphoresEXT(Context *context, GLsizei n, const GLuint *semaphores)
......
...@@ -176,6 +176,9 @@ if (is_win || is_linux || is_mac || is_android || is_fuchsia) { ...@@ -176,6 +176,9 @@ if (is_win || is_linux || is_mac || is_android || is_fuchsia) {
if (use_x11) { if (use_x11) {
sources += angle_end2end_tests_x11_sources sources += angle_end2end_tests_x11_sources
} }
if (angle_enable_vulkan) {
sources += angle_end2end_tests_vulkan_sources
}
configs += [ configs += [
"${angle_root}:libANGLE_config", "${angle_root}:libANGLE_config",
...@@ -200,6 +203,9 @@ if (is_win || is_linux || is_mac || is_android || is_fuchsia) { ...@@ -200,6 +203,9 @@ if (is_win || is_linux || is_mac || is_android || is_fuchsia) {
if (is_android) { if (is_android) {
use_native_activity = true use_native_activity = true
} }
if (angle_enable_vulkan) {
deps += [ "${angle_root}:angle_vulkan" ]
}
} }
} }
......
...@@ -161,3 +161,8 @@ angle_end2end_tests_win_sources = [ ...@@ -161,3 +161,8 @@ angle_end2end_tests_win_sources = [
"egl_tests/media/yuvtest.inl", "egl_tests/media/yuvtest.inl",
] ]
angle_end2end_tests_x11_sources = [ "egl_tests/EGLX11VisualTest.cpp" ] angle_end2end_tests_x11_sources = [ "egl_tests/EGLX11VisualTest.cpp" ]
angle_end2end_tests_vulkan_sources = [
"gl_tests/VulkanExternalImageTest.cpp",
"test_utils/VulkanExternalHelper.cpp",
"test_utils/VulkanExternalHelper.h",
]
...@@ -27,6 +27,7 @@ class MemoryObjectTest : public ANGLETest ...@@ -27,6 +27,7 @@ class MemoryObjectTest : public ANGLETest
} }
}; };
// glIsMemoryObjectEXT must identify memory objects.
TEST_P(MemoryObjectTest, MemoryObjectShouldBeMemoryObject) TEST_P(MemoryObjectTest, MemoryObjectShouldBeMemoryObject)
{ {
ANGLE_SKIP_TEST_IF(!ensureExtensionEnabled("GL_EXT_memory_object")); ANGLE_SKIP_TEST_IF(!ensureExtensionEnabled("GL_EXT_memory_object"));
...@@ -47,13 +48,28 @@ TEST_P(MemoryObjectTest, MemoryObjectShouldBeMemoryObject) ...@@ -47,13 +48,28 @@ TEST_P(MemoryObjectTest, MemoryObjectShouldBeMemoryObject)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// glImportMemoryFdEXT must fail for handle types that are not file descriptors.
TEST_P(MemoryObjectTest, ShouldFailValidationOnImportFdUnsupportedHandleType)
{
ANGLE_SKIP_TEST_IF(!ensureExtensionEnabled("GL_EXT_memory_object_fd"));
{
GLMemoryObject memoryObject;
GLsizei deviceMemorySize = 1;
int fd = -1;
glImportMemoryFdEXT(memoryObject, deviceMemorySize, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, fd);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
EXPECT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(MemoryObjectTest, ANGLE_INSTANTIATE_TEST(MemoryObjectTest,
ES2_D3D9(), ES2_D3D9(),
ES2_D3D11(), ES2_D3D11(),
ES3_D3D11(), ES3_D3D11(),
ES2_D3D11_FL9_3(),
ES2_OPENGL(), ES2_OPENGL(),
ES3_OPENGL(), ES3_OPENGL(),
ES2_OPENGLES(), ES2_OPENGLES(),
......
//
// 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.
//
// VulkanExternalImageTest.cpp : Tests of images allocated externally using Vulkan.
#include "test_utils/ANGLETest.h"
#include "common/debug.h"
#include "test_utils/VulkanExternalHelper.h"
#include "test_utils/gl_raii.h"
namespace angle
{
namespace
{
constexpr int kInvalidFd = -1;
VkFormat ChooseAnyImageFormat(const VulkanExternalHelper &helper)
{
static constexpr VkFormat kFormats[] = {
VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_R8G8B8A8_UNORM,
};
for (VkFormat format : kFormats)
{
if (helper.canCreateImageOpaqueFd(format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL))
{
return format;
}
}
return VK_FORMAT_UNDEFINED;
}
} // namespace
class VulkanExternalImageTest : public ANGLETest
{
protected:
VulkanExternalImageTest()
{
setWindowWidth(1);
setWindowHeight(1);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
// glImportMemoryFdEXT must be able to import a valid opaque fd.
TEST_P(VulkanExternalImageTest, ShouldImportVulkanExternalOpaqueFd)
{
ANGLE_SKIP_TEST_IF(!ensureExtensionEnabled("GL_EXT_memory_object_fd"));
VulkanExternalHelper helper;
helper.initialize();
VkFormat format = ChooseAnyImageFormat(helper);
ANGLE_SKIP_TEST_IF(format == VK_FORMAT_UNDEFINED);
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
VkDeviceSize deviceMemorySize = 0;
VkExtent3D extent = {1, 1, 1};
VkResult result =
helper.createImage2DOpaqueFd(format, extent, &image, &deviceMemory, &deviceMemorySize);
EXPECT_EQ(result, VK_SUCCESS);
int fd = kInvalidFd;
result = helper.exportMemoryOpaqueFd(deviceMemory, &fd);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(fd, kInvalidFd);
{
GLMemoryObject memoryObject;
glImportMemoryFdEXT(memoryObject, deviceMemorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd);
}
EXPECT_GL_NO_ERROR();
vkDestroyImage(helper.getDevice(), image, nullptr);
vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(VulkanExternalImageTest,
ES2_D3D9(),
ES2_D3D11(),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL(),
ES2_OPENGLES(),
ES3_OPENGLES(),
ES2_VULKAN());
} // namespace angle
//
// 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.
//
// VulkanExternalHelper.h : Helper for allocating & managing vulkan external objects.
#ifndef ANGLE_TESTS_TESTUTILS_VULKANEXTERNALHELPER_H_
#define ANGLE_TESTS_TESTUTILS_VULKANEXTERNALHELPER_H_
#include <vulkan/vulkan.h>
namespace angle
{
class VulkanExternalHelper
{
public:
VulkanExternalHelper();
~VulkanExternalHelper();
void initialize();
VkInstance getInstance() const { return mInstance; }
VkPhysicalDevice getPhysicalDevice() const { return mPhysicalDevice; }
VkDevice getDevice() const { return mDevice; }
VkQueue getGraphicsQueue() const { return mGraphicsQueue; }
// VK_KHR_external_memory_fd
bool canCreateImageOpaqueFd(VkFormat format, VkImageType type, VkImageTiling tiling) const;
VkResult createImage2DOpaqueFd(VkFormat format,
VkExtent3D extent,
VkImage *imageOut,
VkDeviceMemory *deviceMemoryOut,
VkDeviceSize *deviceMemorySizeOut);
VkResult exportMemoryOpaqueFd(VkDeviceMemory deviceMemory, int *fd);
private:
VkInstance mInstance = VK_NULL_HANDLE;
VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE;
VkDevice mDevice = VK_NULL_HANDLE;
VkQueue mGraphicsQueue = VK_NULL_HANDLE;
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
uint32_t mGraphicsQueueFamilyIndex = UINT32_MAX;
bool mHasExternalMemoryFd = false;
bool mHasExternalSemaphoreFd = false;
PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2 =
nullptr;
PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = nullptr;
};
} // namespace angle
#endif // ANGLE_TESTS_TESTUTILS_VULKANEXTERNALHELPER_H_
...@@ -86,6 +86,11 @@ class GLFramebuffer : public GLWrapper ...@@ -86,6 +86,11 @@ class GLFramebuffer : public GLWrapper
public: public:
GLFramebuffer() : GLWrapper(&glGenFramebuffers, &glDeleteFramebuffers) {} GLFramebuffer() : GLWrapper(&glGenFramebuffers, &glDeleteFramebuffers) {}
}; };
class GLMemoryObject : public GLWrapper
{
public:
GLMemoryObject() : GLWrapper(&glCreateMemoryObjectsEXT, &glDeleteMemoryObjectsEXT) {}
};
class GLRenderbuffer : public GLWrapper class GLRenderbuffer : public GLWrapper
{ {
public: public:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment