1 /*
2 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7 #include "drmclientbuffer.h"
8 #include "clientbuffer_p.h"
9 #include "display.h"
10
11 #include <EGL/egl.h>
12 #include <QtGui/qopengl.h>
13
14 #ifndef EGL_WL_bind_wayland_display
15 #define EGL_WAYLAND_Y_INVERTED_WL 0x31DB
16 #endif
17
18 namespace KWaylandServer
19 {
20 typedef GLboolean (*eglQueryWaylandBufferWL_func)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
21 static eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr;
22
23 class DrmClientBufferPrivate : public ClientBufferPrivate
24 {
25 public:
26 int textureFormat = 0;
27 int width = 0;
28 int height = 0;
29 int yInverted = 0;
30 bool hasAlphaChannel = false;
31 };
32
DrmClientBuffer(wl_resource * resource,DrmClientBufferIntegration * integration)33 DrmClientBuffer::DrmClientBuffer(wl_resource *resource, DrmClientBufferIntegration *integration)
34 : ClientBuffer(resource, *new DrmClientBufferPrivate)
35 {
36 Q_D(DrmClientBuffer);
37
38 EGLDisplay eglDisplay = integration->display()->eglDisplay();
39 if (!eglQueryWaylandBufferWL(eglDisplay, resource, EGL_TEXTURE_FORMAT, &d->textureFormat)) {
40 // The proprietary Nvidia driver doesn't support querying the EGL_TEXTURE_FORMAT.
41 // We must assume that the buffer has an alpha channel for transparency to work.
42 d->textureFormat = EGL_TEXTURE_RGBA;
43 }
44
45 eglQueryWaylandBufferWL(eglDisplay, resource, EGL_WIDTH, &d->width);
46 eglQueryWaylandBufferWL(eglDisplay, resource, EGL_HEIGHT, &d->height);
47
48 if (!eglQueryWaylandBufferWL(eglDisplay, resource, EGL_WAYLAND_Y_INVERTED_WL, &d->yInverted)) {
49 // If EGL_WAYLAND_Y_INVERTED_WL is unsupported, we must assume that the buffer is inverted.
50 d->yInverted = true;
51 }
52 }
53
textureFormat() const54 int DrmClientBuffer::textureFormat() const
55 {
56 Q_D(const DrmClientBuffer);
57 return d->textureFormat;
58 }
59
size() const60 QSize DrmClientBuffer::size() const
61 {
62 Q_D(const DrmClientBuffer);
63 return QSize(d->width, d->height);
64 }
65
hasAlphaChannel() const66 bool DrmClientBuffer::hasAlphaChannel() const
67 {
68 Q_D(const DrmClientBuffer);
69 return d->textureFormat == EGL_TEXTURE_RGBA;
70 }
71
origin() const72 ClientBuffer::Origin DrmClientBuffer::origin() const
73 {
74 Q_D(const DrmClientBuffer);
75 return d->yInverted ? Origin::TopLeft : Origin::BottomLeft;
76 }
77
DrmClientBufferIntegration(Display * display)78 DrmClientBufferIntegration::DrmClientBufferIntegration(Display *display)
79 : ClientBufferIntegration(display)
80 {
81 }
82
createBuffer(::wl_resource * resource)83 ClientBuffer *DrmClientBufferIntegration::createBuffer(::wl_resource *resource)
84 {
85 EGLDisplay eglDisplay = display()->eglDisplay();
86 static bool resolved = false;
87 if (!resolved && eglDisplay != EGL_NO_DISPLAY) {
88 eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress("eglQueryWaylandBufferWL");
89 resolved = true;
90 }
91
92 EGLint height;
93 if (eglQueryWaylandBufferWL(eglDisplay, resource, EGL_HEIGHT, &height)) {
94 return new DrmClientBuffer(resource, this);
95 }
96 return nullptr;
97 }
98
99 } // namespace KWaylandServer
100