Re-apply change 353dcfd307853da289fdd245410e2e07358624a0 by Friedemann Kleint
[qt-netbsd.git] / src / opengl / qwindowsurface_gl.cpp
blob3a7a07e74c6154f08e88a0f99f13918ae967a93a
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
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.
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.
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.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://www.qtsoftware.com/contact.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include <QtGui/QApplication>
43 #include <QtGui/QColormap>
44 #include <QtGui/QDesktopWidget>
45 #include <QtGui/QPaintDevice>
46 #include <QtGui/QWidget>
48 #include <qglframebufferobject.h>
49 #include <qglpixelbuffer.h>
50 #include <qcolormap.h>
51 #include <qdesktopwidget.h>
52 #include "qdebug.h"
54 #ifdef Q_WS_X11
55 #include <private/qt_x11_p.h>
56 #include <qx11info_x11.h>
57 #include <private/qwidget_p.h>
59 #ifndef QT_OPENGL_ES
60 #include <GL/glx.h>
61 #include <X11/Xlib.h>
62 #endif
63 #endif //Q_WS_X11
65 #include <private/qglextensions_p.h>
66 #include <private/qwindowsurface_gl_p.h>
68 #include <private/qgl_p.h>
70 #include <private/qglpixelbuffer_p.h>
71 #include <private/qgraphicssystem_gl_p.h>
73 #include <private/qpaintengineex_opengl2_p.h>
75 #ifndef QT_OPENGL_ES_2
76 #include <private/qpaintengine_opengl_p.h>
77 #endif
79 #ifndef GLX_ARB_multisample
80 #define GLX_SAMPLE_BUFFERS_ARB 100000
81 #define GLX_SAMPLES_ARB 100001
82 #endif
84 #ifdef QT_OPENGL_ES_1_CL
85 #include "qgl_cl_p.h"
86 #endif
88 QT_BEGIN_NAMESPACE
91 // QGLGraphicsSystem
93 #ifdef Q_WS_WIN
94 extern Q_GUI_EXPORT bool qt_win_owndc_required;
95 #endif
96 QGLGraphicsSystem::QGLGraphicsSystem()
97 : QGraphicsSystem()
99 #if defined(Q_WS_X11) && !defined(QT_OPENGL_ES)
100 // only override the system defaults if the user hasn't already
101 // picked a visual
102 if (X11->visual == 0 && X11->visual_id == -1 && X11->visual_class == -1) {
103 // find a double buffered, RGBA visual that supports OpenGL
104 // and set that as the default visual for windows in Qt
105 int i = 0;
106 int spec[16];
107 spec[i++] = GLX_RGBA;
108 spec[i++] = GLX_DOUBLEBUFFER;
110 if (!qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull()) {
111 spec[i++] = GLX_DEPTH_SIZE;
112 spec[i++] = 8;
113 spec[i++] = GLX_STENCIL_SIZE;
114 spec[i++] = 8;
115 spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
116 spec[i++] = 1;
117 spec[i++] = GLX_SAMPLES_ARB;
118 spec[i++] = 4;
121 spec[i++] = XNone;
123 XVisualInfo *vi = glXChooseVisual(X11->display, X11->defaultScreen, spec);
124 if (vi) {
125 X11->visual_id = vi->visualid;
126 X11->visual_class = vi->c_class;
128 QGLFormat format;
129 int res;
130 glXGetConfig(X11->display, vi, GLX_LEVEL, &res);
131 format.setPlane(res);
132 glXGetConfig(X11->display, vi, GLX_DOUBLEBUFFER, &res);
133 format.setDoubleBuffer(res);
134 glXGetConfig(X11->display, vi, GLX_DEPTH_SIZE, &res);
135 format.setDepth(res);
136 if (format.depth())
137 format.setDepthBufferSize(res);
138 glXGetConfig(X11->display, vi, GLX_RGBA, &res);
139 format.setRgba(res);
140 glXGetConfig(X11->display, vi, GLX_RED_SIZE, &res);
141 format.setRedBufferSize(res);
142 glXGetConfig(X11->display, vi, GLX_GREEN_SIZE, &res);
143 format.setGreenBufferSize(res);
144 glXGetConfig(X11->display, vi, GLX_BLUE_SIZE, &res);
145 format.setBlueBufferSize(res);
146 glXGetConfig(X11->display, vi, GLX_ALPHA_SIZE, &res);
147 format.setAlpha(res);
148 if (format.alpha())
149 format.setAlphaBufferSize(res);
150 glXGetConfig(X11->display, vi, GLX_ACCUM_RED_SIZE, &res);
151 format.setAccum(res);
152 if (format.accum())
153 format.setAccumBufferSize(res);
154 glXGetConfig(X11->display, vi, GLX_STENCIL_SIZE, &res);
155 format.setStencil(res);
156 if (format.stencil())
157 format.setStencilBufferSize(res);
158 glXGetConfig(X11->display, vi, GLX_STEREO, &res);
159 format.setStereo(res);
160 glXGetConfig(X11->display, vi, GLX_SAMPLE_BUFFERS_ARB, &res);
161 format.setSampleBuffers(res);
162 if (format.sampleBuffers()) {
163 glXGetConfig(X11->display, vi, GLX_SAMPLES_ARB, &res);
164 format.setSamples(res);
167 QGLWindowSurface::surfaceFormat = format;
168 XFree(vi);
170 printf("using visual class %x, id %x\n", X11->visual_class, X11->visual_id);
173 #elif defined(Q_WS_WIN)
174 QGLWindowSurface::surfaceFormat.setDoubleBuffer(false);
176 qt_win_owndc_required = true;
177 #endif
181 // QGLWindowSurface
184 class QGLGlobalShareWidget
186 public:
187 QGLGlobalShareWidget() : widget(0), initializing(false) {}
189 QGLWidget *shareWidget() {
190 if (!initializing && !widget && !cleanedUp) {
191 initializing = true;
192 widget = new QGLWidget;
193 initializing = false;
195 return widget;
198 void cleanup() {
199 QGLWidget *w = widget;
200 cleanedUp = true;
201 widget = 0;
202 delete w;
205 static bool cleanedUp;
207 private:
208 QGLWidget *widget;
209 bool initializing;
212 bool QGLGlobalShareWidget::cleanedUp = false;
214 static void qt_cleanup_gl_share_widget();
215 Q_GLOBAL_STATIC_WITH_INITIALIZER(QGLGlobalShareWidget, _qt_gl_share_widget,
217 qAddPostRoutine(qt_cleanup_gl_share_widget);
220 static void qt_cleanup_gl_share_widget()
222 _qt_gl_share_widget()->cleanup();
225 QGLWidget* qt_gl_share_widget()
227 if (QGLGlobalShareWidget::cleanedUp)
228 return 0;
229 return _qt_gl_share_widget()->shareWidget();
232 struct QGLWindowSurfacePrivate
234 QGLFramebufferObject *fbo;
235 QGLPixelBuffer *pb;
236 GLuint tex_id;
237 GLuint pb_tex_id;
239 int tried_fbo : 1;
240 int tried_pb : 1;
241 int destructive_swap_buffers : 1;
243 QGLContext *ctx;
245 QList<QGLContext **> contexts;
247 QRegion paintedRegion;
248 QSize size;
250 QList<QImage> buffers;
253 QGLFormat QGLWindowSurface::surfaceFormat;
255 QGLWindowSurface::QGLWindowSurface(QWidget *window)
256 : QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate)
258 Q_ASSERT(window->isTopLevel());
259 QGLExtensions::init();
260 d_ptr->pb = 0;
261 d_ptr->fbo = 0;
262 d_ptr->ctx = 0;
263 d_ptr->tried_fbo = false;
264 d_ptr->tried_pb = false;
265 d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull();
268 QGLWindowSurface::~QGLWindowSurface()
270 if (d_ptr->ctx)
271 glDeleteTextures(1, &d_ptr->tex_id);
272 foreach(QGLContext **ctx, d_ptr->contexts) {
273 delete *ctx;
274 *ctx = 0;
277 delete d_ptr->pb;
278 delete d_ptr->fbo;
279 delete d_ptr;
282 void QGLWindowSurface::deleted(QObject *object)
284 QWidget *widget = qobject_cast<QWidget *>(object);
285 if (widget) {
286 QWidgetPrivate *widgetPrivate = widget->d_func();
287 if (widgetPrivate->extraData()) {
288 union { QGLContext **ctxPtr; void **voidPtr; };
289 voidPtr = &widgetPrivate->extraData()->glContext;
290 int index = d_ptr->contexts.indexOf(ctxPtr);
291 if (index != -1) {
292 delete *ctxPtr;
293 *ctxPtr = 0;
294 d_ptr->contexts.removeAt(index);
300 void QGLWindowSurface::hijackWindow(QWidget *widget)
302 QWidgetPrivate *widgetPrivate = widget->d_func();
303 widgetPrivate->createExtra();
304 if (widgetPrivate->extraData()->glContext)
305 return;
307 QGLContext *ctx = new QGLContext(surfaceFormat, widget);
308 ctx->create(qt_gl_share_widget()->context());
309 #ifdef Q_WS_MAC
310 ctx->updatePaintDevice();
311 #endif
312 widgetPrivate->extraData()->glContext = ctx;
314 union { QGLContext **ctxPtr; void **voidPtr; };
316 connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(deleted(QObject *)));
318 voidPtr = &widgetPrivate->extraData()->glContext;
319 d_ptr->contexts << ctxPtr;
320 qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
323 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_2_engine)
325 #if !defined (QT_OPENGL_ES_2)
326 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_engine)
327 #endif
329 /*! \reimp */
330 QPaintEngine *QGLWindowSurface::paintEngine() const
332 #if !defined(QT_OPENGL_ES_2)
333 if (!qt_gl_preferGL2Engine())
334 return qt_gl_window_surface_engine();
335 #endif
336 return qt_gl_window_surface_2_engine();
339 int QGLWindowSurface::metric(PaintDeviceMetric m) const
341 return window()->metric(m);
344 QGLContext *QGLWindowSurface::context() const
346 return d_ptr->ctx;
349 QPaintDevice *QGLWindowSurface::paintDevice()
351 updateGeometry();
353 if (d_ptr->pb)
354 return d_ptr->pb;
356 if (d_ptr->ctx)
357 return this;
359 QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
360 ctx->makeCurrent();
361 return d_ptr->fbo;
364 static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &src = QRectF());
366 void QGLWindowSurface::beginPaint(const QRegion &)
368 updateGeometry();
371 void QGLWindowSurface::endPaint(const QRegion &rgn)
373 if (context())
374 d_ptr->paintedRegion |= rgn;
376 d_ptr->buffers.clear();
379 void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
381 QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget();
382 Q_ASSERT(parent);
384 if (!geometry().isValid())
385 return;
387 hijackWindow(parent);
389 QRect br = rgn.boundingRect().translated(offset);
390 br = br.intersected(window()->rect());
391 QPoint wOffset = qt_qwidget_data(parent)->wrect.topLeft();
392 QRect rect = br.translated(-offset - wOffset);
394 const GLenum target = GL_TEXTURE_2D;
396 if (context()) {
397 context()->makeCurrent();
399 if (context()->format().doubleBuffer()) {
400 #if !defined(QT_OPENGL_ES_2)
401 if (d_ptr->destructive_swap_buffers) {
402 glBindTexture(target, d_ptr->tex_id);
404 QVector<QRect> rects = d_ptr->paintedRegion.rects();
405 for (int i = 0; i < rects.size(); ++i) {
406 QRect br = rects.at(i);
407 if (br.isEmpty())
408 continue;
410 const uint bottom = window()->height() - (br.y() + br.height());
411 glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
414 glBindTexture(target, 0);
416 QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion;
418 if (!dirtyRegion.isEmpty()) {
419 context()->makeCurrent();
421 glMatrixMode(GL_MODELVIEW);
422 glLoadIdentity();
424 glMatrixMode(GL_PROJECTION);
425 glLoadIdentity();
426 #ifndef QT_OPENGL_ES
427 glOrtho(0, window()->width(), window()->height(), 0, -999999, 999999);
428 #else
429 glOrthof(0, window()->width(), window()->height(), 0, -999999, 999999);
430 #endif
431 glViewport(0, 0, window()->width(), window()->height());
433 QVector<QRect> rects = dirtyRegion.rects();
434 glColor4f(1, 1, 1, 1);
435 for (int i = 0; i < rects.size(); ++i) {
436 QRect rect = rects.at(i);
437 if (rect.isEmpty())
438 continue;
440 drawTexture(rect, d_ptr->tex_id, window()->size(), rect);
444 #endif
445 d_ptr->paintedRegion = QRegion();
447 context()->swapBuffers();
448 } else {
449 glFlush();
452 return;
455 QGLContext *ctx = reinterpret_cast<QGLContext *>(parent->d_func()->extraData()->glContext);
456 GLuint texture;
457 if (d_ptr->fbo) {
458 texture = d_ptr->fbo->texture();
459 } else {
460 d_ptr->pb->makeCurrent();
461 glBindTexture(target, d_ptr->pb_tex_id);
462 const uint bottom = window()->height() - (br.y() + br.height());
463 glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
464 texture = d_ptr->pb_tex_id;
465 glBindTexture(target, 0);
468 QSize size = widget->rect().size();
469 if (d_ptr->destructive_swap_buffers && ctx->format().doubleBuffer()) {
470 rect = parent->rect();
471 br = rect.translated(wOffset);
472 size = parent->size();
475 glDisable(GL_SCISSOR_TEST);
477 if (d_ptr->fbo && QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit) {
478 const int h = d_ptr->fbo->height();
480 const int x0 = rect.left();
481 const int x1 = rect.left() + rect.width();
482 const int y0 = h - (rect.top() + rect.height());
483 const int y1 = h - rect.top();
485 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
487 glBlitFramebufferEXT(x0, y0, x1, y1,
488 x0, y0, x1, y1,
489 GL_COLOR_BUFFER_BIT,
490 GL_NEAREST);
492 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
494 #if !defined(QT_OPENGL_ES_2)
495 else {
496 glDisable(GL_DEPTH_TEST);
498 if (d_ptr->fbo) {
499 d_ptr->fbo->release();
500 } else {
501 ctx->makeCurrent();
502 #ifdef Q_WS_MAC
503 ctx->updatePaintDevice();
504 #endif
507 glMatrixMode(GL_MODELVIEW);
508 glLoadIdentity();
510 glMatrixMode(GL_PROJECTION);
511 glLoadIdentity();
512 #ifndef QT_OPENGL_ES
513 glOrtho(0, size.width(), size.height(), 0, -999999, 999999);
514 #else
515 glOrthof(0, size.width(), size.height(), 0, -999999, 999999);
516 #endif
517 glViewport(0, 0, size.width(), size.height());
519 glColor4f(1, 1, 1, 1);
520 drawTexture(rect, texture, window()->size(), br);
522 if (d_ptr->fbo)
523 d_ptr->fbo->bind();
525 #endif
527 if (ctx->format().doubleBuffer())
528 ctx->swapBuffers();
529 else
530 glFlush();
533 void QGLWindowSurface::updateGeometry()
535 QRect rect = QWindowSurface::geometry();
537 const GLenum target = GL_TEXTURE_2D;
539 if (rect.width() <= 0 || rect.height() <= 0)
540 return;
542 if (d_ptr->size == rect.size())
543 return;
545 d_ptr->size = rect.size();
547 if (d_ptr->ctx) {
548 if (d_ptr->destructive_swap_buffers) {
549 glBindTexture(target, d_ptr->tex_id);
550 glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
551 glBindTexture(target, 0);
553 return;
556 if (d_ptr->destructive_swap_buffers
557 && (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject)
558 #ifdef QT_OPENGL_ES_2
559 && (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
560 #endif
561 && (d_ptr->fbo || !d_ptr->tried_fbo))
563 d_ptr->tried_fbo = true;
564 hijackWindow(window());
565 QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
566 ctx->d_ptr->internal_context = true;
567 ctx->makeCurrent();
568 delete d_ptr->fbo;
570 QGLFramebufferObjectFormat format;
571 format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
572 format.setInternalFormat(GL_RGBA);
573 format.setTextureTarget(target);
575 if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
576 format.setSamples(8);
578 d_ptr->fbo = new QGLFramebufferObject(rect.size(), format);
579 d_ptr->fbo->bind();
580 if (d_ptr->fbo->isValid()) {
581 qDebug() << "Created Window Surface FBO" << rect.size()
582 << "with samples" << d_ptr->fbo->format().samples();
583 return;
584 } else {
585 qDebug() << "QGLWindowSurface: Failed to create valid FBO, falling back";
586 delete d_ptr->fbo;
587 d_ptr->fbo = 0;
591 #if !defined(QT_OPENGL_ES_2)
592 if (d_ptr->destructive_swap_buffers && (d_ptr->pb || !d_ptr->tried_pb)) {
593 d_ptr->tried_pb = true;
595 if (d_ptr->pb) {
596 d_ptr->pb->makeCurrent();
597 glDeleteTextures(1, &d_ptr->pb_tex_id);
600 delete d_ptr->pb;
602 d_ptr->pb = new QGLPixelBuffer(rect.width(), rect.height(),
603 QGLFormat(QGL::SampleBuffers | QGL::StencilBuffer | QGL::DepthBuffer),
604 qt_gl_share_widget());
606 if (d_ptr->pb->isValid()) {
607 qDebug() << "Created Window Surface Pixelbuffer, Sample buffers:" << d_ptr->pb->format().sampleBuffers();
608 d_ptr->pb->makeCurrent();
610 glGenTextures(1, &d_ptr->pb_tex_id);
611 glBindTexture(target, d_ptr->pb_tex_id);
612 glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
614 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
615 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
616 glBindTexture(target, 0);
618 glMatrixMode(GL_PROJECTION);
619 glLoadIdentity();
620 #ifndef QT_OPENGL_ES
621 glOrtho(0, d_ptr->pb->width(), d_ptr->pb->height(), 0, -999999, 999999);
622 #else
623 glOrthof(0, d_ptr->pb->width(), d_ptr->pb->height(), 0, -999999, 999999);
624 #endif
626 d_ptr->pb->d_ptr->qctx->d_func()->internal_context = true;
627 return;
628 } else {
629 qDebug() << "QGLWindowSurface: Failed to create valid pixelbuffer, falling back";
630 delete d_ptr->pb;
631 d_ptr->pb = 0;
634 #endif // !defined(QT_OPENGL_ES_2)
636 hijackWindow(window());
637 QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
638 ctx->makeCurrent();
640 if (d_ptr->destructive_swap_buffers) {
641 glGenTextures(1, &d_ptr->tex_id);
642 glBindTexture(target, d_ptr->tex_id);
643 glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
645 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
646 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
647 glBindTexture(target, 0);
650 qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;;
651 d_ptr->ctx = ctx;
652 d_ptr->ctx->d_ptr->internal_context = true;
655 void QGLWindowSurface::setGeometry(const QRect &rect)
657 QWindowSurface::setGeometry(rect);
660 bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy)
662 // this code randomly fails currently for unknown reasons
663 return false;
665 if (!d_ptr->pb)
666 return false;
668 d_ptr->pb->makeCurrent();
670 QRect br = area.boundingRect();
672 #if 0
673 // ## workaround driver issue (scrolling by these deltas is unbearably slow for some reason)
674 // ## maybe we should use glCopyTexSubImage insteadk
675 if (dx == 1 || dx == -1 || dy == 1 || dy == -1 || dy == 2)
676 return false;
678 glRasterPos2i(br.x() + dx, br.y() + br.height() + dy);
679 glCopyPixels(br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), GL_COLOR);
680 return true;
681 #endif
683 const GLenum target = GL_TEXTURE_2D;
685 glBindTexture(target, d_ptr->tex_id);
686 glCopyTexImage2D(target, 0, GL_RGBA, br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), 0);
687 glBindTexture(target, 0);
689 drawTexture(br.translated(dx, dy), d_ptr->tex_id, window()->size());
691 return true;
694 static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &br)
696 const GLenum target = GL_TEXTURE_2D;
697 QRectF src = br.isEmpty()
698 ? QRectF(QPointF(), texSize)
699 : QRectF(QPointF(br.x(), texSize.height() - br.bottom()), br.size());
701 if (target == GL_TEXTURE_2D) {
702 qreal width = texSize.width();
703 qreal height = texSize.height();
705 src.setLeft(src.left() / width);
706 src.setRight(src.right() / width);
707 src.setTop(src.top() / height);
708 src.setBottom(src.bottom() / height);
711 const q_vertexType tx1 = f2vt(src.left());
712 const q_vertexType tx2 = f2vt(src.right());
713 const q_vertexType ty1 = f2vt(src.top());
714 const q_vertexType ty2 = f2vt(src.bottom());
716 q_vertexType texCoordArray[4*2] = {
717 tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1
720 q_vertexType vertexArray[4*2];
721 extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array); // qpaintengine_opengl.cpp
722 qt_add_rect_to_array(rect, vertexArray);
724 #if !defined(QT_OPENGL_ES_2)
725 glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
726 glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
728 glBindTexture(target, tex_id);
729 glEnable(target);
731 glEnableClientState(GL_VERTEX_ARRAY);
732 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
733 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
734 glDisableClientState(GL_VERTEX_ARRAY);
735 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
736 #endif
738 glDisable(target);
739 glBindTexture(target, 0);
742 QImage *QGLWindowSurface::buffer(const QWidget *widget)
744 QImage image;
746 if (d_ptr->pb)
747 image = d_ptr->pb->toImage();
748 else if (d_ptr->fbo)
749 image = d_ptr->fbo->toImage();
751 if (image.isNull())
752 return 0;
754 QRect rect = widget->rect();
755 rect.translate(widget->mapTo(widget->window(), QPoint()));
757 QImage subImage = image.copy(rect);
758 d_ptr->buffers << subImage;
759 return &d_ptr->buffers.last();
764 QT_END_NAMESPACE