Use different buffer for indices and vertices only in the WebGL plugin

This patch partially reverts 098ba08653.
Only QtWebGL will use separate buffers for indices and vertices. This
patch gives a performance boost.

Task-number: QTBUG-66191
Task-number: QTBUG-67147
Change-Id: I58b4db2bdf44cd954390e85e079de82031caf9e5
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Jesus Fernandez 2018-02-05 17:20:08 +01:00 committed by Jesus Fernandez
parent 03739f2150
commit 5cc8db797a
5 changed files with 54 additions and 89 deletions

View File

@ -775,9 +775,7 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx)
, m_currentClip(nullptr) , m_currentClip(nullptr)
, m_currentClipType(NoClip) , m_currentClipType(NoClip)
, m_vertexUploadPool(256) , m_vertexUploadPool(256)
#ifdef QSG_SEPARATE_INDEX_BUFFER
, m_indexUploadPool(64) , m_indexUploadPool(64)
#endif
, m_vao(nullptr) , m_vao(nullptr)
, m_visualizeMode(VisualizeNothing) , m_visualizeMode(VisualizeNothing)
{ {
@ -834,12 +832,11 @@ static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs)
free(buffer->data); free(buffer->data);
} }
static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs) static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs, bool separateIndexBuffer)
{ {
qsg_wipeBuffer(&batch->vbo, funcs); qsg_wipeBuffer(&batch->vbo, funcs);
#ifdef QSG_SEPARATE_INDEX_BUFFER if (separateIndexBuffer)
qsg_wipeBuffer(&batch->ibo, funcs); qsg_wipeBuffer(&batch->ibo, funcs);
#endif
delete batch; delete batch;
} }
@ -847,9 +844,13 @@ Renderer::~Renderer()
{ {
if (QOpenGLContext::currentContext()) { if (QOpenGLContext::currentContext()) {
// Clean up batches and buffers // Clean up batches and buffers
for (int i=0; i<m_opaqueBatches.size(); ++i) qsg_wipeBatch(m_opaqueBatches.at(i), this); const bool separateIndexBuffer = m_context->separateIndexBuffer();
for (int i=0; i<m_alphaBatches.size(); ++i) qsg_wipeBatch(m_alphaBatches.at(i), this); for (int i = 0; i < m_opaqueBatches.size(); ++i)
for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this); qsg_wipeBatch(m_opaqueBatches.at(i), this, separateIndexBuffer);
for (int i = 0; i < m_alphaBatches.size(); ++i)
qsg_wipeBatch(m_alphaBatches.at(i), this, separateIndexBuffer);
for (int i = 0; i < m_batchPool.size(); ++i)
qsg_wipeBatch(m_batchPool.at(i), this, separateIndexBuffer);
} }
for (Node *n : qAsConst(m_nodes)) for (Node *n : qAsConst(m_nodes))
@ -889,13 +890,8 @@ void Renderer::map(Buffer *buffer, int byteSize, bool isIndexBuf)
if (!m_context->hasBrokenIndexBufferObjects() && m_visualizeMode == VisualizeNothing) { if (!m_context->hasBrokenIndexBufferObjects() && m_visualizeMode == VisualizeNothing) {
// Common case, use a shared memory pool for uploading vertex data to avoid // Common case, use a shared memory pool for uploading vertex data to avoid
// excessive reevaluation // excessive reevaluation
QDataBuffer<char> &pool = QDataBuffer<char> &pool = m_context->separateIndexBuffer() && isIndexBuf
#ifdef QSG_SEPARATE_INDEX_BUFFER ? m_indexUploadPool : m_vertexUploadPool;
isIndexBuf ? m_indexUploadPool : m_vertexUploadPool;
#else
m_vertexUploadPool;
Q_UNUSED(isIndexBuf);
#endif
if (byteSize > pool.size()) if (byteSize > pool.size())
pool.resize(byteSize); pool.resize(byteSize);
buffer->data = pool.data(); buffer->data = pool.data();
@ -1864,11 +1860,11 @@ void Renderer::uploadBatch(Batch *b)
ibufferSize = unmergedIndexSize; ibufferSize = unmergedIndexSize;
} }
#ifdef QSG_SEPARATE_INDEX_BUFFER const bool separateIndexBuffer = m_context->separateIndexBuffer();
map(&b->ibo, ibufferSize, true); if (separateIndexBuffer)
#else map(&b->ibo, ibufferSize, true);
bufferSize += ibufferSize; else
#endif bufferSize += ibufferSize;
map(&b->vbo, bufferSize); map(&b->vbo, bufferSize);
if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:" if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:"
@ -1878,22 +1874,17 @@ void Renderer::uploadBatch(Batch *b)
if (b->merged) { if (b->merged) {
char *vertexData = b->vbo.data; char *vertexData = b->vbo.data;
char *zData = vertexData + b->vertexCount * g->sizeOfVertex(); char *zData = vertexData + b->vertexCount * g->sizeOfVertex();
#ifdef QSG_SEPARATE_INDEX_BUFFER char *indexData = separateIndexBuffer
char *indexData = b->ibo.data; ? b->ibo.data
#else : zData + (int(m_useDepthBuffer) * b->vertexCount * sizeof(float));
char *indexData = zData + (m_useDepthBuffer ? b->vertexCount * sizeof(float) : 0);
#endif
quint16 iOffset = 0; quint16 iOffset = 0;
e = b->first; e = b->first;
int verticesInSet = 0; int verticesInSet = 0;
int indicesInSet = 0; int indicesInSet = 0;
b->drawSets.reset(); b->drawSets.reset();
#ifdef QSG_SEPARATE_INDEX_BUFFER int drawSetIndices = separateIndexBuffer ? 0 : indexData - vertexData;
int drawSetIndices = 0; const auto indexBase = separateIndexBuffer ? b->ibo.data : b->vbo.data;
#else
int drawSetIndices = indexData - vertexData;
#endif
b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices); b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices);
while (e) { while (e) {
verticesInSet += e->node->geometry()->vertexCount(); verticesInSet += e->node->geometry()->vertexCount();
@ -1903,11 +1894,7 @@ void Renderer::uploadBatch(Batch *b)
b->drawSets.last().indices += 1 * sizeof(quint16); b->drawSets.last().indices += 1 * sizeof(quint16);
b->drawSets.last().indexCount -= 2; b->drawSets.last().indexCount -= 2;
} }
#ifdef QSG_SEPARATE_INDEX_BUFFER drawSetIndices = indexData - indexBase;
drawSetIndices = indexData - b->ibo.data;
#else
drawSetIndices = indexData - b->vbo.data;
#endif
b->drawSets << DrawSet(vertexData - b->vbo.data, b->drawSets << DrawSet(vertexData - b->vbo.data,
zData - b->vbo.data, zData - b->vbo.data,
drawSetIndices); drawSetIndices);
@ -1927,11 +1914,8 @@ void Renderer::uploadBatch(Batch *b)
} }
} else { } else {
char *vboData = b->vbo.data; char *vboData = b->vbo.data;
#ifdef QSG_SEPARATE_INDEX_BUFFER char *iboData = separateIndexBuffer ? b->ibo.data
char *iboData = b->ibo.data; : vboData + b->vertexCount * g->sizeOfVertex();
#else
char *iboData = vboData + b->vertexCount * g->sizeOfVertex();
#endif
Element *e = b->first; Element *e = b->first;
while (e) { while (e) {
QSGGeometry *g = e->node->geometry(); QSGGeometry *g = e->node->geometry();
@ -1979,12 +1963,9 @@ void Renderer::uploadBatch(Batch *b)
} }
if (!b->drawSets.isEmpty()) { if (!b->drawSets.isEmpty()) {
const quint16 *id = const quint16 *id = (const quint16 *)(separateIndexBuffer
# ifdef QSG_SEPARATE_INDEX_BUFFER ? b->ibo.data
(const quint16 *) (b->ibo.data); : b->vbo.data + b->drawSets.at(0).indices);
# else
(const quint16 *) (b->vbo.data + b->drawSets.at(0).indices);
# endif
{ {
QDebug iDump = qDebug(); QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount; iDump << " -- Index Data, count:" << b->indexCount;
@ -2004,9 +1985,8 @@ void Renderer::uploadBatch(Batch *b)
#endif // QT_NO_DEBUG_OUTPUT #endif // QT_NO_DEBUG_OUTPUT
unmap(&b->vbo); unmap(&b->vbo);
#ifdef QSG_SEPARATE_INDEX_BUFFER if (separateIndexBuffer)
unmap(&b->ibo, true); unmap(&b->ibo, true);
#endif
if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed..."; if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed...";
@ -2299,11 +2279,7 @@ void Renderer::renderMergedBatch(const Batch *batch)
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
char *indexBase = nullptr; char *indexBase = nullptr;
#ifdef QSG_SEPARATE_INDEX_BUFFER const Buffer *indexBuf = m_context->separateIndexBuffer() ? &batch->ibo : &batch->vbo;
const Buffer *indexBuf = &batch->ibo;
#else
const Buffer *indexBuf = &batch->vbo;
#endif
if (m_context->hasBrokenIndexBufferObjects()) { if (m_context->hasBrokenIndexBufferObjects()) {
indexBase = indexBuf->data; indexBase = indexBuf->data;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@ -2395,11 +2371,8 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
char *indexBase = nullptr; char *indexBase = nullptr;
#ifdef QSG_SEPARATE_INDEX_BUFFER const auto separateIndexBuffer = m_context->separateIndexBuffer();
const Buffer *indexBuf = &batch->ibo; const Buffer *indexBuf = separateIndexBuffer ? &batch->ibo : &batch->vbo;
#else
const Buffer *indexBuf = &batch->vbo;
#endif
if (batch->indexCount) { if (batch->indexCount) {
if (m_context->hasBrokenIndexBufferObjects()) { if (m_context->hasBrokenIndexBufferObjects()) {
indexBase = indexBuf->data; indexBase = indexBuf->data;
@ -2428,11 +2401,9 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
} }
int vOffset = 0; int vOffset = 0;
#ifdef QSG_SEPARATE_INDEX_BUFFER
char *iOffset = indexBase; char *iOffset = indexBase;
#else if (!separateIndexBuffer)
char *iOffset = indexBase + batch->vertexCount * gn->geometry()->sizeOfVertex(); iOffset += batch->vertexCount * gn->geometry()->sizeOfVertex();
#endif
QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4(); QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4();
@ -2735,17 +2706,13 @@ void Renderer::render()
if (Q_UNLIKELY(debug_render())) timeSorting = timer.restart(); if (Q_UNLIKELY(debug_render())) timeSorting = timer.restart();
int largestVBO = 0; int largestVBO = 0;
#ifdef QSG_SEPARATE_INDEX_BUFFER
int largestIBO = 0; int largestIBO = 0;
#endif
if (Q_UNLIKELY(debug_upload())) qDebug("Uploading Opaque Batches:"); if (Q_UNLIKELY(debug_upload())) qDebug("Uploading Opaque Batches:");
for (int i=0; i<m_opaqueBatches.size(); ++i) { for (int i=0; i<m_opaqueBatches.size(); ++i) {
Batch *b = m_opaqueBatches.at(i); Batch *b = m_opaqueBatches.at(i);
largestVBO = qMax(b->vbo.size, largestVBO); largestVBO = qMax(b->vbo.size, largestVBO);
#ifdef QSG_SEPARATE_INDEX_BUFFER
largestIBO = qMax(b->ibo.size, largestIBO); largestIBO = qMax(b->ibo.size, largestIBO);
#endif
uploadBatch(b); uploadBatch(b);
} }
if (Q_UNLIKELY(debug_render())) timeUploadOpaque = timer.restart(); if (Q_UNLIKELY(debug_render())) timeUploadOpaque = timer.restart();
@ -2756,18 +2723,14 @@ void Renderer::render()
Batch *b = m_alphaBatches.at(i); Batch *b = m_alphaBatches.at(i);
uploadBatch(b); uploadBatch(b);
largestVBO = qMax(b->vbo.size, largestVBO); largestVBO = qMax(b->vbo.size, largestVBO);
#ifdef QSG_SEPARATE_INDEX_BUFFER
largestIBO = qMax(b->ibo.size, largestIBO); largestIBO = qMax(b->ibo.size, largestIBO);
#endif
} }
if (Q_UNLIKELY(debug_render())) timeUploadAlpha = timer.restart(); if (Q_UNLIKELY(debug_render())) timeUploadAlpha = timer.restart();
if (largestVBO * 2 < m_vertexUploadPool.size()) if (largestVBO * 2 < m_vertexUploadPool.size())
m_vertexUploadPool.resize(largestVBO * 2); m_vertexUploadPool.resize(largestVBO * 2);
#ifdef QSG_SEPARATE_INDEX_BUFFER if (m_context->separateIndexBuffer() && largestIBO * 2 < m_indexUploadPool.size())
if (largestIBO * 2 < m_indexUploadPool.size())
m_indexUploadPool.resize(largestIBO * 2); m_indexUploadPool.resize(largestIBO * 2);
#endif
renderBatches(); renderBatches();
@ -2978,14 +2941,12 @@ void Renderer::visualizeBatch(Batch *b)
if (b->merged) { if (b->merged) {
shader->setUniformValue(shader->matrix, matrix); shader->setUniformValue(shader->matrix, matrix);
const auto &dataStart = m_context->separateIndexBuffer() ? b->ibo.data : b->vbo.data;
for (int ds=0; ds<b->drawSets.size(); ++ds) { for (int ds=0; ds<b->drawSets.size(); ++ds) {
const DrawSet &set = b->drawSets.at(ds); const DrawSet &set = b->drawSets.at(ds);
glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(), (void *) (qintptr) (set.vertices)); glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(), (void *) (qintptr) (set.vertices));
#ifdef QSG_SEPARATE_INDEX_BUFFER glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT,
glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (b->ibo.data + set.indices)); (void *)(qintptr)(dataStart + set.indices));
#else
glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (b->vbo.data + set.indices));
#endif
} }
} else { } else {
Element *e = b->first; Element *e = b->first;

View File

@ -433,9 +433,7 @@ struct Batch
mutable uint uploadedThisFrame : 1; // solely for debugging purposes mutable uint uploadedThisFrame : 1; // solely for debugging purposes
Buffer vbo; Buffer vbo;
#ifdef QSG_SEPARATE_INDEX_BUFFER
Buffer ibo; Buffer ibo;
#endif
QDataBuffer<DrawSet> drawSets; QDataBuffer<DrawSet> drawSets;
}; };
@ -738,9 +736,7 @@ private:
ClipType m_currentClipType; ClipType m_currentClipType;
QDataBuffer<char> m_vertexUploadPool; QDataBuffer<char> m_vertexUploadPool;
#ifdef QSG_SEPARATE_INDEX_BUFFER
QDataBuffer<char> m_indexUploadPool; QDataBuffer<char> m_indexUploadPool;
#endif
// For minimal OpenGL core profile support // For minimal OpenGL core profile support
QOpenGLVertexArrayObject *m_vao; QOpenGLVertexArrayObject *m_vao;
@ -760,10 +756,8 @@ Batch *Renderer::newBatch()
m_batchPool.resize(size - 1); m_batchPool.resize(size - 1);
} else { } else {
b = new Batch(); b = new Batch();
memset(&b->vbo, 0, sizeof(Buffer)); Q_ASSERT(offsetof(Batch, ibo) == sizeof(Buffer) + offsetof(Batch, vbo));
#ifdef QSG_SEPARATE_INDEX_BUFFER memset(&b->vbo, 0, sizeof(Buffer) * 2); // Clear VBO & IBO
memset(&b->ibo, 0, sizeof(Buffer));
#endif
} }
b->init(); b->init();
return b; return b;

View File

@ -39,6 +39,7 @@
#include "qsgdefaultrendercontext_p.h" #include "qsgdefaultrendercontext_p.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLFramebufferObject> #include <QtGui/QOpenGLFramebufferObject>
#include <QtQuick/private/qsgbatchrenderer_p.h> #include <QtQuick/private/qsgbatchrenderer_p.h>
@ -317,6 +318,17 @@ QSGDefaultRenderContext *QSGDefaultRenderContext::from(QOpenGLContext *context)
return qobject_cast<QSGDefaultRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>()); return qobject_cast<QSGDefaultRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
} }
bool QSGDefaultRenderContext::separateIndexBuffer() const
{
// WebGL: A given WebGLBuffer object may only be bound to one of
// the ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target in its
// lifetime. An attempt to bind a buffer object to the other
// target will generate an INVALID_OPERATION error, and the
// current binding will remain untouched.
static const bool isWebGL = qGuiApp->platformName().compare(QLatin1String("webgl")) == 0;
return isWebGL;
}
QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font) QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font)
{ {
QString key = fontKey(font); QString key = fontKey(font);

View File

@ -95,6 +95,7 @@ public:
bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; } bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
int maxTextureSize() const override { return m_maxTextureSize; } int maxTextureSize() const override { return m_maxTextureSize; }
bool separateIndexBuffer() const;
protected: protected:
static QString fontKey(const QRawFont &font); static QString fontKey(const QRawFont &font);
@ -106,8 +107,6 @@ protected:
bool m_serializedRender; bool m_serializedRender;
bool m_attachToGLContext; bool m_attachToGLContext;
QSGAtlasTexture::Manager *m_atlasManager; QSGAtlasTexture::Manager *m_atlasManager;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -1,4 +1,3 @@
# DEFINES += QSG_SEPARATE_INDEX_BUFFER
# DEFINES += QSG_DISTANCEFIELD_CACHE_DEBUG # DEFINES += QSG_DISTANCEFIELD_CACHE_DEBUG
# Core API # Core API