summaryrefslogtreecommitdiffstats
path: root/src/declarative/scenegraph/coreapi/renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/scenegraph/coreapi/renderer.cpp')
-rw-r--r--src/declarative/scenegraph/coreapi/renderer.cpp548
1 files changed, 0 insertions, 548 deletions
diff --git a/src/declarative/scenegraph/coreapi/renderer.cpp b/src/declarative/scenegraph/coreapi/renderer.cpp
deleted file mode 100644
index a1da799ba5..0000000000
--- a/src/declarative/scenegraph/coreapi/renderer.cpp
+++ /dev/null
@@ -1,548 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "renderer.h"
-#include "node.h"
-#include "material.h"
-#include "nodeupdater_p.h"
-
-#include "adaptationlayer.h"
-
-#include <QGLShaderProgram>
-#include <qglframebufferobject.h>
-#include <QtGui/qapplication.h>
-
-#include <qdatetime.h>
-
-QT_BEGIN_NAMESPACE
-
-//#define RENDERER_DEBUG
-//#define QT_GL_NO_SCISSOR_TEST
-
-// #define QSG_RENDERER_TIMING
-#ifdef QSG_RENDERER_TIMING
-static QTime frameTimer;
-static int preprocessTime;
-static int updatePassTime;
-static int frameNumber = 0;
-#endif
-
-void Bindable::clear() const
-{
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-}
-
-// Reactivate the color buffer after switching to the stencil.
-void Bindable::reactivate() const
-{
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-}
-
-BindableFbo::BindableFbo(QGLContext *ctx, QGLFramebufferObject *fbo) : m_ctx(ctx), m_fbo(fbo)
-{
-}
-
-
-void BindableFbo::bind() const
-{
- m_fbo->bind();
-}
-
-/*!
- \class Renderer
- \brief The renderer class is the abstract baseclass use for rendering the
- QML scene graph.
-
- The renderer is not tied to any particular surface. It expects a context to
- be current and will render into that surface according to how the device rect,
- viewport rect and projection transformation are set up.
-
- Rendering is a sequence of steps initiated by calling renderScene(). This will
- effectively draw the scene graph starting at the root node. The Node::preprocess()
- function will be called for all the nodes in the graph, followed by an update
- pass which updates all matrices, opacity, clip states and similar in the graph.
- Because the update pass is called after preprocess, it is safe to modify the graph
- during preprocess. To run a custom update pass over the graph, install a custom
- NodeUpdater using setNodeUpdater(). Once all the graphs dirty states are updated,
- the virtual render() function is called.
-
- The render() function is implemented by Renderer subclasses to render the graph
- in the most optimal way for a given hardware.
-
- The renderer can make use of stencil, depth and color buffers in addition to the
- scissor rect.
-
- \internal
- */
-
-
-Renderer::Renderer()
- : QObject()
- , m_clear_color(Qt::transparent)
- , m_root_node(0)
- , m_node_updater(0)
- , m_changed_emitted(false)
- , m_mirrored(false)
- , m_is_rendering(false)
- , m_bindable(0)
-{
- Q_ASSERT(QGLContext::currentContext());
- initializeGLFunctions();
-}
-
-
-Renderer::~Renderer()
-{
- setRootNode(0);
- delete m_node_updater;
-}
-
-
-/*!
- Returns the node updater that this renderer uses to update states in the
- scene graph.
-
- If no updater is specified a default one is constructed.
- */
-
-NodeUpdater *Renderer::nodeUpdater() const
-{
- if (!m_node_updater)
- const_cast<Renderer *>(this)->m_node_updater = new NodeUpdater();
- return m_node_updater;
-}
-
-
-/*!
- Sets the node updater that this renderer uses to update states in the
- scene graph.
-
- This will delete and override any existing node updater
- */
-void Renderer::setNodeUpdater(NodeUpdater *updater)
-{
- if (m_node_updater)
- delete m_node_updater;
- m_node_updater = updater;
-}
-
-
-void Renderer::setRootNode(RootNode *node)
-{
- if (m_root_node == node)
- return;
- if (m_root_node) {
- m_root_node->m_renderers.removeOne(this);
- nodeChanged(m_root_node, Node::DirtyNodeRemoved);
- }
- m_root_node = node;
- if (m_root_node) {
- Q_ASSERT(!m_root_node->m_renderers.contains(this));
- m_root_node->m_renderers << this;
- nodeChanged(m_root_node, Node::DirtyNodeAdded);
- }
-}
-
-
-void Renderer::renderScene()
-{
- class B : public Bindable
- {
- public:
- B() : m_ctx(const_cast<QGLContext *>(QGLContext::currentContext())) { }
- void bind() const { QGLFramebufferObject::bindDefault(); }
- private:
- QGLContext *m_ctx;
- } b;
- renderScene(b);
-}
-
-void Renderer::renderScene(const Bindable &bindable)
-{
- if (!m_root_node)
- return;
-
- m_is_rendering = true;
-#ifdef QSG_RENDERER_TIMING
- frameTimer.start();
-#endif
-
- m_bindable = &bindable;
- preprocess();
-
- bindable.bind();
-#ifdef QSG_RENDERER_TIMING
- int bindTime = frameTimer.elapsed();
-#endif
-
- render();
-#ifdef QSG_RENDERER_TIMING
- int renderTime = frameTimer.elapsed();
-#endif
-
- glDisable(GL_SCISSOR_TEST);
- m_is_rendering = false;
- m_changed_emitted = false;
- m_bindable = 0;
-
-#ifdef QSG_RENDERER_TIMING
- printf("Frame #%d: Breakdown of frametime: preprocess=%d, updates=%d, binding=%d, render=%d, total=%d\n",
- ++frameNumber,
- preprocessTime,
- updatePassTime - preprocessTime,
- bindTime - updatePassTime,
- renderTime - bindTime,
- renderTime);
-#endif
-}
-
-void Renderer::setProjectMatrixToDeviceRect()
-{
- setProjectMatrixToRect(m_device_rect);
-}
-
-void Renderer::setProjectMatrixToRect(const QRectF &rect)
-{
- QMatrix4x4 matrix;
- matrix.ortho(rect.x(),
- rect.x() + rect.width(),
- rect.y() + rect.height(),
- rect.y(),
- qreal(0.01),
- -1);
- setProjectMatrix(matrix);
-}
-
-void Renderer::setProjectMatrix(const QMatrix4x4 &matrix)
-{
- m_projection_matrix = matrix;
- // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
- m_mirrored = matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
-}
-
-void Renderer::setClearColor(const QColor &color)
-{
- m_clear_color = color;
-}
-
-void Renderer::setTexture(int unit, const QSGTextureRef &texture)
-{
- if (unit < 0)
- return;
-
- // Select the texture unit and bind the texture.
- glActiveTexture(GL_TEXTURE0 + unit);
- if (texture.isNull()) {
- glBindTexture(GL_TEXTURE_2D, 0);
- } else {
- glBindTexture(GL_TEXTURE_2D, texture->textureId());
- }
-
- if (unit != 0)
- glActiveTexture(GL_TEXTURE0);
-}
-
-AbstractMaterialShader *Renderer::prepareMaterial(AbstractMaterial *material)
-{
- AbstractMaterialType *type = material->type();
- AbstractMaterialShader *shader = m_materials.value(type);
- if (shader)
- return shader;
-
- shader = material->createShader();
- m_materials[type] = shader;
- return shader;
-}
-
-void Renderer::nodeChanged(Node *node, Node::DirtyFlags flags)
-{
- Q_UNUSED(node);
- Q_UNUSED(flags);
-
- if (flags & Node::DirtyNodeAdded)
- addNodesToPreprocess(node);
- if (flags & Node::DirtyNodeRemoved)
- removeNodesToPreprocess(node);
-
- if (!m_changed_emitted && !m_is_rendering) {
- // Premature overoptimization to avoid excessive signal emissions
- m_changed_emitted = true;
- emit sceneGraphChanged();
- }
-}
-
-void Renderer::materialChanged(GeometryNode *, AbstractMaterial *, AbstractMaterial *)
-{
-}
-
-void Renderer::preprocess()
-{
- Q_ASSERT(m_root_node);
-
- for (QSet<Node *>::const_iterator it = m_nodes_to_preprocess.constBegin();
- it != m_nodes_to_preprocess.constEnd(); ++it) {
- Node *n = *it;
- if (!nodeUpdater()->isNodeBlocked(n, m_root_node)) {
- n->preprocess();
- }
- }
-
-#ifdef QSG_RENDERER_TIMING
- preprocessTime = frameTimer.elapsed();
-#endif
-
- nodeUpdater()->updateStates(m_root_node);
-
-#ifdef QSG_RENDERER_TIMING
- updatePassTime = frameTimer.elapsed();
-#endif
-
-}
-
-void Renderer::addNodesToPreprocess(Node *node)
-{
- for (int i = 0; i < node->childCount(); ++i)
- addNodesToPreprocess(node->childAtIndex(i));
- if (node->flags() & Node::UsePreprocess)
- m_nodes_to_preprocess.insert(node);
-}
-
-void Renderer::removeNodesToPreprocess(Node *node)
-{
- for (int i = 0; i < node->childCount(); ++i)
- removeNodesToPreprocess(node->childAtIndex(i));
- if (node->flags() & Node::UsePreprocess)
- m_nodes_to_preprocess.remove(node);
-}
-
-
-/*!
- Convenience function to set up the stencil buffer for clipping based on \a clip.
-
- If the clip is a pixel aligned rectangle, this function will use glScissor instead
- of stencil.
- */
-
-Renderer::ClipType Renderer::updateStencilClip(const ClipNode *clip)
-{
- if (!clip) {
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_SCISSOR_TEST);
- return NoClip;
- }
-
- bool stencilEnabled = false;
- bool scissorEnabled = false;
-
- glDisable(GL_SCISSOR_TEST);
-
- int clipDepth = 0;
- QRect clipRect;
- while (clip) {
- QMatrix4x4 matrix = m_projectionMatrix.top();
- if (clip->matrix())
- matrix *= *clip->matrix();
-
- const QMatrix4x4 &m = matrix;
-
- // TODO: Check for multisampling and pixel grid alignment.
- bool canUseScissor = clip->isRectangular()
- && qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(0, 2))
- && qFuzzyIsNull(m(1, 0)) && qFuzzyIsNull(m(1, 2));
-
- if (canUseScissor) {
- QRectF bbox = clip->clipRect();
- qreal invW = 1 / m(3, 3);
- qreal fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
- qreal fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
- qreal fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
- qreal fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
-
- GLint ix1 = qRound((fx1 + 1) * m_device_rect.width() * qreal(0.5));
- GLint iy1 = qRound((fy1 + 1) * m_device_rect.height() * qreal(0.5));
- GLint ix2 = qRound((fx2 + 1) * m_device_rect.width() * qreal(0.5));
- GLint iy2 = qRound((fy2 + 1) * m_device_rect.height() * qreal(0.5));
-
- if (!scissorEnabled) {
- clipRect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
- glEnable(GL_SCISSOR_TEST);
- scissorEnabled = true;
- } else {
- clipRect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
- }
-
- clipRect = clipRect.normalized();
- glScissor(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
- } else {
- if (!stencilEnabled) {
- if (!m_clip_program.isLinked()) {
- m_clip_program.addShaderFromSourceCode(QGLShader::Vertex,
- "attribute highp vec4 vCoord; \n"
- "uniform highp mat4 matrix; \n"
- "void main() { \n"
- " gl_Position = matrix * vCoord; \n"
- "}");
- m_clip_program.addShaderFromSourceCode(QGLShader::Fragment,
- "void main() { \n"
- " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw!
- "}");
- m_clip_program.bindAttributeLocation("vCoord", 0);
- m_clip_program.link();
- m_clip_matrix_id = m_clip_program.uniformLocation("matrix");
- }
-
- glStencilMask(0xff); // write mask
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
- glEnable(GL_STENCIL_TEST);
- glDisable(GL_DEPTH_TEST);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glDepthMask(GL_FALSE);
-
- m_clip_program.bind();
- m_clip_program.enableAttributeArray(0);
-
- stencilEnabled = true;
- }
-
- glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
- glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass
-
- const QSGGeometry *geometry = clip->geometry();
- Q_ASSERT(geometry->attributeCount() > 0);
- const QSGGeometry::Attribute *a = geometry->attributes();
-
- glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, geometry->stride(), geometry->vertexData());
-
- m_clip_program.setUniformValue(m_clip_matrix_id, m);
- draw(clip);
-
- ++clipDepth;
- }
-
- clip = clip->clipList();
- }
-
- if (stencilEnabled) {
- m_clip_program.disableAttributeArray(0);
- glEnable(GL_DEPTH_TEST);
- glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass
- glStencilMask(0); // write mask
- bindable()->reactivate();
- //glDepthMask(GL_TRUE); // must be reset correctly by caller.
- } else {
- glDisable(GL_STENCIL_TEST);
- }
-
- if (!scissorEnabled)
- glDisable(GL_SCISSOR_TEST);
-
- return stencilEnabled ? StencilClip : ScissorClip;
-}
-
-
-/*!
- Issues the GL draw call for \a geometryNode.
-
- The function assumes that attributes have been bound and set up prior
- to making this call.
-
- \internal
- */
-
-void Renderer::draw(const BasicGeometryNode *node)
-{
- const QSGGeometry *g = node->geometry();
- if (g->indexCount()) {
- glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
- } else {
- glDrawArrays(g->drawingMode(), 0, g->vertexCount());
- }
-}
-
-
-static inline int size_of_type(GLenum type)
-{
- static int sizes[] = {
- sizeof(char),
- sizeof(unsigned char),
- sizeof(short),
- sizeof(unsigned short),
- sizeof(int),
- sizeof(unsigned int),
- sizeof(float),
- 2,
- 3,
- 4,
- sizeof(double)
- };
- return sizes[type - GL_BYTE];
-}
-
-/*!
- Convenience function to set up and bind the vertex data in \a g to the
- required attribute positions defined in \a material.
-
- \internal
- */
-
-void Renderer::bindGeometry(AbstractMaterialShader *material, const QSGGeometry *g)
-{
- char const *const *attrNames = material->attributeNames();
- int offset = 0;
- for (int j = 0; attrNames[j]; ++j) {
- if (!*attrNames[j])
- continue;
- Q_ASSERT_X(j < g->attributeCount(), "Renderer::bindGeometry()", "Geometry lacks attribute required by material");
- const QSGGeometry::Attribute &a = g->attributes()[j];
- Q_ASSERT_X(j == a.position, "Renderer::bindGeometry()", "Geometry does not have continous attribute positions");
-#if defined(QT_OPENGL_ES_2)
- GLboolean normalize = a.type != GL_FLOAT;
-#else
- GLboolean normalize = a.type != GL_FLOAT && a.type != GL_DOUBLE;
-#endif
- glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->stride(), (char *) g->vertexData() + offset);
- offset += a.tupleSize * size_of_type(a.type);
- }
-}
-
-QT_END_NAMESPACE