104 QVideoFrameFormat::PixelFormat qtFormat, QSize frameSize,
105 std::shared_ptr<
void> parentKeepAlive, DmaBufImportMode importMode)
107 qCDebug(qLDmaBuf) <<
"Importing textures from DMA buffer," << qtFormat;
108 Qt::HANDLE eglDisplay = eglContext.eglDisplay();
109 QOpenGLContext *glContext = eglContext.glContext();
111 QOpenGLFunctions functions(glContext);
112 const auto &elgImageFunctions = QEglImageFunctions::instance();
114 auto *desc = QVideoTextureHelper::textureDescription(qtFormat);
115 int nPlanes = desc->nplanes;
116 Q_ASSERT(planes.size() == nPlanes);
118 rhi.makeThreadLocalNativeContextCurrent();
122 if (importMode == DmaBufImportMode::PerPlane
123 && ranges::any_of(planes.first(nPlanes), [&](
const DmaBufPlane &plane) {
124 return isExternalOesOnly(elgImageFunctions, eglDisplay, plane);
126 qCDebug(qLDmaBuf) <<
"Planes can only be sampled as external textures, not importing";
127 return q23::unexpected{ FailureSeverity::recoverable };
130 QVideoFrameFormat::PixelFormat texturePixelFormat = qtFormat;
131 GLenum glTarget = GL_TEXTURE_2D;
132 if (importMode == DmaBufImportMode::SingleImage) {
134 texturePixelFormat = QVideoFrameFormat::Format_RGBA8888;
135#ifdef GL_OES_EGL_image_external
136 if (QVideoTextureHelper::forceGlTextureExternalOesIsSet()) {
137 texturePixelFormat = QVideoFrameFormat::Format_SamplerExternalOES;
138 glTarget = GL_TEXTURE_EXTERNAL_OES;
143 const int nImages = importMode == DmaBufImportMode::SingleImage ? 1 : nPlanes;
145 std::array<EGLImageHandle, 4> images;
146 std::array<GLuint, 4> rawGlTextures{};
147 functions.glGenTextures(nImages, rawGlTextures.data());
149 std::vector<GlTextureHandle> glTextures;
150 glTextures.reserve(nImages);
151 for (
int i = 0; i < nImages; ++i)
152 glTextures.emplace_back(rawGlTextures[i], GlTextureDeleter(glContext));
155 [&](
int image, DRMFormat drmFormat, QSize imageSize,
156 QSpan<
const DmaBufPlane> imagePlanes) -> q23::expected<
void, FailureSeverity> {
157 constexpr EGLint fdAttrs[4] = {
158 EGL_DMA_BUF_PLANE0_FD_EXT,
159 EGL_DMA_BUF_PLANE1_FD_EXT,
160 EGL_DMA_BUF_PLANE2_FD_EXT,
161 EGL_DMA_BUF_PLANE3_FD_EXT,
163 constexpr EGLint offsetAttrs[4] = {
164 EGL_DMA_BUF_PLANE0_OFFSET_EXT,
165 EGL_DMA_BUF_PLANE1_OFFSET_EXT,
166 EGL_DMA_BUF_PLANE2_OFFSET_EXT,
167 EGL_DMA_BUF_PLANE3_OFFSET_EXT,
169 constexpr EGLint pitchAttrs[4] = {
170 EGL_DMA_BUF_PLANE0_PITCH_EXT,
171 EGL_DMA_BUF_PLANE1_PITCH_EXT,
172 EGL_DMA_BUF_PLANE2_PITCH_EXT,
173 EGL_DMA_BUF_PLANE3_PITCH_EXT,
175 constexpr EGLint modifierLoAttrs[4] = {
176 EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
177 EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
178 EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
179 EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
181 constexpr EGLint modifierHiAttrs[4] = {
182 EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
183 EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
184 EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
185 EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
188 constexpr size_t maxAttrCount = 6 + 4 * 10 + 1;
189 std::array<EGLAttrib, maxAttrCount> img_attr = {
190 EGL_LINUX_DRM_FOURCC_EXT,
191 (EGLint)qToUnderlying(drmFormat),
197 size_t img_attr_idx = 6;
198 for (
int plane = 0; plane < imagePlanes.size() && plane < 4; ++plane) {
199 const DmaBufPlane &dmabuf = imagePlanes[plane];
200 img_attr[img_attr_idx++] = fdAttrs[plane];
201 img_attr[img_attr_idx++] = dmabuf.fd;
202 img_attr[img_attr_idx++] = offsetAttrs[plane];
203 img_attr[img_attr_idx++] = (EGLint)dmabuf.offset;
204 img_attr[img_attr_idx++] = pitchAttrs[plane];
205 img_attr[img_attr_idx++] = (EGLint)dmabuf.pitch;
206 if (dmabuf.modifier != DmaBufFormatModifierInvalid) {
207 const auto modifier = qToUnderlying(dmabuf.modifier);
208 img_attr[img_attr_idx++] = modifierLoAttrs[plane];
209 img_attr[img_attr_idx++] = EGLAttrib(modifier & 0xFFFFFFFF);
210 img_attr[img_attr_idx++] = modifierHiAttrs[plane];
211 img_attr[img_attr_idx++] = EGLAttrib(modifier >> 32);
214 img_attr[img_attr_idx++] = EGL_NONE;
215 Q_ASSERT(img_attr_idx <= maxAttrCount);
217 images[image] = elgImageFunctions.eglCreateImage(
218 eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
nullptr,
219 QSpan<
const EGLAttrib>(img_attr.data(), img_attr_idx));
220 if (!images[image]) {
221 const EGLError error = EGLError(eglGetError());
223 case EGLError::Success: {
226 case EGLError::BadMatch: {
227 qWarning() <<
"eglCreateImage failed for image" << image <<
"with" << error
228 <<
", disabling hardware acceleration. "
229 "This could indicate an EGL implementation issue."
231 << eglQueryString(eglDisplay, EGL_VENDOR);
233 return q23::unexpected{ FailureSeverity::unrecoverable };
235 case EGLError::BadParameter: {
236 bool dmaModifierNotSupported =
237 ranges::any_of(imagePlanes, [&](
const DmaBufPlane &plane) {
238 return dmaModifierIsNotSupportedByDisplay(plane, eglDisplay);
240 if (dmaModifierNotSupported) {
241 qWarning() <<
"eglCreateImage failed for image" << image <<
"with" << error
242 <<
", disabling hardware acceleration. "
243 "This could indicate an EGL implementation issue."
245 << eglQueryString(eglDisplay, EGL_VENDOR);
247 return q23::unexpected{ FailureSeverity::unrecoverable };
252 qWarning() <<
"eglCreateImage failed for image" << image <<
"with" << error;
253 return q23::unexpected{ FailureSeverity::recoverable };
257 functions.glActiveTexture(GL_TEXTURE0 + image);
258 functions.glBindTexture(glTarget, glTextures[image].get());
260 elgImageFunctions.glEGLImageTargetTexture2DOES(glTarget, images[image].get());
261 const GLError error = GLError(glGetError());
262 if (error != GLError::NoError) {
263 qWarning() <<
"eglImageTargetTexture2D failed for image" << image <<
"with" << error
264 <<
"(the driver may not support importing this dma-buf as a GL texture)";
265 return q23::unexpected{ FailureSeverity::recoverable };
270 switch (importMode) {
271 case DmaBufImportMode::SingleImage: {
272 const auto combinedFormat = dmaBufSingleImageFourccFromPixelFormat(qtFormat);
273 if (!combinedFormat) {
274 qCWarning(qLDmaBuf) <<
"No single-image DRM format for" << qtFormat;
275 return q23::unexpected(FailureSeverity::recoverable);
277 auto result = importImage(0, *combinedFormat, frameSize, planes.first(nPlanes));
279 return q23::unexpected(result.error());
282 case DmaBufImportMode::PerPlane:
283 for (
int i = 0; i < nPlanes; ++i) {
284 const QSize planeSize = desc->rhiPlaneSize(frameSize, i, &rhi);
285 auto result = importImage(i, planes[i].drmFormat, planeSize, planes.subspan(i, 1));
287 return q23::unexpected(result.error());
294 for (
int i = 0; i < nImages; ++i) {
295 functions.glActiveTexture(GL_TEXTURE0 + i);
296 functions.glBindTexture(glTarget, 0);
299 return std::make_unique<DmaBufTextureHandles>(rhi,
std::move(glTextures), texturePixelFormat,
300 std::move(parentKeepAlive));