diff options
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/qgl.cpp | 160 | ||||
-rw-r--r-- | src/opengl/qgl.h | 2 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 4 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 32 | ||||
-rw-r--r-- | src/opengl/qpaintengine_opengl.cpp | 9 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl.cpp | 8 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl_p.h | 2 |
7 files changed, 156 insertions, 61 deletions
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index b4a0e5c..b8fa133 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1297,6 +1297,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) max_texture_size = -1; version_flags_cached = false; version_flags = QGLFormat::OpenGL_Version_None; + current_fbo = 0; } QGLContext* QGLContext::currentCtx = 0; @@ -1676,58 +1677,105 @@ static void qt_gl_clean_cache(qint64 cacheKey) static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format) { - Q_ASSERT(dst.size() == img.size()); Q_ASSERT(dst.depth() == 32); Q_ASSERT(img.depth() == 32); - const int width = img.width(); - const int height = img.height(); - const uint *p = (const uint*) img.scanLine(img.height() - 1); - uint *q = (uint*) dst.scanLine(0); - - if (texture_format == GL_BGRA) { - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - // mirror + swizzle - for (int i=0; i < height; ++i) { - const uint *end = p + width; - while (p < end) { - *q = ((*p << 24) & 0xff000000) - | ((*p >> 24) & 0x000000ff) - | ((*p << 8) & 0x00ff0000) - | ((*p >> 8) & 0x0000ff00); - p++; - q++; + if (dst.size() != img.size()) { + int target_width = dst.width(); + int target_height = dst.height(); + qreal sx = target_width / qreal(img.width()); + qreal sy = target_height / qreal(img.height()); + + quint32 *dest = (quint32 *) dst.scanLine(0); // NB! avoid detach here + uchar *srcPixels = (uchar *) img.scanLine(img.height() - 1); + int sbpl = img.bytesPerLine(); + int dbpl = dst.bytesPerLine(); + + int ix = 0x00010000 / sx; + int iy = 0x00010000 / sy; + + quint32 basex = int(0.5 * ix); + quint32 srcy = int(0.5 * iy); + + // scale, swizzle and mirror in one loop + while (target_height--) { + const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl); + int srcx = basex; + for (int x=0; x<target_width; ++x) { + uint src_pixel = src[srcx >> 16]; + if (texture_format == GL_BGRA) { + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + dest[x] = ((src_pixel << 24) & 0xff000000) + | ((src_pixel >> 24) & 0x000000ff) + | ((src_pixel << 8) & 0x00ff0000) + | ((src_pixel >> 8) & 0x0000ff00); + } else { + dest[x] = src_pixel; + } + } else { // GL_RGBA + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + dest[x] = (src_pixel << 8) | ((src_pixel >> 24) & 0xff); + } else { + dest[x] = ((src_pixel << 16) & 0xff0000) + | ((src_pixel >> 16) & 0xff) + | (src_pixel & 0xff00ff00); + } } - p -= 2 * width; - } - } else { - const uint bytesPerLine = img.bytesPerLine(); - for (int i=0; i < height; ++i) { - memcpy(q, p, bytesPerLine); - q += width; - p -= width; + srcx += ix; } + dest = (quint32 *)(((uchar *) dest) + dbpl); + srcy += iy; } } else { - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - for (int i=0; i < height; ++i) { - const uint *end = p + width; - while (p < end) { - *q = (*p << 8) | ((*p >> 24) & 0xFF); - p++; - q++; + const int width = img.width(); + const int height = img.height(); + const uint *p = (const uint*) img.scanLine(img.height() - 1); + uint *q = (uint*) dst.scanLine(0); + + if (texture_format == GL_BGRA) { + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + // mirror + swizzle + for (int i=0; i < height; ++i) { + const uint *end = p + width; + while (p < end) { + *q = ((*p << 24) & 0xff000000) + | ((*p >> 24) & 0x000000ff) + | ((*p << 8) & 0x00ff0000) + | ((*p >> 8) & 0x0000ff00); + p++; + q++; + } + p -= 2 * width; + } + } else { + const uint bytesPerLine = img.bytesPerLine(); + for (int i=0; i < height; ++i) { + memcpy(q, p, bytesPerLine); + q += width; + p -= width; } - p -= 2 * width; } } else { - for (int i=0; i < height; ++i) { - const uint *end = p + width; - while (p < end) { - *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); - p++; - q++; + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + for (int i=0; i < height; ++i) { + const uint *end = p + width; + while (p < end) { + *q = (*p << 8) | ((*p >> 24) & 0xff); + p++; + q++; + } + p -= 2 * width; + } + } else { + for (int i=0; i < height; ++i) { + const uint *end = p + width; + while (p < end) { + *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); + p++; + q++; + } + p -= 2 * width; } - p -= 2 * width; } } } @@ -1770,19 +1818,18 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint } // Scale the pixmap if needed. GL textures needs to have the - // dimensions 2^n+2(border) x 2^m+2(border). + // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL + // 2.0 or use the GL_TEXTURE_RECTANGLE texture target int tx_w = qt_next_power_of_two(image.width()); int tx_h = qt_next_power_of_two(image.height()); + bool scale = false; - // Note: the clean param is only true when a texture is bound - // from the QOpenGLPaintEngine - in that case we have to force - // a premultiplied texture format QImage img = image; if (( !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) ) && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height()))) { - img = image.scaled(tx_w, tx_h); + scale = true; } GLuint tx_id; @@ -1814,17 +1861,24 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint ptr = reinterpret_cast<uchar *>(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB)); } - if (ptr) { - QImage::Format target_format = img.format(); - if (clean || img.format() != QImage::Format_ARGB32) - target_format = QImage::Format_ARGB32_Premultiplied; + QImage::Format target_format = img.format(); + // Note: the clean param is only true when a texture is bound + // from the QOpenGLPaintEngine - in that case we have to force + // a premultiplied texture format + if (clean || img.format() != QImage::Format_ARGB32) + target_format = QImage::Format_ARGB32_Premultiplied; + if (img.format() != target_format) + img = img.convertToFormat(target_format); + if (ptr) { QImage buffer(ptr, img.width(), img.height(), target_format); - convertToGLFormatHelper(buffer, img.convertToFormat(target_format), texture_format); + convertToGLFormatHelper(buffer, img, texture_format); glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); - glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format, GL_UNSIGNED_BYTE, 0); + glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format, + GL_UNSIGNED_BYTE, 0); } else { - QImage tx = convertToGLFormat(img, clean, texture_format); + QImage tx(scale ? QSize(tx_w, tx_h) : img.size(), target_format); + convertToGLFormatHelper(tx, img, texture_format); glTexImage2D(target, 0, format, tx.width(), tx.height(), 0, texture_format, GL_UNSIGNED_BYTE, tx.bits()); } diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 01b1d6f..32fbce2 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -371,8 +371,8 @@ private: friend class QMacGLWindowChangeEvent; friend QGLContextPrivate *qt_phonon_get_dptr(const QGLContext *); #endif -#ifdef Q_WS_WIN friend class QGLFramebufferObject; +#ifdef Q_WS_WIN friend class QGLFramebufferObjectPrivate; friend bool qt_resolve_GLSL_functions(QGLContext *ctx); friend bool qt_createGLSLProgram(QGLContext *ctx, GLuint &program, const char *shader_src, GLuint &shader); diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 16aaa96..1214f20 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -255,6 +255,8 @@ public: QGLExtensionFuncs extensionFuncs; GLint max_texture_size; + GLuint current_fbo; + #ifdef Q_WS_WIN static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; } #endif @@ -268,7 +270,7 @@ public: }; // ### make QGLContext a QObject in 5.0 and remove the proxy stuff -class QGLSignalProxy : public QObject +class Q_OPENGL_EXPORT QGLSignalProxy : public QObject { Q_OBJECT public: diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index c362b7e..4ba9213 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -70,7 +70,7 @@ extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); class QGLFramebufferObjectPrivate { public: - QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), bound(false), ctx(0) {} + QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), bound(false), ctx(0), previous_fbo(0) {} ~QGLFramebufferObjectPrivate() {} void init(const QSize& sz, QGLFramebufferObject::Attachment attachment, @@ -85,6 +85,7 @@ public: uint bound : 1; QGLFramebufferObject::Attachment fbo_attachment; QGLContext *ctx; // for Windows extension ptrs + GLuint previous_fbo; }; bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const @@ -473,6 +474,15 @@ bool QGLFramebufferObject::isValid() const Switches rendering from the default, windowing system provided framebuffer to this framebuffer object. Returns true upon success, false otherwise. + + Since 4.6: if another QGLFramebufferObject instance was already bound + to the current context, then its handle() will be remembered and + automatically restored when release() is called. This allows multiple + framebuffer rendering targets to be stacked up. It is important that + release() is called on the stacked framebuffer objects in the reverse + order of the calls to bind(). + + \sa release() */ bool QGLFramebufferObject::bind() { @@ -482,6 +492,12 @@ bool QGLFramebufferObject::bind() QGL_FUNC_CONTEXT; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->fbo); d->bound = d->valid = d->checkFramebufferStatus(); + const QGLContext *context = QGLContext::currentContext(); + if (d->valid && context) { + // Save the previous setting to automatically restore in release(). + d->previous_fbo = context->d_ptr->current_fbo; + context->d_ptr->current_fbo = d->fbo; + } return d->valid; } @@ -491,6 +507,12 @@ bool QGLFramebufferObject::bind() Switches rendering back to the default, windowing system provided framebuffer. Returns true upon success, false otherwise. + + Since 4.6: if another QGLFramebufferObject instance was already bound + to the current context when bind() was called, then this function will + automatically re-bind it to the current context. + + \sa bind() */ bool QGLFramebufferObject::release() { @@ -501,6 +523,14 @@ bool QGLFramebufferObject::release() glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); d->valid = d->checkFramebufferStatus(); d->bound = false; + const QGLContext *context = QGLContext::currentContext(); + if (d->valid && context) { + // Restore the previous setting for stacked framebuffer objects. + context->d_ptr->current_fbo = d->previous_fbo; + if (d->previous_fbo) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->previous_fbo); + d->previous_fbo = 0; + } return d->valid; } diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index ec6e33b..77ff9fb 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -1924,15 +1924,15 @@ static void drawTrapezoid(const QGLTrapezoid &trap, const qreal offscreenHeight, qreal leftB = trap.bottomLeftX + (trap.topLeftX - trap.bottomLeftX) * reciprocal; qreal rightB = trap.bottomRightX + (trap.topRightX - trap.bottomRightX) * reciprocal; - const bool topZero = qFuzzyCompare(topDist + 1, 1); + const bool topZero = qFuzzyIsNull(topDist); reciprocal = topZero ? 1.0 / bottomDist : 1.0 / topDist; qreal leftA = topZero ? (trap.bottomLeftX - leftB) * reciprocal : (trap.topLeftX - leftB) * reciprocal; qreal rightA = topZero ? (trap.bottomRightX - rightB) * reciprocal : (trap.topRightX - rightB) * reciprocal; - qreal invLeftA = qFuzzyCompare(leftA + 1, 1) ? 0.0 : 1.0 / leftA; - qreal invRightA = qFuzzyCompare(rightA + 1, 1) ? 0.0 : 1.0 / rightA; + qreal invLeftA = qFuzzyIsNull(leftA) ? 0.0 : 1.0 / leftA; + qreal invRightA = qFuzzyIsNull(rightA) ? 0.0 : 1.0 / rightA; // fragment program needs the negative of invRightA as it mirrors the line glTexCoord4f(topDist, bottomDist, invLeftA, -invRightA); @@ -3445,8 +3445,7 @@ QVector<QGLTrapezoid> QGLRectMaskGenerator::generateTrapezoids() // manhattan distance (no rotation) qreal width = qAbs(delta.x()) + qAbs(delta.y()); - Q_ASSERT(qFuzzyCompare(delta.x() + 1, static_cast<qreal>(1)) - || qFuzzyCompare(delta.y() + 1, static_cast<qreal>(1))); + Q_ASSERT(qFuzzyIsNull(delta.x()) || qFuzzyIsNull(delta.y())); tessellator.tessellateRect(first, last, width); } else { diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 5d668cd..b079557 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -205,6 +205,14 @@ void QGLPixmapData::fromImage(const QImage &image, m_dirty = true; } +bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect) +{ + Q_UNUSED(dx); + Q_UNUSED(dy); + Q_UNUSED(rect); + return false; +} + void QGLPixmapData::fill(const QColor &color) { if (!isValid()) diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index 63703fd..e450f01 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -73,6 +73,8 @@ public: void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + bool scroll(int dx, int dy, const QRect &rect); + void fill(const QColor &color); bool hasAlphaChannel() const; QImage toImage() const; |