10#include "compositor.h" 
   24#include <QOpenGLContext> 
   28#include <drm_fourcc.h> 
   34static std::unique_ptr<EglContext> s_globalShareContext;
 
   36static bool isOpenGLES_helper()
 
   38    if (qstrcmp(qgetenv(
"KWIN_COMPOSE"), 
"O2ES") == 0) {
 
   41    return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES;
 
   45    : m_deviceId(deviceId)
 
 
   56    if (!s_globalShareContext) {
 
   59    if (s_globalShareContext) {
 
   60        kwinApp()->outputBackend()->setSceneEglGlobalShareContext(s_globalShareContext->handle());
 
 
   69    EglDisplay *
const eglDisplay = kwinApp()->outputBackend()->sceneEglDisplayObject();
 
   70    if (!eglDisplay || !s_globalShareContext) {
 
   73    s_globalShareContext.reset();
 
   74    kwinApp()->outputBackend()->setSceneEglGlobalShareContext(EGL_NO_CONTEXT);
 
 
  109static eglFuncPtr getProcAddress(
const char *name)
 
  111    return eglGetProcAddress(name);
 
  124    if (!WaylandServer::self()) {
 
  130        if (renderNode.isEmpty()) {
 
  131            drmDevice *device = 
nullptr;
 
  132            if (drmGetDeviceFromDevId(
deviceId(), 0, &device) != 0) {
 
  133                qCWarning(KWIN_OPENGL) << 
"drmGetDeviceFromDevId() failed:" << strerror(errno);
 
  135                if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
 
  136                    renderNode = QString::fromLocal8Bit(device->nodes[DRM_NODE_RENDER]);
 
  137                } 
else if (device->available_nodes & (1 << DRM_NODE_PRIMARY)) {
 
  138                    qCWarning(KWIN_OPENGL) << 
"No render nodes have been found, falling back to primary node";
 
  139                    renderNode = QString::fromLocal8Bit(device->nodes[DRM_NODE_PRIMARY]);
 
  141                drmFreeDevice(&device);
 
  145        if (!renderNode.isEmpty()) {
 
  148            qCWarning(KWIN_OPENGL) << 
"No render node have been found, not initializing wl-drm";
 
  153    auto filterFormats = [
this, &formats](std::optional<uint32_t> bpc, 
bool withExternalOnlyYUV) {
 
  154        QHash<uint32_t, QList<uint64_t>> set;
 
  155        for (
auto it = formats.constBegin(); it != formats.constEnd(); it++) {
 
  157            if (!info || (bpc && bpc != info->bitsPerColor)) {
 
  161            const bool externalOnlySupported = withExternalOnlyYUV && info->yuvConversion();
 
  162            QList<uint64_t> modifiers = externalOnlySupported ? it->allModifiers : it->nonExternalOnlyModifiers;
 
  164            if (externalOnlySupported && !modifiers.isEmpty()) {
 
  165                if (
auto yuv = info->yuvConversion()) {
 
  166                    for (
auto plane : std::as_const(yuv->plane)) {
 
  167                        const auto planeModifiers = formats.value(plane.format).allModifiers;
 
  168                        modifiers.erase(std::remove_if(modifiers.begin(), modifiers.end(), [&planeModifiers](uint64_t mod) {
 
  169                                            return !planeModifiers.contains(mod);
 
  175            for (
const auto &tranche : std::as_const(
m_tranches)) {
 
  176                if (modifiers.isEmpty()) {
 
  179                const auto trancheModifiers = tranche.formatTable.value(it.key());
 
  180                for (
auto trancheModifier : trancheModifiers) {
 
  181                    modifiers.removeAll(trancheModifier);
 
  184            if (modifiers.isEmpty()) {
 
  187            set.insert(it.key(), modifiers);
 
  192    auto includeShaderConversions = [](QHash<uint32_t, QList<uint64_t>> &&formats) -> QHash<uint32_t, QList<uint64_t>> {
 
  193        for (
auto format : s_drmConversions.keys()) {
 
  194            auto &modifiers = formats[
format];
 
  195            if (modifiers.isEmpty()) {
 
  196                modifiers = {DRM_FORMAT_MOD_LINEAR};
 
  206            .formatTable = filterFormats(10, 
false),
 
  212        .formatTable = filterFormats(8, 
false),
 
  217        .formatTable = includeShaderConversions(filterFormats({}, 
true)),
 
 
  228    const char *clientExtensionsCString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
 
  229    const QByteArray clientExtensionsString = QByteArray::fromRawData(clientExtensionsCString, qstrlen(clientExtensionsCString));
 
  230    if (clientExtensionsString.isEmpty()) {
 
 
  246    if (QOpenGLContext *context = QOpenGLContext::currentContext()) {
 
  248        context->doneCurrent();
 
 
  260    return isOpenGLES_helper();
 
 
  294    std::pair key(buffer, plane);
 
  302    if (image != EGL_NO_IMAGE_KHR) {
 
  304        connect(buffer, &QObject::destroyed, 
this, [
this, key]() {
 
  308        qCWarning(KWIN_OPENGL) << 
"failed to import dmabuf" << buffer;
 
 
  316    auto key = std::pair(buffer, 0);
 
  324    if (image != EGL_NO_IMAGE_KHR) {
 
  326        connect(buffer, &QObject::destroyed, 
this, [
this, key]() {
 
  330        qCWarning(KWIN_OPENGL) << 
"failed to import dmabuf" << buffer;
 
 
  348    return m_context->importDmaBufAsTexture(attributes);
 
 
  382#include "moc_abstract_egl_backend.cpp" 
void initClientExtensions()
EGLSurface surface() const
virtual void cleanupSurfaces()
bool makeCurrent() override
bool hasClientExtension(const QByteArray &ext) const
EglDisplay * eglDisplayObject() const
QList< LinuxDmaBufV1Feedback::Tranche > tranches() const
void setEglDisplay(EglDisplay *display)
EGLImageKHR importBufferAsImage(GraphicsBuffer *buffer)
QHash< std::pair< GraphicsBuffer *, int >, EGLImageKHR > m_importedBuffers
void doneCurrent() override
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &attributes) const
QList< LinuxDmaBufV1Feedback::Tranche > m_tranches
std::shared_ptr< GLTexture > importDmaBufAsTexture(const DmaBufAttributes &attributes) const
bool ensureGlobalShareContext(EGLConfig config)
EglContext * contextObject()
QHash< uint32_t, QList< uint64_t > > supportedFormats() const override
void setSurface(const EGLSurface &surface)
virtual bool prefer10bpc() const
bool createContext(EGLConfig config)
std::shared_ptr< EglContext > m_context
~AbstractEglBackend() override
void destroyGlobalShareContext()
bool testImportBuffer(GraphicsBuffer *buffer) override
QList< QByteArray > m_clientExtensions
AbstractEglBackend(dev_t deviceId=0)
static Compositor * self()
void setDevice(const QString &node)
static std::unique_ptr< EglContext > create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
QString renderNode() const
bool supportsNativeFence() const
QList< QByteArray > extensions() const
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf) const
QHash< uint32_t, QList< uint64_t > > nonExternalOnlySupportedDrmFormats() const
QHash< uint32_t, DrmFormatInfo > allSupportedDrmFormats() const
bool supportsBufferAge() const
::EGLDisplay handle() const
virtual const DmaBufAttributes * dmabufAttributes() const
void setSupportedFormatsWithModifiers(const QList< LinuxDmaBufV1Feedback::Tranche > &tranches)
void setRenderBackend(RenderBackend *renderBackend)
void setSupportsBufferAge(bool value)
void setSupportsNativeFence(bool value)
void setExtensions(const QList< QByteArray > &extensions)
LinuxDmaBufV1ClientBufferIntegration * linuxDmabuf()
DrmClientBufferIntegration * drm()
void KWIN_EXPORT cleanupGL()
void initGL(const std::function< resolveFuncPtr(const char *)> &resolveFunction)
WaylandServer * waylandServer()