• 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 bool 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     if (propertiesIndex >= formatModifierPropertiesList.drmFormatModifierCount)
146     {
147         return false;
148     }
149 
150     *modifierPropertiesOut =
151         formatModifierPropertiesList.pDrmFormatModifierProperties[propertiesIndex];
152     return true;
153 }
154 
GetUsageFlags(RendererVk * renderer,const angle::Format & format,const VkDrmFormatModifierPropertiesEXT & properties,bool * texturableOut,bool * renderableOut)155 VkImageUsageFlags GetUsageFlags(RendererVk *renderer,
156                                 const angle::Format &format,
157                                 const VkDrmFormatModifierPropertiesEXT &properties,
158                                 bool *texturableOut,
159                                 bool *renderableOut)
160 {
161     const bool isDepthStencilFormat = format.hasDepthOrStencilBits();
162 
163     // Check what format features are exposed for this modifier.
164     constexpr uint32_t kTextureableRequiredBits =
165         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
166     constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
167     constexpr uint32_t kDepthStencilRenderableRequiredBits =
168         VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
169 
170     *texturableOut =
171         IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kTextureableRequiredBits);
172     *renderableOut = IsMaskFlagSet(
173         properties.drmFormatModifierTilingFeatures,
174         isDepthStencilFormat ? kDepthStencilRenderableRequiredBits : kColorRenderableRequiredBits);
175 
176     VkImageUsageFlags usage = kTransferUsage;
177     if (*texturableOut)
178     {
179         usage |= kTextureUsage;
180     }
181     if (*renderableOut)
182     {
183         usage |= isDepthStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
184                                       : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
185     }
186 
187     return usage;
188 }
189 
IsFormatSupported(RendererVk * renderer,VkFormat vkFormat,uint64_t drmModifier,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,VkImageFormatListCreateInfoKHR imageFormatListInfo,VkImageFormatProperties2 * imageFormatPropertiesOut)190 bool IsFormatSupported(RendererVk *renderer,
191                        VkFormat vkFormat,
192                        uint64_t drmModifier,
193                        VkImageUsageFlags usageFlags,
194                        VkImageCreateFlags createFlags,
195                        VkImageFormatListCreateInfoKHR imageFormatListInfo,
196                        VkImageFormatProperties2 *imageFormatPropertiesOut)
197 {
198     VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {};
199     externalImageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
200     externalImageFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
201     imageFormatListInfo.pNext          = &externalImageFormatInfo;
202 
203     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
204     imageFormatInfo.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
205     imageFormatInfo.format = vkFormat;
206     imageFormatInfo.type   = VK_IMAGE_TYPE_2D;
207     imageFormatInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
208     imageFormatInfo.usage  = usageFlags;
209     imageFormatInfo.flags  = createFlags;
210     imageFormatInfo.pNext  = &imageFormatListInfo;
211 
212     VkPhysicalDeviceImageDrmFormatModifierInfoEXT drmFormatModifierInfo = {};
213     drmFormatModifierInfo.sType =
214         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
215     drmFormatModifierInfo.drmFormatModifier = drmModifier;
216     drmFormatModifierInfo.sharingMode       = VK_SHARING_MODE_EXCLUSIVE;
217     externalImageFormatInfo.pNext           = &drmFormatModifierInfo;
218 
219     return vkGetPhysicalDeviceImageFormatProperties2(renderer->getPhysicalDevice(),
220                                                      &imageFormatInfo, imageFormatPropertiesOut) !=
221            VK_ERROR_FORMAT_NOT_SUPPORTED;
222 }
223 
GetChromaLocation(const egl::AttributeMap & attribs,EGLenum hint)224 VkChromaLocation GetChromaLocation(const egl::AttributeMap &attribs, EGLenum hint)
225 {
226     return attribs.getAsInt(hint, EGL_YUV_CHROMA_SITING_0_EXT) == EGL_YUV_CHROMA_SITING_0_EXT
227                ? VK_CHROMA_LOCATION_COSITED_EVEN
228                : VK_CHROMA_LOCATION_MIDPOINT;
229 }
230 
GetYcbcrModel(const egl::AttributeMap & attribs)231 VkSamplerYcbcrModelConversion GetYcbcrModel(const egl::AttributeMap &attribs)
232 {
233     switch (attribs.getAsInt(EGL_YUV_COLOR_SPACE_HINT_EXT, EGL_ITU_REC601_EXT))
234     {
235         case EGL_ITU_REC601_EXT:
236             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
237         case EGL_ITU_REC709_EXT:
238             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
239         case EGL_ITU_REC2020_EXT:
240             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
241         default:
242             UNREACHABLE();
243             return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
244     }
245 }
246 
GetYcbcrRange(const egl::AttributeMap & attribs)247 VkSamplerYcbcrRange GetYcbcrRange(const egl::AttributeMap &attribs)
248 {
249     return attribs.getAsInt(EGL_SAMPLE_RANGE_HINT_EXT, EGL_YUV_FULL_RANGE_EXT) ==
250                    EGL_YUV_FULL_RANGE_EXT
251                ? VK_SAMPLER_YCBCR_RANGE_ITU_FULL
252                : VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
253 }
254 
GetAllocateInfo(const egl::AttributeMap & attribs,VkImage image,uint32_t planeCount,const VkDrmFormatModifierPropertiesEXT & properties,AllocateInfo * infoOut,uint32_t * infoCountOut)255 angle::Result GetAllocateInfo(const egl::AttributeMap &attribs,
256                               VkImage image,
257                               uint32_t planeCount,
258                               const VkDrmFormatModifierPropertiesEXT &properties,
259                               AllocateInfo *infoOut,
260                               uint32_t *infoCountOut)
261 {
262     // There are a number of situations:
263     //
264     // - If the format tilingFeatures does not have the DISJOINT bit, then allocation and bind is
265     //   done as usual; the fd is used to create the allocation and vkBindImageMemory is called
266     //   without any extra bind info (which would need vkBindImageMemory2).
267     // - If the format tilingFeatures does have the DISJOINT bit, but all fds are identical, it's
268     //   handled similarly to the non-disjoint case.
269     // - Otherwise if there are N planes, there must be N allocations and N binds (one per fd).
270     //   When binding, VkBindImagePlaneMemoryInfo is used to identify which plane is being bound.
271     //
272     constexpr uint32_t kDisjointBit = VK_FORMAT_FEATURE_DISJOINT_BIT;
273     bool isDisjoint =
274         planeCount > 1 && IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kDisjointBit);
275     if (isDisjoint)
276     {
277         bool areFdsIdentical = true;
278         for (uint32_t plane = 1; plane < planeCount; ++plane)
279         {
280             if (attribs.getAsInt(kFds[plane]) != attribs.getAsInt(kFds[0]))
281             {
282                 areFdsIdentical = false;
283                 break;
284             }
285         }
286 
287         // Treat DISJOINT-but-identical-fds as non-disjoint.
288         if (areFdsIdentical)
289         {
290             isDisjoint = false;
291         }
292     }
293 
294     // Fill in allocateInfo, importFdInfo, bindInfo and bindPlaneInfo first.
295     *infoCountOut = isDisjoint ? planeCount : 1;
296     for (uint32_t plane = 0; plane < *infoCountOut; ++plane)
297     {
298         infoOut->allocateInfo[plane].sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
299         infoOut->allocateInfo[plane].pNext = &infoOut->importFdInfo[plane];
300         infoOut->allocateInfo[plane].image = image;
301 
302         infoOut->importFdInfo[plane].sType      = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
303         infoOut->importFdInfo[plane].handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
304 
305         // Vulkan takes ownership of the FD, closed on vkFreeMemory.
306         int dfd = fcntl(attribs.getAsInt(kFds[plane]), F_DUPFD_CLOEXEC, 0);
307         if (dfd < 0)
308         {
309             ERR() << "failed to duplicate fd for dma_buf import" << std::endl;
310             return angle::Result::Stop;
311         }
312         infoOut->importFdInfo[plane].fd = dfd;
313 
314         infoOut->allocateInfoPtr[plane] = &infoOut->allocateInfo[plane];
315     }
316 
317     return angle::Result::Continue;
318 }
319 }  // anonymous namespace
320 
DmaBufImageSiblingVkLinux(const egl::AttributeMap & attribs)321 DmaBufImageSiblingVkLinux::DmaBufImageSiblingVkLinux(const egl::AttributeMap &attribs)
322     : mAttribs(attribs),
323       mFormat(GL_NONE),
324       mVkFormats(),
325       mRenderable(false),
326       mTextureable(false),
327       mYUV(false),
328       mSamples(0),
329       mImage(nullptr)
330 {
331     ASSERT(mAttribs.contains(EGL_WIDTH));
332     ASSERT(mAttribs.contains(EGL_HEIGHT));
333     mSize.width  = mAttribs.getAsInt(EGL_WIDTH);
334     mSize.height = mAttribs.getAsInt(EGL_HEIGHT);
335     mSize.depth  = 1;
336 
337     int fourCCFormat = mAttribs.getAsInt(EGL_LINUX_DRM_FOURCC_EXT);
338     mFormat          = gl::Format(angle::DrmFourCCFormatToGLInternalFormat(fourCCFormat, &mYUV));
339     mVkFormats       = angle::DrmFourCCFormatToVkFormats(fourCCFormat);
340 
341     mHasProtectedContent = mAttribs.getAsInt(EGL_PROTECTED_CONTENT_EXT, false);
342 }
343 
~DmaBufImageSiblingVkLinux()344 DmaBufImageSiblingVkLinux::~DmaBufImageSiblingVkLinux() {}
345 
initialize(const egl::Display * display)346 egl::Error DmaBufImageSiblingVkLinux::initialize(const egl::Display *display)
347 {
348     DisplayVk *displayVk = vk::GetImpl(display);
349     return angle::ToEGL(initImpl(displayVk), EGL_BAD_PARAMETER);
350 }
351 
FindSupportedUsageFlagsForFormat(RendererVk * renderer,VkFormat format,uint64_t drmModifier,VkImageFormatListCreateInfo imageFormatListCreateInfo,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,VkImageFormatProperties2 * outImageFormatProperties)352 VkImageUsageFlags FindSupportedUsageFlagsForFormat(
353     RendererVk *renderer,
354     VkFormat format,
355     uint64_t drmModifier,
356     VkImageFormatListCreateInfo imageFormatListCreateInfo,
357     VkImageUsageFlags usageFlags,
358     VkImageCreateFlags createFlags,
359     VkImageFormatProperties2 *outImageFormatProperties)
360 {
361     if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
362                            imageFormatListCreateInfo, outImageFormatProperties))
363     {
364         usageFlags &= ~kRenderUsage;
365         if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
366                                imageFormatListCreateInfo, outImageFormatProperties))
367         {
368             usageFlags &= ~kTextureUsage;
369             if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
370                                    imageFormatListCreateInfo, outImageFormatProperties))
371             {
372                 // Can not find supported usage flags for this image.
373                 return 0;
374             }
375         }
376     }
377 
378     return usageFlags;
379 }
380 
FindSupportedFlagsForFormat(RendererVk * renderer,VkFormat format,uint64_t drmModifier,VkImageFormatListCreateInfo imageFormatListCreateInfo,VkImageUsageFlags * outUsageFlags,VkImageCreateFlags createFlags,VkImageFormatProperties2 * outImageFormatProperties)381 bool FindSupportedFlagsForFormat(RendererVk *renderer,
382                                  VkFormat format,
383                                  uint64_t drmModifier,
384                                  VkImageFormatListCreateInfo imageFormatListCreateInfo,
385                                  VkImageUsageFlags *outUsageFlags,
386                                  VkImageCreateFlags createFlags,
387                                  VkImageFormatProperties2 *outImageFormatProperties)
388 {
389     *outUsageFlags =
390         FindSupportedUsageFlagsForFormat(renderer, format, drmModifier, imageFormatListCreateInfo,
391                                          *outUsageFlags, createFlags, outImageFormatProperties);
392     return *outUsageFlags != 0;
393 }
394 
initWithFormat(DisplayVk * displayVk,const angle::Format & format,VkFormat vulkanFormat,MutableFormat mutableFormat,InitResult * initResultOut)395 angle::Result DmaBufImageSiblingVkLinux::initWithFormat(DisplayVk *displayVk,
396                                                         const angle::Format &format,
397                                                         VkFormat vulkanFormat,
398                                                         MutableFormat mutableFormat,
399                                                         InitResult *initResultOut)
400 {
401     *initResultOut       = InitResult::Success;
402     RendererVk *renderer = displayVk->getRenderer();
403 
404     const angle::FormatID intendedFormatID    = vk::GetFormatIDFromVkFormat(vulkanFormat);
405     const angle::FormatID actualImageFormatID = vk::GetFormatIDFromVkFormat(vulkanFormat);
406 
407     const uint32_t planeCount = GetPlaneCount(mAttribs);
408 
409     PerPlane<uint64_t> planeModifiers = {};
410     GetModifiers(mAttribs, planeCount, &planeModifiers);
411 
412     // The EGL extension allows for each plane to have a different DRM modifier.  This is not
413     // allowed in Vulkan, and all hardware past and current require the planes to have the same DRM
414     // modifier.  If an application provides different modifiers for the planes, fail.
415     const uint64_t plane0Modifier = planeModifiers[0];
416     for (uint32_t plane = 0; plane < planeCount; ++plane)
417     {
418         ANGLE_VK_CHECK(displayVk, planeModifiers[plane] == plane0Modifier,
419                        VK_ERROR_INCOMPATIBLE_DRIVER);
420     }
421 
422     // First, check the possible features for the format and determine usage and create flags.
423     VkDrmFormatModifierPropertiesEXT modifierProperties = {};
424     if (!GetFormatModifierProperties(displayVk, vulkanFormat, plane0Modifier, &modifierProperties))
425     {
426         // Format is incompatible
427         *initResultOut = InitResult::Failed;
428         return angle::Result::Continue;
429     }
430 
431     VkImageUsageFlags usageFlags =
432         GetUsageFlags(renderer, format, modifierProperties, &mTextureable, &mRenderable);
433 
434     VkImageCreateFlags createFlags =
435         vk::kVkImageCreateFlagsNone | (hasProtectedContent() ? VK_IMAGE_CREATE_PROTECTED_BIT : 0);
436 
437     // The Vulkan and EGL plane counts are expected to match.
438     ANGLE_VK_CHECK(displayVk, modifierProperties.drmFormatModifierPlaneCount == planeCount,
439                    VK_ERROR_INCOMPATIBLE_DRIVER);
440 
441     // Verify that such a usage is compatible with the provided modifiers, if any.  If not, try to
442     // remove features until it is.
443     VkExternalImageFormatProperties externalFormatProperties = {};
444     externalFormatProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
445 
446     VkImageFormatProperties2 imageFormatProperties = {};
447     imageFormatProperties.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
448     imageFormatProperties.pNext                    = &externalFormatProperties;
449 
450     std::vector<VkSubresourceLayout> planes(planeCount, VkSubresourceLayout{});
451     for (uint32_t plane = 0; plane < planeCount; ++plane)
452     {
453         planes[plane].offset   = mAttribs.getAsInt(kOffsets[plane]);
454         planes[plane].rowPitch = mAttribs.getAsInt(kPitches[plane]);
455     }
456 
457     VkImageDrmFormatModifierExplicitCreateInfoEXT imageDrmModifierCreateInfo = {};
458     imageDrmModifierCreateInfo.sType =
459         VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
460     imageDrmModifierCreateInfo.drmFormatModifier           = plane0Modifier;
461     imageDrmModifierCreateInfo.drmFormatModifierPlaneCount = planeCount;
462     imageDrmModifierCreateInfo.pPlaneLayouts               = planes.data();
463 
464     VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
465     externalMemoryImageCreateInfo.sType       = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
466     externalMemoryImageCreateInfo.pNext       = &imageDrmModifierCreateInfo;
467     externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
468 
469     VkImageFormatListCreateInfoKHR imageFormatListCreateInfo;
470     vk::ImageHelper::ImageListFormats imageListFormatsStorage;
471     const void *imageCreateInfoPNext = vk::ImageHelper::DeriveCreateInfoPNext(
472         displayVk, actualImageFormatID, &externalMemoryImageCreateInfo, &imageFormatListCreateInfo,
473         &imageListFormatsStorage, &createFlags);
474 
475     if (mutableFormat == MutableFormat::NotAllowed)
476     {
477         createFlags &= ~VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
478         // When mutable format bit is not set, viewFormatCount must be 0 or 1.
479         imageFormatListCreateInfo.viewFormatCount =
480             std::min(imageFormatListCreateInfo.viewFormatCount, 1u);
481     }
482 
483     if (!FindSupportedFlagsForFormat(renderer, vulkanFormat, plane0Modifier,
484                                      imageFormatListCreateInfo, &usageFlags, createFlags,
485                                      &imageFormatProperties))
486     {
487         // The image is not unusable with current flags.
488         *initResultOut = InitResult::Failed;
489         return angle::Result::Continue;
490     }
491     mRenderable  = usageFlags & kRenderUsage;
492     mTextureable = usageFlags & kTextureUsage;
493 
494     // Make sure image width/height/samples are within allowed range and the image is importable.
495     const bool isWidthValid = static_cast<uint32_t>(mSize.width) <=
496                               imageFormatProperties.imageFormatProperties.maxExtent.width;
497     const bool isHeightValid = static_cast<uint32_t>(mSize.height) <=
498                                imageFormatProperties.imageFormatProperties.maxExtent.height;
499     const bool isSampleCountValid =
500         (imageFormatProperties.imageFormatProperties.sampleCounts & VK_SAMPLE_COUNT_1_BIT) != 0;
501     const bool isMemoryImportable =
502         (externalFormatProperties.externalMemoryProperties.externalMemoryFeatures &
503          VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) != 0;
504     ANGLE_VK_CHECK(displayVk,
505                    isWidthValid && isHeightValid && isSampleCountValid && isMemoryImportable,
506                    VK_ERROR_INCOMPATIBLE_DRIVER);
507 
508     // Create the image
509     mImage = new vk::ImageHelper();
510 
511     VkExtent3D vkExtents;
512     gl_vk::GetExtent(mSize, &vkExtents);
513 
514     constexpr bool kIsRobustInitEnabled = false;
515 
516     ANGLE_TRY(mImage->initExternal(
517         displayVk, gl::TextureType::_2D, vkExtents, intendedFormatID, actualImageFormatID, 1,
518         usageFlags, createFlags, vk::ImageLayout::ExternalPreInitialized, imageCreateInfoPNext,
519         gl::LevelIndex(0), 1, 1, kIsRobustInitEnabled, hasProtectedContent()));
520 
521     VkMemoryRequirements externalMemoryRequirements;
522     mImage->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
523 
524     const VkMemoryPropertyFlags flags =
525         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
526         (hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
527 
528     if (mYUV)
529     {
530         const VkChromaLocation xChromaOffset =
531             GetChromaLocation(mAttribs, EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT);
532         const VkChromaLocation yChromaOffset =
533             GetChromaLocation(mAttribs, EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT);
534         const VkSamplerYcbcrModelConversion model = GetYcbcrModel(mAttribs);
535         const VkSamplerYcbcrRange range           = GetYcbcrRange(mAttribs);
536         const VkComponentMapping components       = {
537             VK_COMPONENT_SWIZZLE_IDENTITY,
538             VK_COMPONENT_SWIZZLE_IDENTITY,
539             VK_COMPONENT_SWIZZLE_IDENTITY,
540             VK_COMPONENT_SWIZZLE_IDENTITY,
541         };
542 
543         ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
544                        VK_ERROR_FEATURE_NOT_PRESENT);
545 
546         mImage->updateYcbcrConversionDesc(renderer, 0, model, range, xChromaOffset, yChromaOffset,
547                                           VK_FILTER_NEAREST, components, intendedFormatID);
548     }
549 
550     AllocateInfo allocateInfo;
551     uint32_t allocateInfoCount;
552     ANGLE_TRY(GetAllocateInfo(mAttribs, mImage->getImage().getHandle(), planeCount,
553                               modifierProperties, &allocateInfo, &allocateInfoCount));
554 
555     return mImage->initExternalMemory(
556         displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, allocateInfoCount,
557         allocateInfo.allocateInfoPtr.data(), VK_QUEUE_FAMILY_FOREIGN_EXT, flags);
558 }
559 
initImpl(DisplayVk * displayVk)560 angle::Result DmaBufImageSiblingVkLinux::initImpl(DisplayVk *displayVk)
561 {
562     RendererVk *renderer = displayVk->getRenderer();
563 
564     const vk::Format &vkFormat  = renderer->getFormat(mFormat.info->sizedInternalFormat);
565     const angle::Format &format = vkFormat.getActualImageFormat(rx::vk::ImageAccess::SampleOnly);
566 
567     InitResult initResult;
568 
569     for (VkFormat vkFmt : mVkFormats)
570     {
571         // Try all formats with mutable format bit first
572         ANGLE_TRY(initWithFormat(displayVk, format, vkFmt, MutableFormat::Allowed, &initResult));
573         if (initResult == InitResult::Success)
574         {
575             return angle::Result::Continue;
576         }
577     }
578 
579     for (VkFormat vkFmt : mVkFormats)
580     {
581         // Then try without mutable format bit
582         ANGLE_TRY(initWithFormat(displayVk, format, vkFmt, MutableFormat::NotAllowed, &initResult));
583         if (initResult == InitResult::Success)
584         {
585             return angle::Result::Continue;
586         }
587     }
588 
589     // Failed to find any suitable format
590     ANGLE_VK_UNREACHABLE(displayVk);
591     return angle::Result::Stop;
592 }
593 
onDestroy(const egl::Display * display)594 void DmaBufImageSiblingVkLinux::onDestroy(const egl::Display *display)
595 {
596     ASSERT(mImage == nullptr);
597 }
598 
getFormat() const599 gl::Format DmaBufImageSiblingVkLinux::getFormat() const
600 {
601     return mFormat;
602 }
603 
isRenderable(const gl::Context * context) const604 bool DmaBufImageSiblingVkLinux::isRenderable(const gl::Context *context) const
605 {
606     return mRenderable;
607 }
608 
isTexturable(const gl::Context * context) const609 bool DmaBufImageSiblingVkLinux::isTexturable(const gl::Context *context) const
610 {
611     return mTextureable;
612 }
613 
isYUV() const614 bool DmaBufImageSiblingVkLinux::isYUV() const
615 {
616     return mYUV;
617 }
618 
hasProtectedContent() const619 bool DmaBufImageSiblingVkLinux::hasProtectedContent() const
620 {
621     return mHasProtectedContent;
622 }
623 
getSize() const624 gl::Extents DmaBufImageSiblingVkLinux::getSize() const
625 {
626     return mSize;
627 }
628 
getSamples() const629 size_t DmaBufImageSiblingVkLinux::getSamples() const
630 {
631     return mSamples;
632 }
633 
634 // ExternalImageSiblingVk interface
getImage() const635 vk::ImageHelper *DmaBufImageSiblingVkLinux::getImage() const
636 {
637     return mImage;
638 }
639 
release(RendererVk * renderer)640 void DmaBufImageSiblingVkLinux::release(RendererVk *renderer)
641 {
642     if (mImage != nullptr)
643     {
644         // TODO: Handle the case where the EGLImage is used in two contexts not in the same share
645         // group.  https://issuetracker.google.com/169868803
646         mImage->releaseImage(renderer);
647         mImage->releaseStagedUpdates(renderer);
648         SafeDelete(mImage);
649     }
650 }
651 
652 }  // namespace rx
653