DmaBufImageSiblingVkLinux.cpp 25.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// DmaBufImageSiblingVkLinux.cpp: Implements DmaBufImageSiblingVkLinux.

#include "libANGLE/renderer/vulkan/linux/DmaBufImageSiblingVkLinux.h"

#include "common/linux/dma_buf_utils.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"

16
17
#include <fcntl.h>

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
namespace rx
{
namespace
{
constexpr uint32_t kMaxPlaneCount = 4;
template <typename T>
using PerPlane = std::array<T, kMaxPlaneCount>;

constexpr PerPlane<EGLenum> kFds = {EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE1_FD_EXT,
                                    EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE3_FD_EXT};

constexpr PerPlane<EGLenum> kOffsets = {
    EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT,
    EGL_DMA_BUF_PLANE3_OFFSET_EXT};

constexpr PerPlane<EGLenum> kPitches = {EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT,
                                        EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT};

constexpr PerPlane<EGLenum> kModifiersLo = {
    EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
    EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT};

constexpr PerPlane<EGLenum> kModifiersHi = {
    EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
    EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT};

constexpr VkImageUsageFlags kTransferUsage =
    VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
constexpr VkImageUsageFlags kTextureUsage =
    VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
constexpr VkImageUsageFlags kRenderUsage =
    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;

struct AllocateInfo
{
    PerPlane<VkMemoryDedicatedAllocateInfo> allocateInfo = {};
    PerPlane<VkImportMemoryFdInfoKHR> importFdInfo       = {};

    PerPlane<const void *> allocateInfoPtr = {};
};

// Look at provided fds and count the number of planes based on that.
uint32_t GetPlaneCount(const egl::AttributeMap &attribs)
{
    // There should always be at least one plane.
    ASSERT(attribs.contains(kFds[0]));
    ASSERT(attribs.contains(kOffsets[0]));
    ASSERT(attribs.contains(kPitches[0]));

    for (uint32_t plane = 1; plane < kMaxPlaneCount; ++plane)
    {
        if (!attribs.contains(kFds[plane]))
        {
            return plane;
        }

        ASSERT(attribs.contains(kOffsets[plane]));
        ASSERT(attribs.contains(kPitches[plane]));
    }

    return kMaxPlaneCount;
}

uint64_t GetModifier(const egl::AttributeMap &attribs, EGLenum lo, EGLenum hi)
{
    if (!attribs.contains(lo))
    {
        return 0;
    }

    ASSERT(attribs.contains(hi));

    uint64_t modifier = attribs.getAsInt(hi);
    modifier          = modifier << 32 | attribs.getAsInt(lo);

    return modifier;
}

void GetModifiers(const egl::AttributeMap &attribs,
                  uint32_t planeCount,
                  PerPlane<uint64_t> *drmModifiersOut)
{
    for (uint32_t plane = 0; plane < planeCount; ++plane)
    {
        (*drmModifiersOut)[plane] = GetModifier(attribs, kModifiersLo[plane], kModifiersHi[plane]);
    }
}

angle::Result GetFormatModifierProperties(DisplayVk *displayVk,
                                          VkFormat vkFormat,
                                          uint64_t drmModifier,
                                          VkDrmFormatModifierPropertiesEXT *modifierPropertiesOut)
{
    RendererVk *renderer = displayVk->getRenderer();

    // Query list of drm format modifiers compatible with VkFormat.
    VkDrmFormatModifierPropertiesListEXT formatModifierPropertiesList = {};
    formatModifierPropertiesList.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
    formatModifierPropertiesList.drmFormatModifierCount = 0;

    VkFormatProperties2 formatProperties = {};
    formatProperties.sType               = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
    formatProperties.pNext               = &formatModifierPropertiesList;

    vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
                                         &formatProperties);

    std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProperties(
        formatModifierPropertiesList.drmFormatModifierCount);
    formatModifierPropertiesList.pDrmFormatModifierProperties = formatModifierProperties.data();

    vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
                                         &formatProperties);

    // Find the requested DRM modifiers.
    uint32_t propertiesIndex = formatModifierPropertiesList.drmFormatModifierCount;
    for (uint32_t index = 0; index < formatModifierPropertiesList.drmFormatModifierCount; ++index)
    {
        if (formatModifierPropertiesList.pDrmFormatModifierProperties[index].drmFormatModifier ==
            drmModifier)
        {
            propertiesIndex = index;
            break;
        }
    }

    // Return the properties if found.
    ANGLE_VK_CHECK(displayVk, propertiesIndex < formatModifierPropertiesList.drmFormatModifierCount,
                   VK_ERROR_FORMAT_NOT_SUPPORTED);

    *modifierPropertiesOut =
        formatModifierPropertiesList.pDrmFormatModifierProperties[propertiesIndex];
    return angle::Result::Continue;
}

VkImageUsageFlags GetUsageFlags(RendererVk *renderer,
                                const angle::Format &format,
                                const VkDrmFormatModifierPropertiesEXT &properties,
                                bool *texturableOut,
                                bool *renderableOut)
{
    const bool isDepthStencilFormat = format.depthBits > 0 || format.stencilBits > 0;

    // Check what format features are exposed for this modifier.
    constexpr uint32_t kTextureableRequiredBits =
        VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
    constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
    constexpr uint32_t kDepthStencilRenderableRequiredBits =
        VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;

    *texturableOut =
        IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kTextureableRequiredBits);
    *renderableOut = IsMaskFlagSet(
        properties.drmFormatModifierTilingFeatures,
        isDepthStencilFormat ? kDepthStencilRenderableRequiredBits : kColorRenderableRequiredBits);

    VkImageUsageFlags usage = kTransferUsage;
    if (*texturableOut)
    {
        usage |= kTextureUsage;
    }
    if (*renderableOut)
    {
        usage |= isDepthStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
                                      : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    }

    return usage;
}

bool IsFormatSupported(RendererVk *renderer,
                       VkFormat vkFormat,
                       uint64_t drmModifier,
                       VkImageUsageFlags usageFlags,
                       VkImageCreateFlags createFlags,
193
                       VkImageFormatListCreateInfoKHR imageFormatListInfo,
194
195
                       VkImageFormatProperties2 *imageFormatPropertiesOut)
{
196
197
198
    VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {};
    externalImageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
    externalImageFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
199
    imageFormatListInfo.pNext          = &externalImageFormatInfo;
200
201
202

    VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
    imageFormatInfo.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
203
    imageFormatInfo.pNext  = &externalImageFormatInfo;
204
205
    imageFormatInfo.format = vkFormat;
    imageFormatInfo.type   = VK_IMAGE_TYPE_2D;
206
    imageFormatInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
207
208
    imageFormatInfo.usage  = usageFlags;
    imageFormatInfo.flags  = createFlags;
209
    imageFormatInfo.pNext  = &imageFormatListInfo;
210
211
212
213
214
215

    VkPhysicalDeviceImageDrmFormatModifierInfoEXT drmFormatModifierInfo = {};
    drmFormatModifierInfo.sType =
        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
    drmFormatModifierInfo.drmFormatModifier = drmModifier;
    drmFormatModifierInfo.sharingMode       = VK_SHARING_MODE_EXCLUSIVE;
216
    externalImageFormatInfo.pNext           = &drmFormatModifierInfo;
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

    return vkGetPhysicalDeviceImageFormatProperties2(renderer->getPhysicalDevice(),
                                                     &imageFormatInfo, imageFormatPropertiesOut) !=
           VK_ERROR_FORMAT_NOT_SUPPORTED;
}

VkChromaLocation GetChromaLocation(const egl::AttributeMap &attribs, EGLenum hint)
{
    return attribs.getAsInt(hint, EGL_YUV_CHROMA_SITING_0_EXT) == EGL_YUV_CHROMA_SITING_0_EXT
               ? VK_CHROMA_LOCATION_COSITED_EVEN
               : VK_CHROMA_LOCATION_MIDPOINT;
}

VkSamplerYcbcrModelConversion GetYcbcrModel(const egl::AttributeMap &attribs)
{
    switch (attribs.getAsInt(EGL_YUV_COLOR_SPACE_HINT_EXT, EGL_ITU_REC601_EXT))
    {
        case EGL_ITU_REC601_EXT:
            return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
        case EGL_ITU_REC709_EXT:
            return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
        case EGL_ITU_REC2020_EXT:
            return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
        default:
            UNREACHABLE();
            return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
    }
}

VkSamplerYcbcrRange GetYcbcrRange(const egl::AttributeMap &attribs)
{
    return attribs.getAsInt(EGL_SAMPLE_RANGE_HINT_EXT, EGL_YUV_FULL_RANGE_EXT) ==
                   EGL_YUV_FULL_RANGE_EXT
               ? VK_SAMPLER_YCBCR_RANGE_ITU_FULL
               : VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
}

254
255
256
257
258
259
angle::Result GetAllocateInfo(const egl::AttributeMap &attribs,
                              VkImage image,
                              uint32_t planeCount,
                              const VkDrmFormatModifierPropertiesEXT &properties,
                              AllocateInfo *infoOut,
                              uint32_t *infoCountOut)
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
{
    // There are a number of situations:
    //
    // - If the format tilingFeatures does not have the DISJOINT bit, then allocation and bind is
    //   done as usual; the fd is used to create the allocation and vkBindImageMemory is called
    //   without any extra bind info (which would need vkBindImageMemory2).
    // - If the format tilingFeatures does have the DISJOINT bit, but all fds are identical, it's
    //   handled similarly to the non-disjoint case.
    // - Otherwise if there are N planes, there must be N allocations and N binds (one per fd).
    //   When binding, VkBindImagePlaneMemoryInfo is used to identify which plane is being bound.
    //
    constexpr uint32_t kDisjointBit = VK_FORMAT_FEATURE_DISJOINT_BIT;
    bool isDisjoint =
        planeCount > 1 && IsMaskFlagSet(properties.drmFormatModifierTilingFeatures, kDisjointBit);
    if (isDisjoint)
    {
        bool areFdsIdentical = true;
        for (uint32_t plane = 1; plane < planeCount; ++plane)
        {
            if (attribs.getAsInt(kFds[plane]) != attribs.getAsInt(kFds[0]))
            {
                areFdsIdentical = false;
                break;
            }
        }

        // Treat DISJOINT-but-identical-fds as non-disjoint.
        if (areFdsIdentical)
        {
            isDisjoint = false;
        }
    }

    // Fill in allocateInfo, importFdInfo, bindInfo and bindPlaneInfo first.
294
295
    *infoCountOut = isDisjoint ? planeCount : 1;
    for (uint32_t plane = 0; plane < *infoCountOut; ++plane)
296
297
298
299
300
301
    {
        infoOut->allocateInfo[plane].sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
        infoOut->allocateInfo[plane].pNext = &infoOut->importFdInfo[plane];
        infoOut->allocateInfo[plane].image = image;

        infoOut->importFdInfo[plane].sType      = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
302
303
304
305
306
307
308
309
310
311
        infoOut->importFdInfo[plane].handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;

        // Vulkan takes ownership of the FD, closed on vkFreeMemory.
        int dfd = fcntl(attribs.getAsInt(kFds[plane]), F_DUPFD_CLOEXEC, 0);
        if (dfd < 0)
        {
            ERR() << "failed to duplicate fd for dma_buf import" << std::endl;
            return angle::Result::Stop;
        }
        infoOut->importFdInfo[plane].fd = dfd;
312
313
314
315

        infoOut->allocateInfoPtr[plane] = &infoOut->allocateInfo[plane];
    }

316
    return angle::Result::Continue;
317
318
319
320
321
322
}
}  // anonymous namespace

DmaBufImageSiblingVkLinux::DmaBufImageSiblingVkLinux(const egl::AttributeMap &attribs)
    : mAttribs(attribs),
      mFormat(GL_NONE),
323
      mVkFormats(),
324
325
326
327
328
329
330
331
332
333
334
335
336
337
      mRenderable(false),
      mTextureable(false),
      mYUV(false),
      mSamples(0),
      mImage(nullptr)
{
    ASSERT(mAttribs.contains(EGL_WIDTH));
    ASSERT(mAttribs.contains(EGL_HEIGHT));
    mSize.width  = mAttribs.getAsInt(EGL_WIDTH);
    mSize.height = mAttribs.getAsInt(EGL_HEIGHT);
    mSize.depth  = 1;

    int fourCCFormat = mAttribs.getAsInt(EGL_LINUX_DRM_FOURCC_EXT);
    mFormat          = gl::Format(angle::DrmFourCCFormatToGLInternalFormat(fourCCFormat, &mYUV));
338
    mVkFormats       = angle::DrmFourCCFormatToVkFormats(fourCCFormat);
339
340
341
342
343
344
345
346
347
348
349
350

    mHasProtectedContent = mAttribs.getAsInt(EGL_PROTECTED_CONTENT_EXT, false);
}

DmaBufImageSiblingVkLinux::~DmaBufImageSiblingVkLinux() {}

egl::Error DmaBufImageSiblingVkLinux::initialize(const egl::Display *display)
{
    DisplayVk *displayVk = vk::GetImpl(display);
    return angle::ToEGL(initImpl(displayVk), displayVk, EGL_BAD_PARAMETER);
}

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
VkImageUsageFlags FindSupportedUsageFlagsForFormat(
    RendererVk *renderer,
    VkFormat format,
    uint64_t drmModifier,
    VkImageFormatListCreateInfo imageFormatListCreateInfo,
    VkImageUsageFlags usageFlags,
    VkImageCreateFlags createFlags,
    VkImageFormatProperties2 *outImageFormatProperties)
{
    if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
                           imageFormatListCreateInfo, outImageFormatProperties))
    {
        usageFlags &= ~kRenderUsage;
        if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
                               imageFormatListCreateInfo, outImageFormatProperties))
        {
            usageFlags &= ~kTextureUsage;
            if (!IsFormatSupported(renderer, format, drmModifier, usageFlags, createFlags,
                                   imageFormatListCreateInfo, outImageFormatProperties))
            {
                // Can not find supported usage flags for this image.
                return 0;
            }
        }
    }

    return usageFlags;
}

bool FindSupportedFlagsForFormat(RendererVk *renderer,
                                 VkFormat format,
                                 uint64_t drmModifier,
                                 VkImageFormatListCreateInfo imageFormatListCreateInfo,
                                 VkImageUsageFlags *outUsageFlags,
385
                                 VkImageCreateFlags createFlags,
386
387
                                 VkImageFormatProperties2 *outImageFormatProperties)
{
388
    *outUsageFlags =
389
        FindSupportedUsageFlagsForFormat(renderer, format, drmModifier, imageFormatListCreateInfo,
390
391
                                         *outUsageFlags, createFlags, outImageFormatProperties);
    return *outUsageFlags != 0;
392
393
}

394
395
396
397
398
angle::Result DmaBufImageSiblingVkLinux::initWithFormat(DisplayVk *displayVk,
                                                        const angle::Format &format,
                                                        VkFormat vulkanFormat,
                                                        MutableFormat mutableFormat,
                                                        InitResult *initResultOut)
399
{
400
    *initResultOut       = InitResult::Success;
401
402
    RendererVk *renderer = displayVk->getRenderer();

403
404
    const angle::FormatID intendedFormatID    = vk::GetFormatIDFromVkFormat(vulkanFormat);
    const angle::FormatID actualImageFormatID = vk::GetFormatIDFromVkFormat(vulkanFormat);
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

    const uint32_t planeCount = GetPlaneCount(mAttribs);

    PerPlane<uint64_t> planeModifiers = {};
    GetModifiers(mAttribs, planeCount, &planeModifiers);

    // The EGL extension allows for each plane to have a different DRM modifier.  This is not
    // allowed in Vulkan, and all hardware past and current require the planes to have the same DRM
    // modifier.  If an application provides different modifiers for the planes, fail.
    const uint64_t plane0Modifier = planeModifiers[0];
    for (uint32_t plane = 0; plane < planeCount; ++plane)
    {
        ANGLE_VK_CHECK(displayVk, planeModifiers[plane] == plane0Modifier,
                       VK_ERROR_INCOMPATIBLE_DRIVER);
    }

    // First, check the possible features for the format and determine usage and create flags.
    VkDrmFormatModifierPropertiesEXT modifierProperties = {};
    ANGLE_TRY(
        GetFormatModifierProperties(displayVk, vulkanFormat, plane0Modifier, &modifierProperties));

    VkImageUsageFlags usageFlags =
        GetUsageFlags(renderer, format, modifierProperties, &mTextureable, &mRenderable);

429
    VkImageCreateFlags createFlags =
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
        vk::kVkImageCreateFlagsNone | (hasProtectedContent() ? VK_IMAGE_CREATE_PROTECTED_BIT : 0);

    // The Vulkan and EGL plane counts are expected to match.
    ANGLE_VK_CHECK(displayVk, modifierProperties.drmFormatModifierPlaneCount == planeCount,
                   VK_ERROR_INCOMPATIBLE_DRIVER);

    // Verify that such a usage is compatible with the provided modifiers, if any.  If not, try to
    // remove features until it is.
    VkExternalImageFormatProperties externalFormatProperties = {};
    externalFormatProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;

    VkImageFormatProperties2 imageFormatProperties = {};
    imageFormatProperties.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
    imageFormatProperties.pNext                    = &externalFormatProperties;

445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
    std::vector<VkSubresourceLayout> planes(planeCount, VkSubresourceLayout{});
    for (uint32_t plane = 0; plane < planeCount; ++plane)
    {
        planes[plane].offset   = mAttribs.getAsInt(kOffsets[plane]);
        planes[plane].rowPitch = mAttribs.getAsInt(kPitches[plane]);
    }

    VkImageDrmFormatModifierExplicitCreateInfoEXT imageDrmModifierCreateInfo = {};
    imageDrmModifierCreateInfo.sType =
        VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
    imageDrmModifierCreateInfo.drmFormatModifier           = plane0Modifier;
    imageDrmModifierCreateInfo.drmFormatModifierPlaneCount = planeCount;
    imageDrmModifierCreateInfo.pPlaneLayouts               = planes.data();

    VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
    externalMemoryImageCreateInfo.sType       = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
    externalMemoryImageCreateInfo.pNext       = &imageDrmModifierCreateInfo;
    externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;

    VkImageFormatListCreateInfoKHR imageFormatListCreateInfo;
    vk::ImageHelper::ImageListFormats imageListFormatsStorage;
    const void *imageCreateInfoPNext = vk::ImageHelper::DeriveCreateInfoPNext(
        displayVk, actualImageFormatID, &externalMemoryImageCreateInfo, &imageFormatListCreateInfo,
        &imageListFormatsStorage, &createFlags);

470
    if (mutableFormat == MutableFormat::NotAllowed)
471
472
473
474
475
476
477
    {
        createFlags &= ~VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
        // When mutable format bit is not set, viewFormatCount must be 0 or 1.
        imageFormatListCreateInfo.viewFormatCount =
            std::min(imageFormatListCreateInfo.viewFormatCount, 1u);
    }

478
    if (!FindSupportedFlagsForFormat(renderer, vulkanFormat, plane0Modifier,
479
                                     imageFormatListCreateInfo, &usageFlags, createFlags,
480
                                     &imageFormatProperties))
481
    {
482
483
484
        // The image is not unusable with current flags.
        *initResultOut = InitResult::Failed;
        return angle::Result::Continue;
485
    }
486
487
    mRenderable  = usageFlags & kRenderUsage;
    mTextureable = usageFlags & kTextureUsage;
488
489
490
491
492
493
494
495
496
497

    // Make sure image width/height/samples are within allowed range and the image is importable.
    const bool isWidthValid = static_cast<uint32_t>(mSize.width) <=
                              imageFormatProperties.imageFormatProperties.maxExtent.width;
    const bool isHeightValid = static_cast<uint32_t>(mSize.height) <=
                               imageFormatProperties.imageFormatProperties.maxExtent.height;
    const bool isSampleCountValid =
        (imageFormatProperties.imageFormatProperties.sampleCounts & VK_SAMPLE_COUNT_1_BIT) != 0;
    const bool isMemoryImportable =
        (externalFormatProperties.externalMemoryProperties.externalMemoryFeatures &
498
         VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) != 0;
499
500
501
502
503
504
505
506
507
508
509
510
    ANGLE_VK_CHECK(displayVk,
                   isWidthValid && isHeightValid && isSampleCountValid && isMemoryImportable,
                   VK_ERROR_INCOMPATIBLE_DRIVER);

    // Create the image
    mImage = new vk::ImageHelper();

    VkExtent3D vkExtents;
    gl_vk::GetExtent(mSize, &vkExtents);

    constexpr bool kIsRobustInitEnabled = false;

511
512
513
514
    ANGLE_TRY(mImage->initExternal(
        displayVk, gl::TextureType::_2D, vkExtents, intendedFormatID, actualImageFormatID, 1,
        usageFlags, createFlags, vk::ImageLayout::ExternalPreInitialized, imageCreateInfoPNext,
        gl::LevelIndex(0), 1, 1, kIsRobustInitEnabled, hasProtectedContent()));
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530

    VkMemoryRequirements externalMemoryRequirements;
    mImage->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);

    const VkMemoryPropertyFlags flags =
        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
        (hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);

    if (mYUV)
    {
        const VkChromaLocation xChromaOffset =
            GetChromaLocation(mAttribs, EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT);
        const VkChromaLocation yChromaOffset =
            GetChromaLocation(mAttribs, EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT);
        const VkSamplerYcbcrModelConversion model = GetYcbcrModel(mAttribs);
        const VkSamplerYcbcrRange range           = GetYcbcrRange(mAttribs);
531
        const VkComponentMapping components       = {
532
533
534
535
                  VK_COMPONENT_SWIZZLE_IDENTITY,
                  VK_COMPONENT_SWIZZLE_IDENTITY,
                  VK_COMPONENT_SWIZZLE_IDENTITY,
                  VK_COMPONENT_SWIZZLE_IDENTITY,
536
        };
537
538
539
540

        ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
                       VK_ERROR_FEATURE_NOT_PRESENT);

541
        mImage->updateYcbcrConversionDesc(renderer, 0, model, range, xChromaOffset, yChromaOffset,
542
                                          VK_FILTER_NEAREST, components, intendedFormatID);
543
544
545
    }

    AllocateInfo allocateInfo;
546
547
548
    uint32_t allocateInfoCount;
    ANGLE_TRY(GetAllocateInfo(mAttribs, mImage->getImage().getHandle(), planeCount,
                              modifierProperties, &allocateInfo, &allocateInfoCount));
549

550
551
552
    return mImage->initExternalMemory(
        displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, allocateInfoCount,
        allocateInfo.allocateInfoPtr.data(), VK_QUEUE_FAMILY_FOREIGN_EXT, flags);
553
554
}

555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
angle::Result DmaBufImageSiblingVkLinux::initImpl(DisplayVk *displayVk)
{
    RendererVk *renderer = displayVk->getRenderer();

    const vk::Format &vkFormat  = renderer->getFormat(mFormat.info->sizedInternalFormat);
    const angle::Format &format = vkFormat.getActualImageFormat(rx::vk::ImageAccess::SampleOnly);

    InitResult initResult;

    for (VkFormat vkFmt : mVkFormats)
    {
        // Try all formats with mutable format bit first
        ANGLE_TRY(initWithFormat(displayVk, format, vkFmt, MutableFormat::Allowed, &initResult));
        if (initResult == InitResult::Success)
        {
            return angle::Result::Continue;
        }
    }

    for (VkFormat vkFmt : mVkFormats)
    {
        // Then try without mutable format bit
        ANGLE_TRY(initWithFormat(displayVk, format, vkFmt, MutableFormat::NotAllowed, &initResult));
        if (initResult == InitResult::Success)
        {
            return angle::Result::Continue;
        }
    }

    // Failed to find any suitable format
    ANGLE_VK_UNREACHABLE(displayVk);
    return angle::Result::Stop;
}

589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
void DmaBufImageSiblingVkLinux::onDestroy(const egl::Display *display)
{
    ASSERT(mImage == nullptr);
}

gl::Format DmaBufImageSiblingVkLinux::getFormat() const
{
    return mFormat;
}

bool DmaBufImageSiblingVkLinux::isRenderable(const gl::Context *context) const
{
    return mRenderable;
}

bool DmaBufImageSiblingVkLinux::isTexturable(const gl::Context *context) const
{
    return mTextureable;
}

bool DmaBufImageSiblingVkLinux::isYUV() const
{
    return mYUV;
}

bool DmaBufImageSiblingVkLinux::hasProtectedContent() const
{
    return mHasProtectedContent;
}

gl::Extents DmaBufImageSiblingVkLinux::getSize() const
{
    return mSize;
}

size_t DmaBufImageSiblingVkLinux::getSamples() const
{
    return mSamples;
}

// ExternalImageSiblingVk interface
vk::ImageHelper *DmaBufImageSiblingVkLinux::getImage() const
{
    return mImage;
}

void DmaBufImageSiblingVkLinux::release(RendererVk *renderer)
{
    if (mImage != nullptr)
    {
        // TODO: Handle the case where the EGLImage is used in two contexts not in the same share
        // group.  https://issuetracker.google.com/169868803
        mImage->releaseImage(renderer);
642
        mImage->releaseStagedUpdates(renderer);
643
644
645
646
647
        SafeDelete(mImage);
    }
}

}  // namespace rx