0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 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 QtOpenGL module 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 "qgl.h"
|
|
43 |
#include <private/qt_x11_p.h>
|
|
44 |
#include <private/qpixmap_x11_p.h>
|
|
45 |
#include <private/qgl_p.h>
|
|
46 |
#include <private/qpaintengine_opengl_p.h>
|
|
47 |
#include "qgl_egl_p.h"
|
|
48 |
#include "qcolormap.h"
|
|
49 |
#include <QDebug>
|
|
50 |
|
|
51 |
|
|
52 |
QT_BEGIN_NAMESPACE
|
|
53 |
|
|
54 |
bool QGLFormat::hasOpenGLOverlays()
|
|
55 |
{
|
|
56 |
return false;
|
|
57 |
}
|
|
58 |
|
|
59 |
void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
|
|
60 |
{
|
|
61 |
if (device->devType() == QInternal::Image)
|
|
62 |
props.setPixelFormat(static_cast<QImage *>(device)->format());
|
|
63 |
}
|
|
64 |
|
|
65 |
bool QGLContext::chooseContext(const QGLContext* shareContext)
|
|
66 |
{
|
|
67 |
Q_D(QGLContext);
|
|
68 |
|
|
69 |
if (!device())
|
|
70 |
return false;
|
|
71 |
|
|
72 |
int devType = device()->devType();
|
|
73 |
|
|
74 |
// Get the display and initialize it.
|
|
75 |
d->eglContext = new QEglContext();
|
|
76 |
d->eglContext->setApi(QEgl::OpenGL);
|
|
77 |
if (!d->eglContext->openDisplay(device())) {
|
|
78 |
delete d->eglContext;
|
|
79 |
d->eglContext = 0;
|
|
80 |
return false;
|
|
81 |
}
|
|
82 |
|
|
83 |
// Construct the configuration we need for this surface.
|
|
84 |
QEglProperties configProps;
|
|
85 |
qt_egl_set_format(configProps, devType, d->glFormat);
|
|
86 |
qt_egl_add_platform_config(configProps, device());
|
|
87 |
configProps.setRenderableType(QEgl::OpenGL);
|
|
88 |
|
|
89 |
QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat;
|
|
90 |
if (device()->depth() == 16) {
|
|
91 |
configProps.setValue(EGL_RED_SIZE, 5);
|
|
92 |
configProps.setValue(EGL_GREEN_SIZE, 6);
|
|
93 |
configProps.setValue(EGL_BLUE_SIZE, 5);
|
|
94 |
configProps.setValue(EGL_ALPHA_SIZE, 0);
|
|
95 |
matchType = QEgl::ExactPixelFormat;
|
|
96 |
}
|
|
97 |
configProps.setRenderableType(QEgl::OpenGL);
|
|
98 |
|
|
99 |
// Search for a matching configuration, reducing the complexity
|
|
100 |
// each time until we get something that matches.
|
|
101 |
if (!d->eglContext->chooseConfig(configProps, matchType)) {
|
|
102 |
delete d->eglContext;
|
|
103 |
d->eglContext = 0;
|
|
104 |
return false;
|
|
105 |
}
|
|
106 |
|
|
107 |
// Inform the higher layers about the actual format properties.
|
|
108 |
qt_egl_update_format(*(d->eglContext), d->glFormat);
|
|
109 |
|
|
110 |
// Create a new context for the configuration.
|
|
111 |
if (!d->eglContext->createContext
|
|
112 |
(shareContext ? shareContext->d_func()->eglContext : 0)) {
|
|
113 |
delete d->eglContext;
|
|
114 |
d->eglContext = 0;
|
|
115 |
return false;
|
|
116 |
}
|
|
117 |
|
|
118 |
#if defined(EGL_VERSION_1_1)
|
|
119 |
if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
|
|
120 |
eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
|
|
121 |
#endif
|
|
122 |
|
|
123 |
return true;
|
|
124 |
}
|
|
125 |
|
|
126 |
void QGLWidget::resizeEvent(QResizeEvent *)
|
|
127 |
{
|
|
128 |
Q_D(QGLWidget);
|
|
129 |
if (!isValid())
|
|
130 |
return;
|
|
131 |
makeCurrent();
|
|
132 |
if (!d->glcx->initialized())
|
|
133 |
glInit();
|
|
134 |
resizeGL(width(), height());
|
|
135 |
//handle overlay
|
|
136 |
}
|
|
137 |
|
|
138 |
const QGLContext* QGLWidget::overlayContext() const
|
|
139 |
{
|
|
140 |
return 0;
|
|
141 |
}
|
|
142 |
|
|
143 |
void QGLWidget::makeOverlayCurrent()
|
|
144 |
{
|
|
145 |
//handle overlay
|
|
146 |
}
|
|
147 |
|
|
148 |
void QGLWidget::updateOverlayGL()
|
|
149 |
{
|
|
150 |
//handle overlay
|
|
151 |
}
|
|
152 |
|
|
153 |
bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual)
|
|
154 |
{
|
|
155 |
bool foundVisualIsArgb = useArgbVisual;
|
|
156 |
|
|
157 |
memset(&vi, 0, sizeof(XVisualInfo));
|
|
158 |
|
|
159 |
// Check to see if EGL is suggesting an appropriate visual id:
|
|
160 |
EGLint nativeVisualId;
|
|
161 |
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId);
|
|
162 |
vi.visualid = nativeVisualId;
|
|
163 |
|
|
164 |
if (vi.visualid) {
|
|
165 |
// EGL has suggested a visual id, so get the rest of the visual info for that id:
|
|
166 |
XVisualInfo *chosenVisualInfo;
|
|
167 |
int matchingCount = 0;
|
|
168 |
chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount);
|
|
169 |
if (chosenVisualInfo) {
|
|
170 |
#if !defined(QT_NO_XRENDER)
|
|
171 |
if (useArgbVisual) {
|
|
172 |
// Check to make sure the visual provided by EGL is ARGB
|
|
173 |
XRenderPictFormat *format;
|
|
174 |
format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual);
|
|
175 |
if (format->type == PictTypeDirect && format->direct.alphaMask) {
|
|
176 |
// qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid);
|
|
177 |
foundVisualIsArgb = true;
|
|
178 |
vi = *chosenVisualInfo;
|
|
179 |
}
|
|
180 |
else {
|
|
181 |
qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB",
|
|
182 |
nativeVisualId, (int)config);
|
|
183 |
vi.visualid = 0;
|
|
184 |
}
|
|
185 |
} else
|
|
186 |
#endif
|
|
187 |
{
|
|
188 |
// qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
|
|
189 |
vi = *chosenVisualInfo;
|
|
190 |
}
|
|
191 |
XFree(chosenVisualInfo);
|
|
192 |
}
|
|
193 |
else {
|
|
194 |
qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
|
|
195 |
nativeVisualId, (int)config);
|
|
196 |
vi.visualid = 0;
|
|
197 |
}
|
|
198 |
}
|
|
199 |
|
|
200 |
// If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
|
|
201 |
// using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
|
|
202 |
|
|
203 |
#if !defined(QT_NO_XRENDER)
|
|
204 |
if (vi.visualid == 0 && useArgbVisual) {
|
|
205 |
// Try to use XRender to find an ARGB visual we can use
|
|
206 |
vi.screen = x11Info.screen();
|
|
207 |
vi.depth = 32; //### We might at some point (soon) get ARGB4444
|
|
208 |
vi.c_class = TrueColor;
|
|
209 |
XVisualInfo *matchingVisuals;
|
|
210 |
int matchingCount = 0;
|
|
211 |
matchingVisuals = XGetVisualInfo(x11Info.display(),
|
|
212 |
VisualScreenMask|VisualDepthMask|VisualClassMask,
|
|
213 |
&vi, &matchingCount);
|
|
214 |
|
|
215 |
for (int i = 0; i < matchingCount; ++i) {
|
|
216 |
XRenderPictFormat *format;
|
|
217 |
format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual);
|
|
218 |
if (format->type == PictTypeDirect && format->direct.alphaMask) {
|
|
219 |
vi = matchingVisuals[i];
|
|
220 |
foundVisualIsArgb = true;
|
|
221 |
// qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);
|
|
222 |
break;
|
|
223 |
}
|
|
224 |
}
|
|
225 |
XFree(matchingVisuals);
|
|
226 |
}
|
|
227 |
#endif
|
|
228 |
|
|
229 |
if (vi.visualid == 0) {
|
|
230 |
EGLint depth;
|
|
231 |
eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);
|
|
232 |
int err;
|
|
233 |
err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
|
|
234 |
if (err == 0) {
|
|
235 |
qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",
|
|
236 |
(int)config, depth);
|
|
237 |
depth = x11Info.depth();
|
|
238 |
err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
|
|
239 |
if (err == 0) {
|
|
240 |
qWarning("Error: Couldn't get any matching X visual!");
|
|
241 |
return false;
|
|
242 |
} else
|
|
243 |
qWarning(" - Falling back to X11 suggested depth (%d)", depth);
|
|
244 |
}
|
|
245 |
// else
|
|
246 |
// qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);
|
|
247 |
|
|
248 |
// Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(
|
|
249 |
if (useArgbVisual)
|
|
250 |
foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444
|
|
251 |
}
|
|
252 |
|
|
253 |
// qDebug("Visual Info:");
|
|
254 |
// qDebug(" bits_per_rgb=%d", vi.bits_per_rgb);
|
|
255 |
// qDebug(" red_mask=0x%x", vi.red_mask);
|
|
256 |
// qDebug(" green_mask=0x%x", vi.green_mask);
|
|
257 |
// qDebug(" blue_mask=0x%x", vi.blue_mask);
|
|
258 |
// qDebug(" colormap_size=%d", vi.colormap_size);
|
|
259 |
// qDebug(" c_class=%d", vi.c_class);
|
|
260 |
// qDebug(" depth=%d", vi.depth);
|
|
261 |
// qDebug(" screen=%d", vi.screen);
|
|
262 |
// qDebug(" visualid=%d", vi.visualid);
|
|
263 |
return foundVisualIsArgb;
|
|
264 |
}
|
|
265 |
|
|
266 |
void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
|
|
267 |
{
|
|
268 |
Q_D(QGLWidget);
|
|
269 |
if (context == 0) {
|
|
270 |
qWarning("QGLWidget::setContext: Cannot set null context");
|
|
271 |
return;
|
|
272 |
}
|
|
273 |
if (!context->deviceIsPixmap() && context->device() != this) {
|
|
274 |
qWarning("QGLWidget::setContext: Context must refer to this widget");
|
|
275 |
return;
|
|
276 |
}
|
|
277 |
|
|
278 |
if (d->glcx)
|
|
279 |
d->glcx->doneCurrent();
|
|
280 |
QGLContext* oldcx = d->glcx;
|
|
281 |
d->glcx = context;
|
|
282 |
|
|
283 |
if (parentWidget()) {
|
|
284 |
// force creation of delay-created widgets
|
|
285 |
parentWidget()->winId();
|
|
286 |
if (parentWidget()->x11Info().screen() != x11Info().screen())
|
|
287 |
d_func()->xinfo = parentWidget()->d_func()->xinfo;
|
|
288 |
}
|
|
289 |
|
|
290 |
// If the application has set WA_TranslucentBackground and not explicitly set
|
|
291 |
// the alpha buffer size to zero, modify the format so it have an alpha channel
|
|
292 |
QGLFormat& fmt = d->glcx->d_func()->glFormat;
|
|
293 |
const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground);
|
|
294 |
if (tryArgbVisual && fmt.alphaBufferSize() == -1)
|
|
295 |
fmt.setAlphaBufferSize(1);
|
|
296 |
|
|
297 |
bool createFailed = false;
|
|
298 |
if (!d->glcx->isValid()) {
|
|
299 |
if (!d->glcx->create(shareContext ? shareContext : oldcx))
|
|
300 |
createFailed = true;
|
|
301 |
}
|
|
302 |
if (createFailed) {
|
|
303 |
if (deleteOldContext)
|
|
304 |
delete oldcx;
|
|
305 |
return;
|
|
306 |
}
|
|
307 |
|
|
308 |
if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
|
|
309 |
if (deleteOldContext)
|
|
310 |
delete oldcx;
|
|
311 |
return;
|
|
312 |
}
|
|
313 |
|
|
314 |
bool visible = isVisible();
|
|
315 |
if (visible)
|
|
316 |
hide();
|
|
317 |
|
|
318 |
XVisualInfo vi;
|
|
319 |
QEglContext *eglContext = d->glcx->d_func()->eglContext;
|
|
320 |
bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(),
|
|
321 |
x11Info(), tryArgbVisual);
|
|
322 |
|
|
323 |
XSetWindowAttributes a;
|
|
324 |
|
|
325 |
Window p = RootWindow(x11Info().display(), x11Info().screen());
|
|
326 |
if (parentWidget())
|
|
327 |
p = parentWidget()->winId();
|
|
328 |
|
|
329 |
QColormap colmap = QColormap::instance(vi.screen);
|
|
330 |
a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
|
|
331 |
a.border_pixel = colmap.pixel(Qt::black);
|
|
332 |
|
|
333 |
unsigned int valueMask = CWBackPixel|CWBorderPixel;
|
|
334 |
if (usingArgbVisual) {
|
|
335 |
a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone);
|
|
336 |
valueMask |= CWColormap;
|
|
337 |
}
|
|
338 |
|
|
339 |
Window w = XCreateWindow(x11Info().display(), p, x(), y(), width(), height(),
|
|
340 |
0, vi.depth, InputOutput, vi.visual, valueMask, &a);
|
|
341 |
|
|
342 |
if (deleteOldContext)
|
|
343 |
delete oldcx;
|
|
344 |
oldcx = 0;
|
|
345 |
|
|
346 |
create(w); // Create with the ID of the window we've just created
|
|
347 |
|
|
348 |
|
|
349 |
// Create the EGL surface to draw into.
|
|
350 |
QGLContextPrivate *ctxpriv = d->glcx->d_func();
|
|
351 |
ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(this);
|
|
352 |
if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
|
|
353 |
delete ctxpriv->eglContext;
|
|
354 |
ctxpriv->eglContext = 0;
|
|
355 |
return;
|
|
356 |
}
|
|
357 |
|
|
358 |
d->eglSurfaceWindowId = w; // Remember the window id we created the surface for
|
|
359 |
|
|
360 |
if (visible)
|
|
361 |
show();
|
|
362 |
|
|
363 |
XFlush(X11->display);
|
|
364 |
d->glcx->setWindowCreated(true);
|
|
365 |
}
|
|
366 |
|
|
367 |
void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
|
|
368 |
{
|
|
369 |
Q_Q(QGLWidget);
|
|
370 |
|
|
371 |
initContext(context, shareWidget);
|
|
372 |
|
|
373 |
if(q->isValid() && glcx->format().hasOverlay()) {
|
|
374 |
//no overlay
|
|
375 |
qWarning("QtOpenGL ES doesn't currently support overlays");
|
|
376 |
}
|
|
377 |
}
|
|
378 |
|
|
379 |
void QGLWidgetPrivate::cleanupColormaps()
|
|
380 |
{
|
|
381 |
}
|
|
382 |
|
|
383 |
const QGLColormap & QGLWidget::colormap() const
|
|
384 |
{
|
|
385 |
return d_func()->cmap;
|
|
386 |
}
|
|
387 |
|
|
388 |
void QGLWidget::setColormap(const QGLColormap &)
|
|
389 |
{
|
|
390 |
}
|
|
391 |
|
|
392 |
void QGLExtensions::init()
|
|
393 |
{
|
|
394 |
static bool init_done = false;
|
|
395 |
|
|
396 |
if (init_done)
|
|
397 |
return;
|
|
398 |
init_done = true;
|
|
399 |
|
|
400 |
// We need a context current to initialize the extensions.
|
|
401 |
QGLWidget tmpWidget;
|
|
402 |
tmpWidget.makeCurrent();
|
|
403 |
|
|
404 |
init_extensions();
|
|
405 |
|
|
406 |
tmpWidget.doneCurrent();
|
|
407 |
}
|
|
408 |
|
|
409 |
// Re-creates the EGL surface if the window ID has changed or if force is true
|
|
410 |
void QGLWidgetPrivate::recreateEglSurface(bool force)
|
|
411 |
{
|
|
412 |
Q_Q(QGLWidget);
|
|
413 |
|
|
414 |
Window currentId = q->winId();
|
|
415 |
|
|
416 |
if ( force || (currentId != eglSurfaceWindowId) ) {
|
|
417 |
// The window id has changed so we need to re-create the EGL surface
|
|
418 |
QEglContext *ctx = glcx->d_func()->eglContext;
|
|
419 |
EGLSurface surface = glcx->d_func()->eglSurface;
|
|
420 |
if (surface != EGL_NO_SURFACE)
|
|
421 |
ctx->destroySurface(surface); // Will force doneCurrent() if nec.
|
|
422 |
surface = ctx->createSurface(q);
|
|
423 |
if (surface == EGL_NO_SURFACE)
|
|
424 |
qWarning("Error creating EGL window surface: 0x%x", eglGetError());
|
|
425 |
glcx->d_func()->eglSurface = surface;
|
|
426 |
|
|
427 |
eglSurfaceWindowId = currentId;
|
|
428 |
}
|
|
429 |
}
|
|
430 |
|
|
431 |
// Selects which configs should be used
|
|
432 |
EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly)
|
|
433 |
{
|
|
434 |
// Cache the configs we select as they wont change:
|
|
435 |
static EGLConfig roPixmapRGBConfig = 0;
|
|
436 |
static EGLConfig roPixmapRGBAConfig = 0;
|
|
437 |
static EGLConfig rwPixmapRGBConfig = 0;
|
|
438 |
static EGLConfig rwPixmapRGBAConfig = 0;
|
|
439 |
|
|
440 |
EGLConfig* targetConfig;
|
|
441 |
|
|
442 |
if (hasAlpha) {
|
|
443 |
if (readOnly)
|
|
444 |
targetConfig = &roPixmapRGBAConfig;
|
|
445 |
else
|
|
446 |
targetConfig = &rwPixmapRGBAConfig;
|
|
447 |
}
|
|
448 |
else {
|
|
449 |
if (readOnly)
|
|
450 |
targetConfig = &roPixmapRGBConfig;
|
|
451 |
else
|
|
452 |
targetConfig = &rwPixmapRGBConfig;
|
|
453 |
}
|
|
454 |
|
|
455 |
if (*targetConfig == 0) {
|
|
456 |
QEglProperties configAttribs;
|
|
457 |
configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT);
|
|
458 |
configAttribs.setRenderableType(QEgl::OpenGL);
|
|
459 |
if (hasAlpha)
|
|
460 |
configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
|
|
461 |
else
|
|
462 |
configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
|
|
463 |
|
|
464 |
// If this is going to be a render target, it needs to have a depth, stencil & sample buffer
|
|
465 |
if (!readOnly) {
|
|
466 |
configAttribs.setValue(EGL_DEPTH_SIZE, 1);
|
|
467 |
configAttribs.setValue(EGL_STENCIL_SIZE, 1);
|
|
468 |
configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1);
|
|
469 |
}
|
|
470 |
|
|
471 |
EGLint configCount = 0;
|
|
472 |
do {
|
|
473 |
eglChooseConfig(QEglContext::defaultDisplay(0), configAttribs.properties(), targetConfig, 1, &configCount);
|
|
474 |
if (configCount > 0) {
|
|
475 |
// Got one
|
|
476 |
qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" )
|
|
477 |
<< "config (" << int(*targetConfig) << ") to create a pixmap surface:";
|
|
478 |
|
|
479 |
// QEglProperties configProps(*targetConfig);
|
|
480 |
// qDebug() << configProps.toString();
|
|
481 |
break;
|
|
482 |
}
|
|
483 |
qWarning("choosePixmapConfig() - No suitible config found, reducing requirements");
|
|
484 |
} while (configAttribs.reduceConfiguration());
|
|
485 |
}
|
|
486 |
|
|
487 |
if (*targetConfig == 0)
|
|
488 |
qWarning("choosePixmapConfig() - Couldn't find a suitable config");
|
|
489 |
|
|
490 |
return *targetConfig;
|
|
491 |
}
|
|
492 |
|
|
493 |
bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly)
|
|
494 |
{
|
|
495 |
Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
|
|
496 |
QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd);
|
|
497 |
|
|
498 |
bool hasAlpha = pixmapData->hasAlphaChannel();
|
|
499 |
|
|
500 |
EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly);
|
|
501 |
|
|
502 |
QEglProperties pixmapAttribs;
|
|
503 |
|
|
504 |
// If the pixmap can't be bound to a texture, it's pretty useless
|
|
505 |
pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
|
|
506 |
if (hasAlpha)
|
|
507 |
pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
|
|
508 |
else
|
|
509 |
pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
|
|
510 |
|
|
511 |
EGLSurface pixmapSurface;
|
|
512 |
pixmapSurface = eglCreatePixmapSurface(QEglContext::defaultDisplay(0),
|
|
513 |
pixmapConfig,
|
|
514 |
(EGLNativePixmapType) pixmapData->handle(),
|
|
515 |
pixmapAttribs.properties());
|
|
516 |
// qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x",
|
|
517 |
// pixmapSurface, pixmapData->handle());
|
|
518 |
if (pixmapSurface == EGL_NO_SURFACE) {
|
|
519 |
qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig
|
|
520 |
<< ":" << QEglContext::errorString(eglGetError());
|
|
521 |
return false;
|
|
522 |
}
|
|
523 |
|
|
524 |
static bool doneOnce = false;
|
|
525 |
if (!doneOnce) {
|
|
526 |
// Make sure QGLTextureCache is instanciated so it can install cleanup hooks
|
|
527 |
// which cleanup the EGL surface.
|
|
528 |
QGLTextureCache::instance();
|
|
529 |
doneOnce = true;
|
|
530 |
}
|
|
531 |
|
|
532 |
Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
|
|
533 |
pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
|
|
534 |
pixmapData->is_cached = true; // Make sure the cleanup hook gets called
|
|
535 |
|
|
536 |
return true;
|
|
537 |
}
|
|
538 |
|
|
539 |
|
|
540 |
QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key,
|
|
541 |
QGLContext::BindOptions options)
|
|
542 |
{
|
|
543 |
Q_Q(QGLContext);
|
|
544 |
|
|
545 |
// The EGL texture_from_pixmap has no facility to invert the y coordinate
|
|
546 |
if (!(options & QGLContext::CanFlipNativePixmapBindOption))
|
|
547 |
return 0;
|
|
548 |
|
|
549 |
Q_ASSERT(pd->classId() == QPixmapData::X11Class);
|
|
550 |
|
|
551 |
static bool checkedForTFP = false;
|
|
552 |
static bool haveTFP = false;
|
|
553 |
|
|
554 |
if (!checkedForTFP) {
|
|
555 |
// Check for texture_from_pixmap egl extension
|
|
556 |
checkedForTFP = true;
|
|
557 |
if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
|
|
558 |
eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
|
|
559 |
{
|
|
560 |
qDebug("Found texture_from_pixmap EGL extension!");
|
|
561 |
haveTFP = true;
|
|
562 |
}
|
|
563 |
}
|
|
564 |
|
|
565 |
if (!haveTFP)
|
|
566 |
return 0;
|
|
567 |
|
|
568 |
QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
|
|
569 |
|
|
570 |
bool hasAlpha = pixmapData->hasAlphaChannel();
|
|
571 |
|
|
572 |
// Check to see if the surface is still valid
|
|
573 |
if (pixmapData->gl_surface &&
|
|
574 |
hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
|
|
575 |
{
|
|
576 |
// Surface is invalid!
|
|
577 |
destroyGlSurfaceForPixmap(pixmapData);
|
|
578 |
}
|
|
579 |
|
|
580 |
if (pixmapData->gl_surface == 0) {
|
|
581 |
bool success = qt_createEGLSurfaceForPixmap(pixmapData, true);
|
|
582 |
if (!success) {
|
|
583 |
haveTFP = false;
|
|
584 |
return 0;
|
|
585 |
}
|
|
586 |
}
|
|
587 |
|
|
588 |
Q_ASSERT(pixmapData->gl_surface);
|
|
589 |
|
|
590 |
GLuint textureId;
|
|
591 |
glGenTextures(1, &textureId);
|
|
592 |
glEnable(GL_TEXTURE_2D);
|
|
593 |
glBindTexture(GL_TEXTURE_2D, textureId);
|
|
594 |
|
|
595 |
// bind the egl pixmap surface to a texture
|
|
596 |
EGLBoolean success;
|
|
597 |
success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
|
|
598 |
if (success == EGL_FALSE) {
|
|
599 |
qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
|
|
600 |
eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
|
|
601 |
pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
|
|
602 |
haveTFP = false;
|
|
603 |
return 0;
|
|
604 |
}
|
|
605 |
|
|
606 |
QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
|
|
607 |
pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
|
|
608 |
|
|
609 |
// We assume the cost of bound pixmaps is zero
|
|
610 |
QGLTextureCache::instance()->insert(q, key, texture, 0);
|
|
611 |
|
|
612 |
glBindTexture(GL_TEXTURE_2D, textureId);
|
|
613 |
return texture;
|
|
614 |
}
|
|
615 |
|
|
616 |
void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
|
|
617 |
{
|
|
618 |
Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
|
|
619 |
QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
|
|
620 |
if (pixmapData->gl_surface) {
|
|
621 |
EGLBoolean success;
|
|
622 |
success = eglDestroySurface(QEglContext::defaultDisplay(0), (EGLSurface)pixmapData->gl_surface);
|
|
623 |
if (success == EGL_FALSE) {
|
|
624 |
qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
|
|
625 |
<< QEglContext::errorString(eglGetError());
|
|
626 |
}
|
|
627 |
pixmapData->gl_surface = 0;
|
|
628 |
}
|
|
629 |
}
|
|
630 |
|
|
631 |
void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
|
|
632 |
{
|
|
633 |
Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
|
|
634 |
QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
|
|
635 |
if (pixmapData->gl_surface) {
|
|
636 |
EGLBoolean success;
|
|
637 |
success = eglReleaseTexImage(QEglContext::defaultDisplay(0),
|
|
638 |
(EGLSurface)pixmapData->gl_surface,
|
|
639 |
EGL_BACK_BUFFER);
|
|
640 |
if (success == EGL_FALSE) {
|
|
641 |
qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
|
|
642 |
<< QEglContext::errorString(eglGetError());
|
|
643 |
}
|
|
644 |
}
|
|
645 |
}
|
|
646 |
|
|
647 |
QT_END_NAMESPACE
|