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