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

Last change on this file since 99 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 16.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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 multimedia
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.
71 \endlist
72
73 Pbuffers are provided by the OpenGL \c pbuffer extension; call
74 hasOpenGLPbuffer() to find out if the system provides pbuffers.
75
76 \sa {opengl/pbuffers}{Pbuffers Example}
77*/
78
79
80#include <qglpixelbuffer.h>
81#include <private/qglpixelbuffer_p.h>
82#include <qimage.h>
83
84#if !defined(QT_OPENGL_ES_2)
85#include <private/qpaintengine_opengl_p.h>
86#endif
87
88QT_BEGIN_NAMESPACE
89
90#if !defined(QT_OPENGL_ES_2)
91extern void qgl_cleanup_glyph_cache(QGLContext *);
92#else
93void qgl_cleanup_glyph_cache(QGLContext *) {}
94#endif
95
96extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
97
98void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
99{
100 Q_Q(QGLPixelBuffer);
101 if(init(size, format, shareWidget)) {
102 req_size = size;
103 req_format = format;
104 req_shareWidget = shareWidget;
105 invalid = false;
106 qctx = new QGLContext(format);
107 qctx->d_func()->sharing = (shareWidget != 0);
108 if (shareWidget != 0 && shareWidget->d_func()->glcx)
109 qgl_share_reg()->addShare(qctx, shareWidget->d_func()->glcx);
110
111 qctx->d_func()->paintDevice = q;
112 qctx->d_func()->valid = true;
113#if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES)
114 qctx->d_func()->dc = dc;
115 qctx->d_func()->rc = ctx;
116#elif (defined(Q_WS_X11) && !defined(QT_OPENGL_ES))
117 qctx->d_func()->cx = ctx;
118 qctx->d_func()->pbuf = (void *) pbuf;
119 qctx->d_func()->vi = 0;
120#elif defined(Q_WS_MAC)
121 qctx->d_func()->cx = ctx;
122 qctx->d_func()->vi = 0;
123#elif defined(QT_OPENGL_ES)
124 qctx->d_func()->eglContext = ctx;
125#endif
126 }
127}
128
129/*!
130 Constructs an OpenGL pbuffer of the given \a size. If no \a
131 format is specified, the \l{QGLFormat::defaultFormat()}{default
132 format} is used. If the \a shareWidget parameter points to a
133 valid QGLWidget, the pbuffer will share its context with \a
134 shareWidget.
135
136 If you intend to bind this pbuffer as a dynamic texture, the width
137 and height components of \c size must be powers of two (e.g., 512
138 x 128).
139
140 \sa size(), format()
141*/
142QGLPixelBuffer::QGLPixelBuffer(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
143 : d_ptr(new QGLPixelBufferPrivate(this))
144{
145 Q_D(QGLPixelBuffer);
146 d->common_init(size, format, shareWidget);
147}
148
149
150/*! \overload
151
152 Constructs an OpenGL pbuffer with the \a width and \a height. If
153 no \a format is specified, the
154 \l{QGLFormat::defaultFormat()}{default format} is used. If the \a
155 shareWidget parameter points to a valid QGLWidget, the pbuffer
156 will share its context with \a shareWidget.
157
158 If you intend to bind this pbuffer as a dynamic texture, the width
159 and height components of \c size must be powers of two (e.g., 512
160 x 128).
161
162 \sa size(), format()
163*/
164QGLPixelBuffer::QGLPixelBuffer(int width, int height, const QGLFormat &format, QGLWidget *shareWidget)
165 : d_ptr(new QGLPixelBufferPrivate(this))
166{
167 Q_D(QGLPixelBuffer);
168 d->common_init(QSize(width, height), format, shareWidget);
169}
170
171
172/*! \fn QGLPixelBuffer::~QGLPixelBuffer()
173
174 Destroys the pbuffer and frees any allocated resources.
175*/
176QGLPixelBuffer::~QGLPixelBuffer()
177{
178 Q_D(QGLPixelBuffer);
179
180 // defined in qpaintengine_opengl.cpp
181 QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
182 if (current != d->qctx)
183 makeCurrent();
184 qgl_cleanup_glyph_cache(d->qctx);
185 d->cleanup();
186 delete d->qctx;
187 if (current && current != d->qctx)
188 current->makeCurrent();
189 delete d_ptr;
190}
191
192/*! \fn bool QGLPixelBuffer::makeCurrent()
193
194 Makes this pbuffer the current OpenGL rendering context. Returns
195 true on success; otherwise returns false.
196
197 \sa QGLContext::makeCurrent(), doneCurrent()
198*/
199
200bool QGLPixelBuffer::makeCurrent()
201{
202 Q_D(QGLPixelBuffer);
203 if (d->invalid)
204 return false;
205 d->qctx->makeCurrent();
206 return true;
207}
208
209/*! \fn bool QGLPixelBuffer::doneCurrent()
210
211 Makes no context the current OpenGL context. Returns true on
212 success; otherwise returns false.
213*/
214
215bool QGLPixelBuffer::doneCurrent()
216{
217 Q_D(QGLPixelBuffer);
218 if (d->invalid)
219 return false;
220 d->qctx->doneCurrent();
221 return true;
222}
223
224/*!
225 Generates and binds a 2D GL texture that is the same size as the
226 pbuffer, and returns the texture's ID. This can be used in
227 conjunction with bindToDynamicTexture() and
228 updateDynamicTexture().
229
230 \sa size()
231*/
232
233#if (defined(Q_WS_X11) || defined(Q_WS_WIN)) && !defined(QT_OPENGL_ES)
234GLuint QGLPixelBuffer::generateDynamicTexture() const
235{
236 Q_D(const QGLPixelBuffer);
237 GLuint texture;
238 glGenTextures(1, &texture);
239 glBindTexture(GL_TEXTURE_2D, texture);
240 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, d->req_size.width(), d->req_size.height(), 0, GL_RGBA, GL_FLOAT, 0);
241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
243 return texture;
244}
245#endif
246
247/*! \fn bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
248
249 Binds the texture specified by \a texture_id to this pbuffer.
250 Returns true on success; otherwise returns false.
251
252 The texture must be of the same size and format as the pbuffer.
253
254 To unbind the texture, call releaseFromDynamicTexture(). While
255 the texture is bound, it is updated automatically when the
256 pbuffer contents change, eliminating the need for additional copy
257 operations.
258
259 Example:
260
261 \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 0
262
263 \warning This function uses the \c {render_texture} extension,
264 which is currently not supported under X11. An alternative that
265 works on all systems (including X11) is to manually copy the
266 pbuffer contents to a texture using updateDynamicTexture().
267
268 \warning For the bindToDynamicTexture() call to succeed on the
269 Mac OS X, the pbuffer needs a shared context, i.e. the
270 QGLPixelBuffer must be created with a share widget.
271
272 \sa generateDynamicTexture(), releaseFromDynamicTexture()
273*/
274
275/*! \fn void QGLPixelBuffer::releaseFromDynamicTexture()
276
277 Releases the pbuffer from any previously bound texture.
278
279 \sa bindToDynamicTexture()
280*/
281
282/*! \fn bool QGLPixelBuffer::hasOpenGLPbuffers()
283
284 Returns true if the OpenGL \c pbuffer extension is present on
285 this system; otherwise returns false.
286*/
287
288/*!
289 Copies the pbuffer contents into the texture specified with \a
290 texture_id.
291
292 The texture must be of the same size and format as the pbuffer.
293
294 Example:
295
296 \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 1
297
298 An alternative on Windows and Mac OS X systems that support the
299 \c render_texture extension is to use bindToDynamicTexture() to
300 get dynamic updates of the texture.
301
302 \sa generateDynamicTexture(), bindToDynamicTexture()
303*/
304void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const
305{
306 Q_D(const QGLPixelBuffer);
307 if (d->invalid)
308 return;
309 glBindTexture(GL_TEXTURE_2D, texture_id);
310#ifndef QT_OPENGL_ES
311 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, d->req_size.width(), d->req_size.height(), 0);
312#else
313 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, d->req_size.width(), d->req_size.height(), 0);
314#endif
315}
316
317#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
318void QGLPixelBuffer::updateDynamicTexture(QMacCompatGLuint texture_id) const
319{
320 updateDynamicTexture(GLuint(texture_id));
321}
322#endif
323
324/*!
325 Returns the size of the pbuffer.
326*/
327QSize QGLPixelBuffer::size() const
328{
329 Q_D(const QGLPixelBuffer);
330 return d->req_size;
331}
332
333/*!
334 Returns the contents of the pbuffer as a QImage.
335*/
336QImage QGLPixelBuffer::toImage() const
337{
338 Q_D(const QGLPixelBuffer);
339 if (d->invalid)
340 return QImage();
341
342 const_cast<QGLPixelBuffer *>(this)->makeCurrent();
343 return qt_gl_read_framebuffer(d->req_size, d->format.alpha(), true);
344}
345
346/*!
347 Returns the native pbuffer handle.
348*/
349Qt::HANDLE QGLPixelBuffer::handle() const
350{
351 Q_D(const QGLPixelBuffer);
352 if (d->invalid)
353 return 0;
354 return (Qt::HANDLE) d->pbuf;
355}
356
357/*!
358 Returns true if this pbuffer is valid; otherwise returns false.
359*/
360bool QGLPixelBuffer::isValid() const
361{
362 Q_D(const QGLPixelBuffer);
363 return !d->invalid;
364}
365
366#if !defined(QT_OPENGL_ES_2)
367Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
368#endif
369
370/*! \reimp */
371QPaintEngine *QGLPixelBuffer::paintEngine() const
372{
373#if !defined(QT_OPENGL_ES_2)
374 return qt_buffer_paintengine();
375#else
376 return 0;
377#endif
378}
379
380extern int qt_defaultDpi();
381
382/*! \reimp */
383int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
384{
385 Q_D(const QGLPixelBuffer);
386
387 float dpmx = qt_defaultDpi()*100./2.54;
388 float dpmy = qt_defaultDpi()*100./2.54;
389 int w = d->req_size.width();
390 int h = d->req_size.height();
391 switch (metric) {
392 case PdmWidth:
393 return w;
394
395 case PdmHeight:
396 return h;
397
398 case PdmWidthMM:
399 return qRound(w * 1000 / dpmx);
400
401 case PdmHeightMM:
402 return qRound(h * 1000 / dpmy);
403
404 case PdmNumColors:
405 return 0;
406
407 case PdmDepth:
408 return 32;//d->depth;
409
410 case PdmDpiX:
411 return (int)(dpmx * 0.0254);
412
413 case PdmDpiY:
414 return (int)(dpmy * 0.0254);
415
416 case PdmPhysicalDpiX:
417 return (int)(dpmx * 0.0254);
418
419 case PdmPhysicalDpiY:
420 return (int)(dpmy * 0.0254);
421
422 default:
423 qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric);
424 break;
425 }
426 return 0;
427}
428
429/*!
430 Generates and binds a 2D GL texture to the current context, based
431 on \a image. The generated texture id is returned and can be used
432 in later glBindTexture() calls.
433
434 The \a target parameter specifies the texture target.
435
436 Equivalent to calling QGLContext::bindTexture().
437
438 \sa deleteTexture()
439*/
440GLuint QGLPixelBuffer::bindTexture(const QImage &image, GLenum target)
441{
442 Q_D(QGLPixelBuffer);
443#ifndef QT_OPENGL_ES
444 return d->qctx->bindTexture(image, target, GLint(GL_RGBA8));
445#else
446 return d->qctx->bindTexture(image, target, GL_RGBA);
447#endif
448}
449
450#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
451/*! \internal */
452GLuint QGLPixelBuffer::bindTexture(const QImage &image, QMacCompatGLenum target)
453{
454 Q_D(QGLPixelBuffer);
455 return d->qctx->bindTexture(image, target, QMacCompatGLint(GL_RGBA8));
456}
457#endif
458
459/*! \overload
460
461 Generates and binds a 2D GL texture based on \a pixmap.
462
463 Equivalent to calling QGLContext::bindTexture().
464
465 \sa deleteTexture()
466*/
467GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, GLenum target)
468{
469 Q_D(QGLPixelBuffer);
470#ifndef QT_OPENGL_ES
471 return d->qctx->bindTexture(pixmap, target, GLint(GL_RGBA8));
472#else
473 return d->qctx->bindTexture(pixmap, target, GL_RGBA);
474#endif
475}
476
477#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
478/*! \internal */
479GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target)
480{
481 Q_D(QGLPixelBuffer);
482 return d->qctx->bindTexture(pixmap, target, QMacCompatGLint(GL_RGBA8));
483}
484#endif
485
486/*! \overload
487
488 Reads the DirectDrawSurface (DDS) compressed file \a fileName and
489 generates a 2D GL texture from it.
490
491 Equivalent to calling QGLContext::bindTexture().
492
493 \sa deleteTexture()
494*/
495GLuint QGLPixelBuffer::bindTexture(const QString &fileName)
496{
497 Q_D(QGLPixelBuffer);
498 return d->qctx->bindTexture(fileName);
499}
500
501/*!
502 Removes the texture identified by \a texture_id from the texture cache.
503
504 Equivalent to calling QGLContext::deleteTexture().
505 */
506void QGLPixelBuffer::deleteTexture(GLuint texture_id)
507{
508 Q_D(QGLPixelBuffer);
509 d->qctx->deleteTexture(texture_id);
510}
511
512#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
513/*! \internal */
514void QGLPixelBuffer::deleteTexture(QMacCompatGLuint texture_id)
515{
516 Q_D(QGLPixelBuffer);
517 d->qctx->deleteTexture(texture_id);
518}
519#endif
520
521/*!
522 \since 4.4
523
524 Draws the given texture, \a textureId, to the given target rectangle,
525 \a target, in OpenGL model space. The \a textureTarget should be a 2D
526 texture target.
527
528 Equivalent to the corresponding QGLContext::drawTexture().
529*/
530void QGLPixelBuffer::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
531{
532 Q_D(QGLPixelBuffer);
533 d->qctx->drawTexture(target, textureId, textureTarget);
534}
535
536#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
537/*! \internal */
538void QGLPixelBuffer::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
539{
540 Q_D(QGLPixelBuffer);
541 d->qctx->drawTexture(target, textureId, textureTarget);
542}
543#endif
544
545/*!
546 \since 4.4
547
548 Draws the given texture, \a textureId, at the given \a point in OpenGL model
549 space. The textureTarget parameter should be a 2D texture target.
550
551 Equivalent to the corresponding QGLContext::drawTexture().
552*/
553void QGLPixelBuffer::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
554{
555 Q_D(QGLPixelBuffer);
556 d->qctx->drawTexture(point, textureId, textureTarget);
557}
558
559#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
560/*! \internal */
561void QGLPixelBuffer::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
562{
563 Q_D(QGLPixelBuffer);
564 d->qctx->drawTexture(point, textureId, textureTarget);
565}
566#endif
567
568/*!
569 Returns the format of the pbuffer. The format may be different
570 from the one that was requested.
571*/
572QGLFormat QGLPixelBuffer::format() const
573{
574 Q_D(const QGLPixelBuffer);
575 return d->format;
576}
577
578/*! \fn int QGLPixelBuffer::devType() const
579 \reimp
580*/
581
582QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.