Browse Source

GL: make it possible to bind a scratch VAO for external GL code.

Used in those sad and unfortunate cases where we need to call
shitty external GL code that's not VAO-aware.
pull/297/head
Vladimír Vondruš 8 years ago
parent
commit
dd343fe35b
  1. 8
      doc/changelog.dox
  2. 14
      src/Magnum/GL/Context.cpp
  3. 25
      src/Magnum/GL/Context.h
  4. 11
      src/Magnum/GL/Implementation/MeshState.cpp
  5. 5
      src/Magnum/GL/Implementation/MeshState.h
  6. 44
      src/Magnum/GL/Test/MeshGLTest.cpp

8
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

14
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);

25
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,

11
src/Magnum/GL/Implementation/MeshState.cpp

@ -170,7 +170,11 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector<s
#ifndef MAGNUM_TARGET_GLES
/* If we are on core profile and ARB_VAO was explicitly disabled by the
user, we need to bind a default VAO so we are still able to draw things */
user, we need to bind a default VAO so we are still able to draw things.
There's another "scratch" VAO that's used by Context::resetState() for
crappy external code if ARB_VAO *isn't* disabled, but that one is
generated on-demand as we optimistically hope crappy external code is
not a norm. */
if(context.isExtensionDisabled<Extensions::ARB::vertex_array_object>() && context.isCoreProfileInternal(contextState)) {
glGenVertexArrays(1, &defaultVAO);
glBindVertexArray(defaultVAO);
@ -182,8 +186,11 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector<s
MeshState::~MeshState() {
#ifndef MAGNUM_TARGET_GLES
/* If the default VAO was created, we need to delete it to avoid leaks */
/* 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
}

5
src/Magnum/GL/Implementation/MeshState.h

@ -65,7 +65,10 @@ struct MeshState {
void(*bindVAOImplementation)(GLuint);
#ifndef MAGNUM_TARGET_GLES
GLuint defaultVAO{}; /* Used on core profile in case ARB_VAO is disabled */
GLuint defaultVAO{}, /* Used on core profile in case ARB_VAO is disabled */
/* Used for non-VAO-aware external GL code on core profile in case
ARB_VAO is *not* disabled */
scratchVAO{};
#endif
GLuint currentVAO;

44
src/Magnum/GL/Test/MeshGLTest.cpp

@ -132,6 +132,7 @@ struct MeshGLTest: OpenGLTester {
void unbindVAOWhenSettingIndexBufferData();
void unbindVAOBeforeEnteringExternalSection();
void bindScratchVaoWhenEnteringExternalSection();
#ifndef MAGNUM_TARGET_GLES
void setBaseVertex();
@ -251,6 +252,7 @@ MeshGLTest::MeshGLTest() {
&MeshGLTest::unbindVAOWhenSettingIndexBufferData,
&MeshGLTest::unbindVAOBeforeEnteringExternalSection,
&MeshGLTest::bindScratchVaoWhenEnteringExternalSection,
#ifndef MAGNUM_TARGET_GLES
&MeshGLTest::setBaseVertex,
@ -2128,6 +2130,48 @@ void MeshGLTest::unbindVAOBeforeEnteringExternalSection() {
CORRADE_COMPARE(value, 92);
}
void MeshGLTest::bindScratchVaoWhenEnteringExternalSection() {
typedef Attribute<0, Float> Attribute;
const Float data[] = { -0.7f, Math::unpack<Float, UnsignedByte>(92), Math::unpack<Float, UnsignedByte>(32) };
Buffer buffer{Buffer::TargetHint::Array};
buffer.setData(data, BufferUsage::StaticDraw);
Buffer indices{Buffer::TargetHint::ElementArray};
indices.setData(std::vector<UnsignedByte>{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<UnsignedByte>(PixelFormat::RGBA, PixelType::UnsignedByte);
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(value, 92);
}
#ifndef MAGNUM_TARGET_GLES
void MeshGLTest::setBaseVertex() {
if(!Context::current().isExtensionSupported<Extensions::ARB::draw_elements_base_vertex>())

Loading…
Cancel
Save