From a1f1f66c04daaa32ee3153ac9a9c0ab8cf9dceb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 5 Apr 2020 23:14:53 +0200 Subject: [PATCH] Shaders: implement instancing in Flat. --- doc/changelog.dox | 1 + doc/snippets/MagnumShaders.cpp | 20 ++ src/Magnum/Shaders/Flat.cpp | 13 +- src/Magnum/Shaders/Flat.h | 95 ++++++++- src/Magnum/Shaders/Flat.vert | 38 +++- src/Magnum/Shaders/Test/CMakeLists.txt | 2 + src/Magnum/Shaders/Test/FlatGLTest.cpp | 195 +++++++++++++++++- src/Magnum/Shaders/Test/FlatTest.cpp | 32 +-- .../Test/FlatTestFiles/instanced2D.tga | Bin 0 -> 2630 bytes .../Test/FlatTestFiles/instanced3D.tga | Bin 0 -> 2086 bytes 10 files changed, 367 insertions(+), 29 deletions(-) create mode 100644 src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga create mode 100644 src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga diff --git a/doc/changelog.dox b/doc/changelog.dox index e443408662..151f27d935 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -233,6 +233,7 @@ See also: @ref Shaders::Generic::TransformationMatrix, @ref Shaders::Generic::NormalMatrix and @ref Shaders::Generic::TextureOffset for instancing +- Instancing in @ref Shaders::Flat @subsubsection changelog-latest-new-trade Trade library diff --git a/doc/snippets/MagnumShaders.cpp b/doc/snippets/MagnumShaders.cpp index b6174b29d8..a871a4094d 100644 --- a/doc/snippets/MagnumShaders.cpp +++ b/doc/snippets/MagnumShaders.cpp @@ -249,6 +249,26 @@ framebuffer.mapForDraw({ } #endif +{ +GL::Mesh mesh; +/* [Flat-usage-instancing] */ +struct { + Matrix4 transformation; + Color3 color; +} instanceData[] { + {Matrix4::translation({1.0f, 2.0f, 0.0f}), 0xff3333_rgbf}, + {Matrix4::translation({2.0f, 1.0f, 0.0f}), 0x33ff33_rgbf}, + {Matrix4::translation({3.0f, 0.0f, 1.0f}), 0x3333ff_rgbf}, + // ... +}; + +mesh.setInstanceCount(Containers::arraySize(instanceData)) + .addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0, + Shaders::Flat3D::TransformationMatrix{}, + Shaders::Flat3D::Color3{}); +/* [Flat-usage-instancing] */ +} + { /* [MeshVisualizer-usage-geom1] */ struct Vertex { diff --git a/src/Magnum/Shaders/Flat.cpp b/src/Magnum/Shaders/Flat.cpp index f126cba5e7..f9c5c9e56d 100644 --- a/src/Magnum/Shaders/Flat.cpp +++ b/src/Magnum/Shaders/Flat.cpp @@ -72,6 +72,8 @@ template Flat::Flat(const Flags flags): _fla #ifndef MAGNUM_TARGET_GLES2 .addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") #endif + .addSource(flags & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n" : "") + .addSource(flags >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : "") .addSource(rs.get("generic.glsl")) .addSource(rs.get("Flat.vert")); frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") @@ -107,6 +109,10 @@ template Flat::Flat(const Flags flags): _fla } if(flags >= Flag::InstancedObjectId) bindAttributeLocation(ObjectId::Location, "instanceObjectId"); + if(flags & Flag::InstancedTransformation) + bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix"); + if(flags >= Flag::InstancedTextureOffset) + bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); #endif } #endif @@ -203,6 +209,8 @@ Debug& operator<<(Debug& debug, const FlatFlag value) { _c(ObjectId) _c(InstancedObjectId) #endif + _c(InstancedTransformation) + _c(InstancedTextureOffset) #undef _c /* LCOV_EXCL_STOP */ } @@ -215,12 +223,13 @@ Debug& operator<<(Debug& debug, const FlatFlags value) { FlatFlag::Textured, FlatFlag::AlphaMask, FlatFlag::VertexColor, + FlatFlag::InstancedTextureOffset, /* Superset of TextureTransformation */ FlatFlag::TextureTransformation, #ifndef MAGNUM_TARGET_GLES2 FlatFlag::InstancedObjectId, /* Superset of ObjectId */ - FlatFlag::ObjectId + FlatFlag::ObjectId, #endif - }); + FlatFlag::InstancedTransformation}); } } diff --git a/src/Magnum/Shaders/Flat.h b/src/Magnum/Shaders/Flat.h index e8a2158f2f..78ea0dcedc 100644 --- a/src/Magnum/Shaders/Flat.h +++ b/src/Magnum/Shaders/Flat.h @@ -44,8 +44,10 @@ namespace Implementation { TextureTransformation = 1 << 3, #ifndef MAGNUM_TARGET_GLES2 ObjectId = 1 << 4, - InstancedObjectId = (1 << 5)|ObjectId + InstancedObjectId = (1 << 5)|ObjectId, #endif + InstancedTransformation = 1 << 6, + InstancedTextureOffset = (1 << 7)|TextureTransformation }; typedef Containers::EnumSet FlatFlags; } @@ -120,6 +122,28 @@ from @ref setObjectId(). @requires_gles30 Object ID output requires integer buffer attachments, which are not available in OpenGL ES 2.0 or WebGL 1.0. +@section Shaders-Flat-instancing Instanced rendering + +Enabling @ref Flag::InstancedTransformation will turn the shader into an +instanced one. It'll take per-instance transformation from the +@ref TransformationMatrix attribute, applying it before the matrix set by +@ref setTransformationProjectionMatrix(). Besides that, @ref Flag::VertexColor +(and the @ref Color3 / @ref Color4) attributes can work as both per-vertex and +per-instance, and for texturing it's possible to have per-instance texture +offset taken from @ref TextureOffset when @ref Flag::InstancedTextureOffset is +enabled (similarly to transformation, applied before @ref setTextureMatrix()). +The snippet below shows adding a buffer with per-instance transformation and +color to a mesh: + +@snippet MagnumShaders.cpp Flat-usage-instancing + +@requires_gl33 Extension @gl_extension{ARB,instanced_arrays} +@requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays}, + @gl_extension{EXT,instanced_arrays} or @gl_extension{NV,instanced_arrays} + in OpenGL ES 2.0. +@requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays} in WebGL + 1.0. + @see @ref shaders, @ref Flat2D, @ref Flat3D */ template class MAGNUM_SHADERS_EXPORT Flat: public GL::AbstractShaderProgram { @@ -176,6 +200,37 @@ template class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab typedef typename Generic::ObjectId ObjectId; #endif + /** + * @brief (Instanced) transformation matrix + * @m_since_latest + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Matrix3 in + * 2D, @ref Magnum::Matrix4 in 3D. Used only if + * @ref Flag::InstancedTransformation is set. + * @requires_gl33 Extension @gl_extension{ARB,instanced_arrays} + * @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays}, + * @gl_extension{EXT,instanced_arrays} or + * @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0. + * @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays} + * in WebGL 1.0. + */ + typedef typename Generic::TransformationMatrix TransformationMatrix; + + /** + * @brief (Instanced) texture offset + * @m_since_latest + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Vector2. Used + * only if @ref Flag::InstancedTextureOffset is set. + * @requires_gl33 Extension @gl_extension{ARB,instanced_arrays} + * @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays}, + * @gl_extension{EXT,instanced_arrays} or + * @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0. + * @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays} + * in WebGL 1.0. + */ + typedef typename Generic::TextureOffset TextureOffset; + enum: UnsignedInt { /** * Color shader output. Present always, expects three- or @@ -263,8 +318,44 @@ template class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab * WebGL 1.0. * @m_since_latest */ - InstancedObjectId = (1 << 5)|ObjectId + InstancedObjectId = (1 << 5)|ObjectId, #endif + + /** + * Instanced transformation. Retrieves a per-instance + * transformation matrix from the @ref TransformationMatrix + * attribute and uses it together with the matrix coming from + * @ref setTransformationProjectionMatrix() (first the + * per-instance, then the uniform matrix). See + * @ref Shaders-Flat-instancing for more information. + * @requires_gl33 Extension @gl_extension{ARB,instanced_arrays} + * @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays}, + * @gl_extension{EXT,instanced_arrays} or + * @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0. + * @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays} + * in WebGL 1.0. + * @m_since_latest + */ + InstancedTransformation = 1 << 6, + + /** + * Instanced texture offset. Retrieves a per-instance offset vector + * from the @ref TextureOffset attribute and uses it together with + * the matrix coming from @ref setTextureMatrix() (first the + * per-instance vector, then the uniform matrix). Instanced texture + * scaling and rotation is not supported at the moment, you can + * specify that only via the uniform @ref setTextureMatrix(). + * Implicitly enables @ref Flag::TextureTransformation. See + * @ref Shaders-Flat-instancing for more information. + * @requires_gl33 Extension @gl_extension{ARB,instanced_arrays} + * @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays}, + * @gl_extension{EXT,instanced_arrays} or + * @gl_extension{NV,instanced_arrays} in OpenGL ES 2.0. + * @requires_webgl20 Extension @webgl_extension{ANGLE,instanced_arrays} + * in WebGL 1.0. + * @m_since_latest + */ + InstancedTextureOffset = (1 << 7)|TextureTransformation }; /** diff --git a/src/Magnum/Shaders/Flat.vert b/src/Magnum/Shaders/Flat.vert index a2779d889c..08bf36814a 100644 --- a/src/Magnum/Shaders/Flat.vert +++ b/src/Magnum/Shaders/Flat.vert @@ -96,11 +96,39 @@ in highp uint instanceObjectId; flat out highp uint interpolatedInstanceObjectId; #endif +#ifdef INSTANCED_TRANSFORMATION +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = TRANSFORMATION_MATRIX_ATTRIBUTE_LOCATION) +#endif +#ifdef TWO_DIMENSIONS +in highp mat3 instancedTransformationMatrix; +#elif defined(THREE_DIMENSIONS) +in highp mat4 instancedTransformationMatrix; +#else +#error +#endif +#endif + +#ifdef INSTANCED_TEXTURE_OFFSET +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = TEXTURE_OFFSET_ATTRIBUTE_LOCATION) +#endif +in mediump vec2 instancedTextureOffset; +#endif + void main() { #ifdef TWO_DIMENSIONS - gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0); + gl_Position.xywz = vec4(transformationProjectionMatrix* + #ifdef INSTANCED_TRANSFORMATION + instancedTransformationMatrix* + #endif + vec3(position, 1.0), 0.0); #elif defined(THREE_DIMENSIONS) - gl_Position = transformationProjectionMatrix*position; + gl_Position = transformationProjectionMatrix* + #ifdef INSTANCED_TRANSFORMATION + instancedTransformationMatrix* + #endif + position; #else #error #endif @@ -109,7 +137,11 @@ void main() { /* Texture coordinates, if needed */ interpolatedTextureCoordinates = #ifdef TEXTURE_TRANSFORMATION - (textureMatrix*vec3(textureCoordinates, 1.0)).xy + (textureMatrix*vec3( + #ifdef INSTANCED_TEXTURE_OFFSET + instancedTextureOffset + + #endif + textureCoordinates, 1.0)).xy #else textureCoordinates #endif diff --git a/src/Magnum/Shaders/Test/CMakeLists.txt b/src/Magnum/Shaders/Test/CMakeLists.txt index 53a1d5a766..688a6c862e 100644 --- a/src/Magnum/Shaders/Test/CMakeLists.txt +++ b/src/Magnum/Shaders/Test/CMakeLists.txt @@ -121,6 +121,8 @@ if(BUILD_GL_TESTS) FlatTestFiles/colored2D.tga FlatTestFiles/colored3D.tga FlatTestFiles/defaults.tga + FlatTestFiles/instanced2D.tga + FlatTestFiles/instanced3D.tga FlatTestFiles/textured2D.tga FlatTestFiles/textured3D.tga FlatTestFiles/textured2D-alpha.tga diff --git a/src/Magnum/Shaders/Test/FlatGLTest.cpp b/src/Magnum/Shaders/Test/FlatGLTest.cpp index 57971503cd..6355f4968b 100644 --- a/src/Magnum/Shaders/Test/FlatGLTest.cpp +++ b/src/Magnum/Shaders/Test/FlatGLTest.cpp @@ -35,6 +35,8 @@ #include "Magnum/ImageView.h" #include "Magnum/PixelFormat.h" #include "Magnum/DebugTools/CompareImage.h" +#include "Magnum/GL/Context.h" +#include "Magnum/GL/Extensions.h" #include "Magnum/GL/Mesh.h" #include "Magnum/GL/Framebuffer.h" #include "Magnum/GL/Renderer.h" @@ -103,6 +105,9 @@ struct FlatGLTest: GL::OpenGLTester { void renderObjectId3D(); #endif + void renderInstanced2D(); + void renderInstanced3D(); + private: PluginManager::Manager _manager{"nonexistent"}; std::string _testDir; @@ -120,12 +125,12 @@ struct FlatGLTest: GL::OpenGLTester { - Mesa Intel - Mesa AMD - SwiftShader ES2/ES3 - - ARM Mali (Huawei P10) ES2/ES3 - - WebGL 1 / 2 (on Mesa Intel) - - NVidia Windows - - Intel Windows - - AMD on macOS - - iPhone 6 w/ iOS 12.4 + - ARM Mali (Huawei P10) ES2/ES3 (except instancing) + - WebGL 1 / 2 (on Mesa Intel) (except instancing) + - NVidia Windows (except instancing) + - Intel Windows (except instancing) + - AMD on macOS (except instancing) + - iPhone 6 w/ iOS 12.4 (except instancing) */ using namespace Math::Literals; @@ -144,8 +149,10 @@ constexpr struct { #ifndef MAGNUM_TARGET_GLES2 {"object ID", Flat2D::Flag::ObjectId}, {"instanced object ID", Flat2D::Flag::InstancedObjectId}, - {"object ID + alpha mask + textured", Flat2D::Flag::ObjectId|Flat2D::Flag::AlphaMask|Flat2D::Flag::Textured} + {"object ID + alpha mask + textured", Flat2D::Flag::ObjectId|Flat2D::Flag::AlphaMask|Flat2D::Flag::Textured}, #endif + {"instanced transformation", Flat2D::Flag::InstancedTransformation}, + {"instanced texture offset", Flat2D::Flag::Textured|Flat2D::Flag::InstancedTextureOffset} }; const struct { @@ -261,6 +268,11 @@ FlatGLTest::FlatGLTest() { &FlatGLTest::renderObjectIdTeardown); #endif + addTests({&FlatGLTest::renderInstanced2D, + &FlatGLTest::renderInstanced3D}, + &FlatGLTest::renderSetup, + &FlatGLTest::renderTeardown); + /* Load the plugins directly from the build tree. Otherwise they're either static and already loaded or not present in the build tree */ #ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME @@ -1107,6 +1119,175 @@ void FlatGLTest::renderObjectId3D() { } #endif +void FlatGLTest::renderInstanced2D() { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::instanced_arrays::string() + std::string(" is not supported")); + #elif defined(MAGNUM_TARGET_GLES2) + #ifndef MAGNUM_TARGET_WEBGL + if(!GL::Context::current().isExtensionSupported() && + !GL::Context::current().isExtensionSupported() && + !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP("GL_{ANGLE,EXT,NV}_instanced_arrays is not supported"); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ANGLE::instanced_arrays::string() + std::string(" is not supported")); + #endif + #endif + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32, + Primitives::Circle2DFlag::TextureCoordinates)); + + /* Three circles, each in a different location */ + struct { + Matrix3 transformation; + Color3 color; + Vector2 textureOffset; + } instanceData[] { + {Matrix3::translation({-1.25f, -1.25f}), 0xff3333_rgbf, + {0.0f, 0.0f}}, + {Matrix3::translation({ 1.25f, -1.25f}), 0x33ff33_rgbf, + {1.0f, 0.0f}}, + {Matrix3::translation({ 0.00f, 1.25f}), 0x9999ff_rgbf, + {0.5f, 1.0f}} + }; + + circle + .addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0, + Flat2D::TransformationMatrix{}, + Flat2D::Color3{}, + Flat2D::TextureOffset{}) + .setInstanceCount(3); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + + Flat2D{Flat2D::Flag::Textured| + Flat2D::Flag::VertexColor| + Flat2D::Flag::InstancedTransformation| + Flat2D::Flag::InstancedTextureOffset} + .setColor(0xffff99_rgbf) + .setTransformationProjectionMatrix( + Matrix3::projection({2.1f, 2.1f})* + Matrix3::scaling(Vector2{0.4f})) + .setTextureMatrix(Matrix3::scaling(Vector2{0.5f})) + .bindTexture(texture) + .draw(circle); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* Minor differences on AMD, SwiftShader a bit more */ + const Float maxThreshold = 3.0f, meanThreshold = 0.018f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage */ + const Float maxThreshold = 3.0f, meanThreshold = 0.018f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(_testDir, "FlatTestFiles/instanced2D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void FlatGLTest::renderInstanced3D() { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::instanced_arrays::string() + std::string(" is not supported")); + #elif defined(MAGNUM_TARGET_GLES2) + #ifndef MAGNUM_TARGET_WEBGL + if(!GL::Context::current().isExtensionSupported() && + !GL::Context::current().isExtensionSupported() && + !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP("GL_{ANGLE,EXT,NV}_instanced_arrays is not supported"); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ANGLE::instanced_arrays::string() + std::string(" is not supported")); + #endif + #endif + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32, + Primitives::UVSphereFlag::TextureCoordinates)); + + /* Three spheres, each in a different location */ + struct { + Matrix4 transformation; + Color3 color; + Vector2 textureOffset; + } instanceData[] { + {Matrix4::translation({-1.25f, -1.25f, 0.0f}), 0xff3333_rgbf, + {0.0f, 0.0f}}, + {Matrix4::translation({ 1.25f, -1.25f, 0.0f}), 0x33ff33_rgbf, + {1.0f, 0.0f}}, + {Matrix4::translation({ 0.0f, 1.0f, 1.0f}), 0x9999ff_rgbf, + {0.5f, 1.0f}} + }; + + sphere + .addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0, + Flat3D::TransformationMatrix{}, + Flat3D::Color3{}, + Flat3D::TextureOffset{}) + .setInstanceCount(3); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + + Flat3D{Flat3D::Flag::Textured| + Flat3D::Flag::VertexColor| + Flat3D::Flag::InstancedTransformation| + Flat3D::Flag::InstancedTextureOffset} + .setColor(0xffff99_rgbf) + .setTransformationProjectionMatrix( + Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::scaling(Vector3{0.4f})) + .setTextureMatrix(Matrix3::scaling(Vector2{0.5f})) + .bindTexture(texture) + .draw(sphere); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* Minor differences on AMD, SwiftShader a bit more */ + const Float maxThreshold = 67.67f, meanThreshold = 0.062f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage */ + const Float maxThreshold = 67.67f, meanThreshold = 0.062f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(_testDir, "FlatTestFiles/instanced3D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + }}}} CORRADE_TEST_MAIN(Magnum::Shaders::Test::FlatGLTest) diff --git a/src/Magnum/Shaders/Test/FlatTest.cpp b/src/Magnum/Shaders/Test/FlatTest.cpp index 39d29ec969..6258870023 100644 --- a/src/Magnum/Shaders/Test/FlatTest.cpp +++ b/src/Magnum/Shaders/Test/FlatTest.cpp @@ -39,9 +39,7 @@ struct FlatTest: TestSuite::Tester { void debugFlag(); void debugFlags(); - #ifndef MAGNUM_TARGET_GLES2 - void debugFlagsInstancedObjectId(); - #endif + void debugFlagsSupersets(); }; FlatTest::FlatTest() { @@ -53,10 +51,7 @@ FlatTest::FlatTest() { &FlatTest::debugFlag, &FlatTest::debugFlags, - #ifndef MAGNUM_TARGET_GLES2 - &FlatTest::debugFlagsInstancedObjectId - #endif - }); + &FlatTest::debugFlagsSupersets}); } template void FlatTest::constructNoCreate() { @@ -94,16 +89,23 @@ void FlatTest::debugFlags() { CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::Textured|Shaders::Flat::Flag::AlphaMask Shaders::Flat::Flags{}\n"); } -#ifndef MAGNUM_TARGET_GLES2 -void FlatTest::debugFlagsInstancedObjectId() { - std::ostringstream out; - +void FlatTest::debugFlagsSupersets() { + #ifndef MAGNUM_TARGET_GLES2 /* InstancedObjectId is a superset of ObjectId so only one should be - *printed */ - Debug{&out} << (Flat3D::Flag::ObjectId|Flat3D::Flag::InstancedObjectId); - CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::InstancedObjectId\n"); + printed */ + { + std::ostringstream out; + Debug{&out} << (Flat3D::Flag::ObjectId|Flat3D::Flag::InstancedObjectId); + CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::InstancedObjectId\n"); + } + #endif + + /* InstancedTextureOffset is a superset of TextureTransformation so only + one should be printed */ + std::ostringstream out; + Debug{&out} << (Flat3D::Flag::InstancedTextureOffset|Flat3D::Flag::TextureTransformation); + CORRADE_COMPARE(out.str(), "Shaders::Flat::Flag::InstancedTextureOffset\n"); } -#endif }}}} diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga new file mode 100644 index 0000000000000000000000000000000000000000..a130de40ebf0ee24b2176d9c04a294f2af228c87 GIT binary patch literal 2630 zcmcIl?{8C87`|<9@6GPLVJn+=U3+`aY1ge~5)-i&Hs zERyusT9GO-^2-T0!#^M-@=5u!pg~>KPa=Pe&vUz5XM`9{Xx_Jd&-*^-InQ~|xwnd9 zDE?*oU!$*Rnpe7%%6r=P^+MJjxlN#)R;d7ucB5( z?Ni36RZ(O9LwFE1&+d?+2Gkj3YwHX_?dL4OFk)+P6{ybM?=~ks>X4V(VkgTOQ&Tve zS$W7k(Pr<*cdX|kQj``3k$KfLW)1VKX?|u}-&(%%uy#A6m%FsH3B4NAuBWgF7pTHD zPto1huDRIOKNvs!do;Vs?Q@Gtd;HxZe!0B@_ygtz)4XnS*X)Sa)Qmu%u^akHyTl0~ zQ6o;ZtM4~NkvK^2Y$WDh*c+-07!}i6waN&Wz!K1I_39r)3kb>NvxT6st!utDdb~qk zW;=Y1f1|Q~v0C0UNL9xCkoIFnA8*qOQSGOUPgntI5%WXQ?Duy1YeXH%m5qdDXk&}G z(|~!-v~GFLY-qdDtzB`8;3iFz%I>+*nYl@-hBi_JoXkpleA;I#f=xyLtThXfv1nMg zJ=%uOA2OiSZuV%W<34#A3s6=t;?y?TQ+E0qM;vJ|&@W?<|2Spv?*ws4b)gN>XYt^m3A#XjbRo8M`npz$}&1+9Qb2-*?p7*1S zrGtjk-?Dj|5zUn_;=!`Rs&*}h;RQIlMW zrcRNWT&kHKu(E@QtSv)WrMS+|hAaBXC|?d`%nxXJSIhM<^lyzv)#1!;pxUucl^HbM z?f0UpkV?xwMu`71pWv?0aHb?Md>mMH)6`B>EA7$4qW#&^N?a z3J<|=5=DhPvLqrHsd!Rh&~zl`aoJ(5_C&0AnJZAC3R)wUhe0RCd<}-cNn3XHS=;Zv zik9j5sGjd?aFf@2&4Q?giDxjbVO9-g=Dk-rYE{&{S2=1`)R_1F0#K`<=KTer#$#dr z6FA?O?D`jsQDc{xU;7vT%A315S4@Z#jIY2e&f;7JW5$=@Rg9|`GbVp+y&g=61*Boj zF2h5p(B_Z3QwK>?LNN?jQjDhLGcZ@oAVn~tiVgYCbFd{F) zOGGE1d)7y*t~@5hJ3t6=G%3dmh=^-qQ%^ijY#I5WloKiWRJYv4of2^YUPd*Lm_Cx2 zIm(b~RjBQj!>*VY;w>o;5>6qW!6p`{lpF=Z71LN?BbHlJlY4h}_iv-+A9dfJ z;s!i1LLNxVd`dpa70G-aUPrZ#G2{O=#@zbCUZ*+#Ka8n?TG*zv+#$szb(X;vSlHt{ zKj1L*+rVwALQF|<0Fe}L;K(?+0*o^J$Um_uIf70B0mB7oVn=dKEKh{zr>5l7Qck*J zHYrD4@xG4@ytd1Mk|LJykC^aK1106_z)~_b1ZGB@{X3gjUY`(3Fd+^L@#YeuCE!9Y z4m$ID97HgpcrC*XWKxbL<;(bnaB3(45peUeS21SnJzN-5B;yshPtN#$59^;rL7VIV literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga new file mode 100644 index 0000000000000000000000000000000000000000..c1c4d964064b9bcf88aae8d73c376f36f49753c6 GIT binary patch literal 2086 zcmbu9?{8C87{||T$SG_!T{D4gy|?YUb-U+ohDbUCnL{B40&Hwy#!QWg!Ktvx26N!r zu5Z@0x4#R5!KsJ=jlPg*Vq$z@Oic8JZ)n*oU--xP{od|w#Snv$+!K1f-_P@$AJ20p zM4NE`O^GSdCF+4d;7P`Z;5@qd6~1nDW4&kiuMH^cvTk}h8Uf#?4zEhd3;#nu8Tu8BEaJs}l`Dc_T#-zm-kAkMzl@P1vsYayfuU9+ z^YnwgIWY7~7&e$Pe6fG);T0aG? zUxL@ISka5LA zYRK%{^t4jHPpb;TSl?E@23`cMpSg&TSIydEm}_9@U;B@q z*kh%cpRvp~4he*yDE1$+TNmjK^f$ERn{&y0p__ z%}X42X-&o>-Vwb_RMum>Gh!UVH*nYnUgibp=9jz_UJ%pKXVbdAGl$1`>TGbQUTxM= zk?~#85*aMV&9OW@2U~+E-%+-?vy&{Z=+u{}6ZejE=kXs=Vtihrtt-9`oKN98=iZTh zHkd3J`qVN^*KVEV)7F9mw*%ehZ#2>FELZo|``I!?Z(?Y`@nt~s&qM}@1{)vUdds*+ z+X$yJ`sxS#{RM^yg_p9>a?m)xL(K>$bI@#PoZqI_7a7Y#6XDgxJalTGQ4fXRr>=#< zsmSU=0T$&?o7PH!mKnPQs|btoC$xGaXN$B{>{2v+p#+OE_b@ZfvS6*M89)1zNpF^(m% zVHaHkx@-A#-^|zxM-RS&Q}jizu%22oh^5}8UtQ7PT`^`73>`?VwS?OU_al7%#PGRe zBd;DgGClgz)Zr5ohfYn69`Ai^!5B{%Clki;gmE-!97-Aon84mj;9NBlXcxx^jpvd) z(Dqe7vCLwZNiU2K7$Zp**6o39Ile8kb4o59Px5*wvDb<_GTV(3yR$%faUy0sn`DDh zVn641WVSS=&oOu(+U1FU9F(V|#FvtFWh=!8MCmR@hVt^6UL%s?Tcgza2LJi{Z+{{c Af&c&j literal 0 HcmV?d00001