src/opengl/qgl.cpp
branchRCL_3
changeset 8 3f74d0d4af4c
parent 5 d3bac044e0f0
equal deleted inserted replaced
6:dee5afe5301f 8:3f74d0d4af4c
   100 #endif
   100 #endif
   101 
   101 
   102 
   102 
   103 #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
   103 #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
   104 QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs;
   104 QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs;
       
   105 #endif
       
   106 
       
   107 #ifdef Q_WS_X11
       
   108 extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
   105 #endif
   109 #endif
   106 
   110 
   107 struct QGLThreadContext {
   111 struct QGLThreadContext {
   108     QGLContext *context;
   112     QGLContext *context;
   109 };
   113 };
  1588     : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though
  1592     : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though
  1589 {
  1593 {
  1590     Q_ASSERT(qt_gl_texture_cache == 0);
  1594     Q_ASSERT(qt_gl_texture_cache == 0);
  1591     qt_gl_texture_cache = this;
  1595     qt_gl_texture_cache = this;
  1592 
  1596 
  1593     QImagePixmapCleanupHooks::instance()->addPixmapModificationHook(cleanupTextures);
  1597     QImagePixmapCleanupHooks::instance()->addPixmapDataModificationHook(cleanupTexturesForPixampData);
  1594 #ifdef Q_WS_X11
  1598     QImagePixmapCleanupHooks::instance()->addPixmapDataDestructionHook(cleanupBeforePixmapDestruction);
  1595     QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(cleanupPixmapSurfaces);
  1599     QImagePixmapCleanupHooks::instance()->addImageHook(cleanupTexturesForCacheKey);
  1596 #endif
       
  1597     QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook);
       
  1598 }
  1600 }
  1599 
  1601 
  1600 QGLTextureCache::~QGLTextureCache()
  1602 QGLTextureCache::~QGLTextureCache()
  1601 {
  1603 {
  1602     qt_gl_texture_cache = 0;
  1604     qt_gl_texture_cache = 0;
  1603 
  1605 
  1604     QImagePixmapCleanupHooks::instance()->removePixmapModificationHook(cleanupTextures);
  1606     QImagePixmapCleanupHooks::instance()->removePixmapDataModificationHook(cleanupTexturesForPixampData);
  1605 #ifdef Q_WS_X11
  1607     QImagePixmapCleanupHooks::instance()->removePixmapDataDestructionHook(cleanupBeforePixmapDestruction);
  1606     QImagePixmapCleanupHooks::instance()->removePixmapDestructionHook(cleanupPixmapSurfaces);
  1608     QImagePixmapCleanupHooks::instance()->removeImageHook(cleanupTexturesForCacheKey);
  1607 #endif
       
  1608     QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook);
       
  1609 }
  1609 }
  1610 
  1610 
  1611 void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
  1611 void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
  1612 {
  1612 {
  1613     if (m_cache.totalCost() + cost > m_cache.maxCost()) {
  1613     if (m_cache.totalCost() + cost > m_cache.maxCost()) {
  1659 
  1659 
  1660 /*
  1660 /*
  1661   a hook that removes textures from the cache when a pixmap/image
  1661   a hook that removes textures from the cache when a pixmap/image
  1662   is deref'ed
  1662   is deref'ed
  1663 */
  1663 */
  1664 void QGLTextureCache::imageCleanupHook(qint64 cacheKey)
  1664 void QGLTextureCache::cleanupTexturesForCacheKey(qint64 cacheKey)
  1665 {
       
  1666     // ### remove when the GL texture cache becomes thread-safe
       
  1667     if (qApp->thread() != QThread::currentThread())
       
  1668         return;
       
  1669     QGLTexture *texture = instance()->getTexture(cacheKey);
       
  1670     if (texture && texture->options & QGLContext::MemoryManagedBindOption)
       
  1671         instance()->remove(cacheKey);
       
  1672 }
       
  1673 
       
  1674 
       
  1675 void QGLTextureCache::cleanupTextures(QPixmap* pixmap)
       
  1676 {
  1665 {
  1677     // ### remove when the GL texture cache becomes thread-safe
  1666     // ### remove when the GL texture cache becomes thread-safe
  1678     if (qApp->thread() == QThread::currentThread()) {
  1667     if (qApp->thread() == QThread::currentThread()) {
  1679         const qint64 cacheKey = pixmap->cacheKey();
  1668         instance()->remove(cacheKey);
  1680         QGLTexture *texture = instance()->getTexture(cacheKey);
  1669         Q_ASSERT(instance()->getTexture(cacheKey) == 0);
  1681         if (texture && texture->options & QGLContext::MemoryManagedBindOption)
  1670     }
  1682             instance()->remove(cacheKey);
  1671 }
  1683     }
  1672 
  1684 }
  1673 
       
  1674 void QGLTextureCache::cleanupTexturesForPixampData(QPixmapData* pmd)
       
  1675 {
       
  1676     cleanupTexturesForCacheKey(pmd->cacheKey());
       
  1677 }
       
  1678 
       
  1679 void QGLTextureCache::cleanupBeforePixmapDestruction(QPixmapData* pmd)
       
  1680 {
       
  1681     // Remove any bound textures first:
       
  1682     cleanupTexturesForPixampData(pmd);
  1685 
  1683 
  1686 #if defined(Q_WS_X11)
  1684 #if defined(Q_WS_X11)
  1687 void QGLTextureCache::cleanupPixmapSurfaces(QPixmap* pixmap)
  1685     if (pmd->classId() == QPixmapData::X11Class) {
  1688 {
  1686         Q_ASSERT(pmd->ref == 0); // Make sure reference counting isn't broken
  1689     // Remove any bound textures first:
  1687         QGLContextPrivate::destroyGlSurfaceForPixmap(pmd);
  1690     cleanupTextures(pixmap);
  1688     }
  1691 
  1689 #endif
  1692     QPixmapData *pd = pixmap->data_ptr().data();
  1690 }
  1693     if (pd->classId() == QPixmapData::X11Class) {
       
  1694         Q_ASSERT(pd->ref == 1); // Make sure reference counting isn't broken
       
  1695         QGLContextPrivate::destroyGlSurfaceForPixmap(pd);
       
  1696     }
       
  1697 }
       
  1698 #endif
       
  1699 
  1691 
  1700 void QGLTextureCache::deleteIfEmpty()
  1692 void QGLTextureCache::deleteIfEmpty()
  1701 {
  1693 {
  1702     if (instance()->size() == 0)
  1694     if (instance()->size() == 0)
  1703         delete instance();
  1695         delete instance();
  2086     if (!texture)
  2078     if (!texture)
  2087         texture = bindTexture(image, target, format, key, options);
  2079         texture = bindTexture(image, target, format, key, options);
  2088     // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
  2080     // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
  2089     Q_ASSERT(texture);
  2081     Q_ASSERT(texture);
  2090 
  2082 
  2091     if (texture->id > 0)
  2083     // Enable the cleanup hooks for this image so that the texture cache entry is removed when the
  2092         QImagePixmapCleanupHooks::enableCleanupHooks(image);
  2084     // image gets deleted:
       
  2085     QImagePixmapCleanupHooks::enableCleanupHooks(image);
  2093 
  2086 
  2094     return texture;
  2087     return texture;
  2095 }
  2088 }
  2096 
  2089 
  2097 // #define QGL_BIND_TEXTURE_DEBUG
  2090 // #define QGL_BIND_TEXTURE_DEBUG
  2141     // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
  2134     // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
  2142     int tx_w = qt_next_power_of_two(image.width());
  2135     int tx_w = qt_next_power_of_two(image.width());
  2143     int tx_h = qt_next_power_of_two(image.height());
  2136     int tx_h = qt_next_power_of_two(image.height());
  2144 
  2137 
  2145     QImage img = image;
  2138     QImage img = image;
       
  2139 
  2146     if (!(QGLExtensions::glExtensions() & QGLExtensions::NPOTTextures)
  2140     if (!(QGLExtensions::glExtensions() & QGLExtensions::NPOTTextures)
  2147         && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0)
  2141         && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0)
  2148         && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
  2142         && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
  2149     {
  2143     {
  2150         img = img.scaled(tx_w, tx_h);
  2144         img = img.scaled(tx_w, tx_h);
  2309 
  2303 
  2310     // this assumes the size of a texture is always smaller than the max cache size
  2304     // this assumes the size of a texture is always smaller than the max cache size
  2311     int cost = img.width()*img.height()*4/1024;
  2305     int cost = img.width()*img.height()*4/1024;
  2312     QGLTexture *texture = new QGLTexture(q, tx_id, target, options);
  2306     QGLTexture *texture = new QGLTexture(q, tx_id, target, options);
  2313     QGLTextureCache::instance()->insert(q, key, texture, cost);
  2307     QGLTextureCache::instance()->insert(q, key, texture, cost);
       
  2308 
  2314     return texture;
  2309     return texture;
  2315 }
  2310 }
  2316 
  2311 
  2317 QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target)
  2312 QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target)
  2318 {
  2313 {
  2353         return texture;
  2348         return texture;
  2354     }
  2349     }
  2355 
  2350 
  2356 #if defined(Q_WS_X11)
  2351 #if defined(Q_WS_X11)
  2357     // Try to use texture_from_pixmap
  2352     // Try to use texture_from_pixmap
  2358     if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType) {
  2353     const QX11Info *xinfo = qt_x11Info(paintDevice);
       
  2354     if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType
       
  2355         && xinfo && xinfo->screen() == pixmap.x11Info().screen())
       
  2356     {
  2359         texture = bindTextureFromNativePixmap(pd, key, options);
  2357         texture = bindTextureFromNativePixmap(pd, key, options);
  2360         if (texture) {
  2358         if (texture) {
  2361             texture->options |= QGLContext::MemoryManagedBindOption;
  2359             texture->options |= QGLContext::MemoryManagedBindOption;
  2362             texture->boundPixmap = pd;
  2360             texture->boundPixmap = pd;
  2363             boundPixmaps.insert(pd, QPixmap(pixmap));
  2361             boundPixmaps.insert(pd, QPixmap(pixmap));
  2422 {
  2420 {
  2423     if (image.isNull())
  2421     if (image.isNull())
  2424         return 0;
  2422         return 0;
  2425 
  2423 
  2426     Q_D(QGLContext);
  2424     Q_D(QGLContext);
  2427     QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption);
  2425     QGLTexture *texture = d->bindTexture(image, target, format, DefaultBindOption);
  2428     return texture->id;
  2426     return texture->id;
  2429 }
  2427 }
  2430 
  2428 
  2431 /*!
  2429 /*!
  2432     \since 4.6
  2430     \since 4.6
  2562     QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
  2560     QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
  2563     QList<QString> ddsKeys = dds_cache->keys();
  2561     QList<QString> ddsKeys = dds_cache->keys();
  2564     for (int i = 0; i < ddsKeys.size(); ++i) {
  2562     for (int i = 0; i < ddsKeys.size(); ++i) {
  2565         GLuint texture = dds_cache->value(ddsKeys.at(i));
  2563         GLuint texture = dds_cache->value(ddsKeys.at(i));
  2566         if (id == texture) {
  2564         if (id == texture) {
  2567             glDeleteTextures(1, &texture);
       
  2568             dds_cache->remove(ddsKeys.at(i));
  2565             dds_cache->remove(ddsKeys.at(i));
  2569             return;
  2566             break;
  2570         }
  2567         }
  2571     }
  2568     }
       
  2569 
       
  2570     // Finally, actually delete the texture ID
       
  2571     glDeleteTextures(1, &id);
  2572 }
  2572 }
  2573 
  2573 
  2574 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
  2574 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
  2575 /*! \internal */
  2575 /*! \internal */
  2576 void QGLContext::deleteTexture(QMacCompatGLuint id)
  2576 void QGLContext::deleteTexture(QMacCompatGLuint id)
  5449         reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize);
  5449         reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize);
  5450     bufferSize = pvrHeader->dataSize;
  5450     bufferSize = pvrHeader->dataSize;
  5451     quint32 level = 0;
  5451     quint32 level = 0;
  5452     quint32 width = pvrHeader->width;
  5452     quint32 width = pvrHeader->width;
  5453     quint32 height = pvrHeader->height;
  5453     quint32 height = pvrHeader->height;
  5454     while (bufferSize > 0 && level < pvrHeader->mipMapCount) {
  5454     while (bufferSize > 0 && level <= pvrHeader->mipMapCount) {
  5455         quint32 size =
  5455         quint32 size =
  5456             (qMax(width, minWidth) * qMax(height, minHeight) *
  5456             (qMax(width, minWidth) * qMax(height, minHeight) *
  5457              pvrHeader->bitsPerPixel) / 8;
  5457              pvrHeader->bitsPerPixel) / 8;
  5458         if (size > bufferSize)
  5458         if (size > bufferSize)
  5459             break;
  5459             break;