Browse Source

Finally completed ARB_uniform_buffer_object.

Also with ES3/WebGL2 port.
pull/132/head
Vladimír Vondruš 10 years ago
parent
commit
1caf96a347
  1. 4
      doc/opengl-mapping.dox
  2. 2
      doc/opengl-support.dox
  3. 9
      src/Magnum/AbstractShaderProgram.cpp
  4. 99
      src/Magnum/AbstractShaderProgram.h
  5. 159
      src/Magnum/Test/AbstractShaderProgramGLTest.cpp
  6. 11
      src/Magnum/Test/AbstractShaderProgramGLTestFiles/UniformBlockShader.frag
  7. 10
      src/Magnum/Test/AbstractShaderProgramGLTestFiles/UniformBlockShader.vert
  8. 6
      src/Magnum/Test/AbstractShaderProgramGLTestFiles/resources.conf

4
doc/opengl-mapping.dox

@ -219,7 +219,7 @@ OpenGL function | Matching API
@fn_gl{GetTransformFeedback} | not queryable, @ref TransformFeedback::attachBuffer() and @ref TransformFeedback::attachBuffers() setters only
@fn_gl{GetTransformFeedbackVarying} | not queryable, @ref AbstractShaderProgram::setTransformFeedbackOutputs() setter only
@fn_gl{GetUniform}, \n `glGetnUniform()`, \n @fn_gl_extension{GetnUniform,ARB,robustness} | not queryable, @ref AbstractShaderProgram::setUniform() setter only
@fn_gl{GetUniformBlockIndex} | |
@fn_gl{GetUniformBlockIndex} | @ref AbstractShaderProgram::uniformBlockIndex()
@fn_gl{GetUniformIndices} | |
@fn_gl{GetUniformLocation} | @ref AbstractShaderProgram::uniformLocation()
@fn_gl{GetUniformSubroutine} | |
@ -350,7 +350,7 @@ OpenGL function | Matching API
--------------------------------------- | ------------
@fn_gl{Uniform}, \n @fn_gl{ProgramUniform}, \n @fn_gl_extension{ProgramUniform,EXT,direct_state_access} | @ref AbstractShaderProgram::setUniform()
@fn_gl_extension{UniformHandle,ARB,bindless_texture}, \n @fn_gl_extension{ProgramUniformHandle,ARB,bindless_texture} | |
@fn_gl{UniformBlockBinding} | |
@fn_gl{UniformBlockBinding} | @ref AbstractShaderProgram::setUniformBlockBinding()
@fn_gl{UniformSubroutines} | |
@fn_gl{UseProgram} | @ref Mesh::draw(), @ref MeshView::draw()
@fn_gl{UseProgramStages} | |

2
doc/opengl-support.dox

@ -80,7 +80,7 @@ GLSL 1.40 | done
@extension{ARB,texture_rectangle} | done
@extension{ARB,draw_instanced} | done
@extension{ARB,texture_buffer_object} | done
@extension{ARB,uniform_buffer_object} | missing uniform block binding
@extension{ARB,uniform_buffer_object} | done
@extension{ARB,copy_buffer} | done
@extension{EXT,texture_snorm} | done
@extension{NV,primitive_restart} | |

9
src/Magnum/AbstractShaderProgram.cpp

@ -401,6 +401,15 @@ Int AbstractShaderProgram::uniformLocationInternal(const Containers::ArrayView<c
return location;
}
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt AbstractShaderProgram::uniformBlockIndexInternal(const Containers::ArrayView<const char> name) {
const GLuint index = glGetUniformBlockIndex(_id, name);
if(index == GL_INVALID_INDEX)
Warning() << "AbstractShaderProgram: index of uniform block \'" << Debug::nospace << std::string{name, name.size()} << Debug::nospace << "\' cannot be retrieved";
return index;
}
#endif
void AbstractShaderProgram::setUniform(const Int location, const Containers::ArrayView<const Float> values) {
(this->*Context::current().state().shaderProgram->uniform1fvImplementation)(location, values.size(), values);
}

99
src/Magnum/AbstractShaderProgram.h

@ -238,6 +238,57 @@ Int normalMatrixUniform = uniformLocation("normalMatrix");
@requires_gles Explicit uniform location is not supported in WebGL. Use
@ref uniformLocation() instead.
@anchor AbstractShaderProgram-uniform-block-binding
### Uniform block bindings
The preferred workflow is to specify uniform block binding directly in the
shader code, e.g.:
@code
// GLSL 4.20, GLSL ES 3.10 or
#extension GL_ARB_shading_language_420pack: require
layout(std140, binding = 0) uniform matrices {
mat4 projectionMatrix;
mat4 transformationMatrix;
};
layout(std140, binding = 1) uniform material {
vec4 diffuse;
vec4 specular;
};
@endcode
If you don't have the required version/extension, declare the uniform blocks
without the `layout()` qualifier, get uniform block index using
@ref uniformBlockIndex() and then map it to the uniform buffer binding using
@ref setUniformBlockBinding(). Note that additional syntax changes may be
needed for GLSL ES.
@code
layout(std140) uniform matrices {
mat4 projectionMatrix;
mat4 transformationMatrix;
};
layout(std140) uniform material {
vec4 diffuse;
vec4 specular;
};
@endcode
@code
setUniformBlockBinding(uniformBlockIndex("matrices"), 0);
setUniformBlockBinding(uniformBlockIndex("material"), 1);
@endcode
@see @ref Buffer::maxUniformBindings()
@requires_gl31 Extension @extension{ARB,uniform_buffer_object}
@requires_gl42 Extension @extension{ARB,shading_language_420pack} for explicit
uniform block binding instead of using @ref uniformBlockIndex() and
@ref setUniformBlockBinding().
@requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
@requires_gles31 Explicit uniform block binding is not supported in OpenGL ES
3.0 and older. Use @ref uniformBlockIndex() and @ref setUniformBlockBinding()
instead.
@requires_webgl20 Uniform buffers are not available in WebGL 1.0.
@requires_gles Explicit uniform block binding is not supported in WebGL. Use
@ref uniformBlockIndex() and @ref setUniformBlockBinding() instead.
@anchor AbstractShaderProgram-texture-units
### Specifying texture binding units
@ -878,6 +929,32 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject {
return uniformLocationInternal({name, size - 1});
}
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Get uniform block index
* @param name Uniform block name
*
* If given uniform block name is not found in the linked shader, a
* warning is printed and `0xffffffffu` is returned.
* @see @ref setUniformBlockBinding(), @fn_gl{GetUniformBlockIndex}
* @requires_gl31 Extension @extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
* @deprecated_gl Preferred usage is to specify uniform block binding
* explicitly in the shader instead of using this function. See
* @ref AbstractShaderProgram-uniform-block-binding "class documentation"
* for more information.
*/
UnsignedInt uniformBlockIndex(const std::string& name) {
return uniformBlockIndexInternal({name.data(), name.size()});
}
/** @overload */
template<std::size_t size> UnsignedInt uniformBlockIndex(const char(&name)[size]) {
return uniformBlockIndexInternal({name, size - 1});
}
#endif
/**
* @brief Set uniform value
* @param location Uniform location
@ -1012,6 +1089,27 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject {
}
#endif
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Set uniform block binding
* @param index Uniform block index
* @param binding Uniform block binding
*
* @see @ref uniformBlockIndex(), @ref Buffer::maxUniformBindings(),
* @fn_gl{UniformBlockBinding}
* @requires_gl31 Extension @extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
* @deprecated_gl Preferred usage is to specify uniform block binding
* explicitly in the shader instead of using this function. See
* @ref AbstractShaderProgram-uniform-block-binding "class documentation"
* for more information.
*/
void setUniformBlockBinding(UnsignedInt index, UnsignedInt binding) {
glUniformBlockBinding(_id, index, binding);
}
#endif
private:
#ifndef MAGNUM_TARGET_WEBGL
AbstractShaderProgram& setLabelInternal(Containers::ArrayView<const char> label);
@ -1021,6 +1119,7 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject {
void bindFragmentDataLocationIndexedInternal(UnsignedInt location, UnsignedInt index, Containers::ArrayView<const char> name);
void bindFragmentDataLocationInternal(UnsignedInt location, Containers::ArrayView<const char> name);
Int uniformLocationInternal(Containers::ArrayView<const char> name);
UnsignedInt uniformBlockIndexInternal(Containers::ArrayView<const char> name);
#ifndef MAGNUM_BUILD_DEPRECATED
void use();

159
src/Magnum/Test/AbstractShaderProgramGLTest.cpp

@ -56,6 +56,12 @@ struct AbstractShaderProgramGLTest: AbstractOpenGLTester {
void uniformVector();
void uniformMatrix();
void uniformArray();
#ifndef MAGNUM_TARGET_GLES2
void createUniformBlocks();
void uniformBlockIndexNotFound();
void uniformBlock();
#endif
};
AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() {
@ -75,7 +81,14 @@ AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() {
&AbstractShaderProgramGLTest::uniform,
&AbstractShaderProgramGLTest::uniformVector,
&AbstractShaderProgramGLTest::uniformMatrix,
&AbstractShaderProgramGLTest::uniformArray});
&AbstractShaderProgramGLTest::uniformArray,
#ifndef MAGNUM_TARGET_GLES2
&AbstractShaderProgramGLTest::createUniformBlocks,
&AbstractShaderProgramGLTest::uniformBlockIndexNotFound,
&AbstractShaderProgramGLTest::uniformBlock
#endif
});
}
namespace {
@ -148,6 +161,9 @@ namespace {
#endif
using AbstractShaderProgram::link;
using AbstractShaderProgram::uniformLocation;
#ifndef MAGNUM_TARGET_GLES2
using AbstractShaderProgram::uniformBlockIndex;
#endif
};
}
@ -473,6 +489,147 @@ void AbstractShaderProgramGLTest::uniformArray() {
MAGNUM_VERIFY_NO_ERROR();
}
#ifndef MAGNUM_TARGET_GLES2
void AbstractShaderProgramGLTest::createUniformBlocks() {
Utility::Resource rs("AbstractShaderProgramGLTest");
Shader vert(
#ifndef MAGNUM_TARGET_GLES
Version::GL310
#else
Version::GLES300
#endif
, Shader::Type::Vertex);
vert.addSource(rs.get("UniformBlockShader.vert"));
const bool vertCompiled = vert.compile();
Shader frag(
#ifndef MAGNUM_TARGET_GLES
Version::GL310
#else
Version::GLES300
#endif
, Shader::Type::Fragment);
frag.addSource(rs.get("UniformBlockShader.frag"));
const bool fragCompiled = frag.compile();
MAGNUM_VERIFY_NO_ERROR();
CORRADE_VERIFY(vertCompiled);
CORRADE_VERIFY(fragCompiled);
MyPublicShader program;
program.attachShaders({vert, frag});
MAGNUM_VERIFY_NO_ERROR();
const bool linked = program.link();
const bool valid = program.validate().first;
MAGNUM_VERIFY_NO_ERROR();
CORRADE_VERIFY(linked);
{
#ifdef CORRADE_TARGET_APPLE
CORRADE_EXPECT_FAIL("OSX drivers need insane amount of state to validate properly.");
#endif
CORRADE_VERIFY(valid);
}
const Int matricesUniformBlock = program.uniformBlockIndex("matrices");
const Int materialUniformBlock = program.uniformBlockIndex("material");
MAGNUM_VERIFY_NO_ERROR();
CORRADE_VERIFY(matricesUniformBlock >= 0);
CORRADE_VERIFY(materialUniformBlock >= 0);
}
void AbstractShaderProgramGLTest::uniformBlockIndexNotFound() {
MyPublicShader program;
Shader vert(
#ifndef MAGNUM_TARGET_GLES
Version::GL310
#else
Version::GLES200
#endif
, Shader::Type::Vertex);
Shader frag(
#ifndef MAGNUM_TARGET_GLES
Version::GL310
#else
Version::GLES200
#endif
, Shader::Type::Fragment);
vert.addSource("void main() { gl_Position = vec4(0.0); }");
frag.addSource("out vec4 color;\n"
"void main() { color = vec4(1.0); }");
CORRADE_VERIFY(Shader::compile({vert, frag}));
program.attachShaders({vert, frag});
CORRADE_VERIFY(program.link());
std::ostringstream out;
Warning::setOutput(&out);
program.uniformBlockIndex("nonexistent");
program.uniformBlockIndex(std::string{"another"});
CORRADE_COMPARE(out.str(),
"AbstractShaderProgram: index of uniform block 'nonexistent' cannot be retrieved\n"
"AbstractShaderProgram: index of uniform block 'another' cannot be retrieved\n");
}
namespace {
struct UniformBlockShader: AbstractShaderProgram {
explicit UniformBlockShader();
using AbstractShaderProgram::setUniformBlockBinding;
Int matricesUniformBlock,
materialUniformBlock;
};
}
#ifndef DOXYGEN_GENERATING_OUTPUT
UniformBlockShader::UniformBlockShader() {
Utility::Resource rs("AbstractShaderProgramGLTest");
Shader vert(
#ifndef MAGNUM_TARGET_GLES
Version::GL310
#else
Version::GLES300
#endif
, Shader::Type::Vertex);
Shader frag(
#ifndef MAGNUM_TARGET_GLES
Version::GL310
#else
Version::GLES300
#endif
, Shader::Type::Fragment);
vert.addSource(rs.get("UniformBlockShader.vert"));
frag.addSource(rs.get("UniformBlockShader.frag"));
Shader::compile({vert, frag});
attachShaders({vert, frag});
link();
matricesUniformBlock = uniformBlockIndex("matrices");
materialUniformBlock = uniformBlockIndex("material");
}
#endif
void AbstractShaderProgramGLTest::uniformBlock() {
UniformBlockShader shader;
MAGNUM_VERIFY_NO_ERROR();
shader.setUniformBlockBinding(shader.matricesUniformBlock, 0);
shader.setUniformBlockBinding(shader.materialUniformBlock, 1);
MAGNUM_VERIFY_NO_ERROR();
}
#endif
}}
MAGNUM_GL_TEST_MAIN(Magnum::Test::AbstractShaderProgramGLTest)

11
src/Magnum/Test/AbstractShaderProgramGLTestFiles/UniformBlockShader.frag

@ -0,0 +1,11 @@
layout(std140) uniform material {
lowp vec4 color;
lowp vec4 additions[3];
lowp float multiplier;
};
out lowp vec4 fragColor;
void main() {
fragColor = color*multiplier + additions[0] + additions[1] + additions[2];
}

10
src/Magnum/Test/AbstractShaderProgramGLTestFiles/UniformBlockShader.vert

@ -0,0 +1,10 @@
in mediump vec4 position;
layout(std140) uniform matrices {
mediump mat4 transformation;
mediump mat4 projection;
};
void main() {
gl_Position = projection*transformation*position;
}

6
src/Magnum/Test/AbstractShaderProgramGLTestFiles/resources.conf

@ -8,3 +8,9 @@ filename=MyShader.vert
[file]
filename=MyShaderFragmentOutputs.frag
[file]
filename=UniformBlockShader.frag
[file]
filename=UniformBlockShader.vert

Loading…
Cancel
Save