diff options
author | Oleg Evseev <ev.mipt@gmail.com> | 2017-04-26 13:03:42 +0300 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2017-05-04 12:34:41 +0000 |
commit | 46e4a33fe90b7ff21baffcb08194ef4c7b346df7 (patch) | |
tree | a143facf8e6ff6daf9be515f9807340d279103fc | |
parent | d8caeb4bbe91f950d645bd339c573ee9d0869737 (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.cpp | 9 | ||||
-rw-r--r-- | src/render/graphicshelpers/graphicscontext.cpp | 36 |
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) |