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