KWin
Loading...
Searching...
No Matches
eglcontext.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "eglcontext.h"
10#include "core/graphicsbuffer.h"
11#include "egldisplay.h"
12#include "eglimagetexture.h"
14#include "opengl/eglutils_p.h"
15#include "opengl/glutils.h"
16#include "utils/common.h"
18
19#include <QOpenGLContext>
20#include <drm_fourcc.h>
21
22namespace KWin
23{
24
25std::unique_ptr<EglContext> EglContext::create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
26{
27 auto handle = createContext(display, config, sharedContext);
28 if (!handle) {
29 return nullptr;
30 }
31 if (!eglMakeCurrent(display->handle(), EGL_NO_SURFACE, EGL_NO_SURFACE, handle)) {
32 eglDestroyContext(display->handle(), handle);
33 return nullptr;
34 }
35 auto ret = std::make_unique<EglContext>(display, config, handle);
36 if (!ret->checkSupported()) {
37 return nullptr;
38 }
39 return ret;
40}
41
42EglContext::EglContext(EglDisplay *display, EGLConfig config, ::EGLContext context)
43 : m_display(display)
44 , m_handle(context)
45 , m_config(config)
46 , m_shaderManager(std::make_unique<ShaderManager>())
47{
48 // It is not legal to not have a vertex array object bound in a core context
49 // to make code handling old and new OpenGL versions easier, bind a dummy vao that's used for everything
50 if (!isOpenglES() && hasOpenglExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) {
51 glGenVertexArrays(1, &m_vao);
52 glBindVertexArray(m_vao);
53 }
54}
55
57{
59 if (m_vao) {
60 glDeleteVertexArrays(1, &m_vao);
61 }
62 m_shaderManager.reset();
64 eglDestroyContext(m_display->handle(), m_handle);
65}
66
67bool EglContext::makeCurrent(EGLSurface surface) const
68{
69 return eglMakeCurrent(m_display->handle(), surface, surface, m_handle) == EGL_TRUE;
70}
71
73{
74 eglMakeCurrent(m_display->handle(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
75}
76
78{
79 return m_display;
80}
81
82::EGLContext EglContext::handle() const
83{
84 return m_handle;
85}
86
87EGLConfig EglContext::config() const
88{
89 return m_config;
90}
91
93{
94 return m_display != nullptr && m_handle != EGL_NO_CONTEXT;
95}
96
97::EGLContext EglContext::createContext(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
98{
99 const bool haveRobustness = display->hasExtension(QByteArrayLiteral("EGL_EXT_create_context_robustness"));
100 const bool haveCreateContext = display->hasExtension(QByteArrayLiteral("EGL_KHR_create_context"));
101 const bool haveContextPriority = display->hasExtension(QByteArrayLiteral("EGL_IMG_context_priority"));
102 const bool haveResetOnVideoMemoryPurge = display->hasExtension(QByteArrayLiteral("EGL_NV_robustness_video_memory_purge"));
103
104 std::vector<std::unique_ptr<AbstractOpenGLContextAttributeBuilder>> candidates;
105 if (isOpenGLES()) {
106 if (haveCreateContext && haveRobustness && haveContextPriority && haveResetOnVideoMemoryPurge) {
107 auto glesRobustPriority = std::make_unique<EglOpenGLESContextAttributeBuilder>();
108 glesRobustPriority->setResetOnVideoMemoryPurge(true);
109 glesRobustPriority->setVersion(2);
110 glesRobustPriority->setRobust(true);
111 glesRobustPriority->setHighPriority(true);
112 candidates.push_back(std::move(glesRobustPriority));
113 }
114
115 if (haveCreateContext && haveRobustness && haveContextPriority) {
116 auto glesRobustPriority = std::make_unique<EglOpenGLESContextAttributeBuilder>();
117 glesRobustPriority->setVersion(2);
118 glesRobustPriority->setRobust(true);
119 glesRobustPriority->setHighPriority(true);
120 candidates.push_back(std::move(glesRobustPriority));
121 }
122 if (haveCreateContext && haveRobustness) {
123 auto glesRobust = std::make_unique<EglOpenGLESContextAttributeBuilder>();
124 glesRobust->setVersion(2);
125 glesRobust->setRobust(true);
126 candidates.push_back(std::move(glesRobust));
127 }
128 if (haveContextPriority) {
129 auto glesPriority = std::make_unique<EglOpenGLESContextAttributeBuilder>();
130 glesPriority->setVersion(2);
131 glesPriority->setHighPriority(true);
132 candidates.push_back(std::move(glesPriority));
133 }
134 auto gles = std::make_unique<EglOpenGLESContextAttributeBuilder>();
135 gles->setVersion(2);
136 candidates.push_back(std::move(gles));
137 } else {
138 if (haveCreateContext) {
139 if (haveRobustness && haveContextPriority && haveResetOnVideoMemoryPurge) {
140 auto robustCorePriority = std::make_unique<EglContextAttributeBuilder>();
141 robustCorePriority->setResetOnVideoMemoryPurge(true);
142 robustCorePriority->setVersion(3, 1);
143 robustCorePriority->setRobust(true);
144 robustCorePriority->setHighPriority(true);
145 candidates.push_back(std::move(robustCorePriority));
146 }
147 if (haveRobustness && haveContextPriority) {
148 auto robustCorePriority = std::make_unique<EglContextAttributeBuilder>();
149 robustCorePriority->setVersion(3, 1);
150 robustCorePriority->setRobust(true);
151 robustCorePriority->setHighPriority(true);
152 candidates.push_back(std::move(robustCorePriority));
153 }
154 if (haveRobustness) {
155 auto robustCore = std::make_unique<EglContextAttributeBuilder>();
156 robustCore->setVersion(3, 1);
157 robustCore->setRobust(true);
158 candidates.push_back(std::move(robustCore));
159 }
160 if (haveContextPriority) {
161 auto corePriority = std::make_unique<EglContextAttributeBuilder>();
162 corePriority->setVersion(3, 1);
163 corePriority->setHighPriority(true);
164 candidates.push_back(std::move(corePriority));
165 }
166 auto core = std::make_unique<EglContextAttributeBuilder>();
167 core->setVersion(3, 1);
168 candidates.push_back(std::move(core));
169 }
170 if (haveRobustness && haveCreateContext && haveContextPriority) {
171 auto robustPriority = std::make_unique<EglContextAttributeBuilder>();
172 robustPriority->setRobust(true);
173 robustPriority->setHighPriority(true);
174 candidates.push_back(std::move(robustPriority));
175 }
176 if (haveRobustness && haveCreateContext) {
177 auto robust = std::make_unique<EglContextAttributeBuilder>();
178 robust->setRobust(true);
179 candidates.push_back(std::move(robust));
180 }
181 candidates.emplace_back(new EglContextAttributeBuilder);
182 }
183
184 for (const auto &candidate : candidates) {
185 const auto attribs = candidate->build();
186 ::EGLContext ctx = eglCreateContext(display->handle(), config, sharedContext, attribs.data());
187 if (ctx != EGL_NO_CONTEXT) {
188 qCDebug(KWIN_OPENGL) << "Created EGL context with attributes:" << candidate.get();
189 return ctx;
190 }
191 }
192 qCCritical(KWIN_OPENGL) << "Create Context failed" << getEglErrorString();
193 return EGL_NO_CONTEXT;
194}
195
196std::shared_ptr<GLTexture> EglContext::importDmaBufAsTexture(const DmaBufAttributes &attributes) const
197{
198 EGLImageKHR image = m_display->importDmaBufAsImage(attributes);
199 if (image != EGL_NO_IMAGE_KHR) {
200 const auto info = FormatInfo::get(attributes.format);
201 return EGLImageTexture::create(m_display, image, info ? info->openglFormat : GL_RGBA8, QSize(attributes.width, attributes.height), m_display->isExternalOnly(attributes.format, attributes.modifier));
202 } else {
203 qCWarning(KWIN_OPENGL) << "Error creating EGLImageKHR: " << getEglErrorString();
204 return nullptr;
205 }
206}
207
209{
210 return m_shaderManager.get();
211}
212}
void doneCurrent() const
bool makeCurrent(EGLSurface surface=EGL_NO_SURFACE) const
::EGLContext handle() const
~EglContext() override
EglDisplay * displayObject() const
EglContext(EglDisplay *display, EGLConfig config, ::EGLContext context)
std::shared_ptr< GLTexture > importDmaBufAsTexture(const DmaBufAttributes &attributes) const
ShaderManager * shaderManager() const
bool isValid() const
static std::unique_ptr< EglContext > create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
EGLConfig config() const
bool hasExtension(const QByteArray &name) const
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf) const
bool isExternalOnly(uint32_t format, uint64_t modifier) const
::EGLDisplay handle() const
bool isOpenglES() const
bool hasOpenglExtension(QByteArrayView name) const
Manager for Shaders.
void * EGLImageKHR
static std::optional< FormatInfo > get(uint32_t drmFormat)