1 | /* |
2 | * Copyright (C) 2015 Igalia S.L |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * |
14 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
17 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "PlatformDisplay.h" |
28 | |
29 | #include "GLContext.h" |
30 | #include <cstdlib> |
31 | #include <mutex> |
32 | |
33 | #if PLATFORM(X11) |
34 | #include "PlatformDisplayX11.h" |
35 | #endif |
36 | |
37 | #if PLATFORM(WAYLAND) |
38 | #include "PlatformDisplayWayland.h" |
39 | #endif |
40 | |
41 | #if PLATFORM(WIN) |
42 | #include "PlatformDisplayWin.h" |
43 | #endif |
44 | |
45 | #if USE(LIBWPE) |
46 | #include "PlatformDisplayLibWPE.h" |
47 | #endif |
48 | |
49 | #if PLATFORM(GTK) |
50 | #include <gtk/gtk.h> |
51 | #endif |
52 | |
53 | #if PLATFORM(GTK) && PLATFORM(X11) |
54 | #include <gdk/gdkx.h> |
55 | #endif |
56 | |
57 | #if PLATFORM(GTK) && PLATFORM(WAYLAND) && !defined(GTK_API_VERSION_2) |
58 | #include <gdk/gdkwayland.h> |
59 | #endif |
60 | |
61 | #if USE(EGL) |
62 | #if USE(LIBEPOXY) |
63 | #include "EpoxyEGL.h" |
64 | #else |
65 | #include <EGL/egl.h> |
66 | #endif |
67 | #include "GLContextEGL.h" |
68 | #include <wtf/HashSet.h> |
69 | #include <wtf/NeverDestroyed.h> |
70 | #endif |
71 | |
72 | namespace WebCore { |
73 | |
74 | std::unique_ptr<PlatformDisplay> PlatformDisplay::createPlatformDisplay() |
75 | { |
76 | #if PLATFORM(GTK) |
77 | #if defined(GTK_API_VERSION_2) |
78 | return PlatformDisplayX11::create(GDK_DISPLAY_XDISPLAY(gdk_display_get_default())); |
79 | #else |
80 | if (gtk_init_check(nullptr, nullptr)) { |
81 | GdkDisplay* display = gdk_display_manager_get_default_display(gdk_display_manager_get()); |
82 | #if PLATFORM(X11) |
83 | if (GDK_IS_X11_DISPLAY(display)) |
84 | return PlatformDisplayX11::create(GDK_DISPLAY_XDISPLAY(display)); |
85 | #endif |
86 | #if PLATFORM(WAYLAND) |
87 | if (GDK_IS_WAYLAND_DISPLAY(display)) |
88 | return PlatformDisplayWayland::create(gdk_wayland_display_get_wl_display(display)); |
89 | #endif |
90 | } |
91 | #endif |
92 | #endif // PLATFORM(GTK) |
93 | |
94 | #if USE(LIBWPE) |
95 | return PlatformDisplayLibWPE::create(); |
96 | #elif PLATFORM(WIN) |
97 | return PlatformDisplayWin::create(); |
98 | #endif |
99 | |
100 | #if PLATFORM(WAYLAND) |
101 | if (auto platformDisplay = PlatformDisplayWayland::create()) |
102 | return platformDisplay; |
103 | #endif |
104 | |
105 | #if PLATFORM(X11) |
106 | if (auto platformDisplay = PlatformDisplayX11::create()) |
107 | return platformDisplay; |
108 | #endif |
109 | |
110 | // If at this point we still don't have a display, just create a fake display with no native. |
111 | #if PLATFORM(WAYLAND) |
112 | return PlatformDisplayWayland::create(nullptr); |
113 | #elif PLATFORM(X11) |
114 | return PlatformDisplayX11::create(nullptr); |
115 | #endif |
116 | |
117 | RELEASE_ASSERT_NOT_REACHED(); |
118 | } |
119 | |
120 | PlatformDisplay& PlatformDisplay::sharedDisplay() |
121 | { |
122 | static std::once_flag onceFlag; |
123 | IGNORE_CLANG_WARNINGS_BEGIN("exit-time-destructors" ) |
124 | static std::unique_ptr<PlatformDisplay> display; |
125 | IGNORE_CLANG_WARNINGS_END |
126 | std::call_once(onceFlag, []{ |
127 | display = createPlatformDisplay(); |
128 | }); |
129 | return *display; |
130 | } |
131 | |
132 | static PlatformDisplay* s_sharedDisplayForCompositing; |
133 | |
134 | PlatformDisplay& PlatformDisplay::sharedDisplayForCompositing() |
135 | { |
136 | return s_sharedDisplayForCompositing ? *s_sharedDisplayForCompositing : sharedDisplay(); |
137 | } |
138 | |
139 | void PlatformDisplay::setSharedDisplayForCompositing(PlatformDisplay& display) |
140 | { |
141 | s_sharedDisplayForCompositing = &display; |
142 | } |
143 | |
144 | PlatformDisplay::PlatformDisplay(NativeDisplayOwned displayOwned) |
145 | : m_nativeDisplayOwned(displayOwned) |
146 | #if USE(EGL) |
147 | , m_eglDisplay(EGL_NO_DISPLAY) |
148 | #endif |
149 | { |
150 | } |
151 | |
152 | PlatformDisplay::~PlatformDisplay() |
153 | { |
154 | #if USE(EGL) |
155 | ASSERT(m_eglDisplay == EGL_NO_DISPLAY); |
156 | #endif |
157 | } |
158 | |
159 | #if USE(EGL) || USE(GLX) |
160 | GLContext* PlatformDisplay::sharingGLContext() |
161 | { |
162 | if (!m_sharingGLContext) |
163 | m_sharingGLContext = GLContext::createSharingContext(*this); |
164 | return m_sharingGLContext.get(); |
165 | } |
166 | #endif |
167 | |
168 | #if USE(EGL) |
169 | static HashSet<PlatformDisplay*>& eglDisplays() |
170 | { |
171 | static NeverDestroyed<HashSet<PlatformDisplay*>> displays; |
172 | return displays; |
173 | } |
174 | |
175 | EGLDisplay PlatformDisplay::eglDisplay() const |
176 | { |
177 | if (!m_eglDisplayInitialized) |
178 | const_cast<PlatformDisplay*>(this)->initializeEGLDisplay(); |
179 | return m_eglDisplay; |
180 | } |
181 | |
182 | bool PlatformDisplay::eglCheckVersion(int major, int minor) const |
183 | { |
184 | if (!m_eglDisplayInitialized) |
185 | const_cast<PlatformDisplay*>(this)->initializeEGLDisplay(); |
186 | |
187 | return (m_eglMajorVersion > major) || ((m_eglMajorVersion == major) && (m_eglMinorVersion >= minor)); |
188 | } |
189 | |
190 | void PlatformDisplay::initializeEGLDisplay() |
191 | { |
192 | m_eglDisplayInitialized = true; |
193 | |
194 | if (m_eglDisplay == EGL_NO_DISPLAY) { |
195 | m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
196 | if (m_eglDisplay == EGL_NO_DISPLAY) { |
197 | WTFLogAlways("Cannot get default EGL display: %s\n" , GLContextEGL::lastErrorString()); |
198 | return; |
199 | } |
200 | } |
201 | |
202 | EGLint majorVersion, minorVersion; |
203 | if (eglInitialize(m_eglDisplay, &majorVersion, &minorVersion) == EGL_FALSE) { |
204 | WTFLogAlways("EGLDisplay Initialization failed: %s\n" , GLContextEGL::lastErrorString()); |
205 | terminateEGLDisplay(); |
206 | return; |
207 | } |
208 | |
209 | m_eglMajorVersion = majorVersion; |
210 | m_eglMinorVersion = minorVersion; |
211 | |
212 | eglDisplays().add(this); |
213 | |
214 | #if !PLATFORM(WIN) |
215 | static bool eglAtexitHandlerInitialized = false; |
216 | if (!eglAtexitHandlerInitialized) { |
217 | // EGL registers atexit handlers to cleanup its global display list. |
218 | // Since the global PlatformDisplay instance is created before, |
219 | // when the PlatformDisplay destructor is called, EGL has already removed the |
220 | // display from the list, causing eglTerminate() to crash. So, here we register |
221 | // our own atexit handler, after EGL has been initialized and after the global |
222 | // instance has been created to ensure we call eglTerminate() before the other |
223 | // EGL atexit handlers and the PlatformDisplay destructor. |
224 | // See https://bugs.webkit.org/show_bug.cgi?id=157973. |
225 | eglAtexitHandlerInitialized = true; |
226 | std::atexit(shutDownEglDisplays); |
227 | } |
228 | #endif |
229 | } |
230 | |
231 | void PlatformDisplay::terminateEGLDisplay() |
232 | { |
233 | m_sharingGLContext = nullptr; |
234 | ASSERT(m_eglDisplayInitialized); |
235 | if (m_eglDisplay == EGL_NO_DISPLAY) |
236 | return; |
237 | eglTerminate(m_eglDisplay); |
238 | m_eglDisplay = EGL_NO_DISPLAY; |
239 | } |
240 | |
241 | void PlatformDisplay::shutDownEglDisplays() |
242 | { |
243 | while (!eglDisplays().isEmpty()) { |
244 | auto* display = eglDisplays().takeAny(); |
245 | display->terminateEGLDisplay(); |
246 | } |
247 | } |
248 | |
249 | #endif // USE(EGL) |
250 | |
251 | } // namespace WebCore |
252 | |