@@ -12,47 +12,133 @@ namespace mg = mir::graphics;
12
12
namespace mgw = mir::graphics::wayland;
13
13
namespace geom = mir::geometry;
14
14
15
+ namespace
16
+ {
17
+ // Utility to restore EGL state on scope exit
18
+ class CacheEglState
19
+ {
20
+ public:
21
+ CacheEglState () = default ;
22
+
23
+ ~CacheEglState ()
24
+ {
25
+ eglMakeCurrent (dpy, draw_surf, read_surf, ctx);
26
+ }
27
+ private:
28
+ CacheEglState (CacheEglState const &) = delete ;
29
+ EGLDisplay const dpy = eglGetCurrentDisplay();
30
+ EGLContext const ctx = eglGetCurrentContext();
31
+ EGLSurface const draw_surf = eglGetCurrentSurface(EGL_DRAW);
32
+ EGLSurface const read_surf = eglGetCurrentSurface(EGL_READ);
33
+ };
34
+ }
35
+
36
+ class mgw ::WlDisplayAllocator::SurfaceState
37
+ {
38
+ public:
39
+ SurfaceState (EGLDisplay dpy, struct ::wl_egl_window* wl_window) :
40
+ dpy{dpy}, wl_window{wl_window} {}
41
+
42
+ ~SurfaceState ()
43
+ {
44
+ if (egl_surface != EGL_NO_SURFACE) eglDestroySurface (dpy, egl_surface);
45
+ wl_egl_window_destroy (wl_window);
46
+ }
47
+
48
+ auto surface (EGLConfig egl_config) -> EGLSurface
49
+ {
50
+ std::lock_guard lock{mutex};
51
+ if (egl_surface == EGL_NO_SURFACE)
52
+ {
53
+ egl_surface = eglCreatePlatformWindowSurface (dpy, egl_config, wl_window, nullptr );
54
+ }
55
+
56
+ if (egl_surface == EGL_NO_SURFACE)
57
+ {
58
+ BOOST_THROW_EXCEPTION (egl_error (" Failed to create EGL surface" ));
59
+ }
60
+
61
+ return egl_surface;
62
+ }
63
+
64
+ private:
65
+ EGLDisplay const dpy;
66
+ struct ::wl_egl_window* const wl_window;
67
+
68
+ std::mutex mutex;
69
+ EGLSurface egl_surface{EGL_NO_SURFACE};
70
+ };
71
+
15
72
class mgw ::WlDisplayAllocator::Framebuffer::EGLState
16
73
{
17
74
public:
18
- EGLState (EGLDisplay dpy, EGLContext ctx, EGLSurface surf)
75
+ EGLState (EGLDisplay dpy, EGLContext ctx, EGLSurface surf, std::shared_ptr<SurfaceState> ss )
19
76
: dpy{dpy},
20
77
ctx{ctx},
21
- surf{surf}
78
+ surf{surf},
79
+ ss{std::move (ss)}
22
80
{
81
+ CacheEglState stash;
82
+
83
+ make_current ();
84
+ // Don't block in eglSwapBuffers; we rely on external synchronisation to throttle rendering
85
+ eglSwapInterval (dpy, 0 );
86
+ release_current ();
23
87
}
24
88
25
89
~EGLState ()
26
90
{
27
- eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
91
+ if (ctx == eglGetCurrentContext ())
92
+ {
93
+ eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
94
+ }
28
95
eglDestroyContext (dpy, ctx);
29
- eglDestroySurface (dpy, surf);
30
96
}
31
-
97
+
98
+ void make_current () const
99
+ {
100
+ if (eglMakeCurrent (dpy, surf, surf, ctx) != EGL_TRUE)
101
+ {
102
+ BOOST_THROW_EXCEPTION ((mg::egl_error (" eglMakeCurrent failed" )));
103
+ }
104
+ }
105
+
106
+ void release_current () const
107
+ {
108
+ if (eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE)
109
+ {
110
+ BOOST_THROW_EXCEPTION (mg::egl_error (" Failed to release EGL context" ));
111
+ }
112
+ }
113
+
114
+ void swap_buffers () const
115
+ {
116
+ if (eglSwapBuffers (dpy, surf) != EGL_TRUE)
117
+ {
118
+ BOOST_THROW_EXCEPTION ((mg::egl_error (" eglSwapBuffers failed" )));
119
+ }
120
+ }
121
+
32
122
EGLDisplay const dpy;
33
123
EGLContext const ctx;
34
124
EGLSurface const surf;
125
+ std::shared_ptr<SurfaceState> const ss;
35
126
};
36
127
37
- mgw::WlDisplayAllocator::Framebuffer::Framebuffer (EGLDisplay dpy, EGLContext ctx, EGLSurface surf, geom::Size size)
38
- : Framebuffer(std::make_shared<EGLState>(dpy, ctx, surf), size)
128
+ mgw::WlDisplayAllocator::Framebuffer::Framebuffer (
129
+ EGLDisplay dpy, EGLContext ctx, EGLSurface surf, std::shared_ptr<SurfaceState> ss, mir::geometry::Size size) :
130
+ Framebuffer{std::make_shared<EGLState>(dpy, ctx, surf, ss), size}
39
131
{
40
- auto current_ctx = eglGetCurrentContext ();
41
- auto current_draw_surf = eglGetCurrentSurface (EGL_DRAW);
42
- auto current_read_surf = eglGetCurrentSurface (EGL_READ);
43
-
44
- make_current ();
45
- // Don't block in eglSwapBuffers; we rely on external synchronisation to throttle rendering
46
- eglSwapInterval (dpy, 0 );
47
- release_current ();
48
-
49
- // Paranoia: Restore the previous EGL context state, just in case
50
- eglMakeCurrent (dpy, current_draw_surf, current_read_surf, current_ctx);
51
132
}
52
133
53
134
mgw::WlDisplayAllocator::Framebuffer::Framebuffer (std::shared_ptr<EGLState const > state, geom::Size size)
54
- : state{std::move (state)},
55
- size_{size}
135
+ : state{std::move (state)}, size_{size}
136
+ {
137
+ }
138
+
139
+ mgw::WlDisplayAllocator::Framebuffer::Framebuffer (Framebuffer const & that)
140
+ : state{that.state },
141
+ size_{that.size_ }
56
142
{
57
143
}
58
144
@@ -63,46 +149,36 @@ auto mgw::WlDisplayAllocator::Framebuffer::size() const -> geom::Size
63
149
64
150
void mgw::WlDisplayAllocator::Framebuffer::make_current ()
65
151
{
66
- if (eglMakeCurrent (state->dpy , state->surf , state->surf , state->ctx ) != EGL_TRUE)
67
- {
68
- BOOST_THROW_EXCEPTION ((mg::egl_error (" eglMakeCurrent failed" )));
69
- }
152
+ state->make_current ();
70
153
}
71
154
72
155
void mgw::WlDisplayAllocator::Framebuffer::release_current ()
73
156
{
74
- if (eglMakeCurrent (state->dpy , EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE)
75
- {
76
- BOOST_THROW_EXCEPTION (mg::egl_error (" Failed to release EGL context" ));
77
- }
157
+ state->release_current ();
78
158
}
79
159
80
160
void mgw::WlDisplayAllocator::Framebuffer::swap_buffers ()
81
161
{
82
- if (eglSwapBuffers (state->dpy , state->surf ) != EGL_TRUE)
83
- {
84
- BOOST_THROW_EXCEPTION ((mg::egl_error (" eglSwapBuffers failed" )));
85
- }
162
+ state->swap_buffers ();
86
163
}
87
164
88
165
auto mgw::WlDisplayAllocator::Framebuffer::clone_handle () -> std::unique_ptr<mg::GenericEGLDisplayAllocator::EGLFramebuffer>
89
166
{
90
- return std::unique_ptr<mg::GenericEGLDisplayAllocator::EGLFramebuffer>{new Framebuffer (state, size_ )};
167
+ return std::unique_ptr<mg::GenericEGLDisplayAllocator::EGLFramebuffer>{new Framebuffer (* this )};
91
168
}
92
169
93
170
mgw::WlDisplayAllocator::WlDisplayAllocator (
94
171
EGLDisplay dpy,
95
172
struct wl_surface * surface,
96
173
geometry::Size size)
97
174
: dpy{dpy},
98
- wl_window{ wl_egl_window_create (surface, size.width .as_int (), size.height .as_int ())},
175
+ surface_state{std::make_shared<SurfaceState>(dpy, wl_egl_window_create (surface, size.width .as_int (), size.height .as_int () ))},
99
176
size{size}
100
177
{
101
178
}
102
179
103
180
mgw::WlDisplayAllocator::~WlDisplayAllocator ()
104
181
{
105
- wl_egl_window_destroy (wl_window);
106
182
}
107
183
108
184
auto mgw::WlDisplayAllocator::alloc_framebuffer (
@@ -138,19 +214,13 @@ auto mgw::WlDisplayAllocator::alloc_framebuffer(
138
214
139
215
auto egl_context = eglCreateContext (dpy, egl_config, share_context, context_attr);
140
216
if (egl_context == EGL_NO_CONTEXT)
141
- BOOST_THROW_EXCEPTION (egl_error (" Failed to create EGL context" ));
142
-
143
- auto surf = eglCreatePlatformWindowSurface (dpy, egl_config, wl_window, nullptr );
144
- if (surf == EGL_NO_SURFACE)
145
217
{
146
- BOOST_THROW_EXCEPTION (egl_error (" Failed to create EGL surface " ));
218
+ BOOST_THROW_EXCEPTION (egl_error (" Failed to create EGL context " ));
147
219
}
148
220
149
- return std::make_unique<Framebuffer>(
150
- dpy,
151
- egl_context,
152
- surf,
153
- size);
221
+ auto surface = surface_state->surface (egl_config);
222
+
223
+ return std::make_unique<Framebuffer>(dpy, egl_context, surface, surface_state, size);
154
224
}
155
225
156
226
mgw::WlDisplayProvider::WlDisplayProvider (EGLDisplay dpy)
0 commit comments