• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // DmaBufImageSiblingVkLinux.cpp: Implements DmaBufImageSiblingVkLinux.
8 
9 #include "libANGLE/renderer/vulkan/linux/DmaBufImageSiblingVkLinux.h"
10 
11 #include "common/linux/dma_buf_utils.h"
12 #include "libANGLE/Display.h"
13 #include "libANGLE/renderer/vulkan/DisplayVk.h"
14 #include "libANGLE/renderer/vulkan/RendererVk.h"
15 
16 #include <fcntl.h>
17 
18 namespace rx
19 {
20 namespace
21 {
22 constexpr uint32_t kMaxPlaneCount = 4;
23 template <typename T>
24 using PerPlane = std::array<T, kMaxPlaneCount>;
25 
26 constexpr PerPlane<EGLenum> kFds = {EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE1_FD_EXT,
27                                     EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE3_FD_EXT};
28 
29 constexpr PerPlane<EGLenum> kOffsets = {
30     EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT,
31     EGL_DMA_BUF_PLANE3_OFFSET_EXT};
32 
33 constexpr PerPlane<EGLenum> kPitches = {EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT,
34                                         EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT};
35 
36 constexpr PerPlane<EGLenum> kModifiersLo = {
37     EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
38     EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT};
39 
40 constexpr PerPlane<EGLenum> kModifiersHi = {
41     EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
42     EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT};
43 
44 constexpr VkImageUsageFlags kTransferUsage =
45     VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
46 constexpr VkImageUsageFlags kTextureUsage =
47     VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
48 constexpr VkImageUsageFlags kRenderUsage =
49     VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
50 
51 struct AllocateInfo
52 {
53     PerPlane<VkMemoryDedicatedAllocateInfo> allocateInfo = {};
54     PerPlane<VkImportMemoryFdInfoKHR> importFdInfo       = {};
55 
56     PerPlane<const void *> allocateInfoPtr = {};
57 };
58 
59 // Look at provided fds and count the number of planes based on that.
GetPlaneCount(const egl::AttributeMap & attribs)60 uint32_t GetPlaneCount(const egl::AttributeMap &attribs)
61 {
62     // There should always be at least one plane.
63     ASSERT(attribs.contains(kFds[0]));
64     ASSERT(attribs.contains(kOffsets[0]));
65     ASSERT(attribs.contains(kPitches[0]));
66 
67     for (uint32_t plane = 1; plane < kMaxPlaneCount; ++plane)
68     {
69         if (!attribs.contains(kFds[plane]))
70         {
71             return plane;
72         }
73 
74         ASSERT(attribs.contains(kOffsets[plane]));
75         ASSERT(attribs.contains(kPitches[plane]));
76     }
77 
78     return kMaxPlaneCount;
79 }
80 
GetModifier(const egl::AttributeMap & attribs,EGLenum lo,EGLenum hi)81 uint64_t GetModifier(const egl::AttributeMap &attribs, EGLenum lo, EGLenum hi)
82 {
83     if (!attribs.contains(lo))
84     {
85         return 0;
86     }
87 
88     ASSERT(attribs.contains(hi));
89 
90     uint64_t modifier = attribs.getAsInt(hi);
91     modifier          = modifier << 32 | attribs.getAsInt(lo);
92 
93     return modifier;
94 }
95 
GetModifiers(const egl::AttributeMap & attribs,uint32_t planeCount,PerPlane<uint64_t> * drmModifiersOut)96 void GetModifiers(const egl::AttributeMap &attribs,
97                   uint32_t planeCount,
98                   PerPlane<uint64_t> *drmModifiersOut)
99 {
100     for (uint32_t plane = 0; plane < planeCount; ++plane)
101     {
102         (*drmModifiersOut)[plane] = GetModifier(attribs, kModifiersLo[plane], kModifiersHi[plane]);
103     }
104 }
105 
GetFormatModifierProperties(DisplayVk * displayVk,VkFormat vkFormat,uint64_t drmModifier,VkDrmFormatModifierPropertiesEXT * modifierPropertiesOut)106 angle::Result GetFormatModifierProperties(DisplayVk *displayVk,
107                                           VkFormat vkFormat,
108                                           uint64_t drmModifier,
109                                           VkDrmFormatModifierPropertiesEXT *modifierPropertiesOut)
110 {
111     RendererVk *renderer = displayVk->getRenderer();
112 
113     // Query list of drm format modifiers compatible with VkFormat.
114     VkDrmFormatModifierPropertiesListEXT formatModifierPropertiesList = {};
115     formatModifierPropertiesList.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
116     formatModifierPropertiesList.drmFormatModifierCount = 0;
117 
118     VkFormatProperties2 formatProperties = {};
119     formatProperties.sType               = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
120     formatProperties.pNext               = &formatModifierPropertiesList;
121 
122     vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
123                                          &formatProperties);
124 
125     std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProperties(
126         formatModifierPropertiesList.drmFormatModifierCount);
127     formatModifierPropertiesList.pDrmFormatModifierProperties = formatModifierProperties.data();
128 
129     vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
130                                          &formatProperties);
131 
132     // Find the requested DRM modifiers.
133     uint32_t propertiesIndex = formatModifierPropertiesList.drmFormatModifierCount;
134     for (uint32_t index = 0; index < formatModifierPropertiesList.drmFormatModifierCount; ++index)
135     {
136         if (formatModifierPropertiesList.pDrmFormatModifierProperties[index].drmFormatModifier ==
137             drmModifier)
138         {
139             propertiesIndex = index;
140             break;
141         }
142     }
143 
144     // Return the properties if found.
145     ANGLE_VK_CHECK(displayVk, propertiesIndex < formatModifierPropertiesList.drmFormatModifierCount,
146                    VK_ERROR_FORMAT_NOT_SUPPORTED);
147 
148     *modifierPropertiesOut =
149         formatModifierPropertiesList.pDrmFormatModifierProperties[propertiesIndex];
150     return angle::Result::Continue;
151 }
152 
GetUsageFlags(RendererVk * renderer,const angle::Format & format,const VkDrmFormatModifierPropertiesEXT & properties,bool * texturableOut,bool * renderableOut)153 VkImageUsageFlags GetUsageFlags(RendererVk *renderer,
154                                 const angle::Format &format,
155                                 const VkDrmFormatModifierPropertiesEXT &properties,
156                                 bool *texturableOut,
157                                 bool *renderableOut)
158 {
159     const bool isDepthStencilFormat = format.depthBits > 0 || format.stencilBits > 0;
160 
161     // Check what format features are exposed for this modifier.
162     constexpr uint32_t kTextureableRequiredBits =
163         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
164     constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
165     constexpr uint32_t kDepthStencilRenderableRequiredBits =
166         VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
167 
168     *texturableOut =
169         IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kTextureableRequiredBits);
170     *renderableOut = IsMaskFlagSet(
171         properties.drmFormatModifierTilingFeatures,
172         isDepthStencilFormat ? kDepthStencilRenderableRequiredBits : kColorRenderableRequiredBits);
173 
174     VkImageUsageFlags usage = kTransferUsage;
175     if (*texturableOut)
176     {
177         usage |= kTextureUsage;
178     }
179     if (*renderableOut)
180     {
181         usage |= isDepthStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
182                                       : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
183     }
184 
185     return usage;
186 }
187 
IsFormatSupported(RendererVk * renderer,VkFormat vkFormat,uint64_t drmModifier,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,VkImageFormatListCreateInfoKHR imageFormatListInfo,VkImageFormatProperties2 * imageFormatPropertiesOut)188 bool IsFormatSupported(RendererVk *renderer,
189                        VkFormat vkFormat,
190                        uint64_t drmModifier,
191                        VkImageUsageFlags usageFlags,
192                        VkImageCreateFlags createFlags,
193                        VkImageFormatListCreateInfoKHR imageFormatListInfo,
194                        VkImageFormatProperties2 *imageFormatPropertiesOut)
195 {
196     VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {};
197     externalImageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
198     externalImageFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
199 
200     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
201     imageFormatInfo.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
202     imageFormatInfo.pNext  = &externalImageFormatInfo;
203     imageFormatInfo.format = vkFormat;
204     imageFormatInfo.type   = VK_IMAGE_TYPE_2D;
205     imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
206     imageFormatInfo.usage  = usageFlags;
207     imageFormatInfo.flags  = createFlags;
208 
209     VkPhysicalDeviceImageDrmFormatModifierInfoEXT drmFormatModifierInfo = {};
210     drmFormatModifierInfo.sType =
211         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
212     drmFormatModifierInfo.drmFormatModifier = drmModifier;
213     drmFormatModifierInfo.sharingMode       = VK_SHARING_MODE_EXCLUSIVE;
214     if (drmModifier != 0)
215     {
216         externalImageFormatInfo.pNext = &drmFormatModifierInfo;
217         imageFormatListInfo.pNext     = &externalImageFormatInfo;
218         imageFormatInfo.pNext         = &imageFormatListInfo;
219         imageFormatInfo.tiling        = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
220     }
221 
222     return vkGetPhysicalDeviceImageFormatProperties2(renderer->getPhysicalDevice(),
223                                                      &imageFormatInfo, imageFormatPropertiesOut) !=
224            VK_ERROR_FORMAT_NOT_SUPPORTED;
225 }
226 
GetChromaLocation(const egl::AttributeMap & attribs,EGLenum hint)227 VkChromaLocation GetChromaLocation(const egl::AttributeMap &attribs, EGLenum hint)
228 {
229     return attribs.getAsInt(hint, EGL_YUV_CHROMA_SITING_0_EXT) == EGL_YUV_CHROMA_SITING_0_EXT
230                ? VK_CHROMA_LOCATION_COSITED_EVEN
231                : VK_CHROMA_LOCATION_MIDPOINT;
232 }
233 
GetYcbcrModel(const egl::AttributeMap & attribs)234 VkSamplerYcbcrModelConversion GetYcbcrModel(const egl::AttributeMap &attribs)
235 {
236     switch (attribs.getAsInt(EGL_YUV_COLOR_SPACE_HINT_EXT, EGL_ITU_REC601_EXT))
237     {
238         case EGL_ITU_REC601_EXT:
239             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
240         case EGL_ITU_REC709_EXT:
241             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
242         case EGL_ITU_REC2020_EXT:
243             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
244         default:
245             UNREACHABLE();
246             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
247     }
248 }
249 
GetYcbcrRange(const egl::AttributeMap & attribs)250 VkSamplerYcbcrRange GetYcbcrRange(const egl::AttributeMap &attribs)
251 {
252     return attribs.getAsInt(EGL_SAMPLE_RANGE_HINT_EXT, EGL_YUV_FULL_RANGE_EXT) ==
253                    EGL_YUV_FULL_RANGE_EXT
254                ? VK_SAMPLER_YCBCR_RANGE_ITU_FULL
255                : VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
256 }
257 
GetAllocateInfo(const egl::AttributeMap & attribs,VkImage image,uint32_t planeCount,const VkDrmFormatModifierPropertiesEXT & properties,AllocateInfo * infoOut,uint32_t * infoCountOut)258 angle::Result GetAllocateInfo(const egl::AttributeMap &attribs,
259                               VkImage image,
260                               uint32_t planeCount,
261                               const VkDrmFormatModifierPropertiesEXT &properties,
262                               AllocateInfo *infoOut,
263                               uint32_t *infoCountOut)
264 {
265     // There are a number of situations:
266     //
267     // - If the format tilingFeatures does not have the DISJOINT bit, then allocation and bind is
268     //   done as usual; the fd is used to create the allocation and vkBindImageMemory is called
269     //   without any extra bind info (which would need vkBindImageMemory2).
270     // - If the format tilingFeatures does have the DISJOINT bit, but all fds are identical, it's
271     //   handled similarly to the non-disjoint case.
272     // - Otherwise if there are N planes, there must be N allocations and N binds (one per fd).
273     //   When binding, VkBindImagePlaneMemoryInfo is used to identify which plane is being bound.
274     //
275     constexpr uint32_t kDisjointBit = VK_FORMAT_FEATURE_DISJOINT_BIT;
276     bool isDisjoint =
277         planeCount > 1 && IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kDisjointBit);
278     if (isDisjoint)
279     {
280         bool areFdsIdentical = true;
281         for (uint32_t plane = 1; plane < planeCount; ++plane)
282         {
283             if (attribs.getAsInt(kFds[plane]) != attribs.getAsInt(kFds[0]))
284             {
285                 areFdsIdentical = false;
286                 break;
287             }
288         }
289 
290         // Treat DISJOINT-but-identical-fds as non-disjoint.
291         if (areFdsIdentical)
292         {
293             isDisjoint = false;
294         }
295     }
296 
297     // Fill in allocateInfo, importFdInfo, bindInfo and bindPlaneInfo first.
298     *infoCountOut = isDisjoint ? planeCount : 1;
299     for (uint32_t plane = 0; plane < *infoCountOut; ++plane)
300     {
301         infoOut->allocateInfo[plane].sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
302         infoOut->allocateInfo[plane].pNext = &infoOut->importFdInfo[plane];
303         infoOut->allocateInfo[plane].image = image;
304 
305         infoOut->importFdInfo[plane].sType      = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
306         infoOut->importFdInfo[plane].handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
307 
308         // Vulkan takes ownership of the FD, closed on vkFreeMemory.
309         int dfd = fcntl(attribs.getAsInt(kFds[plane]), F_DUPFD_CLOEXEC, 0);
310         if (dfd < 0)
311         {
312             ERR() << "failed to duplicate fd for dma_buf import" << std::endl;
313             return angle::Result::Stop;
314         }
315         infoOut->importFdInfo[plane].fd = dfd;
316 
317         infoOut->allocateInfoPtr[plane] = &infoOut->allocateInfo[plane];
318     }
319 
320     return angle::Result::Continue;
321 }
322 }  // anonymous namespace
323 
DmaBufImageSiblingVkLinux(const egl::AttributeMap & attribs)324 DmaBufImageSiblingVkLinux::DmaBufImageSiblingVkLinux(const egl::AttributeMap &attribs)
325     : mAttribs(attribs),
326       mFormat(GL_NONE),
327       mRenderable(false),
328       mTextureable(false),
329       mYUV(false),
330       mSamples(0),
331       mImage(nullptr)
332 {
333     ASSERT(mAttribs.contains(EGL_WIDTH));
334     ASSERT(mAttribs.contains(EGL_HEIGHT));
335     mSize.width  = mAttribs.getAsInt(EGL_WIDTH);
336     mSize.height = mAttribs.getAsInt(EGL_HEIGHT);
337     mSize.depth  = 1;
338 
339     int fourCCFormat = mAttribs.getAsInt(EGL_LINUX_DRM_FOURCC_EXT);
340     mFormat          = gl::Format(angle::DrmFourCCFormatToGLInternalFormat(fourCCFormat, &mYUV));
341 
342     mHasProtectedContent = mAttribs.getAsInt(EGL_PROTECTED_CONTENT_EXT, false);
343 }
344 
~DmaBufImageSiblingVkLinux()345 DmaBufImageSiblingVkLinux::~DmaBufImageSiblingVkLinux() {}
346 
initialize(const egl::Display * display)347 egl::Error DmaBufImageSiblingVkLinux::initialize(const egl::Display *display)
348 {
349     DisplayVk *displayVk = vk::GetImpl(display);
350     return angle::ToEGL(initImpl(displayVk), displayVk, EGL_BAD_PARAMETER);
351 }
352 
FindSupportedUsageFlagsForFormat(RendererVk * renderer,VkFormat format,uint64_t drmModifier,VkImageFormatListCreateInfo imageFormatListCreateInfo,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,VkImageFormatProperties2 * outImageFormatProperties)353 VkImageUsageFlags FindSupportedUsageFlagsForFormat(
354     RendererVk *renderer,
355     VkFormat format,
356     uint64_t drmModifier,
357     VkImageFormatListCreateInfo imageFormatListCreateInfo,
358     VkImageUsageFlags usageFlags,
359     VkImageCreateFlags createFlags,
360     VkImageFormatProperties2 *outImageFormatProperties)
361 {
362     if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
363                            imageFormatListCreateInfo, outImageFormatProperties))
364     {
365         usageFlags &= ~kRenderUsage;
366         if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
367                                imageFormatListCreateInfo, outImageFormatProperties))
368         {
369             usageFlags &= ~kTextureUsage;
370             if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
371                                    imageFormatListCreateInfo, outImageFormatProperties))
372             {
373                 // Can not find supported usage flags for this image.
374                 return 0;
375             }
376         }
377     }
378 
379     return usageFlags;
380 }
381 
FindSupportedFlagsForFormat(RendererVk * renderer,VkFormat format,uint64_t drmModifier,VkImageFormatListCreateInfo imageFormatListCreateInfo,VkImageUsageFlags * outUsageFlags,VkImageCreateFlags * outCreateFlags,VkImageFormatProperties2 * outImageFormatProperties)382 bool FindSupportedFlagsForFormat(RendererVk *renderer,
383                                  VkFormat format,
384                                  uint64_t drmModifier,
385                                  VkImageFormatListCreateInfo imageFormatListCreateInfo,
386                                  VkImageUsageFlags *outUsageFlags,
387                                  VkImageCreateFlags *outCreateFlags,
388                                  VkImageFormatProperties2 *outImageFormatProperties)
389 {
390     VkImageUsageFlags supportedUsageFlags =
391         FindSupportedUsageFlagsForFormat(renderer, format, drmModifier, imageFormatListCreateInfo,
392                                          *outUsageFlags, *outCreateFlags, outImageFormatProperties);
393     if (supportedUsageFlags == 0)
394     {
395         // Remove mutable format bit and try again.
396         *outCreateFlags &= ~VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
397         supportedUsageFlags = FindSupportedUsageFlagsForFormat(
398             renderer, format, drmModifier, imageFormatListCreateInfo, *outUsageFlags,
399             *outCreateFlags, outImageFormatProperties);
400     }
401 
402     *outUsageFlags = supportedUsageFlags;
403     return supportedUsageFlags != 0;
404 }
405 
initImpl(DisplayVk * displayVk)406 angle::Result DmaBufImageSiblingVkLinux::initImpl(DisplayVk *displayVk)
407 {
408     RendererVk *renderer = displayVk->getRenderer();
409 
410     const vk::Format &vkFormat  = renderer->getFormat(mFormat.info->sizedInternalFormat);
411     const angle::Format &format = vkFormat.getActualImageFormat(rx::vk::ImageAccess::SampleOnly);
412     const VkFormat vulkanFormat = vkFormat.getActualImageVkFormat(rx::vk::ImageAccess::SampleOnly);
413     const angle::FormatID intendedFormatID = vkFormat.getIntendedFormatID();
414     const angle::FormatID actualImageFormatID =
415         vkFormat.getActualImageFormatID(rx::vk::ImageAccess::SampleOnly);
416 
417     const uint32_t planeCount = GetPlaneCount(mAttribs);
418 
419     PerPlane<uint64_t> planeModifiers = {};
420     GetModifiers(mAttribs, planeCount, &planeModifiers);
421 
422     // The EGL extension allows for each plane to have a different DRM modifier.  This is not
423     // allowed in Vulkan, and all hardware past and current require the planes to have the same DRM
424     // modifier.  If an application provides different modifiers for the planes, fail.
425     const uint64_t plane0Modifier = planeModifiers[0];
426     for (uint32_t plane = 0; plane < planeCount; ++plane)
427     {
428         ANGLE_VK_CHECK(displayVk, planeModifiers[plane] == plane0Modifier,
429                        VK_ERROR_INCOMPATIBLE_DRIVER);
430     }
431 
432     // First, check the possible features for the format and determine usage and create flags.
433     VkDrmFormatModifierPropertiesEXT modifierProperties = {};
434     ANGLE_TRY(
435         GetFormatModifierProperties(displayVk, vulkanFormat, plane0Modifier, &modifierProperties));
436 
437     VkImageUsageFlags usageFlags =
438         GetUsageFlags(renderer, format, modifierProperties, &mTextureable, &mRenderable);
439 
440     VkImageCreateFlags createFlags =
441         vk::kVkImageCreateFlagsNone | (hasProtectedContent() ? VK_IMAGE_CREATE_PROTECTED_BIT : 0);
442 
443     // The Vulkan and EGL plane counts are expected to match.
444     ANGLE_VK_CHECK(displayVk, modifierProperties.drmFormatModifierPlaneCount == planeCount,
445                    VK_ERROR_INCOMPATIBLE_DRIVER);
446 
447     // Verify that such a usage is compatible with the provided modifiers, if any.  If not, try to
448     // remove features until it is.
449     VkExternalImageFormatProperties externalFormatProperties = {};
450     externalFormatProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
451 
452     VkImageFormatProperties2 imageFormatProperties = {};
453     imageFormatProperties.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
454     imageFormatProperties.pNext                    = &externalFormatProperties;
455 
456     std::vector<VkSubresourceLayout> planes(planeCount, VkSubresourceLayout{});
457     for (uint32_t plane = 0; plane < planeCount; ++plane)
458     {
459         planes[plane].offset   = mAttribs.getAsInt(kOffsets[plane]);
460         planes[plane].rowPitch = mAttribs.getAsInt(kPitches[plane]);
461     }
462 
463     VkImageDrmFormatModifierExplicitCreateInfoEXT imageDrmModifierCreateInfo = {};
464     imageDrmModifierCreateInfo.sType =
465         VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
466     imageDrmModifierCreateInfo.drmFormatModifier           = plane0Modifier;
467     imageDrmModifierCreateInfo.drmFormatModifierPlaneCount = planeCount;
468     imageDrmModifierCreateInfo.pPlaneLayouts               = planes.data();
469 
470     VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
471     externalMemoryImageCreateInfo.sType       = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
472     externalMemoryImageCreateInfo.pNext       = &imageDrmModifierCreateInfo;
473     externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
474 
475     VkImageFormatListCreateInfoKHR imageFormatListCreateInfo;
476     vk::ImageHelper::ImageListFormats imageListFormatsStorage;
477     const void *imageCreateInfoPNext = vk::ImageHelper::DeriveCreateInfoPNext(
478         displayVk, actualImageFormatID, &externalMemoryImageCreateInfo, &imageFormatListCreateInfo,
479         &imageListFormatsStorage, &createFlags);
480 
481     if (!FindSupportedFlagsForFormat(renderer, vulkanFormat, plane0Modifier,
482                                      imageFormatListCreateInfo, &usageFlags, &createFlags,
483                                      &imageFormatProperties))
484     {
485         // The image is completely unusable.
486         ANGLE_VK_CHECK(displayVk, false, VK_ERROR_FORMAT_NOT_SUPPORTED);
487     }
488     mRenderable  = usageFlags & kRenderUsage;
489     mTextureable = usageFlags & kTextureUsage;
490 
491     // Make sure image width/height/samples are within allowed range and the image is importable.
492     const bool isWidthValid = static_cast<uint32_t>(mSize.width) <=
493                               imageFormatProperties.imageFormatProperties.maxExtent.width;
494     const bool isHeightValid = static_cast<uint32_t>(mSize.height) <=
495                                imageFormatProperties.imageFormatProperties.maxExtent.height;
496     const bool isSampleCountValid =
497         (imageFormatProperties.imageFormatProperties.sampleCounts & VK_SAMPLE_COUNT_1_BIT) != 0;
498     const bool isMemoryImportable =
499         (externalFormatProperties.externalMemoryProperties.externalMemoryFeatures &
500          VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) != 0;
501     ANGLE_VK_CHECK(displayVk,
502                    isWidthValid && isHeightValid && isSampleCountValid && isMemoryImportable,
503                    VK_ERROR_INCOMPATIBLE_DRIVER);
504 
505     // Create the image
506     mImage = new vk::ImageHelper();
507 
508     VkExtent3D vkExtents;
509     gl_vk::GetExtent(mSize, &vkExtents);
510 
511     constexpr bool kIsRobustInitEnabled = false;
512 
513     ANGLE_TRY(mImage->initExternal(
514         displayVk, gl::TextureType::_2D, vkExtents, intendedFormatID, actualImageFormatID, 1,
515         usageFlags, createFlags, vk::ImageLayout::ExternalPreInitialized, imageCreateInfoPNext,
516         gl::LevelIndex(0), 1, 1, kIsRobustInitEnabled, hasProtectedContent()));
517 
518     VkMemoryRequirements externalMemoryRequirements;
519     mImage->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
520 
521     const VkMemoryPropertyFlags flags =
522         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
523         (hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
524 
525     if (mYUV)
526     {
527         const VkChromaLocation xChromaOffset =
528             GetChromaLocation(mAttribs, EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT);
529         const VkChromaLocation yChromaOffset =
530             GetChromaLocation(mAttribs, EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT);
531         const VkSamplerYcbcrModelConversion model = GetYcbcrModel(mAttribs);
532         const VkSamplerYcbcrRange range           = GetYcbcrRange(mAttribs);
533         const VkComponentMapping components       = {
534             VK_COMPONENT_SWIZZLE_IDENTITY,
535             VK_COMPONENT_SWIZZLE_IDENTITY,
536             VK_COMPONENT_SWIZZLE_IDENTITY,
537             VK_COMPONENT_SWIZZLE_IDENTITY,
538         };
539 
540         ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
541                        VK_ERROR_FEATURE_NOT_PRESENT);
542 
543         mImage->updateYcbcrConversionDesc(renderer, 0, model, range, xChromaOffset, yChromaOffset,
544                                           VK_FILTER_NEAREST, components, intendedFormatID);
545     }
546 
547     AllocateInfo allocateInfo;
548     uint32_t allocateInfoCount;
549     ANGLE_TRY(GetAllocateInfo(mAttribs, mImage->getImage().getHandle(), planeCount,
550                               modifierProperties, &allocateInfo, &allocateInfoCount));
551 
552     return mImage->initExternalMemory(
553         displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, allocateInfoCount,
554         allocateInfo.allocateInfoPtr.data(), VK_QUEUE_FAMILY_FOREIGN_EXT, flags);
555 }
556 
onDestroy(const egl::Display * display)557 void DmaBufImageSiblingVkLinux::onDestroy(const egl::Display *display)
558 {
559     ASSERT(mImage == nullptr);
560 }
561 
getFormat() const562 gl::Format DmaBufImageSiblingVkLinux::getFormat() const
563 {
564     return mFormat;
565 }
566 
isRenderable(const gl::Context * context) const567 bool DmaBufImageSiblingVkLinux::isRenderable(const gl::Context *context) const
568 {
569     return mRenderable;
570 }
571 
isTexturable(const gl::Context * context) const572 bool DmaBufImageSiblingVkLinux::isTexturable(const gl::Context *context) const
573 {
574     return mTextureable;
575 }
576 
isYUV() const577 bool DmaBufImageSiblingVkLinux::isYUV() const
578 {
579     return mYUV;
580 }
581 
hasProtectedContent() const582 bool DmaBufImageSiblingVkLinux::hasProtectedContent() const
583 {
584     return mHasProtectedContent;
585 }
586 
getSize() const587 gl::Extents DmaBufImageSiblingVkLinux::getSize() const
588 {
589     return mSize;
590 }
591 
getSamples() const592 size_t DmaBufImageSiblingVkLinux::getSamples() const
593 {
594     return mSamples;
595 }
596 
597 // ExternalImageSiblingVk interface
getImage() const598 vk::ImageHelper *DmaBufImageSiblingVkLinux::getImage() const
599 {
600     return mImage;
601 }
602 
release(RendererVk * renderer)603 void DmaBufImageSiblingVkLinux::release(RendererVk *renderer)
604 {
605     if (mImage != nullptr)
606     {
607         // TODO: Handle the case where the EGLImage is used in two contexts not in the same share
608         // group.  https://issuetracker.google.com/169868803
609         mImage->releaseImage(renderer);
610         mImage->releaseStagedUpdates(renderer);
611         SafeDelete(mImage);
612     }
613 }
614 
615 }  // namespace rx
616