diff options
Diffstat (limited to 'src/core/ozone/surface_factory_qt.cpp')
-rw-r--r-- | src/core/ozone/surface_factory_qt.cpp | 272 |
1 files changed, 227 insertions, 45 deletions
diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp index 846d930d6..204f4d62d 100644 --- a/src/core/ozone/surface_factory_qt.cpp +++ b/src/core/ozone/surface_factory_qt.cpp @@ -1,78 +1,260 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #if defined(USE_OZONE) #include "surface_factory_qt.h" +#include "qtwebenginecoreglobal_p.h" #include "ozone/gl_context_qt.h" #include "ozone/gl_ozone_egl_qt.h" -#if defined(USE_GLX) + +#include "media/gpu/buildflags.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_buffer.h" +#include "ui/gfx/linux/native_pixmap_dmabuf.h" +#include "ui/gl/egl_util.h" +#include "ui/ozone/buildflags.h" + +#include <QDebug> +#include <QtGui/qtgui-config.h> + +#if BUILDFLAG(OZONE_PLATFORM_X11) #include "ozone/gl_ozone_glx_qt.h" + +#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" +#endif + +#if QT_CONFIG(webengine_vulkan) +#include "compositor/vulkan_implementation_qt.h" #endif namespace QtWebEngineCore { SurfaceFactoryQt::SurfaceFactoryQt() { -#if defined(USE_GLX) +#if BUILDFLAG(OZONE_PLATFORM_X11) if (GLContextHelper::getGlxPlatformInterface()) { - m_impl = { gl::kGLImplementationDesktopGL }; + m_impl = { gl::GLImplementationParts(gl::kGLImplementationDesktopGL), + gl::GLImplementationParts(gl::kGLImplementationDisabled) }; m_ozone.reset(new ui::GLOzoneGLXQt()); } else #endif if (GLContextHelper::getEglPlatformInterface()) { - m_impl = { gl::kGLImplementationDesktopGL, gl::kGLImplementationEGLGLES2 }; + m_impl = { gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), + gl::GLImplementationParts(gl::kGLImplementationDesktopGL), + gl::GLImplementationParts(gl::kGLImplementationDisabled) }; m_ozone.reset(new ui::GLOzoneEGLQt()); } else { - qFatal("No suitable graphics backend found\n"); + m_impl = { gl::GLImplementationParts(gl::kGLImplementationDisabled) }; } } -std::vector<gl::GLImplementation> SurfaceFactoryQt::GetAllowedGLImplementations() +std::vector<gl::GLImplementationParts> SurfaceFactoryQt::GetAllowedGLImplementations() { return m_impl; } -ui::GLOzone* SurfaceFactoryQt::GetGLOzone(gl::GLImplementation implementation) +ui::GLOzone *SurfaceFactoryQt::GetGLOzone(const gl::GLImplementationParts &implementation) { return m_ozone.get(); } +#if BUILDFLAG(ENABLE_VULKAN) +std::unique_ptr<gpu::VulkanImplementation> +SurfaceFactoryQt::CreateVulkanImplementation(bool /*allow_protected_memory*/, + bool /*enforce_protected_memory*/) +{ +#if QT_CONFIG(webengine_vulkan) + return std::make_unique<gpu::VulkanImplementationQt>(); +#else + return nullptr; +#endif +} +#endif + +bool SurfaceFactoryQt::CanCreateNativePixmapForFormat(gfx::BufferFormat format) +{ +#if BUILDFLAG(OZONE_PLATFORM_X11) + if (GLContextHelper::getGlxPlatformInterface()) + return ui::GpuMemoryBufferSupportX11::GetInstance()->CanCreateNativePixmapForFormat(format); +#endif + + if (GLContextHelper::getEglPlatformInterface()) + return ui::SurfaceFactoryOzone::CanCreateNativePixmapForFormat(format); + + return false; +} + +scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap( + gfx::AcceleratedWidget widget, + gpu::VulkanDeviceQueue *device_queue, + gfx::Size size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + absl::optional<gfx::Size> framebuffer_size) +{ + Q_ASSERT(SupportsNativePixmaps()); + +#if QT_CONFIG(opengl) + if (framebuffer_size && !gfx::Rect(size).Contains(gfx::Rect(*framebuffer_size))) + return nullptr; + + gfx::NativePixmapHandle handle; + +#if BUILDFLAG(OZONE_PLATFORM_X11) + if (GLContextHelper::getGlxPlatformInterface()) { + auto gbmBuffer = + ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size, usage); + if (!gbmBuffer) + qFatal("Failed to create GBM buffer for GLX."); + handle = gbmBuffer->ExportHandle(); + } +#endif + + if (GLContextHelper::getEglPlatformInterface()) { + int fd = -1; + int stride; + int offset; + uint64_t modifiers; + EGLHelper::instance()->queryDmaBuf(size.width(), size.height(), &fd, &stride, &offset, + &modifiers); + if (fd == -1) + qFatal("Failed to query DRM FD for EGL."); + + const uint64_t planeSize = uint64_t(size.width()) * size.height() * 4; + gfx::NativePixmapPlane plane(stride, offset, planeSize, base::ScopedFD(::dup(fd))); + + handle.planes.push_back(std::move(plane)); + handle.modifier = modifiers; + } + + return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(handle)); +#else + return nullptr; +#endif // QT_CONFIG(opengl) +} + +void SurfaceFactoryQt::CreateNativePixmapAsync( + gfx::AcceleratedWidget widget, + gpu::VulkanDeviceQueue *device_queue, + gfx::Size size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + NativePixmapCallback callback) +{ + Q_ASSERT(SupportsNativePixmaps()); + // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it + // and return the result with the provided callback. + std::move(callback).Run(CreateNativePixmap(widget, device_queue, size, format, usage)); +} + +scoped_refptr<gfx::NativePixmap> +SurfaceFactoryQt::CreateNativePixmapFromHandle( + gfx::AcceleratedWidget /*widget*/, + gfx::Size size, + gfx::BufferFormat format, + gfx::NativePixmapHandle handle) +{ + Q_ASSERT(SupportsNativePixmaps()); + +#if QT_CONFIG(opengl) + gfx::NativePixmapHandle bufferHandle; + +#if BUILDFLAG(OZONE_PLATFORM_X11) + if (GLContextHelper::getGlxPlatformInterface()) { + auto gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBufferFromHandle( + size, format, std::move(handle)); + if (!gbmBuffer) + qFatal("Failed to create GBM buffer for GLX."); + bufferHandle = gbmBuffer->ExportHandle(); + } +#endif + + if (GLContextHelper::getEglPlatformInterface()) { + const size_t numPlanes = handle.planes.size(); + const uint32_t fourccFormat = ui::GetFourCCFormatFromBufferFormat(format); + + std::vector<EGLAttrib> attrs; + attrs.push_back(EGL_WIDTH); + attrs.push_back(size.width()); + attrs.push_back(EGL_HEIGHT); + attrs.push_back(size.height()); + attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT); + attrs.push_back(fourccFormat); + for (size_t planeIndex = 0; planeIndex < numPlanes; ++planeIndex) { + attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + planeIndex * 3); + attrs.push_back(handle.planes[planeIndex].fd.get()); + attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + planeIndex * 3); + attrs.push_back(handle.planes[planeIndex].offset); + attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + planeIndex * 3); + attrs.push_back(handle.planes[planeIndex].stride); + attrs.push_back(EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT + planeIndex * 2); + attrs.push_back(handle.modifier & 0xffffffff); + attrs.push_back(EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + planeIndex * 2); + attrs.push_back(handle.modifier >> 32); + } + attrs.push_back(EGL_NONE); + + EGLDisplay eglDisplay = GLContextHelper::getEGLDisplay(); + EGLHelper *eglHelper = EGLHelper::instance(); + auto *eglFun = eglHelper->functions(); + + EGLImage eglImage = + eglFun->eglCreateImage(eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, + (EGLClientBuffer)NULL, attrs.data()); + if (eglImage == EGL_NO_IMAGE_KHR) { + qFatal() << "Failed to import EGLImage:" + << ui::GetEGLErrorString(eglFun->eglGetError()); + } + + Q_ASSERT(numPlanes <= 3); + int fds[3]; + int strides[3]; + int offsets[3]; + if (!eglFun->eglExportDMABUFImageMESA(eglDisplay, eglImage, fds, strides, offsets)) { + qFatal() << "Failed to export EGLImage:" + << ui::GetEGLErrorString(eglFun->eglGetError()); + } + + bufferHandle.modifier = handle.modifier; + for (size_t i = 0; i < numPlanes; ++i) { + int fd = fds[i]; + int stride = strides[i]; + int offset = offsets[i]; + int size = handle.planes[i].size; + + if (fd == -1) { + fd = fds[0]; + stride = handle.planes[i].stride; + offset = handle.planes[i].offset; + } + + gfx::NativePixmapPlane plane(stride, offset, size, base::ScopedFD(::dup(fd))); + bufferHandle.planes.push_back(std::move(plane)); + } + + eglFun->eglDestroyImage(eglDisplay, eglImage); + } + + return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(bufferHandle)); +#else + return nullptr; +#endif // QT_CONFIG(opengl) +} + +bool SurfaceFactoryQt::SupportsNativePixmaps() const +{ +#if QT_CONFIG(opengl) +#if BUILDFLAG(OZONE_PLATFORM_X11) + if (GLContextHelper::getGlxPlatformInterface()) + return ui::GpuMemoryBufferSupportX11::GetInstance()->has_gbm_device(); +#endif // BUILDFLAG(OZONE_PLATFORM_X11) + + if (GLContextHelper::getEglPlatformInterface()) + return EGLHelper::instance()->isDmaBufSupported(); +#endif // QT_CONFIG(opengl) + + return false; +} } // namespace QtWebEngineCore #endif // defined(USE_OZONE) |