Changeset 561 for trunk/src/opengl/qgl.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/opengl/qgl.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 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. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 60 60 #endif 61 61 62 #include <qdatetime.h> 63 62 64 #include <stdlib.h> // malloc 63 65 … … 66 68 #include "qgl_p.h" 67 69 68 #if defined(QT_OPENGL_ES_2)70 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) 69 71 #include "gl2paintengineex/qpaintengineex_opengl2_p.h" 70 #else 72 #endif 73 74 #ifndef QT_OPENGL_ES_2 71 75 #include <private/qpaintengine_opengl_p.h> 72 76 #endif 77 78 #ifdef Q_WS_QWS 79 #include <private/qglwindowsurface_qws_p.h> 80 #endif 81 82 #include <qglpixelbuffer.h> 83 #include <qglframebufferobject.h> 73 84 74 85 #include <private/qimage_p.h> 75 86 #include <private/qpixmapdata_p.h> 76 87 #include <private/qpixmapdata_gl_p.h> 88 #include <private/qglpixelbuffer_p.h> 89 #include <private/qwindowsurface_gl_p.h> 90 #include <private/qimagepixmapcleanuphooks_p.h> 77 91 #include "qcolormap.h" 78 #include "qcache.h"79 92 #include "qfile.h" 80 93 #include "qlibrary.h" … … 92 105 #endif 93 106 94 QThreadStorage<QGLThreadContext *> qgl_context_storage; 107 struct QGLThreadContext { 108 QGLContext *context; 109 }; 110 111 static QThreadStorage<QGLThreadContext *> qgl_context_storage; 95 112 96 113 Q_GLOBAL_STATIC(QGLFormat, qgl_default_format) … … 111 128 bool QGLExtensions::nvidiaFboNeedsFinish = false; 112 129 113 #ifndef APIENTRY114 # define APIENTRY115 #endif116 typedef void (APIENTRY *pfn_glCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei,117 GLsizei, GLint, GLsizei, const GLvoid *);118 static pfn_glCompressedTexImage2DARB qt_glCompressedTexImage2DARB = 0;119 120 121 #ifndef APIENTRY122 #define APIENTRY123 #endif124 125 130 Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy) 126 131 QGLSignalProxy *QGLSignalProxy::instance() … … 129 134 } 130 135 136 137 class QGLEngineSelector 138 { 139 public: 140 QGLEngineSelector() : engineType(QPaintEngine::MaxUser) 141 { 142 } 143 144 void setPreferredPaintEngine(QPaintEngine::Type type) { 145 if (type == QPaintEngine::OpenGL || type == QPaintEngine::OpenGL2) 146 engineType = type; 147 } 148 149 QPaintEngine::Type preferredPaintEngine() { 150 #ifdef Q_WS_MAC 151 // The ATI X1600 driver for Mac OS X does not support return 152 // values from functions in GLSL. Since working around this in 153 // the GL2 engine would require a big, ugly rewrite, we're 154 // falling back to the GL 1 engine.. 155 static bool mac_x1600_check_done = false; 156 if (!mac_x1600_check_done) { 157 QGLWidget *tmp = 0; 158 if (!QGLContext::currentContext()) { 159 tmp = new QGLWidget(); 160 tmp->makeCurrent(); 161 } 162 if (strstr((char *) glGetString(GL_RENDERER), "X1600")) 163 engineType = QPaintEngine::OpenGL; 164 if (tmp) 165 delete tmp; 166 mac_x1600_check_done = true; 167 } 168 #endif 169 if (engineType == QPaintEngine::MaxUser) { 170 // No user-set engine - use the defaults 171 #if defined(QT_OPENGL_ES_2) 172 engineType = QPaintEngine::OpenGL2; 173 #else 174 // We can't do this in the constructor for this object because it 175 // needs to be called *before* the QApplication constructor. 176 // Also check for the FragmentShader extension in conjunction with 177 // the 2.0 version flag, to cover the case where we export the display 178 // from an old GL 1.1 server to a GL 2.x client. In that case we can't 179 // use GL 2.0. 180 if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) 181 && (QGLExtensions::glExtensions & QGLExtensions::FragmentShader) 182 && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty()) 183 engineType = QPaintEngine::OpenGL2; 184 else 185 engineType = QPaintEngine::OpenGL; 186 #endif 187 } 188 return engineType; 189 } 190 191 private: 192 QPaintEngine::Type engineType; 193 }; 194 195 Q_GLOBAL_STATIC(QGLEngineSelector, qgl_engine_selector) 196 197 198 bool qt_gl_preferGL2Engine() 199 { 200 return qgl_engine_selector()->preferredPaintEngine() == QPaintEngine::OpenGL2; 201 } 202 203 131 204 /*! 132 205 \namespace QGL 206 \inmodule QtOpenGL 133 207 134 208 \brief The QGL namespace specifies miscellaneous identifiers used 135 209 in the Qt OpenGL module. 136 210 137 \ingroup multimedia211 \ingroup painting-3D 138 212 */ 139 213 … … 168 242 */ 169 243 244 /*! 245 \fn void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType) 246 247 \since 4.6 248 249 Sets the preferred OpenGL paint engine that is used to draw onto 250 QGLWidget, QGLPixelBuffer and QGLFramebufferObject targets with QPainter 251 in Qt. 252 253 The \a engineType parameter specifies which of the GL engines to 254 use. Only \c QPaintEngine::OpenGL and \c QPaintEngine::OpenGL2 are 255 valid parameters to this function. All other values are ignored. 256 257 By default, the \c QPaintEngine::OpenGL2 engine is used if GL/GLES 258 version 2.0 is available, otherwise \c QPaintEngine::OpenGL is 259 used. 260 261 \warning This function must be called before the QApplication 262 constructor is called. 263 */ 264 void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType) 265 { 266 qgl_engine_selector()->setPreferredPaintEngine(engineType); 267 } 268 269 170 270 /***************************************************************************** 171 271 QGLFormat implementation … … 178 278 rendering context. 179 279 180 \ingroup multimedia280 \ingroup painting-3D 181 281 182 282 A display format has several characteristics: … … 191 291 \i \link setDirectRendering() Direct rendering.\endlink 192 292 \i \link setOverlay() Presence of an overlay.\endlink 193 \i \link setPlane() The plane of an overlay format.\endlink293 \i \link setPlane() Plane of an overlay.\endlink 194 294 \i \link setSampleBuffers() Multisample buffers.\endlink 195 295 \endlist 196 296 197 You can also specify preferred bit depths for the depth buffer, 198 alpha buffer, accumulation buffer and the stencil buffer with the 199 functions: setDepthBufferSize(), setAlphaBufferSize(), 297 You can also specify preferred bit depths for the color buffer, 298 depth buffer, alpha buffer, accumulation buffer and the stencil 299 buffer with the functions: setRedBufferSize(), setGreenBufferSize(), 300 setBlueBufferSize(), setDepthBufferSize(), setAlphaBufferSize(), 200 301 setAccumBufferSize() and setStencilBufferSize(). 201 302 … … 237 338 \sa QGLContext, QGLWidget 238 339 */ 340 341 #ifndef QT_OPENGL_ES 239 342 240 343 static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4]) … … 280 383 } 281 384 282 /*! 283 Constructs a QGLFormat object with the factory default settings: 385 #endif // !QT_OPENGL_ES 386 387 /*! 388 Constructs a QGLFormat object with the following default settings: 284 389 \list 285 390 \i \link setDoubleBuffer() Double buffer:\endlink Enabled. … … 288 393 \i \link setAlpha() Alpha channel:\endlink Disabled. 289 394 \i \link setAccum() Accumulator buffer:\endlink Disabled. 290 \i \link setStencil() Stencil buffer:\endlink Disabled.395 \i \link setStencil() Stencil buffer:\endlink Enabled. 291 396 \i \link setStereo() Stereo:\endlink Disabled. 292 397 \i \link setDirectRendering() Direct rendering:\endlink Enabled. … … 304 409 305 410 /*! 306 Creates a QGLFormat object that is a copy of the current \link307 defaultFormat() application default format\endlink.308 309 If \a options is not 0, th is copy is modified by these format310 options. The \a options parameter should be \c FormatOption values311 OR'ed together.411 Creates a QGLFormat object that is a copy of the current 412 defaultFormat(). 413 414 If \a options is not 0, the default format is modified by the 415 specified format options. The \a options parameter should be 416 QGL::FormatOption values OR'ed together. 312 417 313 418 This constructor makes it easy to specify a certain desired format … … 315 420 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 3 316 421 317 Note that there are \cFormatOption values to turn format settings318 both on and off, e.g. \c DepthBuffer and \cNoDepthBuffer,319 \c DirectRendering and \cIndirectRendering, etc.422 Note that there are QGL::FormatOption values to turn format settings 423 both on and off, e.g. QGL::DepthBuffer and QGL::NoDepthBuffer, 424 QGL::DirectRendering and QGL::IndirectRendering, etc. 320 425 321 426 The \a plane parameter defaults to 0 and is the plane which this … … 323 428 supports overlay/underlay rendering planes. 324 429 325 \sa defaultFormat(), setOption() 430 \sa defaultFormat(), setOption(), setPlane() 326 431 */ 327 432 … … 337 442 338 443 /*! 444 \internal 445 */ 446 void QGLFormat::detach() 447 { 448 if (d->ref != 1) { 449 QGLFormatPrivate *newd = new QGLFormatPrivate(d); 450 if (!d->ref.deref()) 451 delete d; 452 d = newd; 453 } 454 } 455 456 /*! 339 457 Constructs a copy of \a other. 340 458 */ … … 342 460 QGLFormat::QGLFormat(const QGLFormat &other) 343 461 { 344 d = new QGLFormatPrivate;345 *d = *other.d;462 d = other.d; 463 d->ref.ref(); 346 464 } 347 465 … … 352 470 QGLFormat &QGLFormat::operator=(const QGLFormat &other) 353 471 { 354 *d = *other.d; 472 if (d != other.d) { 473 other.d->ref.ref(); 474 if (!d->ref.deref()) 475 delete d; 476 d = other.d; 477 } 355 478 return *this; 356 479 } … … 361 484 QGLFormat::~QGLFormat() 362 485 { 363 delete d; 486 if (!d->ref.deref()) 487 delete d; 364 488 } 365 489 … … 515 639 516 640 Returns true if the stencil buffer is enabled; otherwise returns 517 false. The stencil buffer is disabled by default.641 false. The stencil buffer is enabled by default. 518 642 519 643 \sa setStencil(), setStencilBufferSize() … … 524 648 disables the stencil buffer. 525 649 526 The stencil buffer is disabled by default.650 The stencil buffer is enabled by default. 527 651 528 652 The stencil buffer masks certain parts of the drawing area so that … … 637 761 void QGLFormat::setSamples(int numSamples) 638 762 { 763 detach(); 639 764 if (numSamples < 0) { 640 765 qWarning("QGLFormat::setSamples: Cannot have negative number of samples per pixel %d", numSamples); … … 664 789 void QGLFormat::setSwapInterval(int interval) 665 790 { 791 detach(); 666 792 d->swapInterval = interval; 667 793 } … … 709 835 formats is 1, which is the first overlay plane. 710 836 711 \sa setPlane() 837 \sa setPlane(), defaultOverlayFormat() 712 838 */ 713 839 int QGLFormat::plane() const … … 731 857 void QGLFormat::setPlane(int plane) 732 858 { 859 detach(); 733 860 d->pln = plane; 734 861 } … … 742 869 void QGLFormat::setOption(QGL::FormatOptions opt) 743 870 { 871 detach(); 744 872 if (opt & 0xffff) 745 873 d->opts |= opt; … … 771 899 void QGLFormat::setDepthBufferSize(int size) 772 900 { 901 detach(); 773 902 if (size < 0) { 774 903 qWarning("QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size %d", size); … … 797 926 void QGLFormat::setRedBufferSize(int size) 798 927 { 928 detach(); 799 929 if (size < 0) { 800 930 qWarning("QGLFormat::setRedBufferSize: Cannot set negative red buffer size %d", size); … … 825 955 void QGLFormat::setGreenBufferSize(int size) 826 956 { 957 detach(); 827 958 if (size < 0) { 828 959 qWarning("QGLFormat::setGreenBufferSize: Cannot set negative green buffer size %d", size); … … 853 984 void QGLFormat::setBlueBufferSize(int size) 854 985 { 986 detach(); 855 987 if (size < 0) { 856 988 qWarning("QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size %d", size); … … 880 1012 void QGLFormat::setAlphaBufferSize(int size) 881 1013 { 1014 detach(); 882 1015 if (size < 0) { 883 1016 qWarning("QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size %d", size); … … 906 1039 void QGLFormat::setAccumBufferSize(int size) 907 1040 { 1041 detach(); 908 1042 if (size < 0) { 909 1043 qWarning("QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size %d", size); … … 930 1064 void QGLFormat::setStencilBufferSize(int size) 931 1065 { 1066 detach(); 932 1067 if (size < 0) { 933 1068 qWarning("QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size %d", size); … … 1125 1260 return defaultVersionFlags; 1126 1261 } else { 1127 cachedDefault = true;1128 1262 if (!hasOpenGL()) 1129 1263 return defaultVersionFlags; 1130 1264 dummy = new QGLWidget; 1131 1265 dummy->makeCurrent(); // glGetString() needs a current context 1266 cachedDefault = true; 1132 1267 } 1133 1268 } … … 1149 1284 1150 1285 /*! 1151 Returns the default QGLFormat for the application. All QGLWidget s1152 that are created use this format unless another format is1286 Returns the default QGLFormat for the application. All QGLWidget 1287 objects that are created use this format unless another format is 1153 1288 specified, e.g. when they are constructed. 1154 1289 … … 1183 1318 Returns the default QGLFormat for overlay contexts. 1184 1319 1185 The factorydefault overlay format is:1320 The default overlay format is: 1186 1321 \list 1187 1322 \i \link setDoubleBuffer() Double buffer:\endlink Disabled. … … 1194 1329 \i \link setDirectRendering() Direct rendering:\endlink Enabled. 1195 1330 \i \link setOverlay() Overlay:\endlink Disabled. 1331 \i \link setSampleBuffers() Multisample buffers:\endlink Disabled. 1196 1332 \i \link setPlane() Plane:\endlink 1 (i.e., first overlay plane). 1197 1333 \endlist … … 1236 1372 1237 1373 /*! 1238 Returns true if all the options of the two QGLFormats are equal; 1239 otherwise returns false. 1374 Returns true if all the options of the two QGLFormat objects 1375 \a a and \a b are equal; otherwise returns false. 1376 1377 \relates QGLFormat 1240 1378 */ 1241 1379 … … 1244 1382 return (int) a.d->opts == (int) b.d->opts && a.d->pln == b.d->pln && a.d->alphaSize == b.d->alphaSize 1245 1383 && a.d->accumSize == b.d->accumSize && a.d->stencilSize == b.d->stencilSize 1246 && a.d->depthSize == b.d->depthSize; 1247 } 1248 1249 1250 /*! 1251 Returns false if all the options of the two QGLFormats are equal; 1252 otherwise returns true. 1384 && a.d->depthSize == b.d->depthSize 1385 && a.d->redSize == b.d->redSize 1386 && a.d->greenSize == b.d->greenSize 1387 && a.d->blueSize == b.d->blueSize 1388 && a.d->numSamples == b.d->numSamples 1389 && a.d->swapInterval == b.d->swapInterval; 1390 } 1391 1392 1393 /*! 1394 Returns false if all the options of the two QGLFormat objects 1395 \a a and \a b are equal; otherwise returns true. 1396 1397 \relates QGLFormat 1253 1398 */ 1254 1399 … … 1261 1406 QGLContext implementation 1262 1407 *****************************************************************************/ 1408 1409 QGLContextGroup::~QGLContextGroup() 1410 { 1411 // Clear any remaining QGLSharedResourceGuard objects on the group. 1412 QGLSharedResourceGuard *guard = m_guards; 1413 while (guard != 0) { 1414 guard->m_group = 0; 1415 guard->m_id = 0; 1416 guard = guard->m_next; 1417 } 1418 } 1419 1420 void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard) 1421 { 1422 if (m_guards) 1423 m_guards->m_prev = guard; 1424 guard->m_next = m_guards; 1425 guard->m_prev = 0; 1426 m_guards = guard; 1427 } 1428 1429 void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard) 1430 { 1431 if (guard->m_next) 1432 guard->m_next->m_prev = guard->m_prev; 1433 if (guard->m_prev) 1434 guard->m_prev->m_next = guard->m_next; 1435 else 1436 m_guards = guard->m_next; 1437 } 1438 1439 QGLContextPrivate::~QGLContextPrivate() 1440 { 1441 if (!group->m_refs.deref()) { 1442 Q_ASSERT(group->context() == q_ptr); 1443 delete group; 1444 } 1445 } 1446 1263 1447 void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) 1264 1448 { … … 1289 1473 #if defined(QT_OPENGL_ES) 1290 1474 eglContext = 0; 1291 #endif 1292 pbo = 0; 1475 eglSurface = EGL_NO_SURFACE; 1476 #endif 1477 fbo = 0; 1293 1478 crWin = false; 1294 1479 initDone = false; 1295 1480 sharing = false; 1296 clear_on_painter_begin = true;1297 1481 max_texture_size = -1; 1298 1482 version_flags_cached = false; 1299 1483 version_flags = QGLFormat::OpenGL_Version_None; 1484 current_fbo = 0; 1485 default_fbo = 0; 1486 active_engine = 0; 1300 1487 } 1301 1488 … … 1308 1495 */ 1309 1496 1310 QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) 1311 { 1312 QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32); 1313 int w = size.width(); 1314 int h = size.height(); 1315 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); 1497 static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha) 1498 { 1316 1499 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 1317 1500 // OpenGL gives RGBA; Qt wants ARGB … … 1328 1511 // we shouldn't remove 1329 1512 while (p < end) { 1330 *p = 0x FF000000 | (*p>>8);1513 *p = 0xff000000 | (*p>>8); 1331 1514 ++p; 1332 1515 } … … 1334 1517 } else { 1335 1518 // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB 1336 img = img.rgbSwapped(); 1337 } 1338 return img.mirrored(); 1519 for (int y = 0; y < h; y++) { 1520 uint *q = (uint*)img.scanLine(y); 1521 for (int x=0; x < w; ++x) { 1522 const uint pixel = *q; 1523 *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00); 1524 q++; 1525 } 1526 } 1527 1528 } 1529 img = img.mirrored(); 1530 } 1531 1532 QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) 1533 { 1534 QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32); 1535 int w = size.width(); 1536 int h = size.height(); 1537 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); 1538 convertFromGLImage(img, w, h, alpha_format, include_alpha); 1539 return img; 1540 } 1541 1542 QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha) 1543 { 1544 QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32); 1545 int w = size.width(); 1546 int h = size.height(); 1547 #if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) 1548 //### glGetTexImage not in GL ES 2.0, need to do something else here! 1549 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); 1550 #endif 1551 convertFromGLImage(img, w, h, alpha_format, include_alpha); 1552 return img; 1339 1553 } 1340 1554 … … 1353 1567 } 1354 1568 1355 class QGLTexture {1356 public:1357 QGLTexture(const QGLContext *ctx, GLuint tx_id, GLenum tx_target, bool _clean = false)1358 : context(ctx), id(tx_id), target(tx_target), clean(_clean) {}1359 ~QGLTexture() {1360 if (clean) {1361 QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());1362 QGLContext *ctx = const_cast<QGLContext *>(context);1363 bool switch_context = current && current != ctx && !qgl_share_reg()->checkSharing(current, ctx);1364 if (switch_context)1365 ctx->makeCurrent();1366 glDeleteTextures(1, &id);1367 if (switch_context)1368 current->makeCurrent();1369 }1370 }1371 1372 const QGLContext *context;1373 GLuint id;1374 GLenum target;1375 bool clean;1376 };1377 1378 typedef QCache<qint64, QGLTexture> QGLTextureCache;1379 static int qt_tex_cache_limit = 64*1024; // cache ~64 MB worth of textures - this is not accurate though1380 static QGLTextureCache *qt_tex_cache = 0;1381 1382 1569 typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); 1383 1570 typedef void (*_qt_image_cleanup_hook_64)(qint64); … … 1385 1572 extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64; 1386 1573 extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64; 1574 1575 static QGLTextureCache *qt_gl_texture_cache = 0; 1576 1577 QGLTextureCache::QGLTextureCache() 1578 : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though 1579 { 1580 Q_ASSERT(qt_gl_texture_cache == 0); 1581 qt_gl_texture_cache = this; 1582 1583 QImagePixmapCleanupHooks::instance()->addPixmapModificationHook(cleanupTextures); 1584 #ifdef Q_WS_X11 1585 QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(cleanupPixmapSurfaces); 1586 #endif 1587 QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook); 1588 } 1589 1590 QGLTextureCache::~QGLTextureCache() 1591 { 1592 qt_gl_texture_cache = 0; 1593 1594 QImagePixmapCleanupHooks::instance()->removePixmapModificationHook(cleanupTextures); 1595 #ifdef Q_WS_X11 1596 QImagePixmapCleanupHooks::instance()->removePixmapDestructionHook(cleanupPixmapSurfaces); 1597 #endif 1598 QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook); 1599 } 1600 1601 void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost) 1602 { 1603 if (m_cache.totalCost() + cost > m_cache.maxCost()) { 1604 // the cache is full - make an attempt to remove something 1605 const QList<qint64> keys = m_cache.keys(); 1606 int i = 0; 1607 while (i < m_cache.count() 1608 && (m_cache.totalCost() + cost > m_cache.maxCost())) { 1609 QGLTexture *tex = m_cache.object(keys.at(i)); 1610 if (tex->context == ctx) 1611 m_cache.remove(keys.at(i)); 1612 ++i; 1613 } 1614 } 1615 m_cache.insert(key, texture, cost); 1616 } 1617 1618 bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId) 1619 { 1620 QList<qint64> keys = m_cache.keys(); 1621 for (int i = 0; i < keys.size(); ++i) { 1622 QGLTexture *tex = m_cache.object(keys.at(i)); 1623 if (tex->id == textureId && tex->context == ctx) { 1624 tex->options |= QGLContext::MemoryManagedBindOption; // forces a glDeleteTextures() call 1625 m_cache.remove(keys.at(i)); 1626 return true; 1627 } 1628 } 1629 return false; 1630 } 1631 1632 void QGLTextureCache::removeContextTextures(QGLContext* ctx) 1633 { 1634 QList<qint64> keys = m_cache.keys(); 1635 for (int i = 0; i < keys.size(); ++i) { 1636 const qint64 &key = keys.at(i); 1637 if (m_cache.object(key)->context == ctx) 1638 m_cache.remove(key); 1639 } 1640 } 1641 1642 QGLTextureCache* QGLTextureCache::instance() 1643 { 1644 if (!qt_gl_texture_cache) 1645 qt_gl_texture_cache = new QGLTextureCache; 1646 1647 return qt_gl_texture_cache; 1648 } 1649 1650 /* 1651 a hook that removes textures from the cache when a pixmap/image 1652 is deref'ed 1653 */ 1654 void QGLTextureCache::imageCleanupHook(qint64 cacheKey) 1655 { 1656 // ### remove when the GL texture cache becomes thread-safe 1657 if (qApp->thread() != QThread::currentThread()) 1658 return; 1659 QGLTexture *texture = instance()->getTexture(cacheKey); 1660 if (texture && texture->options & QGLContext::MemoryManagedBindOption) 1661 instance()->remove(cacheKey); 1662 } 1663 1664 1665 void QGLTextureCache::cleanupTextures(QPixmap* pixmap) 1666 { 1667 // ### remove when the GL texture cache becomes thread-safe 1668 if (qApp->thread() == QThread::currentThread()) { 1669 const qint64 cacheKey = pixmap->cacheKey(); 1670 QGLTexture *texture = instance()->getTexture(cacheKey); 1671 if (texture && texture->options & QGLContext::MemoryManagedBindOption) 1672 instance()->remove(cacheKey); 1673 } 1674 } 1675 1676 #if defined(Q_WS_X11) 1677 void QGLTextureCache::cleanupPixmapSurfaces(QPixmap* pixmap) 1678 { 1679 // Remove any bound textures first: 1680 cleanupTextures(pixmap); 1681 1682 QPixmapData *pd = pixmap->data_ptr().data(); 1683 if (pd->classId() == QPixmapData::X11Class) { 1684 Q_ASSERT(pd->ref == 1); // Make sure reference counting isn't broken 1685 QGLContextPrivate::destroyGlSurfaceForPixmap(pd); 1686 } 1687 } 1688 #endif 1689 1690 void QGLTextureCache::deleteIfEmpty() 1691 { 1692 if (instance()->size() == 0) 1693 delete instance(); 1694 } 1387 1695 1388 1696 // DDS format structure … … 1422 1730 #endif 1423 1731 1424 Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg) ;1732 Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg) 1425 1733 Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg() 1426 1734 { … … 1432 1740 \brief The QGLContext class encapsulates an OpenGL rendering context. 1433 1741 1434 \ingroup multimedia1742 \ingroup painting-3D 1435 1743 1436 1744 An OpenGL rendering context is a complete set of OpenGL state … … 1457 1765 */ 1458 1766 1767 /*! 1768 \enum QGLContext::BindOption 1769 \since 4.6 1770 1771 A set of options to decide how to bind a texture using bindTexture(). 1772 1773 \value NoBindOption Don't do anything, pass the texture straight 1774 through. 1775 1776 \value InvertedYBindOption Specifies that the texture should be flipped 1777 over the X axis so that the texture coordinate 0,0 corresponds to 1778 the top left corner. Inverting the texture implies a deep copy 1779 prior to upload. 1780 1781 \value MipmapBindOption Specifies that bindTexture() should try 1782 to generate mipmaps. If the GL implementation supports the \c 1783 GL_SGIS_generate_mipmap extension, mipmaps will be automatically 1784 generated for the texture. Mipmap generation is only supported for 1785 the \c GL_TEXTURE_2D target. 1786 1787 \value PremultipliedAlphaBindOption Specifies that the image should be 1788 uploaded with premultiplied alpha and does a conversion accordingly. 1789 1790 \value LinearFilteringBindOption Specifies that the texture filtering 1791 should be set to GL_LINEAR. Default is GL_NEAREST. If mipmap is 1792 also enabled, filtering will be set to GL_LINEAR_MIPMAP_LINEAR. 1793 1794 \value DefaultBindOption In Qt 4.5 and earlier, bindTexture() 1795 would mirror the image and automatically generate mipmaps. This 1796 option helps preserve this default behavior. 1797 1798 \omitvalue CanFlipNativePixmapBindOption Used by x11 from pixmap to choose 1799 wether or not it can bind the pixmap upside down or not. 1800 1801 \omitvalue MemoryManagedBindOption Used by paint engines to 1802 indicate that the pixmap should be memory managed along side with 1803 the pixmap/image that it stems from, e.g. installing destruction 1804 hooks in them. 1805 1806 \omitvalue InternalBindOption 1807 */ 1459 1808 1460 1809 /*! … … 1477 1826 1478 1827 QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device) 1479 { 1480 d_ptr = new QGLContextPrivate(this); 1828 : d_ptr(new QGLContextPrivate(this)) 1829 { 1481 1830 Q_D(QGLContext); 1482 1831 d->init(device, format); … … 1500 1849 */ 1501 1850 QGLContext::QGLContext(const QGLFormat &format) 1502 { 1503 d_ptr = new QGLContextPrivate(this); 1851 : d_ptr(new QGLContextPrivate(this)) 1852 { 1504 1853 Q_D(QGLContext); 1505 1854 d->init(0, format); … … 1512 1861 QGLContext::~QGLContext() 1513 1862 { 1514 Q_D(QGLContext);1515 1863 // remove any textures cached in this context 1516 if (qt_tex_cache) { 1517 QList<qint64> keys = qt_tex_cache->keys(); 1518 for (int i = 0; i < keys.size(); ++i) { 1519 const qint64 &key = keys.at(i); 1520 if (qt_tex_cache->object(key)->context == this) 1521 qt_tex_cache->remove(key); 1522 } 1523 // ### thread safety 1524 if (qt_tex_cache->size() == 0) { 1525 qt_pixmap_cleanup_hook_64 = 0; 1526 qt_image_cleanup_hook_64 = 0; 1527 delete qt_tex_cache; 1528 qt_tex_cache = 0; 1529 } 1530 } 1864 QGLTextureCache::instance()->removeContextTextures(this); 1865 QGLTextureCache::deleteIfEmpty(); // ### thread safety 1866 1867 d_ptr->group->cleanupResources(this); 1531 1868 1532 1869 QGLSignalProxy::instance()->emitAboutToDestroyContext(this); 1533 1870 reset(); 1534 delete d;1535 1871 } 1536 1872 1537 1873 void QGLContextPrivate::cleanup() 1538 1874 { 1539 Q_Q(QGLContext); 1540 if (pbo) { 1541 QGLContext *ctx = q; 1542 glDeleteBuffersARB(1, &pbo); 1543 pbo = 0; 1544 } 1545 } 1546 1547 typedef QHash<QString, GLuint> QGLDDSCache; 1548 Q_GLOBAL_STATIC(QGLDDSCache, qgl_dds_cache) 1875 } 1549 1876 1550 1877 /*! 1551 1878 \overload 1552 1879 1553 Reads the DirectDrawSurface (DDS) compressed file \a fileName and 1554 generates a 2D GL texture from it. 1555 1556 Only the DXT1, DXT3 and DXT5 DDS formats are supported. 1557 1558 Note that this will only work if the implementation supports the 1559 \c GL_ARB_texture_compression and \c GL_EXT_texture_compression_s3tc 1560 extensions. 1880 Reads the compressed texture file \a fileName and generates a 2D GL 1881 texture from it. 1882 1883 This function can load DirectDrawSurface (DDS) textures in the 1884 DXT1, DXT3 and DXT5 DDS formats if the \c GL_ARB_texture_compression 1885 and \c GL_EXT_texture_compression_s3tc extensions are supported. 1886 1887 Since 4.6.1, textures in the ETC1 format can be loaded if the 1888 \c GL_OES_compressed_ETC1_RGB8_texture extension is supported 1889 and the ETC1 texture has been encapsulated in the PVR container format. 1890 Also, textures in the PVRTC2 and PVRTC4 formats can be loaded 1891 if the \c GL_IMG_texture_compression_pvrtc extension is supported. 1561 1892 1562 1893 \sa deleteTexture() … … 1565 1896 GLuint QGLContext::bindTexture(const QString &fileName) 1566 1897 { 1567 if (!qt_glCompressedTexImage2DARB) { 1568 qWarning("QGLContext::bindTexture(): The GL implementation does not support texture" 1569 "compression extensions."); 1570 return 0; 1571 } 1572 1573 QGLDDSCache::const_iterator it = qgl_dds_cache()->constFind(fileName); 1574 if (it != qgl_dds_cache()->constEnd()) { 1898 Q_D(QGLContext); 1899 QGLDDSCache *dds_cache = &(d->group->m_dds_cache); 1900 QGLDDSCache::const_iterator it = dds_cache->constFind(fileName); 1901 if (it != dds_cache->constEnd()) { 1575 1902 glBindTexture(GL_TEXTURE_2D, it.value()); 1576 1903 return it.value(); 1577 1904 } 1578 1905 1579 QFile f(fileName); 1580 f.open(QIODevice::ReadOnly); 1581 1582 char tag[4]; 1583 f.read(&tag[0], 4); 1584 if (strncmp(tag,"DDS ", 4) != 0) { 1585 qWarning("QGLContext::bindTexture(): not a DDS image file."); 1906 QGLTexture texture(this); 1907 QSize size = texture.bindCompressedTexture(fileName); 1908 if (!size.isValid()) 1586 1909 return 0; 1587 } 1588 1589 DDSFormat ddsHeader; 1590 f.read((char *) &ddsHeader, sizeof(DDSFormat)); 1591 1592 if (!ddsHeader.dwLinearSize) { 1593 qWarning("QGLContext::bindTexture() DDS image size is not valid."); 1594 return 0; 1595 } 1596 1597 int factor = 4; 1598 int bufferSize = 0; 1599 int blockSize = 16; 1600 GLenum format; 1601 1602 switch(ddsHeader.ddsPixelFormat.dwFourCC) { 1603 case FOURCC_DXT1: 1604 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; 1605 factor = 2; 1606 blockSize = 8; 1607 break; 1608 case FOURCC_DXT3: 1609 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; 1610 break; 1611 case FOURCC_DXT5: 1612 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; 1613 break; 1614 default: 1615 qWarning("QGLContext::bindTexture() DDS image format not supported."); 1616 return 0; 1617 } 1618 1619 if (ddsHeader.dwMipMapCount > 1) 1620 bufferSize = ddsHeader.dwLinearSize * factor; 1621 else 1622 bufferSize = ddsHeader.dwLinearSize; 1623 1624 GLubyte *pixels = (GLubyte *) malloc(bufferSize*sizeof(GLubyte)); 1625 f.seek(ddsHeader.dwSize + 4); 1626 f.read((char *) pixels, bufferSize); 1627 f.close(); 1628 1629 GLuint tx_id; 1630 glGenTextures(1, &tx_id); 1631 glBindTexture(GL_TEXTURE_2D, tx_id); 1632 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1633 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1634 1635 int size; 1636 int offset = 0; 1637 int w = ddsHeader.dwWidth; 1638 int h = ddsHeader.dwHeight; 1639 1640 // load mip-maps 1641 for(int i = 0; i < (int) ddsHeader.dwMipMapCount; ++i) { 1642 if (w == 0) w = 1; 1643 if (h == 0) h = 1; 1644 1645 size = ((w+3)/4) * ((h+3)/4) * blockSize; 1646 qt_glCompressedTexImage2DARB(GL_TEXTURE_2D, i, format, w, h, 0, 1647 size, pixels + offset); 1648 offset += size; 1649 1650 // half size for each mip-map level 1651 w = w/2; 1652 h = h/2; 1653 } 1654 1655 free(pixels); 1656 1657 qgl_dds_cache()->insert(fileName, tx_id); 1658 return tx_id; 1659 } 1660 1661 /* 1662 a hook that removes textures from the cache when a pixmap/image 1663 is deref'ed 1664 */ 1665 static void qt_gl_clean_cache(qint64 cacheKey) 1666 { 1667 // ### remove when the GL texture cache becomes thread-safe 1668 if (qApp->thread() != QThread::currentThread()) 1669 return; 1670 if (qt_tex_cache) { 1671 QGLTexture *texture = qt_tex_cache->object(cacheKey); 1672 if (texture && texture->clean) 1673 qt_tex_cache->remove(cacheKey); 1674 } 1910 1911 dds_cache->insert(fileName, texture.id); 1912 return texture.id; 1913 } 1914 1915 static inline QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format) 1916 { 1917 if (texture_format == GL_BGRA) { 1918 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 1919 return ((src_pixel << 24) & 0xff000000) 1920 | ((src_pixel >> 24) & 0x000000ff) 1921 | ((src_pixel << 8) & 0x00ff0000) 1922 | ((src_pixel >> 8) & 0x0000ff00); 1923 } else { 1924 return src_pixel; 1925 } 1926 } else { // GL_RGBA 1927 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 1928 return (src_pixel << 8) | ((src_pixel >> 24) & 0xff); 1929 } else { 1930 return ((src_pixel << 16) & 0xff0000) 1931 | ((src_pixel >> 16) & 0xff) 1932 | (src_pixel & 0xff00ff00); 1933 } 1934 } 1935 } 1936 1937 QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format) 1938 { 1939 return qt_gl_convertToGLFormatHelper(src_pixel, texture_format); 1675 1940 } 1676 1941 1677 1942 static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format) 1678 1943 { 1679 Q_ASSERT(dst.size() == img.size());1680 1944 Q_ASSERT(dst.depth() == 32); 1681 1945 Q_ASSERT(img.depth() == 32); 1682 1946 1683 const int width = img.width(); 1684 const int height = img.height(); 1685 const uint *p = (const uint*) img.scanLine(img.height() - 1); 1686 uint *q = (uint*) dst.scanLine(0); 1687 1688 if (texture_format == GL_BGRA) { 1689 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 1690 // mirror + swizzle 1691 for (int i=0; i < height; ++i) { 1692 const uint *end = p + width; 1693 while (p < end) { 1694 *q = ((*p << 24) & 0xff000000) 1695 | ((*p >> 24) & 0x000000ff) 1696 | ((*p << 8) & 0x00ff0000) 1697 | ((*p >> 8) & 0x0000ff00); 1698 p++; 1699 q++; 1947 if (dst.size() != img.size()) { 1948 int target_width = dst.width(); 1949 int target_height = dst.height(); 1950 qreal sx = target_width / qreal(img.width()); 1951 qreal sy = target_height / qreal(img.height()); 1952 1953 quint32 *dest = (quint32 *) dst.scanLine(0); // NB! avoid detach here 1954 uchar *srcPixels = (uchar *) img.scanLine(img.height() - 1); 1955 int sbpl = img.bytesPerLine(); 1956 int dbpl = dst.bytesPerLine(); 1957 1958 int ix = int(0x00010000 / sx); 1959 int iy = int(0x00010000 / sy); 1960 1961 quint32 basex = int(0.5 * ix); 1962 quint32 srcy = int(0.5 * iy); 1963 1964 // scale, swizzle and mirror in one loop 1965 while (target_height--) { 1966 const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl); 1967 int srcx = basex; 1968 for (int x=0; x<target_width; ++x) { 1969 dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format); 1970 srcx += ix; 1971 } 1972 dest = (quint32 *)(((uchar *) dest) + dbpl); 1973 srcy += iy; 1974 } 1975 } else { 1976 const int width = img.width(); 1977 const int height = img.height(); 1978 const uint *p = (const uint*) img.scanLine(img.height() - 1); 1979 uint *q = (uint*) dst.scanLine(0); 1980 1981 if (texture_format == GL_BGRA) { 1982 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 1983 // mirror + swizzle 1984 for (int i=0; i < height; ++i) { 1985 const uint *end = p + width; 1986 while (p < end) { 1987 *q = ((*p << 24) & 0xff000000) 1988 | ((*p >> 24) & 0x000000ff) 1989 | ((*p << 8) & 0x00ff0000) 1990 | ((*p >> 8) & 0x0000ff00); 1991 p++; 1992 q++; 1993 } 1994 p -= 2 * width; 1700 1995 } 1701 p -= 2 * width; 1996 } else { 1997 const uint bytesPerLine = img.bytesPerLine(); 1998 for (int i=0; i < height; ++i) { 1999 memcpy(q, p, bytesPerLine); 2000 q += width; 2001 p -= width; 2002 } 1702 2003 } 1703 2004 } else { 1704 const uint bytesPerLine = img.bytesPerLine(); 1705 for (int i=0; i < height; ++i) { 1706 memcpy(q, p, bytesPerLine); 1707 q += width; 1708 p -= width; 1709 } 1710 } 1711 } else { 1712 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 1713 for (int i=0; i < height; ++i) { 1714 const uint *end = p + width; 1715 while (p < end) { 1716 *q = (*p << 8) | ((*p >> 24) & 0xFF); 1717 p++; 1718 q++; 2005 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { 2006 for (int i=0; i < height; ++i) { 2007 const uint *end = p + width; 2008 while (p < end) { 2009 *q = (*p << 8) | ((*p >> 24) & 0xff); 2010 p++; 2011 q++; 2012 } 2013 p -= 2 * width; 1719 2014 } 1720 p -= 2 * width;1721 }1722 } else {1723 for (int i=0; i < height; ++i) {1724 const uint *end = p + width;1725 while (p < end) {1726 *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);1727 p++;1728 q++;2015 } else { 2016 for (int i=0; i < height; ++i) { 2017 const uint *end = p + width; 2018 while (p < end) { 2019 *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); 2020 p++; 2021 q++; 2022 } 2023 p -= 2 * width; 1729 2024 } 1730 p -= 2 * width;1731 2025 } 1732 2026 } … … 1746 2040 } 1747 2041 1748 GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, 1749 const qint64 key, bool clean) 2042 /*! \internal */ 2043 QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, 2044 QGLContext::BindOptions options) 2045 { 2046 const qint64 key = image.cacheKey(); 2047 QGLTexture *texture = textureCacheLookup(key, target); 2048 if (texture) { 2049 glBindTexture(target, texture->id); 2050 return texture; 2051 } 2052 2053 if (!texture) 2054 texture = bindTexture(image, target, format, key, options); 2055 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null 2056 Q_ASSERT(texture); 2057 2058 if (texture->id > 0) 2059 QImagePixmapCleanupHooks::enableCleanupHooks(image); 2060 2061 return texture; 2062 } 2063 2064 // #define QGL_BIND_TEXTURE_DEBUG 2065 2066 // map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout 2067 static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) 2068 { 2069 const int width = img.width(); 2070 const int height = img.height(); 2071 2072 if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV 2073 || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) 2074 { 2075 for (int i = 0; i < height; ++i) { 2076 uint *p = (uint *) img.scanLine(i); 2077 for (int x = 0; x < width; ++x) 2078 p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); 2079 } 2080 } else { 2081 for (int i = 0; i < height; ++i) { 2082 uint *p = (uint *) img.scanLine(i); 2083 for (int x = 0; x < width; ++x) 2084 p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); 2085 } 2086 } 2087 } 2088 2089 QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat, 2090 const qint64 key, QGLContext::BindOptions options) 1750 2091 { 1751 2092 Q_Q(QGLContext); 1752 2093 1753 QGLContext *ctx = q; 1754 1755 bool use_pbo = false; 1756 if (QGLExtensions::glExtensions & QGLExtensions::PixelBufferObject) { 1757 1758 use_pbo = qt_resolve_buffer_extensions(ctx); 1759 if (use_pbo && pbo == 0) 1760 glGenBuffersARB(1, &pbo); 1761 } 1762 1763 // the GL_BGRA format is only present in GL version >= 1.2 1764 GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2) 1765 ? GL_BGRA : GL_RGBA; 1766 if (!qt_tex_cache) { 1767 qt_tex_cache = new QGLTextureCache(qt_tex_cache_limit); 1768 qt_pixmap_cleanup_hook_64 = qt_gl_clean_cache; 1769 qt_image_cleanup_hook_64 = qt_gl_clean_cache; 1770 } 2094 #ifdef QGL_BIND_TEXTURE_DEBUG 2095 printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), internalFormat =0x%x, options=%x\n", 2096 image.width(), image.height(), internalFormat, int(options)); 2097 QTime time; 2098 time.start(); 2099 #endif 2100 2101 #ifndef QT_NO_DEBUG 2102 // Reset the gl error stack...git 2103 while (glGetError() != GL_NO_ERROR) ; 2104 #endif 1771 2105 1772 2106 // Scale the pixmap if needed. GL textures needs to have the 1773 // dimensions 2^n+2(border) x 2^m+2(border). 2107 // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL 2108 // 2.0 or use the GL_TEXTURE_RECTANGLE texture target 1774 2109 int tx_w = qt_next_power_of_two(image.width()); 1775 2110 int tx_h = qt_next_power_of_two(image.height()); 1776 2111 1777 // Note: the clean param is only true when a texture is bound1778 // from the QOpenGLPaintEngine - in that case we have to force1779 // a premultiplied texture format1780 2112 QImage img = image; 1781 if ( ( !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) &&1782 !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))2113 if (!(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) 2114 && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) 1783 2115 && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height()))) 1784 2116 { 1785 img = image.scaled(tx_w, tx_h); 1786 } 2117 img = img.scaled(tx_w, tx_h); 2118 #ifdef QGL_BIND_TEXTURE_DEBUG 2119 printf(" - upscaled to %dx%d (%d ms)\n", tx_w, tx_h, time.elapsed()); 2120 2121 #endif 2122 } 2123 2124 GLuint filtering = options & QGLContext::LinearFilteringBindOption ? GL_LINEAR : GL_NEAREST; 1787 2125 1788 2126 GLuint tx_id; 1789 2127 glGenTextures(1, &tx_id); 1790 2128 glBindTexture(target, tx_id); 1791 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 2129 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, filtering); 2130 2131 #if defined(QT_OPENGL_ES_2) 2132 bool genMipmap = false; 2133 #endif 1792 2134 if (glFormat.directRendering() 1793 && QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap 1794 && target == GL_TEXTURE_2D && !clean) 2135 && (QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap) 2136 && target == GL_TEXTURE_2D 2137 && (options & QGLContext::MipmapBindOption)) 1795 2138 { 2139 #ifdef QGL_BIND_TEXTURE_DEBUG 2140 printf(" - generating mipmaps (%d ms)\n", time.elapsed()); 2141 #endif 2142 #if !defined(QT_OPENGL_ES_2) 1796 2143 glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); 1797 2144 #ifndef QT_OPENGL_ES … … 1800 2147 glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); 1801 2148 #endif 1802 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 1803 1804 // Mipmap generation causes huge slowdown with PBO's for some reason 1805 use_pbo = false; 2149 #else 2150 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); 2151 genMipmap = true; 2152 #endif 2153 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, options & QGLContext::LinearFilteringBindOption 2154 ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST); 1806 2155 } else { 1807 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1808 } 1809 1810 uchar *ptr = 0; 1811 if (use_pbo) { 1812 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); 1813 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, img.width() * img.height() * 4, 0, GL_STREAM_DRAW_ARB); 1814 ptr = reinterpret_cast<uchar *>(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB)); 1815 } 1816 1817 if (ptr) { 1818 QImage::Format target_format = img.format(); 1819 if (clean || img.format() != QImage::Format_ARGB32) 1820 target_format = QImage::Format_ARGB32_Premultiplied; 1821 1822 QImage buffer(ptr, img.width(), img.height(), target_format); 1823 convertToGLFormatHelper(buffer, img.convertToFormat(target_format), texture_format); 1824 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); 1825 glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format, GL_UNSIGNED_BYTE, 0); 2156 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, filtering); 2157 } 2158 2159 QImage::Format target_format = img.format(); 2160 bool premul = options & QGLContext::PremultipliedAlphaBindOption; 2161 GLenum externalFormat; 2162 GLuint pixel_type; 2163 if (QGLExtensions::glExtensions & QGLExtensions::BGRATextureFormat) { 2164 externalFormat = GL_BGRA; 2165 pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV; 1826 2166 } else { 1827 QImage tx = convertToGLFormat(img, clean, texture_format); 1828 glTexImage2D(target, 0, format, tx.width(), tx.height(), 0, texture_format, 1829 GL_UNSIGNED_BYTE, tx.bits()); 1830 } 1831 1832 if (use_pbo) 1833 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); 2167 externalFormat = GL_RGBA; 2168 pixel_type = GL_UNSIGNED_BYTE; 2169 } 2170 2171 switch (target_format) { 2172 case QImage::Format_ARGB32: 2173 if (premul) { 2174 img = img.convertToFormat(target_format = QImage::Format_ARGB32_Premultiplied); 2175 #ifdef QGL_BIND_TEXTURE_DEBUG 2176 printf(" - converting ARGB32 -> ARGB32_Premultiplied (%d ms) \n", time.elapsed()); 2177 #endif 2178 } 2179 break; 2180 case QImage::Format_ARGB32_Premultiplied: 2181 if (!premul) { 2182 img = img.convertToFormat(target_format = QImage::Format_ARGB32); 2183 #ifdef QGL_BIND_TEXTURE_DEBUG 2184 printf(" - converting ARGB32_Premultiplied -> ARGB32 (%d ms)\n", time.elapsed()); 2185 #endif 2186 } 2187 break; 2188 case QImage::Format_RGB16: 2189 pixel_type = GL_UNSIGNED_SHORT_5_6_5; 2190 externalFormat = GL_RGB; 2191 internalFormat = GL_RGB; 2192 break; 2193 case QImage::Format_RGB32: 2194 break; 2195 default: 2196 if (img.hasAlphaChannel()) { 2197 img = img.convertToFormat(premul 2198 ? QImage::Format_ARGB32_Premultiplied 2199 : QImage::Format_ARGB32); 2200 #ifdef QGL_BIND_TEXTURE_DEBUG 2201 printf(" - converting to 32-bit alpha format (%d ms)\n", time.elapsed()); 2202 #endif 2203 } else { 2204 img = img.convertToFormat(QImage::Format_RGB32); 2205 #ifdef QGL_BIND_TEXTURE_DEBUG 2206 printf(" - converting to 32-bit (%d ms)\n", time.elapsed()); 2207 #endif 2208 } 2209 } 2210 2211 if (options & QGLContext::InvertedYBindOption) { 2212 #ifdef QGL_BIND_TEXTURE_DEBUG 2213 printf(" - flipping bits over y (%d ms)\n", time.elapsed()); 2214 #endif 2215 if (img.isDetached()) { 2216 int ipl = img.bytesPerLine() / 4; 2217 int h = img.height(); 2218 for (int y=0; y<h/2; ++y) { 2219 int *a = (int *) img.scanLine(y); 2220 int *b = (int *) img.scanLine(h - y - 1); 2221 for (int x=0; x<ipl; ++x) 2222 qSwap(a[x], b[x]); 2223 } 2224 } else { 2225 // Create a new image and copy across. If we use the 2226 // above in-place code then a full copy of the image is 2227 // made before the lines are swapped, which processes the 2228 // data twice. This version should only do it once. 2229 img = img.mirrored(); 2230 } 2231 } 2232 2233 if (externalFormat == GL_RGBA) { 2234 #ifdef QGL_BIND_TEXTURE_DEBUG 2235 printf(" - doing byte swapping (%d ms)\n", time.elapsed()); 2236 #endif 2237 // The only case where we end up with a depth different from 2238 // 32 in the switch above is for the RGB16 case, where we set 2239 // the format to GL_RGB 2240 Q_ASSERT(img.depth() == 32); 2241 qgl_byteSwapImage(img, pixel_type); 2242 } 2243 #ifdef QT_OPENGL_ES 2244 // OpenGL/ES requires that the internal and external formats be identical. 2245 // This is typically used to convert GL_RGBA into GL_BGRA. 2246 // Also, we need to use GL_UNSIGNED_BYTE when the format is GL_BGRA. 2247 internalFormat = externalFormat; 2248 if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV) 2249 pixel_type = GL_UNSIGNED_BYTE; 2250 #endif 2251 #ifdef QGL_BIND_TEXTURE_DEBUG 2252 printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n", 2253 img.format(), externalFormat, internalFormat, pixel_type); 2254 #endif 2255 2256 const QImage &constRef = img; // to avoid detach in bits()... 2257 glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat, 2258 pixel_type, constRef.bits()); 2259 #if defined(QT_OPENGL_ES_2) 2260 if (genMipmap) 2261 glGenerateMipmap(target); 2262 #endif 2263 #ifndef QT_NO_DEBUG 2264 GLenum error = glGetError(); 2265 if (error != GL_NO_ERROR) { 2266 qWarning(" - texture upload failed, error code 0x%x\n", error); 2267 } 2268 #endif 2269 2270 #ifdef QGL_BIND_TEXTURE_DEBUG 2271 static int totalUploadTime = 0; 2272 totalUploadTime += time.elapsed(); 2273 printf(" - upload done in (%d ms) time=%d\n", time.elapsed(), totalUploadTime); 2274 #endif 2275 1834 2276 1835 2277 // this assumes the size of a texture is always smaller than the max cache size 1836 2278 int cost = img.width()*img.height()*4/1024; 1837 if (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost()) { 1838 // the cache is full - make an attempt to remove something 1839 const QList<qint64> keys = qt_tex_cache->keys(); 1840 int i = 0; 1841 while (i < qt_tex_cache->count() 1842 && (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost())) { 1843 QGLTexture *tex = qt_tex_cache->object(keys.at(i)); 1844 if (tex->context == q) 1845 qt_tex_cache->remove(keys.at(i)); 1846 ++i; 2279 QGLTexture *texture = new QGLTexture(q, tx_id, target, options); 2280 QGLTextureCache::instance()->insert(q, key, texture, cost); 2281 return texture; 2282 } 2283 2284 QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target) 2285 { 2286 Q_Q(QGLContext); 2287 QGLTexture *texture = QGLTextureCache::instance()->getTexture(key); 2288 if (texture && texture->target == target 2289 && (texture->context == q || QGLContext::areSharing(q, texture->context))) 2290 { 2291 return texture; 2292 } 2293 return 0; 2294 } 2295 2296 2297 /*! \internal */ 2298 QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options) 2299 { 2300 Q_Q(QGLContext); 2301 QPixmapData *pd = pixmap.pixmapData(); 2302 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) 2303 if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) { 2304 const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pd); 2305 2306 if (data->isValidContext(q)) { 2307 data->bind(); 2308 return data->texture(); 1847 2309 } 1848 2310 } 1849 qt_tex_cache->insert(key, new QGLTexture(q, tx_id, target, clean), cost); 1850 return tx_id; 1851 } 1852 1853 bool QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target, GLuint *id) 1854 { 1855 Q_Q(QGLContext); 1856 if (qt_tex_cache) { 1857 QGLTexture *texture = qt_tex_cache->object(key); 1858 if (texture && texture->target == target 1859 && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context))) 1860 { 1861 *id = texture->id; 1862 return true; 2311 #else 2312 Q_UNUSED(pd); 2313 Q_UNUSED(q); 2314 #endif 2315 2316 const qint64 key = pixmap.cacheKey(); 2317 QGLTexture *texture = textureCacheLookup(key, target); 2318 if (texture) { 2319 glBindTexture(target, texture->id); 2320 return texture; 2321 } 2322 2323 #if defined(Q_WS_X11) 2324 // Try to use texture_from_pixmap 2325 if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType) { 2326 texture = bindTextureFromNativePixmap(pd, key, options); 2327 if (texture) { 2328 texture->options |= QGLContext::MemoryManagedBindOption; 2329 texture->boundPixmap = pd; 2330 boundPixmaps.insert(pd, QPixmap(pixmap)); 1863 2331 } 1864 2332 } 1865 return false; 1866 } 1867 1868 /*! \internal */ 1869 GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean) 1870 { 1871 const qint64 key = image.cacheKey(); 1872 GLuint id; 1873 if (textureCacheLookup(key, target, &id)) { 1874 glBindTexture(target, id); 1875 return id; 1876 } 1877 GLuint cached = bindTexture(image, target, format, key, clean); 1878 const_cast<QImage &>(image).data_ptr()->is_cached = (cached > 0); 1879 return cached; 1880 } 1881 1882 /*! \internal */ 1883 GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean) 1884 { 1885 #if !defined(QT_OPENGL_ES_2) 1886 if (target == qt_gl_preferredTextureTarget() && pixmap.pixmapData()->classId() == QPixmapData::OpenGLClass) { 1887 const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pixmap.pixmapData()); 1888 1889 if (data->isValidContext(QGLContext::currentContext())) 1890 return data->bind(); 1891 } 1892 #endif 1893 1894 const qint64 key = pixmap.cacheKey(); 1895 GLuint id; 1896 if (textureCacheLookup(key, target, &id)) { 1897 glBindTexture(target, id); 1898 return id; 1899 } 1900 GLuint cached = bindTexture(pixmap.toImage(), target, format, key, clean); 1901 const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = (cached > 0); 1902 return cached; 2333 #endif 2334 2335 if (!texture) 2336 texture = bindTexture(pixmap.toImage(), target, format, key, options); 2337 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null 2338 Q_ASSERT(texture); 2339 2340 if (texture->id > 0) 2341 QImagePixmapCleanupHooks::enableCleanupHooks(pixmap); 2342 2343 return texture; 1903 2344 } 1904 2345 … … 1939 2380 1940 2381 /*! 2382 Generates and binds a 2D GL texture to the current context, based 2383 on \a image. The generated texture id is returned and can be used in 2384 later \c glBindTexture() calls. 2385 2386 \overload 2387 */ 2388 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) 2389 { 2390 if (image.isNull()) 2391 return 0; 2392 2393 Q_D(QGLContext); 2394 QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption); 2395 return texture->id; 2396 } 2397 2398 /*! 2399 \since 4.6 2400 1941 2401 Generates and binds a 2D GL texture to the current context, based 1942 2402 on \a image. The generated texture id is returned and can be used … … 1947 2407 1948 2408 The \a format parameter sets the internal format for the 1949 texture. The default format is \c GL_RGBA8. 1950 1951 If the GL implementation supports the \c GL_SGIS_generate_mipmap 1952 extension, mipmaps will be automatically generated for the 1953 texture. Mipmap generation is only supported for the \c 1954 GL_TEXTURE_2D target. 2409 texture. The default format is \c GL_RGBA. 2410 2411 The binding \a options are a set of options used to decide how to 2412 bind the texture to the context. 1955 2413 1956 2414 The texture that is generated is cached, so multiple calls to … … 1963 2421 \sa deleteTexture() 1964 2422 */ 1965 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) 1966 { 2423 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options) 2424 { 2425 if (image.isNull()) 2426 return 0; 2427 1967 2428 Q_D(QGLContext); 1968 return d->bindTexture(image, target, format, false); 2429 QGLTexture *texture = d->bindTexture(image, target, format, false, options); 2430 return texture->id; 1969 2431 } 1970 2432 … … 1973 2435 GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) 1974 2436 { 2437 if (image.isNull()) 2438 return 0; 2439 1975 2440 Q_D(QGLContext); 1976 return d->bindTexture(image, GLenum(target), GLint(format), false); 2441 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption); 2442 return texture->id; 2443 } 2444 2445 /*! \internal */ 2446 GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, 2447 BindOptions options) 2448 { 2449 if (image.isNull()) 2450 return 0; 2451 2452 Q_D(QGLContext); 2453 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options); 2454 return texture->id; 1977 2455 } 1978 2456 #endif … … 1984 2462 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) 1985 2463 { 2464 if (pixmap.isNull()) 2465 return 0; 2466 1986 2467 Q_D(QGLContext); 1987 return d->bindTexture(pixmap, target, format, false); 2468 QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption); 2469 return texture->id; 2470 } 2471 2472 /*! 2473 \overload 2474 \since 4.6 2475 2476 Generates and binds a 2D GL texture to the current context, based 2477 on \a pixmap. 2478 */ 2479 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options) 2480 { 2481 if (pixmap.isNull()) 2482 return 0; 2483 2484 Q_D(QGLContext); 2485 QGLTexture *texture = d->bindTexture(pixmap, target, format, options); 2486 return texture->id; 1988 2487 } 1989 2488 … … 1992 2491 GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format) 1993 2492 { 2493 if (pixmap.isNull()) 2494 return 0; 2495 1994 2496 Q_D(QGLContext); 1995 return d->bindTexture(pixmap, GLenum(target), GLint(format), false); 2497 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption); 2498 return texture->id; 2499 } 2500 /*! \internal */ 2501 GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format, 2502 BindOptions options) 2503 { 2504 if (pixmap.isNull()) 2505 return 0; 2506 2507 Q_D(QGLContext); 2508 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options); 2509 return texture->id; 1996 2510 } 1997 2511 #endif … … 2006 2520 void QGLContext::deleteTexture(GLuint id) 2007 2521 { 2008 if (qt_tex_cache) { 2009 QList<qint64> keys = qt_tex_cache->keys(); 2010 for (int i = 0; i < keys.size(); ++i) { 2011 QGLTexture *tex = qt_tex_cache->object(keys.at(i)); 2012 if (tex->id == id && tex->context == this) { 2013 tex->clean = true; // forces a glDeleteTextures() call 2014 qt_tex_cache->remove(keys.at(i)); 2015 return; 2016 } 2017 } 2018 } 2522 Q_D(QGLContext); 2523 2524 if (QGLTextureCache::instance()->remove(this, id)) 2525 return; 2019 2526 2020 2527 // check the DDS cache if the texture wasn't found in the pixmap/image 2021 2528 // cache 2022 QList<QString> ddsKeys = qgl_dds_cache()->keys(); 2529 QGLDDSCache *dds_cache = &(d->group->m_dds_cache); 2530 QList<QString> ddsKeys = dds_cache->keys(); 2023 2531 for (int i = 0; i < ddsKeys.size(); ++i) { 2024 GLuint texture = qgl_dds_cache()->value(ddsKeys.at(i));2532 GLuint texture = dds_cache->value(ddsKeys.at(i)); 2025 2533 if (id == texture) { 2026 2534 glDeleteTextures(1, &texture); 2027 qgl_dds_cache()->remove(ddsKeys.at(i));2535 dds_cache->remove(ddsKeys.at(i)); 2028 2536 return; 2029 2537 } … … 2039 2547 #endif 2040 2548 2041 // qpaintengine_opengl.cpp 2549 void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) 2550 { 2551 qreal left = r.left(); 2552 qreal right = r.right(); 2553 qreal top = r.top(); 2554 qreal bottom = r.bottom(); 2555 2556 array[0] = f2vt(left); 2557 array[1] = f2vt(top); 2558 array[2] = f2vt(right); 2559 array[3] = f2vt(top); 2560 array[4] = f2vt(right); 2561 array[5] = f2vt(bottom); 2562 array[6] = f2vt(left); 2563 array[7] = f2vt(bottom); 2564 } 2565 2566 void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array) 2567 { 2568 array[0] = f2vt(x1); 2569 array[1] = f2vt(y1); 2570 array[2] = f2vt(x2); 2571 array[3] = f2vt(y1); 2572 array[4] = f2vt(x2); 2573 array[5] = f2vt(y2); 2574 array[6] = f2vt(x1); 2575 array[7] = f2vt(y2); 2576 } 2577 2042 2578 #if !defined(QT_OPENGL_ES_2) 2043 extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);2044 #else2045 void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) {};2046 #endif2047 2579 2048 2580 static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget) … … 2074 2606 qt_add_rect_to_array(target, vertexArray); 2075 2607 2076 #if !defined(QT_OPENGL_ES_2)2077 2608 glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray); 2078 2609 glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray); … … 2084 2615 glDisableClientState(GL_VERTEX_ARRAY); 2085 2616 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 2086 #endif 2087 } 2617 } 2618 2619 #endif // !QT_OPENGL_ES_2 2088 2620 2089 2621 /*! … … 2094 2626 texture target. 2095 2627 2096 Equivalent to the corresponding QGLContext::drawTexture().2628 \note This function is not supported under OpenGL/ES 2.0. 2097 2629 */ 2098 2630 void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) 2099 2631 { 2632 #ifndef QT_OPENGL_ES_2 2100 2633 #ifdef QT_OPENGL_ES 2101 2634 if (textureTarget != GL_TEXTURE_2D) { … … 2121 2654 glBindTexture(textureTarget, oldTexture); 2122 2655 #endif 2656 #else 2657 Q_UNUSED(target); 2658 Q_UNUSED(textureId); 2659 Q_UNUSED(textureTarget); 2660 qWarning("drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES/2.0"); 2661 #endif 2123 2662 } 2124 2663 … … 2137 2676 space. The \a textureTarget should be a 2D texture target. 2138 2677 2139 Equivalent to the corresponding QGLContext::drawTexture().2678 \note This function is not supported under OpenGL/ES. 2140 2679 */ 2141 2680 void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) … … 2188 2727 void QGLContext::setTextureCacheLimit(int size) 2189 2728 { 2190 qt_tex_cache_limit = size; 2191 if (qt_tex_cache) 2192 qt_tex_cache->setMaxCost(qt_tex_cache_limit); 2729 QGLTextureCache::instance()->setMaxCost(size); 2193 2730 } 2194 2731 … … 2200 2737 int QGLContext::textureCacheLimit() 2201 2738 { 2202 return qt_tex_cache_limit;2739 return QGLTextureCache::instance()->maxCost(); 2203 2740 } 2204 2741 … … 2279 2816 formats. 2280 2817 */ 2818 2819 /*! 2820 Returns true if \a context1 and \a context2 are sharing their 2821 GL resources such as textures, shader programs, etc; 2822 otherwise returns false. 2823 2824 \since 4.6 2825 */ 2826 bool QGLContext::areSharing(const QGLContext *context1, const QGLContext *context2) 2827 { 2828 if (!context1 || !context2) 2829 return false; 2830 return context1->d_ptr->group == context2->d_ptr->group; 2831 } 2281 2832 2282 2833 /*! … … 2399 2950 reset(); 2400 2951 d->valid = chooseContext(shareContext); 2952 if (d->valid && d->paintDevice->devType() == QInternal::Widget) { 2953 QWidgetPrivate *wd = qt_widget_private(static_cast<QWidget *>(d->paintDevice)); 2954 wd->usesDoubleBufferedGLContext = d->glFormat.doubleBuffer(); 2955 } 2401 2956 if (d->sharing) // ok, we managed to share 2402 2957 qgl_share_reg()->addShare(this, shareContext); … … 2419 2974 { 2420 2975 Q_D(const QGLContext); 2421 return d-> sharing;2976 return d->group->isSharing(); 2422 2977 } 2423 2978 … … 2474 3029 const QGLContext* QGLContext::currentContext() 2475 3030 { 2476 if (qgl_context_storage.hasLocalData()) 2477 return qgl_context_storage.localData()->context; 3031 QGLThreadContext *threadContext = qgl_context_storage.localData(); 3032 if (threadContext) 3033 return threadContext->context; 2478 3034 return 0; 3035 } 3036 3037 void QGLContextPrivate::setCurrentContext(QGLContext *context) 3038 { 3039 QGLThreadContext *threadContext = qgl_context_storage.localData(); 3040 if (!threadContext) { 3041 if (!QThread::currentThread()) { 3042 // We don't have a current QThread, so just set the static. 3043 QGLContext::currentCtx = context; 3044 return; 3045 } 3046 threadContext = new QGLThreadContext; 3047 qgl_context_storage.setLocalData(threadContext); 3048 } 3049 threadContext->context = context; 3050 QGLContext::currentCtx = context; // XXX: backwards-compat, not thread-safe 2479 3051 } 2480 3052 … … 2493 3065 */ 2494 3066 3067 /*! \fn int QGLContext::choosePixelFormat(void* dummyPfd, HDC pdc) 3068 3069 \bold{Win32 only:} This virtual function chooses a pixel format 3070 that matches the OpenGL \link setFormat() format\endlink. 3071 Reimplement this function in a subclass if you need a custom 3072 context. 3073 3074 \warning The \a dummyPfd pointer and \a pdc are used as a \c 3075 PIXELFORMATDESCRIPTOR*. We use \c void to avoid using 3076 Windows-specific types in our header files. 3077 3078 \sa chooseContext() 3079 */ 3080 3081 /*! \fn void *QGLContext::chooseVisual() 3082 3083 \bold{X11 only:} This virtual function tries to find a visual that 3084 matches the format, reducing the demands if the original request 3085 cannot be met. 3086 3087 The algorithm for reducing the demands of the format is quite 3088 simple-minded, so override this method in your subclass if your 3089 application has spcific requirements on visual selection. 3090 3091 \sa chooseContext() 3092 */ 3093 3094 /*! \fn void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) 3095 \internal 3096 3097 \bold{X11 only:} This virtual function chooses a visual that matches 3098 the OpenGL \link format() format\endlink. Reimplement this function 3099 in a subclass if you need a custom visual. 3100 3101 \sa chooseContext() 3102 */ 2495 3103 2496 3104 /*! … … 2561 3169 \brief The QGLWidget class is a widget for rendering OpenGL graphics. 2562 3170 2563 \ingroup multimedia2564 \mainclass 3171 \ingroup painting-3D 3172 2565 3173 2566 3174 QGLWidget provides functionality for displaying OpenGL graphics … … 2577 3185 needs to be updated. 2578 3186 \i resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets 2579 called whenever the thewidget has been resized (and also when it3187 called whenever the widget has been resized (and also when it 2580 3188 is shown for the first time because all newly created widgets get a 2581 3189 resize event automatically). … … 2603 3211 customized rendering \link QGLContext contexts\endlink. 2604 3212 2605 You can also share OpenGL display lists between QGLWidget s (see3213 You can also share OpenGL display lists between QGLWidget objects (see 2606 3214 the documentation of the QGLWidget constructors for details). 2607 3215 … … 2885 3493 Returns true if this widget's GL context is shared with another GL 2886 3494 context, otherwise false is returned. Context sharing might not be 2887 possible if the QGLWidgets use different formats.3495 possible if the widgets use different formats. 2888 3496 2889 3497 \sa format() … … 2983 3591 2984 3592 This method will try to keep display list and texture object sharing 2985 in effect with other QGLWidget s, but changing the format might make3593 in effect with other QGLWidget objects, but changing the format might make 2986 3594 sharing impossible. Use isSharing() to see if sharing is still in 2987 3595 effect. … … 3009 3617 3010 3618 /* 3619 \fn void QGLWidget::setContext(QGLContext *context, 3620 const QGLContext* shareContext, 3621 bool deleteOldContext) 3011 3622 \obsolete 3012 3013 \fn void QGLWidget::setContext(QGLContext *context,3014 const QGLContext* shareContext,3015 bool deleteOldContext)3016 3623 3017 3624 Sets a new context for this widget. The QGLContext \a context must … … 3163 3770 } 3164 3771 3165 3772 /*! \fn bool QGLWidget::event(QEvent *e) 3773 \reimp 3774 */ 3166 3775 #if !defined(Q_OS_WINCE) && !defined(Q_WS_QWS) 3167 /*! \reimp */3168 3776 bool QGLWidget::event(QEvent *e) 3169 3777 { … … 3191 3799 doneCurrent(); 3192 3800 } else if (e->type() == QEvent::ParentChange) { 3193 if (d->glcx->d_func()->screen != d->xinfo.screen()) { 3801 // if we've reparented a window that has the current context 3802 // bound, we need to rebind that context to the new window id 3803 if (d->glcx == QGLContext::currentContext()) 3804 makeCurrent(); 3805 3806 if (d->glcx->d_func()->screen != d->xinfo.screen() || testAttribute(Qt::WA_TranslucentBackground)) { 3194 3807 setContext(new QGLContext(d->glcx->requestedFormat(), this)); 3195 3808 // ### recreating the overlay isn't supported atm 3196 3809 } 3810 } 3811 3197 3812 #if defined(QT_OPENGL_ES) 3198 // The window may have been re-created during re-parent - if so, the EGL 3813 // A re-parent is likely to destroy the X11 window and re-create it. It is important 3814 // that we free the EGL surface _before_ the winID changes - otherwise we can leak. 3815 if (e->type() == QEvent::ParentAboutToChange) 3816 d->glcx->d_func()->destroyEglSurfaceForDevice(); 3817 3818 if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) { 3819 // The window may have been re-created during re-parent or state change - if so, the EGL 3199 3820 // surface will need to be re-created. 3200 3821 d->recreateEglSurface(false); 3201 #endif 3202 } 3822 } 3823 #endif 3203 3824 #elif defined(Q_WS_WIN) 3204 3825 if (e->type() == QEvent::ParentChange) { 3205 3826 QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this); 3206 qgl_share_reg()->replaceShare(d->glcx, newContext);3207 setContext(newContext); 3827 setContext(newContext, d->glcx); 3828 3208 3829 // the overlay needs to be recreated as well 3209 3830 delete d->olcx; … … 3284 3905 Renders the current scene on a pixmap and returns the pixmap. 3285 3906 3286 You can use this method on both visible and invisible QGLWidget s.3907 You can use this method on both visible and invisible QGLWidget objects. 3287 3908 3288 3909 This method will create a pixmap and a temporary QGLContext to … … 3406 4027 const QVector<QColor> pal = QColormap::instance().colormap(); 3407 4028 if (pal.size()) { 3408 res.set NumColors(pal.size());4029 res.setColorCount(pal.size()); 3409 4030 for (int i = 0; i < pal.size(); i++) 3410 4031 res.setColor(i, pal.at(i).rgb()); … … 3470 4091 with the color \a c. Applies to this widgets GL context. 3471 4092 4093 \note This function is not supported on OpenGL/ES 2.0 systems. 4094 3472 4095 \sa qglClearColor(), QGLContext::currentContext(), QColor 3473 4096 */ … … 3477 4100 #if !defined(QT_OPENGL_ES_2) 3478 4101 #ifdef QT_OPENGL_ES 3479 glColor4f(c.red ()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0);4102 glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()); 3480 4103 #else 3481 4104 Q_D(const QGLWidget); … … 3483 4106 if (ctx) { 3484 4107 if (ctx->format().rgba()) 3485 glColor4 ub(c.red(), c.green(), c.blue(), c.alpha());4108 glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()); 3486 4109 else if (!d->cmap.isEmpty()) { // QGLColormap in use? 3487 4110 int i = d->cmap.find(c.rgb()); … … 3493 4116 } 3494 4117 #endif //QT_OPENGL_ES 4118 #else 4119 Q_UNUSED(c); 3495 4120 #endif //QT_OPENGL_ES_2 3496 4121 } … … 3507 4132 { 3508 4133 #ifdef QT_OPENGL_ES 3509 glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0, 3510 (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0); 4134 glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); 3511 4135 #else 3512 4136 Q_D(const QGLWidget); … … 3514 4138 if (ctx) { 3515 4139 if (ctx->format().rgba()) 3516 glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0, 3517 (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0); 4140 glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); 3518 4141 else if (!d->cmap.isEmpty()) { // QGLColormap in use? 3519 4142 int i = d->cmap.find(c.rgb()); … … 3586 4209 will return the colormap for the child's top-level widget. 3587 4210 3588 If no colormap has been set for this widget, the Q Colormap4211 If no colormap has been set for this widget, the QGLColormap 3589 4212 returned will be empty. 3590 4213 3591 \sa setColormap() 4214 \sa setColormap(), QGLColormap::isEmpty() 3592 4215 */ 3593 4216 … … 3609 4232 value used when generating the display lists for the font. The 3610 4233 default value is 2000. 4234 4235 \note This function is not supported on OpenGL/ES systems. 3611 4236 */ 3612 4237 int QGLWidget::fontDisplayListBase(const QFont & font, int listBase) 3613 4238 { 4239 #ifndef QT_OPENGL_ES 3614 4240 Q_D(QGLWidget); 3615 4241 int base; … … 3629 4255 if (font.styleStrategy() != QFont::NoAntialias) { 3630 4256 GLfloat color[4]; 3631 #ifndef QT_OPENGL_ES3632 4257 glGetFloatv(GL_CURRENT_COLOR, color); 3633 #endif3634 4258 color_key.sprintf("%f_%f_%f",color[0], color[1], color[2]); 3635 4259 } … … 3654 4278 } 3655 4279 return base; 3656 } 4280 #else // QT_OPENGL_ES 4281 Q_UNUSED(font); 4282 Q_UNUSED(listBase); 4283 return 0; 4284 #endif 4285 } 4286 4287 #ifndef QT_OPENGL_ES 3657 4288 3658 4289 static void qt_save_gl_state() 3659 4290 { 3660 #ifndef QT_OPENGL_ES3661 4291 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); 3662 4292 glPushAttrib(GL_ALL_ATTRIB_BITS); 3663 #endif3664 #if !defined(QT_OPENGL_ES_2)3665 4293 glMatrixMode(GL_TEXTURE); 3666 4294 glPushMatrix(); … … 3675 4303 glDisable(GL_LIGHTING); 3676 4304 glDisable(GL_STENCIL_TEST); 4305 glDisable(GL_DEPTH_TEST); 3677 4306 glEnable(GL_BLEND); 3678 4307 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 3679 #endif // !defined(QT_OPENGL_ES_2)3680 4308 } 3681 4309 3682 4310 static void qt_restore_gl_state() 3683 4311 { 3684 #if !defined(QT_OPENGL_ES_2)3685 4312 glMatrixMode(GL_TEXTURE); 3686 4313 glPopMatrix(); … … 3689 4316 glMatrixMode(GL_MODELVIEW); 3690 4317 glPopMatrix(); 3691 #endif // !defined(QT_OPENGL_ES_2)3692 #ifndef QT_OPENGL_ES3693 4318 glPopAttrib(); 3694 4319 glPopClientAttrib(); 3695 #endif3696 4320 } 3697 4321 … … 3700 4324 { 3701 4325 GLfloat color[4]; 3702 #ifndef QT_OPENGL_ES3703 4326 glGetFloatv(GL_CURRENT_COLOR, &color[0]); 3704 #endif3705 4327 3706 4328 QColor col; … … 3716 4338 p->setFont(old_font); 3717 4339 } 4340 4341 #endif // !QT_OPENGL_ES 3718 4342 3719 4343 /*! … … 3731 4355 3732 4356 \note This function clears the stencil buffer. 4357 4358 \note This function is not supported on OpenGL/ES systems. 4359 4360 \note This function temporarily disables depth-testing when the 4361 text is drawn. 4362 4363 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. 3733 4364 */ 3734 4365 3735 4366 void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int) 3736 4367 { 4368 #ifndef QT_OPENGL_ES 3737 4369 Q_D(QGLWidget); 3738 4370 if (str.isEmpty() || !isValid()) … … 3740 4372 3741 4373 GLint view[4]; 3742 #ifndef QT_OPENGL_ES3743 4374 bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST); 3744 4375 if (!use_scissor_testing) 3745 4376 glGetIntegerv(GL_VIEWPORT, &view[0]); 3746 #else3747 bool use_scissor_testing = false;3748 #endif3749 4377 int width = d->glcx->device()->width(); 3750 4378 int height = d->glcx->device()->height(); 3751 4379 bool auto_swap = autoBufferSwap(); 3752 4380 4381 QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine(); 4382 qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL); 3753 4383 QPaintEngine *engine = paintEngine(); 3754 4384 QPainter *p; … … 3759 4389 qt_save_gl_state(); 3760 4390 3761 #if !defined(QT_OPENGL_ES_2)3762 4391 glDisable(GL_DEPTH_TEST); 3763 4392 glViewport(0, 0, width, height); 3764 4393 glMatrixMode(GL_PROJECTION); 3765 4394 glLoadIdentity(); 3766 #ifndef QT_OPENGL_ES3767 4395 glOrtho(0, width, height, 0, 0, 1); 3768 #else3769 glOrthof(0, width, height, 0, 0, 1);3770 #endif3771 4396 glMatrixMode(GL_MODELVIEW); 3772 4397 3773 4398 glLoadIdentity(); 3774 #endif // !defined(QT_OPENGL_ES_2)3775 4399 } else { 3776 4400 setAutoBufferSwap(false); 3777 4401 // disable glClear() as a result of QPainter::begin() 3778 d-> glcx->d_func()->clear_on_painter_begin = false;4402 d->disable_clear_on_painter_begin = true; 3779 4403 p = new QPainter(this); 3780 4404 } … … 3799 4423 delete p; 3800 4424 setAutoBufferSwap(auto_swap); 3801 d->glcx->d_func()->clear_on_painter_begin = true; 3802 } 4425 d->disable_clear_on_painter_begin = false; 4426 } 4427 qgl_engine_selector()->setPreferredPaintEngine(oldEngineType); 4428 #else // QT_OPENGL_ES 4429 Q_UNUSED(x); 4430 Q_UNUSED(y); 4431 Q_UNUSED(str); 4432 Q_UNUSED(font); 4433 qWarning("QGLWidget::renderText is not supported under OpenGL/ES"); 4434 #endif 3803 4435 } 3804 4436 … … 3809 4441 can be useful if you want to annotate models with text labels and 3810 4442 have the labels move with the model as it is rotated etc. 4443 4444 \note This function is not supported on OpenGL/ES systems. 4445 4446 \note If depth testing is enabled before this function is called, 4447 then the drawn text will be depth-tested against the models that 4448 have already been drawn in the scene. Use \c{glDisable(GL_DEPTH_TEST)} 4449 before calling this function to annotate the models without 4450 depth-testing the text. 4451 4452 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. 3811 4453 */ 3812 4454 void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int) 3813 4455 { 4456 #ifndef QT_OPENGL_ES 3814 4457 Q_D(QGLWidget); 3815 4458 if (str.isEmpty() || !isValid()) … … 3822 4465 GLdouble model[4][4], proj[4][4]; 3823 4466 GLint view[4]; 3824 #ifndef QT_OPENGL_ES3825 4467 glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]); 3826 4468 glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]); 3827 4469 glGetIntegerv(GL_VIEWPORT, &view[0]); 3828 #endif3829 4470 GLdouble win_x = 0, win_y = 0, win_z = 0; 3830 4471 qgluProject(x, y, z, &model[0][0], &proj[0][0], &view[0], … … 3832 4473 win_y = height - win_y; // y is inverted 3833 4474 4475 QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine(); 4476 qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL); 3834 4477 QPaintEngine *engine = paintEngine(); 3835 4478 QPainter *p; 3836 4479 bool reuse_painter = false; 3837 #ifndef QT_OPENGL_ES3838 4480 bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST); 3839 4481 bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST); 3840 #else3841 bool use_depth_testing = false;3842 bool use_scissor_testing = false;3843 #endif3844 4482 3845 4483 if (engine->isActive()) { … … 3850 4488 setAutoBufferSwap(false); 3851 4489 // disable glClear() as a result of QPainter::begin() 3852 d-> glcx->d_func()->clear_on_painter_begin = false;4490 d->disable_clear_on_painter_begin = true; 3853 4491 p = new QPainter(this); 3854 4492 } … … 3861 4499 glEnable(GL_SCISSOR_TEST); 3862 4500 } 3863 #if !defined(QT_OPENGL_ES_2)3864 4501 glMatrixMode(GL_PROJECTION); 3865 4502 glLoadIdentity(); 3866 4503 glViewport(0, 0, width, height); 3867 #ifndef QT_OPENGL_ES3868 4504 glOrtho(0, width, height, 0, 0, 1); 3869 #else3870 glOrthof(0, width, height, 0, 0, 1);3871 #endif3872 4505 glMatrixMode(GL_MODELVIEW); 3873 4506 glLoadIdentity(); … … 3876 4509 if (use_depth_testing) 3877 4510 glEnable(GL_DEPTH_TEST); 3878 #ifndef QT_OPENGL_ES3879 4511 glTranslated(0, 0, -win_z); 3880 #else3881 glTranslatef(0, 0, -win_z);3882 #endif3883 #endif // !defined(QT_OPENGL_ES_2)3884 4512 qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font); 3885 4513 … … 3890 4518 delete p; 3891 4519 setAutoBufferSwap(auto_swap); 3892 d->glcx->d_func()->clear_on_painter_begin = true; 3893 } 4520 d->disable_clear_on_painter_begin = false; 4521 } 4522 qgl_engine_selector()->setPreferredPaintEngine(oldEngineType); 4523 #else // QT_OPENGL_ES 4524 Q_UNUSED(x); 4525 Q_UNUSED(y); 4526 Q_UNUSED(z); 4527 Q_UNUSED(str); 4528 Q_UNUSED(font); 4529 qWarning("QGLWidget::renderText is not supported under OpenGL/ES"); 4530 #endif 3894 4531 } 3895 4532 … … 3932 4569 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format) 3933 4570 { 4571 if (image.isNull()) 4572 return 0; 4573 3934 4574 Q_D(QGLWidget); 3935 return d->glcx->bindTexture(image, target, format); 3936 } 4575 return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption); 4576 } 4577 4578 /*! 4579 \overload 4580 \since 4.6 4581 4582 The binding \a options are a set of options used to decide how to 4583 bind the texture to the context. 4584 */ 4585 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options) 4586 { 4587 if (image.isNull()) 4588 return 0; 4589 4590 Q_D(QGLWidget); 4591 return d->glcx->bindTexture(image, target, format, options); 4592 } 4593 3937 4594 3938 4595 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS … … 3940 4597 GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format) 3941 4598 { 4599 if (image.isNull()) 4600 return 0; 4601 3942 4602 Q_D(QGLWidget); 3943 return d->glcx->bindTexture(image, GLenum(target), GLint(format)); 4603 return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption); 4604 } 4605 4606 GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format, 4607 QGLContext::BindOptions options) 4608 { 4609 if (image.isNull()) 4610 return 0; 4611 4612 Q_D(QGLWidget); 4613 return d->glcx->bindTexture(image, GLenum(target), GLint(format), options); 3944 4614 } 3945 4615 #endif … … 3953 4623 GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format) 3954 4624 { 4625 if (pixmap.isNull()) 4626 return 0; 4627 3955 4628 Q_D(QGLWidget); 3956 return d->glcx->bindTexture(pixmap, target, format); 4629 return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption); 4630 } 4631 4632 /*! 4633 \overload 4634 \since 4.6 4635 4636 Generates and binds a 2D GL texture to the current context, based 4637 on \a pixmap. The generated texture id is returned and can be used in 4638 4639 The binding \a options are a set of options used to decide how to 4640 bind the texture to the context. 4641 */ 4642 GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, 4643 QGLContext::BindOptions options) 4644 { 4645 Q_D(QGLWidget); 4646 return d->glcx->bindTexture(pixmap, target, format, options); 3957 4647 } 3958 4648 … … 3962 4652 { 3963 4653 Q_D(QGLWidget); 3964 return d->glcx->bindTexture(pixmap, target, format); 4654 return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption); 4655 } 4656 4657 GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format, 4658 QGLContext::BindOptions options) 4659 { 4660 Q_D(QGLWidget); 4661 return d->glcx->bindTexture(pixmap, target, format, options); 3965 4662 } 3966 4663 #endif … … 4047 4744 #endif 4048 4745 4049 #if defined(QT_OPENGL_ES_2) 4050 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_engine) 4746 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) 4747 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine) 4748 #endif 4749 4750 #ifndef QT_OPENGL_ES_2 4751 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine) 4752 #endif 4753 4754 Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine() 4755 { 4756 #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) 4757 return qt_gl_engine(); 4758 #elif defined(QT_OPENGL_ES_2) 4759 return qt_gl_2_engine(); 4051 4760 #else 4052 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine) 4053 #endif 4054 4055 #ifdef Q_WS_QWS 4056 Q_OPENGL_EXPORT QOpenGLPaintEngine* qt_qgl_paint_engine() 4057 { 4058 #if !defined(QT_OPENGL_ES_2) 4059 return qt_gl_engine(); 4060 #else 4061 return 0; // XXX 4062 #endif 4063 } 4064 #endif 4761 if (qt_gl_preferGL2Engine()) 4762 return qt_gl_2_engine(); 4763 else 4764 return qt_gl_engine(); 4765 #endif 4766 } 4065 4767 4066 4768 /*! … … 4072 4774 QPaintEngine *QGLWidget::paintEngine() const 4073 4775 { 4074 return qt_ gl_engine();4776 return qt_qgl_paint_engine(); 4075 4777 } 4076 4778 … … 4132 4834 void QGLExtensions::init_extensions() 4133 4835 { 4134 QString extensions = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); 4135 if (extensions.contains(QLatin1String("texture_rectangle"))) 4836 QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); 4837 4838 if (extensions.match("GL_ARB_texture_rectangle")) 4136 4839 glExtensions |= TextureRectangle; 4137 if (extensions. contains(QLatin1String("multisample")))4840 if (extensions.match("GL_ARB_multisample")) 4138 4841 glExtensions |= SampleBuffers; 4139 if (extensions. contains(QLatin1String("generate_mipmap")))4842 if (extensions.match("GL_SGIS_generate_mipmap")) 4140 4843 glExtensions |= GenerateMipmap; 4141 if (extensions. contains(QLatin1String("texture_compression_s3tc")))4844 if (extensions.match("GL_ARB_texture_compression")) 4142 4845 glExtensions |= TextureCompression; 4143 if (extensions.contains(QLatin1String("ARB_fragment_program"))) 4846 if (extensions.match("GL_EXT_texture_compression_s3tc")) 4847 glExtensions |= DDSTextureCompression; 4848 if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture")) 4849 glExtensions |= ETC1TextureCompression; 4850 if (extensions.match("GL_IMG_texture_compression_pvrtc")) 4851 glExtensions |= PVRTCTextureCompression; 4852 if (extensions.match("GL_ARB_fragment_program")) 4144 4853 glExtensions |= FragmentProgram; 4145 if (extensions.contains(QLatin1String("mirrored_repeat"))) 4854 if (extensions.match("GL_ARB_fragment_shader")) 4855 glExtensions |= FragmentShader; 4856 if (extensions.match("GL_ARB_texture_mirrored_repeat")) 4146 4857 glExtensions |= MirroredRepeat; 4147 if (extensions. contains(QLatin1String("EXT_framebuffer_object")))4858 if (extensions.match("GL_EXT_framebuffer_object")) 4148 4859 glExtensions |= FramebufferObject; 4149 if (extensions. contains(QLatin1String("EXT_stencil_two_side")))4860 if (extensions.match("GL_EXT_stencil_two_side")) 4150 4861 glExtensions |= StencilTwoSide; 4151 if (extensions. contains(QLatin1String("EXT_stencil_wrap")))4862 if (extensions.match("GL_EXT_stencil_wrap")) 4152 4863 glExtensions |= StencilWrap; 4153 if (extensions. contains(QLatin1String("EXT_packed_depth_stencil")))4864 if (extensions.match("GL_EXT_packed_depth_stencil")) 4154 4865 glExtensions |= PackedDepthStencil; 4155 if (extensions. contains(QLatin1String("GL_NV_float_buffer")))4866 if (extensions.match("GL_NV_float_buffer")) 4156 4867 glExtensions |= NVFloatBuffer; 4157 if (extensions. contains(QLatin1String("ARB_pixel_buffer_object")))4868 if (extensions.match("GL_ARB_pixel_buffer_object")) 4158 4869 glExtensions |= PixelBufferObject; 4159 4870 #if defined(QT_OPENGL_ES_2) 4160 4871 glExtensions |= FramebufferObject; 4161 4872 glExtensions |= GenerateMipmap; 4162 #endif 4163 4164 QGLContext cx(QGLFormat::defaultFormat()); 4165 if (glExtensions & TextureCompression) { 4166 qt_glCompressedTexImage2DARB = (pfn_glCompressedTexImage2DARB) cx.getProcAddress(QLatin1String("glCompressedTexImage2DARB")); 4167 } 4873 glExtensions |= FragmentShader; 4874 #endif 4875 #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) 4876 if (extensions.match("GL_OES_framebuffer_object")) 4877 glExtensions |= FramebufferObject; 4878 #endif 4879 #if defined(QT_OPENGL_ES) 4880 if (extensions.match("GL_OES_packed_depth_stencil")) 4881 glExtensions |= PackedDepthStencil; 4882 #endif 4883 if (extensions.match("GL_ARB_framebuffer_object")) { 4884 // ARB_framebuffer_object also includes EXT_framebuffer_blit. 4885 glExtensions |= FramebufferObject; 4886 glExtensions |= FramebufferBlit; 4887 } 4888 4889 if (extensions.match("GL_EXT_framebuffer_blit")) 4890 glExtensions |= FramebufferBlit; 4891 4892 if (extensions.match("GL_ARB_texture_non_power_of_two")) 4893 glExtensions |= NPOTTextures; 4894 4895 if (extensions.match("GL_EXT_bgra")) 4896 glExtensions |= BGRATextureFormat; 4168 4897 } 4169 4898 … … 4174 4903 { 4175 4904 Q_Q(QGLWidget); 4905 4906 glDevice.setWidget(q); 4176 4907 4177 4908 QGLExtensions::init(); … … 4190 4921 4191 4922 #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) 4192 Q_GLOBAL_STATIC(QString, qt_gl_lib_name) ;4923 Q_GLOBAL_STATIC(QString, qt_gl_lib_name) 4193 4924 4194 4925 Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name) … … 4201 4932 if (qt_gl_lib_name()->isNull()) { 4202 4933 #if defined(Q_WS_X11) || defined(Q_WS_QWS) 4203 return Q String(QLatin1String("GL"));4934 return QLatin1String("GL"); 4204 4935 #else // Q_WS_MAC 4205 4936 return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"); … … 4210 4941 #endif 4211 4942 4943 void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) { 4944 Q_ASSERT(context && share); 4945 if (context->d_ptr->group == share->d_ptr->group) 4946 return; 4947 4948 // Make sure 'context' is not already shared with another group of contexts. 4949 Q_ASSERT(context->d_ptr->group->m_refs == 1); 4950 4951 // Free 'context' group resources and make it use the same resources as 'share'. 4952 QGLContextGroup *group = share->d_ptr->group; 4953 delete context->d_ptr->group; 4954 context->d_ptr->group = group; 4955 group->m_refs.ref(); 4956 4957 // Maintain a list of all the contexts in each group of sharing contexts. 4958 // The list is empty if the "share" context wasn't sharing already. 4959 if (group->m_shares.isEmpty()) 4960 group->m_shares.append(share); 4961 group->m_shares.append(context); 4962 } 4963 4964 QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) { 4965 return context->d_ptr->group->m_shares; 4966 } 4967 4968 void QGLShareRegister::removeShare(const QGLContext *context) { 4969 // Remove the context from the group. 4970 QGLContextGroup *group = context->d_ptr->group; 4971 if (group->m_shares.isEmpty()) 4972 return; 4973 group->m_shares.removeAll(context); 4974 4975 // Update context group representative. 4976 Q_ASSERT(group->m_shares.size() != 0); 4977 if (group->m_context == context) 4978 group->m_context = group->m_shares[0]; 4979 4980 // If there is only one context left, then make the list empty. 4981 if (group->m_shares.size() == 1) 4982 group->m_shares.clear(); 4983 } 4984 4985 QGLContextResource::QGLContextResource(FreeFunc f) 4986 : free(f), active(0) 4987 { 4988 } 4989 4990 QGLContextResource::~QGLContextResource() 4991 { 4992 #ifndef QT_NO_DEBUG 4993 if (active != 0) { 4994 qWarning("QtOpenGL: Resources are still available at program shutdown.\n" 4995 " This is possibly caused by a leaked QGLWidget, \n" 4996 " QGLFramebufferObject or QGLPixelBuffer."); 4997 } 4998 #endif 4999 } 5000 5001 void QGLContextResource::insert(const QGLContext *key, void *value) 5002 { 5003 QGLContextGroup *group = QGLContextPrivate::contextGroup(key); 5004 Q_ASSERT(!group->m_resources.contains(this)); 5005 group->m_resources.insert(this, value); 5006 active.ref(); 5007 } 5008 5009 void *QGLContextResource::value(const QGLContext *key) 5010 { 5011 QGLContextGroup *group = QGLContextPrivate::contextGroup(key); 5012 return group->m_resources.value(this, 0); 5013 } 5014 5015 void QGLContextResource::cleanup(const QGLContext *ctx, void *value) 5016 { 5017 QGLShareContextScope scope(ctx); 5018 free(value); 5019 active.deref(); 5020 } 5021 5022 void QGLContextGroup::cleanupResources(const QGLContext *ctx) 5023 { 5024 // If there are still shares, then no cleanup to be done yet. 5025 if (m_shares.size() > 1) 5026 return; 5027 5028 // Iterate over all resources and free each in turn. 5029 QHash<QGLContextResource *, void *>::ConstIterator it; 5030 for (it = m_resources.begin(); it != m_resources.end(); ++it) 5031 it.key()->cleanup(ctx, it.value()); 5032 } 5033 5034 QGLSharedResourceGuard::~QGLSharedResourceGuard() 5035 { 5036 if (m_group) 5037 m_group->removeGuard(this); 5038 } 5039 5040 void QGLSharedResourceGuard::setContext(const QGLContext *context) 5041 { 5042 if (m_group) 5043 m_group->removeGuard(this); 5044 if (context) { 5045 m_group = QGLContextPrivate::contextGroup(context); 5046 m_group->addGuard(this); 5047 } else { 5048 m_group = 0; 5049 } 5050 } 5051 5052 QSize QGLTexture::bindCompressedTexture 5053 (const QString& fileName, const char *format) 5054 { 5055 QFile file(fileName); 5056 if (!file.open(QIODevice::ReadOnly)) 5057 return QSize(); 5058 QByteArray contents = file.readAll(); 5059 file.close(); 5060 return bindCompressedTexture 5061 (contents.constData(), contents.size(), format); 5062 } 5063 5064 // PVR header format for container files that store textures compressed 5065 // with the ETC1, PVRTC2, and PVRTC4 encodings. Format information from the 5066 // PowerVR SDK at http://www.imgtec.com/powervr/insider/powervr-sdk.asp 5067 // "PVRTexTool Reference Manual, version 1.11f". 5068 struct PvrHeader 5069 { 5070 quint32 headerSize; 5071 quint32 height; 5072 quint32 width; 5073 quint32 mipMapCount; 5074 quint32 flags; 5075 quint32 dataSize; 5076 quint32 bitsPerPixel; 5077 quint32 redMask; 5078 quint32 greenMask; 5079 quint32 blueMask; 5080 quint32 alphaMask; 5081 quint32 magic; 5082 quint32 surfaceCount; 5083 }; 5084 5085 #define PVR_MAGIC 0x21525650 // "PVR!" in little-endian 5086 5087 #define PVR_FORMAT_MASK 0x000000FF 5088 #define PVR_FORMAT_PVRTC2 0x00000018 5089 #define PVR_FORMAT_PVRTC4 0x00000019 5090 #define PVR_FORMAT_ETC1 0x00000036 5091 5092 #define PVR_HAS_MIPMAPS 0x00000100 5093 #define PVR_TWIDDLED 0x00000200 5094 #define PVR_NORMAL_MAP 0x00000400 5095 #define PVR_BORDER_ADDED 0x00000800 5096 #define PVR_CUBE_MAP 0x00001000 5097 #define PVR_FALSE_COLOR_MIPMAPS 0x00002000 5098 #define PVR_VOLUME_TEXTURE 0x00004000 5099 #define PVR_ALPHA_IN_TEXTURE 0x00008000 5100 #define PVR_VERTICAL_FLIP 0x00010000 5101 5102 #ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 5103 #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 5104 #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 5105 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 5106 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 5107 #endif 5108 5109 #ifndef GL_ETC1_RGB8_OES 5110 #define GL_ETC1_RGB8_OES 0x8D64 5111 #endif 5112 5113 bool QGLTexture::canBindCompressedTexture 5114 (const char *buf, int len, const char *format, bool *hasAlpha) 5115 { 5116 if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) { 5117 // Compressed texture loading only supported on little-endian 5118 // systems such as x86 and ARM at the moment. 5119 return false; 5120 } 5121 if (!format) { 5122 // Auto-detect the format from the header. 5123 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) { 5124 *hasAlpha = true; 5125 return true; 5126 } else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) { 5127 const PvrHeader *pvrHeader = 5128 reinterpret_cast<const PvrHeader *>(buf); 5129 *hasAlpha = (pvrHeader->alphaMask != 0); 5130 return true; 5131 } 5132 } else { 5133 // Validate the format against the header. 5134 if (!qstricmp(format, "DDS")) { 5135 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) { 5136 *hasAlpha = true; 5137 return true; 5138 } 5139 } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) { 5140 if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) { 5141 const PvrHeader *pvrHeader = 5142 reinterpret_cast<const PvrHeader *>(buf); 5143 *hasAlpha = (pvrHeader->alphaMask != 0); 5144 return true; 5145 } 5146 } 5147 } 5148 return false; 5149 } 5150 5151 #define ctx QGLContext::currentContext() 5152 5153 QSize QGLTexture::bindCompressedTexture 5154 (const char *buf, int len, const char *format) 5155 { 5156 if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) { 5157 // Compressed texture loading only supported on little-endian 5158 // systems such as x86 and ARM at the moment. 5159 return QSize(); 5160 } 5161 #if !defined(QT_OPENGL_ES) 5162 if (!glCompressedTexImage2D) { 5163 if (!(QGLExtensions::glExtensions & QGLExtensions::TextureCompression)) { 5164 qWarning("QGLContext::bindTexture(): The GL implementation does " 5165 "not support texture compression extensions."); 5166 return QSize(); 5167 } 5168 glCompressedTexImage2D = (_glCompressedTexImage2DARB) ctx->getProcAddress(QLatin1String("glCompressedTexImage2DARB")); 5169 if (!glCompressedTexImage2D) { 5170 qWarning("QGLContext::bindTexture(): could not resolve " 5171 "glCompressedTexImage2DARB."); 5172 return QSize(); 5173 } 5174 } 5175 #endif 5176 if (!format) { 5177 // Auto-detect the format from the header. 5178 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) 5179 return bindCompressedTextureDDS(buf, len); 5180 else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) 5181 return bindCompressedTexturePVR(buf, len); 5182 } else { 5183 // Validate the format against the header. 5184 if (!qstricmp(format, "DDS")) { 5185 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) 5186 return bindCompressedTextureDDS(buf, len); 5187 } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) { 5188 if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) 5189 return bindCompressedTexturePVR(buf, len); 5190 } 5191 } 5192 return QSize(); 5193 } 5194 5195 QSize QGLTexture::bindCompressedTextureDDS(const char *buf, int len) 5196 { 5197 // We only support 2D texture loading at present. 5198 if (target != GL_TEXTURE_2D) 5199 return QSize(); 5200 5201 // Bail out if the necessary extension is not present. 5202 if (!(QGLExtensions::glExtensions & QGLExtensions::DDSTextureCompression)) { 5203 qWarning("QGLContext::bindTexture(): DDS texture compression is not supported."); 5204 return QSize(); 5205 } 5206 5207 const DDSFormat *ddsHeader = reinterpret_cast<const DDSFormat *>(buf + 4); 5208 if (!ddsHeader->dwLinearSize) { 5209 qWarning("QGLContext::bindTexture(): DDS image size is not valid."); 5210 return QSize(); 5211 } 5212 5213 int blockSize = 16; 5214 GLenum format; 5215 5216 switch(ddsHeader->ddsPixelFormat.dwFourCC) { 5217 case FOURCC_DXT1: 5218 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; 5219 blockSize = 8; 5220 break; 5221 case FOURCC_DXT3: 5222 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; 5223 break; 5224 case FOURCC_DXT5: 5225 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; 5226 break; 5227 default: 5228 qWarning("QGLContext::bindTexture(): DDS image format not supported."); 5229 return QSize(); 5230 } 5231 5232 const GLubyte *pixels = 5233 reinterpret_cast<const GLubyte *>(buf + ddsHeader->dwSize + 4); 5234 5235 glGenTextures(1, &id); 5236 glBindTexture(GL_TEXTURE_2D, id); 5237 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 5238 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 5239 5240 int size; 5241 int offset = 0; 5242 int available = len - int(ddsHeader->dwSize + 4); 5243 int w = ddsHeader->dwWidth; 5244 int h = ddsHeader->dwHeight; 5245 5246 // load mip-maps 5247 for(int i = 0; i < (int) ddsHeader->dwMipMapCount; ++i) { 5248 if (w == 0) w = 1; 5249 if (h == 0) h = 1; 5250 5251 size = ((w+3)/4) * ((h+3)/4) * blockSize; 5252 if (size > available) 5253 break; 5254 glCompressedTexImage2D(GL_TEXTURE_2D, i, format, w, h, 0, 5255 size, pixels + offset); 5256 offset += size; 5257 available -= size; 5258 5259 // half size for each mip-map level 5260 w = w/2; 5261 h = h/2; 5262 } 5263 5264 // DDS images are not inverted. 5265 options &= ~QGLContext::InvertedYBindOption; 5266 5267 return QSize(ddsHeader->dwWidth, ddsHeader->dwHeight); 5268 } 5269 5270 QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len) 5271 { 5272 // We only support 2D texture loading at present. Cube maps later. 5273 if (target != GL_TEXTURE_2D) 5274 return QSize(); 5275 5276 // Determine which texture format we will be loading. 5277 const PvrHeader *pvrHeader = reinterpret_cast<const PvrHeader *>(buf); 5278 GLenum textureFormat; 5279 quint32 minWidth, minHeight; 5280 switch (pvrHeader->flags & PVR_FORMAT_MASK) { 5281 case PVR_FORMAT_PVRTC2: 5282 if (pvrHeader->alphaMask) 5283 textureFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; 5284 else 5285 textureFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; 5286 minWidth = 16; 5287 minHeight = 8; 5288 break; 5289 5290 case PVR_FORMAT_PVRTC4: 5291 if (pvrHeader->alphaMask) 5292 textureFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; 5293 else 5294 textureFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; 5295 minWidth = 8; 5296 minHeight = 8; 5297 break; 5298 5299 case PVR_FORMAT_ETC1: 5300 textureFormat = GL_ETC1_RGB8_OES; 5301 minWidth = 4; 5302 minHeight = 4; 5303 break; 5304 5305 default: 5306 qWarning("QGLContext::bindTexture(): PVR image format 0x%x not supported.", int(pvrHeader->flags & PVR_FORMAT_MASK)); 5307 return QSize(); 5308 } 5309 5310 // Bail out if the necessary extension is not present. 5311 if (textureFormat == GL_ETC1_RGB8_OES) { 5312 if (!(QGLExtensions::glExtensions & 5313 QGLExtensions::ETC1TextureCompression)) { 5314 qWarning("QGLContext::bindTexture(): ETC1 texture compression is not supported."); 5315 return QSize(); 5316 } 5317 } else { 5318 if (!(QGLExtensions::glExtensions & 5319 QGLExtensions::PVRTCTextureCompression)) { 5320 qWarning("QGLContext::bindTexture(): PVRTC texture compression is not supported."); 5321 return QSize(); 5322 } 5323 } 5324 5325 // Boundary check on the buffer size. 5326 quint32 bufferSize = pvrHeader->headerSize + pvrHeader->dataSize; 5327 if (bufferSize > quint32(len)) { 5328 qWarning("QGLContext::bindTexture(): PVR image size is not valid."); 5329 return QSize(); 5330 } 5331 5332 // Create the texture. 5333 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 5334 glGenTextures(1, &id); 5335 glBindTexture(GL_TEXTURE_2D, id); 5336 if (pvrHeader->mipMapCount) { 5337 if ((options & QGLContext::LinearFilteringBindOption) != 0) { 5338 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 5339 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 5340 } else { 5341 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 5342 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); 5343 } 5344 } else if ((options & QGLContext::LinearFilteringBindOption) != 0) { 5345 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 5346 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 5347 } else { 5348 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 5349 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 5350 } 5351 5352 // Load the compressed mipmap levels. 5353 const GLubyte *buffer = 5354 reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize); 5355 bufferSize = pvrHeader->dataSize; 5356 quint32 level = 0; 5357 quint32 width = pvrHeader->width; 5358 quint32 height = pvrHeader->height; 5359 while (bufferSize > 0 && level < pvrHeader->mipMapCount) { 5360 quint32 size = 5361 (qMax(width, minWidth) * qMax(height, minHeight) * 5362 pvrHeader->bitsPerPixel) / 8; 5363 if (size > bufferSize) 5364 break; 5365 glCompressedTexImage2D(GL_TEXTURE_2D, GLint(level), textureFormat, 5366 GLsizei(width), GLsizei(height), 0, 5367 GLsizei(size), buffer); 5368 width /= 2; 5369 height /= 2; 5370 buffer += size; 5371 ++level; 5372 } 5373 5374 // Restore the default pixel alignment for later texture uploads. 5375 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 5376 5377 // Set the invert flag for the texture. The "vertical flip" 5378 // flag in PVR is the opposite sense to our sense of inversion. 5379 if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0) 5380 options &= ~QGLContext::InvertedYBindOption; 5381 else 5382 options |= QGLContext::InvertedYBindOption; 5383 5384 return QSize(pvrHeader->width, pvrHeader->height); 5385 } 5386 5387 #undef ctx 5388 4212 5389 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.