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