source: trunk/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 9.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qmeegolivepixmapdata.h"
43#include "qmeegorasterpixmapdata.h"
44#include <private/qimage_p.h>
45#include <private/qwindowsurface_gl_p.h>
46#include <private/qeglcontext_p.h>
47#include <private/qapplication_p.h>
48#include <private/qgraphicssystem_runtime_p.h>
49#include <private/qpixmap_x11_p.h>
50#include <stdio.h>
51
52static EGLint lock_attribs[] = {
53 EGL_MAP_PRESERVE_PIXELS_KHR, EGL_TRUE,
54 EGL_LOCK_USAGE_HINT_KHR, EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR,
55 EGL_NONE
56};
57
58static EGLint preserved_attribs[] = {
59 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
60 EGL_NONE
61};
62
63// as copied from qwindowsurface.cpp
64void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
65{
66 // make sure we don't detach
67 uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits());
68
69 int lineskip = img.bytesPerLine();
70 int depth = img.depth() >> 3;
71
72 const QRect imageRect(0, 0, img.width(), img.height());
73 const QRect r = rect & imageRect & imageRect.translated(-offset);
74 const QPoint p = rect.topLeft() + offset;
75
76 if (r.isEmpty())
77 return;
78
79 const uchar *src;
80 uchar *dest;
81
82 if (r.top() < p.y()) {
83 src = mem + r.bottom() * lineskip + r.left() * depth;
84 dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth;
85 lineskip = -lineskip;
86 } else {
87 src = mem + r.top() * lineskip + r.left() * depth;
88 dest = mem + p.y() * lineskip + p.x() * depth;
89 }
90
91 const int w = r.width();
92 int h = r.height();
93 const int bytes = w * depth;
94
95 // overlapping segments?
96 if (offset.y() == 0 && qAbs(offset.x()) < w) {
97 do {
98 ::memmove(dest, src, bytes);
99 dest += lineskip;
100 src += lineskip;
101 } while (--h);
102 } else {
103 do {
104 ::memcpy(dest, src, bytes);
105 dest += lineskip;
106 src += lineskip;
107 } while (--h);
108 }
109}
110
111/* Public */
112
113QMeeGoLivePixmapData::QMeeGoLivePixmapData(int w, int h, QImage::Format format) : QGLPixmapData(QPixmapData::PixmapType)
114{
115 QImage image(w, h, format);
116 QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType);
117 pmd->fromImage(image, Qt::NoOpaqueDetection);
118 backingX11Pixmap = new QPixmap(pmd);
119
120 initializeThroughEGLImage();
121}
122
123QMeeGoLivePixmapData::QMeeGoLivePixmapData(Qt::HANDLE h) : QGLPixmapData(QPixmapData::PixmapType)
124{
125 backingX11Pixmap = new QPixmap(QPixmap::fromX11Pixmap(h));
126 initializeThroughEGLImage();
127}
128
129QMeeGoLivePixmapData::~QMeeGoLivePixmapData()
130{
131 delete backingX11Pixmap;
132}
133
134void QMeeGoLivePixmapData::initializeThroughEGLImage()
135{
136 QGLShareContextScope ctx(qt_gl_share_widget()->context());
137 QMeeGoExtensions::ensureInitialized();
138
139 EGLImageKHR eglImage = EGL_NO_IMAGE_KHR;
140 GLuint newTextureId = 0;
141
142 eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
143 (EGLClientBuffer) backingX11Pixmap->handle(), preserved_attribs);
144
145 if (eglImage == EGL_NO_IMAGE_KHR) {
146 qWarning("eglCreateImageKHR failed (live texture)!");
147 return;
148 }
149
150 glGenTextures(1, &newTextureId);
151 glBindTexture(GL_TEXTURE_2D, newTextureId);
152
153 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (EGLImageKHR) eglImage);
154 if (glGetError() == GL_NO_ERROR) {
155 resize(backingX11Pixmap->width(), backingX11Pixmap->height());
156 texture()->id = newTextureId;
157 texture()->options &= ~QGLContext::InvertedYBindOption;
158 m_hasAlpha = backingX11Pixmap->hasAlphaChannel();
159 } else {
160 qWarning("Failed to create a texture from an egl image (live texture)!");
161 glDeleteTextures(1, &newTextureId);
162 }
163
164 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
165}
166
167QPixmapData *QMeeGoLivePixmapData::createCompatiblePixmapData() const
168{
169 qWarning("Create compatible called on live pixmap! Expect fail soon...");
170 return new QMeeGoRasterPixmapData(pixelType());
171}
172
173QImage* QMeeGoLivePixmapData::lock(EGLSyncKHR fenceSync)
174{
175 QGLShareContextScope ctx(qt_gl_share_widget()->context());
176 QMeeGoExtensions::ensureInitialized();
177
178 if (fenceSync) {
179 QMeeGoExtensions::eglClientWaitSyncKHR(QEgl::display(),
180 fenceSync,
181 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
182 EGL_FOREVER_KHR);
183 }
184
185 void *data = 0;
186 int pitch = 0;
187 EGLSurface surface = 0;
188 QImage::Format format;
189 lockedImage = QImage();
190
191 surface = getSurfaceForBackingPixmap();
192 if (! QMeeGoExtensions::eglLockSurfaceKHR(QEgl::display(), surface, lock_attribs)) {
193 qWarning("Failed to lock surface (live texture)!");
194 return &lockedImage;
195 }
196
197 eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_POINTER_KHR, (EGLint*) &data);
198 eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_PITCH_KHR, (EGLint*) &pitch);
199
200 // Ok, here we know we just support those two formats. Real solution would be:
201 // uqery also the format.
202 if (backingX11Pixmap->depth() > 16)
203 format = QImage::Format_ARGB32_Premultiplied;
204 else
205 format = QImage::Format_RGB16;
206
207 if (data == NULL || pitch == 0) {
208 qWarning("Failed to query the live texture!");
209 return &lockedImage;
210 }
211
212 lockedImage = QImage((uchar *) data, width(), height(), format);
213 return &lockedImage;
214}
215
216bool QMeeGoLivePixmapData::release(QImage* /*img*/)
217{
218 QGLShareContextScope ctx(qt_gl_share_widget()->context());
219 QMeeGoExtensions::ensureInitialized();
220
221 if (QMeeGoExtensions::eglUnlockSurfaceKHR(QEgl::display(), getSurfaceForBackingPixmap())) {
222 lockedImage = QImage();
223 return true;
224 } else {
225 lockedImage = QImage();
226 return false;
227 }
228}
229
230Qt::HANDLE QMeeGoLivePixmapData::handle()
231{
232 return backingX11Pixmap->handle();
233}
234
235bool QMeeGoLivePixmapData::scroll(int dx, int dy, const QRect &rect)
236{
237 lock(NULL);
238
239 if (!lockedImage.isNull())
240 qt_scrollRectInImage(lockedImage, rect, QPoint(dx, dy));
241
242 release(&lockedImage);
243 return true;
244}
245
246EGLSurface QMeeGoLivePixmapData::getSurfaceForBackingPixmap()
247{
248 // This code is a crative remix of the stuff that can be found in the
249 // Qt's TFP implementation in /src/opengl/qgl_x11egl.cpp ::bindiTextureFromNativePixmap
250 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(backingX11Pixmap->data_ptr().data());
251 Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
252 bool hasAlpha = pixmapData->hasAlphaChannel();
253
254 if (pixmapData->gl_surface &&
255 hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
256 return pixmapData->gl_surface;
257
258 // Check to see if the surface is still valid
259 if (pixmapData->gl_surface &&
260 hasAlpha != ((pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha) > 0)) {
261 // Surface is invalid!
262 destroySurfaceForPixmapData(pixmapData);
263 }
264
265 if (pixmapData->gl_surface == 0) {
266 EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap,
267 QEgl::OpenGL,
268 hasAlpha ? QEgl::Translucent : QEgl::NoOptions);
269
270 pixmapData->gl_surface = (void*)QEgl::createSurface(backingX11Pixmap, config);
271
272 if (hasAlpha)
273 pixmapData->flags |= QX11PixmapData::GlSurfaceCreatedWithAlpha;
274 else
275 pixmapData->flags &= ~QX11PixmapData::GlSurfaceCreatedWithAlpha;
276
277 if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE)
278 return NULL;
279 }
280
281 return pixmapData->gl_surface;
282}
283
284void QMeeGoLivePixmapData::destroySurfaceForPixmapData(QPixmapData* pmd)
285{
286 Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
287 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
288 if (pixmapData->gl_surface) {
289 eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface);
290 pixmapData->gl_surface = 0;
291 }
292}
Note: See TracBrowser for help on using the repository browser.