BRCM EGL integration to handle eglCreateGlobalImageBRCM.
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / gl_integration / brcm_egl / qwaylandbrcmeglwindow.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 plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwaylandbrcmeglwindow.h"
43
44 #include "qwaylandbuffer.h"
45 #include "qwaylandscreen.h"
46 #include "qwaylandbrcmglcontext.h"
47
48 #include <QtPlatformSupport/private/qeglconvenience_p.h>
49
50 #include <QtGui/QWindow>
51 #include <QtGui/QWindowSystemInterface>
52
53 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
54 #include "windowmanager_integration/qwaylandwindowmanagerintegration.h"
55 #endif
56
57 #define EGL_EGLEXT_PROTOTYPES
58 #include <EGL/eglext_brcm.h>
59
60 #include "wayland-brcm-client-protocol.h"
61
62 class QWaylandBrcmBuffer : public QWaylandBuffer
63 {
64 public:
65     QWaylandBrcmBuffer(QWaylandDisplay *display,
66                        struct wl_brcm *brcm,
67                        const QSize &size,
68                        EGLint *data,
69                        int count)
70         : m_size(size)
71         , m_released(true)
72         , m_display(display)
73     {
74         wl_array_init(&m_array);
75         m_data = static_cast<EGLint *>(wl_array_add(&m_array, count * sizeof(EGLint)));
76
77         for (int i = 0; i < count; ++i)
78             m_data[i] = data[i];
79
80         mBuffer = wl_brcm_create_buffer(brcm, size.width(), size.height(), &m_array);
81
82         static const struct wl_buffer_listener buffer_listener = {
83             QWaylandBrcmBuffer::buffer_release
84         };
85
86         wl_buffer_add_listener(mBuffer, &buffer_listener, this);
87     }
88
89     ~QWaylandBrcmBuffer()
90     {
91         wl_array_release(&m_array);
92     }
93
94     QSize size() const { return m_size; }
95
96     void bind()
97     {
98         m_released = false;
99     }
100
101     void waitForRelease()
102     {
103         if (m_released)
104             return;
105         m_mutex.lock();
106         while (!m_released)
107             m_condition.wait(&m_mutex);
108         m_mutex.unlock();
109     }
110
111     static void buffer_release(void *data, wl_buffer *buffer)
112     {
113         Q_UNUSED(buffer);
114         m_mutex.lock();
115         static_cast<QWaylandBrcmBuffer *>(data)->m_released = true;
116         m_condition.wakeAll();
117         m_mutex.unlock();
118     }
119
120 private:
121     static QWaitCondition m_condition;
122     static QMutex m_mutex;
123
124     QSize m_size;
125     bool m_released;
126     wl_array m_array;
127     EGLint *m_data;
128     QWaylandDisplay *m_display;
129 };
130
131 QWaitCondition QWaylandBrcmBuffer::m_condition;
132 QMutex QWaylandBrcmBuffer::m_mutex;
133
134 QWaylandBrcmEglWindow::QWaylandBrcmEglWindow(QWindow *window)
135     : QWaylandWindow(window)
136     , m_eglIntegration(static_cast<QWaylandBrcmEglIntegration *>(mDisplay->eglIntegration()))
137     , m_eglConfig(0)
138     , m_format(window->format())
139     , m_current(0)
140     , m_count(0)
141 {
142 }
143
144 QWaylandBrcmEglWindow::~QWaylandBrcmEglWindow()
145 {
146     destroyEglSurfaces();
147 }
148
149 QWaylandWindow::WindowType QWaylandBrcmEglWindow::windowType() const
150 {
151     return QWaylandWindow::Egl;
152 }
153
154 void QWaylandBrcmEglWindow::setGeometry(const QRect &rect)
155 {
156     destroyEglSurfaces();
157     QWaylandWindow::setGeometry(rect);
158 }
159
160 QSurfaceFormat QWaylandBrcmEglWindow::format() const
161 {
162     return m_format;
163 }
164
165 void QWaylandBrcmEglWindow::destroyEglSurfaces()
166 {
167     for (int i = 0; i < m_count; ++i) {
168         if (m_eglSurfaces[i]) {
169             eglDestroySurface(m_eglIntegration->eglDisplay(), m_eglSurfaces[i]);
170             m_eglSurfaces[i] = 0;
171             // the server does this
172             //m_eglIntegration->eglDestroyGlobalImageBRCM(&m_globalImages[5*i]);
173             delete m_buffers[i];
174         }
175     }
176
177     m_count = 0;
178     m_current = 0;
179 }
180
181 QSurfaceFormat brcmFixFormat(const QSurfaceFormat &f)
182 {
183     QSurfaceFormat format = f;
184     format.setRedBufferSize(8);
185     format.setGreenBufferSize(8);
186     format.setBlueBufferSize(8);
187     format.setAlphaBufferSize(8);
188     return format;
189 }
190
191 void QWaylandBrcmEglWindow::createEglSurfaces()
192 {
193     QSize size(geometry().size());
194
195     m_count = window()->format().swapBehavior() == QSurfaceFormat::TripleBuffer ? 3 : 2;
196
197     m_eglConfig = q_configFromGLFormat(m_eglIntegration->eglDisplay(), brcmFixFormat(window()->format()), true, EGL_PIXMAP_BIT);
198
199     m_format = q_glFormatFromConfig(m_eglIntegration->eglDisplay(), m_eglConfig);
200
201     EGLint pixel_format = EGL_PIXEL_FORMAT_ARGB_8888_BRCM;
202
203     EGLint rt;
204     eglGetConfigAttrib(m_eglIntegration->eglDisplay(), m_eglConfig, EGL_RENDERABLE_TYPE, &rt);
205
206     if (rt & EGL_OPENGL_ES_BIT) {
207         pixel_format |= EGL_PIXEL_FORMAT_RENDER_GLES_BRCM;
208         pixel_format |= EGL_PIXEL_FORMAT_GLES_TEXTURE_BRCM;
209     }
210
211     if (rt & EGL_OPENGL_ES2_BIT) {
212         pixel_format |= EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM;
213         pixel_format |= EGL_PIXEL_FORMAT_GLES2_TEXTURE_BRCM;
214     }
215
216     if (rt & EGL_OPENVG_BIT) {
217         pixel_format |= EGL_PIXEL_FORMAT_RENDER_VG_BRCM;
218         pixel_format |= EGL_PIXEL_FORMAT_VG_IMAGE_BRCM;
219     }
220
221     if (rt & EGL_OPENGL_BIT) {
222         pixel_format |= EGL_PIXEL_FORMAT_RENDER_GL_BRCM;
223     }
224
225     memset(m_globalImages, 0, 5 * m_count * sizeof(EGLint));
226     for (int i = 0; i < m_count; ++i) {
227         m_eglIntegration->eglCreateGlobalImageBRCM(size.width(), size.height(), pixel_format,
228                 0, size.width() * 4, &m_globalImages[5*i]);
229
230         m_globalImages[5*i+2] = size.width();
231         m_globalImages[5*i+3] = size.height();
232         m_globalImages[5*i+4] = pixel_format;
233
234         EGLint attrs[] = {
235             EGL_VG_COLORSPACE, EGL_VG_COLORSPACE_sRGB,
236             EGL_VG_ALPHA_FORMAT, pixel_format & EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM ? EGL_VG_ALPHA_FORMAT_PRE : EGL_VG_ALPHA_FORMAT_NONPRE,
237             EGL_NONE
238         };
239
240         m_eglSurfaces[i] = eglCreatePixmapSurface(m_eglIntegration->eglDisplay(), m_eglConfig, (EGLNativePixmapType)&m_globalImages[5*i], attrs);
241         if (m_eglSurfaces[i] == EGL_NO_SURFACE)
242             qFatal("eglCreatePixmapSurface failed: %x, global image id: %d %d\n", eglGetError(), m_globalImages[5*i], m_globalImages[5*i+1]);
243         m_buffers[i] = new QWaylandBrcmBuffer(mDisplay, m_eglIntegration->waylandBrcm(), size, &m_globalImages[5*i], 5);
244     }
245 }
246
247 void QWaylandBrcmEglWindow::swapBuffers()
248 {
249     if (m_eglIntegration->eglFlushBRCM) {
250         m_eglIntegration->eglFlushBRCM();
251     } else {
252         glFlush();
253         glFinish();
254     }
255
256     m_buffers[m_current]->bind();
257
258     m_mutex.lock();
259     m_pending << m_buffers[m_current];
260     m_mutex.unlock();
261
262     // can't use a direct call since swapBuffers might be called from a separate thread
263     QMetaObject::invokeMethod(this, "flushBuffers");
264
265     m_current = (m_current + 1) % m_count;
266
267     m_buffers[m_current]->waitForRelease();
268 }
269
270 void QWaylandBrcmEglWindow::flushBuffers()
271 {
272     if (m_pending.isEmpty())
273         return;
274
275     QSize size = geometry().size();
276
277     m_mutex.lock();
278     while (!m_pending.isEmpty()) {
279         QWaylandBrcmBuffer *buffer = m_pending.takeFirst();
280         attach(buffer);
281         damage(QRect(QPoint(), size));
282     }
283     m_mutex.unlock();
284
285     mDisplay->flushRequests();
286 }
287
288 bool QWaylandBrcmEglWindow::makeCurrent(EGLContext context)
289 {
290     if (!m_count)
291         const_cast<QWaylandBrcmEglWindow *>(this)->createEglSurfaces();
292     return eglMakeCurrent(m_eglIntegration->eglDisplay(), m_eglSurfaces[m_current], m_eglSurfaces[m_current], context);
293 }
294