summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@nokia.com>2010-11-17 14:34:20 +0100
committerYoann Lopes <yoann.lopes@nokia.com>2010-11-17 14:34:20 +0100
commit0938e95cebbd8f9e3f1ba5fe38569e7cb8bf35fb (patch)
tree4d926dc81ac9af2a0e63f98d92b4e0c19049f096
parentaa8de88f52e45ee8caff76398c998fbf04996dea (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.cpp158
-rw-r--r--src/scenegraph/coreapi/geometry.h50
-rw-r--r--src/scenegraph/coreapi/qmlrenderer.cpp71
-rw-r--r--src/scenegraph/coreapi/qmlrenderer.h5
-rw-r--r--src/scenegraph/coreapi/renderer.cpp126
-rw-r--r--src/scenegraph/coreapi/renderer.h37
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(), &currentRenderOrder);
- 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;