From 807768138877e18a54415bb651ef82a83929cb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 27 May 2021 18:09:55 +0200 Subject: [PATCH] Shaders: supply Vector material information in a separate UBO as well. So it's all having the same workflow. This one results in even more saved UBO slots per-draw than in the case of Flat, and the slowdown on Intel is as bad as expected. --- .../Shaders/Test/ShadersGLBenchmark.cpp | 23 +-- src/Magnum/Shaders/Test/VectorGLTest.cpp | 167 +++++++++++++----- src/Magnum/Shaders/Test/VectorTest.cpp | 91 ++++++++-- src/Magnum/Shaders/Vector.frag | 24 ++- src/Magnum/Shaders/Vector.h | 145 +++++++++++---- src/Magnum/Shaders/VectorGL.cpp | 32 +++- src/Magnum/Shaders/VectorGL.h | 65 +++++-- 7 files changed, 423 insertions(+), 124 deletions(-) diff --git a/src/Magnum/Shaders/Test/ShadersGLBenchmark.cpp b/src/Magnum/Shaders/Test/ShadersGLBenchmark.cpp index 15cd1f835..dc2cf2e5f 100644 --- a/src/Magnum/Shaders/Test/ShadersGLBenchmark.cpp +++ b/src/Magnum/Shaders/Test/ShadersGLBenchmark.cpp @@ -204,16 +204,16 @@ const struct { const struct { const char* name; VectorGL2D::Flags flags; - UnsignedInt drawCount; + UnsignedInt materialCount, drawCount; } VectorData[] { - {"", {}, 1}, - {"texture transformation", VectorGL2D::Flag::TextureTransformation, 1}, + {"", {}, 1, 1}, + {"texture transformation", VectorGL2D::Flag::TextureTransformation, 1, 1}, #ifndef MAGNUM_TARGET_GLES2 - {"UBO single", VectorGL2D::Flag::UniformBuffers, 1}, - {"UBO single, texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 1}, - {"UBO multi", VectorGL2D::Flag::UniformBuffers, 128}, - {"UBO multi, texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 128}, - {"multidraw", VectorGL2D::Flag::MultiDraw, 128}, + {"UBO single", VectorGL2D::Flag::UniformBuffers, 1, 1}, + {"UBO single, texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 1, 1}, + {"UBO multi", VectorGL2D::Flag::UniformBuffers, 32, 128}, + {"UBO multi, texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 32, 128}, + {"multidraw", VectorGL2D::Flag::MultiDraw, 32, 128}, #endif }; @@ -826,7 +826,7 @@ template void ShadersGLBenchmark::vector() { VectorGL shader{data.flags #ifndef MAGNUM_TARGET_GLES2 - , data.drawCount + , data.materialCount, data.drawCount #endif }; shader.bindVectorTexture(_textureWhite); @@ -835,11 +835,14 @@ template void ShadersGLBenchmark::vector() { GL::Buffer transformationProjectionUniform{NoCreate}; GL::Buffer drawUniform{NoCreate}; GL::Buffer textureTransformationUniform{NoCreate}; + GL::Buffer materialUniform{NoCreate}; if(data.flags & VectorGL2D::Flag::UniformBuffers) { transformationProjectionUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array::TransformationProjection>{data.drawCount}}; drawUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array{data.drawCount}}; + materialUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array{data.materialCount}}; shader.bindTransformationProjectionBuffer(transformationProjectionUniform) - .bindDrawBuffer(drawUniform); + .bindDrawBuffer(drawUniform) + .bindMaterialBuffer(materialUniform); if(data.flags & VectorGL2D::Flag::TextureTransformation) { textureTransformationUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, { TextureTransformationUniform{} diff --git a/src/Magnum/Shaders/Test/VectorGLTest.cpp b/src/Magnum/Shaders/Test/VectorGLTest.cpp index 1f5260c95..ce9a77d21 100644 --- a/src/Magnum/Shaders/Test/VectorGLTest.cpp +++ b/src/Magnum/Shaders/Test/VectorGLTest.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "Magnum/Image.h" #include "Magnum/ImageView.h" @@ -85,7 +86,7 @@ struct VectorGLTest: GL::OpenGLTester { #endif #ifndef MAGNUM_TARGET_GLES2 - template void constructUniformBuffersZeroDraws(); + template void constructUniformBuffersInvalid(); #endif #ifndef MAGNUM_TARGET_GLES2 @@ -165,15 +166,29 @@ constexpr struct { constexpr struct { const char* name; VectorGL2D::Flags flags; - UnsignedInt drawCount; + UnsignedInt materialCount, drawCount; } ConstructUniformBuffersData[]{ - {"classic fallback", {}, 1}, - {"", VectorGL2D::Flag::UniformBuffers, 1}, - {"texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 1}, - /* SwiftShader has 256 uniform vectors at most, per-draw is 4+3 in 3D case - and 3+3 in 2D */ - {"multiple draws", VectorGL2D::Flag::UniformBuffers, 36}, - {"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 36} + {"classic fallback", {}, 1, 1}, + {"", VectorGL2D::Flag::UniformBuffers, 1, 1}, + {"texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 1, 1}, + /* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case + and 3+1 in 2D, per-material 3 */ + {"multiple materials, draws", VectorGL2D::Flag::UniformBuffers, 15, 42}, + {"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 15, 42} +}; +#endif + +#ifndef MAGNUM_TARGET_GLES2 +constexpr struct { + const char* name; + VectorGL2D::Flags flags; + UnsignedInt materialCount, drawCount; + const char* message; +} ConstructUniformBuffersInvalidData[]{ + {"zero draws", VectorGL2D::Flag::UniformBuffers, 1, 0, + "draw count can't be zero"}, + {"zero materials", VectorGL2D::Flag::UniformBuffers, 0, 1, + "material count can't be zero"}, }; #endif @@ -200,20 +215,20 @@ constexpr struct { const char* expected2D; const char* expected3D; VectorGL2D::Flags flags; - UnsignedInt drawCount; + UnsignedInt materialCount, drawCount; UnsignedInt uniformIncrement; Float maxThreshold, meanThreshold; } RenderMultiData[] { {"bind with offset", "multidraw2D.tga", "multidraw3D.tga", - {}, 1, 16, + {}, 1, 1, 16, /* Minor differences on ARM Mali */ 1.34f, 0.02f}, {"draw offset", "multidraw2D.tga", "multidraw3D.tga", - {}, 3, 1, + {}, 2, 3, 1, /* Minor differences on ARM Mali */ 1.34f, 0.02f}, {"multidraw", "multidraw2D.tga", "multidraw3D.tga", - VectorGL2D::Flag::MultiDraw, 3, 1, + VectorGL2D::Flag::MultiDraw, 2, 3, 1, /* Minor differences on ARM Mali */ 1.34f, 0.02f}, }; @@ -240,12 +255,16 @@ VectorGLTest::VectorGLTest() { &VectorGLTest::constructMoveUniformBuffers<2>, &VectorGLTest::constructMoveUniformBuffers<3>, #endif + }); - #ifndef MAGNUM_TARGET_GLES2 - &VectorGLTest::constructUniformBuffersZeroDraws<2>, - &VectorGLTest::constructUniformBuffersZeroDraws<3>, - #endif + #ifndef MAGNUM_TARGET_GLES2 + addInstancedTests({ + &VectorGLTest::constructUniformBuffersInvalid<2>, + &VectorGLTest::constructUniformBuffersInvalid<3>}, + Containers::arraySize(ConstructUniformBuffersInvalidData)); + #endif + addTests({ #ifndef MAGNUM_TARGET_GLES2 &VectorGLTest::setUniformUniformBuffersEnabled<2>, &VectorGLTest::setUniformUniformBuffersEnabled<3>, @@ -369,7 +388,7 @@ template void VectorGLTest::constructUniformBuffers() { #endif } - VectorGL shader{data.flags, data.drawCount}; + VectorGL shader{data.flags, data.materialCount, data.drawCount}; CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.drawCount(), data.drawCount); CORRADE_VERIFY(shader.id()); @@ -414,7 +433,7 @@ template void VectorGLTest::constructMoveUniformBuffers( CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); #endif - VectorGL a{VectorGL::Flag::UniformBuffers, 5}; + VectorGL a{VectorGL::Flag::UniformBuffers, 2, 5}; const GLuint id = a.id(); CORRADE_VERIFY(id); @@ -423,6 +442,7 @@ template void VectorGLTest::constructMoveUniformBuffers( VectorGL b{std::move(a)}; CORRADE_COMPARE(b.id(), id); CORRADE_COMPARE(b.flags(), VectorGL::Flag::UniformBuffers); + CORRADE_COMPARE(b.materialCount(), 2); CORRADE_COMPARE(b.drawCount(), 5); CORRADE_VERIFY(!a.id()); @@ -430,14 +450,17 @@ template void VectorGLTest::constructMoveUniformBuffers( c = std::move(b); CORRADE_COMPARE(c.id(), id); CORRADE_COMPARE(c.flags(), VectorGL::Flag::UniformBuffers); + CORRADE_COMPARE(c.materialCount(), 2); CORRADE_COMPARE(c.drawCount(), 5); CORRADE_VERIFY(!b.id()); } #endif #ifndef MAGNUM_TARGET_GLES2 -template void VectorGLTest::constructUniformBuffersZeroDraws() { +template void VectorGLTest::constructUniformBuffersInvalid() { + auto&& data = ConstructUniformBuffersInvalidData[testCaseInstanceId()]; setTestCaseTemplateName(std::to_string(dimensions)); + setTestCaseDescription(data.name); #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -450,9 +473,9 @@ template void VectorGLTest::constructUniformBuffersZeroD std::ostringstream out; Error redirectError{&out}; - VectorGL{VectorGL::Flag::UniformBuffers, 0}; - CORRADE_COMPARE(out.str(), - "Shaders::VectorGL: draw count can't be zero\n"); + VectorGL{data.flags, data.materialCount, data.drawCount}; + CORRADE_COMPARE(out.str(), Utility::formatString( + "Shaders::VectorGL: {}\n", data.message)); } #endif @@ -502,6 +525,8 @@ template void VectorGLTest::bindBufferUniformBuffersNotE .bindDrawBuffer(buffer, 0, 16) .bindTextureTransformationBuffer(buffer) .bindTextureTransformationBuffer(buffer, 0, 16) + .bindMaterialBuffer(buffer) + .bindMaterialBuffer(buffer, 0, 16) .setDrawOffset(0); CORRADE_COMPARE(out.str(), "Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n" @@ -510,6 +535,8 @@ template void VectorGLTest::bindBufferUniformBuffersNotE "Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled\n" "Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled\n" "Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled\n" + "Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n" + "Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n" "Shaders::VectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled\n"); } #endif @@ -572,7 +599,7 @@ template void VectorGLTest::setWrongDrawOffset() { std::ostringstream out; Error redirectError{&out}; - VectorGL{VectorGL::Flag::UniformBuffers, 5} + VectorGL{VectorGL::Flag::UniformBuffers, 2, 5} .setDrawOffset(5); CORRADE_COMPARE(out.str(), "Shaders::VectorGL::setDrawOffset(): draw offset 5 is out of bounds for 5 draws\n"); @@ -665,8 +692,12 @@ template void VectorGLTest::renderDefaults2D() { GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { VectorDrawUniform{} }}; + GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { + VectorMaterialUniform{} + }}; shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) + .bindMaterialBuffer(materialUniform) .draw(square); } #endif @@ -740,8 +771,12 @@ template void VectorGLTest::renderDefaults3D() { GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { VectorDrawUniform{} }}; + GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { + VectorMaterialUniform{} + }}; shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) + .bindMaterialBuffer(materialUniform) .draw(plane); } #endif @@ -829,17 +864,21 @@ template void VectorGLTest::render2D() { }}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { VectorDrawUniform{} - .setBackgroundColor(data.backgroundColor) - .setColor(data.color) }}; GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, { TextureTransformationUniform{} .setTextureMatrix(data.textureTransformation) }}; + GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { + VectorMaterialUniform{} + .setBackgroundColor(data.backgroundColor) + .setColor(data.color) + }}; if(data.flags & VectorGL2D::Flag::TextureTransformation) shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) + .bindMaterialBuffer(materialUniform) .draw(square); } #endif @@ -934,17 +973,21 @@ template void VectorGLTest::render3D() { }}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { VectorDrawUniform{} - .setBackgroundColor(data.backgroundColor) - .setColor(data.color) }}; GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, { TextureTransformationUniform{} .setTextureMatrix(data.textureTransformation) }}; + GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { + VectorMaterialUniform{} + .setBackgroundColor(data.backgroundColor) + .setColor(data.color) + }}; if(data.flags & VectorGL3D::Flag::TextureTransformation) shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) + .bindMaterialBuffer(materialUniform) .draw(plane); } #endif @@ -1031,6 +1074,15 @@ void VectorGLTest::renderMulti2D() { The data.uniformIncrement is set high enough to ensure that, in the non-offset-bind case this value is 1. */ + Containers::Array materialData{data.uniformIncrement + 1}; + materialData[0*data.uniformIncrement] = VectorMaterialUniform{} + .setColor(0xff0000_rgbf) + .setBackgroundColor(0xffcccc_rgbf); + materialData[1*data.uniformIncrement] = VectorMaterialUniform{} + .setColor(0x00ff00_rgbf) + .setBackgroundColor(0xccffcc_rgbf); + GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, materialData}; + Containers::Array transformationProjectionData{2*data.uniformIncrement + 1}; transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform2D{} .setTransformationProjectionMatrix( @@ -1069,22 +1121,24 @@ void VectorGLTest::renderMulti2D() { GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData}; Containers::Array drawData{2*data.uniformIncrement + 1}; + /* Material offsets are zero if we have single draw, as those are done with + UBO offset bindings instead. */ drawData[0*data.uniformIncrement] = VectorDrawUniform{} - .setColor(0x00ff00_rgbf) - .setBackgroundColor(0xccffcc_rgbf); + .setMaterialId(data.drawCount == 1 ? 0 : 1); drawData[1*data.uniformIncrement] = VectorDrawUniform{} - .setColor(0xff0000_rgbf) - .setBackgroundColor(0xffcccc_rgbf); + .setMaterialId(data.drawCount == 1 ? 0 : 0); drawData[2*data.uniformIncrement] = VectorDrawUniform{} - .setColor(0x00ff00_rgbf) - .setBackgroundColor(0xccffcc_rgbf); + .setMaterialId(data.drawCount == 1 ? 0 : 1); GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; - VectorGL2D shader{VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation|data.flags, data.drawCount}; + VectorGL2D shader{VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation|data.flags, data.materialCount, data.drawCount}; shader.bindVectorTexture(vector); /* Just one draw, rebinding UBOs each time */ if(data.drawCount == 1) { + shader.bindMaterialBuffer(materialUniform, + 1*data.uniformIncrement*sizeof(VectorMaterialUniform), + sizeof(VectorMaterialUniform)); shader.bindTransformationProjectionBuffer(transformationProjectionUniform, 0*data.uniformIncrement*sizeof(TransformationProjectionUniform2D), sizeof(TransformationProjectionUniform2D)); @@ -1096,6 +1150,9 @@ void VectorGLTest::renderMulti2D() { sizeof(TextureTransformationUniform)); shader.draw(circle); + shader.bindMaterialBuffer(materialUniform, + 0*data.uniformIncrement*sizeof(VectorMaterialUniform), + sizeof(VectorMaterialUniform)); shader.bindTransformationProjectionBuffer(transformationProjectionUniform, 1*data.uniformIncrement*sizeof(TransformationProjectionUniform2D), sizeof(TransformationProjectionUniform2D)); @@ -1107,6 +1164,9 @@ void VectorGLTest::renderMulti2D() { sizeof(TextureTransformationUniform)); shader.draw(square); + shader.bindMaterialBuffer(materialUniform, + 1*data.uniformIncrement*sizeof(VectorMaterialUniform), + sizeof(VectorMaterialUniform)); shader.bindTransformationProjectionBuffer(transformationProjectionUniform, 2*data.uniformIncrement*sizeof(TransformationProjectionUniform2D), sizeof(TransformationProjectionUniform2D)); @@ -1122,7 +1182,8 @@ void VectorGLTest::renderMulti2D() { } else { shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) - .bindTextureTransformationBuffer(textureTransformationUniform); + .bindTextureTransformationBuffer(textureTransformationUniform) + .bindMaterialBuffer(materialUniform); if(data.flags >= VectorGL2D::Flag::MultiDraw) shader.draw({circle, square, triangle}); @@ -1209,6 +1270,15 @@ void VectorGLTest::renderMulti3D() { The data.uniformIncrement is set high enough to ensure that, in the non-offset-bind case this value is 1. */ + Containers::Array materialData{data.uniformIncrement + 1}; + materialData[0*data.uniformIncrement] = VectorMaterialUniform{} + .setColor(0xff0000_rgbf) + .setBackgroundColor(0xffcccc_rgbf); + materialData[1*data.uniformIncrement] = VectorMaterialUniform{} + .setColor(0x00ff00_rgbf) + .setBackgroundColor(0xccffcc_rgbf); + GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, materialData}; + Containers::Array transformationProjectionData{2*data.uniformIncrement + 1}; transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform3D{} .setTransformationProjectionMatrix( @@ -1252,22 +1322,24 @@ void VectorGLTest::renderMulti3D() { GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData}; Containers::Array drawData{2*data.uniformIncrement + 1}; + /* Material offsets are zero if we have single draw, as those are done with + UBO offset bindings instead. */ drawData[0*data.uniformIncrement] = VectorDrawUniform{} - .setColor(0x00ff00_rgbf) - .setBackgroundColor(0xccffcc_rgbf); + .setMaterialId(data.drawCount == 1 ? 0 : 1); drawData[1*data.uniformIncrement] = VectorDrawUniform{} - .setColor(0xff0000_rgbf) - .setBackgroundColor(0xffcccc_rgbf); + .setMaterialId(data.drawCount == 1 ? 0 : 0); drawData[2*data.uniformIncrement] = VectorDrawUniform{} - .setColor(0x00ff00_rgbf) - .setBackgroundColor(0xccffcc_rgbf); + .setMaterialId(data.drawCount == 1 ? 0 : 1); GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; - VectorGL3D shader{VectorGL3D::Flag::UniformBuffers|VectorGL3D::Flag::TextureTransformation|data.flags, data.drawCount}; + VectorGL3D shader{VectorGL3D::Flag::UniformBuffers|VectorGL3D::Flag::TextureTransformation|data.flags, data.materialCount, data.drawCount}; shader.bindVectorTexture(vector); /* Just one draw, rebinding UBOs each time */ if(data.drawCount == 1) { + shader.bindMaterialBuffer(materialUniform, + 1*data.uniformIncrement*sizeof(VectorMaterialUniform), + sizeof(VectorMaterialUniform)); shader.bindTransformationProjectionBuffer(transformationProjectionUniform, 0*data.uniformIncrement*sizeof(TransformationProjectionUniform3D), sizeof(TransformationProjectionUniform3D)); @@ -1279,6 +1351,9 @@ void VectorGLTest::renderMulti3D() { sizeof(TextureTransformationUniform)); shader.draw(sphere); + shader.bindMaterialBuffer(materialUniform, + 0*data.uniformIncrement*sizeof(VectorMaterialUniform), + sizeof(VectorMaterialUniform)); shader.bindTransformationProjectionBuffer(transformationProjectionUniform, 1*data.uniformIncrement*sizeof(TransformationUniform3D), sizeof(TransformationUniform3D)); @@ -1290,6 +1365,9 @@ void VectorGLTest::renderMulti3D() { sizeof(TextureTransformationUniform)); shader.draw(plane); + shader.bindMaterialBuffer(materialUniform, + 1*data.uniformIncrement*sizeof(VectorMaterialUniform), + sizeof(VectorMaterialUniform)); shader.bindTransformationProjectionBuffer(transformationProjectionUniform, 2*data.uniformIncrement*sizeof(TransformationUniform3D), sizeof(TransformationUniform3D)); @@ -1305,7 +1383,8 @@ void VectorGLTest::renderMulti3D() { } else { shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) - .bindTextureTransformationBuffer(textureTransformationUniform); + .bindTextureTransformationBuffer(textureTransformationUniform) + .bindMaterialBuffer(materialUniform); if(data.flags >= VectorGL3D::Flag::MultiDraw) shader.draw({sphere, plane, cone}); diff --git a/src/Magnum/Shaders/Test/VectorTest.cpp b/src/Magnum/Shaders/Test/VectorTest.cpp index fffb94115..12985d5ba 100644 --- a/src/Magnum/Shaders/Test/VectorTest.cpp +++ b/src/Magnum/Shaders/Test/VectorTest.cpp @@ -38,14 +38,25 @@ struct VectorTest: TestSuite::Tester { void drawUniformConstructDefault(); void drawUniformConstructNoInit(); void drawUniformSetters(); + void drawUniformMaterialIdPacking(); + + void materialUniformConstructDefault(); + void materialUniformConstructNoInit(); + void materialUniformSetters(); }; VectorTest::VectorTest() { addTests({&VectorTest::uniformSizeAlignment, + &VectorTest::uniformSizeAlignment, &VectorTest::drawUniformConstructDefault, &VectorTest::drawUniformConstructNoInit, - &VectorTest::drawUniformSetters}); + &VectorTest::drawUniformSetters, + &VectorTest::drawUniformMaterialIdPacking, + + &VectorTest::materialUniformConstructDefault, + &VectorTest::materialUniformConstructNoInit, + &VectorTest::materialUniformSetters}); } using namespace Math::Literals; @@ -54,6 +65,9 @@ template struct UniformTraits; template<> struct UniformTraits { static const char* name() { return "VectorDrawUniform"; } }; +template<> struct UniformTraits { + static const char* name() { return "VectorMaterialUniform"; } +}; template void VectorTest::uniformSizeAlignment() { setTestCaseTemplateName(UniformTraits::name()); @@ -72,17 +86,13 @@ template void VectorTest::uniformSizeAlignment() { void VectorTest::drawUniformConstructDefault() { VectorDrawUniform a; VectorDrawUniform b{DefaultInit}; - CORRADE_COMPARE(a.color, 0xffffffff_rgbaf); - CORRADE_COMPARE(b.color, 0xffffffff_rgbaf); - CORRADE_COMPARE(a.backgroundColor, 0x00000000_rgbaf); - CORRADE_COMPARE(b.backgroundColor, 0x00000000_rgbaf); + CORRADE_COMPARE(a.materialId, 0); + CORRADE_COMPARE(b.materialId, 0); constexpr VectorDrawUniform ca; constexpr VectorDrawUniform cb{DefaultInit}; - CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf); - CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf); - CORRADE_COMPARE(ca.backgroundColor, 0x00000000_rgbaf); - CORRADE_COMPARE(cb.backgroundColor, 0x00000000_rgbaf); + CORRADE_COMPARE(ca.materialId, 0); + CORRADE_COMPARE(cb.materialId, 0); CORRADE_VERIFY(std::is_nothrow_default_constructible::value); CORRADE_VERIFY(std::is_nothrow_constructible::value); @@ -94,16 +104,14 @@ void VectorTest::drawUniformConstructDefault() { void VectorTest::drawUniformConstructNoInit() { /* Testing only some fields, should be enough */ VectorDrawUniform a; - a.color = 0x354565fc_rgbaf; - a.backgroundColor = 0x98769facb_rgbaf; + a.materialId = 5; new(&a) VectorDrawUniform{NoInit}; { #if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__ CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value."); #endif - CORRADE_COMPARE(a.color, 0x354565fc_rgbaf); - CORRADE_COMPARE(a.backgroundColor, 0x98769facb_rgbaf); + CORRADE_COMPARE(a.materialId, 5); } CORRADE_VERIFY(std::is_nothrow_constructible::value); @@ -114,6 +122,63 @@ void VectorTest::drawUniformConstructNoInit() { void VectorTest::drawUniformSetters() { VectorDrawUniform a; + a.setMaterialId(5); + CORRADE_COMPARE(a.materialId, 5); +} + +void VectorTest::drawUniformMaterialIdPacking() { + VectorDrawUniform a; + a.setMaterialId(13765); + /* materialId should be right at the beginning, in the low 16 bits on both + LE and BE */ + CORRADE_COMPARE(reinterpret_cast(&a)[0] & 0xffff, 13765); +} + +void VectorTest::materialUniformConstructDefault() { + VectorMaterialUniform a; + VectorMaterialUniform b{DefaultInit}; + CORRADE_COMPARE(a.color, 0xffffffff_rgbaf); + CORRADE_COMPARE(b.color, 0xffffffff_rgbaf); + CORRADE_COMPARE(a.backgroundColor, 0x00000000_rgbaf); + CORRADE_COMPARE(b.backgroundColor, 0x00000000_rgbaf); + + constexpr VectorMaterialUniform ca; + constexpr VectorMaterialUniform cb{DefaultInit}; + CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf); + CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf); + CORRADE_COMPARE(ca.backgroundColor, 0x00000000_rgbaf); + CORRADE_COMPARE(cb.backgroundColor, 0x00000000_rgbaf); + + CORRADE_VERIFY(std::is_nothrow_default_constructible::value); + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); +} + +void VectorTest::materialUniformConstructNoInit() { + /* Testing only some fields, should be enough */ + VectorMaterialUniform a; + a.color = 0x354565fc_rgbaf; + a.backgroundColor = 0x98769facb_rgbaf; + + new(&a) VectorMaterialUniform{NoInit}; + { + #if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__ + CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value."); + #endif + CORRADE_COMPARE(a.color, 0x354565fc_rgbaf); + CORRADE_COMPARE(a.backgroundColor, 0x98769facb_rgbaf); + } + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); +} + +void VectorTest::materialUniformSetters() { + VectorMaterialUniform a; a.setColor(0x354565fc_rgbaf) .setBackgroundColor(0x98769facb_rgbaf); CORRADE_COMPARE(a.color, 0x354565fc_rgbaf); diff --git a/src/Magnum/Shaders/Vector.frag b/src/Magnum/Shaders/Vector.frag index 8f1993944..a36e3a7a6 100644 --- a/src/Magnum/Shaders/Vector.frag +++ b/src/Magnum/Shaders/Vector.frag @@ -66,9 +66,8 @@ uniform highp uint drawOffset #endif struct DrawUniform { - lowp vec4 color; - lowp vec4 backgroundColor; - lowp uvec4 reserved; + highp uvec4 materialIdReservedReservedReservedReserved; + #define draw_materialIdReserved materialIdReservedReservedReservedReserved.x }; layout(std140 @@ -78,6 +77,20 @@ layout(std140 ) uniform Draw { DrawUniform draws[DRAW_COUNT]; }; + +struct MaterialUniform { + lowp vec4 color; + lowp vec4 backgroundColor; + lowp uvec4 reserved; +}; + +layout(std140 + #ifdef EXPLICIT_BINDING + , binding = 4 + #endif +) uniform Material { + MaterialUniform materials[MATERIAL_COUNT]; +}; #endif /* Textures */ @@ -106,8 +119,9 @@ out lowp vec4 fragmentColor; void main() { #ifdef UNIFORM_BUFFERS - lowp const vec4 color = draws[drawId].color; - lowp const vec4 backgroundColor = draws[drawId].backgroundColor; + mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu; + lowp const vec4 color = materials[materialId].color; + lowp const vec4 backgroundColor = materials[materialId].backgroundColor; #endif lowp float intensity = texture(vectorTexture, interpolatedTextureCoordinates).r; diff --git a/src/Magnum/Shaders/Vector.h b/src/Magnum/Shaders/Vector.h index f45ce9df5..4d6b44675 100644 --- a/src/Magnum/Shaders/Vector.h +++ b/src/Magnum/Shaders/Vector.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Struct @ref Magnum::Shaders::VectorDrawUniform + * @brief Struct @ref Magnum::Shaders::VectorDrawUniform, @ref Magnum::Shaders::VectorMaterialUniform */ #include "Magnum/Magnum.h" @@ -47,20 +47,121 @@ namespace Magnum { namespace Shaders { Together with the generic @ref TransformationProjectionUniform2D / @ref TransformationProjectionUniform3D contains parameters that are specific to each draw call. Texture transformation, if needed, is supplied separately in a -@ref TextureTransformationUniform. +@ref TextureTransformationUniform; material-related properties are expected to +be shared among multiple draw calls and thus are provided in a separate +@ref VectorMaterialUniform structure, referenced by @ref materialId. @see @ref VectorGL::bindDrawBuffer() */ struct VectorDrawUniform { /** @brief Construct with default parameters */ - constexpr explicit VectorDrawUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, backgroundColor{0.0f, 0.0f, 0.0f, 0.0f} + constexpr explicit VectorDrawUniform(DefaultInitT = DefaultInit) noexcept: + #if ((defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)) && defined(CORRADE_TARGET_BIG_ENDIAN) + _pad0{}, /* Otherwise it refuses to constexpr, on 3.8 at least */ + #endif + materialId{0} + #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) && !defined(CORRADE_TARGET_BIG_ENDIAN) + , _pad0{}, _pad1{}, _pad2{}, _pad3{} + #endif + {} + + /** @brief Construct without initializing the contents */ + explicit VectorDrawUniform(NoInitT) noexcept {} + + /** @{ + * @name Convenience setters + * + * Provided to allow the use of method chaining for populating a structure + * in a single expression, otherwise equivalent to accessing the fields + * directly. Also guaranteed to provide backwards compatibility when + * packing of the actual fields changes. + */ + + /** + * @brief Set the @ref materialId field + * @return Reference to self (for method chaining) + */ + VectorDrawUniform& setMaterialId(UnsignedInt id) { + materialId = id; + return *this; + } + + /** + * @} + */ + + /** @var materialId + * @brief Material ID + * + * References a particular material from a @ref VectorMaterialUniform + * array. Useful when an UBO with more than one material is supplied or in + * a multi-draw scenario. Should be less than the material count passed to + * the @ref VectorGL::VectorGL(Flags, UnsignedInt, UnsignedInt) + * constructor. Default value is @cpp 0 @ce, meaning the first material + * gets used. + */ + + /* This field is an UnsignedInt in the shader and materialId is extracted + as (value & 0xffff), so the order has to be different on BE */ + #ifndef CORRADE_TARGET_BIG_ENDIAN + alignas(4) UnsignedShort materialId; + /* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK + I MADE THOSE UNNAMED, YOU DUMB FOOL */ + #ifndef DOXYGEN_GENERATING_OUTPUT + UnsignedShort + #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) + _pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */ + #endif + :16; /* reserved for skinOffset */ + #endif + #else + alignas(4) UnsignedShort + #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) + _pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */ + #endif + :16; /* reserved for skinOffset */ + UnsignedShort materialId; + #endif + + /* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK + I MADE THOSE UNNAMED, YOU DUMB FOOL */ + #ifndef DOXYGEN_GENERATING_OUTPUT + Int + #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) + _pad1 /* Otherwise it refuses to constexpr, on 3.8 at least */ + #endif + :32; /* reserved for objectId */ + Int + #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) + _pad2 /* Otherwise it refuses to constexpr, on 3.8 at least */ + #endif + :32; + Int + #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) + _pad3 /* Otherwise it refuses to constexpr, on 3.8 at least */ + #endif + :32; + #endif +}; + +/** +@brief Material uniform for vector shaders +@m_since_latest + +Describes material properties referenced from +@ref VectorDrawUniform::materialId. +@see @ref VectorGL::bindMaterialBuffer() +*/ +struct VectorMaterialUniform { + /** @brief Construct with default parameters */ + constexpr explicit VectorMaterialUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, backgroundColor{0.0f, 0.0f, 0.0f, 0.0f} #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) /* Otherwise it refuses to constexpr, on 3.8 at least */ - , _pad0{}, _pad1{}, _pad2{}, _pad3{}, _pad4{} + , _pad0{}, _pad1{}, _pad2{}, _pad3{} #endif {} /** @brief Construct without initializing the contents */ - explicit VectorDrawUniform(NoInitT) noexcept: color{NoInit}, backgroundColor{NoInit} {} + explicit VectorMaterialUniform(NoInitT) noexcept: color{NoInit}, backgroundColor{NoInit} {} /** @{ * @name Convenience setters @@ -75,7 +176,7 @@ struct VectorDrawUniform { * @brief Set the @ref color field * @return Reference to self (for method chaining) */ - VectorDrawUniform& setColor(const Color4& color) { + VectorMaterialUniform& setColor(const Color4& color) { this->color = color; return *this; } @@ -84,7 +185,7 @@ struct VectorDrawUniform { * @brief Set the @ref backgroundColor field * @return Reference to self (for method chaining) */ - VectorDrawUniform& setBackgroundColor(const Color4& color) { + VectorMaterialUniform& setBackgroundColor(const Color4& color) { backgroundColor = color; return *this; } @@ -112,45 +213,25 @@ struct VectorDrawUniform { /* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK I MADE THOSE UNNAMED, YOU DUMB FOOL */ #ifndef DOXYGEN_GENERATING_OUTPUT - /* This field is an UnsignedInt in the shader and skinOffset is extracted - as (value >> 16), so the order has to be different on BE */ - #ifndef CORRADE_TARGET_BIG_ENDIAN - UnsignedShort - #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) - _pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */ - #endif - :16; - UnsignedShort - #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) - _pad1 /* Otherwise it refuses to constexpr, on 3.8 at least */ - #endif - :16; /* reserved for skinOffset */ - #else - UnsignedShort + Int #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) _pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */ #endif - :16; /* reserved for skinOffset */ - UnsignedShort + :32; /* reserved for alpha mask */ + Int #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) _pad1 /* Otherwise it refuses to constexpr, on 3.8 at least */ #endif - :16; - #endif + :32; Int #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) _pad2 /* Otherwise it refuses to constexpr, on 3.8 at least */ #endif - :32; /* reserved for objectId */ + :32; Int #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) _pad3 /* Otherwise it refuses to constexpr, on 3.8 at least */ #endif - :32; /* reserved for alphaMask */ - Int - #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) - _pad4 /* Otherwise it refuses to constexpr, on 3.8 at least */ - #endif :32; #endif }; diff --git a/src/Magnum/Shaders/VectorGL.cpp b/src/Magnum/Shaders/VectorGL.cpp index 9efddeb6b..bd98a6fdc 100644 --- a/src/Magnum/Shaders/VectorGL.cpp +++ b/src/Magnum/Shaders/VectorGL.cpp @@ -57,22 +57,25 @@ namespace { bound to the same buffer for the whole time */ TransformationProjectionBufferBinding = 1, DrawBufferBinding = 2, - TextureTransformationBufferBinding = 3 + TextureTransformationBufferBinding = 3, + MaterialBufferBinding = 4 }; #endif } template VectorGL::VectorGL(const Flags flags #ifndef MAGNUM_TARGET_GLES2 - , const UnsignedInt drawCount + , const UnsignedInt materialCount, const UnsignedInt drawCount #endif ): _flags{flags} #ifndef MAGNUM_TARGET_GLES2 - , _drawCount{drawCount} + , _materialCount{materialCount}, _drawCount{drawCount} #endif { #ifndef MAGNUM_TARGET_GLES2 + CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, + "Shaders::VectorGL: material count can't be zero", ); CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, "Shaders::VectorGL: draw count can't be zero", ); #endif @@ -128,8 +131,10 @@ template VectorGL::VectorGL(const Flags flag if(flags >= Flag::UniformBuffers) { frag.addSource(Utility::formatString( "#define UNIFORM_BUFFERS\n" - "#define DRAW_COUNT {}\n", - drawCount)); + "#define DRAW_COUNT {}\n" + "#define MATERIAL_COUNT {}\n", + drawCount, + materialCount)); frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : ""); } #endif @@ -182,6 +187,7 @@ template VectorGL::VectorGL(const Flags flag setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); if(flags & Flag::TextureTransformation) setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding); + setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding); } #endif } @@ -204,7 +210,7 @@ template VectorGL::VectorGL(const Flags flag } #ifndef MAGNUM_TARGET_GLES2 -template VectorGL::VectorGL(const Flags flags): VectorGL{flags, 1} {} +template VectorGL::VectorGL(const Flags flags): VectorGL{flags, 1, 1} {} #endif template VectorGL& VectorGL::setTransformationProjectionMatrix(const MatrixTypeFor& matrix) { @@ -300,6 +306,20 @@ template VectorGL& VectorGL::bin buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size); return *this; } + +template VectorGL& VectorGL::bindMaterialBuffer(GL::Buffer& buffer) { + CORRADE_ASSERT(_flags >= Flag::UniformBuffers, + "Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); + buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding); + return *this; +} + +template VectorGL& VectorGL::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { + CORRADE_ASSERT(_flags >= Flag::UniformBuffers, + "Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); + buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size); + return *this; +} #endif template VectorGL& VectorGL::bindVectorTexture(GL::Texture2D& texture) { diff --git a/src/Magnum/Shaders/VectorGL.h b/src/Magnum/Shaders/VectorGL.h index d5fd88d10..51068ad54 100644 --- a/src/Magnum/Shaders/VectorGL.h +++ b/src/Magnum/Shaders/VectorGL.h @@ -127,8 +127,8 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL /** * Use uniform buffers. Expects that uniform data are supplied via * @ref bindTransformationProjectionBuffer(), - * @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer() - * instead of direct uniform setters. + * @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer() + * and @ref bindMaterialBuffer() instead of direct uniform setters. * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gles30 Uniform buffers are not available in OpenGL ES * 2.0. @@ -185,7 +185,8 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL * * While this function is meant mainly for the classic uniform * scenario (without @ref Flag::UniformBuffers set), it's equivalent to - * @ref VectorGL(Flags, UnsignedInt) with @p drawCount set to @cpp 1 @ce. + * @ref VectorGL(Flags, UnsignedInt, UnsignedInt) with @p materialCount + * and @p drawCount set to @cpp 1 @ce. */ explicit VectorGL(Flags flags = {}); @@ -193,16 +194,19 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL /** * @brief Construct for a multi-draw scenario * @param flags Flags + * @param materialCount Size of a @ref VectorMaterialUniform buffer + * bound with @ref bindMaterialBuffer() * @param drawCount Size of a @ref TransformationProjectionUniform2D * / @ref TransformationProjectionUniform3D / * @ref VectorDrawUniform / @ref TextureTransformationUniform * buffer bound with @ref bindTransformationProjectionBuffer(), * @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer() * - * If @p flags contains @ref Flag::UniformBuffers @p drawCount - * describes the uniform buffer sizes as these are required to have a - * statically defined size. The draw offset is then set via - * @ref setDrawOffset(). + * If @p flags contains @ref Flag::UniformBuffers, @p materialCount and + * @p drawCount describe the uniform buffer sizes as these are required + * to have a statically defined size. The draw offset is then set via + * @ref setDrawOffset() and the per-draw materials specified via + * @ref VectorDrawUniform::materialId. * * If @p flags don't contain @ref Flag::UniformBuffers, @p drawCount is * ignored and the constructor behaves the same as @ref VectorGL(Flags). @@ -217,7 +221,7 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL (accepting pairs of parameter type and value like in GL context creation, e.g., which will probably need a new enum as reusing Flag for this might be too confusing) */ - explicit VectorGL(Flags flags, UnsignedInt drawCount); + explicit VectorGL(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount); #endif /** @@ -253,6 +257,18 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL Flags flags() const { return _flags; } #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Material count + * @m_since_latest + * + * Statically defined size of the @ref VectorMaterialUniform uniform + * buffer. Has use only if @ref Flag::UniformBuffers is set. + * @see @ref bindMaterialBuffer() + * @requires_gles30 Not defined on OpenGL ES 2.0 builds. + * @requires_webgl20 Not defined on WebGL 1.0 builds. + */ + UnsignedInt materialCount() const { return _materialCount; } + /** * @brief Draw count * @m_since_latest @@ -310,8 +326,8 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL * Initial value is @cpp 0x00000000_rgbaf @ce. * * Expects that @ref Flag::UniformBuffers is not set, in that case fill - * @ref VectorDrawUniform::backgroundColor and call - * @ref bindDrawBuffer() instead. + * @ref VectorMaterialUniform::backgroundColor and call + * @ref bindMaterialBuffer() instead. * @see @ref setColor() */ VectorGL& setBackgroundColor(const Color4& color); @@ -323,7 +339,7 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL * Initial value is @cpp 0xffffffff_rgbaf @ce. * * Expects that @ref Flag::UniformBuffers is not set, in that case fill - * @ref VectorDrawUniform::color and call @ref bindDrawBuffer() + * @ref VectorMaterialUniform::color and call @ref bindMaterialBuffer() * instead. * @see @ref setBackgroundColor() */ @@ -373,7 +389,7 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL * expected to contain @ref drawCount() instances of * @ref TransformationProjectionUniform2D / * @ref TransformationProjectionUniform3D. At the very least you need - * to call also @ref bindDrawBuffer(). + * to call also @ref bindDrawBuffer() and @ref bindMaterialBuffer(). * @requires_gl31 Extension @gl_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. @@ -393,7 +409,8 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL * Expects that @ref Flag::UniformBuffers is set. The buffer is * expected to contain @ref drawCount() instances of * @ref VectorDrawUniform. At the very least you need to call also - * @ref bindTransformationProjectionBuffer(). + * @ref bindTransformationProjectionBuffer() and + * @ref bindMaterialBuffer(). * @requires_gl31 Extension @gl_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. @@ -425,6 +442,26 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL */ VectorGL& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); + /** + * @brief Set a material uniform buffer + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Expects that @ref Flag::UniformBuffers is set. The buffer is + * expected to contain @ref materialCount() instances of + * @ref VectorMaterialUniform. At the very least you need to call also + * @ref bindTransformationProjectionBuffer() and @ref bindDrawBuffer(). + * @requires_gl31 Extension @gl_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. + */ + VectorGL& bindMaterialBuffer(GL::Buffer& buffer); + /** + * @overload + * @m_since_latest + */ + VectorGL& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); + /** * @} */ @@ -457,7 +494,7 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL Flags _flags; #ifndef MAGNUM_TARGET_GLES2 - UnsignedInt _drawCount{}; + UnsignedInt _materialCount{}, _drawCount{}; #endif Int _transformationProjectionMatrixUniform{0}, _textureMatrixUniform{1},