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>
This commit is contained in:
Shahbaz Youssefi 2021-09-02 22:41:40 -04:00 коммит произвёл Angle LUCI CQ
Родитель c85d9a19ff
Коммит 458389f249
34 изменённых файлов: 1030 добавлений и 172 удалений

Просмотреть файл

@ -301,6 +301,15 @@ struct FeaturesVk : FeatureSetBase
"VkDevice supports the VK_EXT_swapchain_colorspace extension", &members,
"http://anglebug.com/2514"};
// Whether the VkDevice supports the VK_EXT_external_memory_dma_buf and
// VK_EXT_image_drm_format_modifier extensions. These extensions are always used together to
// implement EGL_EXT_image_dma_buf_import and EGL_EXT_image_dma_buf_import_modifiers.
Feature supportsExternalMemoryDmaBufAndModifiers = {
"supportsExternalMemoryDmaBufAndModifiers", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_EXT_external_memory_dma_buf and VK_EXT_image_drm_format_modifier "
"extensions",
&members, "http://anglebug.com/6248"};
// Whether the VkDevice supports the VK_EXT_external_memory_host extension, on which the
// ANGLE_iosurface_client_buffer extension can be layered.
Feature supportsExternalMemoryHost = {

14
src/common/linux/BUILD.gn Normal file
Просмотреть файл

@ -0,0 +1,14 @@
# Copyright 2021 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.
import("../../../gni/angle.gni")
angle_source_set("angle_dma_buf") {
sources = [
"dma_buf_utils.cpp",
"dma_buf_utils.h",
]
deps = [ "$angle_root:angle_common" ]
}

Просмотреть файл

@ -0,0 +1,81 @@
//
// Copyright 2021 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.
//
// dma_buf_utils.cpp: Utilities to interact with Linux dma bufs.
#include "dma_buf_utils.h"
#include "common/debug.h"
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <array>
// Refer to:
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/drm/drm_fourcc.h
// https://source.chromium.org/chromium/chromium/src/+/main:ui/gl/gl_image_native_pixmap.cc;l=24
#define FOURCC(a, b, c, d) \
((static_cast<uint32_t>(a)) | (static_cast<uint32_t>(b) << 8) | \
(static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24))
#define DRM_FORMAT_R8 FOURCC('R', '8', ' ', ' ')
#define DRM_FORMAT_R16 FOURCC('R', '1', '6', ' ')
#define DRM_FORMAT_GR88 FOURCC('G', 'R', '8', '8')
#define DRM_FORMAT_RGB565 FOURCC('R', 'G', '1', '6')
#define DRM_FORMAT_ARGB8888 FOURCC('A', 'R', '2', '4')
#define DRM_FORMAT_ABGR8888 FOURCC('A', 'B', '2', '4')
#define DRM_FORMAT_XRGB8888 FOURCC('X', 'R', '2', '4')
#define DRM_FORMAT_XBGR8888 FOURCC('X', 'B', '2', '4')
#define DRM_FORMAT_ABGR2101010 FOURCC('A', 'B', '3', '0')
#define DRM_FORMAT_ARGB2101010 FOURCC('A', 'R', '3', '0')
#define DRM_FORMAT_YVU420 FOURCC('Y', 'V', '1', '2')
#define DRM_FORMAT_NV12 FOURCC('N', 'V', '1', '2')
#define DRM_FORMAT_P010 FOURCC('P', '0', '1', '0')
namespace angle
{
GLenum DrmFourCCFormatToGLInternalFormat(int fourccFormat, bool *isYUV)
{
*isYUV = false;
switch (fourccFormat)
{
case DRM_FORMAT_R8:
return GL_R8;
case DRM_FORMAT_R16:
return GL_R16_EXT;
case DRM_FORMAT_GR88:
return GL_RG8_EXT;
case DRM_FORMAT_ABGR8888:
return GL_RGBA8;
case DRM_FORMAT_XBGR8888:
return GL_RGB8;
case DRM_FORMAT_ARGB8888:
return GL_BGRA8_EXT;
case DRM_FORMAT_XRGB8888:
return GL_RGB8;
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_ARGB2101010:
return GL_RGB10_A2_EXT;
case DRM_FORMAT_RGB565:
return GL_RGB565;
case DRM_FORMAT_NV12:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_P010:
*isYUV = true;
return GL_RGB8;
default:
UNREACHABLE();
WARN() << "Unknown dma_buf format " << fourccFormat
<< " used to initialize an EGL image.";
return GL_RGB8;
}
}
} // namespace angle

Просмотреть файл

@ -0,0 +1,19 @@
//
// Copyright 2021 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.
//
// dma_buf_utils.h: Utilities to interact with Linux dma bufs.
#ifndef COMMON_LINUX_DMA_BUF_UTILS_H_
#define COMMON_LINUX_DMA_BUF_UTILS_H_
#include <angle_gl.h>
namespace angle
{
GLenum DrmFourCCFormatToGLInternalFormat(int format, bool *isYUV);
} // namespace angle
#endif // COMMON_LINUX_DMA_BUF_UTILS_H_

Просмотреть файл

@ -369,7 +369,7 @@ CheckedUnsignedAbs(T value)
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type Checked##NAME( \
T, T, RangeConstraint *) \
{ \
NOTREACHED(); \
UNREACHABLE(); \
return static_cast<T>(0); \
}
@ -496,7 +496,7 @@ class CheckedNumericState<T, NUMERIC_FLOATING>
break;
default:
NOTREACHED();
UNREACHABLE();
}
}

Просмотреть файл

@ -264,6 +264,9 @@ angle_source_set("angle_gl_backend") {
"Xext",
]
}
if (is_android || is_linux || is_chromeos) {
deps += [ "$angle_root/src/common/linux:angle_dma_buf" ]
}
if (is_apple) {
frameworks = [
"IOSurface.framework",

Просмотреть файл

@ -9,67 +9,7 @@
#include "libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.h"
namespace
{
// Refer to the following link
// https://source.chromium.org/chromium/chromium/src/+/main:ui/gl/gl_image_native_pixmap.cc;l=24
#define FOURCC(a, b, c, d) \
((static_cast<uint32_t>(a)) | (static_cast<uint32_t>(b) << 8) | \
(static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24))
#define DRM_FORMAT_R8 FOURCC('R', '8', ' ', ' ')
#define DRM_FORMAT_R16 FOURCC('R', '1', '6', ' ')
#define DRM_FORMAT_GR88 FOURCC('G', 'R', '8', '8')
#define DRM_FORMAT_RGB565 FOURCC('R', 'G', '1', '6')
#define DRM_FORMAT_ARGB8888 FOURCC('A', 'R', '2', '4')
#define DRM_FORMAT_ABGR8888 FOURCC('A', 'B', '2', '4')
#define DRM_FORMAT_XRGB8888 FOURCC('X', 'R', '2', '4')
#define DRM_FORMAT_XBGR8888 FOURCC('X', 'B', '2', '4')
#define DRM_FORMAT_ABGR2101010 FOURCC('A', 'B', '3', '0')
#define DRM_FORMAT_ARGB2101010 FOURCC('A', 'R', '3', '0')
#define DRM_FORMAT_YVU420 FOURCC('Y', 'V', '1', '2')
#define DRM_FORMAT_NV12 FOURCC('N', 'V', '1', '2')
#define DRM_FORMAT_P010 FOURCC('P', '0', '1', '0')
GLenum FourCCFormatToGLInternalFormat(int format, bool *isYUV)
{
*isYUV = false;
switch (format)
{
case DRM_FORMAT_R8:
return GL_R8;
case DRM_FORMAT_R16:
return GL_R16_EXT;
case DRM_FORMAT_GR88:
return GL_RG8_EXT;
case DRM_FORMAT_ABGR8888:
return GL_RGBA8;
case DRM_FORMAT_XBGR8888:
return GL_RGB8;
case DRM_FORMAT_ARGB8888:
return GL_BGRA8_EXT;
case DRM_FORMAT_XRGB8888:
return GL_RGB8;
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_ARGB2101010:
return GL_RGB10_A2_EXT;
case DRM_FORMAT_RGB565:
return GL_RGB565;
case DRM_FORMAT_NV12:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_P010:
*isYUV = true;
return GL_RGB8;
default:
NOTREACHED();
WARN() << "Unknown dma_buf format " << format << " used to initialize an EGL image.";
return GL_RGB8;
}
}
} // namespace
#include "common/linux/dma_buf_utils.h"
namespace rx
{
@ -84,7 +24,7 @@ DmaBufImageSiblingEGL::DmaBufImageSiblingEGL(const egl::AttributeMap &attribs)
mHasProtectedContent = false;
int fourCCFormat = mAttribs.getAsInt(EGL_LINUX_DRM_FOURCC_EXT);
mFormat = gl::Format(FourCCFormatToGLInternalFormat(fourCCFormat, &mYUV));
mFormat = gl::Format(angle::DrmFourCCFormatToGLInternalFormat(fourCCFormat, &mYUV));
}
DmaBufImageSiblingEGL::~DmaBufImageSiblingEGL() {}

Просмотреть файл

@ -138,14 +138,18 @@ if (angle_use_vulkan_null_display) {
if (is_linux) {
_vulkan_backend_sources += [
"display/DisplayVkSimple.cpp",
"display/DisplayVkSimple.h",
"display/WindowSurfaceVkSimple.cpp",
"display/WindowSurfaceVkSimple.h",
"headless/DisplayVkHeadless.cpp",
"headless/DisplayVkHeadless.h",
"headless/WindowSurfaceVkHeadless.cpp",
"headless/WindowSurfaceVkHeadless.h",
"linux/DisplayVkLinux.cpp",
"linux/DisplayVkLinux.h",
"linux/DmaBufImageSiblingVkLinux.cpp",
"linux/DmaBufImageSiblingVkLinux.h",
"linux/display/DisplayVkSimple.cpp",
"linux/display/DisplayVkSimple.h",
"linux/display/WindowSurfaceVkSimple.cpp",
"linux/display/WindowSurfaceVkSimple.h",
"linux/headless/DisplayVkHeadless.cpp",
"linux/headless/DisplayVkHeadless.h",
"linux/headless/WindowSurfaceVkHeadless.cpp",
"linux/headless/WindowSurfaceVkHeadless.h",
]
}
@ -173,10 +177,10 @@ if (is_win) {
if (angle_use_x11) {
_vulkan_backend_sources += [
"xcb/DisplayVkXcb.cpp",
"xcb/DisplayVkXcb.h",
"xcb/WindowSurfaceVkXcb.cpp",
"xcb/WindowSurfaceVkXcb.h",
"linux/xcb/DisplayVkXcb.cpp",
"linux/xcb/DisplayVkXcb.h",
"linux/xcb/WindowSurfaceVkXcb.cpp",
"linux/xcb/WindowSurfaceVkXcb.h",
]
}
@ -277,6 +281,10 @@ angle_source_set("angle_vulkan_backend") {
data_deps += [ "$angle_root/src/common/vulkan:vulkan_validation_layers" ]
}
if (is_linux) {
deps += [ "$angle_root/src/common/linux:angle_dma_buf" ]
}
if (is_fuchsia) {
public_deps += [ "$angle_root/src/common/fuchsia_egl:backend" ]
}

Просмотреть файл

@ -230,6 +230,14 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->framebufferTargetANDROID = true;
#endif // defined(ANGLE_PLATFORM_ANDROID)
// EGL_EXT_image_dma_buf_import is only exposed if EGL_EXT_image_dma_buf_import_modifiers can
// also be exposed. The Vulkan extensions that support these EGL extensions are not split in
// the same way; both Vulkan extensions are needed for EGL_EXT_image_dma_buf_import, and with
// both Vulkan extensions, EGL_EXT_image_dma_buf_import_modifiers is also supportable.
outExtensions->imageDmaBufImportEXT =
getRenderer()->getFeatures().supportsExternalMemoryDmaBufAndModifiers.enabled;
outExtensions->imageDmaBufImportModifiersEXT = outExtensions->imageDmaBufImportEXT;
// Disable context priority when non-zero memory init is enabled. This enforces a queue order.
outExtensions->contextPriority = !getRenderer()->getFeatures().allocateNonZeroMemory.enabled;
outExtensions->noConfigContext = true;

Просмотреть файл

@ -221,7 +221,7 @@ angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
VkMemoryRequirements externalMemoryRequirements;
image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
void *importMemoryInfo = nullptr;
const void *importMemoryInfo = nullptr;
VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {};
if (mDedicatedMemory)
{
@ -262,7 +262,7 @@ angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
VkMemoryPropertyFlags flags = hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0;
ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(),
externalMemoryRequirements, nullptr, importMemoryInfo,
externalMemoryRequirements, nullptr, 1, &importMemoryInfo,
renderer->getQueueFamilyIndex(), flags));
return angle::Result::Continue;

Просмотреть файл

@ -1819,6 +1819,12 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
}
}
if (getFeatures().supportsExternalMemoryDmaBufAndModifiers.enabled)
{
enabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
enabledDeviceExtensions.push_back(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
}
if (getFeatures().supportsExternalMemoryHost.enabled)
{
enabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME);
@ -2428,6 +2434,11 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportCallbacks, false);
ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportStats, false);
ANGLE_FEATURE_CONDITION(
&mFeatures, supportsExternalMemoryDmaBufAndModifiers,
ExtensionFound(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, deviceExtensionNames) &&
ExtensionFound(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, deviceExtensionNames));
ANGLE_FEATURE_CONDITION(
&mFeatures, supportsExternalMemoryHost,
ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames));

Просмотреть файл

@ -235,7 +235,8 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initializeWithExternalMemory(
importMemoryHostPointerInfo.pNext = nullptr;
importMemoryHostPointerInfo.handleType =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT;
importMemoryHostPointerInfo.pHostPointer = buffer;
importMemoryHostPointerInfo.pHostPointer = buffer;
const void *importMemoryHostPointerInfoPtr = &importMemoryHostPointerInfo;
VkMemoryRequirements externalMemoryRequirements;
image.getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
@ -246,8 +247,8 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initializeWithExternalMemory(
flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
}
ANGLE_TRY(image.initExternalMemory(
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, nullptr,
&importMemoryHostPointerInfo, VK_QUEUE_FAMILY_EXTERNAL, flags));
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, nullptr, 1,
&importMemoryHostPointerInfoPtr, VK_QUEUE_FAMILY_EXTERNAL, flags));
imageViews.init(renderer);

Просмотреть файл

@ -54,7 +54,7 @@ VkImageTiling AhbDescUsageToVkImageTiling(const AHardwareBuffer_Desc &ahbDescrip
//
// Also, as an aside, in terms of what's generally expected from the Vulkan
// ICD in Android when determining AHB compatibility, if the vendor wants
// to declare a particular combinatino of format/tiling/usage/etc as not
// to declare a particular combination of format/tiling/usage/etc as not
// supported AHB-wise, it's up to the ICD vendor to zero out bits in
// supportedHandleTypes in the vkGetPhysicalDeviceImageFormatProperties2
// query:
@ -72,6 +72,38 @@ VkImageTiling AhbDescUsageToVkImageTiling(const AHardwareBuffer_Desc &ahbDescrip
return VK_IMAGE_TILING_OPTIMAL;
}
// Map AHB usage flags to VkImageUsageFlags using this table from the Vulkan spec
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap10.html#memory-external-android-hardware-buffer-usage
VkImageUsageFlags AhbDescUsageToVkImageUsage(const AHardwareBuffer_Desc &ahbDescription,
bool isDepthOrStencilFormat)
{
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) != 0)
{
usage |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) != 0)
{
if (isDepthOrStencilFormat)
{
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
else
{
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
}
if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) != 0)
{
usage |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
return usage;
}
} // namespace
HardwareBufferImageSiblingVkAndroid::HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer)
@ -161,43 +193,6 @@ egl::Error HardwareBufferImageSiblingVkAndroid::initialize(const egl::Display *d
return angle::ToEGL(initImpl(displayVk), displayVk, EGL_BAD_PARAMETER);
}
// Map AHB usage flags to VkImageUsageFlags using this table from the Vulkan spec
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap10.html#memory-external-android-hardware-buffer-usage
VkImageUsageFlags AhbDescUsageToVkImageUsage(const AHardwareBuffer_Desc &ahbDescription,
bool isDepthOrStencilFormat)
{
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) != 0)
{
usage |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) != 0)
{
if (isDepthOrStencilFormat)
{
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
else
{
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
}
if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) != 0)
{
usage |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) != 0)
{
usage |= VK_IMAGE_CREATE_PROTECTED_BIT;
}
return usage;
}
angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk)
{
const AHBFunctions &functions = static_cast<DisplayVkAndroid *>(displayVk)->getAHBFunctions();
@ -296,18 +291,23 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
importHardwareBufferInfo.buffer = hardwareBuffer;
VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {};
dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
dedicatedAllocInfo.pNext = &importHardwareBufferInfo;
dedicatedAllocInfo.image = mImage->getImage().getHandle();
dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
dedicatedAllocInfo.pNext = &importHardwareBufferInfo;
dedicatedAllocInfo.image = mImage->getImage().getHandle();
dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
const void *dedicatedAllocInfoPtr = &dedicatedAllocInfo;
VkMemoryRequirements externalMemoryRequirements = {};
externalMemoryRequirements.size = bufferProperties.allocationSize;
externalMemoryRequirements.alignment = 0;
externalMemoryRequirements.memoryTypeBits = bufferProperties.memoryTypeBits;
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
(hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
const VkMemoryPropertyFlags flags =
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
(hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
VkSamplerYcbcrConversionCreateInfo yuvConversionInfo = {};
VkSamplerYcbcrConversionCreateInfo *yuvConversionInfoPtr = nullptr;
if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
{
// Note from Vulkan spec: Since GL_OES_EGL_image_external does not require the same sampling
@ -316,7 +316,7 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
VK_ERROR_FEATURE_NOT_PRESENT);
ASSERT(externalFormat.pNext == nullptr);
VkSamplerYcbcrConversionCreateInfo yuvConversionInfo = {};
yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
yuvConversionInfo.pNext = &externalFormat;
yuvConversionInfo.format = VK_FORMAT_UNDEFINED;
@ -327,18 +327,14 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
yuvConversionInfo.chromaFilter = VK_FILTER_NEAREST;
yuvConversionInfo.components = bufferFormatProperties.samplerYcbcrConversionComponents;
ANGLE_TRY(mImage->initExternalMemory(
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements,
&yuvConversionInfo, &dedicatedAllocInfo, VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
yuvConversionInfoPtr = &yuvConversionInfo;
mYUV = true;
}
else
{
ANGLE_TRY(mImage->initExternalMemory(
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, nullptr,
&dedicatedAllocInfo, VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
}
ANGLE_TRY(mImage->initExternalMemory(
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements,
yuvConversionInfoPtr, 1, &dedicatedAllocInfoPtr, VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
constexpr uint32_t kDepthStencilRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
@ -411,8 +407,8 @@ void HardwareBufferImageSiblingVkAndroid::release(RendererVk *renderer)
{
if (mImage != nullptr)
{
// TODO: We need to handle the case that EGLImage used in two context that aren't shared.
// https://issuetracker.google.com/169868803
// TODO: Handle the case where the EGLImage is used in two contexts not in the same share
// group. https://issuetracker.google.com/169868803
mImage->releaseImage(renderer);
mImage->releaseStagingBuffer(renderer);
SafeDelete(mImage);

Просмотреть файл

@ -0,0 +1,37 @@
//
// Copyright 2021 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.
//
// DisplayVkLinux.cpp:
// Implements the class methods for DisplayVkLinux.
//
#include "libANGLE/renderer/vulkan/linux/DisplayVkLinux.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/linux/DmaBufImageSiblingVkLinux.h"
namespace rx
{
DisplayVkLinux::DisplayVkLinux(const egl::DisplayState &state) : DisplayVk(state) {}
ExternalImageSiblingImpl *DisplayVkLinux::createExternalImageSibling(
const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
switch (target)
{
case EGL_LINUX_DMA_BUF_EXT:
ASSERT(context == nullptr);
ASSERT(buffer == nullptr);
return new DmaBufImageSiblingVkLinux(attribs);
default:
return DisplayVk::createExternalImageSibling(context, target, buffer, attribs);
}
}
} // namespace rx

Просмотреть файл

@ -0,0 +1,32 @@
//
// Copyright 2021 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.
//
// DisplayVkLinux.h:
// Defines the class interface for DisplayVkLinux, which is the base of DisplayVkSimple,
// DisplayVkHeadless and DisplayVkXcb. This base class implements the common functionality of
// handling Linux dma-bufs.
//
#ifndef LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKLINUX_H_
#define LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKLINUX_H_
#include "libANGLE/renderer/vulkan/DisplayVk.h"
namespace rx
{
class DisplayVkLinux : public DisplayVk
{
public:
DisplayVkLinux(const egl::DisplayState &state);
ExternalImageSiblingImpl *createExternalImageSibling(const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs) override;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKLINUX_H_

Просмотреть файл

@ -0,0 +1,558 @@
//
// Copyright 2021 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.
//
// DmaBufImageSiblingVkLinux.cpp: Implements DmaBufImageSiblingVkLinux.
#include "libANGLE/renderer/vulkan/linux/DmaBufImageSiblingVkLinux.h"
#include "common/linux/dma_buf_utils.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx
{
namespace
{
constexpr uint32_t kMaxPlaneCount = 4;
template <typename T>
using PerPlane = std::array<T, kMaxPlaneCount>;
constexpr PerPlane<EGLenum> kFds = {EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE1_FD_EXT,
EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE3_FD_EXT};
constexpr PerPlane<EGLenum> kOffsets = {
EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT,
EGL_DMA_BUF_PLANE3_OFFSET_EXT};
constexpr PerPlane<EGLenum> kPitches = {EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT,
EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT};
constexpr PerPlane<EGLenum> kModifiersLo = {
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT};
constexpr PerPlane<EGLenum> kModifiersHi = {
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT};
constexpr VkImageUsageFlags kTransferUsage =
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
constexpr VkImageUsageFlags kTextureUsage =
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
constexpr VkImageUsageFlags kRenderUsage =
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
struct AllocateInfo
{
PerPlane<VkMemoryDedicatedAllocateInfo> allocateInfo = {};
PerPlane<VkImportMemoryFdInfoKHR> importFdInfo = {};
PerPlane<const void *> allocateInfoPtr = {};
};
// Look at provided fds and count the number of planes based on that.
uint32_t GetPlaneCount(const egl::AttributeMap &attribs)
{
// There should always be at least one plane.
ASSERT(attribs.contains(kFds[0]));
ASSERT(attribs.contains(kOffsets[0]));
ASSERT(attribs.contains(kPitches[0]));
for (uint32_t plane = 1; plane < kMaxPlaneCount; ++plane)
{
if (!attribs.contains(kFds[plane]))
{
return plane;
}
ASSERT(attribs.contains(kOffsets[plane]));
ASSERT(attribs.contains(kPitches[plane]));
}
return kMaxPlaneCount;
}
uint64_t GetModifier(const egl::AttributeMap &attribs, EGLenum lo, EGLenum hi)
{
if (!attribs.contains(lo))
{
return 0;
}
ASSERT(attribs.contains(hi));
uint64_t modifier = attribs.getAsInt(hi);
modifier = modifier << 32 | attribs.getAsInt(lo);
return modifier;
}
void GetModifiers(const egl::AttributeMap &attribs,
uint32_t planeCount,
PerPlane<uint64_t> *drmModifiersOut)
{
for (uint32_t plane = 0; plane < planeCount; ++plane)
{
(*drmModifiersOut)[plane] = GetModifier(attribs, kModifiersLo[plane], kModifiersHi[plane]);
}
}
angle::Result GetFormatModifierProperties(DisplayVk *displayVk,
VkFormat vkFormat,
uint64_t drmModifier,
VkDrmFormatModifierPropertiesEXT *modifierPropertiesOut)
{
RendererVk *renderer = displayVk->getRenderer();
// Query list of drm format modifiers compatible with VkFormat.
VkDrmFormatModifierPropertiesListEXT formatModifierPropertiesList = {};
formatModifierPropertiesList.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
formatModifierPropertiesList.drmFormatModifierCount = 0;
VkFormatProperties2 formatProperties = {};
formatProperties.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
formatProperties.pNext = &formatModifierPropertiesList;
vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
&formatProperties);
std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProperties(
formatModifierPropertiesList.drmFormatModifierCount);
formatModifierPropertiesList.pDrmFormatModifierProperties = formatModifierProperties.data();
vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
&formatProperties);
// Find the requested DRM modifiers.
uint32_t propertiesIndex = formatModifierPropertiesList.drmFormatModifierCount;
for (uint32_t index = 0; index < formatModifierPropertiesList.drmFormatModifierCount; ++index)
{
if (formatModifierPropertiesList.pDrmFormatModifierProperties[index].drmFormatModifier ==
drmModifier)
{
propertiesIndex = index;
break;
}
}
// Return the properties if found.
ANGLE_VK_CHECK(displayVk, propertiesIndex < formatModifierPropertiesList.drmFormatModifierCount,
VK_ERROR_FORMAT_NOT_SUPPORTED);
*modifierPropertiesOut =
formatModifierPropertiesList.pDrmFormatModifierProperties[propertiesIndex];
return angle::Result::Continue;
}
VkImageUsageFlags GetUsageFlags(RendererVk *renderer,
const angle::Format &format,
const VkDrmFormatModifierPropertiesEXT &properties,
bool *texturableOut,
bool *renderableOut)
{
const bool isDepthStencilFormat = format.depthBits > 0 || format.stencilBits > 0;
// Check what format features are exposed for this modifier.
constexpr uint32_t kTextureableRequiredBits =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
constexpr uint32_t kDepthStencilRenderableRequiredBits =
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
*texturableOut =
IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kTextureableRequiredBits);
*renderableOut = IsMaskFlagSet(
properties.drmFormatModifierTilingFeatures,
isDepthStencilFormat ? kDepthStencilRenderableRequiredBits : kColorRenderableRequiredBits);
VkImageUsageFlags usage = kTransferUsage;
if (*texturableOut)
{
usage |= kTextureUsage;
}
if (*renderableOut)
{
usage |= isDepthStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
: VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
return usage;
}
bool IsFormatSupported(RendererVk *renderer,
VkFormat vkFormat,
uint64_t drmModifier,
VkImageUsageFlags usageFlags,
VkImageCreateFlags createFlags,
VkImageFormatProperties2 *imageFormatPropertiesOut)
{
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
imageFormatInfo.pNext = &externalMemoryImageCreateInfo;
imageFormatInfo.format = vkFormat;
imageFormatInfo.type = VK_IMAGE_TYPE_2D;
imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageFormatInfo.usage = usageFlags;
imageFormatInfo.flags = createFlags;
VkPhysicalDeviceImageDrmFormatModifierInfoEXT drmFormatModifierInfo = {};
drmFormatModifierInfo.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
drmFormatModifierInfo.pNext = &externalMemoryImageCreateInfo;
drmFormatModifierInfo.drmFormatModifier = drmModifier;
drmFormatModifierInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if (drmModifier != 0)
{
imageFormatInfo.pNext = &drmFormatModifierInfo;
imageFormatInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
}
return vkGetPhysicalDeviceImageFormatProperties2(renderer->getPhysicalDevice(),
&imageFormatInfo, imageFormatPropertiesOut) !=
VK_ERROR_FORMAT_NOT_SUPPORTED;
}
VkChromaLocation GetChromaLocation(const egl::AttributeMap &attribs, EGLenum hint)
{
return attribs.getAsInt(hint, EGL_YUV_CHROMA_SITING_0_EXT) == EGL_YUV_CHROMA_SITING_0_EXT
? VK_CHROMA_LOCATION_COSITED_EVEN
: VK_CHROMA_LOCATION_MIDPOINT;
}
VkSamplerYcbcrModelConversion GetYcbcrModel(const egl::AttributeMap &attribs)
{
switch (attribs.getAsInt(EGL_YUV_COLOR_SPACE_HINT_EXT, EGL_ITU_REC601_EXT))
{
case EGL_ITU_REC601_EXT:
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
case EGL_ITU_REC709_EXT:
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
case EGL_ITU_REC2020_EXT:
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
default:
UNREACHABLE();
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
}
}
VkSamplerYcbcrRange GetYcbcrRange(const egl::AttributeMap &attribs)
{
return attribs.getAsInt(EGL_SAMPLE_RANGE_HINT_EXT, EGL_YUV_FULL_RANGE_EXT) ==
EGL_YUV_FULL_RANGE_EXT
? VK_SAMPLER_YCBCR_RANGE_ITU_FULL
: VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
}
uint32_t GetAllocateInfo(const egl::AttributeMap &attribs,
VkImage image,
uint32_t planeCount,
const VkDrmFormatModifierPropertiesEXT &properties,
AllocateInfo *infoOut)
{
// There are a number of situations:
//
// - If the format tilingFeatures does not have the DISJOINT bit, then allocation and bind is
// done as usual; the fd is used to create the allocation and vkBindImageMemory is called
// without any extra bind info (which would need vkBindImageMemory2).
// - If the format tilingFeatures does have the DISJOINT bit, but all fds are identical, it's
// handled similarly to the non-disjoint case.
// - Otherwise if there are N planes, there must be N allocations and N binds (one per fd).
// When binding, VkBindImagePlaneMemoryInfo is used to identify which plane is being bound.
//
constexpr uint32_t kDisjointBit = VK_FORMAT_FEATURE_DISJOINT_BIT;
bool isDisjoint =
planeCount > 1 && IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kDisjointBit);
if (isDisjoint)
{
bool areFdsIdentical = true;
for (uint32_t plane = 1; plane < planeCount; ++plane)
{
if (attribs.getAsInt(kFds[plane]) != attribs.getAsInt(kFds[0]))
{
areFdsIdentical = false;
break;
}
}
// Treat DISJOINT-but-identical-fds as non-disjoint.
if (areFdsIdentical)
{
isDisjoint = false;
}
}
// Fill in allocateInfo, importFdInfo, bindInfo and bindPlaneInfo first.
const uint32_t planesToAllocate = isDisjoint ? planeCount : 1;
for (uint32_t plane = 0; plane < planesToAllocate; ++plane)
{
infoOut->allocateInfo[plane].sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
infoOut->allocateInfo[plane].pNext = &infoOut->importFdInfo[plane];
infoOut->allocateInfo[plane].image = image;
infoOut->importFdInfo[plane].sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
infoOut->importFdInfo[plane].handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
infoOut->importFdInfo[plane].fd = attribs.getAsInt(kFds[plane]);
infoOut->allocateInfoPtr[plane] = &infoOut->allocateInfo[plane];
}
return planesToAllocate;
}
} // anonymous namespace
DmaBufImageSiblingVkLinux::DmaBufImageSiblingVkLinux(const egl::AttributeMap &attribs)
: mAttribs(attribs),
mFormat(GL_NONE),
mRenderable(false),
mTextureable(false),
mYUV(false),
mSamples(0),
mImage(nullptr)
{
ASSERT(mAttribs.contains(EGL_WIDTH));
ASSERT(mAttribs.contains(EGL_HEIGHT));
mSize.width = mAttribs.getAsInt(EGL_WIDTH);
mSize.height = mAttribs.getAsInt(EGL_HEIGHT);
mSize.depth = 1;
int fourCCFormat = mAttribs.getAsInt(EGL_LINUX_DRM_FOURCC_EXT);
mFormat = gl::Format(angle::DrmFourCCFormatToGLInternalFormat(fourCCFormat, &mYUV));
mHasProtectedContent = mAttribs.getAsInt(EGL_PROTECTED_CONTENT_EXT, false);
}
DmaBufImageSiblingVkLinux::~DmaBufImageSiblingVkLinux() {}
egl::Error DmaBufImageSiblingVkLinux::initialize(const egl::Display *display)
{
DisplayVk *displayVk = vk::GetImpl(display);
return angle::ToEGL(initImpl(displayVk), displayVk, EGL_BAD_PARAMETER);
}
angle::Result DmaBufImageSiblingVkLinux::initImpl(DisplayVk *displayVk)
{
RendererVk *renderer = displayVk->getRenderer();
const vk::Format &vkFormat = renderer->getFormat(mFormat.info->sizedInternalFormat);
const angle::Format &format = vkFormat.getActualImageFormat(rx::vk::ImageAccess::SampleOnly);
const VkFormat vulkanFormat = vkFormat.getActualImageVkFormat(rx::vk::ImageAccess::SampleOnly);
const angle::FormatID intendedFormatID = vkFormat.getIntendedFormatID();
const angle::FormatID actualImageFormatID =
vkFormat.getActualImageFormatID(rx::vk::ImageAccess::SampleOnly);
const uint32_t planeCount = GetPlaneCount(mAttribs);
PerPlane<uint64_t> planeModifiers = {};
GetModifiers(mAttribs, planeCount, &planeModifiers);
// The EGL extension allows for each plane to have a different DRM modifier. This is not
// allowed in Vulkan, and all hardware past and current require the planes to have the same DRM
// modifier. If an application provides different modifiers for the planes, fail.
const uint64_t plane0Modifier = planeModifiers[0];
for (uint32_t plane = 0; plane < planeCount; ++plane)
{
ANGLE_VK_CHECK(displayVk, planeModifiers[plane] == plane0Modifier,
VK_ERROR_INCOMPATIBLE_DRIVER);
}
// First, check the possible features for the format and determine usage and create flags.
VkDrmFormatModifierPropertiesEXT modifierProperties = {};
ANGLE_TRY(
GetFormatModifierProperties(displayVk, vulkanFormat, plane0Modifier, &modifierProperties));
VkImageUsageFlags usageFlags =
GetUsageFlags(renderer, format, modifierProperties, &mTextureable, &mRenderable);
const VkImageCreateFlags createFlags =
vk::kVkImageCreateFlagsNone | (hasProtectedContent() ? VK_IMAGE_CREATE_PROTECTED_BIT : 0);
// The Vulkan and EGL plane counts are expected to match.
ANGLE_VK_CHECK(displayVk, modifierProperties.drmFormatModifierPlaneCount == planeCount,
VK_ERROR_INCOMPATIBLE_DRIVER);
// Verify that such a usage is compatible with the provided modifiers, if any. If not, try to
// remove features until it is.
VkExternalImageFormatProperties externalFormatProperties = {};
externalFormatProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
VkImageFormatProperties2 imageFormatProperties = {};
imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
imageFormatProperties.pNext = &externalFormatProperties;
if (!IsFormatSupported(renderer, vulkanFormat, plane0Modifier, usageFlags, createFlags,
&imageFormatProperties))
{
mRenderable = false;
usageFlags &= ~kRenderUsage;
if (!IsFormatSupported(renderer, vulkanFormat, plane0Modifier, usageFlags, createFlags,
&imageFormatProperties))
{
mTextureable = false;
usageFlags &= ~kTextureUsage;
if (!IsFormatSupported(renderer, vulkanFormat, plane0Modifier, usageFlags, createFlags,
&imageFormatProperties))
{
// The image is completely unusable.
ANGLE_VK_CHECK(displayVk, false, VK_ERROR_FORMAT_NOT_SUPPORTED);
}
}
}
// Make sure image width/height/samples are within allowed range and the image is importable.
const bool isWidthValid = static_cast<uint32_t>(mSize.width) <=
imageFormatProperties.imageFormatProperties.maxExtent.width;
const bool isHeightValid = static_cast<uint32_t>(mSize.height) <=
imageFormatProperties.imageFormatProperties.maxExtent.height;
const bool isSampleCountValid =
(imageFormatProperties.imageFormatProperties.sampleCounts & VK_SAMPLE_COUNT_1_BIT) != 0;
const bool isMemoryImportable =
(externalFormatProperties.externalMemoryProperties.externalMemoryFeatures &
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) == 0;
ANGLE_VK_CHECK(displayVk,
isWidthValid && isHeightValid && isSampleCountValid && isMemoryImportable,
VK_ERROR_INCOMPATIBLE_DRIVER);
std::vector<VkSubresourceLayout> planes(planeCount, VkSubresourceLayout{});
for (uint32_t plane = 0; plane < planeCount; ++plane)
{
planes[plane].offset = mAttribs.getAsInt(kOffsets[plane]);
planes[plane].rowPitch = mAttribs.getAsInt(kPitches[plane]);
}
VkImageDrmFormatModifierExplicitCreateInfoEXT imageDrmModifierCreateInfo = {};
imageDrmModifierCreateInfo.sType =
VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
imageDrmModifierCreateInfo.drmFormatModifier = plane0Modifier;
imageDrmModifierCreateInfo.drmFormatModifierPlaneCount = planeCount;
imageDrmModifierCreateInfo.pPlaneLayouts = planes.data();
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
externalMemoryImageCreateInfo.pNext = &imageDrmModifierCreateInfo;
externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
// Create the image
mImage = new vk::ImageHelper();
VkExtent3D vkExtents;
gl_vk::GetExtent(mSize, &vkExtents);
constexpr bool kIsRobustInitEnabled = false;
ANGLE_TRY(mImage->initExternal(displayVk, gl::TextureType::_2D, vkExtents, intendedFormatID,
actualImageFormatID, 1, usageFlags, createFlags,
vk::ImageLayout::ExternalPreInitialized,
&externalMemoryImageCreateInfo, gl::LevelIndex(0), 1, 1,
kIsRobustInitEnabled, nullptr, hasProtectedContent()));
VkMemoryRequirements externalMemoryRequirements;
mImage->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
const VkMemoryPropertyFlags flags =
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
(hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
VkSamplerYcbcrConversionCreateInfo yuvConversionInfo = {};
VkSamplerYcbcrConversionCreateInfo *yuvConversionInfoPtr = nullptr;
if (mYUV)
{
const VkChromaLocation xChromaOffset =
GetChromaLocation(mAttribs, EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT);
const VkChromaLocation yChromaOffset =
GetChromaLocation(mAttribs, EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT);
const VkSamplerYcbcrModelConversion model = GetYcbcrModel(mAttribs);
const VkSamplerYcbcrRange range = GetYcbcrRange(mAttribs);
ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
VK_ERROR_FEATURE_NOT_PRESENT);
yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
yuvConversionInfo.format = vulkanFormat;
yuvConversionInfo.xChromaOffset = xChromaOffset;
yuvConversionInfo.yChromaOffset = yChromaOffset;
yuvConversionInfo.ycbcrModel = model;
yuvConversionInfo.ycbcrRange = range;
yuvConversionInfo.chromaFilter = VK_FILTER_NEAREST;
// yuvConversionInfo.components = {}; // TODO: swizzle?
yuvConversionInfoPtr = &yuvConversionInfo;
}
AllocateInfo allocateInfo;
const uint32_t allocateInfoCount = GetAllocateInfo(
mAttribs, mImage->getImage().getHandle(), planeCount, modifierProperties, &allocateInfo);
return mImage->initExternalMemory(displayVk, renderer->getMemoryProperties(),
externalMemoryRequirements, yuvConversionInfoPtr,
allocateInfoCount, allocateInfo.allocateInfoPtr.data(),
VK_QUEUE_FAMILY_FOREIGN_EXT, flags);
}
void DmaBufImageSiblingVkLinux::onDestroy(const egl::Display *display)
{
ASSERT(mImage == nullptr);
}
gl::Format DmaBufImageSiblingVkLinux::getFormat() const
{
return mFormat;
}
bool DmaBufImageSiblingVkLinux::isRenderable(const gl::Context *context) const
{
return mRenderable;
}
bool DmaBufImageSiblingVkLinux::isTexturable(const gl::Context *context) const
{
return mTextureable;
}
bool DmaBufImageSiblingVkLinux::isYUV() const
{
return mYUV;
}
bool DmaBufImageSiblingVkLinux::hasProtectedContent() const
{
return mHasProtectedContent;
}
gl::Extents DmaBufImageSiblingVkLinux::getSize() const
{
return mSize;
}
size_t DmaBufImageSiblingVkLinux::getSamples() const
{
return mSamples;
}
// ExternalImageSiblingVk interface
vk::ImageHelper *DmaBufImageSiblingVkLinux::getImage() const
{
return mImage;
}
void DmaBufImageSiblingVkLinux::release(RendererVk *renderer)
{
if (mImage != nullptr)
{
// TODO: Handle the case where the EGLImage is used in two contexts not in the same share
// group. https://issuetracker.google.com/169868803
mImage->releaseImage(renderer);
mImage->releaseStagingBuffer(renderer);
SafeDelete(mImage);
}
}
} // namespace rx

Просмотреть файл

@ -0,0 +1,59 @@
//
// Copyright 2021 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.
//
// DmaBufImageSiblingVkLinux.h: Defines the DmaBufImageSiblingVkLinux to wrap
// EGL images created from Linux dma-buf objects
#ifndef LIBANGLE_RENDERER_VULKAN_LINUX_DMABUFIMAGESIBLINGVKLINUX_H_
#define LIBANGLE_RENDERER_VULKAN_LINUX_DMABUFIMAGESIBLINGVKLINUX_H_
#include "libANGLE/renderer/vulkan/ImageVk.h"
namespace rx
{
class DmaBufImageSiblingVkLinux : public ExternalImageSiblingVk
{
public:
DmaBufImageSiblingVkLinux(const egl::AttributeMap &attribs);
~DmaBufImageSiblingVkLinux() override;
egl::Error initialize(const egl::Display *display) override;
void onDestroy(const egl::Display *display) override;
// ExternalImageSiblingImpl interface
gl::Format getFormat() const override;
bool isRenderable(const gl::Context *context) const override;
bool isTexturable(const gl::Context *context) const override;
bool isYUV() const override;
bool hasProtectedContent() const override;
gl::Extents getSize() const override;
size_t getSamples() const override;
// ExternalImageSiblingVk interface
vk::ImageHelper *getImage() const override;
void release(RendererVk *renderer) override;
private:
angle::Result initImpl(DisplayVk *displayVk);
egl::AttributeMap mAttribs;
gl::Extents mSize;
gl::Format mFormat;
bool mRenderable;
bool mTextureable;
bool mYUV;
bool mHasProtectedContent;
size_t mSamples;
vk::ImageHelper *mImage;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_LINUX_DMABUFIMAGESIBLINGVKLINUX_H_

Просмотреть файл

@ -17,7 +17,7 @@
namespace rx
{
DisplayVkSimple::DisplayVkSimple(const egl::DisplayState &state) : DisplayVk(state) {}
DisplayVkSimple::DisplayVkSimple(const egl::DisplayState &state) : DisplayVkLinux(state) {}
void DisplayVkSimple::terminate()
{

Просмотреть файл

@ -11,12 +11,12 @@
#ifndef LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKSIMPLE_H_
#define LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKSIMPLE_H_
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/linux/DisplayVkLinux.h"
namespace rx
{
class DisplayVkSimple : public DisplayVk
class DisplayVkSimple : public DisplayVkLinux
{
public:
DisplayVkSimple(const egl::DisplayState &state);

Просмотреть файл

@ -17,7 +17,7 @@
namespace rx
{
DisplayVkHeadless::DisplayVkHeadless(const egl::DisplayState &state) : DisplayVk(state) {}
DisplayVkHeadless::DisplayVkHeadless(const egl::DisplayState &state) : DisplayVkLinux(state) {}
void DisplayVkHeadless::terminate()
{

Просмотреть файл

@ -11,12 +11,12 @@
#ifndef LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKHEADLESS_H_
#define LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKHEADLESS_H_
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/linux/DisplayVkLinux.h"
namespace rx
{
class DisplayVkHeadless : public DisplayVk
class DisplayVkHeadless : public DisplayVkLinux
{
public:
DisplayVkHeadless(const egl::DisplayState &state);

Просмотреть файл

@ -7,15 +7,15 @@
// Implements the class methods for DisplayVkXcb.
//
#include "libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h"
#include "libANGLE/renderer/vulkan/linux/xcb/DisplayVkXcb.h"
#include <X11/Xutil.h>
#include <xcb/xcb.h>
#include "common/system_utils.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/linux/xcb/WindowSurfaceVkXcb.h"
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
#include "libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h"
namespace rx
{
@ -43,7 +43,7 @@ EGLint GetXcbVisualType(xcb_screen_t *screen)
} // namespace
DisplayVkXcb::DisplayVkXcb(const egl::DisplayState &state)
: DisplayVk(state), mXcbConnection(nullptr), mHasXDisplay(false)
: DisplayVkLinux(state), mXcbConnection(nullptr), mHasXDisplay(false)
{}
egl::Error DisplayVkXcb::initialize(egl::Display *display)

Просмотреть файл

@ -10,14 +10,14 @@
#ifndef LIBANGLE_RENDERER_VULKAN_XCB_DISPLAYVKXCB_H_
#define LIBANGLE_RENDERER_VULKAN_XCB_DISPLAYVKXCB_H_
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/linux/DisplayVkLinux.h"
struct xcb_connection_t;
namespace rx
{
class DisplayVkXcb : public DisplayVk
class DisplayVkXcb : public DisplayVkLinux
{
public:
DisplayVkXcb(const egl::DisplayState &state);

Просмотреть файл

@ -7,7 +7,7 @@
// Implements the class methods for WindowSurfaceVkXcb.
//
#include "libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h"
#include "libANGLE/renderer/vulkan/linux/xcb/WindowSurfaceVkXcb.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"

Просмотреть файл

@ -4362,13 +4362,35 @@ angle::Result ImageHelper::initExternalMemory(
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const VkSamplerYcbcrConversionCreateInfo *samplerYcbcrConversionCreateInfo,
const void *extraAllocationInfo,
uint32_t extraAllocationInfoCount,
const void **extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
VkMemoryPropertyFlags flags)
{
// TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
ANGLE_TRY(AllocateImageMemoryWithRequirements(context, flags, memoryRequirements,
extraAllocationInfo, &mImage, &mDeviceMemory));
// Vulkan allows up to 4 memory planes.
constexpr size_t kMaxMemoryPlanes = 4;
constexpr VkImageAspectFlagBits kMemoryPlaneAspects[kMaxMemoryPlanes] = {
VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
};
ASSERT(extraAllocationInfoCount <= kMaxMemoryPlanes);
VkBindImagePlaneMemoryInfoKHR bindImagePlaneMemoryInfo = {};
bindImagePlaneMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
const VkBindImagePlaneMemoryInfoKHR *bindImagePlaneMemoryInfoPtr =
extraAllocationInfoCount == 1 ? nullptr : &bindImagePlaneMemoryInfo;
for (uint32_t memoryPlane = 0; memoryPlane < extraAllocationInfoCount; ++memoryPlane)
{
bindImagePlaneMemoryInfo.planeAspect = kMemoryPlaneAspects[memoryPlane];
ANGLE_TRY(AllocateImageMemoryWithRequirements(
context, flags, memoryRequirements, extraAllocationInfo[memoryPlane],
bindImagePlaneMemoryInfoPtr, &mImage, &mDeviceMemory));
}
mCurrentQueueFamilyIndex = currentQueueFamilyIndex;
#ifdef VK_USE_PLATFORM_ANDROID_KHR

Просмотреть файл

@ -1480,7 +1480,8 @@ class ImageHelper final : public Resource, public angle::Subject
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const VkSamplerYcbcrConversionCreateInfo *samplerYcbcrConversionCreateInfo,
const void *extraAllocationInfo,
uint32_t extraAllocationInfoCount,
const void **extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
VkMemoryPropertyFlags flags);
angle::Result initLayerImageView(Context *context,

Просмотреть файл

@ -124,7 +124,18 @@ angle::Result AllocateAndBindBufferOrImageMemory(vk::Context *context,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
const VkBindImagePlaneMemoryInfoKHR *extraBindInfo,
T *bufferOrImage,
vk::DeviceMemory *deviceMemoryOut);
template <>
angle::Result AllocateAndBindBufferOrImageMemory(vk::Context *context,
VkMemoryPropertyFlags requestedMemoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
const VkBindImagePlaneMemoryInfoKHR *extraBindInfo,
vk::Image *image,
vk::DeviceMemory *deviceMemoryOut)
{
const vk::MemoryProperties &memoryProperties = context->getRenderer()->getMemoryProperties();
@ -132,7 +143,44 @@ angle::Result AllocateAndBindBufferOrImageMemory(vk::Context *context,
ANGLE_TRY(FindAndAllocateCompatibleMemory(
context, memoryProperties, requestedMemoryPropertyFlags, memoryPropertyFlagsOut,
memoryRequirements, extraAllocationInfo, deviceMemoryOut));
ANGLE_VK_TRY(context, bufferOrImage->bindMemory(context->getDevice(), *deviceMemoryOut));
if (extraBindInfo)
{
VkBindImageMemoryInfoKHR bindInfo = {};
bindInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
bindInfo.pNext = extraBindInfo;
bindInfo.image = image->getHandle();
bindInfo.memory = deviceMemoryOut->getHandle();
bindInfo.memoryOffset = 0;
ANGLE_VK_TRY(context, image->bindMemory2(context->getDevice(), bindInfo));
}
else
{
ANGLE_VK_TRY(context, image->bindMemory(context->getDevice(), *deviceMemoryOut));
}
return angle::Result::Continue;
}
template <>
angle::Result AllocateAndBindBufferOrImageMemory(vk::Context *context,
VkMemoryPropertyFlags requestedMemoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
const VkBindImagePlaneMemoryInfoKHR *extraBindInfo,
vk::Buffer *buffer,
vk::DeviceMemory *deviceMemoryOut)
{
ASSERT(extraBindInfo == nullptr);
const vk::MemoryProperties &memoryProperties = context->getRenderer()->getMemoryProperties();
ANGLE_TRY(FindAndAllocateCompatibleMemory(
context, memoryProperties, requestedMemoryPropertyFlags, memoryPropertyFlagsOut,
memoryRequirements, extraAllocationInfo, deviceMemoryOut));
ANGLE_VK_TRY(context, buffer->bindMemory(context->getDevice(), *deviceMemoryOut));
return angle::Result::Continue;
}
@ -151,7 +199,7 @@ angle::Result AllocateBufferOrImageMemory(vk::Context *context,
ANGLE_TRY(AllocateAndBindBufferOrImageMemory(
context, requestedMemoryPropertyFlags, memoryPropertyFlagsOut, memoryRequirements,
extraAllocationInfo, bufferOrImage, deviceMemoryOut));
extraAllocationInfo, nullptr, bufferOrImage, deviceMemoryOut));
*sizeOut = memoryRequirements.size;
@ -565,17 +613,19 @@ angle::Result AllocateImageMemory(Context *context,
extraAllocationInfo, image, deviceMemoryOut, sizeOut);
}
angle::Result AllocateImageMemoryWithRequirements(Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
Image *image,
DeviceMemory *deviceMemoryOut)
angle::Result AllocateImageMemoryWithRequirements(
Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
const VkBindImagePlaneMemoryInfoKHR *extraBindInfo,
Image *image,
DeviceMemory *deviceMemoryOut)
{
VkMemoryPropertyFlags memoryPropertyFlagsOut = 0;
return AllocateAndBindBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut,
memoryRequirements, extraAllocationInfo, image,
deviceMemoryOut);
memoryRequirements, extraAllocationInfo,
extraBindInfo, image, deviceMemoryOut);
}
angle::Result AllocateBufferMemoryWithRequirements(Context *context,
@ -587,8 +637,8 @@ angle::Result AllocateBufferMemoryWithRequirements(Context *context,
DeviceMemory *deviceMemoryOut)
{
return AllocateAndBindBufferOrImageMemory(context, memoryPropertyFlags, memoryPropertyFlagsOut,
memoryRequirements, extraAllocationInfo, buffer,
deviceMemoryOut);
memoryRequirements, extraAllocationInfo, nullptr,
buffer, deviceMemoryOut);
}
angle::Result InitShaderAndSerial(Context *context,

Просмотреть файл

@ -404,12 +404,14 @@ angle::Result AllocateImageMemory(Context *context,
DeviceMemory *deviceMemoryOut,
VkDeviceSize *sizeOut);
angle::Result AllocateImageMemoryWithRequirements(Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
Image *image,
DeviceMemory *deviceMemoryOut);
angle::Result AllocateImageMemoryWithRequirements(
Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
const VkBindImagePlaneMemoryInfoKHR *extraBindInfo,
Image *image,
DeviceMemory *deviceMemoryOut);
angle::Result AllocateBufferMemoryWithRequirements(Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,

Просмотреть файл

@ -411,6 +411,7 @@ class Image final : public WrappedObject<Image, VkImage>
void getMemoryRequirements(VkDevice device, VkMemoryRequirements *requirementsOut) const;
VkResult bindMemory(VkDevice device, const DeviceMemory &deviceMemory);
VkResult bindMemory2(VkDevice device, const VkBindImageMemoryInfoKHR &bindInfo);
void getSubresourceLayout(VkDevice device,
VkImageAspectFlagBits aspectMask,
@ -1300,6 +1301,12 @@ ANGLE_INLINE VkResult Image::bindMemory(VkDevice device, const vk::DeviceMemory
return vkBindImageMemory(device, mHandle, deviceMemory.getHandle(), 0);
}
ANGLE_INLINE VkResult Image::bindMemory2(VkDevice device, const VkBindImageMemoryInfoKHR &bindInfo)
{
ASSERT(valid());
return vkBindImageMemory2KHR(device, 1, &bindInfo);
}
ANGLE_INLINE void Image::getSubresourceLayout(VkDevice device,
VkImageAspectFlagBits aspectMask,
uint32_t mipLevel,