Optimized EGLFS backing store a bit.
[profile/ivi/qtbase.git] / src / plugins / platforms / eglfs / qeglfsbackingstore.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 "qeglfsbackingstore.h"
43
44 #include <QtGui/QOpenGLContext>
45 #include <QtGui/QOpenGLPaintDevice>
46 #include <QtGui/QOpenGLShaderProgram>
47
48 #include <QtGui/QScreen>
49
50 QT_BEGIN_NAMESPACE
51
52 QEglFSBackingStore::QEglFSBackingStore(QWindow *window)
53     : QPlatformBackingStore(window)
54     , m_context(new QOpenGLContext)
55 #ifdef EGLFS_BACKINGSTORE_USE_IMAGE
56     , m_texture(0)
57     , m_program(0)
58 #endif
59 {
60     m_context->setFormat(window->requestedFormat());
61     m_context->setScreen(window->screen());
62     m_context->create();
63 }
64
65 QEglFSBackingStore::~QEglFSBackingStore()
66 {
67     delete m_context;
68 }
69
70 QPaintDevice *QEglFSBackingStore::paintDevice()
71 {
72 #ifdef EGLFS_BACKINGSTORE_USE_IMAGE
73     return &m_image;
74 #else
75     return m_device;
76 #endif
77 }
78
79 void QEglFSBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
80 {
81     Q_UNUSED(region);
82     Q_UNUSED(offset);
83
84 #ifdef QEGL_EXTRA_DEBUG
85     qWarning("QEglBackingStore::flush %p", window);
86 #endif
87
88 #ifdef EGLFS_BACKINGSTORE_USE_IMAGE
89     if (!m_program) {
90         static const char *textureVertexProgram =
91             "attribute highp vec2 vertexCoordEntry;\n"
92             "attribute highp vec2 textureCoordEntry;\n"
93             "varying highp vec2 textureCoord;\n"
94             "void main() {\n"
95             "   textureCoord = textureCoordEntry;\n"
96             "   gl_Position = vec4(vertexCoordEntry, 0.0, 1.0);\n"
97             "}\n";
98
99         static const char *textureFragmentProgram =
100             "uniform sampler2D texture;\n"
101             "varying highp vec2 textureCoord;\n"
102             "void main() {\n"
103             "   gl_FragColor = texture2D(texture, textureCoord).bgra;\n"
104             "}\n";
105
106         m_program = new QOpenGLShaderProgram;
107
108         m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
109         m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
110         m_program->link();
111
112         m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry");
113         m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry");
114     }
115
116     m_program->bind();
117
118     const GLfloat textureCoordinates[] = {
119         0, 1,
120         1, 1,
121         1, 0,
122         0, 0
123     };
124
125     QRectF r = window->geometry();
126     QRectF sr = window->screen()->geometry();
127
128     GLfloat x1 = (r.left() / sr.width()) * 2 - 1;
129     GLfloat x2 = (r.right() / sr.width()) * 2 - 1;
130     GLfloat y1 = (r.top() / sr.height()) * 2 - 1;
131     GLfloat y2 = (r.bottom() / sr.height()) * 2 - 1;
132
133     const GLfloat vertexCoordinates[] = {
134         x1, y1,
135         x2, y1,
136         x2, y2,
137         x1, y2
138     };
139
140     glEnableVertexAttribArray(m_vertexCoordEntry);
141     glEnableVertexAttribArray(m_textureCoordEntry);
142
143     glVertexAttribPointer(m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates);
144     glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
145
146     glBindTexture(GL_TEXTURE_2D, m_texture);
147
148     if (!m_dirty.isNull()) {
149         QRect imageRect = m_image.rect();
150
151         QRegion fixed;
152         foreach (const QRect &rect, m_dirty.rects()) {
153             // intersect with image rect to be sure
154             QRect r = imageRect & rect;
155
156             // if the rect is wide enough it's cheaper to just
157             // extend it instead of doing an image copy
158             if (r.width() >= imageRect.width() / 2) {
159                 r.setX(0);
160                 r.setWidth(imageRect.width());
161             }
162
163             fixed |= r;
164         }
165
166         foreach (const QRect &rect, fixed.rects()) {
167             // if the sub-rect is full-width we can pass the image data directly to
168             // OpenGL instead of copying, since there's no gap between scanlines
169             if (rect.width() == imageRect.width()) {
170                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_image.constScanLine(rect.y()));
171             } else {
172                 glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
173                     m_image.copy(rect).constBits());
174             }
175         }
176
177         m_dirty = QRegion();
178     }
179
180     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
181
182     glBindTexture(GL_TEXTURE_2D, 0);
183
184     glDisableVertexAttribArray(m_vertexCoordEntry);
185     glDisableVertexAttribArray(m_textureCoordEntry);
186 #endif
187
188     m_context->swapBuffers(window);
189 }
190
191 void QEglFSBackingStore::makeCurrent()
192 {
193     // needed to prevent QOpenGLContext::makeCurrent() from failing
194     window()->setSurfaceType(QSurface::OpenGLSurface);
195
196     m_context->makeCurrent(window());
197 }
198
199 void QEglFSBackingStore::beginPaint(const QRegion &rgn)
200 {
201     makeCurrent();
202
203 #ifdef EGLFS_BACKINGSTORE_USE_IMAGE
204     m_dirty = m_dirty | rgn;
205 #else
206     Q_UNUSED(rgn);
207     m_device = new QOpenGLPaintDevice(window()->size());
208 #endif
209 }
210
211 void QEglFSBackingStore::endPaint()
212 {
213 #ifndef EGLFS_BACKINGSTORE_USE_IMAGE
214     delete m_device;
215 #endif
216 }
217
218 void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents)
219 {
220     Q_UNUSED(staticContents);
221
222 #ifdef EGLFS_BACKINGSTORE_USE_IMAGE
223     m_image = QImage(size, QImage::Format_RGB32);
224     makeCurrent();
225     if (m_texture)
226         glDeleteTextures(1, &m_texture);
227     glGenTextures(1, &m_texture);
228     glBindTexture(GL_TEXTURE_2D, m_texture);
229     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
230     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
231     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
232     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
233
234     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
235 #else
236     Q_UNUSED(size);
237 #endif
238 }
239
240 QT_END_NAMESPACE