tests: Don't omit the body of a test function with QT_BUILD_INTERNAL
[profile/ivi/qtbase.git] / tests / auto / opengl / qgl / tst_qgl.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44
45 #include <qcoreapplication.h>
46 #include <qdebug.h>
47 #include <qgl.h>
48 #include <qglpixelbuffer.h>
49 #include <qglframebufferobject.h>
50 #include <qglcolormap.h>
51 #include <qpaintengine.h>
52
53 #include <QGraphicsView>
54 #include <QGraphicsProxyWidget>
55 #include <QVBoxLayout>
56
57 #ifdef QT_BUILD_INTERNAL
58 #include <qpa/qplatformpixmap.h>
59 #include <QtOpenGL/private/qgl_p.h>
60 #include <QtGui/private/qimage_p.h>
61 #include <QtGui/private/qimagepixmapcleanuphooks_p.h>
62 #endif
63
64 class tst_QGL : public QObject
65 {
66 Q_OBJECT
67
68 public:
69     tst_QGL();
70     virtual ~tst_QGL();
71
72 private slots:
73     void initTestCase();
74     void getSetCheck();
75 #ifdef QT_BUILD_INTERNAL
76     void qglContextDefaultBindTexture();
77     void openGLVersionCheck();
78     void shareRegister();
79     void textureCleanup();
80 #endif
81     void graphicsViewClipping();
82     void partialGLWidgetUpdates_data();
83     void partialGLWidgetUpdates();
84     void glWidgetWithAlpha();
85     void glWidgetRendering();
86     void glFBOSimpleRendering();
87     void glFBORendering();
88     void multipleFBOInterleavedRendering();
89     void glFBOUseInGLWidget();
90     void glPBufferRendering();
91     void glWidgetReparent();
92     void glWidgetRenderPixmap();
93     void colormap();
94     void fboFormat();
95     void testDontCrashOnDanglingResources();
96     void replaceClipping();
97     void clipTest();
98     void destroyFBOAfterContext();
99     void threadImages();
100     void nullRectCrash();
101 };
102
103 tst_QGL::tst_QGL()
104 {
105 }
106
107 tst_QGL::~tst_QGL()
108 {
109 }
110
111 void tst_QGL::initTestCase()
112 {
113     QGLWidget glWidget;
114     if (!glWidget.isValid())
115         QSKIP("QGL is not supported on the test system");
116 }
117
118 class MyGLContext : public QGLContext
119 {
120 public:
121     MyGLContext(const QGLFormat& format) : QGLContext(format) {}
122     bool windowCreated() const { return QGLContext::windowCreated(); }
123     void setWindowCreated(bool on) { QGLContext::setWindowCreated(on); }
124     bool initialized() const { return QGLContext::initialized(); }
125     void setInitialized(bool on) { QGLContext::setInitialized(on); }
126 };
127
128 class MyGLWidget : public QGLWidget
129 {
130 public:
131     MyGLWidget() : QGLWidget() {}
132     bool autoBufferSwap() const { return QGLWidget::autoBufferSwap(); }
133     void setAutoBufferSwap(bool on) { QGLWidget::setAutoBufferSwap(on); }
134 };
135
136 static int appDefaultDepth()
137 {
138     static int depth = 0;
139     if (depth == 0) {
140         QPixmap pm(1, 1);
141         depth = pm.depth();
142     }
143     return depth;
144 }
145
146 // Using INT_MIN and INT_MAX will cause failures on systems
147 // where "int" is 64-bit, so use the explicit values instead.
148 #define TEST_INT_MIN    (-2147483647 - 1)
149 #define TEST_INT_MAX    2147483647
150
151 // Testing get/set functions
152 void tst_QGL::getSetCheck()
153 {
154     QGLFormat obj1;
155     // int QGLFormat::depthBufferSize()
156     // void QGLFormat::setDepthBufferSize(int)
157     QCOMPARE(-1, obj1.depthBufferSize());
158     obj1.setDepthBufferSize(0);
159     QCOMPARE(0, obj1.depthBufferSize());
160     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size -2147483648");
161     obj1.setDepthBufferSize(TEST_INT_MIN);
162     QCOMPARE(0, obj1.depthBufferSize()); // Makes no sense with a negative buffer size
163     obj1.setDepthBufferSize(3);
164     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size -1");
165     obj1.setDepthBufferSize(-1);
166     QCOMPARE(3, obj1.depthBufferSize());
167     obj1.setDepthBufferSize(TEST_INT_MAX);
168     QCOMPARE(TEST_INT_MAX, obj1.depthBufferSize());
169
170     // int QGLFormat::accumBufferSize()
171     // void QGLFormat::setAccumBufferSize(int)
172     QCOMPARE(-1, obj1.accumBufferSize());
173     obj1.setAccumBufferSize(0);
174     QCOMPARE(0, obj1.accumBufferSize());
175     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size -2147483648");
176     obj1.setAccumBufferSize(TEST_INT_MIN);
177     QCOMPARE(0, obj1.accumBufferSize()); // Makes no sense with a negative buffer size
178     obj1.setAccumBufferSize(3);
179     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size -1");
180     obj1.setAccumBufferSize(-1);
181     QCOMPARE(3, obj1.accumBufferSize());
182     obj1.setAccumBufferSize(TEST_INT_MAX);
183     QCOMPARE(TEST_INT_MAX, obj1.accumBufferSize());
184
185     // int QGLFormat::redBufferSize()
186     // void QGLFormat::setRedBufferSize(int)
187     QCOMPARE(-1, obj1.redBufferSize());
188     obj1.setRedBufferSize(0);
189     QCOMPARE(0, obj1.redBufferSize());
190     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setRedBufferSize: Cannot set negative red buffer size -2147483648");
191     obj1.setRedBufferSize(TEST_INT_MIN);
192     QCOMPARE(0, obj1.redBufferSize()); // Makes no sense with a negative buffer size
193     obj1.setRedBufferSize(3);
194     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setRedBufferSize: Cannot set negative red buffer size -1");
195     obj1.setRedBufferSize(-1);
196     QCOMPARE(3, obj1.redBufferSize());
197     obj1.setRedBufferSize(TEST_INT_MAX);
198     QCOMPARE(TEST_INT_MAX, obj1.redBufferSize());
199
200     // int QGLFormat::greenBufferSize()
201     // void QGLFormat::setGreenBufferSize(int)
202     QCOMPARE(-1, obj1.greenBufferSize());
203     obj1.setGreenBufferSize(0);
204     QCOMPARE(0, obj1.greenBufferSize());
205     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setGreenBufferSize: Cannot set negative green buffer size -2147483648");
206     obj1.setGreenBufferSize(TEST_INT_MIN);
207     QCOMPARE(0, obj1.greenBufferSize()); // Makes no sense with a negative buffer size
208     obj1.setGreenBufferSize(3);
209     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setGreenBufferSize: Cannot set negative green buffer size -1");
210     obj1.setGreenBufferSize(-1);
211     QCOMPARE(3, obj1.greenBufferSize());
212     obj1.setGreenBufferSize(TEST_INT_MAX);
213     QCOMPARE(TEST_INT_MAX, obj1.greenBufferSize());
214
215     // int QGLFormat::blueBufferSize()
216     // void QGLFormat::setBlueBufferSize(int)
217     QCOMPARE(-1, obj1.blueBufferSize());
218     obj1.setBlueBufferSize(0);
219     QCOMPARE(0, obj1.blueBufferSize());
220     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size -2147483648");
221     obj1.setBlueBufferSize(TEST_INT_MIN);
222     QCOMPARE(0, obj1.blueBufferSize()); // Makes no sense with a negative buffer size
223     obj1.setBlueBufferSize(3);
224     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size -1");
225     obj1.setBlueBufferSize(-1);
226     QCOMPARE(3, obj1.blueBufferSize());
227     obj1.setBlueBufferSize(TEST_INT_MAX);
228     QCOMPARE(TEST_INT_MAX, obj1.blueBufferSize());
229
230     // int QGLFormat::alphaBufferSize()
231     // void QGLFormat::setAlphaBufferSize(int)
232     QCOMPARE(-1, obj1.alphaBufferSize());
233     QCOMPARE(false, obj1.alpha());
234     QVERIFY(!obj1.testOption(QGL::AlphaChannel));
235     QVERIFY(obj1.testOption(QGL::NoAlphaChannel));
236     obj1.setAlphaBufferSize(1);
237     QCOMPARE(true, obj1.alpha());   // setAlphaBufferSize() enables alpha.
238     QCOMPARE(1, obj1.alphaBufferSize());
239     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -2147483648");
240     obj1.setAlphaBufferSize(TEST_INT_MIN);
241     QCOMPARE(1, obj1.alphaBufferSize()); // Makes no sense with a negative buffer size
242     obj1.setAlphaBufferSize(3);
243     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -1");
244     obj1.setAlphaBufferSize(-1);
245     QCOMPARE(3, obj1.alphaBufferSize());
246     obj1.setAlphaBufferSize(TEST_INT_MAX);
247     QCOMPARE(TEST_INT_MAX, obj1.alphaBufferSize());
248
249     // int QGLFormat::stencilBufferSize()
250     // void QGLFormat::setStencilBufferSize(int)
251     QCOMPARE(-1, obj1.stencilBufferSize());
252     obj1.setStencilBufferSize(1);
253     QCOMPARE(1, obj1.stencilBufferSize());
254     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -2147483648");
255     obj1.setStencilBufferSize(TEST_INT_MIN);
256     QCOMPARE(1, obj1.stencilBufferSize()); // Makes no sense with a negative buffer size
257     obj1.setStencilBufferSize(3);
258     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -1");
259     obj1.setStencilBufferSize(-1);
260     QCOMPARE(3, obj1.stencilBufferSize());
261     obj1.setStencilBufferSize(TEST_INT_MAX);
262     QCOMPARE(TEST_INT_MAX, obj1.stencilBufferSize());
263
264     // bool QGLFormat::sampleBuffers()
265     // void QGLFormat::setSampleBuffers(bool)
266     QCOMPARE(false, obj1.sampleBuffers());
267     QVERIFY(!obj1.testOption(QGL::SampleBuffers));
268     QVERIFY(obj1.testOption(QGL::NoSampleBuffers));
269
270     obj1.setSampleBuffers(false);
271     QCOMPARE(false, obj1.sampleBuffers());
272     QVERIFY(obj1.testOption(QGL::NoSampleBuffers));
273     obj1.setSampleBuffers(true);
274     QCOMPARE(true, obj1.sampleBuffers());
275     QVERIFY(obj1.testOption(QGL::SampleBuffers));
276
277     // int QGLFormat::samples()
278     // void QGLFormat::setSamples(int)
279     QCOMPARE(-1, obj1.samples());
280     obj1.setSamples(0);
281     QCOMPARE(0, obj1.samples());
282     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setSamples: Cannot have negative number of samples per pixel -2147483648");
283     obj1.setSamples(TEST_INT_MIN);
284     QCOMPARE(0, obj1.samples());  // Makes no sense with a negative sample size
285     obj1.setSamples(3);
286     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setSamples: Cannot have negative number of samples per pixel -1");
287     obj1.setSamples(-1);
288     QCOMPARE(3, obj1.samples());
289     obj1.setSamples(TEST_INT_MAX);
290     QCOMPARE(TEST_INT_MAX, obj1.samples());
291
292     // int QGLFormat::swapInterval()
293     // void QGLFormat::setSwapInterval(int)
294     QCOMPARE(-1, obj1.swapInterval());
295     obj1.setSwapInterval(0);
296     QCOMPARE(0, obj1.swapInterval());
297     obj1.setSwapInterval(TEST_INT_MIN);
298     QCOMPARE(TEST_INT_MIN, obj1.swapInterval());
299     obj1.setSwapInterval(-1);
300     QCOMPARE(-1, obj1.swapInterval());
301     obj1.setSwapInterval(TEST_INT_MAX);
302     QCOMPARE(TEST_INT_MAX, obj1.swapInterval());
303
304     // bool QGLFormat::doubleBuffer()
305     // void QGLFormat::setDoubleBuffer(bool)
306     QCOMPARE(true, obj1.doubleBuffer());
307     QVERIFY(obj1.testOption(QGL::DoubleBuffer));
308     QVERIFY(!obj1.testOption(QGL::SingleBuffer));
309     obj1.setDoubleBuffer(false);
310     QCOMPARE(false, obj1.doubleBuffer());
311     QVERIFY(!obj1.testOption(QGL::DoubleBuffer));
312     QVERIFY(obj1.testOption(QGL::SingleBuffer));
313     obj1.setDoubleBuffer(true);
314     QCOMPARE(true, obj1.doubleBuffer());
315     QVERIFY(obj1.testOption(QGL::DoubleBuffer));
316     QVERIFY(!obj1.testOption(QGL::SingleBuffer));
317
318     // bool QGLFormat::depth()
319     // void QGLFormat::setDepth(bool)
320     QCOMPARE(true, obj1.depth());
321     QVERIFY(obj1.testOption(QGL::DepthBuffer));
322     QVERIFY(!obj1.testOption(QGL::NoDepthBuffer));
323     obj1.setDepth(false);
324     QCOMPARE(false, obj1.depth());
325     QVERIFY(!obj1.testOption(QGL::DepthBuffer));
326     QVERIFY(obj1.testOption(QGL::NoDepthBuffer));
327     obj1.setDepth(true);
328     QCOMPARE(true, obj1.depth());
329     QVERIFY(obj1.testOption(QGL::DepthBuffer));
330     QVERIFY(!obj1.testOption(QGL::NoDepthBuffer));
331
332     // bool QGLFormat::rgba()
333     // void QGLFormat::setRgba(bool)
334     QCOMPARE(true, obj1.rgba());
335     QVERIFY(obj1.testOption(QGL::Rgba));
336     QVERIFY(!obj1.testOption(QGL::ColorIndex));
337     obj1.setRgba(false);
338     QCOMPARE(false, obj1.rgba());
339     QVERIFY(!obj1.testOption(QGL::Rgba));
340     QVERIFY(obj1.testOption(QGL::ColorIndex));
341     obj1.setRgba(true);
342     QCOMPARE(true, obj1.rgba());
343     QVERIFY(obj1.testOption(QGL::Rgba));
344     QVERIFY(!obj1.testOption(QGL::ColorIndex));
345
346     // bool QGLFormat::alpha()
347     // void QGLFormat::setAlpha(bool)
348     QVERIFY(obj1.testOption(QGL::AlphaChannel));
349     QVERIFY(!obj1.testOption(QGL::NoAlphaChannel));
350     obj1.setAlpha(false);
351     QCOMPARE(false, obj1.alpha());
352     QVERIFY(!obj1.testOption(QGL::AlphaChannel));
353     QVERIFY(obj1.testOption(QGL::NoAlphaChannel));
354     obj1.setAlpha(true);
355     QCOMPARE(true, obj1.alpha());
356     QVERIFY(obj1.testOption(QGL::AlphaChannel));
357     QVERIFY(!obj1.testOption(QGL::NoAlphaChannel));
358
359     // bool QGLFormat::accum()
360     // void QGLFormat::setAccum(bool)
361     obj1.setAccumBufferSize(0);
362     QCOMPARE(false, obj1.accum());
363     QVERIFY(!obj1.testOption(QGL::AccumBuffer));
364     QVERIFY(obj1.testOption(QGL::NoAccumBuffer));
365     obj1.setAccum(false);
366     QCOMPARE(false, obj1.accum());
367     QVERIFY(!obj1.testOption(QGL::AccumBuffer));
368     QVERIFY(obj1.testOption(QGL::NoAccumBuffer));
369     obj1.setAccum(true);
370     QCOMPARE(true, obj1.accum());
371     QVERIFY(obj1.testOption(QGL::AccumBuffer));
372     QVERIFY(!obj1.testOption(QGL::NoAccumBuffer));
373
374     // bool QGLFormat::stencil()
375     // void QGLFormat::setStencil(bool)
376     QCOMPARE(true, obj1.stencil());
377     QVERIFY(obj1.testOption(QGL::StencilBuffer));
378     QVERIFY(!obj1.testOption(QGL::NoStencilBuffer));
379     obj1.setStencil(false);
380     QCOMPARE(false, obj1.stencil());
381     QVERIFY(!obj1.testOption(QGL::StencilBuffer));
382     QVERIFY(obj1.testOption(QGL::NoStencilBuffer));
383     obj1.setStencil(true);
384     QCOMPARE(true, obj1.stencil());
385     QVERIFY(obj1.testOption(QGL::StencilBuffer));
386     QVERIFY(!obj1.testOption(QGL::NoStencilBuffer));
387
388     // bool QGLFormat::stereo()
389     // void QGLFormat::setStereo(bool)
390     QCOMPARE(false, obj1.stereo());
391     QVERIFY(!obj1.testOption(QGL::StereoBuffers));
392     QVERIFY(obj1.testOption(QGL::NoStereoBuffers));
393     obj1.setStereo(false);
394     QCOMPARE(false, obj1.stereo());
395     QVERIFY(!obj1.testOption(QGL::StereoBuffers));
396     QVERIFY(obj1.testOption(QGL::NoStereoBuffers));
397     obj1.setStereo(true);
398     QCOMPARE(true, obj1.stereo());
399     QVERIFY(obj1.testOption(QGL::StereoBuffers));
400     QVERIFY(!obj1.testOption(QGL::NoStereoBuffers));
401
402     // bool QGLFormat::directRendering()
403     // void QGLFormat::setDirectRendering(bool)
404     QCOMPARE(true, obj1.directRendering());
405     QVERIFY(obj1.testOption(QGL::DirectRendering));
406     QVERIFY(!obj1.testOption(QGL::IndirectRendering));
407     obj1.setDirectRendering(false);
408     QCOMPARE(false, obj1.directRendering());
409     QVERIFY(!obj1.testOption(QGL::DirectRendering));
410     QVERIFY(obj1.testOption(QGL::IndirectRendering));
411     obj1.setDirectRendering(true);
412     QCOMPARE(true, obj1.directRendering());
413     QVERIFY(obj1.testOption(QGL::DirectRendering));
414     QVERIFY(!obj1.testOption(QGL::IndirectRendering));
415
416     // bool QGLFormat::overlay()
417     // void QGLFormat::setOverlay(bool)
418     QCOMPARE(false, obj1.hasOverlay());
419     QVERIFY(!obj1.testOption(QGL::HasOverlay));
420     QVERIFY(obj1.testOption(QGL::NoOverlay));
421     obj1.setOverlay(false);
422     QCOMPARE(false, obj1.hasOverlay());
423     QVERIFY(!obj1.testOption(QGL::HasOverlay));
424     QVERIFY(obj1.testOption(QGL::NoOverlay));
425     obj1.setOverlay(true);
426     QCOMPARE(true, obj1.hasOverlay());
427     QVERIFY(obj1.testOption(QGL::HasOverlay));
428     QVERIFY(!obj1.testOption(QGL::NoOverlay));
429
430     // int QGLFormat::plane()
431     // void QGLFormat::setPlane(int)
432     QCOMPARE(0, obj1.plane());
433     obj1.setPlane(0);
434     QCOMPARE(0, obj1.plane());
435     obj1.setPlane(TEST_INT_MIN);
436     QCOMPARE(TEST_INT_MIN, obj1.plane());
437     obj1.setPlane(TEST_INT_MAX);
438     QCOMPARE(TEST_INT_MAX, obj1.plane());
439
440     // int QGLFormat::major/minorVersion()
441     // void QGLFormat::setVersion(int, int)
442     QCOMPARE(obj1.majorVersion(), 1);
443     QCOMPARE(obj1.minorVersion(), 0);
444     obj1.setVersion(3, 2);
445     QCOMPARE(obj1.majorVersion(), 3);
446     QCOMPARE(obj1.minorVersion(), 2);
447     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 0.1");
448     obj1.setVersion(0, 1);
449     QCOMPARE(obj1.majorVersion(), 3);
450     QCOMPARE(obj1.minorVersion(), 2);
451     QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 3.-1");
452     obj1.setVersion(3, -1);
453     QCOMPARE(obj1.majorVersion(), 3);
454     QCOMPARE(obj1.minorVersion(), 2);
455     obj1.setVersion(TEST_INT_MAX, TEST_INT_MAX - 1);
456     QCOMPARE(obj1.majorVersion(), TEST_INT_MAX);
457     QCOMPARE(obj1.minorVersion(), TEST_INT_MAX - 1);
458
459
460     // operator== and operator!= for QGLFormat
461     QGLFormat format1;
462     QGLFormat format2;
463
464     QVERIFY(format1 == format2);
465     QVERIFY(!(format1 != format2));
466     format1.setDoubleBuffer(false);
467     QVERIFY(!(format1 == format2));
468     QVERIFY(format1 != format2);
469     format2.setDoubleBuffer(false);
470     QVERIFY(format1 == format2);
471     QVERIFY(!(format1 != format2));
472
473     format1.setDepthBufferSize(8);
474     QVERIFY(!(format1 == format2));
475     QVERIFY(format1 != format2);
476     format2.setDepthBufferSize(8);
477     QVERIFY(format1 == format2);
478     QVERIFY(!(format1 != format2));
479
480     format1.setAccumBufferSize(8);
481     QVERIFY(!(format1 == format2));
482     QVERIFY(format1 != format2);
483     format2.setAccumBufferSize(8);
484     QVERIFY(format1 == format2);
485     QVERIFY(!(format1 != format2));
486
487     format1.setRedBufferSize(8);
488     QVERIFY(!(format1 == format2));
489     QVERIFY(format1 != format2);
490     format2.setRedBufferSize(8);
491     QVERIFY(format1 == format2);
492     QVERIFY(!(format1 != format2));
493
494     format1.setGreenBufferSize(8);
495     QVERIFY(!(format1 == format2));
496     QVERIFY(format1 != format2);
497     format2.setGreenBufferSize(8);
498     QVERIFY(format1 == format2);
499     QVERIFY(!(format1 != format2));
500
501     format1.setBlueBufferSize(8);
502     QVERIFY(!(format1 == format2));
503     QVERIFY(format1 != format2);
504     format2.setBlueBufferSize(8);
505     QVERIFY(format1 == format2);
506     QVERIFY(!(format1 != format2));
507
508     format1.setAlphaBufferSize(8);
509     QVERIFY(!(format1 == format2));
510     QVERIFY(format1 != format2);
511     format2.setAlphaBufferSize(8);
512     QVERIFY(format1 == format2);
513     QVERIFY(!(format1 != format2));
514
515     format1.setStencilBufferSize(8);
516     QVERIFY(!(format1 == format2));
517     QVERIFY(format1 != format2);
518     format2.setStencilBufferSize(8);
519     QVERIFY(format1 == format2);
520     QVERIFY(!(format1 != format2));
521
522     format1.setSamples(8);
523     QVERIFY(!(format1 == format2));
524     QVERIFY(format1 != format2);
525     format2.setSamples(8);
526     QVERIFY(format1 == format2);
527     QVERIFY(!(format1 != format2));
528
529     format1.setSwapInterval(8);
530     QVERIFY(!(format1 == format2));
531     QVERIFY(format1 != format2);
532     format2.setSwapInterval(8);
533     QVERIFY(format1 == format2);
534     QVERIFY(!(format1 != format2));
535
536     format1.setPlane(8);
537     QVERIFY(!(format1 == format2));
538     QVERIFY(format1 != format2);
539     format2.setPlane(8);
540     QVERIFY(format1 == format2);
541     QVERIFY(!(format1 != format2));
542
543     format1.setVersion(3, 2);
544     QVERIFY(!(format1 == format2));
545     QVERIFY(format1 != format2);
546     format2.setVersion(3, 2);
547     QVERIFY(format1 == format2);
548     QVERIFY(!(format1 != format2));
549
550     format1.setProfile(QGLFormat::CoreProfile);
551     QVERIFY(!(format1 == format2));
552     QVERIFY(format1 != format2);
553     format2.setProfile(QGLFormat::CoreProfile);
554     QVERIFY(format1 == format2);
555     QVERIFY(!(format1 != format2));
556
557     format1.setOption(QGL::NoDeprecatedFunctions);
558     QVERIFY(!(format1 == format2));
559     QVERIFY(format1 != format2);
560     format2.setOption(QGL::NoDeprecatedFunctions);
561     QVERIFY(format1 == format2);
562     QVERIFY(!(format1 != format2));
563
564     // Copy constructor and assignment for QGLFormat.
565     QGLFormat format3(format1);
566     QGLFormat format4;
567     QVERIFY(format1 == format3);
568     QVERIFY(format1 != format4);
569     format4 = format1;
570     QVERIFY(format1 == format4);
571
572     // Check that modifying a copy doesn't affect the original.
573     format3.setRedBufferSize(16);
574     format4.setPlane(16);
575     QCOMPARE(format1.redBufferSize(), 8);
576     QCOMPARE(format1.plane(), 8);
577
578     // Check the QGLFormat constructor that takes an option list.
579     QGLFormat format5
580         (QGL::DepthBuffer | QGL::StereoBuffers | QGL::ColorIndex, 3);
581     QVERIFY(format5.depth());
582     QVERIFY(format5.stereo());
583     QVERIFY(format5.doubleBuffer());        // From defaultFormat()
584     QVERIFY(!format5.hasOverlay());         // From defaultFormat()
585     QVERIFY(!format5.rgba());
586     QCOMPARE(format5.plane(), 3);
587
588     // The default format should be the same as QGLFormat().
589     QVERIFY(QGLFormat::defaultFormat() == QGLFormat());
590
591     // Modify the default format and check that it was changed.
592     QGLFormat::setDefaultFormat(format1);
593     QVERIFY(QGLFormat::defaultFormat() == format1);
594
595     // Restore the default format.
596     QGLFormat::setDefaultFormat(QGLFormat());
597     QVERIFY(QGLFormat::defaultFormat() == QGLFormat());
598
599     // Check the default overlay format's expected values.
600     QGLFormat overlay(QGLFormat::defaultOverlayFormat());
601     QCOMPARE(overlay.depthBufferSize(), -1);
602     QCOMPARE(overlay.accumBufferSize(), -1);
603     QCOMPARE(overlay.redBufferSize(), -1);
604     QCOMPARE(overlay.greenBufferSize(), -1);
605     QCOMPARE(overlay.blueBufferSize(), -1);
606     QCOMPARE(overlay.alphaBufferSize(), -1);
607     QCOMPARE(overlay.samples(), -1);
608     QCOMPARE(overlay.swapInterval(), -1);
609     QCOMPARE(overlay.plane(), 1);
610     QVERIFY(!overlay.sampleBuffers());
611     QVERIFY(!overlay.doubleBuffer());
612     QVERIFY(!overlay.depth());
613     QVERIFY(!overlay.rgba());
614     QVERIFY(!overlay.alpha());
615     QVERIFY(!overlay.accum());
616     QVERIFY(!overlay.stencil());
617     QVERIFY(!overlay.stereo());
618     QVERIFY(overlay.directRendering()); // Only option that should be on.
619     QVERIFY(!overlay.hasOverlay());     // Overlay doesn't need an overlay!
620
621     // Modify the default overlay format and check that it was changed.
622     QGLFormat::setDefaultOverlayFormat(format1);
623     QVERIFY(QGLFormat::defaultOverlayFormat() == format1);
624
625     // Restore the default overlay format.
626     QGLFormat::setDefaultOverlayFormat(overlay);
627     QVERIFY(QGLFormat::defaultOverlayFormat() == overlay);
628
629     MyGLContext obj2(obj1);
630     // bool QGLContext::windowCreated()
631     // void QGLContext::setWindowCreated(bool)
632     obj2.setWindowCreated(false);
633     QCOMPARE(false, obj2.windowCreated());
634     obj2.setWindowCreated(true);
635     QCOMPARE(true, obj2.windowCreated());
636
637     // bool QGLContext::initialized()
638     // void QGLContext::setInitialized(bool)
639     obj2.setInitialized(false);
640     QCOMPARE(false, obj2.initialized());
641     obj2.setInitialized(true);
642     QCOMPARE(true, obj2.initialized());
643
644     MyGLWidget obj3;
645     // bool QGLWidget::autoBufferSwap()
646     // void QGLWidget::setAutoBufferSwap(bool)
647     obj3.setAutoBufferSwap(false);
648     QCOMPARE(false, obj3.autoBufferSwap());
649     obj3.setAutoBufferSwap(true);
650     QCOMPARE(true, obj3.autoBufferSwap());
651 }
652
653 #ifdef QT_BUILD_INTERNAL
654 QT_BEGIN_NAMESPACE
655 extern QGLFormat::OpenGLVersionFlags qOpenGLVersionFlagsFromString(const QString &versionString);
656 QT_END_NAMESPACE
657 #endif
658
659 #ifdef QT_BUILD_INTERNAL
660 void tst_QGL::openGLVersionCheck()
661 {
662     QString versionString;
663     QGLFormat::OpenGLVersionFlags expectedFlag;
664     QGLFormat::OpenGLVersionFlags versionFlag;
665
666     versionString = "1.1 Irix 6.5";
667     expectedFlag = QGLFormat::OpenGL_Version_1_1;
668     versionFlag = qOpenGLVersionFlagsFromString(versionString);
669     QCOMPARE(versionFlag, expectedFlag);
670
671     versionString = "1.2 Microsoft";
672     expectedFlag = QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
673     versionFlag = qOpenGLVersionFlagsFromString(versionString);
674     QCOMPARE(versionFlag, expectedFlag);
675
676     versionString = "1.2.1";
677     expectedFlag = QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
678     versionFlag = qOpenGLVersionFlagsFromString(versionString);
679     QCOMPARE(versionFlag, expectedFlag);
680
681     versionString = "1.3 NVIDIA";
682     expectedFlag = QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
683     versionFlag = qOpenGLVersionFlagsFromString(versionString);
684     QCOMPARE(versionFlag, expectedFlag);
685
686     versionString = "1.4";
687     expectedFlag = QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
688     versionFlag = qOpenGLVersionFlagsFromString(versionString);
689     QCOMPARE(versionFlag, expectedFlag);
690
691     versionString = "1.5 NVIDIA";
692     expectedFlag = QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
693     versionFlag = qOpenGLVersionFlagsFromString(versionString);
694     QCOMPARE(versionFlag, expectedFlag);
695
696     versionString = "2.0.2 NVIDIA 87.62";
697     expectedFlag = QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
698     versionFlag = qOpenGLVersionFlagsFromString(versionString);
699     QCOMPARE(versionFlag, expectedFlag);
700
701     versionString = "2.1 NVIDIA";
702     expectedFlag = QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
703     versionFlag = qOpenGLVersionFlagsFromString(versionString);
704     QCOMPARE(versionFlag, expectedFlag);
705
706     versionString = "2.1";
707     expectedFlag = QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
708     versionFlag = qOpenGLVersionFlagsFromString(versionString);
709     QCOMPARE(versionFlag, expectedFlag);
710
711     versionString = "OpenGL ES-CM 1.0 ATI";
712     expectedFlag = QGLFormat::OpenGL_ES_Common_Version_1_0 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
713     versionFlag = qOpenGLVersionFlagsFromString(versionString);
714     QCOMPARE(versionFlag, expectedFlag);
715
716     versionString = "OpenGL ES-CL 1.0 ATI";
717     expectedFlag = QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
718     versionFlag = qOpenGLVersionFlagsFromString(versionString);
719     QCOMPARE(versionFlag, expectedFlag);
720
721     versionString = "OpenGL ES-CM 1.1 ATI";
722     expectedFlag = QGLFormat::OpenGL_ES_Common_Version_1_1 | QGLFormat::OpenGL_ES_CommonLite_Version_1_1 | QGLFormat::OpenGL_ES_Common_Version_1_0 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
723     versionFlag = qOpenGLVersionFlagsFromString(versionString);
724     QCOMPARE(versionFlag, expectedFlag);
725
726     versionString = "OpenGL ES-CL 1.1 ATI";
727     expectedFlag = QGLFormat::OpenGL_ES_CommonLite_Version_1_1 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
728     versionFlag = qOpenGLVersionFlagsFromString(versionString);
729     QCOMPARE(versionFlag, expectedFlag);
730
731     versionString = "OpenGL ES 2.0 ATI";
732     expectedFlag = QGLFormat::OpenGL_ES_Version_2_0;
733     versionFlag = qOpenGLVersionFlagsFromString(versionString);
734     QCOMPARE(versionFlag, expectedFlag);
735
736     versionString = "3.0";
737     expectedFlag = QGLFormat::OpenGL_Version_3_0 | QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
738     versionFlag = qOpenGLVersionFlagsFromString(versionString);
739     QCOMPARE(versionFlag, expectedFlag);
740
741     QGLWidget glWidget;
742     glWidget.show();
743     glWidget.makeCurrent();
744
745     // This is unfortunately the only test we can make on the actual openGLVersionFlags()
746     // However, the complicated parts are in openGLVersionFlags(const QString &versionString)
747     // tested above
748
749 #if defined(QT_OPENGL_ES_1)
750     QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Common_Version_1_0);
751 #elif defined(QT_OPENGL_ES_2)
752     QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0);
753 #else
754     QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_1);
755 #endif //defined(QT_OPENGL_ES_1)
756 }
757 #endif //QT_BUILD_INTERNAL
758
759 static bool fuzzyComparePixels(const QRgb testPixel, const QRgb refPixel, const char* file, int line, int x = -1, int y = -1)
760 {
761     static int maxFuzz = 1;
762     static bool maxFuzzSet = false;
763
764     // On 16 bpp systems, we need to allow for more fuzz:
765     if (!maxFuzzSet) {
766         maxFuzzSet = true;
767         if (appDefaultDepth() < 24)
768             maxFuzz = 32;
769     }
770
771     int redFuzz = qAbs(qRed(testPixel) - qRed(refPixel));
772     int greenFuzz = qAbs(qGreen(testPixel) - qGreen(refPixel));
773     int blueFuzz = qAbs(qBlue(testPixel) - qBlue(refPixel));
774     int alphaFuzz = qAbs(qAlpha(testPixel) - qAlpha(refPixel));
775
776     if (refPixel != 0 && testPixel == 0) {
777         QString msg;
778         if (x >= 0) {
779             msg = QString("Test pixel [%1, %2] is null (black) when it should be (%3,%4,%5,%6)")
780                             .arg(x).arg(y)
781                             .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
782         } else {
783             msg = QString("Test pixel is null (black) when it should be (%2,%3,%4,%5)")
784                             .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
785         }
786
787         QTest::qFail(msg.toLatin1(), file, line);
788         return false;
789     }
790
791     if (redFuzz > maxFuzz || greenFuzz > maxFuzz || blueFuzz > maxFuzz || alphaFuzz > maxFuzz) {
792         QString msg;
793
794         if (x >= 0)
795             msg = QString("Pixel [%1,%2]: ").arg(x).arg(y);
796         else
797             msg = QString("Pixel ");
798
799         msg += QString("Max fuzz (%1) exceeded: (%2,%3,%4,%5) vs (%6,%7,%8,%9)")
800                       .arg(maxFuzz)
801                       .arg(qRed(testPixel)).arg(qGreen(testPixel)).arg(qBlue(testPixel)).arg(qAlpha(testPixel))
802                       .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
803         QTest::qFail(msg.toLatin1(), file, line);
804         return false;
805     }
806     return true;
807 }
808
809 static void fuzzyCompareImages(const QImage &testImage, const QImage &referenceImage, const char* file, int line)
810 {
811     QCOMPARE(testImage.width(), referenceImage.width());
812     QCOMPARE(testImage.height(), referenceImage.height());
813
814     for (int y = 0; y < testImage.height(); y++) {
815         for (int x = 0; x < testImage.width(); x++) {
816             if (!fuzzyComparePixels(testImage.pixel(x, y), referenceImage.pixel(x, y), file, line, x, y)) {
817                 // Might as well save the images for easier debugging:
818                 referenceImage.save("referenceImage.png");
819                 testImage.save("testImage.png");
820                 return;
821             }
822         }
823     }
824 }
825
826 #define QFUZZY_COMPARE_IMAGES(A,B) \
827             fuzzyCompareImages(A, B, __FILE__, __LINE__)
828
829 #define QFUZZY_COMPARE_PIXELS(A,B) \
830             fuzzyComparePixels(A, B, __FILE__, __LINE__)
831
832 class UnclippedWidget : public QWidget
833 {
834 public:
835     void paintEvent(QPaintEvent *)
836     {
837         QPainter p(this);
838         p.fillRect(rect().adjusted(-1000, -1000, 1000, 1000), Qt::black);
839     }
840 };
841
842 void tst_QGL::graphicsViewClipping()
843 {
844     const int size = 64;
845     UnclippedWidget *widget = new UnclippedWidget;
846     widget->setFixedSize(size, size);
847
848     QGraphicsScene scene;
849
850     scene.addWidget(widget)->setPos(0, 0);
851
852     QGraphicsView view(&scene);
853     // Use Qt::Tool as fully decorated windows have a minimum width of 160 on Windows.
854     view.setWindowFlags(view.windowFlags() | Qt::Tool);
855     view.setBackgroundBrush(Qt::white);
856     view.resize(2*size, 2*size);
857
858     QGLWidget *viewport = new QGLWidget;
859     view.setViewport(viewport);
860     view.show();
861     qApp->setActiveWindow(&view);
862
863     if (!viewport->isValid())
864         return;
865
866     scene.setSceneRect(view.viewport()->rect());
867
868     QVERIFY(QTest::qWaitForWindowActive(&view));
869
870     QImage image = viewport->grabFrameBuffer();
871     QImage expected = image;
872
873     QPainter p(&expected);
874     p.fillRect(expected.rect(), Qt::white);
875     p.fillRect(QRect(0, 0, size, size), Qt::black);
876     p.end();
877
878     QFUZZY_COMPARE_IMAGES(image, expected);
879 }
880
881 void tst_QGL::partialGLWidgetUpdates_data()
882 {
883     QTest::addColumn<bool>("doubleBufferedContext");
884     QTest::addColumn<bool>("autoFillBackground");
885     QTest::addColumn<bool>("supportsPartialUpdates");
886
887     QTest::newRow("Double buffered context") << true << true << false;
888     QTest::newRow("Double buffered context without auto-fill background") << true << false << false;
889     QTest::newRow("Single buffered context") << false << true << false;
890     QTest::newRow("Single buffered context without auto-fill background") << false << false << true;
891 }
892
893 void tst_QGL::partialGLWidgetUpdates()
894 {
895     QFETCH(bool, doubleBufferedContext);
896     QFETCH(bool, autoFillBackground);
897     QFETCH(bool, supportsPartialUpdates);
898
899     class MyGLWidget : public QGLWidget
900     {
901         public:
902             QRegion paintEventRegion;
903             void paintEvent(QPaintEvent *e)
904             {
905                 paintEventRegion = e->region();
906             }
907     };
908
909     QGLFormat format = QGLFormat::defaultFormat();
910     format.setDoubleBuffer(doubleBufferedContext);
911     QGLFormat::setDefaultFormat(format);
912
913     MyGLWidget widget;
914     widget.setFixedSize(150, 150);
915     widget.setAutoFillBackground(autoFillBackground);
916     widget.show();
917
918     QTest::qWait(200);
919
920     if (widget.format().doubleBuffer() != doubleBufferedContext)
921         QSKIP("Platform does not support requested format");
922
923     widget.paintEventRegion = QRegion();
924     widget.repaint(50, 50, 50, 50);
925
926     if (supportsPartialUpdates)
927         QCOMPARE(widget.paintEventRegion, QRegion(50, 50, 50, 50));
928     else
929         QCOMPARE(widget.paintEventRegion, QRegion(widget.rect()));
930 }
931
932
933 // This tests that rendering to a QGLPBuffer using QPainter works.
934 void tst_QGL::glPBufferRendering()
935 {
936     if (!QGLPixelBuffer::hasOpenGLPbuffers())
937         QSKIP("QGLPixelBuffer not supported on this platform");
938
939     QGLPixelBuffer* pbuf = new QGLPixelBuffer(128, 128);
940
941     QPainter p;
942     bool begun = p.begin(pbuf);
943     QVERIFY(begun);
944
945     QPaintEngine::Type engineType = p.paintEngine()->type();
946     QVERIFY(engineType == QPaintEngine::OpenGL || engineType == QPaintEngine::OpenGL2);
947
948     p.fillRect(0, 0, 128, 128, Qt::red);
949     p.fillRect(32, 32, 64, 64, Qt::blue);
950     p.end();
951
952     QImage fb = pbuf->toImage();
953     delete pbuf;
954
955     QImage reference(128, 128, fb.format());
956     p.begin(&reference);
957     p.fillRect(0, 0, 128, 128, Qt::red);
958     p.fillRect(32, 32, 64, 64, Qt::blue);
959     p.end();
960
961     QFUZZY_COMPARE_IMAGES(fb, reference);
962 }
963
964 void tst_QGL::glWidgetWithAlpha()
965 {
966     QGLWidget* w = new QGLWidget(QGLFormat(QGL::AlphaChannel));
967     w->show();
968     QVERIFY(QTest::qWaitForWindowExposed(w));
969
970     delete w;
971 }
972
973
974 void qt_opengl_draw_test_pattern(QPainter* painter, int width, int height)
975 {
976     QPainterPath intersectingPath;
977     intersectingPath.moveTo(0, 0);
978     intersectingPath.lineTo(100, 0);
979     intersectingPath.lineTo(0, 100);
980     intersectingPath.lineTo(100, 100);
981     intersectingPath.closeSubpath();
982
983     QPainterPath trianglePath;
984     trianglePath.moveTo(50, 0);
985     trianglePath.lineTo(100, 100);
986     trianglePath.lineTo(0, 100);
987     trianglePath.closeSubpath();
988
989     painter->setTransform(QTransform()); // reset xform
990     painter->fillRect(-1, -1, width+2, height+2, Qt::red); // Background
991     painter->translate(14, 14);
992     painter->fillPath(intersectingPath, Qt::blue); // Test stencil buffer works
993     painter->translate(128, 0);
994     painter->setClipPath(trianglePath); // Test depth buffer works
995     painter->setTransform(QTransform()); // reset xform ready for fill
996     painter->fillRect(-1, -1, width+2, height+2, Qt::green);
997 }
998
999 void qt_opengl_check_test_pattern(const QImage& img)
1000 {
1001     // As we're doing more than trivial painting, we can't just compare to
1002     // an image rendered with raster. Instead, we sample at well-defined
1003     // test-points:
1004     QFUZZY_COMPARE_PIXELS(img.pixel(39, 64), QColor(Qt::red).rgb());
1005     QFUZZY_COMPARE_PIXELS(img.pixel(89, 64), QColor(Qt::red).rgb());
1006     QFUZZY_COMPARE_PIXELS(img.pixel(64, 39), QColor(Qt::blue).rgb());
1007     QFUZZY_COMPARE_PIXELS(img.pixel(64, 89), QColor(Qt::blue).rgb());
1008
1009     QFUZZY_COMPARE_PIXELS(img.pixel(167, 39), QColor(Qt::red).rgb());
1010     QFUZZY_COMPARE_PIXELS(img.pixel(217, 39), QColor(Qt::red).rgb());
1011     QFUZZY_COMPARE_PIXELS(img.pixel(192, 64), QColor(Qt::green).rgb());
1012 }
1013
1014 class GLWidget : public QGLWidget
1015 {
1016 public:
1017     GLWidget(QWidget* p = 0)
1018             : QGLWidget(p), beginOk(false), engineType(QPaintEngine::MaxUser) {}
1019     bool beginOk;
1020     QPaintEngine::Type engineType;
1021     void paintGL()
1022     {
1023         QPainter p;
1024         beginOk = p.begin(this);
1025         QPaintEngine* pe = p.paintEngine();
1026         engineType = pe->type();
1027
1028         qt_opengl_draw_test_pattern(&p, width(), height());
1029
1030         // No p.end() or swap buffers, should be done automatically
1031     }
1032
1033 };
1034
1035 void tst_QGL::glWidgetRendering()
1036 {
1037     GLWidget w;
1038     w.resize(256, 128);
1039     w.show();
1040
1041     QVERIFY(QTest::qWaitForWindowExposed(&w));
1042
1043     QVERIFY(w.beginOk);
1044     QVERIFY(w.engineType == QPaintEngine::OpenGL || w.engineType == QPaintEngine::OpenGL2);
1045
1046     QImage fb = w.grabFrameBuffer(false);
1047     qt_opengl_check_test_pattern(fb);
1048 }
1049
1050 void tst_QGL::glFBOSimpleRendering()
1051 {
1052     if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
1053         QSKIP("QGLFramebufferObject not supported on this platform");
1054
1055     QGLWidget glw;
1056     glw.makeCurrent();
1057
1058     // No multisample with combined depth/stencil attachment:
1059     QGLFramebufferObjectFormat fboFormat;
1060     fboFormat.setAttachment(QGLFramebufferObject::NoAttachment);
1061
1062     QGLFramebufferObject *fbo = new QGLFramebufferObject(200, 100, fboFormat);
1063
1064     fbo->bind();
1065
1066     glClearColor(1.0, 0.0, 0.0, 1.0);
1067     glClear(GL_COLOR_BUFFER_BIT);
1068     glFinish();
1069
1070     QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
1071     QImage reference(fb.size(), QImage::Format_RGB32);
1072     reference.fill(0xffff0000);
1073
1074     QFUZZY_COMPARE_IMAGES(fb, reference);
1075
1076     delete fbo;
1077 }
1078
1079 // NOTE: This tests that CombinedDepthStencil attachment works by assuming the
1080 //       GL2 engine is being used and is implemented the same way as it was when
1081 //       this autotest was written. If this is not the case, there may be some
1082 //       false-positives: I.e. The test passes when either the depth or stencil
1083 //       buffer is actually missing. But that's probably ok anyway.
1084 void tst_QGL::glFBORendering()
1085 {
1086     if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
1087         QSKIP("QGLFramebufferObject not supported on this platform");
1088
1089     QGLWidget glw;
1090     glw.makeCurrent();
1091
1092     // No multisample with combined depth/stencil attachment:
1093     QGLFramebufferObjectFormat fboFormat;
1094     fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
1095
1096     // Don't complicate things by using NPOT:
1097     QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);
1098
1099     if (fbo->attachment() != QGLFramebufferObject::CombinedDepthStencil) {
1100         delete fbo;
1101         QSKIP("FBOs missing combined depth~stencil support");
1102     }
1103
1104     QPainter fboPainter;
1105     bool painterBegun = fboPainter.begin(fbo);
1106     QVERIFY(painterBegun);
1107
1108     qt_opengl_draw_test_pattern(&fboPainter, fbo->width(), fbo->height());
1109
1110     fboPainter.end();
1111
1112     QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
1113     delete fbo;
1114
1115     qt_opengl_check_test_pattern(fb);
1116 }
1117
1118
1119 // Tests multiple QPainters active on different FBOs at the same time, with
1120 // interleaving painting. Performance-wise, this is sub-optimal, but it still
1121 // has to work flawlessly
1122 void tst_QGL::multipleFBOInterleavedRendering()
1123 {
1124     if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
1125         QSKIP("QGLFramebufferObject not supported on this platform");
1126
1127     QGLWidget glw;
1128     glw.makeCurrent();
1129
1130     // No multisample with combined depth/stencil attachment:
1131     QGLFramebufferObjectFormat fboFormat;
1132     fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
1133
1134     QGLFramebufferObject *fbo1 = new QGLFramebufferObject(256, 128, fboFormat);
1135     QGLFramebufferObject *fbo2 = new QGLFramebufferObject(256, 128, fboFormat);
1136     QGLFramebufferObject *fbo3 = new QGLFramebufferObject(256, 128, fboFormat);
1137
1138     if ( (fbo1->attachment() != QGLFramebufferObject::CombinedDepthStencil) ||
1139          (fbo2->attachment() != QGLFramebufferObject::CombinedDepthStencil) ||
1140          (fbo3->attachment() != QGLFramebufferObject::CombinedDepthStencil)    )
1141     {
1142         delete fbo1;
1143         delete fbo2;
1144         delete fbo3;
1145         QSKIP("FBOs missing combined depth~stencil support");
1146     }
1147
1148     QPainter fbo1Painter;
1149     QPainter fbo2Painter;
1150     QPainter fbo3Painter;
1151
1152     QVERIFY(fbo1Painter.begin(fbo1));
1153     QVERIFY(fbo2Painter.begin(fbo2));
1154     QVERIFY(fbo3Painter.begin(fbo3));
1155
1156     // Confirm we're using the GL2 engine, as interleaved rendering isn't supported
1157     // on the GL1 engine:
1158     if (fbo1Painter.paintEngine()->type() != QPaintEngine::OpenGL2)
1159         QSKIP("Interleaved GL rendering requires OpenGL 2.0 or higher");
1160
1161     QPainterPath intersectingPath;
1162     intersectingPath.moveTo(0, 0);
1163     intersectingPath.lineTo(100, 0);
1164     intersectingPath.lineTo(0, 100);
1165     intersectingPath.lineTo(100, 100);
1166     intersectingPath.closeSubpath();
1167
1168     QPainterPath trianglePath;
1169     trianglePath.moveTo(50, 0);
1170     trianglePath.lineTo(100, 100);
1171     trianglePath.lineTo(0, 100);
1172     trianglePath.closeSubpath();
1173
1174     fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::red); // Background
1175     fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::green); // Background
1176     fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::blue); // Background
1177
1178     fbo1Painter.translate(14, 14);
1179     fbo2Painter.translate(14, 14);
1180     fbo3Painter.translate(14, 14);
1181
1182     fbo1Painter.fillPath(intersectingPath, Qt::blue); // Test stencil buffer works
1183     fbo2Painter.fillPath(intersectingPath, Qt::red); // Test stencil buffer works
1184     fbo3Painter.fillPath(intersectingPath, Qt::green); // Test stencil buffer works
1185
1186     fbo1Painter.translate(128, 0);
1187     fbo2Painter.translate(128, 0);
1188     fbo3Painter.translate(128, 0);
1189
1190     fbo1Painter.setClipPath(trianglePath);
1191     fbo2Painter.setClipPath(trianglePath);
1192     fbo3Painter.setClipPath(trianglePath);
1193
1194     fbo1Painter.setTransform(QTransform()); // reset xform
1195     fbo2Painter.setTransform(QTransform()); // reset xform
1196     fbo3Painter.setTransform(QTransform()); // reset xform
1197
1198     fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::green);
1199     fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::blue);
1200     fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::red);
1201
1202     fbo1Painter.end();
1203     fbo2Painter.end();
1204     fbo3Painter.end();
1205
1206     QImage fb1 = fbo1->toImage().convertToFormat(QImage::Format_RGB32);
1207     QImage fb2 = fbo2->toImage().convertToFormat(QImage::Format_RGB32);
1208     QImage fb3 = fbo3->toImage().convertToFormat(QImage::Format_RGB32);
1209     delete fbo1;
1210     delete fbo2;
1211     delete fbo3;
1212
1213     // As we're doing more than trivial painting, we can't just compare to
1214     // an image rendered with raster. Instead, we sample at well-defined
1215     // test-points:
1216     QFUZZY_COMPARE_PIXELS(fb1.pixel(39, 64), QColor(Qt::red).rgb());
1217     QFUZZY_COMPARE_PIXELS(fb1.pixel(89, 64), QColor(Qt::red).rgb());
1218     QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 39), QColor(Qt::blue).rgb());
1219     QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 89), QColor(Qt::blue).rgb());
1220     QFUZZY_COMPARE_PIXELS(fb1.pixel(167, 39), QColor(Qt::red).rgb());
1221     QFUZZY_COMPARE_PIXELS(fb1.pixel(217, 39), QColor(Qt::red).rgb());
1222     QFUZZY_COMPARE_PIXELS(fb1.pixel(192, 64), QColor(Qt::green).rgb());
1223
1224     QFUZZY_COMPARE_PIXELS(fb2.pixel(39, 64), QColor(Qt::green).rgb());
1225     QFUZZY_COMPARE_PIXELS(fb2.pixel(89, 64), QColor(Qt::green).rgb());
1226     QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 39), QColor(Qt::red).rgb());
1227     QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 89), QColor(Qt::red).rgb());
1228     QFUZZY_COMPARE_PIXELS(fb2.pixel(167, 39), QColor(Qt::green).rgb());
1229     QFUZZY_COMPARE_PIXELS(fb2.pixel(217, 39), QColor(Qt::green).rgb());
1230     QFUZZY_COMPARE_PIXELS(fb2.pixel(192, 64), QColor(Qt::blue).rgb());
1231
1232     QFUZZY_COMPARE_PIXELS(fb3.pixel(39, 64), QColor(Qt::blue).rgb());
1233     QFUZZY_COMPARE_PIXELS(fb3.pixel(89, 64), QColor(Qt::blue).rgb());
1234     QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 39), QColor(Qt::green).rgb());
1235     QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 89), QColor(Qt::green).rgb());
1236     QFUZZY_COMPARE_PIXELS(fb3.pixel(167, 39), QColor(Qt::blue).rgb());
1237     QFUZZY_COMPARE_PIXELS(fb3.pixel(217, 39), QColor(Qt::blue).rgb());
1238     QFUZZY_COMPARE_PIXELS(fb3.pixel(192, 64), QColor(Qt::red).rgb());
1239 }
1240
1241 class FBOUseInGLWidget : public QGLWidget
1242 {
1243 public:
1244     bool widgetPainterBeginOk;
1245     bool fboPainterBeginOk;
1246     QImage fboImage;
1247 protected:
1248     void paintEvent(QPaintEvent*)
1249     {
1250         QPainter widgetPainter;
1251         widgetPainterBeginOk = widgetPainter.begin(this);
1252         QGLFramebufferObjectFormat fboFormat;
1253         fboFormat.setAttachment(QGLFramebufferObject::NoAttachment);
1254         QGLFramebufferObject *fbo = new QGLFramebufferObject(100, 100, fboFormat);
1255
1256         QPainter fboPainter;
1257         fboPainterBeginOk = fboPainter.begin(fbo);
1258         fboPainter.fillRect(-1, -1, 130, 130, Qt::red);
1259         fboPainter.end();
1260         fboImage = fbo->toImage();
1261
1262         widgetPainter.fillRect(-1, -1, width()+2, width()+2, Qt::blue);
1263
1264         delete fbo;
1265     }
1266
1267 };
1268
1269 void tst_QGL::glFBOUseInGLWidget()
1270 {
1271     if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
1272         QSKIP("QGLFramebufferObject not supported on this platform");
1273
1274     FBOUseInGLWidget w;
1275     w.resize(100, 100);
1276     w.show();
1277
1278     QVERIFY(QTest::qWaitForWindowExposed(&w));
1279
1280     QVERIFY(w.widgetPainterBeginOk);
1281     QVERIFY(w.fboPainterBeginOk);
1282
1283     QImage widgetFB = w.grabFrameBuffer(false);
1284     QImage widgetReference(widgetFB.size(), widgetFB.format());
1285     widgetReference.fill(0xff0000ff);
1286     QFUZZY_COMPARE_IMAGES(widgetFB, widgetReference);
1287
1288     QImage fboReference(w.fboImage.size(), w.fboImage.format());
1289     fboReference.fill(0xffff0000);
1290     QFUZZY_COMPARE_IMAGES(w.fboImage, fboReference);
1291 }
1292
1293 void tst_QGL::glWidgetReparent()
1294 {
1295     // Try it as a top-level first:
1296     GLWidget *widget = new GLWidget;
1297     widget->setGeometry(0, 0, 200, 30);
1298     widget->show();
1299
1300     QWidget grandParentWidget;
1301     grandParentWidget.setPalette(Qt::blue);
1302     QVBoxLayout grandParentLayout(&grandParentWidget);
1303
1304     QWidget parentWidget(&grandParentWidget);
1305     grandParentLayout.addWidget(&parentWidget);
1306     parentWidget.setPalette(Qt::green);
1307     parentWidget.setAutoFillBackground(true);
1308     QVBoxLayout parentLayout(&parentWidget);
1309
1310     grandParentWidget.setGeometry(0, 100, 200, 200);
1311     grandParentWidget.show();
1312
1313     QVERIFY(QTest::qWaitForWindowExposed(widget));
1314     QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
1315
1316     QVERIFY(parentWidget.children().count() == 1); // The layout
1317
1318     // Now both widgets should be created & shown, time to re-parent:
1319     parentLayout.addWidget(widget);
1320
1321     QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
1322
1323     QVERIFY(parentWidget.children().count() == 2); // Layout & glwidget
1324     QVERIFY(parentWidget.children().contains(widget));
1325     QTRY_VERIFY(widget->height() > 30);
1326
1327     delete widget;
1328
1329     QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
1330
1331     QVERIFY(parentWidget.children().count() == 1); // The layout
1332
1333     // Now do pretty much the same thing, but don't show the
1334     // widget first:
1335     widget = new GLWidget;
1336     parentLayout.addWidget(widget);
1337
1338     QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
1339
1340     QVERIFY(parentWidget.children().count() == 2); // Layout & glwidget
1341     QVERIFY(parentWidget.children().contains(widget));
1342     QVERIFY(widget->height() > 30);
1343
1344     delete widget;
1345 }
1346
1347 class RenderPixmapWidget : public QGLWidget
1348 {
1349 protected:
1350     void initializeGL() {
1351         // Set some gl state:
1352         glClearColor(1.0, 0.0, 0.0, 1.0);
1353     }
1354
1355     void paintGL() {
1356         glClear(GL_COLOR_BUFFER_BIT);
1357     }
1358 };
1359
1360 void tst_QGL::glWidgetRenderPixmap()
1361 {
1362     RenderPixmapWidget *w = new RenderPixmapWidget;
1363
1364     QPixmap pm = w->renderPixmap(100, 100, false);
1365
1366     delete w;
1367
1368     QImage fb = pm.toImage().convertToFormat(QImage::Format_RGB32);
1369     QImage reference(fb.size(), QImage::Format_RGB32);
1370     reference.fill(0xffff0000);
1371
1372     QFUZZY_COMPARE_IMAGES(fb, reference);
1373 }
1374
1375 class ColormapExtended : public QGLColormap
1376 {
1377 public:
1378     ColormapExtended() {}
1379
1380     Qt::HANDLE handle() { return QGLColormap::handle(); }
1381     void setHandle(Qt::HANDLE handle) { QGLColormap::setHandle(handle); }
1382 };
1383
1384 void tst_QGL::colormap()
1385 {
1386     // Check the properties of the default empty colormap.
1387     QGLColormap cmap1;
1388     QVERIFY(cmap1.isEmpty());
1389     QCOMPARE(cmap1.size(), 0);
1390     QVERIFY(cmap1.entryRgb(0) == 0);
1391     QVERIFY(cmap1.entryRgb(-1) == 0);
1392     QVERIFY(cmap1.entryRgb(100) == 0);
1393     QVERIFY(!cmap1.entryColor(0).isValid());
1394     QVERIFY(!cmap1.entryColor(-1).isValid());
1395     QVERIFY(!cmap1.entryColor(100).isValid());
1396     QCOMPARE(cmap1.find(qRgb(255, 0, 0)), -1);
1397     QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), -1);
1398
1399     // Set an entry and re-test.
1400     cmap1.setEntry(56, qRgb(255, 0, 0));
1401     // The colormap is still considered "empty" even though it
1402     // has entries in it now.  The isEmpty() method is used to
1403     // detect when the colormap is in use by a GL widget,
1404     // not to detect when it is empty!
1405     QVERIFY(cmap1.isEmpty());
1406     QCOMPARE(cmap1.size(), 256);
1407     QVERIFY(cmap1.entryRgb(0) == 0);
1408     QVERIFY(cmap1.entryColor(0) == QColor(0, 0, 0, 255));
1409     QVERIFY(cmap1.entryRgb(56) == qRgb(255, 0, 0));
1410     QVERIFY(cmap1.entryColor(56) == QColor(255, 0, 0, 255));
1411     QCOMPARE(cmap1.find(qRgb(255, 0, 0)), 56);
1412     QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), 56);
1413
1414     // Set some more entries.
1415     static QRgb const colors[] = {
1416         qRgb(255, 0, 0),
1417         qRgb(0, 255, 0),
1418         qRgb(255, 255, 255),
1419         qRgb(0, 0, 255),
1420         qRgb(0, 0, 0)
1421     };
1422     cmap1.setEntry(57, QColor(0, 255, 0));
1423     cmap1.setEntries(3, colors + 2, 58);
1424     cmap1.setEntries(5, colors, 251);
1425     int idx;
1426     for (idx = 0; idx < 5; ++idx) {
1427         QVERIFY(cmap1.entryRgb(56 + idx) == colors[idx]);
1428         QVERIFY(cmap1.entryColor(56 + idx) == QColor(colors[idx]));
1429         QVERIFY(cmap1.entryRgb(251 + idx) == colors[idx]);
1430         QVERIFY(cmap1.entryColor(251 + idx) == QColor(colors[idx]));
1431     }
1432     QCOMPARE(cmap1.size(), 256);
1433
1434     // Perform color lookups.
1435     QCOMPARE(cmap1.find(qRgb(255, 0, 0)), 56);
1436     QCOMPARE(cmap1.find(qRgb(0, 0, 0)), 60); // Actually finds 0, 0, 0, 255.
1437     QCOMPARE(cmap1.find(qRgba(0, 0, 0, 0)), 0);
1438     QCOMPARE(cmap1.find(qRgb(0, 255, 0)), 57);
1439     QCOMPARE(cmap1.find(qRgb(255, 255, 255)), 58);
1440     QCOMPARE(cmap1.find(qRgb(0, 0, 255)), 59);
1441     QCOMPARE(cmap1.find(qRgb(140, 0, 0)), -1);
1442     QCOMPARE(cmap1.find(qRgb(0, 140, 0)), -1);
1443     QCOMPARE(cmap1.find(qRgb(0, 0, 140)), -1);
1444     QCOMPARE(cmap1.find(qRgb(64, 0, 0)), -1);
1445     QCOMPARE(cmap1.find(qRgb(0, 64, 0)), -1);
1446     QCOMPARE(cmap1.find(qRgb(0, 0, 64)), -1);
1447     QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), 56);
1448     QCOMPARE(cmap1.findNearest(qRgb(0, 0, 0)), 60);
1449     QCOMPARE(cmap1.findNearest(qRgba(0, 0, 0, 0)), 0);
1450     QCOMPARE(cmap1.findNearest(qRgb(0, 255, 0)), 57);
1451     QCOMPARE(cmap1.findNearest(qRgb(255, 255, 255)), 58);
1452     QCOMPARE(cmap1.findNearest(qRgb(0, 0, 255)), 59);
1453     QCOMPARE(cmap1.findNearest(qRgb(140, 0, 0)), 56);
1454     QCOMPARE(cmap1.findNearest(qRgb(0, 140, 0)), 57);
1455     QCOMPARE(cmap1.findNearest(qRgb(0, 0, 140)), 59);
1456     QCOMPARE(cmap1.findNearest(qRgb(64, 0, 0)), 0);
1457     QCOMPARE(cmap1.findNearest(qRgb(0, 64, 0)), 0);
1458     QCOMPARE(cmap1.findNearest(qRgb(0, 0, 64)), 0);
1459
1460     // Make some copies of the colormap and check that they are the same.
1461     QGLColormap cmap2(cmap1);
1462     QGLColormap cmap3;
1463     cmap3 = cmap1;
1464     QVERIFY(cmap2.isEmpty());
1465     QVERIFY(cmap3.isEmpty());
1466     QCOMPARE(cmap2.size(), 256);
1467     QCOMPARE(cmap3.size(), 256);
1468     for (idx = 0; idx < 256; ++idx) {
1469         QCOMPARE(cmap1.entryRgb(idx), cmap2.entryRgb(idx));
1470         QCOMPARE(cmap1.entryRgb(idx), cmap3.entryRgb(idx));
1471     }
1472
1473     // Modify an entry in one of the copies and recheck the original.
1474     cmap2.setEntry(45, qRgb(255, 0, 0));
1475     for (idx = 0; idx < 256; ++idx) {
1476         if (idx != 45)
1477             QCOMPARE(cmap1.entryRgb(idx), cmap2.entryRgb(idx));
1478         else
1479             QCOMPARE(cmap2.entryRgb(45), qRgb(255, 0, 0));
1480         QCOMPARE(cmap1.entryRgb(idx), cmap3.entryRgb(idx));
1481     }
1482
1483     // Check that setting the handle will cause isEmpty() to work right.
1484     ColormapExtended cmap4;
1485     cmap4.setEntry(56, qRgb(255, 0, 0));
1486     QVERIFY(cmap4.isEmpty());
1487     QCOMPARE(cmap4.size(), 256);
1488     cmap4.setHandle(Qt::HANDLE(42));
1489     QVERIFY(cmap4.handle() == Qt::HANDLE(42));
1490     QVERIFY(!cmap4.isEmpty());
1491     QCOMPARE(cmap4.size(), 256);
1492 }
1493
1494 #ifndef QT_OPENGL_ES
1495 #define DEFAULT_FORMAT GL_RGBA8
1496 #else
1497 #define DEFAULT_FORMAT GL_RGBA
1498 #endif
1499
1500 #ifndef GL_TEXTURE_3D
1501 #define GL_TEXTURE_3D 0x806F
1502 #endif
1503
1504 #ifndef GL_RGB16
1505 #define GL_RGB16 0x8054
1506 #endif
1507
1508 void tst_QGL::fboFormat()
1509 {
1510     // Check the initial conditions.
1511     QGLFramebufferObjectFormat format1;
1512     QCOMPARE(format1.samples(), 0);
1513     QVERIFY(format1.attachment() == QGLFramebufferObject::NoAttachment);
1514     QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_2D));
1515     QCOMPARE(int(format1.internalTextureFormat()), int(DEFAULT_FORMAT));
1516
1517     // Modify the values and re-check.
1518     format1.setSamples(8);
1519     format1.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
1520     format1.setTextureTarget(GL_TEXTURE_3D);
1521     format1.setInternalTextureFormat(GL_RGB16);
1522     QCOMPARE(format1.samples(), 8);
1523     QVERIFY(format1.attachment() == QGLFramebufferObject::CombinedDepthStencil);
1524     QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_3D));
1525     QCOMPARE(int(format1.internalTextureFormat()), int(GL_RGB16));
1526
1527     // Make copies and check that they are the same.
1528     QGLFramebufferObjectFormat format2(format1);
1529     QGLFramebufferObjectFormat format3;
1530     QCOMPARE(format2.samples(), 8);
1531     QVERIFY(format2.attachment() == QGLFramebufferObject::CombinedDepthStencil);
1532     QCOMPARE(int(format2.textureTarget()), int(GL_TEXTURE_3D));
1533     QCOMPARE(int(format2.internalTextureFormat()), int(GL_RGB16));
1534     format3 = format1;
1535     QCOMPARE(format3.samples(), 8);
1536     QVERIFY(format3.attachment() == QGLFramebufferObject::CombinedDepthStencil);
1537     QCOMPARE(int(format3.textureTarget()), int(GL_TEXTURE_3D));
1538     QCOMPARE(int(format3.internalTextureFormat()), int(GL_RGB16));
1539
1540     // Modify the copies and check that the original is unchanged.
1541     format2.setSamples(9);
1542     format3.setTextureTarget(GL_TEXTURE_2D);
1543     QCOMPARE(format1.samples(), 8);
1544     QVERIFY(format1.attachment() == QGLFramebufferObject::CombinedDepthStencil);
1545     QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_3D));
1546     QCOMPARE(int(format1.internalTextureFormat()), int(GL_RGB16));
1547
1548     // operator== and operator!= for QGLFramebufferObjectFormat.
1549     QGLFramebufferObjectFormat format1c;
1550     QGLFramebufferObjectFormat format2c;
1551
1552     QVERIFY(format1c == format2c);
1553     QVERIFY(!(format1c != format2c));
1554     format1c.setSamples(8);
1555     QVERIFY(!(format1c == format2c));
1556     QVERIFY(format1c != format2c);
1557     format2c.setSamples(8);
1558     QVERIFY(format1c == format2c);
1559     QVERIFY(!(format1c != format2c));
1560
1561     format1c.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
1562     QVERIFY(!(format1c == format2c));
1563     QVERIFY(format1c != format2c);
1564     format2c.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
1565     QVERIFY(format1c == format2c);
1566     QVERIFY(!(format1c != format2c));
1567
1568     format1c.setTextureTarget(GL_TEXTURE_3D);
1569     QVERIFY(!(format1c == format2c));
1570     QVERIFY(format1c != format2c);
1571     format2c.setTextureTarget(GL_TEXTURE_3D);
1572     QVERIFY(format1c == format2c);
1573     QVERIFY(!(format1c != format2c));
1574
1575     format1c.setInternalTextureFormat(GL_RGB16);
1576     QVERIFY(!(format1c == format2c));
1577     QVERIFY(format1c != format2c);
1578     format2c.setInternalTextureFormat(GL_RGB16);
1579     QVERIFY(format1c == format2c);
1580     QVERIFY(!(format1c != format2c));
1581
1582     QGLFramebufferObjectFormat format3c(format1c);
1583     QGLFramebufferObjectFormat format4c;
1584     QVERIFY(format1c == format3c);
1585     QVERIFY(!(format1c != format3c));
1586     format3c.setInternalTextureFormat(DEFAULT_FORMAT);
1587     QVERIFY(!(format1c == format3c));
1588     QVERIFY(format1c != format3c);
1589
1590     format4c = format1c;
1591     QVERIFY(format1c == format4c);
1592     QVERIFY(!(format1c != format4c));
1593     format4c.setInternalTextureFormat(DEFAULT_FORMAT);
1594     QVERIFY(!(format1c == format4c));
1595     QVERIFY(format1c != format4c);
1596 }
1597
1598 void tst_QGL::testDontCrashOnDanglingResources()
1599 {
1600     // We have a number of Q_GLOBAL_STATICS inside the QtOpenGL
1601     // library. This test is verify that we don't crash as a result of
1602     // them calling into libgl on application shutdown.
1603     QWidget *widget = new UnclippedWidget();
1604     widget->show();
1605     qApp->processEvents();
1606     widget->hide();
1607 }
1608
1609 class ReplaceClippingGLWidget : public QGLWidget
1610 {
1611 public:
1612     void paint(QPainter *painter)
1613     {
1614         painter->fillRect(rect(), Qt::white);
1615
1616         QPainterPath path;
1617         path.addRect(0, 0, 100, 100);
1618         path.addRect(50, 50, 100, 100);
1619
1620         painter->setClipRect(0, 0, 150, 150);
1621         painter->fillPath(path, Qt::red);
1622
1623         painter->translate(150, 150);
1624         painter->setClipRect(0, 0, 150, 150);
1625         painter->fillPath(path, Qt::red);
1626     }
1627
1628 protected:
1629     void paintEvent(QPaintEvent*)
1630     {
1631         // clear the stencil with junk
1632         glStencilMask(0xFFFF);
1633         glClearStencil(0xFFFF);
1634         glDisable(GL_STENCIL_TEST);
1635         glDisable(GL_SCISSOR_TEST);
1636         glClear(GL_STENCIL_BUFFER_BIT);
1637
1638         QPainter painter(this);
1639         paint(&painter);
1640     }
1641 };
1642
1643 void tst_QGL::replaceClipping()
1644 {
1645     ReplaceClippingGLWidget glw;
1646     glw.resize(300, 300);
1647     glw.show();
1648
1649     QVERIFY(QTest::qWaitForWindowExposed(&glw));
1650
1651     QImage reference(300, 300, QImage::Format_RGB32);
1652     QPainter referencePainter(&reference);
1653     glw.paint(&referencePainter);
1654     referencePainter.end();
1655
1656     const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
1657
1658     // Sample pixels in a grid pattern which avoids false failures due to
1659     // off-by-one pixel errors on some buggy GL implementations
1660     for (int x = 25; x < reference.width(); x += 50) {
1661         for (int y = 25; y < reference.width(); y += 50) {
1662             QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y));
1663         }
1664     }
1665 }
1666
1667 class ClipTestGLWidget : public QGLWidget
1668 {
1669 public:
1670     void paint(QPainter *painter)
1671     {
1672         painter->fillRect(-1, -1, width()+2, height()+2, Qt::white);
1673         painter->setClipRect(10, 10, width()-20, height()-20);
1674         painter->fillRect(rect(), Qt::cyan);
1675
1676         painter->save();
1677         painter->setClipRect(10, 10, 100, 100, Qt::IntersectClip);
1678
1679         painter->fillRect(rect(), Qt::blue);
1680
1681         painter->save();
1682         painter->setClipRect(10, 10, 50, 50, Qt::IntersectClip);
1683         painter->fillRect(rect(), Qt::red);
1684         painter->restore();
1685         painter->fillRect(0, 0, 40, 40, Qt::white);
1686         painter->save();
1687
1688         painter->setClipRect(0, 0, 35, 35, Qt::IntersectClip);
1689         painter->fillRect(rect(), Qt::black);
1690         painter->restore();
1691
1692         painter->fillRect(0, 0, 30, 30, Qt::magenta);
1693
1694         painter->save();
1695         painter->setClipRect(60, 10, 50, 50, Qt::ReplaceClip);
1696         painter->fillRect(rect(), Qt::green);
1697         painter->restore();
1698
1699         painter->restore();
1700
1701         painter->translate(100, 100);
1702
1703         {
1704             QPainterPath path;
1705             path.addRect(10, 10, 100, 100);
1706             path.addRect(10, 10, 10, 10);
1707             painter->setClipPath(path, Qt::IntersectClip);
1708         }
1709
1710         painter->fillRect(rect(), Qt::blue);
1711
1712         painter->save();
1713         {
1714             QPainterPath path;
1715             path.addRect(10, 10, 50, 50);
1716             path.addRect(10, 10, 10, 10);
1717             painter->setClipPath(path, Qt::IntersectClip);
1718         }
1719         painter->fillRect(rect(), Qt::red);
1720         painter->restore();
1721         painter->fillRect(0, 0, 40, 40, Qt::white);
1722         painter->save();
1723
1724         {
1725             QPainterPath path;
1726             path.addRect(0, 0, 35, 35);
1727             path.addRect(10, 10, 10, 10);
1728             painter->setClipPath(path, Qt::IntersectClip);
1729         }
1730         painter->fillRect(rect(), Qt::black);
1731         painter->restore();
1732
1733         painter->fillRect(0, 0, 30, 30, Qt::magenta);
1734
1735         painter->save();
1736         {
1737             QPainterPath path;
1738             path.addRect(60, 10, 50, 50);
1739             path.addRect(10, 10, 10, 10);
1740             painter->setClipPath(path, Qt::ReplaceClip);
1741         }
1742         painter->fillRect(rect(), Qt::green);
1743         painter->restore();
1744     }
1745
1746 protected:
1747     void paintEvent(QPaintEvent*)
1748     {
1749         QPainter painter(this);
1750         paint(&painter);
1751     }
1752 };
1753
1754 void tst_QGL::clipTest()
1755 {
1756     ClipTestGLWidget glw;
1757     glw.resize(220, 220);
1758     glw.show();
1759
1760     QVERIFY(QTest::qWaitForWindowExposed(&glw));
1761
1762     QImage reference(glw.size(), QImage::Format_RGB32);
1763     QPainter referencePainter(&reference);
1764     glw.paint(&referencePainter);
1765     referencePainter.end();
1766
1767     const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
1768
1769     // Sample pixels in a grid pattern which avoids false failures due to
1770     // off-by-one pixel errors on some buggy GL implementations
1771     for (int x = 2; x < reference.width(); x += 5) {
1772         for (int y = 2; y < reference.height(); y += 5) {
1773             QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y));
1774         }
1775     }
1776 }
1777
1778 void tst_QGL::destroyFBOAfterContext()
1779 {
1780     if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
1781         QSKIP("QGLFramebufferObject not supported on this platform");
1782
1783     QGLWidget *glw = new QGLWidget();
1784     glw->makeCurrent();
1785
1786     // No multisample with combined depth/stencil attachment:
1787     QGLFramebufferObjectFormat fboFormat;
1788     fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
1789
1790     // Don't complicate things by using NPOT:
1791     QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);
1792
1793     // The handle should be valid until the context is destroyed.
1794     QVERIFY(fbo->handle() != 0);
1795     QVERIFY(fbo->isValid());
1796
1797     delete glw;
1798
1799     // The handle should now be zero.
1800     QVERIFY(fbo->handle() == 0);
1801     QVERIFY(!fbo->isValid());
1802
1803     delete fbo;
1804 }
1805
1806 #ifdef QT_BUILD_INTERNAL
1807
1808 class tst_QGLResource
1809 {
1810 public:
1811     tst_QGLResource(const QGLContext * = 0) {}
1812     ~tst_QGLResource() { ++deletions; }
1813
1814     static int deletions;
1815 };
1816
1817 int tst_QGLResource::deletions = 0;
1818
1819 #ifdef TODO
1820 Q_GLOBAL_STATIC(QOpenGLContextGroupResource<tst_QGLResource>, qt_shared_test)
1821 #endif //TODO
1822 #endif // QT_BUILD_INTERNAL
1823
1824 #ifdef QT_BUILD_INTERNAL
1825 void tst_QGL::shareRegister()
1826 {
1827 #ifdef TODO
1828     // Create a context.
1829     QGLWidget *glw1 = new QGLWidget();
1830     glw1->makeCurrent();
1831
1832     // Nothing should be sharing with glw1's context yet.
1833     QVERIFY(!glw1->isSharing());
1834
1835     // Create a guard for the first context.
1836     QOpenGLSharedResourceGuard guard(glw1->context()->contextHandle());
1837     QVERIFY(guard.id() == 0);
1838     guard.setId(3);
1839     QVERIFY(guard.id() == 3);
1840
1841     // Request a tst_QGLResource object for the first context.
1842     tst_QGLResource *res1 = qt_shared_test()->value(glw1->context()->contextHandle());
1843     QVERIFY(res1);
1844     QVERIFY(qt_shared_test()->value(glw1->context()->contextHandle()) == res1);
1845
1846     // Create another context that shares with the first.
1847     QVERIFY(!glw1->isSharing());
1848     QGLWidget *glw2 = new QGLWidget(0, glw1);
1849     if (!glw2->isSharing()) {
1850         delete glw2;
1851         delete glw1;
1852         QSKIP("Context sharing is not supported");
1853     }
1854     QVERIFY(glw1->isSharing());
1855     QVERIFY(glw1->context() != glw2->context());
1856
1857     // Check that the first context's resource is also on the second.
1858     QVERIFY(qt_shared_test()->value(glw1->context()) == res1);
1859     QVERIFY(qt_shared_test()->value(glw2->context()) == res1);
1860
1861     // Guard should still be the same.
1862     QVERIFY(guard.context() == glw1->context());
1863     QVERIFY(guard.id() == 3);
1864
1865     // Check the sharing relationships.
1866     QVERIFY(QGLContext::areSharing(glw1->context(), glw1->context()));
1867     QVERIFY(QGLContext::areSharing(glw2->context(), glw2->context()));
1868     QVERIFY(QGLContext::areSharing(glw1->context(), glw2->context()));
1869     QVERIFY(QGLContext::areSharing(glw2->context(), glw1->context()));
1870     QVERIFY(!QGLContext::areSharing(0, glw2->context()));
1871     QVERIFY(!QGLContext::areSharing(glw1->context(), 0));
1872     QVERIFY(!QGLContext::areSharing(0, 0));
1873
1874     // Create a third context, not sharing with the others.
1875     QGLWidget *glw3 = new QGLWidget();
1876     QVERIFY(!glw3->isSharing());
1877
1878     // Create a guard on the standalone context.
1879     QGLSharedResourceGuard guard3(glw3->context());
1880     guard3.setId(5);
1881
1882     // Request a resource to the third context.
1883     tst_QGLResource *res3 = qt_shared_test()->value(glw3->context());
1884     QVERIFY(res3);
1885     QVERIFY(qt_shared_test()->value(glw1->context()) == res1);
1886     QVERIFY(qt_shared_test()->value(glw2->context()) == res1);
1887     QVERIFY(qt_shared_test()->value(glw3->context()) == res3);
1888
1889     // Check the sharing relationships again.
1890     QVERIFY(QGLContext::areSharing(glw1->context(), glw1->context()));
1891     QVERIFY(QGLContext::areSharing(glw2->context(), glw2->context()));
1892     QVERIFY(QGLContext::areSharing(glw1->context(), glw2->context()));
1893     QVERIFY(QGLContext::areSharing(glw2->context(), glw1->context()));
1894     QVERIFY(!QGLContext::areSharing(glw1->context(), glw3->context()));
1895     QVERIFY(!QGLContext::areSharing(glw2->context(), glw3->context()));
1896     QVERIFY(!QGLContext::areSharing(glw3->context(), glw1->context()));
1897     QVERIFY(!QGLContext::areSharing(glw3->context(), glw2->context()));
1898     QVERIFY(QGLContext::areSharing(glw3->context(), glw3->context()));
1899     QVERIFY(!QGLContext::areSharing(0, glw2->context()));
1900     QVERIFY(!QGLContext::areSharing(glw1->context(), 0));
1901     QVERIFY(!QGLContext::areSharing(0, glw3->context()));
1902     QVERIFY(!QGLContext::areSharing(glw3->context(), 0));
1903     QVERIFY(!QGLContext::areSharing(0, 0));
1904
1905     // Shared guard should still be the same.
1906     QVERIFY(guard.context() == glw1->context());
1907     QVERIFY(guard.id() == 3);
1908
1909     // Delete the first context.
1910     delete glw1;
1911
1912     // The second context should no longer register as sharing.
1913     QVERIFY(!glw2->isSharing());
1914
1915     // The first context's resource should transfer to the second context.
1916     QCOMPARE(tst_QGLResource::deletions, 0);
1917     QVERIFY(qt_shared_test()->value(glw2->context()) == res1);
1918     QVERIFY(qt_shared_test()->value(glw3->context()) == res3);
1919
1920     // Shared guard should now be the second context, with the id the same.
1921     QVERIFY(guard.context() == glw2->context());
1922     QVERIFY(guard.id() == 3);
1923     QVERIFY(guard3.context() == glw3->context());
1924     QVERIFY(guard3.id() == 5);
1925
1926     // Clean up and check that the resources are properly deleted.
1927     delete glw2;
1928     QCOMPARE(tst_QGLResource::deletions, 1);
1929     delete glw3;
1930     QCOMPARE(tst_QGLResource::deletions, 2);
1931
1932     // Guards should now be null and the id zero.
1933     QVERIFY(guard.context() == 0);
1934     QVERIFY(guard.id() == 0);
1935     QVERIFY(guard3.context() == 0);
1936     QVERIFY(guard3.id() == 0);
1937 #endif //TODO
1938 }
1939 #endif
1940
1941 // Tests QGLContext::bindTexture with default options
1942 #ifdef QT_BUILD_INTERNAL
1943 void tst_QGL::qglContextDefaultBindTexture()
1944 {
1945     QGLWidget w;
1946     w.makeCurrent();
1947     QGLContext *ctx = const_cast<QGLContext*>(w.context());
1948
1949     QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32);
1950     boundImage->fill(0xFFFFFFFF);
1951     QPixmap *boundPixmap = new QPixmap(256, 256);
1952     boundPixmap->fill(Qt::red);
1953
1954     int startCacheItemCount = QGLTextureCache::instance()->size();
1955
1956     GLuint boundImageTextureId = ctx->bindTexture(*boundImage);
1957     GLuint boundPixmapTextureId = ctx->bindTexture(*boundPixmap);
1958
1959     // Make sure the image & pixmap have been added to the cache:
1960     QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
1961
1962     // Make sure the image & pixmap have the is_cached flag set:
1963     QVERIFY(QImagePixmapCleanupHooks::isImageCached(*boundImage));
1964     QVERIFY(QImagePixmapCleanupHooks::isPixmapCached(*boundPixmap));
1965
1966     // Make sure the texture IDs returned are valid:
1967     QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE);
1968     QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE);
1969
1970     // Make sure the textures are still valid after we delete the image/pixmap:
1971     // Also check that although the textures are left intact, the cache entries are removed:
1972     delete boundImage;
1973     boundImage = 0;
1974     QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE);
1975     QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
1976     delete boundPixmap;
1977     boundPixmap = 0;
1978     QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE);
1979     QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
1980
1981     // Finally, make sure QGLContext::deleteTexture deletes the texture IDs:
1982     ctx->deleteTexture(boundImageTextureId);
1983     ctx->deleteTexture(boundPixmapTextureId);
1984     QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_FALSE);
1985     QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_FALSE);
1986 }
1987 #endif
1988
1989 #ifdef QT_BUILD_INTERNAL
1990 void tst_QGL::textureCleanup()
1991 {
1992     QGLWidget w;
1993     w.resize(200,200);
1994     w.show();
1995     w.makeCurrent();
1996
1997     // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache
1998     // when the pixmap cache is cleared
1999     {
2000         int startCacheItemCount = QGLTextureCache::instance()->size();
2001         QPainter p(&w);
2002
2003         QPixmap boundPixmap(":designer.png");
2004
2005         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2006
2007         p.drawPixmap(0, 0, boundPixmap);
2008         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2009
2010         // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
2011         p.end();
2012
2013         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2014
2015         // Check that the texture doesn't get removed from the cache when the pixmap is cleared
2016         // as it should still be in the cache:
2017         boundPixmap = QPixmap();
2018         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2019
2020         QPixmapCache::clear();
2021         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2022     }
2023
2024     // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache
2025     // when they are explicitly removed from the pixmap cache
2026     {
2027         int startCacheItemCount = QGLTextureCache::instance()->size();
2028         QPainter p(&w);
2029
2030         QPixmap boundPixmap(128, 128);
2031         QString cacheKey = QString::fromLatin1("myPixmap");
2032         QPixmapCache::insert(cacheKey, boundPixmap);
2033
2034         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2035
2036         p.drawPixmap(0, 0, boundPixmap);
2037         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2038
2039         // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
2040         p.end();
2041
2042         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2043
2044         // Check that the texture doesn't get removed from the cache when the pixmap is cleared
2045         // as it should still be in the cache:
2046         boundPixmap = QPixmap();
2047         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2048
2049         // Finally, we check that the texture cache entry is removed when we remove the
2050         // pixmap cache entry, which should hold the last reference:
2051         QPixmapCache::remove(cacheKey);
2052         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2053     }
2054
2055     // Check images & pixmaps are removed from the cache when they are deleted
2056     {
2057         int startCacheItemCount = QGLTextureCache::instance()->size();
2058         QPainter p(&w);
2059
2060         QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32);
2061         boundImage->fill(0xFFFFFFFF);
2062         QPixmap *boundPixmap = new QPixmap(256, 256);
2063         boundPixmap->fill(Qt::red);
2064
2065         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2066
2067         p.drawImage(0, 0, *boundImage);
2068         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2069
2070         p.drawPixmap(0, 0, *boundPixmap);
2071         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2072
2073         // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
2074         p.end();
2075
2076         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2077
2078         delete boundImage;
2079         boundImage = 0;
2080         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2081
2082         delete boundPixmap;
2083         boundPixmap = 0;
2084         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2085     }
2086
2087     // Check images & pixmaps are removed from the cache when they are assigned to
2088     {
2089         int startCacheItemCount = QGLTextureCache::instance()->size();
2090         QPainter p(&w);
2091
2092         QImage boundImage(256, 256, QImage::Format_RGB32);
2093         boundImage.fill(0xFFFFFFFF);
2094         QPixmap boundPixmap(256, 256);
2095         boundPixmap.fill(Qt::red);
2096
2097         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2098
2099         p.drawImage(0, 0, boundImage);
2100         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2101
2102         p.drawPixmap(0, 0, boundPixmap);
2103         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2104
2105         // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
2106         p.end();
2107
2108         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2109
2110         boundImage = QImage(64, 64, QImage::Format_RGB32);
2111         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2112
2113         boundPixmap = QPixmap(64, 64);
2114         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2115     }
2116
2117     // Check images & pixmaps are removed from the cache when they are modified (detached)
2118     {
2119         int startCacheItemCount = QGLTextureCache::instance()->size();
2120         QPainter p(&w);
2121
2122         QImage boundImage(256, 256, QImage::Format_RGB32);
2123         boundImage.fill(0xFFFFFFFF);
2124         QPixmap boundPixmap(256, 256);
2125         boundPixmap.fill(Qt::red);
2126
2127         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2128
2129         p.drawImage(0, 0, boundImage);
2130         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2131
2132         p.drawPixmap(0, 0, boundPixmap);
2133         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2134
2135         // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
2136         p.end();
2137
2138         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2139
2140         boundImage.fill(0x00000000);
2141         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2142
2143         boundPixmap.fill(Qt::blue);
2144         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2145     }
2146
2147     // Check that images/pixmaps aren't removed from the cache if a shallow copy has been made
2148     QImage copyOfImage;
2149     QPixmap copyOfPixmap;
2150     int startCacheItemCount = QGLTextureCache::instance()->size();
2151     {
2152         QPainter p(&w);
2153
2154         QImage boundImage(256, 256, QImage::Format_RGB32);
2155         boundImage.fill(0xFFFFFFFF);
2156         QPixmap boundPixmap(256, 256);
2157         boundPixmap.fill(Qt::red);
2158
2159         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2160
2161         p.drawImage(0, 0, boundImage);
2162         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2163
2164         p.drawPixmap(0, 0, boundPixmap);
2165         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2166
2167         // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
2168         p.end();
2169
2170         copyOfImage = boundImage;
2171         copyOfPixmap = boundPixmap;
2172         QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2173     } // boundImage & boundPixmap would have been deleted when they went out of scope
2174     QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
2175
2176     copyOfImage = QImage();
2177     QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
2178
2179     copyOfPixmap = QPixmap();
2180     QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
2181 }
2182 #endif
2183
2184 namespace ThreadImages {
2185
2186 class Producer : public QObject
2187 {
2188     Q_OBJECT
2189 public:
2190     Producer()
2191     {
2192         startTimer(20);
2193
2194         QThread *thread = new QThread;
2195         thread->start();
2196
2197         connect(this, SIGNAL(destroyed()), thread, SLOT(quit()));
2198
2199         moveToThread(thread);
2200         connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
2201     }
2202
2203 signals:
2204     void imageReady(const QImage &image);
2205
2206 protected:
2207     void timerEvent(QTimerEvent *)
2208     {
2209         QImage image(256, 256, QImage::Format_RGB32);
2210         QLinearGradient g(0, 0, 0, 256);
2211         g.setColorAt(0, QColor(255, 180, 180));
2212         g.setColorAt(1, Qt::white);
2213         g.setSpread(QGradient::ReflectSpread);
2214
2215         QBrush brush(g);
2216         brush.setTransform(QTransform::fromTranslate(0, delta));
2217         delta += 10;
2218
2219         QPainter p(&image);
2220         p.fillRect(image.rect(), brush);
2221
2222         if (images.size() > 10)
2223             images.removeFirst();
2224
2225         images.append(image);
2226
2227         emit imageReady(image);
2228     }
2229
2230 private:
2231     QList<QImage> images;
2232     int delta;
2233 };
2234
2235
2236 class DisplayWidget : public QGLWidget
2237 {
2238     Q_OBJECT
2239 public:
2240     DisplayWidget(QWidget *parent) : QGLWidget(parent) {}
2241     void paintEvent(QPaintEvent *)
2242     {
2243         QPainter p(this);
2244         p.drawImage(rect(), m_image);
2245     }
2246
2247 public slots:
2248     void setImage(const QImage &image)
2249     {
2250         m_image = image;
2251         update();
2252     }
2253
2254 private:
2255     QImage m_image;
2256 };
2257
2258 class Widget : public QWidget
2259 {
2260     Q_OBJECT
2261 public:
2262     Widget()
2263         : iterations(0)
2264         , display(0)
2265         , producer(new Producer)
2266     {
2267         startTimer(400);
2268         connect(this, SIGNAL(destroyed()), producer, SLOT(deleteLater()));
2269     }
2270
2271     int iterations;
2272
2273 protected:
2274     void timerEvent(QTimerEvent *)
2275     {
2276         ++iterations;
2277
2278         delete display;
2279         display = new DisplayWidget(this);
2280         connect(producer, SIGNAL(imageReady(const QImage &)), display, SLOT(setImage(const QImage &)));
2281
2282         display->setGeometry(rect());
2283         display->show();
2284     }
2285
2286 private:
2287     DisplayWidget *display;
2288     Producer *producer;
2289 };
2290
2291 }
2292
2293 void tst_QGL::threadImages()
2294 {
2295     ThreadImages::Widget *widget = new ThreadImages::Widget;
2296     widget->show();
2297
2298     while (widget->iterations <= 5) {
2299         qApp->processEvents();
2300     }
2301
2302     delete widget;
2303 }
2304
2305 void tst_QGL::nullRectCrash()
2306 {
2307     if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
2308         QSKIP("QGLFramebufferObject not supported on this platform");
2309
2310     QGLWidget glw;
2311     glw.makeCurrent();
2312
2313     QGLFramebufferObjectFormat fboFormat;
2314     fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
2315
2316     QGLFramebufferObject *fbo = new QGLFramebufferObject(128, 128, fboFormat);
2317
2318     QPainter fboPainter(fbo);
2319
2320     fboPainter.setPen(QPen(QColor(255, 127, 127, 127), 2));
2321     fboPainter.setBrush(QColor(127, 255, 127, 127));
2322     fboPainter.drawRect(QRectF());
2323
2324     fboPainter.end();
2325 }
2326
2327 QTEST_MAIN(tst_QGL)
2328 #include "tst_qgl.moc"