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.
11 #include "ServiceBroker.h"
12 #include "utils/DRMHelpers.h"
13 #include "utils/EGLUtils.h"
14 #include "utils/StringUtils.h"
15 #include "utils/log.h"
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
,
59 #define X(VAL) std::make_pair(VAL, #VAL)
60 std::map
<EGLint
, const char*> eglAttributes
=
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
),
108 CEGLImage::CEGLImage(EGLDisplay display
)
109 : m_display(display
),
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)}});
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)
162 std::string valueStr
;
164 auto eglAttrKey
= eglAttributes
.find(attrs
[i
]);
165 if (eglAttrKey
!= eglAttributes
.end())
167 keyStr
= eglAttrKey
->second
;
171 keyStr
= std::to_string(attrs
[i
]);
174 auto eglAttrValue
= eglAttributes
.find(attrs
[i
+ 1]);
175 if (eglAttrValue
!= eglAttributes
.end())
177 valueStr
= eglAttrValue
->second
;
181 if (eglAttrKey
!= eglAttributes
.end() && eglAttrKey
->first
== EGL_LINUX_DRM_FOURCC_EXT
)
182 valueStr
= DRMHELPERS::FourCCToString(attrs
[i
+ 1]);
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
);
195 CLog::Log(LOGERROR
, "CEGLImage::{} - failed to import buffer into EGL image: {:#4x}",
196 __FUNCTION__
, eglGetError());
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");
221 if (eglQueryDmaBufFormatsEXT(m_display
, 0, nullptr, &numFormats
) != EGL_TRUE
)
224 "CEGLImage::{} - failed to query the max number of EGL dma-buf formats: {:#4x}",
225 __FUNCTION__
, eglGetError());
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__
,
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
));
254 CLog::Log(LOGERROR
, "CEGLImage::{} - format not supported: {}", __FUNCTION__
,
255 DRMHELPERS::FourCCToString(format
));
260 bool CEGLImage::SupportsFormatAndModifier(uint32_t format
, uint64_t modifier
)
262 if (!SupportsFormat(format
))
265 if (modifier
== DRM_FORMAT_MOD_LINEAR
)
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");
280 if (eglQueryDmaBufModifiersEXT(m_display
, format
, 0, nullptr, nullptr, &numFormats
) != EGL_TRUE
)
283 "CEGLImage::{} - failed to query the max number of EGL dma-buf format modifiers for "
284 "format: {} - {:#4x}",
285 __FUNCTION__
, DRMHELPERS::FourCCToString(format
), eglGetError());
289 std::vector
<EGLuint64KHR
> modifiers(numFormats
);
291 if (eglQueryDmaBufModifiersEXT(m_display
, format
, numFormats
, modifiers
.data(), nullptr,
292 &numFormats
) != EGL_TRUE
)
296 "CEGLImage::{} - failed to query EGL dma-buf format modifiers for format: {} - {:#4x}",
297 __FUNCTION__
, DRMHELPERS::FourCCToString(format
), eglGetError());
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
));
318 CLog::Log(LOGERROR
, "CEGLImage::{} - modifier ({}) not supported for format ({})", __FUNCTION__
,
319 DRMHELPERS::ModifierToString(modifier
), DRMHELPERS::FourCCToString(format
));