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