diff --git a/doc/changelog.dox b/doc/changelog.dox index 5399fb045..10ad28b2c 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -58,6 +58,14 @@ See also: @ref Math::Color3 and @ref Math::Color4 literals with the new experimental @ref Corrade::Utility::Tweakable utility. See also @ref tweakableliterals. +@subsection changelog-latest-changes Changes and improvements + +@subsubsection changelog-latest-changes-gl GL library + +- New @ref GL::Context::State::BindScratchVao state to make external OpenGL + code that's not VAO-aware working on core GL profiles (which don't allow + default VAOs being used for drawing) + @subsection changelog-latest-bugfixes Bug fixes - Fixed @ref Platform::Sdl2Application and @ref Platform::GlfwApplication to diff --git a/src/Magnum/GL/Context.cpp b/src/Magnum/GL/Context.cpp index 9000ff215..dfcc826af 100644 --- a/src/Magnum/GL/Context.cpp +++ b/src/Magnum/GL/Context.cpp @@ -860,6 +860,20 @@ void Context::resetState(const States states) { _state->framebuffer->reset(); if(states & State::Meshes) _state->mesh->reset(); + + #ifndef MAGNUM_TARGET_GLES + /* Bind a scratch VAO for external GL code that is not VAO-aware and just + enables vertex attributes on the default VAO. Generate it on-demand as + we don't expect this case to be used very often. */ + if(states & State::BindScratchVao) { + if(!_state->mesh->scratchVAO) + glGenVertexArrays(1, &_state->mesh->scratchVAO); + + _state->mesh->bindVAOImplementation(_state->mesh->scratchVAO); + + /* Otherwise just unbind the current VAO and leave the the default */ + } else + #endif if(states & State::MeshVao) _state->mesh->bindVAOImplementation(0); diff --git a/src/Magnum/GL/Context.h b/src/Magnum/GL/Context.h index 72bcf5e7e..4b176ab17 100644 --- a/src/Magnum/GL/Context.h +++ b/src/Magnum/GL/Context.h @@ -237,21 +237,34 @@ class MAGNUM_GL_EXPORT Context { */ MeshVao = 1 << 3, + /** + * Bind a "scratch" VAO on core profile. + * + * Use if external code is not VAO-aware and would otherwise try to + * enable vertex attributes on the default (zero) VAO, causing GL + * errors. Meant to be used together with @ref State::MeshVao (or + * @ref State::EnterExternal). + * + * Does nothing on compatibility profile and ES / WebGL platforms, + * as using the default VAO is allowed there. + */ + BindScratchVao = 1 << 4, + /** Reset tracked pixel storage-related state */ - PixelStorage = 1 << 4, + PixelStorage = 1 << 5, /** Reset tracked renderer-related state */ - Renderer = 1 << 5, + Renderer = 1 << 6, /** Reset tracked shader-related bindings */ - Shaders = 1 << 6, + Shaders = 1 << 7, /** Reset tracked texture-related bindings and state */ - Textures = 1 << 7, + Textures = 1 << 8, #ifndef MAGNUM_TARGET_GLES2 /** Reset tracked transform feedback-related bindings */ - TransformFeedback = 1 << 8, + TransformFeedback = 1 << 9, #endif /** @@ -259,6 +272,8 @@ class MAGNUM_GL_EXPORT Context { * * Resets all state that could cause external code to accidentally * modify Magnum objects. This includes only @ref State::MeshVao. + * In some pathological cases you may want to enable + * @ref State::BindScratchVao as well. */ EnterExternal = MeshVao, diff --git a/src/Magnum/GL/Implementation/MeshState.cpp b/src/Magnum/GL/Implementation/MeshState.cpp index f93090ade..dc4f8419d 100644 --- a/src/Magnum/GL/Implementation/MeshState.cpp +++ b/src/Magnum/GL/Implementation/MeshState.cpp @@ -170,7 +170,11 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector() && context.isCoreProfileInternal(contextState)) { glGenVertexArrays(1, &defaultVAO); glBindVertexArray(defaultVAO); @@ -182,8 +186,11 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector Attribute; + + const Float data[] = { -0.7f, Math::unpack(92), Math::unpack(32) }; + Buffer buffer{Buffer::TargetHint::Array}; + buffer.setData(data, BufferUsage::StaticDraw); + + Buffer indices{Buffer::TargetHint::ElementArray}; + indices.setData(std::vector{5, 0}, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.addVertexBuffer(buffer, 4, Attribute{}) + .setIndexBuffer(indices, 0, MeshIndexType::UnsignedByte); + + { + /* Should bind a scratch VAO only on desktop with core profile and be + a no-op everywhere else */ + Context::current().resetState(Context::State::EnterExternal + |Context::State::BindScratchVao /* Comment this out to watch the world burn */ + ); + + /* Should throw no GL error if scratch VAO is bound */ + glDrawArrays(GL_POINTS, 0, 0); + + /* Be nice to the other tests */ + Context::current().resetState(Context::State::ExitExternal); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); + + const auto value = Checker(FloatShader("float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"), + #ifndef MAGNUM_TARGET_GLES2 + RenderbufferFormat::RGBA8, + #else + RenderbufferFormat::RGBA4, + #endif + mesh).get(PixelFormat::RGBA, PixelType::UnsignedByte); + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE(value, 92); +} + #ifndef MAGNUM_TARGET_GLES void MeshGLTest::setBaseVertex() { if(!Context::current().isExtensionSupported())