Use the new QPlatformNativeInterface native resource function getter
[profile/ivi/qtwayland.git] / src / compositor / hardware_integration / wayland_egl / waylandeglintegration.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the Qt Compositor.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
21 **     the names of its contributors may be used to endorse or promote
22 **     products derived from this software without specific prior written
23 **     permission.
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "waylandeglintegration.h"
42 #include "wayland_wrapper/wlcompositor.h"
43 #include "wayland_wrapper/wlsurface.h"
44 #include "compositor_api/waylandsurface.h"
45 #include <qpa/qplatformnativeinterface.h>
46 #include <QtGui/QGuiApplication>
47 #include <QtGui/QOpenGLContext>
48 #include <qpa/qplatformscreen.h>
49 #include <QtGui/QWindow>
50 #include <QtCore/QPointer>
51
52 #include <QDebug>
53
54 #include <EGL/egl.h>
55 #include <EGL/eglext.h>
56
57 #include <GLES2/gl2.h>
58 #include <GLES2/gl2ext.h>
59
60
61 GraphicsHardwareIntegration * GraphicsHardwareIntegration::createGraphicsHardwareIntegration(WaylandCompositor *compositor)
62 {
63     return new WaylandEglIntegration(compositor);
64 }
65
66 #ifndef EGL_WL_bind_wayland_display
67 typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
68 typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
69 #endif
70
71 #ifndef EGL_KHR_image
72 typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
73 typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
74 #endif
75
76 #ifndef GL_OES_EGL_image
77 typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
78 typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
79 #endif
80
81 class WaylandEglIntegrationPrivate
82 {
83 public:
84     WaylandEglIntegrationPrivate()
85         : egl_display(EGL_NO_DISPLAY)
86         , valid(false)
87         , flipperConnected(false)
88         , egl_bind_wayland_display(0)
89         , egl_unbind_wayland_display(0)
90         , egl_create_image(0)
91         , egl_destroy_image(0)
92         , gl_egl_image_target_texture_2d(0)
93     { }
94     EGLDisplay egl_display;
95     bool valid;
96     bool flipperConnected;
97 #ifdef EGL_WL_request_client_buffer_format
98     QPointer<WaylandSurface> directRenderSurface;
99 #endif
100     PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display;
101     PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display;
102
103     PFNEGLCREATEIMAGEKHRPROC egl_create_image;
104     PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image;
105
106     PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d;
107
108     QPlatformNativeInterface::NativeResourceForContextFunction get_egl_context;
109 };
110
111 WaylandEglIntegration::WaylandEglIntegration(WaylandCompositor *compositor)
112     : GraphicsHardwareIntegration(compositor)
113     , d_ptr(new WaylandEglIntegrationPrivate)
114 {
115 }
116
117 void WaylandEglIntegration::initializeHardware(Wayland::Display *waylandDisplay)
118 {
119     Q_D(WaylandEglIntegration);
120
121     QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
122     if (nativeInterface) {
123         d->egl_display = nativeInterface->nativeResourceForWindow("EglDisplay", m_compositor->window());
124         if (d->egl_display) {
125             const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS);
126             if (extensionString && strstr(extensionString, "EGL_WL_bind_wayland_display"))
127             {
128                 d->get_egl_context = nativeInterface->nativeResourceFunctionForContext("get_egl_context");
129                 if (!d->get_egl_context) {
130                     qWarning("Failed to retrieve the get_egl_context function");
131                 }
132                 d->egl_bind_wayland_display =
133                         reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL"));
134                 d->egl_unbind_wayland_display =
135                         reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL"));
136                 d->egl_create_image =
137                         reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
138                 d->egl_destroy_image =
139                         reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
140                 d->gl_egl_image_target_texture_2d =
141                         reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
142
143                 if (d->egl_bind_wayland_display
144                         && d->get_egl_context
145                         && d->egl_unbind_wayland_display
146                         && d->egl_create_image
147                         && d->egl_destroy_image
148                         && d->gl_egl_image_target_texture_2d) {
149                     if (d->egl_bind_wayland_display(d->egl_display, waylandDisplay->handle())) {
150                         d->valid = true;
151                     }
152                 }
153             }
154         }
155
156         if (!d->valid)
157             qWarning("Failed to initialize egl display\n");
158     }
159 }
160
161 GLuint WaylandEglIntegration::createTextureFromBuffer(wl_buffer *buffer, QOpenGLContext *context)
162 {
163     Q_D(WaylandEglIntegration);
164     if (!d->valid) {
165         qWarning("createTextureFromBuffer() failed\n");
166         return 0;
167     }
168
169     QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
170     EGLContext egl_context = d->get_egl_context(context);
171
172     EGLImageKHR image = d->egl_create_image(d->egl_display, egl_context,
173                                           EGL_WAYLAND_BUFFER_WL,
174                                           buffer, NULL);
175
176     GLuint textureId;
177     glGenTextures(1,&textureId);
178
179     glBindTexture(GL_TEXTURE_2D, textureId);
180
181     d->gl_egl_image_target_texture_2d(GL_TEXTURE_2D, image);
182
183     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
184     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
185     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
186     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
187
188     d->egl_destroy_image(d->egl_display, image);
189
190     return textureId;
191 }
192
193 bool WaylandEglIntegration::isYInverted(struct wl_buffer *buffer) const
194 {
195 #ifdef EGL_WL_request_client_buffer_format
196     return eglGetBufferYInvertedWL(buffer);
197 #else
198     return GraphicsHardwareIntegration::isYInverted(buffer);
199 #endif
200 }
201
202
203 bool WaylandEglIntegration::setDirectRenderSurface(WaylandSurface *surface)
204 {
205     Q_D(WaylandEglIntegration);
206
207     QPlatformScreen *screen = QPlatformScreen::platformScreenForWindow(m_compositor->window());
208     QPlatformScreenPageFlipper *flipper = screen ? screen->pageFlipper() : 0;
209     if (flipper && !d->flipperConnected) {
210         QObject::connect(flipper, SIGNAL(bufferReleased(void*)), m_compositor->handle(), SLOT(releaseBuffer(void*)));
211         d->flipperConnected = true;
212     }
213 #ifdef EGL_WL_request_client_buffer_format
214     int buffer_format = surface ? EGL_SCANOUT_FORMAT_WL : EGL_RENDER_FORMAT_WL;
215     struct wl_client *client = 0;
216     if (surface) {
217         client = surface->handle()->base()->resource.client;
218     } else {
219         WaylandSurface *oldSurface = d->directRenderSurface.data();
220         if (oldSurface)
221             client = oldSurface->handle()->base()->resource.client;
222     }
223     if (client)
224         eglRequestClientBufferFormatWL(d->egl_display, client, buffer_format);
225     d->directRenderSurface = surface;
226 #else
227     Q_UNUSED(surface);
228 #endif
229     return flipper;
230 }
231
232 void *WaylandEglIntegration::lockNativeBuffer(struct wl_buffer *buffer, QOpenGLContext *context) const
233 {
234     Q_D(const WaylandEglIntegration);
235
236     QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
237     EGLContext egl_context = d->get_egl_context(context);
238
239     EGLImageKHR image = d->egl_create_image(d->egl_display, egl_context,
240                                           EGL_WAYLAND_BUFFER_WL,
241                                           buffer, NULL);
242     return image;
243 }
244
245 void WaylandEglIntegration::unlockNativeBuffer(void *native_buffer, QOpenGLContext *) const
246 {
247     Q_D(const WaylandEglIntegration);
248     EGLImageKHR image = static_cast<EGLImageKHR>(native_buffer);
249
250     d->egl_destroy_image(d->egl_display, image);
251 }
252