Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/opengl/qgl.cpp

    r2 r561  
    22**
    33** 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)
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    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.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** 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.
    3838** $QT_END_LICENSE$
    3939**
     
    6060#endif
    6161
     62#include <qdatetime.h>
     63
    6264#include <stdlib.h> // malloc
    6365
     
    6668#include "qgl_p.h"
    6769
    68 #if defined(QT_OPENGL_ES_2)
     70#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
    6971#include "gl2paintengineex/qpaintengineex_opengl2_p.h"
    70 #else
     72#endif
     73
     74#ifndef QT_OPENGL_ES_2
    7175#include <private/qpaintengine_opengl_p.h>
    7276#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>
    7384
    7485#include <private/qimage_p.h>
    7586#include <private/qpixmapdata_p.h>
    7687#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>
    7791#include "qcolormap.h"
    78 #include "qcache.h"
    7992#include "qfile.h"
    8093#include "qlibrary.h"
     
    92105#endif
    93106
    94 QThreadStorage<QGLThreadContext *> qgl_context_storage;
     107struct QGLThreadContext {
     108    QGLContext *context;
     109};
     110
     111static QThreadStorage<QGLThreadContext *> qgl_context_storage;
    95112
    96113Q_GLOBAL_STATIC(QGLFormat, qgl_default_format)
     
    111128bool QGLExtensions::nvidiaFboNeedsFinish = false;
    112129
    113 #ifndef APIENTRY
    114 # define APIENTRY
    115 #endif
    116 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 APIENTRY
    122 #define APIENTRY
    123 #endif
    124 
    125130Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy)
    126131QGLSignalProxy *QGLSignalProxy::instance()
     
    129134}
    130135
     136
     137class QGLEngineSelector
     138{
     139public:
     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
     191private:
     192    QPaintEngine::Type engineType;
     193};
     194
     195Q_GLOBAL_STATIC(QGLEngineSelector, qgl_engine_selector)
     196
     197
     198bool qt_gl_preferGL2Engine()
     199{
     200    return qgl_engine_selector()->preferredPaintEngine() == QPaintEngine::OpenGL2;
     201}
     202
     203
    131204/*!
    132205    \namespace QGL
     206    \inmodule QtOpenGL
    133207
    134208    \brief The QGL namespace specifies miscellaneous identifiers used
    135209    in the Qt OpenGL module.
    136210
    137     \ingroup multimedia
     211    \ingroup painting-3D
    138212*/
    139213
     
    168242*/
    169243
     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*/
     264void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
     265{
     266    qgl_engine_selector()->setPreferredPaintEngine(engineType);
     267}
     268
     269
    170270/*****************************************************************************
    171271  QGLFormat implementation
     
    178278    rendering context.
    179279
    180     \ingroup multimedia
     280    \ingroup painting-3D
    181281
    182282    A display format has several characteristics:
     
    191291    \i \link setDirectRendering() Direct rendering.\endlink
    192292    \i \link setOverlay() Presence of an overlay.\endlink
    193     \i \link setPlane() The plane of an overlay format.\endlink
     293    \i \link setPlane() Plane of an overlay.\endlink
    194294    \i \link setSampleBuffers() Multisample buffers.\endlink
    195295    \endlist
    196296
    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(),
    200301    setAccumBufferSize() and setStencilBufferSize().
    201302
     
    237338    \sa QGLContext, QGLWidget
    238339*/
     340
     341#ifndef QT_OPENGL_ES
    239342
    240343static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
     
    280383}
    281384
    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:
    284389    \list
    285390    \i \link setDoubleBuffer() Double buffer:\endlink Enabled.
     
    288393    \i \link setAlpha() Alpha channel:\endlink Disabled.
    289394    \i \link setAccum() Accumulator buffer:\endlink Disabled.
    290     \i \link setStencil() Stencil buffer:\endlink Disabled.
     395    \i \link setStencil() Stencil buffer:\endlink Enabled.
    291396    \i \link setStereo() Stereo:\endlink Disabled.
    292397    \i \link setDirectRendering() Direct rendering:\endlink Enabled.
     
    304409
    305410/*!
    306     Creates a QGLFormat object that is a copy of the current \link
    307     defaultFormat() application default format\endlink.
    308 
    309     If \a options is not 0, this copy is modified by these format
    310     options. The \a options parameter should be \c FormatOption values
    311     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.
    312417
    313418    This constructor makes it easy to specify a certain desired format
     
    315420    \snippet doc/src/snippets/code/src_opengl_qgl.cpp 3
    316421
    317     Note that there are \c FormatOption values to turn format settings
    318     both on and off, e.g. \c DepthBuffer and \c NoDepthBuffer,
    319     \c DirectRendering and \c IndirectRendering, 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.
    320425
    321426    The \a plane parameter defaults to 0 and is the plane which this
     
    323428    supports overlay/underlay rendering planes.
    324429
    325     \sa defaultFormat(), setOption()
     430    \sa defaultFormat(), setOption(), setPlane()
    326431*/
    327432
     
    337442
    338443/*!
     444    \internal
     445*/
     446void 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/*!
    339457    Constructs a copy of \a other.
    340458*/
     
    342460QGLFormat::QGLFormat(const QGLFormat &other)
    343461{
    344     d = new QGLFormatPrivate;
    345     *d = *other.d;
     462    d = other.d;
     463    d->ref.ref();
    346464}
    347465
     
    352470QGLFormat &QGLFormat::operator=(const QGLFormat &other)
    353471{
    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    }
    355478    return *this;
    356479}
     
    361484QGLFormat::~QGLFormat()
    362485{
    363     delete d;
     486    if (!d->ref.deref())
     487        delete d;
    364488}
    365489
     
    515639
    516640    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.
    518642
    519643    \sa setStencil(), setStencilBufferSize()
     
    524648    disables the stencil buffer.
    525649
    526     The stencil buffer is disabled by default.
     650    The stencil buffer is enabled by default.
    527651
    528652    The stencil buffer masks certain parts of the drawing area so that
     
    637761void QGLFormat::setSamples(int numSamples)
    638762{
     763    detach();
    639764    if (numSamples < 0) {
    640765        qWarning("QGLFormat::setSamples: Cannot have negative number of samples per pixel %d", numSamples);
     
    664789void QGLFormat::setSwapInterval(int interval)
    665790{
     791    detach();
    666792    d->swapInterval = interval;
    667793}
     
    709835    formats is 1, which is the first overlay plane.
    710836
    711     \sa setPlane()
     837    \sa setPlane(), defaultOverlayFormat()
    712838*/
    713839int QGLFormat::plane() const
     
    731857void QGLFormat::setPlane(int plane)
    732858{
     859    detach();
    733860    d->pln = plane;
    734861}
     
    742869void QGLFormat::setOption(QGL::FormatOptions opt)
    743870{
     871    detach();
    744872    if (opt & 0xffff)
    745873        d->opts |= opt;
     
    771899void QGLFormat::setDepthBufferSize(int size)
    772900{
     901    detach();
    773902    if (size < 0) {
    774903        qWarning("QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size %d", size);
     
    797926void QGLFormat::setRedBufferSize(int size)
    798927{
     928    detach();
    799929    if (size < 0) {
    800930        qWarning("QGLFormat::setRedBufferSize: Cannot set negative red buffer size %d", size);
     
    825955void QGLFormat::setGreenBufferSize(int size)
    826956{
     957    detach();
    827958    if (size < 0) {
    828959        qWarning("QGLFormat::setGreenBufferSize: Cannot set negative green buffer size %d", size);
     
    853984void QGLFormat::setBlueBufferSize(int size)
    854985{
     986    detach();
    855987    if (size < 0) {
    856988        qWarning("QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size %d", size);
     
    8801012void QGLFormat::setAlphaBufferSize(int size)
    8811013{
     1014    detach();
    8821015    if (size < 0) {
    8831016        qWarning("QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size %d", size);
     
    9061039void QGLFormat::setAccumBufferSize(int size)
    9071040{
     1041    detach();
    9081042    if (size < 0) {
    9091043        qWarning("QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size %d", size);
     
    9301064void QGLFormat::setStencilBufferSize(int size)
    9311065{
     1066    detach();
    9321067    if (size < 0) {
    9331068        qWarning("QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size %d", size);
     
    11251260            return defaultVersionFlags;
    11261261        } else {
    1127             cachedDefault = true;
    11281262            if (!hasOpenGL())
    11291263                return defaultVersionFlags;
    11301264            dummy = new QGLWidget;
    11311265            dummy->makeCurrent(); // glGetString() needs a current context
     1266            cachedDefault = true;
    11321267        }
    11331268    }
     
    11491284
    11501285/*!
    1151     Returns the default QGLFormat for the application. All QGLWidgets
    1152     that are created use this format unless another format is
     1286    Returns the default QGLFormat for the application. All QGLWidget
     1287    objects that are created use this format unless another format is
    11531288    specified, e.g. when they are constructed.
    11541289
     
    11831318    Returns the default QGLFormat for overlay contexts.
    11841319
    1185     The factory default overlay format is:
     1320    The default overlay format is:
    11861321    \list
    11871322    \i \link setDoubleBuffer() Double buffer:\endlink Disabled.
     
    11941329    \i \link setDirectRendering() Direct rendering:\endlink Enabled.
    11951330    \i \link setOverlay() Overlay:\endlink Disabled.
     1331    \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
    11961332    \i \link setPlane() Plane:\endlink 1 (i.e., first overlay plane).
    11971333    \endlist
     
    12361372
    12371373/*!
    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
    12401378*/
    12411379
     
    12441382    return (int) a.d->opts == (int) b.d->opts && a.d->pln == b.d->pln && a.d->alphaSize == b.d->alphaSize
    12451383        && 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
    12531398*/
    12541399
     
    12611406  QGLContext implementation
    12621407 *****************************************************************************/
     1408
     1409QGLContextGroup::~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
     1420void 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
     1429void 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
     1439QGLContextPrivate::~QGLContextPrivate()
     1440{
     1441    if (!group->m_refs.deref()) {
     1442        Q_ASSERT(group->context() == q_ptr);
     1443        delete group;
     1444    }
     1445}
     1446
    12631447void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
    12641448{
     
    12891473#if defined(QT_OPENGL_ES)
    12901474    eglContext = 0;
    1291 #endif
    1292     pbo = 0;
     1475    eglSurface = EGL_NO_SURFACE;
     1476#endif
     1477    fbo = 0;
    12931478    crWin = false;
    12941479    initDone = false;
    12951480    sharing = false;
    1296     clear_on_painter_begin = true;
    12971481    max_texture_size = -1;
    12981482    version_flags_cached = false;
    12991483    version_flags = QGLFormat::OpenGL_Version_None;
     1484    current_fbo = 0;
     1485    default_fbo = 0;
     1486    active_engine = 0;
    13001487}
    13011488
     
    13081495*/
    13091496
    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());
     1497static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha)
     1498{
    13161499    if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
    13171500        // OpenGL gives RGBA; Qt wants ARGB
     
    13281511            // we shouldn't remove
    13291512            while (p < end) {
    1330                 *p = 0xFF000000 | (*p>>8);
     1513                *p = 0xff000000 | (*p>>8);
    13311514                ++p;
    13321515            }
     
    13341517    } else {
    13351518        // 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
     1532QImage 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
     1542QImage 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;
    13391553}
    13401554
     
    13531567}
    13541568
    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 though
    1380 static QGLTextureCache *qt_tex_cache = 0;
    1381 
    13821569typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
    13831570typedef void (*_qt_image_cleanup_hook_64)(qint64);
     
    13851572extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64;
    13861573extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64;
     1574
     1575static QGLTextureCache *qt_gl_texture_cache = 0;
     1576
     1577QGLTextureCache::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
     1590QGLTextureCache::~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
     1601void 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
     1618bool 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
     1632void 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
     1642QGLTextureCache* 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*/
     1654void 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
     1665void 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)
     1677void 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
     1690void QGLTextureCache::deleteIfEmpty()
     1691{
     1692    if (instance()->size() == 0)
     1693        delete instance();
     1694}
    13871695
    13881696// DDS format structure
     
    14221730#endif
    14231731
    1424 Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg);
     1732Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg)
    14251733Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
    14261734{
     
    14321740    \brief The QGLContext class encapsulates an OpenGL rendering context.
    14331741
    1434     \ingroup multimedia
     1742    \ingroup painting-3D
    14351743
    14361744    An OpenGL rendering context is a complete set of OpenGL state
     
    14571765*/
    14581766
     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*/
    14591808
    14601809/*!
     
    14771826
    14781827QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
    1479 {
    1480     d_ptr = new QGLContextPrivate(this);
     1828    : d_ptr(new QGLContextPrivate(this))
     1829{
    14811830    Q_D(QGLContext);
    14821831    d->init(device, format);
     
    15001849*/
    15011850QGLContext::QGLContext(const QGLFormat &format)
    1502 {
    1503     d_ptr = new QGLContextPrivate(this);
     1851    : d_ptr(new QGLContextPrivate(this))
     1852{
    15041853    Q_D(QGLContext);
    15051854    d->init(0, format);
     
    15121861QGLContext::~QGLContext()
    15131862{
    1514     Q_D(QGLContext);
    15151863    // 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);
    15311868
    15321869    QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
    15331870    reset();
    1534     delete d;
    15351871}
    15361872
    15371873void QGLContextPrivate::cleanup()
    15381874{
    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}
    15491876
    15501877/*!
    15511878    \overload
    15521879
    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.
    15611892
    15621893    \sa deleteTexture()
     
    15651896GLuint QGLContext::bindTexture(const QString &fileName)
    15661897{
    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()) {
    15751902        glBindTexture(GL_TEXTURE_2D, it.value());
    15761903        return it.value();
    15771904    }
    15781905
    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())
    15861909        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
     1915static 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
     1937QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format)
     1938{
     1939    return qt_gl_convertToGLFormatHelper(src_pixel, texture_format);
    16751940}
    16761941
    16771942static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
    16781943{
    1679     Q_ASSERT(dst.size() == img.size());
    16801944    Q_ASSERT(dst.depth() == 32);
    16811945    Q_ASSERT(img.depth() == 32);
    16821946
    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;
    17001995                }
    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                }
    17022003            }
    17032004        } 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;
    17192014                }
    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;
    17292024                }
    1730                 p -= 2 * width;
    17312025            }
    17322026        }
     
    17462040}
    17472041
    1748 GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
    1749                                       const qint64 key, bool clean)
     2042/*! \internal */
     2043QGLTexture *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
     2067static 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
     2089QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat,
     2090                                           const qint64 key, QGLContext::BindOptions options)
    17502091{
    17512092    Q_Q(QGLContext);
    17522093
    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
    17712105
    17722106    // 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
    17742109    int tx_w = qt_next_power_of_two(image.width());
    17752110    int tx_h = qt_next_power_of_two(image.height());
    17762111
    1777     // Note: the clean param is only true when a texture is bound
    1778     // from the QOpenGLPaintEngine - in that case we have to force
    1779     // a premultiplied texture format
    17802112    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)
    17832115        && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
    17842116    {
    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;
    17872125
    17882126    GLuint tx_id;
    17892127    glGenTextures(1, &tx_id);
    17902128    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
    17922134    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))
    17952138    {
     2139#ifdef QGL_BIND_TEXTURE_DEBUG
     2140        printf(" - generating mipmaps (%d ms)\n", time.elapsed());
     2141#endif
     2142#if !defined(QT_OPENGL_ES_2)
    17962143        glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
    17972144#ifndef QT_OPENGL_ES
     
    18002147        glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
    18012148#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);
    18062155    } 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;
    18262166    } 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
    18342276
    18352277    // this assumes the size of a texture is always smaller than the max cache size
    18362278    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
     2284QGLTexture *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 */
     2298QGLTexture *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();
    18472309        }
    18482310    }
    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));
    18632331        }
    18642332    }
    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;
    19032344}
    19042345
     
    19392380
    19402381/*!
     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*/
     2388GLuint 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
    19412401    Generates and binds a 2D GL texture to the current context, based
    19422402    on \a image. The generated texture id is returned and can be used
     
    19472407
    19482408    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.
    19552413
    19562414    The texture that is generated is cached, so multiple calls to
     
    19632421    \sa deleteTexture()
    19642422*/
    1965 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
    1966 {
     2423GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options)
     2424{
     2425    if (image.isNull())
     2426        return 0;
     2427
    19672428    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;
    19692431}
    19702432
     
    19732435GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
    19742436{
     2437    if (image.isNull())
     2438        return 0;
     2439
    19752440    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 */
     2446GLuint 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;
    19772455}
    19782456#endif
     
    19842462GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
    19852463{
     2464    if (pixmap.isNull())
     2465        return 0;
     2466
    19862467    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*/
     2479GLuint 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;
    19882487}
    19892488
     
    19922491GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
    19932492{
     2493    if (pixmap.isNull())
     2494        return 0;
     2495
    19942496    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 */
     2501GLuint 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;
    19962510}
    19972511#endif
     
    20062520void QGLContext::deleteTexture(GLuint id)
    20072521{
    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;
    20192526
    20202527    // check the DDS cache if the texture wasn't found in the pixmap/image
    20212528    // 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();
    20232531    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));
    20252533        if (id == texture) {
    20262534            glDeleteTextures(1, &texture);
    2027             qgl_dds_cache()->remove(ddsKeys.at(i));
     2535            dds_cache->remove(ddsKeys.at(i));
    20282536            return;
    20292537        }
     
    20392547#endif
    20402548
    2041 // qpaintengine_opengl.cpp
     2549void 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
     2566void 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
    20422578#if !defined(QT_OPENGL_ES_2)
    2043 extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);
    2044 #else
    2045 void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) {};
    2046 #endif
    20472579
    20482580static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget)
     
    20742606    qt_add_rect_to_array(target, vertexArray);
    20752607
    2076 #if !defined(QT_OPENGL_ES_2)
    20772608    glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
    20782609    glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
     
    20842615    glDisableClientState(GL_VERTEX_ARRAY);
    20852616    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    2086 #endif
    2087 }
     2617}
     2618
     2619#endif // !QT_OPENGL_ES_2
    20882620
    20892621/*!
     
    20942626    texture target.
    20952627
    2096     Equivalent to the corresponding QGLContext::drawTexture().
     2628    \note This function is not supported under OpenGL/ES 2.0.
    20972629*/
    20982630void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
    20992631{
     2632#ifndef QT_OPENGL_ES_2
    21002633#ifdef QT_OPENGL_ES
    21012634    if (textureTarget != GL_TEXTURE_2D) {
     
    21212654    glBindTexture(textureTarget, oldTexture);
    21222655#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
    21232662}
    21242663
     
    21372676    space. The \a textureTarget should be a 2D texture target.
    21382677
    2139     Equivalent to the corresponding QGLContext::drawTexture().
     2678    \note This function is not supported under OpenGL/ES.
    21402679*/
    21412680void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
     
    21882727void QGLContext::setTextureCacheLimit(int size)
    21892728{
    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);
    21932730}
    21942731
     
    22002737int QGLContext::textureCacheLimit()
    22012738{
    2202     return qt_tex_cache_limit;
     2739    return QGLTextureCache::instance()->maxCost();
    22032740}
    22042741
     
    22792816    formats.
    22802817*/
     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*/
     2826bool 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}
    22812832
    22822833/*!
     
    23992950    reset();
    24002951    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    }
    24012956    if (d->sharing)  // ok, we managed to share
    24022957        qgl_share_reg()->addShare(this, shareContext);
     
    24192974{
    24202975    Q_D(const QGLContext);
    2421     return d->sharing;
     2976    return d->group->isSharing();
    24222977}
    24232978
     
    24743029const QGLContext* QGLContext::currentContext()
    24753030{
    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;
    24783034    return 0;
     3035}
     3036
     3037void 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
    24793051}
    24803052
     
    24933065*/
    24943066
     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*/
    24953103
    24963104/*!
     
    25613169    \brief The QGLWidget class is a widget for rendering OpenGL graphics.
    25623170
    2563     \ingroup multimedia
    2564     \mainclass
     3171    \ingroup painting-3D
     3172
    25653173
    25663174    QGLWidget provides functionality for displaying OpenGL graphics
     
    25773185    needs to be updated.
    25783186    \i resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets
    2579     called whenever the the widget has been resized (and also when it
     3187    called whenever the widget has been resized (and also when it
    25803188    is shown for the first time because all newly created widgets get a
    25813189    resize event automatically).
     
    26033211    customized rendering \link QGLContext contexts\endlink.
    26043212
    2605     You can also share OpenGL display lists between QGLWidgets (see
     3213    You can also share OpenGL display lists between QGLWidget objects (see
    26063214    the documentation of the QGLWidget constructors for details).
    26073215
     
    28853493    Returns true if this widget's GL context is shared with another GL
    28863494    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.
    28883496
    28893497    \sa format()
     
    29833591
    29843592  This method will try to keep display list and texture object sharing
    2985   in effect with other QGLWidgets, but changing the format might make
     3593  in effect with other QGLWidget objects, but changing the format might make
    29863594  sharing impossible. Use isSharing() to see if sharing is still in
    29873595  effect.
     
    30093617
    30103618/*
     3619  \fn void QGLWidget::setContext(QGLContext *context,
     3620                                 const QGLContext* shareContext,
     3621                                 bool deleteOldContext)
    30113622  \obsolete
    3012 
    3013   \fn void QGLWidget::setContext(QGLContext *context,
    3014                                   const QGLContext* shareContext,
    3015                                   bool deleteOldContext)
    30163623
    30173624  Sets a new context for this widget. The QGLContext \a context must
     
    31633770}
    31643771
    3165 
     3772/*! \fn bool QGLWidget::event(QEvent *e)
     3773  \reimp
     3774*/
    31663775#if !defined(Q_OS_WINCE) && !defined(Q_WS_QWS)
    3167 /*! \reimp */
    31683776bool QGLWidget::event(QEvent *e)
    31693777{
     
    31913799        doneCurrent();
    31923800    } 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)) {
    31943807            setContext(new QGLContext(d->glcx->requestedFormat(), this));
    31953808            // ### recreating the overlay isn't supported atm
    31963809        }
     3810    }
     3811
    31973812#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
    31993820        // surface will need to be re-created.
    32003821        d->recreateEglSurface(false);
    3201 #endif
    3202     }
     3822    }
     3823#endif
    32033824#elif defined(Q_WS_WIN)
    32043825    if (e->type() == QEvent::ParentChange) {
    32053826        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
    32083829        // the overlay needs to be recreated as well
    32093830        delete d->olcx;
     
    32843905    Renders the current scene on a pixmap and returns the pixmap.
    32853906
    3286     You can use this method on both visible and invisible QGLWidgets.
     3907    You can use this method on both visible and invisible QGLWidget objects.
    32873908
    32883909    This method will create a pixmap and a temporary QGLContext to
     
    34064027        const QVector<QColor> pal = QColormap::instance().colormap();
    34074028        if (pal.size()) {
    3408             res.setNumColors(pal.size());
     4029            res.setColorCount(pal.size());
    34094030            for (int i = 0; i < pal.size(); i++)
    34104031                res.setColor(i, pal.at(i).rgb());
     
    34704091    with the color \a c. Applies to this widgets GL context.
    34714092
     4093    \note This function is not supported on OpenGL/ES 2.0 systems.
     4094
    34724095    \sa qglClearColor(), QGLContext::currentContext(), QColor
    34734096*/
     
    34774100#if !defined(QT_OPENGL_ES_2)
    34784101#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());
    34804103#else
    34814104    Q_D(const QGLWidget);
     
    34834106    if (ctx) {
    34844107        if (ctx->format().rgba())
    3485             glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
     4108            glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
    34864109        else if (!d->cmap.isEmpty()) { // QGLColormap in use?
    34874110            int i = d->cmap.find(c.rgb());
     
    34934116    }
    34944117#endif //QT_OPENGL_ES
     4118#else
     4119    Q_UNUSED(c);
    34954120#endif //QT_OPENGL_ES_2
    34964121}
     
    35074132{
    35084133#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());
    35114135#else
    35124136    Q_D(const QGLWidget);
     
    35144138    if (ctx) {
    35154139        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());
    35184141        else if (!d->cmap.isEmpty()) { // QGLColormap in use?
    35194142            int i = d->cmap.find(c.rgb());
     
    35864209    will return the colormap for the child's top-level widget.
    35874210
    3588     If no colormap has been set for this widget, the QColormap
     4211    If no colormap has been set for this widget, the QGLColormap
    35894212    returned will be empty.
    35904213
    3591     \sa setColormap()
     4214    \sa setColormap(), QGLColormap::isEmpty()
    35924215*/
    35934216
     
    36094232    value used when generating the display lists for the font. The
    36104233    default value is 2000.
     4234
     4235    \note This function is not supported on OpenGL/ES systems.
    36114236*/
    36124237int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
    36134238{
     4239#ifndef QT_OPENGL_ES
    36144240    Q_D(QGLWidget);
    36154241    int base;
     
    36294255    if (font.styleStrategy() != QFont::NoAntialias) {
    36304256        GLfloat color[4];
    3631 #ifndef QT_OPENGL_ES
    36324257        glGetFloatv(GL_CURRENT_COLOR, color);
    3633 #endif
    36344258        color_key.sprintf("%f_%f_%f",color[0], color[1], color[2]);
    36354259    }
     
    36544278    }
    36554279    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
    36574288
    36584289static void qt_save_gl_state()
    36594290{
    3660 #ifndef QT_OPENGL_ES
    36614291    glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
    36624292    glPushAttrib(GL_ALL_ATTRIB_BITS);
    3663 #endif
    3664 #if !defined(QT_OPENGL_ES_2)
    36654293    glMatrixMode(GL_TEXTURE);
    36664294    glPushMatrix();
     
    36754303    glDisable(GL_LIGHTING);
    36764304    glDisable(GL_STENCIL_TEST);
     4305    glDisable(GL_DEPTH_TEST);
    36774306    glEnable(GL_BLEND);
    36784307    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    3679 #endif // !defined(QT_OPENGL_ES_2)
    36804308}
    36814309
    36824310static void qt_restore_gl_state()
    36834311{
    3684 #if !defined(QT_OPENGL_ES_2)
    36854312    glMatrixMode(GL_TEXTURE);
    36864313    glPopMatrix();
     
    36894316    glMatrixMode(GL_MODELVIEW);
    36904317    glPopMatrix();
    3691 #endif // !defined(QT_OPENGL_ES_2)
    3692 #ifndef QT_OPENGL_ES
    36934318    glPopAttrib();
    36944319    glPopClientAttrib();
    3695 #endif
    36964320}
    36974321
     
    37004324{
    37014325    GLfloat color[4];
    3702 #ifndef QT_OPENGL_ES
    37034326    glGetFloatv(GL_CURRENT_COLOR, &color[0]);
    3704 #endif
    37054327
    37064328    QColor col;
     
    37164338    p->setFont(old_font);
    37174339}
     4340
     4341#endif // !QT_OPENGL_ES
    37184342
    37194343/*!
     
    37314355
    37324356   \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.
    37334364*/
    37344365
    37354366void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int)
    37364367{
     4368#ifndef QT_OPENGL_ES
    37374369    Q_D(QGLWidget);
    37384370    if (str.isEmpty() || !isValid())
     
    37404372
    37414373    GLint view[4];
    3742 #ifndef QT_OPENGL_ES
    37434374    bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
    37444375    if (!use_scissor_testing)
    37454376        glGetIntegerv(GL_VIEWPORT, &view[0]);
    3746 #else
    3747     bool use_scissor_testing = false;
    3748 #endif
    37494377    int width = d->glcx->device()->width();
    37504378    int height = d->glcx->device()->height();
    37514379    bool auto_swap = autoBufferSwap();
    37524380
     4381    QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
     4382    qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
    37534383    QPaintEngine *engine = paintEngine();
    37544384    QPainter *p;
     
    37594389        qt_save_gl_state();
    37604390
    3761 #if !defined(QT_OPENGL_ES_2)
    37624391        glDisable(GL_DEPTH_TEST);
    37634392        glViewport(0, 0, width, height);
    37644393        glMatrixMode(GL_PROJECTION);
    37654394        glLoadIdentity();
    3766 #ifndef QT_OPENGL_ES
    37674395        glOrtho(0, width, height, 0, 0, 1);
    3768 #else
    3769         glOrthof(0, width, height, 0, 0, 1);
    3770 #endif
    37714396        glMatrixMode(GL_MODELVIEW);
    37724397
    37734398        glLoadIdentity();
    3774 #endif // !defined(QT_OPENGL_ES_2)
    37754399    } else {
    37764400        setAutoBufferSwap(false);
    37774401        // 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;
    37794403        p = new QPainter(this);
    37804404    }
     
    37994423        delete p;
    38004424        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
    38034435}
    38044436
     
    38094441    can be useful if you want to annotate models with text labels and
    38104442    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.
    38114453*/
    38124454void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int)
    38134455{
     4456#ifndef QT_OPENGL_ES
    38144457    Q_D(QGLWidget);
    38154458    if (str.isEmpty() || !isValid())
     
    38224465    GLdouble model[4][4], proj[4][4];
    38234466    GLint view[4];
    3824 #ifndef QT_OPENGL_ES
    38254467    glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
    38264468    glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
    38274469    glGetIntegerv(GL_VIEWPORT, &view[0]);
    3828 #endif
    38294470    GLdouble win_x = 0, win_y = 0, win_z = 0;
    38304471    qgluProject(x, y, z, &model[0][0], &proj[0][0], &view[0],
     
    38324473    win_y = height - win_y; // y is inverted
    38334474
     4475    QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
     4476    qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
    38344477    QPaintEngine *engine = paintEngine();
    38354478    QPainter *p;
    38364479    bool reuse_painter = false;
    3837 #ifndef QT_OPENGL_ES
    38384480    bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
    38394481    bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
    3840 #else
    3841     bool use_depth_testing = false;
    3842     bool use_scissor_testing = false;
    3843 #endif
    38444482
    38454483    if (engine->isActive()) {
     
    38504488        setAutoBufferSwap(false);
    38514489        // 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;
    38534491        p = new QPainter(this);
    38544492    }
     
    38614499        glEnable(GL_SCISSOR_TEST);
    38624500    }
    3863 #if !defined(QT_OPENGL_ES_2)
    38644501    glMatrixMode(GL_PROJECTION);
    38654502    glLoadIdentity();
    38664503    glViewport(0, 0, width, height);
    3867 #ifndef QT_OPENGL_ES
    38684504    glOrtho(0, width, height, 0, 0, 1);
    3869 #else
    3870     glOrthof(0, width, height, 0, 0, 1);
    3871 #endif
    38724505    glMatrixMode(GL_MODELVIEW);
    38734506    glLoadIdentity();
     
    38764509    if (use_depth_testing)
    38774510        glEnable(GL_DEPTH_TEST);
    3878 #ifndef QT_OPENGL_ES
    38794511    glTranslated(0, 0, -win_z);
    3880 #else
    3881     glTranslatef(0, 0, -win_z);
    3882 #endif
    3883 #endif // !defined(QT_OPENGL_ES_2)
    38844512    qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font);
    38854513
     
    38904518        delete p;
    38914519        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
    38944531}
    38954532
     
    39324569GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
    39334570{
     4571    if (image.isNull())
     4572        return 0;
     4573
    39344574    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 */
     4585GLuint 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
    39374594
    39384595#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
     
    39404597GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
    39414598{
     4599    if (image.isNull())
     4600        return 0;
     4601
    39424602   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
     4606GLuint 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);
    39444614}
    39454615#endif
     
    39534623GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
    39544624{
     4625    if (pixmap.isNull())
     4626        return 0;
     4627
    39554628    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 */
     4642GLuint 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);
    39574647}
    39584648
     
    39624652{
    39634653    Q_D(QGLWidget);
    3964     return d->glcx->bindTexture(pixmap, target, format);
     4654    return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
     4655}
     4656
     4657GLuint 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);
    39654662}
    39664663#endif
     
    40474744#endif
    40484745
    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)
     4747Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine)
     4748#endif
     4749
     4750#ifndef QT_OPENGL_ES_2
     4751Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine)
     4752#endif
     4753
     4754Q_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();
    40514760#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}
    40654767
    40664768/*!
     
    40724774QPaintEngine *QGLWidget::paintEngine() const
    40734775{
    4074     return qt_gl_engine();
     4776    return qt_qgl_paint_engine();
    40754777}
    40764778
     
    41324834void QGLExtensions::init_extensions()
    41334835{
    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"))
    41364839        glExtensions |= TextureRectangle;
    4137     if (extensions.contains(QLatin1String("multisample")))
     4840    if (extensions.match("GL_ARB_multisample"))
    41384841        glExtensions |= SampleBuffers;
    4139     if (extensions.contains(QLatin1String("generate_mipmap")))
     4842    if (extensions.match("GL_SGIS_generate_mipmap"))
    41404843        glExtensions |= GenerateMipmap;
    4141     if (extensions.contains(QLatin1String("texture_compression_s3tc")))
     4844    if (extensions.match("GL_ARB_texture_compression"))
    41424845        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"))
    41444853        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"))
    41464857        glExtensions |= MirroredRepeat;
    4147     if (extensions.contains(QLatin1String("EXT_framebuffer_object")))
     4858    if (extensions.match("GL_EXT_framebuffer_object"))
    41484859        glExtensions |= FramebufferObject;
    4149     if (extensions.contains(QLatin1String("EXT_stencil_two_side")))
     4860    if (extensions.match("GL_EXT_stencil_two_side"))
    41504861        glExtensions |= StencilTwoSide;
    4151     if (extensions.contains(QLatin1String("EXT_stencil_wrap")))
     4862    if (extensions.match("GL_EXT_stencil_wrap"))
    41524863        glExtensions |= StencilWrap;
    4153     if (extensions.contains(QLatin1String("EXT_packed_depth_stencil")))
     4864    if (extensions.match("GL_EXT_packed_depth_stencil"))
    41544865        glExtensions |= PackedDepthStencil;
    4155     if (extensions.contains(QLatin1String("GL_NV_float_buffer")))
     4866    if (extensions.match("GL_NV_float_buffer"))
    41564867        glExtensions |= NVFloatBuffer;
    4157     if (extensions.contains(QLatin1String("ARB_pixel_buffer_object")))
     4868    if (extensions.match("GL_ARB_pixel_buffer_object"))
    41584869        glExtensions |= PixelBufferObject;
    41594870#if defined(QT_OPENGL_ES_2)
    41604871    glExtensions |= FramebufferObject;
    41614872    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;
    41684897}
    41694898
     
    41744903{
    41754904    Q_Q(QGLWidget);
     4905
     4906    glDevice.setWidget(q);
    41764907
    41774908    QGLExtensions::init();
     
    41904921
    41914922#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
    4192 Q_GLOBAL_STATIC(QString, qt_gl_lib_name);
     4923Q_GLOBAL_STATIC(QString, qt_gl_lib_name)
    41934924
    41944925Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name)
     
    42014932    if (qt_gl_lib_name()->isNull()) {
    42024933#if defined(Q_WS_X11) || defined(Q_WS_QWS)
    4203         return QString(QLatin1String("GL"));
     4934        return QLatin1String("GL");
    42044935#else // Q_WS_MAC
    42054936        return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib");
     
    42104941#endif
    42114942
     4943void 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
     4964QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
     4965    return context->d_ptr->group->m_shares;
     4966}
     4967
     4968void 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
     4985QGLContextResource::QGLContextResource(FreeFunc f)
     4986    : free(f), active(0)
     4987{
     4988}
     4989
     4990QGLContextResource::~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
     5001void 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
     5009void *QGLContextResource::value(const QGLContext *key)
     5010{
     5011    QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
     5012    return group->m_resources.value(this, 0);
     5013}
     5014
     5015void QGLContextResource::cleanup(const QGLContext *ctx, void *value)
     5016{
     5017    QGLShareContextScope scope(ctx);
     5018    free(value);
     5019    active.deref();
     5020}
     5021
     5022void 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
     5034QGLSharedResourceGuard::~QGLSharedResourceGuard()
     5035{
     5036    if (m_group)
     5037        m_group->removeGuard(this);
     5038}
     5039
     5040void 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
     5052QSize 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".
     5068struct 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
     5113bool 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
     5153QSize 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
     5195QSize 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
     5270QSize 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
    42125389QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.