1 | // Copyright (C) 2017 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "drmeglserverbufferintegration.h" |
5 | |
6 | #include <QtOpenGL/QOpenGLTexture> |
7 | #include <QtGui/QOpenGLContext> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | DrmEglServerBuffer::DrmEglServerBuffer(DrmEglServerBufferIntegration *integration, const QImage &qimage, QtWayland::ServerBuffer::Format format) |
12 | : QtWayland::ServerBuffer(qimage.size(),format) |
13 | , m_integration(integration) |
14 | { |
15 | m_format = format; |
16 | |
17 | EGLint egl_format; |
18 | switch (m_format) { |
19 | case RGBA32: |
20 | m_drm_format = QtWaylandServer::qt_drm_egl_server_buffer::format_RGBA32; |
21 | egl_format = EGL_DRM_BUFFER_FORMAT_ARGB32_MESA; |
22 | break; |
23 | #ifdef EGL_DRM_BUFFER_FORMAT_A8_MESA |
24 | case A8: |
25 | m_drm_format = QtWaylandServer::qt_drm_egl_server_buffer::format_A8; |
26 | egl_format = EGL_DRM_BUFFER_FORMAT_A8_MESA; |
27 | break; |
28 | #endif |
29 | default: |
30 | qWarning(msg: "DrmEglServerBuffer: unsupported format" ); |
31 | m_drm_format = QtWaylandServer::qt_drm_egl_server_buffer::format_RGBA32; |
32 | egl_format = EGL_DRM_BUFFER_FORMAT_ARGB32_MESA; |
33 | break; |
34 | } |
35 | EGLint imageAttribs[] = { |
36 | EGL_WIDTH, m_size.width(), |
37 | EGL_HEIGHT, m_size.height(), |
38 | EGL_DRM_BUFFER_FORMAT_MESA, egl_format, |
39 | EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA, |
40 | EGL_NONE |
41 | }; |
42 | |
43 | m_image = m_integration->eglCreateDRMImageMESA(attrib_list: imageAttribs); |
44 | |
45 | EGLint handle; |
46 | if (!m_integration->eglExportDRMImageMESA(image: m_image, name: &m_name, handle: &handle, stride: &m_stride)) { |
47 | qWarning(msg: "DrmEglServerBuffer: Failed to export egl image" ); |
48 | } |
49 | |
50 | m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D); |
51 | m_texture->create(); |
52 | m_texture->bind(); |
53 | |
54 | m_integration->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image: m_image); |
55 | |
56 | glTexSubImage2D(GL_TEXTURE_2D, level: 0, xoffset: 0, yoffset: 0, width: qimage.width(), height: qimage.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels: qimage.constBits()); |
57 | |
58 | m_texture->release(); |
59 | m_texture->setSize(width: m_size.width(), height: m_size.height()); |
60 | } |
61 | |
62 | struct ::wl_resource *DrmEglServerBuffer::resourceForClient(struct ::wl_client *client) |
63 | { |
64 | auto *bufferResource = resourceMap().value(client); |
65 | if (!bufferResource) { |
66 | auto integrationResource = m_integration->resourceMap().value(client); |
67 | if (!integrationResource) { |
68 | qWarning(msg: "DrmEglServerBuffer::resourceForClient: Trying to get resource for ServerBuffer. But client is not bound to the drm_egl interface" ); |
69 | return nullptr; |
70 | } |
71 | struct ::wl_resource *drm_egl_integration_resource = integrationResource->handle; |
72 | Resource *resource = add(client, 1); |
73 | m_integration->send_server_buffer_created(drm_egl_integration_resource, resource->handle, m_name, m_size.width(), m_size.height(), m_stride, m_drm_format); |
74 | return resource->handle; |
75 | } |
76 | return bufferResource->handle; |
77 | } |
78 | |
79 | |
80 | QOpenGLTexture *DrmEglServerBuffer::toOpenGlTexture() |
81 | { |
82 | if (!m_texture) { |
83 | qWarning(msg: "DrmEglServerBuffer::toOpenGlTexture: no texture defined" ); |
84 | } |
85 | return m_texture; |
86 | } |
87 | |
88 | bool DrmEglServerBuffer::bufferInUse() |
89 | { |
90 | return resourceMap().size() > 0; |
91 | } |
92 | |
93 | DrmEglServerBufferIntegration::DrmEglServerBufferIntegration() |
94 | { |
95 | } |
96 | |
97 | DrmEglServerBufferIntegration::~DrmEglServerBufferIntegration() |
98 | { |
99 | } |
100 | |
101 | bool DrmEglServerBufferIntegration::initializeHardware(QWaylandCompositor *compositor) |
102 | { |
103 | Q_ASSERT(QGuiApplication::platformNativeInterface()); |
104 | |
105 | m_egl_display = static_cast<EGLDisplay>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration(resource: "egldisplay" )); |
106 | if (!m_egl_display) { |
107 | qWarning(msg: "Can't initialize drm egl server buffer integration. Missing egl display from platform plugin" ); |
108 | return false; |
109 | } |
110 | |
111 | const char *extensionString = eglQueryString(dpy: m_egl_display, EGL_EXTENSIONS); |
112 | if (!extensionString || !strstr(haystack: extensionString, needle: "EGL_KHR_image" )) { |
113 | qWarning(msg: "Failed to initialize drm egl server buffer integration. There is no EGL_KHR_image extension.\n" ); |
114 | return false; |
115 | } |
116 | m_egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress(procname: "eglCreateImageKHR" )); |
117 | m_egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress(procname: "eglDestroyImageKHR" )); |
118 | if (!m_egl_create_image || !m_egl_destroy_image) { |
119 | qWarning(msg: "Failed to initialize drm egl server buffer integration. Could not resolve eglCreateImageKHR or eglDestroyImageKHR" ); |
120 | return false; |
121 | } |
122 | |
123 | if (!extensionString || !strstr(haystack: extensionString, needle: "EGL_MESA_drm_image" )) { |
124 | qWarning(msg: "Failed to initialize drm egl server buffer integration. There is no EGL_MESA_drm_image extension.\n" ); |
125 | return false; |
126 | } |
127 | |
128 | m_egl_create_drm_image = reinterpret_cast<PFNEGLCREATEDRMIMAGEMESAPROC>(eglGetProcAddress(procname: "eglCreateDRMImageMESA" )); |
129 | m_egl_export_drm_image = reinterpret_cast<PFNEGLEXPORTDRMIMAGEMESAPROC>(eglGetProcAddress(procname: "eglExportDRMImageMESA" )); |
130 | if (!m_egl_create_drm_image || !m_egl_export_drm_image) { |
131 | qWarning(msg: "Failed to initialize drm egl server buffer integration. Could not find eglCreateDRMImageMESA or eglExportDRMImageMESA.\n" ); |
132 | return false; |
133 | } |
134 | |
135 | m_gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress(procname: "glEGLImageTargetTexture2DOES" )); |
136 | if (!m_gl_egl_image_target_texture_2d) { |
137 | qWarning(msg: "Failed to initialize drm egl server buffer integration. Could not find glEGLImageTargetTexture2DOES.\n" ); |
138 | return false; |
139 | } |
140 | |
141 | QtWaylandServer::qt_drm_egl_server_buffer::init(compositor->display(), 1); |
142 | return true; |
143 | } |
144 | |
145 | bool DrmEglServerBufferIntegration::supportsFormat(QtWayland::ServerBuffer::Format format) const |
146 | { |
147 | switch (format) { |
148 | case QtWayland::ServerBuffer::RGBA32: |
149 | return true; |
150 | case QtWayland::ServerBuffer::A8: |
151 | #ifdef EGL_DRM_BUFFER_FORMAT_A8_MESA |
152 | return true; |
153 | #else |
154 | return false; |
155 | #endif |
156 | default: |
157 | return false; |
158 | } |
159 | } |
160 | |
161 | QtWayland::ServerBuffer *DrmEglServerBufferIntegration::createServerBufferFromImage(const QImage &qimage, QtWayland::ServerBuffer::Format format) |
162 | { |
163 | return new DrmEglServerBuffer(this, qimage, format); |
164 | } |
165 | |
166 | QT_END_NAMESPACE |
167 | |