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
72namespace WebCore {
73
74std::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
120PlatformDisplay& 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
132static PlatformDisplay* s_sharedDisplayForCompositing;
133
134PlatformDisplay& PlatformDisplay::sharedDisplayForCompositing()
135{
136 return s_sharedDisplayForCompositing ? *s_sharedDisplayForCompositing : sharedDisplay();
137}
138
139void PlatformDisplay::setSharedDisplayForCompositing(PlatformDisplay& display)
140{
141 s_sharedDisplayForCompositing = &display;
142}
143
144PlatformDisplay::PlatformDisplay(NativeDisplayOwned displayOwned)
145 : m_nativeDisplayOwned(displayOwned)
146#if USE(EGL)
147 , m_eglDisplay(EGL_NO_DISPLAY)
148#endif
149{
150}
151
152PlatformDisplay::~PlatformDisplay()
153{
154#if USE(EGL)
155 ASSERT(m_eglDisplay == EGL_NO_DISPLAY);
156#endif
157}
158
159#if USE(EGL) || USE(GLX)
160GLContext* 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)
169static HashSet<PlatformDisplay*>& eglDisplays()
170{
171 static NeverDestroyed<HashSet<PlatformDisplay*>> displays;
172 return displays;
173}
174
175EGLDisplay PlatformDisplay::eglDisplay() const
176{
177 if (!m_eglDisplayInitialized)
178 const_cast<PlatformDisplay*>(this)->initializeEGLDisplay();
179 return m_eglDisplay;
180}
181
182bool 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
190void 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
231void 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
241void 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