aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-08-11 13:59:58 +0200
committerLars Knoll <lars.knoll@digia.com>2014-08-12 18:02:25 +0300
commit62949ea655512c9c5974a0789f59f8729bef7d8f (patch)
tree9f7a2d2c6bdb5e46d8e705bb01728d0e87e97fd0
parentcd71ddd020d16dc06c5eb7f5d4d0988255d49cd9 (diff)
Add support for software layers
Change-Id: Iefac991ea5b9124cc9dd482e809180aa5f3d96d7 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--softwarecontext/context.cpp38
-rw-r--r--softwarecontext/context.h16
-rw-r--r--softwarecontext/imagenode.cpp54
-rw-r--r--softwarecontext/imagenode.h7
-rw-r--r--softwarecontext/pixmaptexture.h2
-rw-r--r--softwarecontext/softwarecontext.pro6
-rw-r--r--softwarecontext/softwarelayer.cpp200
-rw-r--r--softwarecontext/softwarelayer.h67
8 files changed, 371 insertions, 19 deletions
diff --git a/softwarecontext/context.cpp b/softwarecontext/context.cpp
index 69e05951c9..de0e644a80 100644
--- a/softwarecontext/context.cpp
+++ b/softwarecontext/context.cpp
@@ -47,6 +47,7 @@
#include "glyphnode.h"
#include "ninepatchnode.h"
#include "renderingvisitor.h"
+#include "softwarelayer.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QElapsedTimer>
@@ -107,6 +108,38 @@ void Renderer::render()
backingStore->flush(rect);
}
+void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
+{
+
+ QSGRenderer::nodeChanged(node, state);
+}
+
+PixmapRenderer::PixmapRenderer(QSGRenderContext *context)
+ : QSGRenderer(context)
+{
+
+}
+
+void PixmapRenderer::renderScene(GLuint)
+{
+ Q_UNREACHABLE();
+}
+
+void PixmapRenderer::render()
+{
+ Q_UNREACHABLE();
+}
+
+void PixmapRenderer::render(QPixmap *target)
+{
+ const QRect rect(0, 0, target->width(), target->height());
+ target->fill(clearColor());
+ QPainter painter(target);
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ RenderingVisitor(&painter).visitChildren(rootNode());
+}
+
RenderContext::RenderContext(QSGContext *ctx)
: QSGRenderContext(ctx)
, currentWindow(0)
@@ -143,6 +176,11 @@ QSGNinePatchNode *Context::createQStyleNode()
return new NinePatchNode();
}
+QSGLayer *Context::createLayer(QSGRenderContext *renderContext)
+{
+ return new SoftwareLayer(renderContext);
+}
+
void RenderContext::initialize(QOpenGLContext *context)
{
QSGRenderContext::initialize(context);
diff --git a/softwarecontext/context.h b/softwarecontext/context.h
index 75d75ac369..c2dfa469cb 100644
--- a/softwarecontext/context.h
+++ b/softwarecontext/context.h
@@ -62,8 +62,23 @@ public:
virtual void render();
+ void nodeChanged(QSGNode *node, QSGNode::DirtyState state);
+
private:
QScopedPointer<QBackingStore> backingStore;
+ QRect m_dirtyRect;
+};
+
+class PixmapRenderer : public QSGRenderer
+{
+public:
+ PixmapRenderer(QSGRenderContext *context);
+
+ virtual void renderScene(GLuint fboId = 0);
+
+ virtual void render();
+
+ void render(QPixmap *target);
};
class RenderContext : public QSGRenderContext
@@ -93,6 +108,7 @@ public:
virtual QSGImageNode *createImageNode();
virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode);
virtual QSGNinePatchNode *createQStyleNode();
+ virtual QSGLayer *createLayer(QSGRenderContext *renderContext);
private:
};
diff --git a/softwarecontext/imagenode.cpp b/softwarecontext/imagenode.cpp
index e56bfa7f11..a5cf996ebe 100644
--- a/softwarecontext/imagenode.cpp
+++ b/softwarecontext/imagenode.cpp
@@ -1,6 +1,7 @@
#include "imagenode.h"
#include "pixmaptexture.h"
+#include "softwarelayer.h"
#include <QPainter>
#include <qmath.h>
@@ -267,7 +268,10 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin
}
ImageNode::ImageNode()
- : m_mirror(false)
+ : m_innerSourceRect(0, 0, 1, 1)
+ , m_subSourceRect(0, 0, 1, 1)
+ , m_texture(0)
+ , m_mirror(false)
, m_smooth(true)
, m_tileHorizontal(false)
, m_tileVertical(false)
@@ -299,12 +303,7 @@ void ImageNode::setSubSourceRect(const QRectF &rect)
void ImageNode::setTexture(QSGTexture *texture)
{
- PixmapTexture *pt = qobject_cast<PixmapTexture*>(texture);
- if (!pt) {
- qWarning() << "Image used with invalid texture format.";
- return;
- }
- m_pixmap = pt->pixmap();
+ m_texture = texture;
}
void ImageNode::setMirror(bool mirror)
@@ -336,6 +335,18 @@ void ImageNode::update()
{
}
+void ImageNode::preprocess()
+{
+ bool doDirty = false;
+ QSGLayer *t = qobject_cast<QSGLayer *>(m_texture);
+ if (t) {
+ doDirty = t->updateTexture();
+ markDirty(DirtyGeometry);
+ }
+ if (doDirty)
+ markDirty(DirtyMaterial);
+}
+
static Qt::TileRule getTileRule(qreal factor)
{
int ifactor = qRound(factor);
@@ -352,29 +363,42 @@ void ImageNode::paint(QPainter *painter)
{
painter->setRenderHint(QPainter::SmoothPixmapTransform, m_smooth);
+ const QPixmap &pm = pixmap();
+
if (m_innerTargetRect != m_targetRect) {
// border image
QMargins margins(m_innerTargetRect.left() - m_targetRect.left(), m_innerTargetRect.top() - m_targetRect.top(),
m_targetRect.right() - m_innerTargetRect.right(), m_targetRect.bottom() - m_innerTargetRect.bottom());
QTileRules tilerules(getTileRule(m_subSourceRect.width()), getTileRule(m_subSourceRect.height()));
- SoftwareContext::qDrawBorderPixmap(painter, m_targetRect.toRect(), margins, m_pixmap, QRect(0, 0, m_pixmap.width(), m_pixmap.height()),
+ SoftwareContext::qDrawBorderPixmap(painter, m_targetRect.toRect(), margins, pm, QRect(0, 0, pm.width(), pm.height()),
margins, tilerules, QDrawBorderPixmap::DrawingHints(0));
return;
}
if (m_tileHorizontal || m_tileVertical) {
painter->save();
- qreal sx = m_targetRect.width()/(m_subSourceRect.width()*m_pixmap.width());
- qreal sy = m_targetRect.height()/(m_subSourceRect.height()*m_pixmap.height());
+ qreal sx = m_targetRect.width()/(m_subSourceRect.width()*pm.width());
+ qreal sy = m_targetRect.height()/(m_subSourceRect.height()*pm.height());
QMatrix transform(sx, 0, 0, sy, 0, 0);
painter->setMatrix(transform, true);
painter->drawTiledPixmap(QRectF(m_targetRect.x()/sx, m_targetRect.y()/sy, m_targetRect.width()/sx, m_targetRect.height()/sy),
- m_pixmap,
- QPointF(m_subSourceRect.left()*m_pixmap.width(), m_subSourceRect.top()*m_pixmap.height()));
+ pm,
+ QPointF(m_subSourceRect.left()*pm.width(), m_subSourceRect.top()*pm.height()));
painter->restore();
} else {
- QRectF sr(m_subSourceRect.left()*m_pixmap.width(), m_subSourceRect.top()*m_pixmap.height(),
- m_subSourceRect.width()*m_pixmap.width(), m_subSourceRect.height()*m_pixmap.height());
- painter->drawPixmap(m_targetRect, m_pixmap, sr);
+ QRectF sr(m_subSourceRect.left()*pm.width(), m_subSourceRect.top()*pm.height(),
+ m_subSourceRect.width()*pm.width(), m_subSourceRect.height()*pm.height());
+ painter->drawPixmap(m_targetRect, pm, sr);
+ }
+}
+
+const QPixmap &ImageNode::pixmap() const
+{
+ if (PixmapTexture *pt = qobject_cast<PixmapTexture*>(m_texture)) {
+ return pt->pixmap();
+ } else if (SoftwareLayer *layer = qobject_cast<SoftwareLayer*>(m_texture)) {
+ return layer->pixmap();
+ } else {
+ qFatal("Image used with invalid texture format.");
}
}
diff --git a/softwarecontext/imagenode.h b/softwarecontext/imagenode.h
index 6270d05f75..7b3f64b815 100644
--- a/softwarecontext/imagenode.h
+++ b/softwarecontext/imagenode.h
@@ -66,15 +66,20 @@ public:
virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode);
virtual void update();
+ virtual void preprocess();
+
void paint(QPainter *painter);
private:
+ const QPixmap &pixmap() const;
+
QRectF m_targetRect;
QRectF m_innerTargetRect;
QRectF m_innerSourceRect;
QRectF m_subSourceRect;
- QPixmap m_pixmap;
+ QSGTexture *m_texture;
+
bool m_mirror;
bool m_smooth;
bool m_tileHorizontal;
diff --git a/softwarecontext/pixmaptexture.h b/softwarecontext/pixmaptexture.h
index 314005f82a..fcf21c309e 100644
--- a/softwarecontext/pixmaptexture.h
+++ b/softwarecontext/pixmaptexture.h
@@ -15,7 +15,7 @@ public:
virtual bool hasMipmaps() const;
virtual void bind();
- QPixmap pixmap() const { return m_pixmap; }
+ const QPixmap &pixmap() const { return m_pixmap; }
private:
QPixmap m_pixmap;
diff --git a/softwarecontext/softwarecontext.pro b/softwarecontext/softwarecontext.pro
index d884729ffb..dbe948f151 100644
--- a/softwarecontext/softwarecontext.pro
+++ b/softwarecontext/softwarecontext.pro
@@ -14,7 +14,8 @@ SOURCES += \
pixmaptexture.cpp \
glyphnode.cpp \
renderingvisitor.cpp \
- ninepatchnode.cpp
+ ninepatchnode.cpp \
+ softwarelayer.cpp
HEADERS += \
context.h \
@@ -25,7 +26,8 @@ HEADERS += \
pixmaptexture.h \
glyphnode.h \
renderingvisitor.h \
- ninepatchnode.h
+ ninepatchnode.h \
+ softwarelayer.h
OTHER_FILES += softwarecontext.json
diff --git a/softwarecontext/softwarelayer.cpp b/softwarecontext/softwarelayer.cpp
new file mode 100644
index 0000000000..8913f2ec1f
--- /dev/null
+++ b/softwarecontext/softwarelayer.cpp
@@ -0,0 +1,200 @@
+#include "softwarelayer.h"
+
+#include "context.h"
+
+SoftwareLayer::SoftwareLayer(QSGRenderContext *renderContext)
+ : m_item(0)
+ , m_shaderEffectNode(0)
+ , m_context(renderContext)
+ , m_renderer(0)
+ , m_device_pixel_ratio(1)
+ , m_live(true)
+ , m_grab(true)
+ , m_recursive(false)
+ , m_dirtyTexture(true)
+{
+
+}
+
+SoftwareLayer::~SoftwareLayer()
+{
+ invalidated();
+}
+
+int SoftwareLayer::textureId() const
+{
+ return 0;
+}
+
+QSize SoftwareLayer::textureSize() const
+{
+ return m_pixmap.size();
+}
+
+bool SoftwareLayer::hasAlphaChannel() const
+{
+ return m_pixmap.hasAlphaChannel();
+}
+
+bool SoftwareLayer::hasMipmaps() const
+{
+ return false;
+}
+
+void SoftwareLayer::bind()
+{
+}
+
+bool SoftwareLayer::updateTexture()
+{
+ bool doGrab = (m_live || m_grab) && m_dirtyTexture;
+ if (doGrab)
+ grab();
+ if (m_grab)
+ emit scheduledUpdateCompleted();
+ m_grab = false;
+ return doGrab;
+}
+
+void SoftwareLayer::setItem(QSGNode *item)
+{
+ if (item == m_item)
+ return;
+ m_item = item;
+
+ if (m_live && !m_item)
+ m_pixmap = QPixmap();
+
+ markDirtyTexture();
+}
+
+void SoftwareLayer::setShaderEffectNode(QSGNode *node)
+{
+ m_shaderEffectNode = node;
+}
+
+void SoftwareLayer::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ markDirtyTexture();
+}
+
+void SoftwareLayer::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+ m_size = size;
+
+ if (m_live && m_size.isNull())
+ m_pixmap = QPixmap();
+
+ markDirtyTexture();
+}
+
+void SoftwareLayer::scheduleUpdate()
+{
+ if (m_grab)
+ return;
+ m_grab = true;
+ if (m_dirtyTexture) {
+ emit updateRequested();
+ if (m_shaderEffectNode)
+ m_shaderEffectNode->markDirty(QSGNode::DirtyMaterial);
+ }
+}
+
+QImage SoftwareLayer::toImage() const
+{
+ return m_pixmap.toImage();
+}
+
+void SoftwareLayer::setLive(bool live)
+{
+ if (live == m_live)
+ return;
+ m_live = live;
+
+ if (m_live && (!m_item || m_size.isNull()))
+ m_pixmap = QPixmap();
+
+ markDirtyTexture();
+}
+
+void SoftwareLayer::setRecursive(bool recursive)
+{
+ m_recursive = recursive;
+}
+
+void SoftwareLayer::setFormat(GLenum)
+{
+}
+
+void SoftwareLayer::setHasMipmaps(bool)
+{
+}
+
+void SoftwareLayer::setDevicePixelRatio(qreal ratio)
+{
+ m_device_pixel_ratio = ratio;
+}
+
+void SoftwareLayer::markDirtyTexture()
+{
+ m_dirtyTexture = true;
+ if (m_live || m_grab) {
+ emit updateRequested();
+ if (m_shaderEffectNode)
+ m_shaderEffectNode->markDirty(QSGNode::DirtyMaterial);
+ }
+}
+
+void SoftwareLayer::invalidated()
+{
+ delete m_renderer;
+ m_renderer = 0;
+}
+
+void SoftwareLayer::grab()
+{
+ if (!m_item || m_size.isNull()) {
+ m_pixmap = QPixmap();
+ m_dirtyTexture = false;
+ return;
+ }
+ QSGNode *root = m_item;
+ while (root->firstChild() && root->type() != QSGNode::RootNodeType)
+ root = root->firstChild();
+ if (root->type() != QSGNode::RootNodeType)
+ return;
+
+ if (!m_renderer) {
+ m_renderer = new SoftwareContext::PixmapRenderer(m_context);
+ connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()));
+ }
+ m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
+ m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
+
+ if (m_pixmap.size() != m_size)
+ m_pixmap = QPixmap(m_size);
+
+ // Render texture.
+ root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
+ m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update.
+
+ m_dirtyTexture = false;
+
+ m_renderer->setDeviceRect(m_size);
+ m_renderer->setViewportRect(m_size);
+ QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
+ m_renderer->setProjectionMatrixToRect(mirrored);
+ m_renderer->setClearColor(Qt::transparent);
+
+ m_renderer->render(&m_pixmap);
+
+ root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
+
+ if (m_recursive)
+ markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
+}
diff --git a/softwarecontext/softwarelayer.h b/softwarecontext/softwarelayer.h
new file mode 100644
index 0000000000..b584841f87
--- /dev/null
+++ b/softwarecontext/softwarelayer.h
@@ -0,0 +1,67 @@
+#ifndef SOFTWARELAYER_H
+#define SOFTWARELAYER_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgcontext_p.h>
+
+namespace SoftwareContext {
+class PixmapRenderer;
+}
+
+class SoftwareLayer : public QSGLayer
+{
+ Q_OBJECT
+public:
+ SoftwareLayer(QSGRenderContext *renderContext);
+ ~SoftwareLayer();
+
+ const QPixmap &pixmap() const { return m_pixmap; }
+
+ // QSGTexture interface
+public:
+ virtual int textureId() const;
+ virtual QSize textureSize() const;
+ virtual bool hasAlphaChannel() const;
+ virtual bool hasMipmaps() const;
+ virtual void bind();
+
+ // QSGDynamicTexture interface
+public:
+ virtual bool updateTexture();
+
+ // QSGLayer interface
+public:
+ virtual void setItem(QSGNode *item);
+ virtual void setShaderEffectNode(QSGNode *node);
+ virtual void setRect(const QRectF &rect);
+ virtual void setSize(const QSize &size);
+ virtual void scheduleUpdate();
+ virtual QImage toImage() const;
+ virtual void setLive(bool live);
+ virtual void setRecursive(bool recursive);
+ virtual void setFormat(GLenum);
+ virtual void setHasMipmaps(bool);
+ virtual void setDevicePixelRatio(qreal ratio);
+
+public slots:
+ virtual void markDirtyTexture();
+ virtual void invalidated();
+
+private:
+ void grab();
+
+ QSGNode *m_item;
+ QSGNode *m_shaderEffectNode;
+ QSGRenderContext *m_context;
+ SoftwareContext::PixmapRenderer *m_renderer;
+ QRectF m_rect;
+ QSize m_size;
+ QPixmap m_pixmap;
+ qreal m_device_pixel_ratio;
+ bool m_live;
+ bool m_grab;
+ bool m_recursive;
+ bool m_dirtyTexture;
+};
+
+#endif // SOFTWARELAYER_H