Provide a way to cheaply flip your painted FBO
authorSarah Smith <sarah.j.smith@nokia.com>
Thu, 20 Oct 2011 00:01:39 +0000 (10:01 +1000)
committerQt by Nokia <qt-info@nokia.com>
Sun, 23 Oct 2011 12:44:23 +0000 (14:44 +0200)
After recent changes the painted images are upside down from previous
and there is no way to get at the texture coordinates to flip them back
without reimplementing QSGPainterNode and QSGPaintedItem.

This change adds only an enum and has minimal impact, while providing
useful functionality that also fixes this problem.

Change-Id: I6884da884d9303f6e08a984d4560cc7f7728d918
Reviewed-by: Sarah Jane Smith <sarah.j.smith@nokia.com>
src/declarative/items/qquickpainteditem.cpp
src/declarative/items/qquickpainteditem.h
src/declarative/scenegraph/util/qsgpainternode.cpp

index 5e5eb79..ac67f6a 100644 (file)
@@ -92,6 +92,12 @@ QT_BEGIN_NAMESPACE
     quality is not as good as if using an image. This render target allows faster rendering
     in some cases, but you should avoid using it if the item is resized often.
 
+    \value InvertedYFramebufferObject Exactly as for FramebufferObject above, except once
+    the painting is done, prior to rendering the painted image is flipped about the
+    x-axis so that the top-most pixels are now at the bottom.  Since this is done with the
+    OpenGL texture coordinates it is a much faster way to achieve this effect than using a
+    painter transform.
+
     \sa setRenderTarget()
 */
 
@@ -437,10 +443,11 @@ void QQuickPaintedItem::setFillColor(const QColor &c)
     \brief The item's render target.
 
     This property defines which render target the QPainter renders into, it can be either
-    QQuickPaintedItem::Image or QQuickPaintedItem::FramebufferObject. Both have certains benefits,
-    typically performance versus quality. Using a framebuffer object avoids a costly upload
-    of the image contents to the texture in graphics memory, while using an image enables
-    high quality anti-aliasing.
+    QSGPaintedItem::Image, QSGPaintedItem::FramebufferObject or QSGPaintedItem::InvertedYFramebufferObject.
+
+    Each has certain benefits, typically performance versus quality. Using a framebuffer
+    object avoids a costly upload of the image contents to the texture in graphics memory,
+    while using an image enables high quality anti-aliasing.
 
     \warning Resizing a framebuffer object is a costly operation, avoid using
     the QQuickPaintedItem::FramebufferObject render target if the item gets resized often.
index 5f461fd..1ddfa25 100644 (file)
@@ -65,7 +65,8 @@ public:
 
     enum RenderTarget {
         Image,
-        FramebufferObject
+        FramebufferObject,
+        InvertedYFramebufferObject
     };
 
     enum PerformanceHint {
index 3f07f20..1f44750 100644 (file)
@@ -238,8 +238,11 @@ void QSGPainterNode::updateGeometry()
         source = QRectF(0, 0, 1, 1);
     else
         source = QRectF(0, 0, qreal(m_size.width()) / m_fboSize.width(), qreal(m_size.height()) / m_fboSize.height());
+    QRectF dest(0, 0, m_size.width(), m_size.height());
+    if (m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject)
+        dest = QRectF(QPointF(0, m_size.height()), QPointF(m_size.width(), 0));
     QSGGeometry::updateTexturedRectGeometry(&m_geometry,
-                                            QRectF(0, 0, m_size.width(), m_size.height()),
+                                            dest,
                                             source);
     markDirty(DirtyGeometry);
 }
@@ -262,7 +265,7 @@ void QSGPainterNode::updateRenderTarget()
         if (!m_multisamplingSupported && m_smoothPainting)
             m_actualRenderTarget = QQuickPaintedItem::Image;
         else
-            m_actualRenderTarget = QQuickPaintedItem::FramebufferObject;
+            m_actualRenderTarget = m_preferredRenderTarget;
     }
     if (oldTarget != m_actualRenderTarget) {
         m_image = QImage();
@@ -271,7 +274,8 @@ void QSGPainterNode::updateRenderTarget()
         m_fbo = m_multisampledFbo = 0;
     }
 
-    if (m_actualRenderTarget == QQuickPaintedItem::FramebufferObject) {
+    if (m_actualRenderTarget == QQuickPaintedItem::FramebufferObject ||
+            m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject) {
         const QOpenGLContext *ctx = m_context->glContext();
         if (m_fbo && !m_dirtyGeometry && (!ctx->format().samples() || !m_multisamplingSupported))
             return;