Merge pull request #26220 from 78andyp/blurayfixes
[xbmc.git] / xbmc / utils / EGLImage.cpp
blob623721fd57744f7eb7c3c3dec7c019232ea1cf7e
1 /*
2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "EGLImage.h"
11 #include "ServiceBroker.h"
12 #include "utils/DRMHelpers.h"
13 #include "utils/EGLUtils.h"
14 #include "utils/StringUtils.h"
15 #include "utils/log.h"
17 #include <algorithm>
18 #include <map>
20 namespace
22 const EGLint eglDmabufPlaneFdAttr[CEGLImage::MAX_NUM_PLANES] =
24 EGL_DMA_BUF_PLANE0_FD_EXT,
25 EGL_DMA_BUF_PLANE1_FD_EXT,
26 EGL_DMA_BUF_PLANE2_FD_EXT,
29 const EGLint eglDmabufPlaneOffsetAttr[CEGLImage::MAX_NUM_PLANES] =
31 EGL_DMA_BUF_PLANE0_OFFSET_EXT,
32 EGL_DMA_BUF_PLANE1_OFFSET_EXT,
33 EGL_DMA_BUF_PLANE2_OFFSET_EXT,
36 const EGLint eglDmabufPlanePitchAttr[CEGLImage::MAX_NUM_PLANES] =
38 EGL_DMA_BUF_PLANE0_PITCH_EXT,
39 EGL_DMA_BUF_PLANE1_PITCH_EXT,
40 EGL_DMA_BUF_PLANE2_PITCH_EXT,
43 #if defined(EGL_EXT_image_dma_buf_import_modifiers)
44 const EGLint eglDmabufPlaneModifierLoAttr[CEGLImage::MAX_NUM_PLANES] =
46 EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
47 EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
48 EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
51 const EGLint eglDmabufPlaneModifierHiAttr[CEGLImage::MAX_NUM_PLANES] =
53 EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
54 EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
55 EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
57 #endif
59 #define X(VAL) std::make_pair(VAL, #VAL)
60 std::map<EGLint, const char*> eglAttributes =
62 X(EGL_WIDTH),
63 X(EGL_HEIGHT),
65 // please keep attributes in accordance to:
66 // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
67 X(EGL_LINUX_DRM_FOURCC_EXT),
68 X(EGL_DMA_BUF_PLANE0_FD_EXT),
69 X(EGL_DMA_BUF_PLANE0_OFFSET_EXT),
70 X(EGL_DMA_BUF_PLANE0_PITCH_EXT),
71 X(EGL_DMA_BUF_PLANE1_FD_EXT),
72 X(EGL_DMA_BUF_PLANE1_OFFSET_EXT),
73 X(EGL_DMA_BUF_PLANE1_PITCH_EXT),
74 X(EGL_DMA_BUF_PLANE2_FD_EXT),
75 X(EGL_DMA_BUF_PLANE2_OFFSET_EXT),
76 X(EGL_DMA_BUF_PLANE2_PITCH_EXT),
77 X(EGL_YUV_COLOR_SPACE_HINT_EXT),
78 X(EGL_SAMPLE_RANGE_HINT_EXT),
79 X(EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT),
80 X(EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT),
81 X(EGL_ITU_REC601_EXT),
82 X(EGL_ITU_REC709_EXT),
83 X(EGL_ITU_REC2020_EXT),
84 X(EGL_YUV_FULL_RANGE_EXT),
85 X(EGL_YUV_NARROW_RANGE_EXT),
86 X(EGL_YUV_CHROMA_SITING_0_EXT),
87 X(EGL_YUV_CHROMA_SITING_0_5_EXT),
89 #if defined(EGL_EXT_image_dma_buf_import_modifiers)
90 // please keep attributes in accordance to:
91 // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt
92 X(EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT),
93 X(EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT),
94 X(EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT),
95 X(EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT),
96 X(EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT),
97 X(EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT),
98 X(EGL_DMA_BUF_PLANE3_FD_EXT),
99 X(EGL_DMA_BUF_PLANE3_OFFSET_EXT),
100 X(EGL_DMA_BUF_PLANE3_PITCH_EXT),
101 X(EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT),
102 X(EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT),
103 #endif
106 } // namespace
108 CEGLImage::CEGLImage(EGLDisplay display)
109 : m_display(display),
110 m_eglCreateImageKHR(
111 CEGLUtils::GetRequiredProcAddress<PFNEGLCREATEIMAGEKHRPROC>("eglCreateImageKHR")),
112 m_eglDestroyImageKHR(
113 CEGLUtils::GetRequiredProcAddress<PFNEGLDESTROYIMAGEKHRPROC>("eglDestroyImageKHR")),
114 m_glEGLImageTargetTexture2DOES(
115 CEGLUtils::GetRequiredProcAddress<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
116 "glEGLImageTargetTexture2DOES"))
120 bool CEGLImage::CreateImage(EglAttrs imageAttrs)
122 CEGLAttributes<22> attribs;
123 attribs.Add({{EGL_WIDTH, imageAttrs.width},
124 {EGL_HEIGHT, imageAttrs.height},
125 {EGL_LINUX_DRM_FOURCC_EXT, static_cast<EGLint>(imageAttrs.format)}});
127 if (imageAttrs.colorSpace != 0 && imageAttrs.colorRange != 0)
129 attribs.Add({{EGL_YUV_COLOR_SPACE_HINT_EXT, imageAttrs.colorSpace},
130 {EGL_SAMPLE_RANGE_HINT_EXT, imageAttrs.colorRange},
131 {EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT, EGL_YUV_CHROMA_SITING_0_EXT},
132 {EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT, EGL_YUV_CHROMA_SITING_0_EXT}});
135 for (int i = 0; i < MAX_NUM_PLANES; i++)
137 if (imageAttrs.planes[i].fd != 0)
139 attribs.Add({{eglDmabufPlaneFdAttr[i], imageAttrs.planes[i].fd},
140 {eglDmabufPlaneOffsetAttr[i], imageAttrs.planes[i].offset},
141 {eglDmabufPlanePitchAttr[i], imageAttrs.planes[i].pitch}});
143 #if defined(EGL_EXT_image_dma_buf_import_modifiers)
144 if (imageAttrs.planes[i].modifier != DRM_FORMAT_MOD_INVALID && imageAttrs.planes[i].modifier != DRM_FORMAT_MOD_LINEAR)
145 attribs.Add({{eglDmabufPlaneModifierLoAttr[i], static_cast<EGLint>(imageAttrs.planes[i].modifier & 0xFFFFFFFF)},
146 {eglDmabufPlaneModifierHiAttr[i], static_cast<EGLint>(imageAttrs.planes[i].modifier >> 32)}});
147 #endif
151 m_image = m_eglCreateImageKHR(m_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attribs.Get());
153 if (!m_image || CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO))
155 const EGLint* attrs = attribs.Get();
157 std::string eglString;
159 for (int i = 0; i < (attribs.Size()); i += 2)
161 std::string keyStr;
162 std::string valueStr;
164 auto eglAttrKey = eglAttributes.find(attrs[i]);
165 if (eglAttrKey != eglAttributes.end())
167 keyStr = eglAttrKey->second;
169 else
171 keyStr = std::to_string(attrs[i]);
174 auto eglAttrValue = eglAttributes.find(attrs[i + 1]);
175 if (eglAttrValue != eglAttributes.end())
177 valueStr = eglAttrValue->second;
179 else
181 if (eglAttrKey != eglAttributes.end() && eglAttrKey->first == EGL_LINUX_DRM_FOURCC_EXT)
182 valueStr = DRMHELPERS::FourCCToString(attrs[i + 1]);
183 else
184 valueStr = std::to_string(attrs[i + 1]);
187 eglString.append(StringUtils::Format("{}: {}\n", keyStr, valueStr));
190 CLog::Log(LOGDEBUG, "CEGLImage::{} - attributes:\n{}", __FUNCTION__, eglString);
193 if (!m_image)
195 CLog::Log(LOGERROR, "CEGLImage::{} - failed to import buffer into EGL image: {:#4x}",
196 __FUNCTION__, eglGetError());
197 return false;
200 return true;
203 void CEGLImage::UploadImage(GLenum textureTarget)
205 m_glEGLImageTargetTexture2DOES(textureTarget, m_image);
208 void CEGLImage::DestroyImage()
210 m_eglDestroyImageKHR(m_display, m_image);
213 #if defined(EGL_EXT_image_dma_buf_import_modifiers)
214 bool CEGLImage::SupportsFormat(uint32_t format)
216 auto eglQueryDmaBufFormatsEXT =
217 CEGLUtils::GetRequiredProcAddress<PFNEGLQUERYDMABUFFORMATSEXTPROC>(
218 "eglQueryDmaBufFormatsEXT");
220 EGLint numFormats;
221 if (eglQueryDmaBufFormatsEXT(m_display, 0, nullptr, &numFormats) != EGL_TRUE)
223 CLog::Log(LOGERROR,
224 "CEGLImage::{} - failed to query the max number of EGL dma-buf formats: {:#4x}",
225 __FUNCTION__, eglGetError());
226 return false;
229 std::vector<EGLint> formats(numFormats);
230 if (eglQueryDmaBufFormatsEXT(m_display, numFormats, formats.data(), &numFormats) != EGL_TRUE)
232 CLog::Log(LOGERROR, "CEGLImage::{} - failed to query EGL dma-buf formats: {:#4x}", __FUNCTION__,
233 eglGetError());
234 return false;
237 auto foundFormat = std::find(formats.begin(), formats.end(), format);
238 if (foundFormat == formats.end() || CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO))
240 std::string formatStr;
241 for (const auto& supportedFormat : formats)
242 formatStr.append("\n" + DRMHELPERS::FourCCToString(supportedFormat));
244 CLog::Log(LOGDEBUG, "CEGLImage::{} - supported formats:{}", __FUNCTION__, formatStr);
247 if (foundFormat != formats.end())
249 CLog::Log(LOGDEBUG, LOGVIDEO, "CEGLImage::{} - supported format: {}", __FUNCTION__,
250 DRMHELPERS::FourCCToString(format));
251 return true;
254 CLog::Log(LOGERROR, "CEGLImage::{} - format not supported: {}", __FUNCTION__,
255 DRMHELPERS::FourCCToString(format));
257 return false;
260 bool CEGLImage::SupportsFormatAndModifier(uint32_t format, uint64_t modifier)
262 if (!SupportsFormat(format))
263 return false;
265 if (modifier == DRM_FORMAT_MOD_LINEAR)
266 return true;
269 * Some broadcom modifiers have parameters encoded which need to be
270 * masked out before comparing with reported modifiers.
272 if (modifier >> 56 == DRM_FORMAT_MOD_VENDOR_BROADCOM)
273 modifier = fourcc_mod_broadcom_mod(modifier);
275 auto eglQueryDmaBufModifiersEXT =
276 CEGLUtils::GetRequiredProcAddress<PFNEGLQUERYDMABUFMODIFIERSEXTPROC>(
277 "eglQueryDmaBufModifiersEXT");
279 EGLint numFormats;
280 if (eglQueryDmaBufModifiersEXT(m_display, format, 0, nullptr, nullptr, &numFormats) != EGL_TRUE)
282 CLog::Log(LOGERROR,
283 "CEGLImage::{} - failed to query the max number of EGL dma-buf format modifiers for "
284 "format: {} - {:#4x}",
285 __FUNCTION__, DRMHELPERS::FourCCToString(format), eglGetError());
286 return false;
289 std::vector<EGLuint64KHR> modifiers(numFormats);
291 if (eglQueryDmaBufModifiersEXT(m_display, format, numFormats, modifiers.data(), nullptr,
292 &numFormats) != EGL_TRUE)
294 CLog::Log(
295 LOGERROR,
296 "CEGLImage::{} - failed to query EGL dma-buf format modifiers for format: {} - {:#4x}",
297 __FUNCTION__, DRMHELPERS::FourCCToString(format), eglGetError());
298 return false;
301 auto foundModifier = std::find(modifiers.begin(), modifiers.end(), modifier);
302 if (foundModifier == modifiers.end() || CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO))
304 std::string modifierStr;
305 for (const auto& supportedModifier : modifiers)
306 modifierStr.append("\n" + DRMHELPERS::ModifierToString(supportedModifier));
308 CLog::Log(LOGDEBUG, "CEGLImage::{} - supported modifiers:{}", __FUNCTION__, modifierStr);
311 if (foundModifier != modifiers.end())
313 CLog::Log(LOGDEBUG, LOGVIDEO, "CEGLImage::{} - supported modifier: {}", __FUNCTION__,
314 DRMHELPERS::ModifierToString(modifier));
315 return true;
318 CLog::Log(LOGERROR, "CEGLImage::{} - modifier ({}) not supported for format ({})", __FUNCTION__,
319 DRMHELPERS::ModifierToString(modifier), DRMHELPERS::FourCCToString(format));
321 return false;
323 #endif