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