xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/linux/DisplayVkLinux.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 // DisplayVkLinux.cpp:
7 //    Implements the class methods for DisplayVkLinux.
8 //
9 
10 #include "libANGLE/renderer/vulkan/linux/DisplayVkLinux.h"
11 
12 #include "common/linux/dma_buf_utils.h"
13 #include "libANGLE/renderer/vulkan/linux/DeviceVkLinux.h"
14 #include "libANGLE/renderer/vulkan/linux/DmaBufImageSiblingVkLinux.h"
15 #include "libANGLE/renderer/vulkan/vk_renderer.h"
16 
17 namespace rx
18 {
19 
DisplayVkLinux(const egl::DisplayState & state)20 DisplayVkLinux::DisplayVkLinux(const egl::DisplayState &state)
21     : DisplayVk(state), mDrmFormatsInitialized(false)
22 {}
23 
createDevice()24 DeviceImpl *DisplayVkLinux::createDevice()
25 {
26     return new DeviceVkLinux(this);
27 }
28 
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)29 ExternalImageSiblingImpl *DisplayVkLinux::createExternalImageSibling(
30     const gl::Context *context,
31     EGLenum target,
32     EGLClientBuffer buffer,
33     const egl::AttributeMap &attribs)
34 {
35     switch (target)
36     {
37         case EGL_LINUX_DMA_BUF_EXT:
38             ASSERT(context == nullptr);
39             ASSERT(buffer == nullptr);
40             return new DmaBufImageSiblingVkLinux(attribs);
41 
42         default:
43             return DisplayVk::createExternalImageSibling(context, target, buffer, attribs);
44     }
45 }
46 
47 // Returns the list of DRM modifiers that a VkFormat supports
GetDrmModifiers(const DisplayVk * displayVk,VkFormat vkFormat)48 std::vector<VkDrmFormatModifierPropertiesEXT> DisplayVkLinux::GetDrmModifiers(
49     const DisplayVk *displayVk,
50     VkFormat vkFormat)
51 {
52     vk::Renderer *renderer = displayVk->getRenderer();
53 
54     // Query list of drm format modifiers compatible with VkFormat.
55     VkDrmFormatModifierPropertiesListEXT formatModifierPropertiesList = {};
56     formatModifierPropertiesList.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
57     formatModifierPropertiesList.drmFormatModifierCount = 0;
58 
59     VkFormatProperties2 formatProperties = {};
60     formatProperties.sType               = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
61     formatProperties.pNext               = &formatModifierPropertiesList;
62 
63     vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
64                                          &formatProperties);
65 
66     std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProperties(
67         formatModifierPropertiesList.drmFormatModifierCount);
68     formatModifierPropertiesList.pDrmFormatModifierProperties = formatModifierProperties.data();
69 
70     vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
71                                          &formatProperties);
72 
73     return formatModifierProperties;
74 }
75 
76 // Returns true if that VkFormat has at least on format modifier in its properties
SupportsDrmModifiers(VkPhysicalDevice device,VkFormat vkFormat)77 bool DisplayVkLinux::SupportsDrmModifiers(VkPhysicalDevice device, VkFormat vkFormat)
78 {
79     // Query list of drm format modifiers compatible with VkFormat.
80     VkDrmFormatModifierPropertiesListEXT formatModifierPropertiesList = {};
81     formatModifierPropertiesList.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
82     formatModifierPropertiesList.drmFormatModifierCount = 0;
83 
84     VkFormatProperties2 formatProperties = {};
85     formatProperties.sType               = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
86     formatProperties.pNext               = &formatModifierPropertiesList;
87 
88     vkGetPhysicalDeviceFormatProperties2(device, vkFormat, &formatProperties);
89 
90     // If there is at least one DRM format modifier, it is supported
91     return formatModifierPropertiesList.drmFormatModifierCount > 0;
92 }
93 
94 // Returns a list of VkFormats supporting at least one DRM format modifier
GetVkFormatsWithDrmModifiers(const vk::Renderer * renderer)95 std::vector<VkFormat> DisplayVkLinux::GetVkFormatsWithDrmModifiers(const vk::Renderer *renderer)
96 {
97     std::vector<VkFormat> vkFormats;
98     for (size_t formatIndex = 1; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
99     {
100         const vk::Format &format = renderer->getFormat(angle::FormatID(formatIndex));
101         VkFormat vkFormat =
102             format.getActualImageVkFormat(renderer, rx::vk::ImageAccess::Renderable);
103 
104         if (vkFormat != VK_FORMAT_UNDEFINED &&
105             SupportsDrmModifiers(renderer->getPhysicalDevice(), vkFormat))
106         {
107             vkFormats.push_back(vkFormat);
108         }
109     }
110 
111     return vkFormats;
112 }
113 
114 // Returns a list of supported DRM formats
GetDrmFormats(const vk::Renderer * renderer)115 std::vector<EGLint> DisplayVkLinux::GetDrmFormats(const vk::Renderer *renderer)
116 {
117     std::unordered_set<EGLint> drmFormatsSet;
118     for (VkFormat vkFormat : GetVkFormatsWithDrmModifiers(renderer))
119     {
120         std::vector<EGLint> drmFormats = angle::VkFormatToDrmFourCCFormat(vkFormat);
121         for (EGLint drmFormat : drmFormats)
122         {
123             drmFormatsSet.insert(drmFormat);
124         }
125     }
126 
127     std::vector<EGLint> drmFormats;
128     std::copy(std::begin(drmFormatsSet), std::end(drmFormatsSet), std::back_inserter(drmFormats));
129 
130     return drmFormats;
131 }
132 
supportsDmaBufFormat(EGLint format) const133 bool DisplayVkLinux::supportsDmaBufFormat(EGLint format) const
134 {
135     return std::find(std::begin(mDrmFormats), std::end(mDrmFormats), format) !=
136            std::end(mDrmFormats);
137 }
138 
queryDmaBufFormats(EGLint maxFormats,EGLint * formats,EGLint * numFormats)139 egl::Error DisplayVkLinux::queryDmaBufFormats(EGLint maxFormats,
140                                               EGLint *formats,
141                                               EGLint *numFormats)
142 {
143     if (!mDrmFormatsInitialized)
144     {
145         mDrmFormats            = GetDrmFormats(getRenderer());
146         mDrmFormatsInitialized = true;
147     }
148 
149     EGLint formatsSize = static_cast<EGLint>(mDrmFormats.size());
150     *numFormats        = formatsSize;
151     if (maxFormats > 0)
152     {
153         // Do not copy data beyond the limits of the vector
154         maxFormats = std::min(maxFormats, formatsSize);
155         std::memcpy(formats, mDrmFormats.data(), maxFormats * sizeof(EGLint));
156     }
157 
158     return egl::NoError();
159 }
160 
161 // Queries DRM format modifiers associated to `drmFormat`.
162 // When `maxModifiers` is zero, it will only return the number of modifiers associated to
163 // `drmFormat` using the out parameter `numModifiers`. When `maxModifiers` is greater than zero, it
164 // will put that number of DRM format modifiers into the out parameter `modifiers`.
queryDmaBufModifiers(EGLint drmFormat,EGLint maxModifiers,EGLuint64KHR * modifiers,EGLBoolean * externalOnly,EGLint * numModifiers)165 egl::Error DisplayVkLinux::queryDmaBufModifiers(EGLint drmFormat,
166                                                 EGLint maxModifiers,
167                                                 EGLuint64KHR *modifiers,
168                                                 EGLBoolean *externalOnly,
169                                                 EGLint *numModifiers)
170 {
171     // A DRM format may correspond to multiple Vulkan formats
172     std::vector<VkFormat> vkFormats = angle::DrmFourCCFormatToVkFormats(drmFormat);
173 
174     std::vector<EGLuint64KHR> drmModifiers;
175     // Collect DRM format modifiers common to all those Vulkan formats
176     for (size_t i = 0; i < vkFormats.size(); ++i)
177     {
178         VkFormat vkFmt = vkFormats[i];
179 
180         std::vector<VkDrmFormatModifierPropertiesEXT> vkDrmMods = GetDrmModifiers(this, vkFmt);
181 
182         std::vector<EGLuint64KHR> drmMods(vkDrmMods.size());
183         std::transform(std::begin(vkDrmMods), std::end(vkDrmMods), std::begin(drmMods),
184                        [](VkDrmFormatModifierPropertiesEXT props) {
185                            return static_cast<EGLuint64KHR>(props.drmFormatModifier);
186                        });
187         std::sort(std::begin(drmMods), std::end(drmMods));
188 
189         if (i == 0)
190         {
191             // Just take the modifiers for the first format
192             drmModifiers = drmMods;
193         }
194         else
195         {
196             // Intersect the modifiers of all the other associated Vulkan formats
197             std::vector<EGLuint64KHR> prevMods = drmModifiers;
198             drmModifiers.clear();
199             std::set_intersection(std::begin(drmMods), std::end(drmMods), std::begin(prevMods),
200                                   std::end(prevMods), std::back_inserter(drmModifiers));
201         }
202     }
203 
204     EGLint drmModifiersSize = static_cast<EGLint>(drmModifiers.size());
205 
206     *numModifiers = drmModifiersSize;
207     if (maxModifiers > 0)
208     {
209         maxModifiers = std::min(maxModifiers, drmModifiersSize);
210         std::memcpy(modifiers, drmModifiers.data(), maxModifiers * sizeof(drmModifiers[0]));
211     }
212 
213     return egl::NoError();
214 }
215 }  // namespace rx
216