src/opengl/qpixmapdata_gl.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
--- a/src/opengl/qpixmapdata_gl.cpp	Tue Jan 26 12:42:25 2010 +0200
+++ b/src/opengl/qpixmapdata_gl.cpp	Tue Feb 02 00:43:10 2010 +0200
@@ -53,6 +53,8 @@
 #include <private/qpaintengineex_opengl2_p.h>
 
 #include <qdesktopwidget.h>
+#include <qfile.h>
+#include <qimagereader.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -76,13 +78,35 @@
     return qAbs(size.width() * size.height() - fbo->width() * fbo->height());
 }
 
-QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat)
+extern int qt_next_power_of_two(int v);
+
+static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
+{
+#ifdef QT_OPENGL_ES_2
+    QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height()));
+    if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height())
+        return rounded;
+#endif
+    return sz;
+}
+
+
+QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
 {
     QGLFramebufferObject *chosen = 0;
     QGLFramebufferObject *candidate = 0;
     for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
         QGLFramebufferObject *fbo = m_fbos.at(i);
 
+        if (strictSize) {
+            if (fbo->size() == requestSize && fbo->format() == requestFormat) {
+                chosen = fbo;
+                break;
+            } else {
+                continue;
+            }
+        }
+
         if (fbo->format() == requestFormat) {
             // choose the fbo with a matching format and the closest size
             if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
@@ -106,7 +130,7 @@
 
             if (sz != fboSize) {
                 delete candidate;
-                candidate = new QGLFramebufferObject(sz, requestFormat);
+                candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat);
             }
 
             chosen = candidate;
@@ -114,7 +138,10 @@
     }
 
     if (!chosen) {
-        chosen = new QGLFramebufferObject(requestSize, requestFormat);
+        if (strictSize)
+            chosen = new QGLFramebufferObject(requestSize, requestFormat);
+        else
+            chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
     }
 
     if (!chosen->isValid()) {
@@ -127,7 +154,8 @@
 
 void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
 {
-    m_fbos << fbo;
+    if (fbo)
+        m_fbos << fbo;
 }
 
 
@@ -295,25 +323,36 @@
     QGLShareContextScope ctx(qt_gl_share_widget()->context());
     m_ctx = ctx;
 
-    const GLenum format = qt_gl_preferredTextureFormat();
+    const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB;
+#ifdef QT_OPENGL_ES_2
+    const GLenum external_format = internal_format;
+#else
+    const GLenum external_format = qt_gl_preferredTextureFormat();
+#endif
     const GLenum target = GL_TEXTURE_2D;
 
     if (!m_texture.id) {
         glGenTextures(1, &m_texture.id);
         glBindTexture(target, m_texture.id);
-        GLenum format = m_hasAlpha ? GL_RGBA : GL_RGB;
-        glTexImage2D(target, 0, format, w, h, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, 0);
+        glTexImage2D(target, 0, internal_format, w, h, 0, external_format, GL_UNSIGNED_BYTE, 0);
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     }
 
     if (!m_source.isNull()) {
-        const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format);
+        if (external_format == GL_RGB) {
+            const QImage tx = m_source.convertToFormat(QImage::Format_RGB888);
 
-        glBindTexture(target, m_texture.id);
-        glTexSubImage2D(target, 0, 0, 0, w, h, format,
-                        GL_UNSIGNED_BYTE, tx.bits());
+            glBindTexture(target, m_texture.id);
+            glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
+                            GL_UNSIGNED_BYTE, tx.bits());
+        } else {
+            const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format);
+
+            glBindTexture(target, m_texture.id);
+            glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
+                            GL_UNSIGNED_BYTE, tx.bits());
+        }
 
         if (useFramebufferObjects())
             m_source = QImage();
@@ -359,6 +398,63 @@
     }
 }
 
+bool QGLPixmapData::fromFile(const QString &filename, const char *format,
+                             Qt::ImageConversionFlags flags)
+{
+    if (pixelType() == QPixmapData::BitmapType)
+        return QPixmapData::fromFile(filename, format, flags);
+    QFile file(filename);
+    if (!file.open(QIODevice::ReadOnly))
+        return false;
+    QByteArray data = file.peek(64);
+    bool alpha;
+    if (m_texture.canBindCompressedTexture
+            (data.constData(), data.size(), format, &alpha)) {
+        resize(0, 0);
+        data = file.readAll();
+        file.close();
+        QGLShareContextScope ctx(qt_gl_share_widget()->context());
+        QSize size = m_texture.bindCompressedTexture
+            (data.constData(), data.size(), format);
+        if (!size.isEmpty()) {
+            w = size.width();
+            h = size.height();
+            is_null = false;
+            d = 32;
+            m_hasAlpha = alpha;
+            m_source = QImage();
+            m_dirty = isValid();
+            return true;
+        }
+        return false;
+    }
+    fromImage(QImageReader(&file, format).read(), flags);
+    return !isNull();
+}
+
+bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format,
+                             Qt::ImageConversionFlags flags)
+{
+    bool alpha;
+    const char *buf = reinterpret_cast<const char *>(buffer);
+    if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) {
+        resize(0, 0);
+        QGLShareContextScope ctx(qt_gl_share_widget()->context());
+        QSize size = m_texture.bindCompressedTexture(buf, int(len), format);
+        if (!size.isEmpty()) {
+            w = size.width();
+            h = size.height();
+            is_null = false;
+            d = 32;
+            m_hasAlpha = alpha;
+            m_source = QImage();
+            m_dirty = isValid();
+            return true;
+        }
+    }
+    return QPixmapData::fromData(buffer, len, format, flags);
+}
+
 bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
 {
     Q_UNUSED(dx);
@@ -426,7 +522,7 @@
     if (pixelType() == BitmapType) {
         img = QImage(w, h, QImage::Format_MonoLSB);
 
-        img.setNumColors(2);
+        img.setColorCount(2);
         img.setColor(0, QColor(Qt::color0).rgba());
         img.setColor(1, QColor(Qt::color1).rgba());