Fix eglChooseConfig eglError report, fix first time painting artifacts.
[qt:android-lighthouse.git] / src / plugins / platforms / android / src / opengl / qandroideglfsscreen.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qandroideglfsscreen.h"
43 #include "qandroidplatformintegration.h"
44
45 #include "qeglconvenience.h"
46 #include "qandroideglplatformcontext.h"
47
48 #include "androidjnimain.h"
49 #include "GLES2/gl2.h"
50
51 #include <android/api-level.h>
52
53 #if __ANDROID_API__>8
54 # include <android/native_window.h>
55 #endif
56
57 #include <QWindowSystemInterface>
58 #include <QApplication>
59 #include <QTimer>
60 #include <QThread>
61 #include <QDebug>
62
63 QT_BEGIN_NAMESPACE
64
65 //#define QEGL_EXTRA_DEBUG
66
67 #ifdef QEGL_EXTRA_DEBUG
68
69 struct AttrInfo { EGLint attr; const char *name; };
70 static struct AttrInfo attrs[] = {
71     {EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE"},
72     {EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE"},
73     {EGL_BLUE_SIZE, "EGL_BLUE_SIZE"},
74     {EGL_GREEN_SIZE, "EGL_GREEN_SIZE"},
75     {EGL_RED_SIZE, "EGL_RED_SIZE"},
76     {EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE"},
77     {EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE"},
78     {EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT"},
79     {EGL_CONFIG_ID, "EGL_CONFIG_ID"},
80     {EGL_LEVEL, "EGL_LEVEL"},
81     {EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT"},
82     {EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS"},
83     {EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH"},
84     {EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE"},
85     {EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID"},
86     {EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE"},
87     {EGL_SAMPLES, "EGL_SAMPLES"},
88     {EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS"},
89     {EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE"},
90     {EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE"},
91     {EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE"},
92     {EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE"},
93     {EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE"},
94     {EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB"},
95     {EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA"},
96     {EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL"},
97     {EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL"},
98     {-1, 0}};
99 #endif //QEGL_EXTRA_DEBUG
100
101 QAndroidEglFSScreen::QAndroidEglFSScreen(EGLNativeDisplayType display)
102     : m_depth(32)
103     , m_format(QImage::Format_Invalid)
104     , m_platformContext(0)
105     , m_windowSurface(EGL_NO_SURFACE)
106 {
107     mPhysicalSize = QSize(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth,
108                             QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight);
109
110     mGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth,
111                             QAndroidPlatformIntegration::m_defaultGeometryHeight);
112
113 #ifdef QEGL_EXTRA_DEBUG
114     qWarning("QEglScreen %p\n", this);
115 #endif
116
117     EGLint major, minor;
118     if (!eglBindAPI(EGL_OPENGL_ES_API)) {
119         qWarning("Could not bind GL_ES API\n");
120         qFatal("EGL error");
121     }
122
123     m_display = eglGetDisplay(display);
124     if (m_display == EGL_NO_DISPLAY) {
125         qWarning("Could not open egl display\n");
126         qFatal("EGL error");
127     }
128     qWarning("Opened display %p\n", m_display);
129
130     if (!eglInitialize(m_display, &major, &minor)) {
131         qWarning("Could not initialize egl display\n");
132         qFatal("EGL error");
133     }
134
135     qWarning("Initialized display %d %d\n", major, minor);
136
137     int swapInterval = 1;
138     QByteArray swapIntervalString = qgetenv("QT_QPA_EGLFS_SWAPINTERVAL");
139     if (!swapIntervalString.isEmpty()) {
140         bool ok;
141         swapInterval = swapIntervalString.toInt(&ok);
142         if (!ok)
143             swapInterval = 1;
144     }
145     eglSwapInterval(m_display, swapInterval);
146 }
147
148 void QAndroidEglFSScreen::createWindowSurface()
149 {
150     if (m_windowSurface!=EGL_NO_SURFACE)
151     { // unbind and destroy old surface
152         eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
153         eglDestroySurface(m_display, m_windowSurface);
154         m_windowSurface = EGL_NO_SURFACE;
155     }
156
157     EGLNativeWindowType window=QtAndroid::getNativeWindow();
158 #if __ANDROID_API__>8
159     qDebug()<<"ANativeWindow_settings width "<<ANativeWindow_getWidth(window)<<" height "<<ANativeWindow_getHeight(window)<<" format "<< ANativeWindow_getFormat(window);
160     EGLint format;
161     eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &format);
162     qt_checkAndWarnAboutEGLError(__PRETTY_FUNCTION__, "eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &format);");
163     ANativeWindow_setBuffersGeometry(window, 0, 0, format);
164 #endif
165     qDebug()<<"QAndroidEglFSScreen::createWindowSurface"<<window;
166     m_windowSurface = eglCreateWindowSurface(m_display, m_config, window, 0); 
167     qt_checkAndWarnAboutEGLError(__PRETTY_FUNCTION__, "m_windowSurface = eglCreateWindowSurface(m_display, m_config, window, 0);");
168     if (m_windowSurface == EGL_NO_SURFACE) {
169         qWarning("Could not create the egl surface: error = 0x%x\n", eglGetError());
170         eglTerminate(m_display);
171         qFatal("EGL error");
172     }
173
174     EGLint w,h;                    // screen size detection
175     eglQuerySurface(m_display, m_windowSurface, EGL_WIDTH, &w);
176     qt_checkAndWarnAboutEGLError(__PRETTY_FUNCTION__, "eglQuerySurface(m_display, m_windowSurface, EGL_WIDTH, &w);");
177     eglQuerySurface(m_display, m_windowSurface, EGL_HEIGHT, &h);
178     qt_checkAndWarnAboutEGLError(__PRETTY_FUNCTION__, "eglQuerySurface(m_display, m_windowSurface, EGL_HEIGHT, &h);");
179
180 #ifdef QEGL_EXTRA_DEBUG
181     qDebug() << "eglQuerySurface(m_display, m_windowSurface,...) returned:" << w << "for EGL_WIDTH and" << h << "for EGL_HEIGHT";
182 #endif
183
184     if(w <= 0 || h <= 0)
185         qFatal("EGL-WindowSurface has invalid size!");
186     QWindowSystemInterface::handleScreenAvailableGeometryChange(0);
187     QWindowSystemInterface::handleScreenGeometryChange(0);
188     QTimer::singleShot(50, this, SLOT(updateTLWindows())); // repaint the whole scene
189 }
190
191 void QAndroidEglFSScreen::createAndSetPlatformContext() const {
192     const_cast<QAndroidEglFSScreen *>(this)->createAndSetPlatformContext();
193 }
194
195 void QAndroidEglFSScreen::createAndSetPlatformContext()
196 {
197     QPlatformWindowFormat platformFormat = QPlatformWindowFormat::defaultFormat();
198
199     platformFormat.setWindowApi(QPlatformWindowFormat::OpenGL);
200
201     if (qgetenv("QT_QPA_EGLFS_DEPTH").toInt()==16)
202     {
203         platformFormat.setDepth(16);
204         platformFormat.setRedBufferSize(6);
205         platformFormat.setGreenBufferSize(5);
206         platformFormat.setBlueBufferSize(6);
207         m_depth = 16;
208         m_format = QImage::Format_RGB16;
209     }
210     else
211     {
212         platformFormat.setDepth(32);
213         platformFormat.setRedBufferSize(8);
214         platformFormat.setGreenBufferSize(8);
215         platformFormat.setBlueBufferSize(8);
216         m_depth = 32;
217         m_format = QImage::Format_RGB32;
218     }
219     if (!qgetenv("QT_QPA_EGLFS_MULTISAMPLE").isEmpty()) {
220         platformFormat.setSampleBuffers(true);
221     }
222
223     m_config = q_configFromQPlatformWindowFormat(m_display, platformFormat);
224
225 #ifdef QEGL_EXTRA_DEBUG
226     qWarning("Configuration %d matches requirements\n", (int)m_config);
227
228     for (int index = 0; attrs[index].attr != -1; ++index) {
229         EGLint value;
230         if (eglGetConfigAttrib(m_display, m_config, attrs[index].attr, &value)) {
231             qWarning("\t%s: %d\n", attrs[index].name, (int)value);
232         }
233     }
234     qWarning("\n");
235 #endif
236
237     createWindowSurface();
238
239     Q_ASSERT(m_platformContext == 0);
240     m_platformContext = new QAndroidEglFSPlatformContext(m_display, m_config, m_windowSurface, EGL_OPENGL_ES_API);
241     m_platformContext->makeCurrent();              // Is this necessary?
242 }
243
244 void QAndroidEglFSScreen::setGeometry(QRect rect)
245 {
246     qDebug()<<"QAndroidEglFSScreen::setGeometry"<<rect;
247     mGeometry = rect;
248 }
249
250 void QAndroidEglFSScreen::setPhysicalSize(QSize size)
251 {
252     qDebug()<<"QAndroidEglFSScreen::setPhysicalSize"<<size;
253     mPhysicalSize = size;
254 }
255
256 void QAndroidEglFSScreen::updateTLWindows()
257 {
258     foreach(QWidget * w, qApp->topLevelWidgets())
259         w->update();
260 }
261
262 QRect QAndroidEglFSScreen::geometry() const
263 {
264     return mGeometry;
265 }
266
267 QSize QAndroidEglFSScreen::physicalSize() const
268 {
269     return mPhysicalSize;
270 }
271
272 int QAndroidEglFSScreen::depth() const
273 {
274     return m_depth;
275 }
276
277 QImage::Format QAndroidEglFSScreen::format() const
278 {
279     if (m_format == QImage::Format_Invalid) {
280         createAndSetPlatformContext();
281     }
282     return m_format;
283 }
284
285 QAndroidEglFSPlatformContext *QAndroidEglFSScreen::platformContext() const
286 {
287     if (!m_platformContext) {
288         createAndSetPlatformContext();
289     }
290     return m_platformContext;
291 }
292
293 void QAndroidEglFSScreen::surfaceChanged()
294 {
295     if (!m_platformContext)
296         createAndSetPlatformContext();
297     else
298         createWindowSurface();
299
300     platformContext()->setSurface(m_windowSurface);
301 }
302
303 QT_END_NAMESPACE