2
* Copyright © 2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
19
#include "mir/graphics/surfaceless_egl_context.h"
20
#include "mir/graphics/gl_extensions_base.h"
22
#include <boost/throw_exception.hpp>
26
namespace mg = mir::graphics;
31
class EGLExtensions : public mg::GLExtensionsBase
34
EGLExtensions(EGLDisplay egl_display) :
36
reinterpret_cast<char const*>(eglQueryString(egl_display, EGL_EXTENSIONS))}
41
bool supports_surfaceless_context(EGLDisplay egl_display)
43
EGLExtensions const extensions{egl_display};
45
return extensions.support("EGL_KHR_surfaceless_context");
48
std::vector<EGLint> ensure_pbuffer_set(EGLint const* attribs)
50
bool has_preferred_surface = false;
51
std::vector<EGLint> attribs_with_surface_type;
54
while (attribs[i] != EGL_NONE)
56
attribs_with_surface_type.push_back(attribs[i]);
57
if (attribs[i] == EGL_SURFACE_TYPE)
59
has_preferred_surface = true;
60
if (attribs[i+1] == EGL_DONT_CARE)
62
/* Need to treat EGL_DONT_CARE specially, as it is defined as all-bits-set */
63
attribs_with_surface_type.push_back(EGL_PBUFFER_BIT);
67
attribs_with_surface_type.push_back(attribs[i+1] | EGL_PBUFFER_BIT);
72
attribs_with_surface_type.push_back(attribs[i+1]);
77
if (!has_preferred_surface)
79
attribs_with_surface_type.push_back(EGL_SURFACE_TYPE);
80
attribs_with_surface_type.push_back(EGL_PBUFFER_BIT);
83
attribs_with_surface_type.push_back(EGL_NONE);
85
return attribs_with_surface_type;
88
EGLConfig choose_config(EGLDisplay egl_display, EGLint const* attribs, bool surfaceless)
90
EGLConfig egl_config{0};
91
int num_egl_configs{0};
92
std::vector<EGLint> validated_attribs;
96
validated_attribs = ensure_pbuffer_set(attribs);
97
attribs = validated_attribs.data();
100
if (eglChooseConfig(egl_display, attribs, &egl_config, 1, &num_egl_configs) == EGL_FALSE ||
101
num_egl_configs != 1)
103
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to choose EGL config"));
109
EGLSurface create_surface(EGLDisplay egl_display, EGLConfig egl_config)
111
static EGLint const dummy_pbuffer_attribs[] =
118
return eglCreatePbufferSurface(egl_display, egl_config, dummy_pbuffer_attribs);
121
EGLint const default_egl_context_attr[] =
123
EGL_CONTEXT_CLIENT_VERSION, 2,
127
EGLint const default_attr[] =
129
EGL_SURFACE_TYPE, EGL_DONT_CARE,
134
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
141
mg::SurfacelessEGLContext::SurfacelessEGLContext(EGLDisplay egl_display, EGLContext shared_context)
142
: SurfacelessEGLContext(egl_display, default_attr, shared_context)
146
mg::SurfacelessEGLContext::SurfacelessEGLContext(
147
EGLDisplay egl_display,
148
EGLint const* attribs,
149
EGLContext shared_context)
150
: egl_display{egl_display},
151
surfaceless{supports_surfaceless_context(egl_display)},
152
egl_config{choose_config(egl_display, attribs, surfaceless)},
153
egl_surface{egl_display,
154
surfaceless ? EGL_NO_SURFACE : create_surface(egl_display, egl_config),
155
surfaceless ? EGLSurfaceStore::AllowNoSurface :
156
EGLSurfaceStore::DisallowNoSurface},
157
egl_context{egl_display,
158
eglCreateContext(egl_display, egl_config,
160
default_egl_context_attr)}
165
mg::SurfacelessEGLContext::SurfacelessEGLContext(SurfacelessEGLContext&& move)
166
: egl_display(move.egl_display),
167
surfaceless(move.surfaceless),
168
egl_config(move.egl_config),
169
egl_surface{std::move(move.egl_surface)},
170
egl_context{std::move(move.egl_context)}
172
move.egl_display = EGL_NO_DISPLAY;
175
mg::SurfacelessEGLContext::~SurfacelessEGLContext() noexcept
181
void mg::SurfacelessEGLContext::make_current() const
183
if (eglGetCurrentContext() == egl_context)
186
if (eglMakeCurrent(egl_display, egl_surface, egl_surface,
187
egl_context) == EGL_FALSE)
189
BOOST_THROW_EXCEPTION(
190
std::runtime_error("could not make context current\n"));
194
void mg::SurfacelessEGLContext::release_current() const
196
if (egl_context != EGL_NO_CONTEXT && eglGetCurrentContext() == egl_context)
197
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
200
mg::SurfacelessEGLContext::operator EGLContext() const