diff options
author | Yoann Lopes <yoann.lopes@nokia.com> | 2010-11-17 14:34:20 +0100 |
---|---|---|
committer | Yoann Lopes <yoann.lopes@nokia.com> | 2010-11-17 14:34:20 +0100 |
commit | 0938e95cebbd8f9e3f1ba5fe38569e7cb8bf35fb (patch) | |
tree | 4d926dc81ac9af2a0e63f98d92b4e0c19049f096 | |
parent | aa8de88f52e45ee8caff76398c998fbf04996dea (diff) |
Optimizes geometry data uploading.
Data is now uploaded only once per frame even when having a subtree
rendered separately (ShaderEffectItem).
-rw-r--r-- | src/scenegraph/coreapi/geometry.cpp | 158 | ||||
-rw-r--r-- | src/scenegraph/coreapi/geometry.h | 50 | ||||
-rw-r--r-- | src/scenegraph/coreapi/qmlrenderer.cpp | 71 | ||||
-rw-r--r-- | src/scenegraph/coreapi/qmlrenderer.h | 5 | ||||
-rw-r--r-- | src/scenegraph/coreapi/renderer.cpp | 126 | ||||
-rw-r--r-- | src/scenegraph/coreapi/renderer.h | 37 |
6 files changed, 203 insertions, 244 deletions
diff --git a/src/scenegraph/coreapi/geometry.cpp b/src/scenegraph/coreapi/geometry.cpp index 1e8f735..3f52b34 100644 --- a/src/scenegraph/coreapi/geometry.cpp +++ b/src/scenegraph/coreapi/geometry.cpp @@ -46,27 +46,30 @@ #include <QApplication> Geometry::Geometry() - : m_isVertexDataDirty(false) - , m_isIndexDataDirty(false) - , m_mode(QGL::Triangles) + : m_mode(QGL::Triangles) , m_vertex_stride(0) , m_index_stride(0) { setIndexType(GL_UNSIGNED_SHORT); + GeometryDataUploader::registerGeometry(this); } Geometry::Geometry(const QVector<QGLAttributeDescription> &description, GLenum indexType) - : m_isVertexDataDirty(false) - , m_isIndexDataDirty(false) - , m_mode(QGL::Triangles) + : m_mode(QGL::Triangles) { setIndexType(indexType); setVertexDescription(description); + GeometryDataUploader::registerGeometry(this); +} + +Geometry::~Geometry() +{ + GeometryDataUploader::unregisterGeometry(this); } void *Geometry::vertexData() { - m_isVertexDataDirty = true; + GeometryDataUploader::markVertexDirty(); return m_vertex_data.data(); } @@ -81,7 +84,7 @@ void Geometry::setVertexDescription(const QVector<QGLAttributeDescription> &desc void *Geometry::indexData() { - m_isIndexDataDirty = true; + GeometryDataUploader::markIndexDirty(); return m_index_data.data(); } @@ -96,7 +99,7 @@ void Geometry::setIndexType(GLenum indexType) ushort *Geometry::ushortIndexData() { if (m_index_type == GL_UNSIGNED_SHORT) { - m_isIndexDataDirty = true; + GeometryDataUploader::markIndexDirty(); return reinterpret_cast<ushort *>(indexData()); } return 0; @@ -105,7 +108,7 @@ ushort *Geometry::ushortIndexData() uint *Geometry::uintIndexData() { if (m_index_type == GL_UNSIGNED_INT) { - m_isIndexDataDirty = true; + GeometryDataUploader::markIndexDirty(); return reinterpret_cast<uint *>(indexData()); } return 0; @@ -138,3 +141,138 @@ QGLAttributeValue Geometry::attributeValue(QGL::VertexAttribute attribute) const } return QGLAttributeValue(); } + + +// Copy bigger memory blocks at once +static inline void arraycpy(QArray<uchar> &dest, const QArray<uchar> &src) +{ + int extendSize = src.size(); + int size = dest.size(); + dest.extend(extendSize); + memcpy(dest.data() + size, src.data(), extendSize * sizeof(uchar)); +} + +bool GeometryDataUploader::m_use_buffers = true; +QSet<const Geometry *> GeometryDataUploader::m_geometries; +QGLBuffer GeometryDataUploader::m_vertex_buffer(QGLBuffer::VertexBuffer); +QGLBuffer GeometryDataUploader::m_index_buffer(QGLBuffer::IndexBuffer); +QArray<uchar> GeometryDataUploader::m_vertex_data; +QArray<uchar> GeometryDataUploader::m_index_data; +QHash<const Geometry *, int> GeometryDataUploader::m_vertex_offsets; +QHash<const Geometry *, int> GeometryDataUploader::m_index_offsets; +bool GeometryDataUploader::m_vertex_bound = false; +bool GeometryDataUploader::m_index_bound = false; +bool GeometryDataUploader::m_vertex_dirty = false; +bool GeometryDataUploader::m_index_dirty = false; + +void GeometryDataUploader::registerGeometry(const Geometry *g) +{ + if (!m_use_buffers) + return; + + m_geometries.insert(g); +} + +void GeometryDataUploader::unregisterGeometry(const Geometry *g) +{ + if (!m_use_buffers) + return; + + m_geometries.remove(g); +} + +void GeometryDataUploader::addGeometryVertex(const Geometry *g) +{ + if (!m_use_buffers || g->vertexCount() == 0) + return; + + const QArray<uchar> &vertexData = g->vertexArray(); + m_vertex_offsets.insert(g, m_vertex_data.count()); + arraycpy(m_vertex_data, vertexData); +} + +void GeometryDataUploader::addGeometryIndex(const Geometry *g) +{ + if (!m_use_buffers || g->indexCount() == 0) + return; + + if (g->indexCount()) { + const QArray<uchar> &indexData = g->indexArray(); + m_index_offsets.insert(g, m_index_data.count()); + arraycpy(m_index_data, indexData); + } +} + +void GeometryDataUploader::bind() +{ + if (!m_use_buffers) + return; + + if (!m_vertex_buffer.isCreated()) + m_vertex_buffer.create(); + if (!m_index_buffer.isCreated()) + m_index_buffer.create(); + + if (!m_vertex_bound) + m_vertex_bound = m_vertex_buffer.bind(); + if (!m_index_bound) + m_index_bound = m_index_buffer.bind(); +} + +void GeometryDataUploader::release() +{ + if (!m_use_buffers) + return; + + if (m_vertex_bound) + m_vertex_buffer.release(); + if (m_index_bound) + m_index_buffer.release(); + m_vertex_bound = false; + m_index_bound = false; +} + +void GeometryDataUploader::upload() +{ + if (!m_use_buffers || (!m_vertex_dirty && !m_index_dirty)) + return; + + bind(); + + if (m_vertex_dirty) + clearVertexData(); + if (m_index_dirty) + clearIndexData(); + + QSet<const Geometry *>::const_iterator i; + for (i = m_geometries.begin(); i != m_geometries.end(); ++i) { + if (m_vertex_dirty) + addGeometryVertex(*i); + if (m_index_dirty) + addGeometryIndex(*i); + } + + if (!m_vertex_data.isEmpty() && m_vertex_dirty) + m_vertex_buffer.allocate(m_vertex_data.data(), m_vertex_data.size()); + if (!m_index_data.isEmpty() && m_index_dirty) + m_index_buffer.allocate(m_index_data.data(), m_index_data.size()); + + m_vertex_dirty = false; + m_index_dirty = false; +} + +const void *GeometryDataUploader::vertexData(const Geometry *g, int offset) +{ + if (m_use_buffers) + return reinterpret_cast<const void *>(m_vertex_offsets.value(g) + offset); + else + return reinterpret_cast<const void *>(g->vertexArray().constData() + offset); +} + +const void *GeometryDataUploader::indexData(const Geometry *g) +{ + if (m_use_buffers) + return reinterpret_cast<const void *>(m_index_offsets.value(g)); + else + return g->constIndexData(); +} diff --git a/src/scenegraph/coreapi/geometry.h b/src/scenegraph/coreapi/geometry.h index 8a9e0b3..a6f3028 100644 --- a/src/scenegraph/coreapi/geometry.h +++ b/src/scenegraph/coreapi/geometry.h @@ -55,6 +55,7 @@ class Geometry public: Geometry(); // Creates a null geometry. Geometry(const QVector<QGLAttributeDescription> &description, GLenum indexType = GL_UNSIGNED_SHORT); + ~Geometry(); void *vertexData(); const void *constVertexData() const { return m_vertex_data.constData(); } @@ -103,15 +104,7 @@ public: bool isNull() const { return m_vertex_description.isEmpty(); } - bool isVertexDataDirty() const { return m_isVertexDataDirty; } - void setVertexDataDirty(bool d) { m_isVertexDataDirty = d; } - bool isIndexDataDirty() const { return m_isIndexDataDirty; } - void setIndexDataDirty(bool d) { m_isIndexDataDirty = d; } - protected: - bool m_isVertexDataDirty; - bool m_isIndexDataDirty; - QArray<uchar> m_vertex_data; QArray<uchar> m_index_data; @@ -122,4 +115,45 @@ protected: int m_index_stride; }; +class GeometryDataUploader +{ +public: + static void registerGeometry(const Geometry *); + static void unregisterGeometry(const Geometry *); + + static void bind(); + static void release(); + static void upload(); + + static const void *vertexData(const Geometry *g, int offset = 0); + static const void *indexData(const Geometry *g); + + static void setUseBuffers(bool b) { m_use_buffers = b; } + static bool useBuffers() { return m_use_buffers; } + + static void markVertexDirty() { m_vertex_dirty = true; } + static void markIndexDirty() { m_index_dirty = true; } + +private: + static void addGeometryVertex(const Geometry *); + static void addGeometryIndex(const Geometry *); + + static void clearVertexData() { m_vertex_offsets.clear(); m_vertex_data.clear(); } + static void clearIndexData() { m_index_offsets.clear(); m_index_data.clear(); } + + static bool m_use_buffers; + static QSet<const Geometry *> m_geometries; + static QGLBuffer m_vertex_buffer; + static QGLBuffer m_index_buffer; + static QArray<uchar> m_vertex_data; + static QArray<uchar> m_index_data; + static QHash<const Geometry *, int> m_vertex_offsets; + static QHash<const Geometry *, int> m_index_offsets; + static bool m_vertex_bound; + static bool m_index_bound; + static bool m_vertex_dirty; + static bool m_index_dirty; +}; + + #endif diff --git a/src/scenegraph/coreapi/qmlrenderer.cpp b/src/scenegraph/coreapi/qmlrenderer.cpp index ceea599..ee991c6 100644 --- a/src/scenegraph/coreapi/qmlrenderer.cpp +++ b/src/scenegraph/coreapi/qmlrenderer.cpp @@ -119,14 +119,14 @@ T Heap<T, prealloc>::pop() QMLRenderer::QMLRenderer() - : m_dirtyVertexData(false) - , m_dirtyIndexData(false) + : Renderer() { -#if defined(QML_RUNTIME_TESTING) QStringList args = qApp->arguments(); +#if defined(QML_RUNTIME_TESTING) m_render_opaque_nodes = !args.contains("--no-opaque-nodes"); m_render_alpha_nodes = !args.contains("--no-alpha-nodes"); #endif + GeometryDataUploader::setUseBuffers(!args.contains("--no-vbo")); } void QMLRenderer::render() @@ -177,9 +177,6 @@ void QMLRenderer::render() int currentRenderOrder = 0; buildLists(rootNode(), ¤tRenderOrder); - if (m_geometry_uploader.useBuffers()) - uploadNodeData(); - ++currentRenderOrder; m_renderOrderMatrix.setToIdentity(); m_renderOrderMatrix.scale(1, 1, qreal(1) / currentRenderOrder); @@ -203,8 +200,6 @@ void QMLRenderer::render() m_currentProgram->deactivate(); m_projectionMatrix.pop(); - - m_geometry_uploader.release(); } class Foo : public QPair<int, GeometryNode *> @@ -244,17 +239,6 @@ void QMLRenderer::buildLists(Node *node, int *currentRenderOrder) m_clipNodes.append(clipNode); } - if (g && m_geometry_uploader.useBuffers()) { - if (g->isVertexDataDirty() || !m_geometry_uploader.containsGeometryVertex(g)) { - m_dirtyVertexData = true; - g->setVertexDataDirty(false); - } - if (g->isIndexDataDirty() || (g->indexCount() && !m_geometry_uploader.containsGeometryIndex(g))) { - m_dirtyIndexData = true; - g->setIndexDataDirty(false); - } - } - int count = node->childCount(); if (!count) return; @@ -298,51 +282,6 @@ void QMLRenderer::buildLists(Node *node, int *currentRenderOrder) } } -void QMLRenderer::uploadNodeData() -{ - m_geometry_uploader.bind(); - - if (!m_dirtyVertexData && !m_dirtyIndexData) - return; - - if (m_dirtyVertexData) - m_geometry_uploader.clearVertexData(); - if (m_dirtyIndexData) - m_geometry_uploader.clearIndexData(); - - int count = m_opaqueNodes.count(); - for (int i = 0; i < count; ++i) { - GeometryNode *geomNode = m_opaqueNodes.at(i); - if (m_dirtyVertexData) - m_geometry_uploader.addGeometryVertex(geomNode->geometry()); - if (m_dirtyIndexData) - m_geometry_uploader.addGeometryIndex(geomNode->geometry()); - } - - count = m_transparentNodes.count(); - for (int i = 0; i < count; ++i) { - GeometryNode *geomNode = m_transparentNodes.at(i); - if (m_dirtyVertexData) - m_geometry_uploader.addGeometryVertex(geomNode->geometry()); - if (m_dirtyIndexData) - m_geometry_uploader.addGeometryIndex(geomNode->geometry()); - } - - count = m_clipNodes.count(); - for (int i = 0; i < count; ++i) { - ClipNode *clipNode = m_clipNodes.at(i); - if (m_dirtyVertexData) - m_geometry_uploader.addGeometryVertex(clipNode->geometry()); - if (m_dirtyIndexData) - m_geometry_uploader.addGeometryIndex(clipNode->geometry()); - } - - m_geometry_uploader.upload(); - - m_dirtyVertexData = false; - m_dirtyIndexData = false; -} - void QMLRenderer::renderNodes(const QVector<GeometryNode *> &list, int renderOrders) { const float scale = 1.0f / renderOrders; @@ -422,7 +361,7 @@ void QMLRenderer::renderNodes(const QVector<GeometryNode *> &list, int renderOrd GLboolean normalize = attr.type() != GL_FLOAT && attr.type() != GL_DOUBLE; #endif glVertexAttribPointer(*attributes, attr.tupleSize(), attr.type(), normalize, attr.stride(), - m_geometry_uploader.vertexData(g, offset)); + GeometryDataUploader::vertexData(g, offset)); offset += attr.tupleSize() * attr.sizeOfType(); } else { qWarning("Attribute required by effect is missing."); @@ -432,7 +371,7 @@ void QMLRenderer::renderNodes(const QVector<GeometryNode *> &list, int renderOrd QPair<int, int> indexRange = geomNode->indexRange(); if (g->indexCount()) glDrawElements(GLenum(g->drawingMode()), indexRange.second - indexRange.first, g->indexType(), - m_geometry_uploader.indexData(g)); + GeometryDataUploader::indexData(g)); else glDrawArrays(GLenum(g->drawingMode()), indexRange.first, indexRange.second - indexRange.first); } diff --git a/src/scenegraph/coreapi/qmlrenderer.h b/src/scenegraph/coreapi/qmlrenderer.h index c0b7947..f8ef8ca 100644 --- a/src/scenegraph/coreapi/qmlrenderer.h +++ b/src/scenegraph/coreapi/qmlrenderer.h @@ -46,6 +46,7 @@ class QMLRenderer : public Renderer { + Q_OBJECT public: QMLRenderer(); @@ -55,7 +56,6 @@ public: private: void buildLists(Node *node, int *currentRenderOrder); - void uploadNodeData(); void renderNodes(const QVector <GeometryNode *> &list, int renderOrders); const ClipNode *m_currentClip; @@ -68,9 +68,6 @@ private: QVector<ClipNode *> m_clipNodes; QVector<GeometryNode *> m_tempNodes; - bool m_dirtyVertexData; - bool m_dirtyIndexData; - #ifdef QML_RUNTIME_TESTING bool m_render_opaque_nodes; bool m_render_alpha_nodes; diff --git a/src/scenegraph/coreapi/renderer.cpp b/src/scenegraph/coreapi/renderer.cpp index 53310ea..facfc71 100644 --- a/src/scenegraph/coreapi/renderer.cpp +++ b/src/scenegraph/coreapi/renderer.cpp @@ -62,125 +62,10 @@ void BindableFbo::bind() const m_fbo->bind(); } -// Copy bigger memory blocks at once -static inline void arraycpy(QArray<uchar> &dest, const QArray<uchar> &src) -{ - int extendSize = src.size(); - int size = dest.size(); - dest.extend(extendSize); - memcpy(dest.data() + size, src.data(), extendSize * sizeof(uchar)); -} - - -GeometryDataUploader::GeometryDataUploader() - : m_use_buffers(!qApp->arguments().contains("--no-vbo")) - , m_vertex_buffer(QGLBuffer::VertexBuffer) - , m_index_buffer(QGLBuffer::IndexBuffer) - , m_vertex_bound(false) - , m_index_bound(false) -{ -} - -void GeometryDataUploader::addGeometryVertex(const Geometry *g) -{ - if (!m_use_buffers) - return; - - const QArray<uchar> &vertexData = g->vertexArray(); - m_vertex_offsets.insert(g, m_vertex_data.count()); - arraycpy(m_vertex_data, vertexData); -} - -void GeometryDataUploader::addGeometryIndex(const Geometry *g) -{ - if (!m_use_buffers) - return; - - if (g->indexCount()) { - const QArray<uchar> &indexData = g->indexArray(); - m_index_offsets.insert(g, m_index_data.count()); - arraycpy(m_index_data, indexData); - } -} - -bool GeometryDataUploader::containsGeometryVertex(const Geometry *g) -{ - if (!m_use_buffers) - return true; - - return m_vertex_offsets.contains(g); -} - -bool GeometryDataUploader::containsGeometryIndex(const Geometry *g) -{ - if (!m_use_buffers) - return true; - - return m_index_offsets.contains(g); -} - -void GeometryDataUploader::bind() -{ - if (!m_use_buffers) - return; - - if (!m_vertex_buffer.isCreated()) - m_vertex_buffer.create(); - if (!m_index_buffer.isCreated()) - m_index_buffer.create(); - - if (!m_vertex_bound) - m_vertex_bound = m_vertex_buffer.bind(); - if (!m_index_bound) - m_index_bound = m_index_buffer.bind(); -} - -void GeometryDataUploader::release() -{ - if (!m_use_buffers) - return; - - if (m_vertex_bound) - m_vertex_buffer.release(); - if (m_index_bound) - m_index_buffer.release(); - m_vertex_bound = false; - m_index_bound = false; -} - -void GeometryDataUploader::upload() -{ - if (!m_use_buffers) - return; - - bind(); - - if (!m_vertex_data.isEmpty()) - m_vertex_buffer.allocate(m_vertex_data.data(), m_vertex_data.size()); - - if (!m_index_data.isEmpty()) - m_index_buffer.allocate(m_index_data.data(), m_index_data.size()); -} - -const void *GeometryDataUploader::vertexData(const Geometry *g, int offset) -{ - if (m_use_buffers) - return reinterpret_cast<const void *>(m_vertex_offsets.value(g) + offset); - else - return reinterpret_cast<const void *>(g->vertexArray().constData() + offset); -} - -const void *GeometryDataUploader::indexData(const Geometry *g) -{ - if (m_use_buffers) - return reinterpret_cast<const void *>(m_index_offsets.value(g)); - else - return g->constIndexData(); -} - Renderer::Renderer() - : m_clear_color(Qt::transparent) + : QObject() + , m_clear_color(Qt::transparent) , m_root_node(0) , m_changed_emitted(false) { @@ -229,7 +114,10 @@ void Renderer::renderScene(const Bindable &bindable) preprocess(); bindable.bind(); + GeometryDataUploader::bind(); + GeometryDataUploader::upload(); render(); + GeometryDataUploader::release(); m_changed_emitted = false; } @@ -445,14 +333,14 @@ Renderer::ClipType Renderer::updateStencilClip(const ClipNode *clip) const QGLAttributeValue &v = geometry->attributeValue(QGL::Position); glVertexAttribPointer(QGL::Position, v.tupleSize(), v.type(), GL_FALSE, v.stride(), - m_geometry_uploader.vertexData(geometry)); + GeometryDataUploader::vertexData(geometry)); m_clip_program.setUniformValue(m_clip_matrix_id, m); QPair<int, int> range = clip->indexRange(); if (geometry->indexCount()) { glDrawElements(GLenum(geometry->drawingMode()), range.second - range.first, geometry->indexType() - , m_geometry_uploader.indexData(geometry)); + , GeometryDataUploader::indexData(geometry)); } else { glDrawArrays(GLenum(geometry->drawingMode()), range.first, range.second - range.first); } diff --git a/src/scenegraph/coreapi/renderer.h b/src/scenegraph/coreapi/renderer.h index d408a5a..bf0343e 100644 --- a/src/scenegraph/coreapi/renderer.h +++ b/src/scenegraph/coreapi/renderer.h @@ -76,41 +76,6 @@ private: QGLFramebufferObject *m_fbo; }; -class GeometryDataUploader -{ -public: - GeometryDataUploader(); - - void addGeometryVertex(const Geometry *); - void addGeometryIndex(const Geometry *); - - bool containsGeometryVertex(const Geometry *); - bool containsGeometryIndex(const Geometry *); - - void bind(); - void release(); - void upload(); - - const void *vertexData(const Geometry *g, int offset = 0); - const void *indexData(const Geometry *g); - - void clearVertexData() { m_vertex_offsets.clear(); m_vertex_data.clear(); } - void clearIndexData() { m_index_offsets.clear(); m_index_data.clear(); } - - bool useBuffers() const { return m_use_buffers; } - -private: - bool m_use_buffers; - - QGLBuffer m_vertex_buffer; - QGLBuffer m_index_buffer; - QArray<uchar> m_vertex_data; - QArray<uchar> m_index_data; - QHash<const Geometry *, int> m_vertex_offsets; - QHash<const Geometry *, int> m_index_offsets; - bool m_vertex_bound; - bool m_index_bound; -}; class Renderer : public QObject, protected QGLFunctions { @@ -186,8 +151,6 @@ protected: QMatrix4x4Stack m_projectionMatrix; QMatrix4x4Stack m_modelViewMatrix; - GeometryDataUploader m_geometry_uploader; - private: RootNode *m_root_node; QRect m_device_rect; |