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