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::connected, this, [this] {
28 m_clientBufferIntegration = static_cast<QWaylandEglClientBufferIntegration *>(
29 mDisplay->clientBufferIntegration());
30 });
31 ensureSize();
32}
33
34QWaylandEglWindow::~QWaylandEglWindow()
35{
36 if (m_eglSurface) {
37 eglDestroySurface(dpy: m_clientBufferIntegration->eglDisplay(), surface: m_eglSurface);
38 m_eglSurface = 0;
39 }
40
41 if (m_waylandEglWindow)
42 wl_egl_window_destroy(egl_window: m_waylandEglWindow);
43
44 delete m_contentFBO;
45}
46
47QWaylandWindow::WindowType QWaylandEglWindow::windowType() const
48{
49 return QWaylandWindow::Egl;
50}
51
52void QWaylandEglWindow::ensureSize()
53{
54 // this is always called on the main thread
55 QRect rect = geometry();
56 QMargins margins = clientSideMargins();
57 QSize sizeWithMargins = (rect.size() + QSize(margins.left() + margins.right(), margins.top() + margins.bottom())) * scale();
58 {
59 QWriteLocker lock(&m_bufferSizeLock);
60 m_bufferSize = sizeWithMargins;
61 }
62
63 updateSurface(create: false);
64}
65
66void QWaylandEglWindow::setGeometry(const QRect &rect)
67{
68 QWaylandWindow::setGeometry(rect);
69 // If the surface was invalidated through invalidateSurface() and
70 // we're now getting a resize we don't want to create it again.
71 // Just resize the wl_egl_window, the EGLSurface will be created
72 // the next time makeCurrent is called.
73 ensureSize();
74}
75
76void QWaylandEglWindow::updateSurface(bool create)
77{
78 QSize sizeWithMargins;
79 {
80 QReadLocker lock(&m_bufferSizeLock);
81 sizeWithMargins = m_bufferSize;
82 }
83
84 // wl_egl_windows must have both width and height > 0
85 // mesa's egl returns NULL if we try to create a, invalid wl_egl_window, however not all EGL
86 // implementations may do that, so check the size ourself. Besides, we must deal with resizing
87 // a valid window to 0x0, which would make it invalid. Hence, destroy it.
88 if (sizeWithMargins.isEmpty()) {
89 if (m_eglSurface) {
90 eglDestroySurface(dpy: m_clientBufferIntegration->eglDisplay(), surface: m_eglSurface);
91 m_eglSurface = 0;
92 }
93 if (m_waylandEglWindow) {
94 wl_egl_window_destroy(egl_window: m_waylandEglWindow);
95 m_waylandEglWindow = 0;
96 }
97 mOffset = QPoint();
98 } else {
99 QReadLocker locker(&mSurfaceLock);
100 if (m_waylandEglWindow) {
101 int current_width = 0;
102 int current_height = 0;
103 static bool disableResizeCheck = qgetenv(varName: "QT_WAYLAND_DISABLE_RESIZECHECK").toInt();
104
105 if (!disableResizeCheck) {
106 wl_egl_window_get_attached_size(egl_window: m_waylandEglWindow, width: &current_width, height: &current_height);
107 }
108 if (disableResizeCheck || (current_width != sizeWithMargins.width() || current_height != sizeWithMargins.height()) || m_requestedSize != sizeWithMargins) {
109 wl_egl_window_resize(egl_window: m_waylandEglWindow, width: sizeWithMargins.width(), height: sizeWithMargins.height(), dx: mOffset.x(), dy: mOffset.y());
110 m_requestedSize = sizeWithMargins;
111 mOffset = QPoint();
112
113 m_resize = true;
114 }
115 } else if (create && mSurface) {
116 wl_egl_window *eglWindow = wl_egl_window_create(mSurface->object(), sizeWithMargins.width(), sizeWithMargins.height());
117 if (Q_UNLIKELY(!eglWindow)) {
118 qCWarning(lcQpaWayland, "Could not create wl_egl_window with size %dx%d\n", sizeWithMargins.width(), sizeWithMargins.height());
119 return;
120 }
121
122 QSurfaceFormat fmt = window()->requestedFormat();
123 if (mDisplay->supportsWindowDecoration())
124 fmt.setAlphaBufferSize(8);
125 EGLConfig eglConfig = q_configFromGLFormat(display: m_clientBufferIntegration->eglDisplay(), format: fmt);
126 m_format = q_glFormatFromConfig(display: m_clientBufferIntegration->eglDisplay(), config: eglConfig, referenceFormat: fmt);
127
128 EGLSurface eglSurface = eglCreateWindowSurface(dpy: m_clientBufferIntegration->eglDisplay(), config: eglConfig, win: (EGLNativeWindowType) eglWindow, attrib_list: 0);
129 if (Q_UNLIKELY(eglSurface == EGL_NO_SURFACE)) {
130 qCWarning(lcQpaWayland, "Could not create EGL surface (EGL error 0x%x)\n", eglGetError());
131 wl_egl_window_destroy(egl_window: eglWindow);
132 return;
133 }
134
135 m_waylandEglWindow = eglWindow;
136 m_eglSurface = eglSurface;
137 m_requestedSize = sizeWithMargins;
138 }
139 }
140}
141
142QRect QWaylandEglWindow::contentsRect() const
143{
144 QRect r = geometry();
145 QMargins m = clientSideMargins();
146 return QRect(m.left(), m.bottom(), r.width(), r.height());
147}
148
149QSurfaceFormat QWaylandEglWindow::format() const
150{
151 return m_format;
152}
153
154void QWaylandEglWindow::invalidateSurface()
155{
156 if (m_eglSurface) {
157 eglDestroySurface(dpy: m_clientBufferIntegration->eglDisplay(), surface: m_eglSurface);
158 m_eglSurface = 0;
159 }
160 if (m_waylandEglWindow) {
161 wl_egl_window_destroy(egl_window: m_waylandEglWindow);
162 m_waylandEglWindow = nullptr;
163 }
164 delete m_contentFBO;
165 m_contentFBO = nullptr;
166}
167
168EGLSurface QWaylandEglWindow::eglSurface() const
169{
170 return m_eglSurface;
171}
172
173GLuint QWaylandEglWindow::contentFBO() const
174{
175 if (!decoration())
176 return 0;
177
178 if (m_resize || !m_contentFBO) {
179 QOpenGLFramebufferObject *old = m_contentFBO;
180 QSize fboSize = geometry().size() * scale();
181 m_contentFBO = new QOpenGLFramebufferObject(fboSize.width(), fboSize.height(), QOpenGLFramebufferObject::CombinedDepthStencil);
182
183 delete old;
184 m_resize = false;
185 }
186
187 return m_contentFBO->handle();
188}
189
190GLuint QWaylandEglWindow::contentTexture() const
191{
192 return m_contentFBO->texture();
193}
194
195void QWaylandEglWindow::bindContentFBO()
196{
197 if (decoration()) {
198 contentFBO();
199 m_contentFBO->bind();
200 }
201}
202
203}
204
205QT_END_NAMESPACE
206
207#include "moc_qwaylandeglwindow_p.cpp"
208

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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