File indexing completed on 2024-05-19 05:31:53

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "eglcontext.h"
0010 #include "core/graphicsbuffer.h"
0011 #include "egldisplay.h"
0012 #include "eglimagetexture.h"
0013 #include "opengl/egl_context_attribute_builder.h"
0014 #include "opengl/eglutils_p.h"
0015 #include "opengl/glutils.h"
0016 #include "utils/common.h"
0017 #include "utils/drm_format_helper.h"
0018 
0019 #include <QOpenGLContext>
0020 #include <drm_fourcc.h>
0021 
0022 namespace KWin
0023 {
0024 
0025 std::unique_ptr<EglContext> EglContext::create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
0026 {
0027     auto handle = createContext(display, config, sharedContext);
0028     if (!handle) {
0029         return nullptr;
0030     }
0031     if (!eglMakeCurrent(display->handle(), EGL_NO_SURFACE, EGL_NO_SURFACE, handle)) {
0032         eglDestroyContext(display->handle(), handle);
0033         return nullptr;
0034     }
0035     auto ret = std::make_unique<EglContext>(display, config, handle);
0036     if (!ret->checkSupported()) {
0037         return nullptr;
0038     }
0039     return ret;
0040 }
0041 
0042 EglContext::EglContext(EglDisplay *display, EGLConfig config, ::EGLContext context)
0043     : m_display(display)
0044     , m_handle(context)
0045     , m_config(config)
0046     , m_shaderManager(std::make_unique<ShaderManager>())
0047 {
0048     // It is not legal to not have a vertex array object bound in a core context
0049     // to make code handling old and new OpenGL versions easier, bind a dummy vao that's used for everything
0050     if (!isOpenglES() && hasOpenglExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) {
0051         glGenVertexArrays(1, &m_vao);
0052         glBindVertexArray(m_vao);
0053     }
0054 }
0055 
0056 EglContext::~EglContext()
0057 {
0058     makeCurrent();
0059     if (m_vao) {
0060         glDeleteVertexArrays(1, &m_vao);
0061     }
0062     m_shaderManager.reset();
0063     doneCurrent();
0064     eglDestroyContext(m_display->handle(), m_handle);
0065 }
0066 
0067 bool EglContext::makeCurrent(EGLSurface surface) const
0068 {
0069     return eglMakeCurrent(m_display->handle(), surface, surface, m_handle) == EGL_TRUE;
0070 }
0071 
0072 void EglContext::doneCurrent() const
0073 {
0074     eglMakeCurrent(m_display->handle(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
0075 }
0076 
0077 EglDisplay *EglContext::displayObject() const
0078 {
0079     return m_display;
0080 }
0081 
0082 ::EGLContext EglContext::handle() const
0083 {
0084     return m_handle;
0085 }
0086 
0087 EGLConfig EglContext::config() const
0088 {
0089     return m_config;
0090 }
0091 
0092 bool EglContext::isValid() const
0093 {
0094     return m_display != nullptr && m_handle != EGL_NO_CONTEXT;
0095 }
0096 
0097 ::EGLContext EglContext::createContext(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
0098 {
0099     const bool haveRobustness = display->hasExtension(QByteArrayLiteral("EGL_EXT_create_context_robustness"));
0100     const bool haveCreateContext = display->hasExtension(QByteArrayLiteral("EGL_KHR_create_context"));
0101     const bool haveContextPriority = display->hasExtension(QByteArrayLiteral("EGL_IMG_context_priority"));
0102     const bool haveResetOnVideoMemoryPurge = display->hasExtension(QByteArrayLiteral("EGL_NV_robustness_video_memory_purge"));
0103 
0104     std::vector<std::unique_ptr<AbstractOpenGLContextAttributeBuilder>> candidates;
0105     if (isOpenGLES()) {
0106         if (haveCreateContext && haveRobustness && haveContextPriority && haveResetOnVideoMemoryPurge) {
0107             auto glesRobustPriority = std::make_unique<EglOpenGLESContextAttributeBuilder>();
0108             glesRobustPriority->setResetOnVideoMemoryPurge(true);
0109             glesRobustPriority->setVersion(2);
0110             glesRobustPriority->setRobust(true);
0111             glesRobustPriority->setHighPriority(true);
0112             candidates.push_back(std::move(glesRobustPriority));
0113         }
0114 
0115         if (haveCreateContext && haveRobustness && haveContextPriority) {
0116             auto glesRobustPriority = std::make_unique<EglOpenGLESContextAttributeBuilder>();
0117             glesRobustPriority->setVersion(2);
0118             glesRobustPriority->setRobust(true);
0119             glesRobustPriority->setHighPriority(true);
0120             candidates.push_back(std::move(glesRobustPriority));
0121         }
0122         if (haveCreateContext && haveRobustness) {
0123             auto glesRobust = std::make_unique<EglOpenGLESContextAttributeBuilder>();
0124             glesRobust->setVersion(2);
0125             glesRobust->setRobust(true);
0126             candidates.push_back(std::move(glesRobust));
0127         }
0128         if (haveContextPriority) {
0129             auto glesPriority = std::make_unique<EglOpenGLESContextAttributeBuilder>();
0130             glesPriority->setVersion(2);
0131             glesPriority->setHighPriority(true);
0132             candidates.push_back(std::move(glesPriority));
0133         }
0134         auto gles = std::make_unique<EglOpenGLESContextAttributeBuilder>();
0135         gles->setVersion(2);
0136         candidates.push_back(std::move(gles));
0137     } else {
0138         if (haveCreateContext) {
0139             if (haveRobustness && haveContextPriority && haveResetOnVideoMemoryPurge) {
0140                 auto robustCorePriority = std::make_unique<EglContextAttributeBuilder>();
0141                 robustCorePriority->setResetOnVideoMemoryPurge(true);
0142                 robustCorePriority->setVersion(3, 1);
0143                 robustCorePriority->setRobust(true);
0144                 robustCorePriority->setHighPriority(true);
0145                 candidates.push_back(std::move(robustCorePriority));
0146             }
0147             if (haveRobustness && haveContextPriority) {
0148                 auto robustCorePriority = std::make_unique<EglContextAttributeBuilder>();
0149                 robustCorePriority->setVersion(3, 1);
0150                 robustCorePriority->setRobust(true);
0151                 robustCorePriority->setHighPriority(true);
0152                 candidates.push_back(std::move(robustCorePriority));
0153             }
0154             if (haveRobustness) {
0155                 auto robustCore = std::make_unique<EglContextAttributeBuilder>();
0156                 robustCore->setVersion(3, 1);
0157                 robustCore->setRobust(true);
0158                 candidates.push_back(std::move(robustCore));
0159             }
0160             if (haveContextPriority) {
0161                 auto corePriority = std::make_unique<EglContextAttributeBuilder>();
0162                 corePriority->setVersion(3, 1);
0163                 corePriority->setHighPriority(true);
0164                 candidates.push_back(std::move(corePriority));
0165             }
0166             auto core = std::make_unique<EglContextAttributeBuilder>();
0167             core->setVersion(3, 1);
0168             candidates.push_back(std::move(core));
0169         }
0170         if (haveRobustness && haveCreateContext && haveContextPriority) {
0171             auto robustPriority = std::make_unique<EglContextAttributeBuilder>();
0172             robustPriority->setRobust(true);
0173             robustPriority->setHighPriority(true);
0174             candidates.push_back(std::move(robustPriority));
0175         }
0176         if (haveRobustness && haveCreateContext) {
0177             auto robust = std::make_unique<EglContextAttributeBuilder>();
0178             robust->setRobust(true);
0179             candidates.push_back(std::move(robust));
0180         }
0181         candidates.emplace_back(new EglContextAttributeBuilder);
0182     }
0183 
0184     for (const auto &candidate : candidates) {
0185         const auto attribs = candidate->build();
0186         ::EGLContext ctx = eglCreateContext(display->handle(), config, sharedContext, attribs.data());
0187         if (ctx != EGL_NO_CONTEXT) {
0188             qCDebug(KWIN_OPENGL) << "Created EGL context with attributes:" << candidate.get();
0189             return ctx;
0190         }
0191     }
0192     qCCritical(KWIN_OPENGL) << "Create Context failed" << getEglErrorString();
0193     return EGL_NO_CONTEXT;
0194 }
0195 
0196 std::shared_ptr<GLTexture> EglContext::importDmaBufAsTexture(const DmaBufAttributes &attributes) const
0197 {
0198     EGLImageKHR image = m_display->importDmaBufAsImage(attributes);
0199     if (image != EGL_NO_IMAGE_KHR) {
0200         const auto info = FormatInfo::get(attributes.format);
0201         return EGLImageTexture::create(m_display, image, info ? info->openglFormat : GL_RGBA8, QSize(attributes.width, attributes.height), m_display->isExternalOnly(attributes.format, attributes.modifier));
0202     } else {
0203         qCWarning(KWIN_OPENGL) << "Error creating EGLImageKHR: " << getEglErrorString();
0204         return nullptr;
0205     }
0206 }
0207 
0208 ShaderManager *EglContext::shaderManager() const
0209 {
0210     return m_shaderManager.get();
0211 }
0212 }