source: trunk/src/opengl/qglpixelbuffer.cpp@ 1054

Last change on this file since 1054 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: 17.2 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 QtOpenGL module 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/*!
43 \class QGLPixelBuffer
44 \brief The QGLPixelBuffer class encapsulates an OpenGL pbuffer.
45 \since 4.1
46
47 \ingroup painting-3D
48
49 Rendering into a pbuffer is normally done using full hardware
50 acceleration. This can be significantly faster than rendering
51 into a QPixmap.
52
53 There are three approaches to using this class:
54
55 \list 1
56 \o \bold{We can draw into the pbuffer and convert it to a QImage
57 using toImage().} This is normally much faster than calling
58 QGLWidget::renderPixmap().
59
60 \o \bold{We can draw into the pbuffer and copy the contents into
61 an OpenGL texture using updateDynamicTexture().} This allows
62 us to create dynamic textures and works on all systems
63 with pbuffer support.
64
65 \o \bold{On systems that support it, we can bind the pbuffer to
66 an OpenGL texture.} The texture is then updated automatically
67 when the pbuffer contents change, eliminating the need for
68 additional copy operations. This is supported only on Windows
69 and Mac OS X systems that provide the \c render_texture
70 extension. Note that under Windows, a multi-sampled pbuffer
71 can't be used in conjunction with the \c render_texture
72 extension. If a multi-sampled pbuffer is requested under
73 Windows, the \c render_texture extension is turned off for that
74 pbuffer.
75
76
77 \endlist
78
79 Pbuffers are provided by the OpenGL \c pbuffer extension; call
80 hasOpenGLPbuffer() to find out if the system provides pbuffers.
81
82 \sa {opengl/pbuffers}{Pbuffers Example}
83*/
84
85#include <QtCore/qglobal.h>
86
87#if !defined(QT_OPENGL_ES_1)
88#include <private/qpaintengineex_opengl2_p.h>
89#endif
90
91#include <qglpixelbuffer.h>
92#include <private/qglpixelbuffer_p.h>
93#include <qimage.h>
94
95#ifndef QT_OPENGL_ES_2
96#include <private/qpaintengine_opengl_p.h>
97#endif
98
99QT_BEGIN_NAMESPACE
100
101#if !defined(QT_OPENGL_ES_2)
102extern void qgl_cleanup_glyph_cache(QGLContext *);
103#else
104void qgl_cleanup_glyph_cache(QGLContext *) {}
105#endif
106
107extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
108
109
110QGLContext* QGLPBufferGLPaintDevice::context() const
111{
112 return pbuf->d_func()->qctx;
113}
114
115void QGLPBufferGLPaintDevice::endPaint() {
116 glFlush();
117 QGLPaintDevice::endPaint();
118}
119
120void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)
121{
122 pbuf = pb;
123}
124
125void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
126{
127 Q_Q(QGLPixelBuffer);
128 if(init(size, format, shareWidget)) {
129 req_size = size;
130 req_format = format;
131 req_shareWidget = shareWidget;
132 invalid = false;
133 qctx = new QGLContext(format);
134 qctx->d_func()->sharing = (shareWidget != 0);
135 if (shareWidget != 0 && shareWidget->d_func()->glcx) {
136 QGLContextGroup::addShare(qctx, shareWidget->d_func()->glcx);
137 shareWidget->d_func()->glcx->d_func()->sharing = true;
138 }
139
140 glDevice.setPBuffer(q);
141 qctx->d_func()->paintDevice = q;
142 qctx->d_func()->valid = true;
143#if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES)
144 qctx->d_func()->dc = dc;
145 qctx->d_func()->rc = ctx;
146#elif (defined(Q_WS_X11) && defined(QT_NO_EGL))
147 qctx->d_func()->cx = ctx;
148 qctx->d_func()->pbuf = (void *) pbuf;
149 qctx->d_func()->vi = 0;
150#elif defined(Q_WS_MAC)
151 qctx->d_func()->cx = ctx;
152 qctx->d_func()->vi = 0;
153#elif !defined(QT_NO_EGL)
154 qctx->d_func()->eglContext = ctx;
155 qctx->d_func()->eglSurface = pbuf;
156#endif
157 }
158}
159
160/*!
161 Constructs an OpenGL pbuffer of the given \a size. If no \a
162 format is specified, the \l{QGLFormat::defaultFormat()}{default
163 format} is used. If the \a shareWidget parameter points to a
164 valid QGLWidget, the pbuffer will share its context with \a
165 shareWidget.
166
167 If you intend to bind this pbuffer as a dynamic texture, the width
168 and height components of \c size must be powers of two (e.g., 512
169 x 128).
170
171 \sa size(), format()
172*/
173QGLPixelBuffer::QGLPixelBuffer(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
174 : d_ptr(new QGLPixelBufferPrivate(this))
175{
176 Q_D(QGLPixelBuffer);
177 d->common_init(size, format, shareWidget);
178}
179
180
181/*! \overload
182
183 Constructs an OpenGL pbuffer with the \a width and \a height. If
184 no \a format is specified, the
185 \l{QGLFormat::defaultFormat()}{default format} is used. If the \a
186 shareWidget parameter points to a valid QGLWidget, the pbuffer
187 will share its context with \a shareWidget.
188
189 If you intend to bind this pbuffer as a dynamic texture, the width
190 and height components of \c size must be powers of two (e.g., 512
191 x 128).
192
193 \sa size(), format()
194*/
195QGLPixelBuffer::QGLPixelBuffer(int width, int height, const QGLFormat &format, QGLWidget *shareWidget)
196 : d_ptr(new QGLPixelBufferPrivate(this))
197{
198 Q_D(QGLPixelBuffer);
199 d->common_init(QSize(width, height), format, shareWidget);
200}
201
202
203/*! \fn QGLPixelBuffer::~QGLPixelBuffer()
204
205 Destroys the pbuffer and frees any allocated resources.
206*/
207QGLPixelBuffer::~QGLPixelBuffer()
208{
209 Q_D(QGLPixelBuffer);
210
211 // defined in qpaintengine_opengl.cpp
212 QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
213 if (current != d->qctx)
214 makeCurrent();
215 qgl_cleanup_glyph_cache(d->qctx);
216 d->cleanup();
217 delete d->qctx;
218 if (current && current != d->qctx)
219 current->makeCurrent();
220}
221
222/*! \fn bool QGLPixelBuffer::makeCurrent()
223
224 Makes this pbuffer the current OpenGL rendering context. Returns
225 true on success; otherwise returns false.
226
227 \sa QGLContext::makeCurrent(), doneCurrent()
228*/
229
230bool QGLPixelBuffer::makeCurrent()
231{
232 Q_D(QGLPixelBuffer);
233 if (d->invalid)
234 return false;
235 d->qctx->makeCurrent();
236 return true;
237}
238
239/*! \fn bool QGLPixelBuffer::doneCurrent()
240
241 Makes no context the current OpenGL context. Returns true on
242 success; otherwise returns false.
243*/
244
245bool QGLPixelBuffer::doneCurrent()
246{
247 Q_D(QGLPixelBuffer);
248 if (d->invalid)
249 return false;
250 d->qctx->doneCurrent();
251 return true;
252}
253
254/*!
255 Generates and binds a 2D GL texture that is the same size as the
256 pbuffer, and returns the texture's ID. This can be used in
257 conjunction with bindToDynamicTexture() and
258 updateDynamicTexture().
259
260 \sa size()
261*/
262
263#if (defined(Q_WS_X11) || defined(Q_WS_WIN)) && defined(QT_NO_EGL)
264GLuint QGLPixelBuffer::generateDynamicTexture() const
265{
266 Q_D(const QGLPixelBuffer);
267 GLuint texture;
268 glGenTextures(1, &texture);
269 glBindTexture(GL_TEXTURE_2D, texture);
270 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, d->req_size.width(), d->req_size.height(), 0, GL_RGBA, GL_FLOAT, 0);
271 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
272 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
273 return texture;
274}
275#endif
276
277/*! \fn bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
278
279 Binds the texture specified by \a texture_id to this pbuffer.
280 Returns true on success; otherwise returns false.
281
282 The texture must be of the same size and format as the pbuffer.
283
284 To unbind the texture, call releaseFromDynamicTexture(). While
285 the texture is bound, it is updated automatically when the
286 pbuffer contents change, eliminating the need for additional copy
287 operations.
288
289 Example:
290
291 \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 0
292
293 \warning This function uses the \c {render_texture} extension,
294 which is currently not supported under X11. An alternative that
295 works on all systems (including X11) is to manually copy the
296 pbuffer contents to a texture using updateDynamicTexture().
297
298 \warning For the bindToDynamicTexture() call to succeed on the
299 Mac OS X, the pbuffer needs a shared context, i.e. the
300 QGLPixelBuffer must be created with a share widget.
301
302 \sa generateDynamicTexture(), releaseFromDynamicTexture()
303*/
304
305/*! \fn void QGLPixelBuffer::releaseFromDynamicTexture()
306
307 Releases the pbuffer from any previously bound texture.
308
309 \sa bindToDynamicTexture()
310*/
311
312/*! \fn bool QGLPixelBuffer::hasOpenGLPbuffers()
313
314 Returns true if the OpenGL \c pbuffer extension is present on
315 this system; otherwise returns false.
316*/
317
318/*!
319 Copies the pbuffer contents into the texture specified with \a
320 texture_id.
321
322 The texture must be of the same size and format as the pbuffer.
323
324 Example:
325
326 \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 1
327
328 An alternative on Windows and Mac OS X systems that support the
329 \c render_texture extension is to use bindToDynamicTexture() to
330 get dynamic updates of the texture.
331
332 \sa generateDynamicTexture(), bindToDynamicTexture()
333*/
334void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const
335{
336 Q_D(const QGLPixelBuffer);
337 if (d->invalid)
338 return;
339 glBindTexture(GL_TEXTURE_2D, texture_id);
340#ifndef QT_OPENGL_ES
341 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, d->req_size.width(), d->req_size.height(), 0);
342#else
343 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, d->req_size.width(), d->req_size.height(), 0);
344#endif
345}
346
347#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
348void QGLPixelBuffer::updateDynamicTexture(QMacCompatGLuint texture_id) const
349{
350 updateDynamicTexture(GLuint(texture_id));
351}
352#endif
353
354/*!
355 Returns the size of the pbuffer.
356*/
357QSize QGLPixelBuffer::size() const
358{
359 Q_D(const QGLPixelBuffer);
360 return d->req_size;
361}
362
363/*!
364 Returns the contents of the pbuffer as a QImage.
365*/
366QImage QGLPixelBuffer::toImage() const
367{
368 Q_D(const QGLPixelBuffer);
369 if (d->invalid)
370 return QImage();
371
372 const_cast<QGLPixelBuffer *>(this)->makeCurrent();
373 return qt_gl_read_framebuffer(d->req_size, d->format.alpha(), true);
374}
375
376/*!
377 Returns the native pbuffer handle.
378*/
379Qt::HANDLE QGLPixelBuffer::handle() const
380{
381 Q_D(const QGLPixelBuffer);
382 if (d->invalid)
383 return 0;
384 return (Qt::HANDLE) d->pbuf;
385}
386
387/*!
388 Returns true if this pbuffer is valid; otherwise returns false.
389*/
390bool QGLPixelBuffer::isValid() const
391{
392 Q_D(const QGLPixelBuffer);
393 return !d->invalid;
394}
395
396#if !defined(QT_OPENGL_ES_1)
397Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
398#endif
399
400#ifndef QT_OPENGL_ES_2
401Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
402#endif
403
404/*! \reimp */
405QPaintEngine *QGLPixelBuffer::paintEngine() const
406{
407#if defined(QT_OPENGL_ES_1)
408 return qt_buffer_engine();
409#elif defined(QT_OPENGL_ES_2)
410 return qt_buffer_2_engine();
411#else
412 if (qt_gl_preferGL2Engine())
413 return qt_buffer_2_engine();
414 else
415 return qt_buffer_engine();
416#endif
417}
418
419Q_DECL_IMPORT extern int qt_defaultDpiX();
420Q_DECL_IMPORT extern int qt_defaultDpiY();
421
422/*! \reimp */
423int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
424{
425 Q_D(const QGLPixelBuffer);
426
427 float dpmx = qt_defaultDpiX()*100./2.54;
428 float dpmy = qt_defaultDpiY()*100./2.54;
429 int w = d->req_size.width();
430 int h = d->req_size.height();
431 switch (metric) {
432 case PdmWidth:
433 return w;
434
435 case PdmHeight:
436 return h;
437
438 case PdmWidthMM:
439 return qRound(w * 1000 / dpmx);
440
441 case PdmHeightMM:
442 return qRound(h * 1000 / dpmy);
443
444 case PdmNumColors:
445 return 0;
446
447 case PdmDepth:
448 return 32;//d->depth;
449
450 case PdmDpiX:
451 return qRound(dpmx * 0.0254);
452
453 case PdmDpiY:
454 return qRound(dpmy * 0.0254);
455
456 case PdmPhysicalDpiX:
457 return qRound(dpmx * 0.0254);
458
459 case PdmPhysicalDpiY:
460 return qRound(dpmy * 0.0254);
461
462 default:
463 qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric);
464 break;
465 }
466 return 0;
467}
468
469/*!
470 Generates and binds a 2D GL texture to the current context, based
471 on \a image. The generated texture id is returned and can be used
472 in later glBindTexture() calls.
473
474 The \a target parameter specifies the texture target.
475
476 Equivalent to calling QGLContext::bindTexture().
477
478 \sa deleteTexture()
479*/
480GLuint QGLPixelBuffer::bindTexture(const QImage &image, GLenum target)
481{
482 Q_D(QGLPixelBuffer);
483#ifndef QT_OPENGL_ES
484 return d->qctx->bindTexture(image, target, GLint(GL_RGBA8));
485#else
486 return d->qctx->bindTexture(image, target, GL_RGBA);
487#endif
488}
489
490#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
491/*! \internal */
492GLuint QGLPixelBuffer::bindTexture(const QImage &image, QMacCompatGLenum target)
493{
494 Q_D(QGLPixelBuffer);
495 return d->qctx->bindTexture(image, target, QMacCompatGLint(GL_RGBA8));
496}
497#endif
498
499/*! \overload
500
501 Generates and binds a 2D GL texture based on \a pixmap.
502
503 Equivalent to calling QGLContext::bindTexture().
504
505 \sa deleteTexture()
506*/
507GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, GLenum target)
508{
509 Q_D(QGLPixelBuffer);
510#ifndef QT_OPENGL_ES
511 return d->qctx->bindTexture(pixmap, target, GLint(GL_RGBA8));
512#else
513 return d->qctx->bindTexture(pixmap, target, GL_RGBA);
514#endif
515}
516
517#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
518/*! \internal */
519GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target)
520{
521 Q_D(QGLPixelBuffer);
522 return d->qctx->bindTexture(pixmap, target, QMacCompatGLint(GL_RGBA8));
523}
524#endif
525
526/*! \overload
527
528 Reads the DirectDrawSurface (DDS) compressed file \a fileName and
529 generates a 2D GL texture from it.
530
531 Equivalent to calling QGLContext::bindTexture().
532
533 \sa deleteTexture()
534*/
535GLuint QGLPixelBuffer::bindTexture(const QString &fileName)
536{
537 Q_D(QGLPixelBuffer);
538 return d->qctx->bindTexture(fileName);
539}
540
541/*!
542 Removes the texture identified by \a texture_id from the texture cache.
543
544 Equivalent to calling QGLContext::deleteTexture().
545 */
546void QGLPixelBuffer::deleteTexture(GLuint texture_id)
547{
548 Q_D(QGLPixelBuffer);
549 d->qctx->deleteTexture(texture_id);
550}
551
552#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
553/*! \internal */
554void QGLPixelBuffer::deleteTexture(QMacCompatGLuint texture_id)
555{
556 Q_D(QGLPixelBuffer);
557 d->qctx->deleteTexture(texture_id);
558}
559#endif
560
561/*!
562 \since 4.4
563
564 Draws the given texture, \a textureId, to the given target rectangle,
565 \a target, in OpenGL model space. The \a textureTarget should be a 2D
566 texture target.
567
568 Equivalent to the corresponding QGLContext::drawTexture().
569*/
570void QGLPixelBuffer::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
571{
572 Q_D(QGLPixelBuffer);
573 d->qctx->drawTexture(target, textureId, textureTarget);
574}
575
576#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
577/*! \internal */
578void QGLPixelBuffer::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
579{
580 Q_D(QGLPixelBuffer);
581 d->qctx->drawTexture(target, textureId, textureTarget);
582}
583#endif
584
585/*!
586 \since 4.4
587
588 Draws the given texture, \a textureId, at the given \a point in OpenGL model
589 space. The textureTarget parameter should be a 2D texture target.
590
591 Equivalent to the corresponding QGLContext::drawTexture().
592*/
593void QGLPixelBuffer::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
594{
595 Q_D(QGLPixelBuffer);
596 d->qctx->drawTexture(point, textureId, textureTarget);
597}
598
599#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
600/*! \internal */
601void QGLPixelBuffer::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
602{
603 Q_D(QGLPixelBuffer);
604 d->qctx->drawTexture(point, textureId, textureTarget);
605}
606#endif
607
608/*!
609 Returns the format of the pbuffer. The format may be different
610 from the one that was requested.
611*/
612QGLFormat QGLPixelBuffer::format() const
613{
614 Q_D(const QGLPixelBuffer);
615 return d->format;
616}
617
618/*! \fn int QGLPixelBuffer::devType() const
619 \internal
620*/
621
622QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.