From c677d913df6beb2475365be42a4b256d4d9f993e Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 21 Apr 2023 13:14:44 +0100 Subject: [PATCH] Ensuring vertex attributes are uploaded once per buffer Changed status if the buffer bindings are modified Ensured samplers are only updated if program is different Change-Id: I07e9682705c309dc1a11412ce3e50ff53fdf93a5 --- dali/internal/graphics/gles-impl/gles-context.cpp | 142 ++++++++++++---------- dali/internal/graphics/gles-impl/gles-context.h | 10 +- 2 files changed, 89 insertions(+), 63 deletions(-) diff --git a/dali/internal/graphics/gles-impl/gles-context.cpp b/dali/internal/graphics/gles-impl/gles-context.cpp index 787f4ce..073bf62 100644 --- a/dali/internal/graphics/gles-impl/gles-context.cpp +++ b/dali/internal/graphics/gles-impl/gles-context.cpp @@ -233,7 +233,8 @@ struct Context::Impl uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO GLStateCache mGlStateCache{}; ///< GL status cache - bool mGlContextCreated{false}; ///< True if the OpenGL context has been created + bool mGlContextCreated{false}; ///< True if the OpenGL context has been created + bool mVertexBuffersChanged{true}; ///< True if BindVertexBuffers changed any buffer bindings EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context @@ -288,11 +289,16 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: return; } + // If this draw uses a different pipeline _AND_ the pipeline has a different GL Program, + // Then bind the new program. Ensure vertex atrributes are set. + + bool programChanged = false; if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline) { if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram()) { mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram()); + programChanged = true; } // Blend state @@ -330,15 +336,18 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: texture->Bind(binding); texture->Prepare(); - // @warning Assume that location of array elements is sequential. - // @warning GL does not guarantee this, but in practice, it is. - gl.Uniform1i(samplers[currentSampler].location + currentElement, - samplers[currentSampler].offset + currentElement); - ++currentElement; - if(currentElement >= samplers[currentSampler].elementCount) + if(programChanged) { - ++currentSampler; - currentElement = 0; + // @warning Assume that location of array elements is sequential. + // @warning GL does not guarantee this, but in practice, it is. + gl.Uniform1i(samplers[currentSampler].location + currentElement, + samplers[currentSampler].offset + currentElement); + ++currentElement; + if(currentElement >= samplers[currentSampler].elementCount) + { + ++currentSampler; + currentElement = 0; + } } if(currentSampler >= samplers.size()) { @@ -347,64 +356,66 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: } } - // for each attribute bind vertices const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo(); const auto& vertexInputState = pipelineState.vertexInputState; - if(hasGLES3) + // for each attribute bind vertices, unless the pipeline+buffer is the same + if(programChanged || mImpl->mVertexBuffersChanged) { - mImpl->BindProgramVAO(static_cast(pipelineState.programState->program)->GetImplementation(), *vertexInputState); - } - - for(const auto& attr : vertexInputState->attributes) - { - // Enable location - if(!hasGLES3) + if(hasGLES3) { - mImpl->SetVertexAttributeLocation(attr.location, true); + mImpl->BindProgramVAO(static_cast(pipelineState.programState->program)->GetImplementation(), *vertexInputState); } - const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding]; - const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding]; + for(const auto& attr : vertexInputState->attributes) + { + // Enable location + if(!hasGLES3) + { + mImpl->SetVertexAttributeLocation(attr.location, true); + } - auto glesBuffer = bufferSlot.buffer->GetGLBuffer(); + const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding]; + const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding]; - // Bind buffer - BindBuffer(GL_ARRAY_BUFFER, glesBuffer); + auto glesBuffer = bufferSlot.buffer->GetGLBuffer(); - if(attr.format == VertexInputFormat::FLOAT || - attr.format == VertexInputFormat::FVECTOR2 || - attr.format == VertexInputFormat::FVECTOR3 || - attr.format == VertexInputFormat::FVECTOR4) - { - gl.VertexAttribPointer(attr.location, - GLVertexFormat(attr.format).size, - GLVertexFormat(attr.format).format, - GL_FALSE, - bufferBinding.stride, - reinterpret_cast(attr.offset)); - } - else - { - gl.VertexAttribIPointer(attr.location, - GLVertexFormat(attr.format).size, - GLVertexFormat(attr.format).format, - bufferBinding.stride, - reinterpret_cast(attr.offset)); - } + BindBuffer(GL_ARRAY_BUFFER, glesBuffer); // Cached - switch(bufferBinding.inputRate) - { - case Graphics::VertexInputRate::PER_VERTEX: + if(attr.format == VertexInputFormat::FLOAT || + attr.format == VertexInputFormat::FVECTOR2 || + attr.format == VertexInputFormat::FVECTOR3 || + attr.format == VertexInputFormat::FVECTOR4) { - gl.VertexAttribDivisor(attr.location, 0); - break; + gl.VertexAttribPointer(attr.location, // Not cached... + GLVertexFormat(attr.format).size, + GLVertexFormat(attr.format).format, + GL_FALSE, + bufferBinding.stride, + reinterpret_cast(attr.offset)); } - case Graphics::VertexInputRate::PER_INSTANCE: + else { - //@todo Get actual instance rate... - gl.VertexAttribDivisor(attr.location, 1); - break; + gl.VertexAttribIPointer(attr.location, + GLVertexFormat(attr.format).size, + GLVertexFormat(attr.format).format, + bufferBinding.stride, + reinterpret_cast(attr.offset)); + } + + switch(bufferBinding.inputRate) + { + case Graphics::VertexInputRate::PER_VERTEX: + { + gl.VertexAttribDivisor(attr.location, 0); + break; + } + case Graphics::VertexInputRate::PER_INSTANCE: + { + //@todo Get actual instance rate... + gl.VertexAttribDivisor(attr.location, 1); + break; + } } } } @@ -412,8 +423,6 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: // Resolve topology const auto& ia = pipelineState.inputAssemblyState; - // Bind uniforms - // Resolve draw call switch(drawCall.type) { @@ -516,9 +525,19 @@ void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindi mImpl->mCurrentVertexBufferBindings.resize(count); } // Copy only set slots - std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) { - return (nullptr != item.buffer); - }); + mImpl->mVertexBuffersChanged = false; + auto toIter = mImpl->mCurrentVertexBufferBindings.begin(); + for(auto fromIter = bindings, end = bindings + count; fromIter != end; ++fromIter) + { + if(fromIter->buffer != nullptr) + { + if(toIter->buffer != fromIter->buffer || toIter->offset != fromIter->offset) + { + mImpl->mVertexBuffersChanged = true; + } + *toIter++ = *fromIter; + } + } } void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding) @@ -1018,7 +1037,7 @@ void Context::GenerateMipmap(GLenum target) gl.GenerateMipmap(target); } -void Context::BindBuffer(GLenum target, uint32_t bufferId) +bool Context::BindBuffer(GLenum target, uint32_t bufferId) { switch(target) { @@ -1026,7 +1045,7 @@ void Context::BindBuffer(GLenum target, uint32_t bufferId) { if(mImpl->mGlStateCache.mBoundArrayBufferId == bufferId) { - return; + return false; } mImpl->mGlStateCache.mBoundArrayBufferId = bufferId; break; @@ -1035,7 +1054,7 @@ void Context::BindBuffer(GLenum target, uint32_t bufferId) { if(mImpl->mGlStateCache.mBoundElementArrayBufferId == bufferId) { - return; + return false; } mImpl->mGlStateCache.mBoundElementArrayBufferId = bufferId; break; @@ -1045,6 +1064,7 @@ void Context::BindBuffer(GLenum target, uint32_t bufferId) // Cache miss. Bind buffer. auto& gl = *mImpl->mController.GetGL(); gl.BindBuffer(target, bufferId); + return true; } void Context::DrawBuffers(uint32_t count, const GLenum* buffers) diff --git a/dali/internal/graphics/gles-impl/gles-context.h b/dali/internal/graphics/gles-impl/gles-context.h index 2345458..55f1db6 100644 --- a/dali/internal/graphics/gles-impl/gles-context.h +++ b/dali/internal/graphics/gles-impl/gles-context.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_GLES_CONTEXT_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -189,7 +189,13 @@ public: void ActiveTexture(uint32_t textureBindingIndex); void BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId); void GenerateMipmap(GLenum target); - void BindBuffer(GLenum target, uint32_t bufferId); + + /** + * Binds the buffer. + * @return true if the buffer was actually bound, false if it's cached + */ + bool BindBuffer(GLenum target, uint32_t bufferId); + void DrawBuffers(uint32_t count, const GLenum* buffers); void BindFrameBuffer(GLenum target, uint32_t bufferId); void GenFramebuffers(uint32_t count, uint32_t* framebuffers); -- 2.7.4