File indexing completed on 2024-11-10 04:56: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 }