summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Evseev <ev.mipt@gmail.com>2017-04-26 13:03:42 +0300
committerPaul Lemire <paul.lemire@kdab.com>2017-05-04 12:34:41 +0000
commit46e4a33fe90b7ff21baffcb08194ef4c7b346df7 (patch)
treea143facf8e6ff6daf9be515f9807340d279103fc
parentd8caeb4bbe91f950d645bd339c573ee9d0869737 (diff)
Optimize partial data update support for QBuffer
Now both QBuffer setData/functor and partial data update can be called without unexpected behavior. Optimize applying sequential updates. Change-Id: I5d3a8bcb7eb6eeb3ae33f0fbedbb34acedd1c000 Reviewed-by: Oleg Evseev <ev.mipt@gmail.com> Reviewed-by: Dmitry Volosnykh <dmitry.volosnykh@gmail.com> Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r--src/render/geometry/buffer.cpp9
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp36
2 files changed, 33 insertions, 12 deletions
diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp
index 1133b8e5e..ae5ede731 100644
--- a/src/render/geometry/buffer.cpp
+++ b/src/render/geometry/buffer.cpp
@@ -134,7 +134,14 @@ void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
QByteArray propertyName = propertyChange->propertyName();
if (propertyName == QByteArrayLiteral("data")) {
QByteArray newData = propertyChange->value().value<QByteArray>();
- m_bufferDirty |= m_data != newData;
+ bool dirty = m_data != newData;
+ m_bufferDirty |= dirty;
+ if (dirty) {
+ QBufferUpdate updateNewData;
+ updateNewData.offset = -1;
+ m_bufferUpdates.clear(); //previous updates are pointless
+ m_bufferUpdates.push_back(updateNewData);
+ }
m_data = newData;
} else if (propertyName == QByteArrayLiteral("updateData")) {
Qt3DRender::QBufferUpdate updateData = propertyChange->value().value<Qt3DRender::QBufferUpdate>();
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index 6e585c0a2..65414e220 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -1528,21 +1528,35 @@ void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool rel
// * setData was called changing the whole data or functor (or the usage pattern)
// * partial buffer updates where received
- // Note: we assume the case where both setData/functor and updates are called to be a misuse
- // with unexpected behavior
- const QVector<Qt3DRender::QBufferUpdate> updates = std::move(buffer->pendingBufferUpdates());
- if (!updates.empty()) {
- for (const Qt3DRender::QBufferUpdate &update : updates) {
+ // TO DO: Handle usage pattern
+ QVector<Qt3DRender::QBufferUpdate> updates = std::move(buffer->pendingBufferUpdates());
+ for (auto it = updates.begin(); it != updates.end(); ++it) {
+ auto update = it;
+ if (update->offset >= 0) {
+ //accumulate sequential updates as single one
+ int bufferSize = update->data.size();
+ auto it2 = it + 1;
+ while ((it2 != updates.end())
+ && (it2->offset - update->offset == bufferSize)) {
+ bufferSize += it2->data.size();
+ ++it2;
+ }
+ update->data.resize(bufferSize);
+ while (it + 1 != it2) {
+ ++it;
+ update->data.replace(it->offset - update->offset, it->data.size(), it->data);
+ it->data.clear();
+ }
// TO DO: based on the number of updates .., it might make sense to
// sometime use glMapBuffer rather than glBufferSubData
- b->update(this, update.data.constData(), update.data.size(), update.offset);
+ b->update(this, update->data.constData(), update->data.size(), update->offset);
+ } else {
+ const int bufferSize = buffer->data().size();
+ b->allocate(this, bufferSize, false); // orphan the buffer
+ b->allocate(this, buffer->data().constData(), bufferSize, false);
}
- } else {
- const int bufferSize = buffer->data().size();
- // TO DO: Handle usage pattern
- b->allocate(this, bufferSize, false); // orphan the buffer
- b->allocate(this, buffer->data().constData(), bufferSize, false);
}
+
if (releaseBuffer) {
b->release(this);
if (bufferTypeToGLBufferType(buffer->type()) == GLBuffer::ArrayBuffer)