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