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)); |
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; |