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