1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qwaylandeglwindow_p.h"
5
6#include <QtWaylandClient/private/qwaylandscreen_p.h>
7#include <QtWaylandClient/private/qwaylandsurface_p.h>
8#include "qwaylandglcontext_p.h"
9
10#include <QtGui/private/qeglconvenience_p.h>
11
12#include <QDebug>
13#include <QtGui/QWindow>
14#include <qpa/qwindowsysteminterface.h>
15#include <QOpenGLFramebufferObject>
16#include <QOpenGLContext>
17
18QT_BEGIN_NAMESPACE
19
20namespace QtWaylandClient {
21
22QWaylandEglWindow::QWaylandEglWindow(QWindow *window, QWaylandDisplay *display)
23 : QWaylandWindow(window, display)
24 , m_clientBufferIntegration(static_cast<QWaylandEglClientBufferIntegration *>(mDisplay->clientBufferIntegration()))
25 , m_format(window->requestedFormat())
26{
27 connect(display, &QWaylandDisplay::reconnected, this, [this] {
28 m_clientBufferIntegration = static_cast<QWaylandEglClientBufferIntegration *>(
29 mDisplay->clientBufferIntegration());
30 });
31}
32
33QWaylandEglWindow::~QWaylandEglWindow()
34{
35 if (m_eglSurface) {
36 eglDestroySurface(dpy: m_clientBufferIntegration->eglDisplay(), surface: m_eglSurface);
37 m_eglSurface = 0;
38 }
39
40 if (m_waylandEglWindow)
41 wl_egl_window_destroy(egl_window: m_waylandEglWindow);
42
43 delete m_contentFBO;
44}
45
46QWaylandWindow::WindowType QWaylandEglWindow::windowType() const
47{
48 return QWaylandWindow::Egl;
49}
50
51void QWaylandEglWindow::ensureSize()
52{
53 updateSurface(create: false);
54}
55
56void QWaylandEglWindow::setGeometry(const QRect &rect)
57{
58 QWaylandWindow::setGeometry(rect);
59 // If the surface was invalidated through invalidateSurface() and
60 // we're now getting a resize we don't want to create it again.
61 // Just resize the wl_egl_window, the EGLSurface will be created
62 // the next time makeCurrent is called.
63 updateSurface(create: false);
64}
65
66void QWaylandEglWindow::updateSurface(bool create)
67{
68 QMargins margins = mWindowDecoration ? frameMargins() : QMargins{};
69 QRect rect = geometry();
70 QSize sizeWithMargins = (rect.size() + QSize(margins.left() + margins.right(), margins.top() + margins.bottom())) * scale();
71
72 // wl_egl_windows must have both width and height > 0
73 // mesa's egl returns NULL if we try to create a, invalid wl_egl_window, however not all EGL
74 // implementations may do that, so check the size ourself. Besides, we must deal with resizing
75 // a valid window to 0x0, which would make it invalid. Hence, destroy it.
76 if (sizeWithMargins.isEmpty()) {
77 if (m_eglSurface) {
78 eglDestroySurface(dpy: m_clientBufferIntegration->eglDisplay(), surface: m_eglSurface);
79 m_eglSurface = 0;
80 }
81 if (m_waylandEglWindow) {
82 wl_egl_window_destroy(egl_window: m_waylandEglWindow);
83 m_waylandEglWindow = 0;
84 }
85 mOffset = QPoint();
86 } else {
87 QReadLocker locker(&mSurfaceLock);
88 if (m_waylandEglWindow) {
89 int current_width, current_height;
90 static bool disableResizeCheck = qgetenv(varName: "QT_WAYLAND_DISABLE_RESIZECHECK").toInt();
91
92 if (!disableResizeCheck) {
93 wl_egl_window_get_attached_size(egl_window: m_waylandEglWindow, width: &current_width, height: &current_height);
94 }
95 if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) {
96 wl_egl_window_resize(egl_window: m_waylandEglWindow, width: sizeWithMargins.width(), height: sizeWithMargins.height(), dx: mOffset.x(), dy: mOffset.y());
97 m_requestedSize = sizeWithMargins;
98 mOffset = QPoint();
99
100 m_resize = true;
101 }
102 } else if (create && mSurface) {
103 m_waylandEglWindow = wl_egl_window_create(mSurface->object(), sizeWithMargins.width(), sizeWithMargins.height());
104 m_requestedSize = sizeWithMargins;
105 }
106
107 if (!m_eglSurface && m_waylandEglWindow && create) {
108 EGLNativeWindowType eglw = (EGLNativeWindowType) m_waylandEglWindow;
109 QSurfaceFormat fmt = window()->requestedFormat();
110 if (mDisplay->supportsWindowDecoration())
111 fmt.setAlphaBufferSize(8);
112 EGLConfig eglConfig = q_configFromGLFormat(display: m_clientBufferIntegration->eglDisplay(), format: fmt);
113 m_format = q_glFormatFromConfig(display: m_clientBufferIntegration->eglDisplay(), config: eglConfig);
114 m_eglSurface = eglCreateWindowSurface(dpy: m_clientBufferIntegration->eglDisplay(), config: eglConfig, win: eglw, attrib_list: 0);
115 if (Q_UNLIKELY(m_eglSurface == EGL_NO_SURFACE))
116 qCWarning(lcQpaWayland, "Could not create EGL surface (EGL error 0x%x)\n", eglGetError());
117 }
118 }
119}
120
121QRect QWaylandEglWindow::contentsRect() const
122{
123 QRect r = geometry();
124 QMargins m = frameMargins();
125 return QRect(m.left(), m.bottom(), r.width(), r.height());
126}
127
128QSurfaceFormat QWaylandEglWindow::format() const
129{
130 return m_format;
131}
132
133void QWaylandEglWindow::invalidateSurface()
134{
135 if (m_eglSurface) {
136 eglDestroySurface(dpy: m_clientBufferIntegration->eglDisplay(), surface: m_eglSurface);
137 m_eglSurface = 0;
138 }
139 if (m_waylandEglWindow) {
140 wl_egl_window_destroy(egl_window: m_waylandEglWindow);
141 m_waylandEglWindow = nullptr;
142 }
143 delete m_contentFBO;
144 m_contentFBO = nullptr;
145}
146
147EGLSurface QWaylandEglWindow::eglSurface() const
148{
149 return m_eglSurface;
150}
151
152GLuint QWaylandEglWindow::contentFBO() const
153{
154 if (!decoration())
155 return 0;
156
157 if (m_resize || !m_contentFBO) {
158 QOpenGLFramebufferObject *old = m_contentFBO;
159 QSize fboSize = geometry().size() * scale();
160 m_contentFBO = new QOpenGLFramebufferObject(fboSize.width(), fboSize.height(), QOpenGLFramebufferObject::CombinedDepthStencil);
161
162 delete old;
163 m_resize = false;
164 }
165
166 return m_contentFBO->handle();
167}
168
169GLuint QWaylandEglWindow::contentTexture() const
170{
171 return m_contentFBO->texture();
172}
173
174void QWaylandEglWindow::bindContentFBO()
175{
176 if (decoration()) {
177 contentFBO();
178 m_contentFBO->bind();
179 }
180}
181
182}
183
184QT_END_NAMESPACE
185
186#include "moc_qwaylandeglwindow_p.cpp"
187

source code of qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp