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

Last change on this file since 616 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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