• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/RendererVk.h"
14 #include "libANGLE/renderer/vulkan/linux/DeviceVkLinux.h"
15 #include "libANGLE/renderer/vulkan/linux/DmaBufImageSiblingVkLinux.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     RendererVk *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 RendererVk * rendererVk)95 std::vector<VkFormat> DisplayVkLinux::GetVkFormatsWithDrmModifiers(const RendererVk *rendererVk)
96 {
97     std::vector<VkFormat> vkFormats;
98     for (size_t formatIndex = 1; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
99     {
100         const vk::Format &format = rendererVk->getFormat(angle::FormatID(formatIndex));
101         VkFormat vkFormat        = format.getActualImageVkFormat(rx::vk::ImageAccess::Renderable);
102 
103         if (vkFormat != VK_FORMAT_UNDEFINED &&
104             SupportsDrmModifiers(rendererVk->getPhysicalDevice(), vkFormat))
105         {
106             vkFormats.push_back(vkFormat);
107         }
108     }
109 
110     return vkFormats;
111 }
112 
113 // Returns a list of supported DRM formats
GetDrmFormats(const RendererVk * rendererVk)114 std::vector<EGLint> DisplayVkLinux::GetDrmFormats(const RendererVk *rendererVk)
115 {
116     std::unordered_set<EGLint> drmFormatsSet;
117     for (VkFormat vkFormat : GetVkFormatsWithDrmModifiers(rendererVk))
118     {
119         std::vector<EGLint> drmFormats = angle::VkFormatToDrmFourCCFormat(vkFormat);
120         for (EGLint drmFormat : drmFormats)
121         {
122             drmFormatsSet.insert(drmFormat);
123         }
124     }
125 
126     std::vector<EGLint> drmFormats;
127     std::copy(std::begin(drmFormatsSet), std::end(drmFormatsSet), std::back_inserter(drmFormats));
128 
129     return drmFormats;
130 }
131 
supportsDmaBufFormat(EGLint format) const132 bool DisplayVkLinux::supportsDmaBufFormat(EGLint format) const
133 {
134     return std::find(std::begin(mDrmFormats), std::end(mDrmFormats), format) !=
135            std::end(mDrmFormats);
136 }
137 
queryDmaBufFormats(EGLint maxFormats,EGLint * formats,EGLint * numFormats)138 egl::Error DisplayVkLinux::queryDmaBufFormats(EGLint maxFormats,
139                                               EGLint *formats,
140                                               EGLint *numFormats)
141 {
142     if (!mDrmFormatsInitialized)
143     {
144         mDrmFormats            = GetDrmFormats(getRenderer());
145         mDrmFormatsInitialized = true;
146     }
147 
148     EGLint formatsSize = static_cast<EGLint>(mDrmFormats.size());
149     *numFormats        = formatsSize;
150     if (maxFormats > 0)
151     {
152         // Do not copy data beyond the limits of the vector
153         maxFormats = std::min(maxFormats, formatsSize);
154         std::memcpy(formats, mDrmFormats.data(), maxFormats * sizeof(EGLint));
155     }
156 
157     return egl::NoError();
158 }
159 
160 // Queries DRM format modifiers associated to `drmFormat`.
161 // When `maxModifiers` is zero, it will only return the number of modifiers associated to
162 // `drmFormat` using the out parameter `numModifiers`. When `maxModifiers` is greater than zero, it
163 // will put that number of DRM format modifiers into the out parameter `modifiers`.
queryDmaBufModifiers(EGLint drmFormat,EGLint maxModifiers,EGLuint64KHR * modifiers,EGLBoolean * externalOnly,EGLint * numModifiers)164 egl::Error DisplayVkLinux::queryDmaBufModifiers(EGLint drmFormat,
165                                                 EGLint maxModifiers,
166                                                 EGLuint64KHR *modifiers,
167                                                 EGLBoolean *externalOnly,
168                                                 EGLint *numModifiers)
169 {
170     // A DRM format may correspond to multiple Vulkan formats
171     std::vector<VkFormat> vkFormats = angle::DrmFourCCFormatToVkFormats(drmFormat);
172 
173     std::vector<EGLuint64KHR> drmModifiers;
174     // Collect DRM format modifiers common to all those Vulkan formats
175     for (size_t i = 0; i < vkFormats.size(); ++i)
176     {
177         VkFormat vkFmt = vkFormats[i];
178 
179         std::vector<VkDrmFormatModifierPropertiesEXT> vkDrmMods = GetDrmModifiers(this, vkFmt);
180 
181         std::vector<EGLuint64KHR> drmMods(vkDrmMods.size());
182         std::transform(std::begin(vkDrmMods), std::end(vkDrmMods), std::begin(drmMods),
183                        [](VkDrmFormatModifierPropertiesEXT props) {
184                            return static_cast<EGLuint64KHR>(props.drmFormatModifier);
185                        });
186         std::sort(std::begin(drmMods), std::end(drmMods));
187 
188         if (i == 0)
189         {
190             // Just take the modifiers for the first format
191             drmModifiers = drmMods;
192         }
193         else
194         {
195             // Intersect the modifiers of all the other associated Vulkan formats
196             std::vector<EGLuint64KHR> prevMods = drmModifiers;
197             drmModifiers.clear();
198             std::set_intersection(std::begin(drmMods), std::end(drmMods), std::begin(prevMods),
199                                   std::end(prevMods), std::back_inserter(drmModifiers));
200         }
201     }
202 
203     EGLint drmModifiersSize = static_cast<EGLint>(drmModifiers.size());
204 
205     *numModifiers = drmModifiersSize;
206     if (maxModifiers > 0)
207     {
208         maxModifiers = std::min(maxModifiers, drmModifiersSize);
209         std::memcpy(modifiers, drmModifiers.data(), maxModifiers * sizeof(drmModifiers[0]));
210     }
211 
212     return egl::NoError();
213 }
214 }  // namespace rx
215