From bf802b7ad941370933271cc999c418aead013be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 26 Feb 2021 18:31:10 +0100 Subject: [PATCH] GL: put texture/image state trackers into the single allocation also. --- doc/changelog.dox | 3 ++ src/Magnum/GL/Implementation/MeshState.cpp | 4 +- src/Magnum/GL/Implementation/MeshState.h | 2 + src/Magnum/GL/Implementation/State.cpp | 42 +++++++++++++++++- src/Magnum/GL/Implementation/TextureState.cpp | 43 ++++++++----------- src/Magnum/GL/Implementation/TextureState.h | 20 ++++++--- 6 files changed, 80 insertions(+), 34 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 5f0558dec..b7b98df1f 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -186,6 +186,9 @@ See also: @subsubsection changelog-latest-changes-gl GL library +- The @ref GL::Context class got significantly optimized in terms of compile + time, header size and runtime as well, significantly reducing the amount of + allocations done at startup. - Added @ref GL::Framebuffer::Status::IncompleteDimensions for ES2. This enum isn't available on ES3 or desktop GL, but NVidia drivers are known to emit it, which is why it got added. diff --git a/src/Magnum/GL/Implementation/MeshState.cpp b/src/Magnum/GL/Implementation/MeshState.cpp index 155023482..5fdbd3378 100644 --- a/src/Magnum/GL/Implementation/MeshState.cpp +++ b/src/Magnum/GL/Implementation/MeshState.cpp @@ -405,15 +405,15 @@ MeshState::MeshState(Context& context, ContextState& contextState, Containers::S #endif } +#ifndef MAGNUM_TARGET_GLES MeshState::~MeshState() { - #ifndef MAGNUM_TARGET_GLES /* If the default VAO was created, we need to delete it to avoid leaks. Delete also the scratch VAO if the engine was so unlucky to have to run awful external GL code (it was created in Context::resetState()). */ if(defaultVAO) glDeleteVertexArrays(1, &defaultVAO); if(scratchVAO) glDeleteVertexArrays(1, &scratchVAO); - #endif } +#endif void MeshState::reset() { currentVAO = State::DisengagedBinding; diff --git a/src/Magnum/GL/Implementation/MeshState.h b/src/Magnum/GL/Implementation/MeshState.h index 13a46478b..5ed0463c2 100644 --- a/src/Magnum/GL/Implementation/MeshState.h +++ b/src/Magnum/GL/Implementation/MeshState.h @@ -33,7 +33,9 @@ struct ContextState; struct MeshState { explicit MeshState(Context& context, ContextState& contextState, Containers::StaticArrayView extensions); + #ifndef MAGNUM_TARGET_GLES ~MeshState(); + #endif void reset(); diff --git a/src/Magnum/GL/Implementation/State.cpp b/src/Magnum/GL/Implementation/State.cpp index 27d21cc55..03225464e 100644 --- a/src/Magnum/GL/Implementation/State.cpp +++ b/src/Magnum/GL/Implementation/State.cpp @@ -25,7 +25,9 @@ #include "State.h" +#include #include +#include #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" @@ -48,6 +50,26 @@ namespace Magnum { namespace GL { namespace Implementation { std::pair State::allocate(Context& context, std::ostream* const out) { + /* TextureState needs to track state per texture / image binding, fetch + how many of them is there and allocate here as well so we don't need to + do another nested allocation */ + GLint maxTextureUnits{}; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + CORRADE_INTERNAL_ASSERT(maxTextureUnits > 0); + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + GLint maxImageUnits{}; + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #else + if(context.isVersionSupported(Version::GLES310)) + #endif + { + glGetIntegerv(GL_MAX_IMAGE_UNITS, &maxImageUnits); + CORRADE_INTERNAL_ASSERT(maxImageUnits > 0); + } + #endif + /* I have to say, the ArrayTuple is quite a crazy thing */ Containers::ArrayView stateView; Containers::ArrayView bufferStateView; @@ -62,6 +84,10 @@ std::pair State::allocate(Context& context, std: Containers::ArrayView shaderStateView; Containers::ArrayView shaderProgramStateView; Containers::ArrayView textureStateView; + Containers::ArrayView> textureBindings; + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + Containers::ArrayView> imageBindings; + #endif #ifndef MAGNUM_TARGET_GLES2 Containers::ArrayView transformFeedbackStateView; #endif @@ -79,11 +105,21 @@ std::pair State::allocate(Context& context, std: {Containers::NoInit, 1, shaderStateView}, {Containers::NoInit, 1, shaderProgramStateView}, {Containers::NoInit, 1, textureStateView}, + {Containers::ValueInit, std::size_t(maxTextureUnits), textureBindings}, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + {Containers::ValueInit, std::size_t(maxImageUnits), imageBindings}, + #endif #ifndef MAGNUM_TARGET_GLES2 {Containers::NoInit, 1, transformFeedbackStateView} #endif }; + #ifdef MAGNUM_TARGET_GLES + /* This whole thing would be trivially destructible except for MeshState + which has to delete scratch VAOs on desktop in a custom destructor. */ + CORRADE_INTERNAL_ASSERT(!data.deleter()); + #endif + /* Extensions that might get used by current context. The State classes will set strings based on Extension::index() and then we'll go through the list and print ones that aren't null. It's 1.5 kB of temporary data @@ -120,7 +156,11 @@ std::pair State::allocate(Context& context, std: new(&state.renderer) RendererState{context, stateView.front().context, extensions}; new(&state.shader) ShaderState(context, extensions); new(&state.shaderProgram) ShaderProgramState{context, extensions}; - new(&state.texture) TextureState{context, extensions}; + new(&state.texture) TextureState{context, textureBindings, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + imageBindings, + #endif + extensions}; #ifndef MAGNUM_TARGET_GLES2 new(&state.transformFeedback) TransformFeedbackState{context, extensions}; #endif diff --git a/src/Magnum/GL/Implementation/TextureState.cpp b/src/Magnum/GL/Implementation/TextureState.cpp index 0717b679e..4a61fa103 100644 --- a/src/Magnum/GL/Implementation/TextureState.cpp +++ b/src/Magnum/GL/Implementation/TextureState.cpp @@ -43,7 +43,13 @@ namespace Magnum { namespace GL { namespace Implementation { using namespace Containers::Literals; -TextureState::TextureState(Context& context, Containers::StaticArrayView extensions): maxSize{}, +TextureState::TextureState(Context& context, + Containers::ArrayView> bindings, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + Containers::ArrayView> imageBindings, + #endif + Containers::StaticArrayView extensions): + maxSize{}, #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) max3DSize{}, #endif @@ -54,16 +60,22 @@ TextureState::TextureState(Context& context, Containers::StaticArrayView 0); - bindings = Containers::Array>{Containers::ValueInit, std::size_t(maxTextureUnits)}; - #if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) if(!context.isDriverWorkaroundDisabled("apple-buffer-texture-unbind-on-buffer-modify"_s)) { CORRADE_INTERNAL_ASSERT(std::size_t(maxTextureUnits) <= decltype(bufferTextureBound)::Size); @@ -536,24 +543,8 @@ TextureState::TextureState(Context& context, Containers::StaticArrayView()) - #else - if(context.isVersionSupported(Version::GLES310)) - #endif - { - GLint maxImageUnits; - glGetIntegerv(GL_MAX_IMAGE_UNITS, &maxImageUnits); - imageBindings = Containers::Array>{Containers::ValueInit, std::size_t(maxImageUnits)}; - } - #endif } -TextureState::~TextureState() = default; - void TextureState::reset() { std::fill_n(bindings.begin(), bindings.size(), std::pair{{}, State::DisengagedBinding}); #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) diff --git a/src/Magnum/GL/Implementation/TextureState.h b/src/Magnum/GL/Implementation/TextureState.h index f36f76811..fcb22b91e 100644 --- a/src/Magnum/GL/Implementation/TextureState.h +++ b/src/Magnum/GL/Implementation/TextureState.h @@ -25,7 +25,7 @@ DEALINGS IN THE SOFTWARE. */ -#include +#include #include #include "Magnum/Magnum.h" @@ -51,8 +51,12 @@ namespace Magnum { namespace GL { namespace Implementation { struct TextureState { - explicit TextureState(Context& context, Containers::StaticArrayView extensions); - ~TextureState(); + explicit TextureState(Context& context, + Containers::ArrayView> bindings, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + Containers::ArrayView> imageBindings, + #endif + Containers::StaticArrayView extensions); void reset(); @@ -155,13 +159,19 @@ struct TextureState { GLint bufferOffsetAlignment; #endif - Containers::Array> bindings; + /* These arrays get allocated in State in a single allocation and views to + them are passed here via the constructor. */ + + /* Texture type, texture object ID. While not true, for simplicity this + assumes that each slot can have just one ID bound, not one ID per + texture type. */ + Containers::ArrayView> bindings; #if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) Math::BoolVector<80> bufferTextureBound; #endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) /* Texture object ID, level, layered, layer, access */ - Containers::Array> imageBindings; + Containers::ArrayView> imageBindings; #endif };