From d0ab2359f5b4b23dcd017ed6abb2c063deb98a85 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 9 Dec 2015 13:23:07 +0100 Subject: GraphicsContext: use GLBuffer instead of QOpenGLBuffer This will be needed to simplify the process of binding SSBO/UBO buffers. Change-Id: Ice3bb97381328c5bddf1c9e46af30b4814ff2572 Note: ShaderData UBO handling temporarly disabled. Reviewed-by: Paul Lemire --- src/render/backend/managers_p.h | 2 +- src/render/backend/renderview.cpp | 71 +++++----- src/render/graphicshelpers/graphicscontext.cpp | 187 +++++++++++++------------ src/render/graphicshelpers/graphicscontext_p.h | 10 +- src/render/io/glbuffer.cpp | 16 ++- src/render/io/glbuffer_p.h | 9 +- 6 files changed, 162 insertions(+), 133 deletions(-) (limited to 'src/render') diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index 94089795c..e3b9cb9d7 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -284,7 +284,7 @@ public: class GLBufferManager : public Qt3DCore::QResourceManager< GLBuffer, - BufferShaderKey, + Qt3DCore::QNodeId, 16, Qt3DCore::ArrayAllocatingPolicy, Qt3DCore::ObjectLevelLockingPolicy> diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index 22aa581a7..120142c51 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -621,41 +621,44 @@ void RenderView::setUniformBlockValue(QUniformPack &uniformPack, Shader *shader, // Note: we assume that if a buffer is shared accross multiple shaders // then it implies that they share the same layout - BufferShaderKey uboKey(shaderData->peerUuid(), - shader->peerUuid()); - - BlockToUBO uniformBlockUBO; - uniformBlockUBO.m_blockIndex = block.m_index; - uniformBlockUBO.m_shaderDataID = shaderData->peerUuid(); - bool uboNeedsUpdate = false; - - // build UBO at uboId if not created before - if (!m_manager->glBufferManager()->contains(uboKey)) { - m_manager->glBufferManager()->getOrCreateResource(uboKey); - uboNeedsUpdate = true; - } - - // If shaderData has been updated (property has changed or one of the nested properties has changed) - // foreach property defined in the QShaderData, we try to fill the value of the corresponding active uniform(s) - // for all the updated properties (all the properties if the UBO was just created) - if (shaderData->updateViewTransform(*m_data->m_viewMatrix) || uboNeedsUpdate) { - // Clear previous values remaining in the hash - m_data->m_uniformBlockBuilder.activeUniformNamesToValue.clear(); - // Update only update properties if uboNeedsUpdate is true, otherwise update the whole block - m_data->m_uniformBlockBuilder.updatedPropertiesOnly = uboNeedsUpdate; - // Retrieve names and description of each active uniforms in the uniform block - m_data->m_uniformBlockBuilder.uniforms = shader->activeUniformsForUniformBlock(block.m_index); - // Builds the name-value map for the block - m_data->m_uniformBlockBuilder.buildActiveUniformNameValueMapStructHelper(shaderData, block.m_name); - if (!uboNeedsUpdate) - shaderData->markDirty(); - // copy the name-value map into the BlockToUBO - uniformBlockUBO.m_updatedProperties = m_data->m_uniformBlockBuilder.activeUniformNamesToValue; - uboNeedsUpdate = true; - } - uniformBlockUBO.m_needsUpdate = uboNeedsUpdate; - uniformPack.setUniformBuffer(uniformBlockUBO); + // Temporarly disabled + + // BufferShaderKey uboKey(shaderData->peerUuid(), + // shader->peerUuid()); + + // BlockToUBO uniformBlockUBO; + // uniformBlockUBO.m_blockIndex = block.m_index; + // uniformBlockUBO.m_shaderDataID = shaderData->peerUuid(); + // bool uboNeedsUpdate = false; + + // // build UBO at uboId if not created before + // if (!m_manager->glBufferManager()->contains(uboKey)) { + // m_manager->glBufferManager()->getOrCreateResource(uboKey); + // uboNeedsUpdate = true; + // } + + // // If shaderData has been updated (property has changed or one of the nested properties has changed) + // // foreach property defined in the QShaderData, we try to fill the value of the corresponding active uniform(s) + // // for all the updated properties (all the properties if the UBO was just created) + // if (shaderData->updateViewTransform(*m_data->m_viewMatrix) || uboNeedsUpdate) { + // // Clear previous values remaining in the hash + // m_data->m_uniformBlockBuilder.activeUniformNamesToValue.clear(); + // // Update only update properties if uboNeedsUpdate is true, otherwise update the whole block + // m_data->m_uniformBlockBuilder.updatedPropertiesOnly = uboNeedsUpdate; + // // Retrieve names and description of each active uniforms in the uniform block + // m_data->m_uniformBlockBuilder.uniforms = shader->activeUniformsForUniformBlock(block.m_index); + // // Builds the name-value map for the block + // m_data->m_uniformBlockBuilder.buildActiveUniformNameValueMapStructHelper(shaderData, block.m_name); + // if (!uboNeedsUpdate) + // shaderData->markDirty(); + // // copy the name-value map into the BlockToUBO + // uniformBlockUBO.m_updatedProperties = m_data->m_uniformBlockBuilder.activeUniformNamesToValue; + // uboNeedsUpdate = true; + // } + + // uniformBlockUBO.m_needsUpdate = uboNeedsUpdate; + // uniformPack.setUniformBuffer(uniformBlockUBO); } } diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 19415d0b8..ad13b2812 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -80,30 +80,20 @@ static QHash static_contexts; namespace { -QOpenGLBuffer createGLBufferFor(Buffer *buffer) +GLBuffer::Type bufferTypeToGLBufferType(QBuffer::BufferType type) { - QOpenGLBuffer b(static_cast(buffer->type())); - b.setUsagePattern(static_cast(buffer->usage())); - if (!b.create()) - qCWarning(Render::Io) << Q_FUNC_INFO << "buffer creation failed"; - - if (!b.bind()) - qCWarning(Render::Io) << Q_FUNC_INFO << "buffer binding failed"; - - b.allocate(buffer->data().constData(), buffer->data().size()); - return b; -} - -void uploadDataToGLBuffer(Buffer *buffer, QOpenGLBuffer &b, bool releaseBuffer = false) -{ - if (!b.bind()) - qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed"; - const int bufferSize = buffer->data().size(); - b.allocate(NULL, bufferSize); // orphan the buffer - b.allocate(buffer->data().constData(), bufferSize); - if (releaseBuffer) - b.release(); - qCDebug(Render::Io) << "uploaded buffer size=" << buffer->data().size(); + switch (type) { + case QBuffer::VertexBuffer: + return GLBuffer::ArrayBuffer; + case QBuffer::IndexBuffer: + return GLBuffer::IndexBuffer; + case QBuffer::PixelPackBuffer: + return GLBuffer::PixelPackBuffer; + case QBuffer::PixelUnpackBuffer: + return GLBuffer::PixelUnpackBuffer; + default: + Q_UNREACHABLE(); + } } } // anonymous @@ -487,11 +477,6 @@ void GraphicsContext::setActiveMaterial(Material *rmat) m_material = rmat; } -// TO DO : Try to move what's in Renderer here -void GraphicsContext::executeCommand(const RenderCommand *) -{ -} - int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUnit) { // Returns the texture unit to use for the texture @@ -890,53 +875,56 @@ void GraphicsContext::setUniforms(QUniformPack &uniforms) const QVector &blockToUbos = uniforms.uniformBuffers(); GLBuffer *ubo = Q_NULLPTR; bool needsToUnbindUBO = false; - for (int i = 0; i < blockToUbos.length(); ++i) { - const ShaderUniformBlock &block = m_activeShader->uniformBlock(blockToUbos[i].m_blockIndex); - if (block.m_index != -1 && block.m_size > 0) { - ubo = manager->lookupResource(BufferShaderKey(blockToUbos[i].m_shaderDataID, - m_activeShader->peerUuid())); - // bind Uniform Block of index ubos[i].m_index to binding point i - bindUniformBlock(m_activeShader->getOrCreateProgram(this)->programId(), block.m_index, i); - // bind the UBO to the binding point i - // Specs specify that there are at least 14 binding points - - // Allocate ubo if not allocated previously - if (!ubo->isCreated()) { - ubo->create(this); - ubo->bind(this, GLBuffer::UniformBuffer); - ubo->allocate(this, block.m_size); - } - // update the ubo if needed - - // TO DO: Maybe QShaderData should act as a QBuffer data provider - // and internally update a QBuffer which we would then reupload - // and the ShaderData updates could then be done in some jobs - // rather than at render time ? - if (blockToUbos[i].m_needsUpdate) { - if (!ubo->isBound()) - ubo->bind(this, GLBuffer::UniformBuffer); - needsToUnbindUBO |= true; - const QHash &activeUniformsInBlock = m_activeShader->activeUniformsForUniformBlock(block.m_index); - const QHash::const_iterator uniformsEnd = activeUniformsInBlock.end(); - QHash::const_iterator uniformsIt = activeUniformsInBlock.begin(); - - while (uniformsIt != uniformsEnd) { - if (blockToUbos[i].m_updatedProperties.contains(uniformsIt.key())) { - buildUniformBuffer(blockToUbos[i].m_updatedProperties.value(uniformsIt.key()), - uniformsIt.value(), - m_uboTempArray); - ubo->update(this, m_uboTempArray.constData() + uniformsIt.value().m_offset, - uniformsIt.value().m_rawByteSize, - uniformsIt.value().m_offset); - } - ++uniformsIt; - } - } - // bind UBO to binding point - ubo->bindToUniformBlock(this, i); - } - } + // TEMPORARLY Disabled + + // for (int i = 0; i < blockToUbos.length(); ++i) { + // const ShaderUniformBlock &block = m_activeShader->uniformBlock(blockToUbos[i].m_blockIndex); + // if (block.m_index != -1 && block.m_size > 0) { + // ubo = manager->lookupResource(BufferShaderKey(blockToUbos[i].m_shaderDataID, + // m_activeShader->peerUuid())); + // // bind Uniform Block of index ubos[i].m_index to binding point i + // bindUniformBlock(m_activeShader->getOrCreateProgram(this)->programId(), block.m_index, i); + // // bind the UBO to the binding point i + // // Specs specify that there are at least 14 binding points + + // // Allocate ubo if not allocated previously + // if (!ubo->isCreated()) { + // ubo->create(this); + // ubo->bind(this, GLBuffer::UniformBuffer); + // ubo->allocate(this, block.m_size); + // } + + // // update the ubo if needed + + // // TO DO: Maybe QShaderData should act as a QBuffer data provider + // // and internally update a QBuffer which we would then reupload + // // and the ShaderData updates could then be done in some jobs + // // rather than at render time ? + // if (blockToUbos[i].m_needsUpdate) { + // if (!ubo->isBound()) + // ubo->bind(this, GLBuffer::UniformBuffer); + // needsToUnbindUBO |= true; + // const QHash &activeUniformsInBlock = m_activeShader->activeUniformsForUniformBlock(block.m_index); + // const QHash::const_iterator uniformsEnd = activeUniformsInBlock.end(); + // QHash::const_iterator uniformsIt = activeUniformsInBlock.begin(); + + // while (uniformsIt != uniformsEnd) { + // if (blockToUbos[i].m_updatedProperties.contains(uniformsIt.key())) { + // buildUniformBuffer(blockToUbos[i].m_updatedProperties.value(uniformsIt.key()), + // uniformsIt.value(), + // m_uboTempArray); + // ubo->update(this, m_uboTempArray.constData() + uniformsIt.value().m_offset, + // uniformsIt.value().m_rawByteSize, + // uniformsIt.value().m_offset); + // } + // ++uniformsIt; + // } + // } + // // bind UBO to binding point + // ubo->bindToUniformBlock(this, i); + // } + // } if (needsToUnbindUBO) ubo->release(this); @@ -950,8 +938,9 @@ void GraphicsContext::specifyAttribute(const Attribute *attribute, Buffer *buffe if (attribute == Q_NULLPTR || buffer == Q_NULLPTR) return; - QOpenGLBuffer buf = glBufferForRenderBuffer(buffer); - buf.bind(); + GLBuffer *buf = glBufferForRenderBuffer(buffer); + buf->bind(this, bufferTypeToGLBufferType(buffer->type())); + // bound within the current VAO QOpenGLShaderProgram* prog = activeShader(); int location = prog->attributeLocation(shaderName); @@ -976,8 +965,8 @@ void GraphicsContext::specifyIndices(Buffer *buffer) { Q_ASSERT(buffer->type() == QBuffer::IndexBuffer); - QOpenGLBuffer buf = glBufferForRenderBuffer(buffer); - if (!buf.bind()) + GLBuffer *buf = glBufferForRenderBuffer(buffer); + if (!buf->bind(this, GLBuffer::IndexBuffer)) qCWarning(Backend) << Q_FUNC_INFO << "binding index buffer failed"; // bound within the current VAO @@ -985,19 +974,45 @@ void GraphicsContext::specifyIndices(Buffer *buffer) void GraphicsContext::updateBuffer(Buffer *buffer) { - const QHash::iterator it = m_renderBufferHash.find(buffer); + const QHash::iterator it = m_renderBufferHash.find(buffer->peerUuid()); if (it != m_renderBufferHash.end()) - uploadDataToGLBuffer(buffer, it.value()); + uploadDataToGLBuffer(buffer, m_renderer->nodeManagers()->glBufferManager()->data(it.value())); } -QOpenGLBuffer GraphicsContext::glBufferForRenderBuffer(Buffer *buf) +GLBuffer *GraphicsContext::glBufferForRenderBuffer(Buffer *buf) { - if (m_renderBufferHash.contains(buf)) - return m_renderBufferHash.value(buf); + if (!m_renderBufferHash.contains(buf->peerUuid())) + m_renderBufferHash.insert(buf->peerUuid(), createGLBufferFor(buf)); + return m_renderer->nodeManagers()->glBufferManager()->data(m_renderBufferHash.value(buf->peerUuid())); +} - QOpenGLBuffer glbuf = createGLBufferFor(buf); - m_renderBufferHash.insert(buf, glbuf); - return glbuf; +HGLBuffer GraphicsContext::createGLBufferFor(Buffer *buffer) +{ + GLBuffer *b = m_renderer->nodeManagers()->glBufferManager()->getOrCreateResource(buffer->peerUuid()); + // b.setUsagePattern(static_cast(buffer->usage())); + Q_ASSERT(b); + if (!b->create(this)) + qCWarning(Render::Io) << Q_FUNC_INFO << "buffer creation failed"; + + if (!b->bind(this, bufferTypeToGLBufferType(buffer->type()))) + qCWarning(Render::Io) << Q_FUNC_INFO << "buffer binding failed"; + + // TO DO: Handle usage pattern + b->allocate(this, buffer->data().constData(), buffer->data().size(), false); + return m_renderer->nodeManagers()->glBufferManager()->lookupHandle(buffer->peerUuid()); +} + +void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer) +{ + if (!b->isBound() && !b->bind(this, bufferTypeToGLBufferType(buffer->type()))) + qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed"; + const int bufferSize = buffer->data().size(); + // TO DO: Handle usage pattern and sub data updates + b->allocate(this, bufferSize, false); // orphan the buffer + b->allocate(this, buffer->data().constData(), bufferSize, false); + if (releaseBuffer) + b->release(this); + qCDebug(Render::Io) << "uploaded buffer size=" << buffer->data().size(); } GLint GraphicsContext::elementType(GLint type) diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h index c377d237b..845beaf5b 100644 --- a/src/render/graphicshelpers/graphicscontext_p.h +++ b/src/render/graphicshelpers/graphicscontext_p.h @@ -51,7 +51,6 @@ #include #include -#include #include #include #include @@ -61,6 +60,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -83,6 +83,7 @@ class RenderTarget; class AttachmentPack; class Attribute; class Buffer; +class GLBuffer; enum TextureScope { @@ -151,8 +152,7 @@ public: * @param buf * @return */ - QOpenGLBuffer glBufferForRenderBuffer(Buffer *buf); - + GLBuffer *glBufferForRenderBuffer(Buffer *buf); /** * @brief activateTexture - make a texture active on a hardware unit @@ -218,6 +218,8 @@ private: void bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments); void activateDrawBuffers(const AttachmentPack &attachments); + HGLBuffer createGLBufferFor(Buffer *buffer); + void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false); bool m_initialized; const unsigned int m_id; @@ -228,7 +230,7 @@ private: Shader *m_activeShader; QHash m_renderShaderHash; - QHash m_renderBufferHash; + QHash m_renderBufferHash; QHash m_renderTargets; QHash m_renderTargetsSize; diff --git a/src/render/io/glbuffer.cpp b/src/render/io/glbuffer.cpp index bff4cb3e4..8e7636964 100644 --- a/src/render/io/glbuffer.cpp +++ b/src/render/io/glbuffer.cpp @@ -86,23 +86,28 @@ GLBuffer::GLBuffer() { } -void GLBuffer::bind(GraphicsContext *ctx, Type t) +bool GLBuffer::bind(GraphicsContext *ctx, Type t) { + if (m_bufferId == 0) + return false; m_lastTarget = glBufferTypes[t]; ctx->openGLContext()->functions()->glBindBuffer(m_lastTarget, m_bufferId); m_bound = true; + return true; } -void GLBuffer::release(GraphicsContext *ctx) +bool GLBuffer::release(GraphicsContext *ctx) { m_bound = false; ctx->openGLContext()->functions()->glBindBuffer(m_lastTarget, 0); + return true; } -void GLBuffer::create(GraphicsContext *ctx) +bool GLBuffer::create(GraphicsContext *ctx) { ctx->openGLContext()->functions()->glGenBuffers(1, &m_bufferId); m_isCreated = true; + return m_bufferId != 0; } void GLBuffer::destroy(GraphicsContext *ctx) @@ -118,6 +123,11 @@ void GLBuffer::allocate(GraphicsContext *ctx, uint size, bool dynamic) ctx->openGLContext()->functions()->glBufferData(m_lastTarget, size, NULL, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); } +void GLBuffer::allocate(GraphicsContext *ctx, const void *data, uint size, bool dynamic) +{ + ctx->openGLContext()->functions()->glBufferData(m_lastTarget, size, data, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +} + void GLBuffer::update(GraphicsContext *ctx, const void *data, uint size, int offset) { ctx->openGLContext()->functions()->glBufferSubData(m_lastTarget, offset, size, data); diff --git a/src/render/io/glbuffer_p.h b/src/render/io/glbuffer_p.h index 9d47a52db..1dc8adb3c 100644 --- a/src/render/io/glbuffer_p.h +++ b/src/render/io/glbuffer_p.h @@ -59,8 +59,6 @@ namespace Render { class GraphicsContext; -typedef QPair BufferShaderKey; - class GLBuffer { public: @@ -76,11 +74,12 @@ public: PixelUnpackBuffer }; - void bind(GraphicsContext *ctx, Type t); - void release(GraphicsContext *ctx); - void create(GraphicsContext *ctx); + bool bind(GraphicsContext *ctx, Type t); + bool release(GraphicsContext *ctx); + bool create(GraphicsContext *ctx); void destroy(GraphicsContext *ctx); void allocate(GraphicsContext *ctx, uint size, bool dynamic = true); + void allocate(GraphicsContext *ctx, const void *data, uint size, bool dynamic = true); void update(GraphicsContext *ctx, const void *data, uint size, int offset = 0); void bindToUniformBlock(GraphicsContext *ctx, int bindingPoint); -- cgit v1.2.3