| // |
| // 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" |
| |
| #include <fcntl.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, |
| VkImageFormatListCreateInfoKHR imageFormatListInfo, |
| VkImageFormatProperties2 *imageFormatPropertiesOut) |
| { |
| VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {}; |
| externalImageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; |
| externalImageFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; |
| |
| VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {}; |
| imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; |
| imageFormatInfo.pNext = &externalImageFormatInfo; |
| 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.drmFormatModifier = drmModifier; |
| drmFormatModifierInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| if (drmModifier != 0) |
| { |
| externalImageFormatInfo.pNext = &drmFormatModifierInfo; |
| imageFormatListInfo.pNext = &externalImageFormatInfo; |
| imageFormatInfo.pNext = &imageFormatListInfo; |
| 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; |
| } |
| |
| angle::Result GetAllocateInfo(const egl::AttributeMap &attribs, |
| VkImage image, |
| uint32_t planeCount, |
| const VkDrmFormatModifierPropertiesEXT &properties, |
| AllocateInfo *infoOut, |
| uint32_t *infoCountOut) |
| { |
| // 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. |
| *infoCountOut = isDisjoint ? planeCount : 1; |
| for (uint32_t plane = 0; plane < *infoCountOut; ++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_DMA_BUF_BIT_EXT; |
| |
| // Vulkan takes ownership of the FD, closed on vkFreeMemory. |
| int dfd = fcntl(attribs.getAsInt(kFds[plane]), F_DUPFD_CLOEXEC, 0); |
| if (dfd < 0) |
| { |
| ERR() << "failed to duplicate fd for dma_buf import" << std::endl; |
| return angle::Result::Stop; |
| } |
| infoOut->importFdInfo[plane].fd = dfd; |
| |
| infoOut->allocateInfoPtr[plane] = &infoOut->allocateInfo[plane]; |
| } |
| |
| return angle::Result::Continue; |
| } |
| } // 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); |
| |
| 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; |
| |
| 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; |
| |
| VkImageFormatListCreateInfoKHR imageFormatListCreateInfo; |
| vk::ImageHelper::ImageListFormats imageListFormatsStorage; |
| const void *imageCreateInfoPNext = vk::ImageHelper::DeriveCreateInfoPNext( |
| displayVk, actualImageFormatID, &externalMemoryImageCreateInfo, &imageFormatListCreateInfo, |
| &imageListFormatsStorage, &createFlags); |
| |
| if (!IsFormatSupported(renderer, vulkanFormat, plane0Modifier, usageFlags, createFlags, |
| imageFormatListCreateInfo, &imageFormatProperties)) |
| { |
| mRenderable = false; |
| usageFlags &= ~kRenderUsage; |
| if (!IsFormatSupported(renderer, vulkanFormat, plane0Modifier, usageFlags, createFlags, |
| imageFormatListCreateInfo, &imageFormatProperties)) |
| { |
| mTextureable = false; |
| usageFlags &= ~kTextureUsage; |
| |
| if (!IsFormatSupported(renderer, vulkanFormat, plane0Modifier, usageFlags, createFlags, |
| imageFormatListCreateInfo, &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); |
| |
| // 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, imageCreateInfoPNext, |
| gl::LevelIndex(0), 1, 1, kIsRobustInitEnabled, 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); |
| |
| 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); |
| const VkComponentMapping components = { |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| }; |
| |
| ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled, |
| VK_ERROR_FEATURE_NOT_PRESENT); |
| |
| mImage->updateYcbcrConversionDesc(renderer, 0, model, range, xChromaOffset, yChromaOffset, |
| VK_FILTER_NEAREST, components, intendedFormatID); |
| } |
| |
| AllocateInfo allocateInfo; |
| uint32_t allocateInfoCount; |
| ANGLE_TRY(GetAllocateInfo(mAttribs, mImage->getImage().getHandle(), planeCount, |
| modifierProperties, &allocateInfo, &allocateInfoCount)); |
| |
| return mImage->initExternalMemory( |
| displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, 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->releaseStagedUpdates(renderer); |
| SafeDelete(mImage); |
| } |
| } |
| |
| } // namespace rx |