diff --git a/src/Magnum/Shaders/MeshVisualizerGL.cpp b/src/Magnum/Shaders/MeshVisualizerGL.cpp index 615231aa5..eaec0dd12 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.cpp +++ b/src/Magnum/Shaders/MeshVisualizerGL.cpp @@ -26,7 +26,6 @@ #include "MeshVisualizerGL.h" #include -#include #include #include #include @@ -72,17 +71,7 @@ namespace { namespace Implementation { -MeshVisualizerGLBase::MeshVisualizerGLBase(FlagsBase flags - #ifndef MAGNUM_TARGET_GLES2 - , const UnsignedInt materialCount, const UnsignedInt drawCount - #endif -): - _flags{flags} - #ifndef MAGNUM_TARGET_GLES2 - , _materialCount{materialCount}, - _drawCount{drawCount} - #endif -{ +void MeshVisualizerGLBase::assertExtensions(const FlagsBase flags) { #ifndef MAGNUM_TARGET_GLES2 #ifndef CORRADE_NO_ASSERT Int countMutuallyExclusive = 0; @@ -120,7 +109,7 @@ MeshVisualizerGLBase::MeshVisualizerGLBase(FlagsBase flags #endif #ifndef MAGNUM_TARGET_GLES2 - if(_flags & FlagBase::Wireframe && !(_flags & FlagBase::NoGeometryShader)) { + if(flags & FlagBase::Wireframe && !(flags & FlagBase::NoGeometryShader)) { #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL320); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::geometry_shader4); @@ -129,12 +118,12 @@ MeshVisualizerGLBase::MeshVisualizerGLBase(FlagsBase flags #endif } #else - if(_flags & FlagBase::Wireframe) + if(flags & FlagBase::Wireframe) MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::OES::standard_derivatives); #endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - if(_flags & FlagBase::PrimitiveId && !(_flags >= FlagBase::PrimitiveIdFromVertexId)) { + if(flags & FlagBase::PrimitiveId && !(flags >= FlagBase::PrimitiveIdFromVertexId)) { #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL320); #else @@ -150,18 +139,23 @@ MeshVisualizerGLBase::MeshVisualizerGLBase(FlagsBase flags #endif } -GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& frag, const Utility::Resource& rs) const { +GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& frag, const Utility::Resource& rs, + const FlagsBase flags + #ifndef MAGNUM_TARGET_GLES2 + , UnsignedInt materialCount, UnsignedInt drawCount + #endif +) { GL::Context& context = GL::Context::current(); #ifndef MAGNUM_TARGET_GLES const GL::Version version = context.supportedVersion({GL::Version::GL320, GL::Version::GL310, GL::Version::GL300, GL::Version::GL210}); /* Extended in MeshVisualizerGL3D for TBN visualization */ - CORRADE_INTERNAL_ASSERT(!(_flags & FlagBase::Wireframe) || _flags & FlagBase::NoGeometryShader || version >= GL::Version::GL320); + CORRADE_INTERNAL_ASSERT(!(flags & FlagBase::Wireframe) || flags & FlagBase::NoGeometryShader || version >= GL::Version::GL320); #elif !defined(MAGNUM_TARGET_WEBGL) /* ES 3.2 needed for gl_PrimitiveID */ const GL::Version version = context.supportedVersion({GL::Version::GLES320, GL::Version::GLES310, GL::Version::GLES300, GL::Version::GLES200}); /* Extended in MeshVisualizerGL3D for TBN visualization */ - CORRADE_INTERNAL_ASSERT(!(_flags & FlagBase::Wireframe) || _flags & FlagBase::NoGeometryShader || version >= GL::Version::GLES310); + CORRADE_INTERNAL_ASSERT(!(flags & FlagBase::Wireframe) || flags & FlagBase::NoGeometryShader || version >= GL::Version::GLES310); #else const GL::Version version = context.supportedVersion({GL::Version::GLES300, GL::Version::GLES200}); #endif @@ -169,18 +163,18 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex); frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); - vert.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + vert.addSource(flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") #ifndef MAGNUM_TARGET_GLES2 - .addSource(_flags >= FlagBase::ObjectIdTexture ? "#define TEXTURED\n" : "") - .addSource(_flags & FlagBase::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "") - .addSource(_flags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") - .addSource(_flags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") + .addSource(flags >= FlagBase::ObjectIdTexture ? "#define TEXTURED\n" : "") + .addSource(flags & FlagBase::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "") + .addSource(flags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") + .addSource(flags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") #endif - .addSource(_flags & FlagBase::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n" : "") + .addSource(flags & FlagBase::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n" : "") #ifndef MAGNUM_TARGET_GLES2 - .addSource(_flags >= FlagBase::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : "") - .addSource(_flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") - .addSource(_flags >= FlagBase::PrimitiveIdFromVertexId ? "#define PRIMITIVE_ID_FROM_VERTEX_ID\n" : "") + .addSource(flags >= FlagBase::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : "") + .addSource(flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") + .addSource(flags >= FlagBase::PrimitiveIdFromVertexId ? "#define PRIMITIVE_ID_FROM_VERTEX_ID\n" : "") #endif #ifdef MAGNUM_TARGET_WEBGL .addSource("#define SUBSCRIPTING_WORKAROUND\n") @@ -190,38 +184,38 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra #endif ; #ifndef MAGNUM_TARGET_GLES2 - if(_flags >= FlagBase::UniformBuffers) { + if(flags >= FlagBase::UniformBuffers) { vert.addSource(Utility::formatString( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", - _drawCount, - _materialCount)); - vert.addSource(_flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : ""); + drawCount, + materialCount)); + vert.addSource(flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : ""); } #endif - frag.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + frag.addSource(flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") #ifndef MAGNUM_TARGET_GLES2 - .addSource(_flags & FlagBase::ObjectId ? "#define OBJECT_ID\n" : "") - .addSource(_flags >= FlagBase::ObjectIdTexture ? "#define OBJECT_ID_TEXTURE\n" : "") - .addSource(_flags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") - .addSource(_flags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") - .addSource(_flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") - .addSource(_flags & FlagBase::PrimitiveId ? - (_flags >= FlagBase::PrimitiveIdFromVertexId ? + .addSource(flags & FlagBase::ObjectId ? "#define OBJECT_ID\n" : "") + .addSource(flags >= FlagBase::ObjectIdTexture ? "#define OBJECT_ID_TEXTURE\n" : "") + .addSource(flags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") + .addSource(flags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") + .addSource(flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") + .addSource(flags & FlagBase::PrimitiveId ? + (flags >= FlagBase::PrimitiveIdFromVertexId ? "#define PRIMITIVE_ID_FROM_VERTEX_ID\n" : "#define PRIMITIVE_ID\n") : "") #endif ; #ifndef MAGNUM_TARGET_GLES2 - if(_flags >= FlagBase::UniformBuffers) { + if(flags >= FlagBase::UniformBuffers) { frag.addSource(Utility::formatString( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", - _drawCount, - _materialCount)); - frag.addSource(_flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : ""); + drawCount, + materialCount)); + frag.addSource(flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : ""); } #endif @@ -382,21 +376,20 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::bindObjectIdTexture(GL::Texture2DArr } -MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags +MeshVisualizerGL2D::CompileState MeshVisualizerGL2D::compile(Flags flags #ifndef MAGNUM_TARGET_GLES2 , const UnsignedInt materialCount, const UnsignedInt drawCount #endif -): Implementation::MeshVisualizerGLBase{Implementation::MeshVisualizerGLBase::FlagBase(UnsignedInt(flags)) - #ifndef MAGNUM_TARGET_GLES2 - , materialCount, drawCount - #endif -} { +) { + FlagsBase baseFlags = Implementation::MeshVisualizerGLBase::FlagBase(UnsignedInt(flags)); + assertExtensions(baseFlags); + #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(flags & ((Flag::Wireframe|Flag::ObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId) & ~Flag::NoGeometryShader), - "Shaders::MeshVisualizerGL2D: at least one visualization feature has to be enabled", ); + "Shaders::MeshVisualizerGL2D: at least one visualization feature has to be enabled", CompileState{NoCreate}); #else CORRADE_ASSERT(flags & (Flag::Wireframe & ~Flag::NoGeometryShader), - "Shaders::MeshVisualizerGL2D: at least Flag::Wireframe has to be enabled", ); + "Shaders::MeshVisualizerGL2D: at least Flag::Wireframe has to be enabled", CompileState{NoCreate}); #endif /* Has to be here and not in the base class in order to have it exit the @@ -404,9 +397,9 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags otherwise */ #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, - "Shaders::MeshVisualizerGL2D: material count can't be zero", ); + "Shaders::MeshVisualizerGL2D: material count can't be zero", CompileState{NoCreate}); CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, - "Shaders::MeshVisualizerGL2D: draw count can't be zero", ); + "Shaders::MeshVisualizerGL2D: draw count can't be zero", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES @@ -416,7 +409,12 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags Utility::Resource rs{"MagnumShadersGL"}; GL::Shader vert{NoCreate}; GL::Shader frag{NoCreate}; - const GL::Version version = setupShaders(vert, frag, rs); + const GL::Version version = setupShaders(vert, frag, rs, baseFlags + #ifndef MAGNUM_TARGET_GLES2 + , materialCount, drawCount + #endif + ); + Containers::Optional geom; vert.addSource("#define TWO_DIMENSIONS\n") /* Pass NO_GEOMETRY_SHADER not only when NoGeometryShader but also when @@ -439,19 +437,19 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags frag.addSource(rs.getString("generic.glsl")) .addSource(rs.getString("MeshVisualizer.frag")); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - Containers::Optional geom; if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) { geom = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Geometry); (*geom) .addSource("#define WIREFRAME_RENDERING\n#define MAX_VERTICES 3\n") - .addSource(_flags >= FlagBase::ObjectIdTexture ? "#define TEXTURED\n" : "") - .addSource(_flags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") - .addSource(_flags & FlagBase::ObjectId ? "#define OBJECT_ID\n" : "") - .addSource(_flags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") - .addSource(_flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") - .addSource(_flags & FlagBase::PrimitiveId ? - (_flags >= FlagBase::PrimitiveIdFromVertexId ? + .addSource(baseFlags >= FlagBase::ObjectIdTexture ? "#define TEXTURED\n" : "") + .addSource(baseFlags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") + .addSource(baseFlags & FlagBase::ObjectId ? "#define OBJECT_ID\n" : "") + .addSource(baseFlags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") + .addSource(baseFlags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") + .addSource(baseFlags & FlagBase::PrimitiveId ? + (baseFlags >= FlagBase::PrimitiveIdFromVertexId ? "#define PRIMITIVE_ID_FROM_VERTEX_ID\n" : "#define PRIMITIVE_ID\n") : ""); #ifndef MAGNUM_TARGET_GLES2 @@ -461,8 +459,8 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", - _drawCount, - _materialCount)); + drawCount, + materialCount)); geom->addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : ""); } #endif @@ -472,48 +470,75 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags static_cast(version); #endif - #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - if(geom) CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, *geom, frag})); - else - #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); + vert.submitCompile(); + frag.submitCompile(); + if (geom) geom->submitCompile(); - attachShaders({vert, frag}); - #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - if(geom) attachShader(*geom); + MeshVisualizerGL2D out{NoInit}; + out._flags = baseFlags; + #ifndef MAGNUM_TARGET_GLES2 + out._materialCount = materialCount; + out._drawCount = drawCount; #endif + out.attachShaders({vert, frag}); + if (geom) out.attachShader(*geom); + /* ES3 has this done in the shader directly */ #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) #endif { - bindAttributeLocation(Position::Location, "position"); + out.bindAttributeLocation(Position::Location, "position"); #ifndef MAGNUM_TARGET_GLES2 if(flags >= Flag::ObjectIdTexture) - bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + out.bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); if(flags >= Flag::InstancedObjectId) - bindAttributeLocation(ObjectId::Location, "instanceObjectId"); + out.bindAttributeLocation(ObjectId::Location, "instanceObjectId"); #endif if(flags & Flag::InstancedTransformation) - bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix"); + out.bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix"); #ifndef MAGNUM_TARGET_GLES2 if(flags >= Flag::InstancedTextureOffset) - bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); + out.bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); #endif #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) #ifndef MAGNUM_TARGET_GLES if(!context.isVersionSupported(GL::Version::GL310)) #endif { - bindAttributeLocation(VertexIndex::Location, "vertexIndex"); + out.bindAttributeLocation(VertexIndex::Location, "vertexIndex"); } #endif } #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + out.submitLink(); + + return CompileState{std::move(out), std::move(vert), std::move(frag), std::move(geom), flags, version}; +} + +MeshVisualizerGL2D::MeshVisualizerGL2D(Flags flags) : MeshVisualizerGL2D{compile(flags)} {} + +#ifndef MAGNUM_TARGET_GLES2 +MeshVisualizer2D::CompileState MeshVisualizer2D::compile(Flags flags) { + return compile(flags, 1, 1); +} + +MeshVisualizerGL2D::MeshVisualizerGL2D(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount) + : MeshVisualizerGL2D{compile(flags, materialCount, drawCount)} {} +#endif + +MeshVisualizer2D::MeshVisualizerGL2D(CompileState&& cs) +: MeshVisualizerGL2D{static_cast(std::move(cs))} { + if (id() == 0) return; + + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink()); + + const GL::Context& context = GL::Context::current(); + const GL::Version version = cs._version; + Flags flags = cs._flags; #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) @@ -610,10 +635,6 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags #endif } -#ifndef MAGNUM_TARGET_GLES2 -MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): MeshVisualizerGL2D{flags, 1, 1} {} -#endif - MeshVisualizerGL2D& MeshVisualizerGL2D::setViewportSize(const Vector2& size) { /* Not asserting here, since the relation to wireframe is a bit vague. Also it's an ugly hack that should be removed, ideally. */ @@ -674,25 +695,24 @@ MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer, const } #endif -MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags +MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(Flags flags #ifndef MAGNUM_TARGET_GLES2 , const UnsignedInt materialCount, const UnsignedInt drawCount #endif -): Implementation::MeshVisualizerGLBase{Implementation::MeshVisualizerGLBase::FlagBase(UnsignedInt(flags)) - #ifndef MAGNUM_TARGET_GLES2 - , materialCount, drawCount - #endif -} { +) { + FlagsBase baseFlags = Implementation::MeshVisualizerGLBase::FlagBase(UnsignedInt(flags)); + assertExtensions(baseFlags); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) CORRADE_ASSERT(flags & ((Flag::Wireframe|Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection|Flag::ObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId) & ~Flag::NoGeometryShader), - "Shaders::MeshVisualizerGL3D: at least one visualization feature has to be enabled", ); + "Shaders::MeshVisualizerGL3D: at least one visualization feature has to be enabled", CompileState{NoCreate}); CORRADE_ASSERT(!(flags & Flag::NoGeometryShader && flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection)), - "Shaders::MeshVisualizerGL3D: geometry shader has to be enabled when rendering TBN direction", ); + "Shaders::MeshVisualizerGL3D: geometry shader has to be enabled when rendering TBN direction", CompileState{NoCreate}); CORRADE_ASSERT(!(flags & Flag::BitangentDirection && flags & Flag::BitangentFromTangentDirection), - "Shaders::MeshVisualizerGL3D: Flag::BitangentDirection and Flag::BitangentFromTangentDirection are mutually exclusive", ); + "Shaders::MeshVisualizerGL3D: Flag::BitangentDirection and Flag::BitangentFromTangentDirection are mutually exclusive", CompileState{NoCreate}); #elif !defined(MAGNUM_TARGET_GLES2) CORRADE_ASSERT(flags & ((Flag::Wireframe|Flag::ObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId) & ~Flag::NoGeometryShader), - "Shaders::MeshVisualizerGL3D: at least one visualization feature has to be enabled", ); + "Shaders::MeshVisualizerGL3D: at least one visualization feature has to be enabled", CompileState{NoCreate}); #else CORRADE_ASSERT(flags & (Flag::Wireframe & ~Flag::NoGeometryShader), "Shaders::MeshVisualizerGL3D: at least Flag::Wireframe has to be enabled", ); @@ -700,7 +720,7 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) CORRADE_ASSERT(!(flags >= Flag::InstancedObjectId) || !(flags & Flag::BitangentDirection), - "Shaders::MeshVisualizerGL3D: Bitangent attribute binding conflicts with the ObjectId attribute, use a Tangent4 attribute with instanced object ID rendering instead", ); + "Shaders::MeshVisualizerGL3D: Bitangent attribute binding conflicts with the ObjectId attribute, use a Tangent4 attribute with instanced object ID rendering instead", CompileState{NoCreate}); #endif /* Has to be here and not in the base class in order to have it exit the @@ -708,9 +728,9 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags otherwise */ #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, - "Shaders::MeshVisualizerGL3D: material count can't be zero", ); + "Shaders::MeshVisualizerGL3D: material count can't be zero", CompileState{NoCreate}); CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, - "Shaders::MeshVisualizerGL3D: draw count can't be zero", ); + "Shaders::MeshVisualizerGL3D: draw count can't be zero", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES @@ -720,7 +740,12 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags Utility::Resource rs{"MagnumShadersGL"}; GL::Shader vert{NoCreate}; GL::Shader frag{NoCreate}; - const GL::Version version = setupShaders(vert, frag, rs); + const GL::Version version = setupShaders(vert, frag, rs, baseFlags + #ifndef MAGNUM_TARGET_GLES2 + , materialCount, drawCount + #endif + ); + Containers::Optional geom; /* Expands the check done for wireframe in MeshVisualizerBase with TBN */ #ifndef MAGNUM_TARGET_GLES @@ -768,7 +793,6 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags .addSource(rs.getString("MeshVisualizer.frag")); #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - Containers::Optional geom; if(flags & (Flag::Wireframe|Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection) && !(flags & Flag::NoGeometryShader)) { Int maxVertices = 0; if(flags & Flag::Wireframe) maxVertices += 3; @@ -781,13 +805,13 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags (*geom) .addSource(Utility::formatString("#define MAX_VERTICES {}\n", maxVertices)) .addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") - .addSource(_flags >= FlagBase::ObjectIdTexture ? "#define TEXTURED\n" : "") - .addSource(_flags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") - .addSource(_flags & FlagBase::ObjectId ? "#define OBJECT_ID\n" : "") - .addSource(_flags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") - .addSource(_flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") - .addSource(_flags & FlagBase::PrimitiveId ? - (_flags >= FlagBase::PrimitiveIdFromVertexId ? + .addSource(baseFlags >= FlagBase::ObjectIdTexture ? "#define TEXTURED\n" : "") + .addSource(baseFlags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") + .addSource(baseFlags & FlagBase::ObjectId ? "#define OBJECT_ID\n" : "") + .addSource(baseFlags >= FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") + .addSource(baseFlags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") + .addSource(baseFlags & FlagBase::PrimitiveId ? + (baseFlags >= FlagBase::PrimitiveIdFromVertexId ? "#define PRIMITIVE_ID_FROM_VERTEX_ID\n" : "#define PRIMITIVE_ID\n") : "") .addSource(flags & Flag::TangentDirection ? "#define TANGENT_DIRECTION\n" : "") @@ -800,8 +824,8 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", - _drawCount, - _materialCount)); + drawCount, + materialCount)); geom->addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : ""); } #endif @@ -811,50 +835,53 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags static_cast(version); #endif - #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - if(geom) CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, *geom, frag})); - else - #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); + vert.submitCompile(); + frag.submitCompile(); + if (geom) geom->submitCompile(); - attachShaders({vert, frag}); - #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - if(geom) attachShader(*geom); + MeshVisualizerGL3D out{NoInit}; + out._flags = baseFlags; + #ifndef MAGNUM_TARGET_GLES2 + out._materialCount = materialCount; + out._drawCount = drawCount; #endif + out.attachShaders({vert, frag}); + if (geom) out.attachShader(*geom); + /* ES3 has this done in the shader directly */ #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) #endif { - bindAttributeLocation(Position::Location, "position"); + out.bindAttributeLocation(Position::Location, "position"); #ifndef MAGNUM_TARGET_GLES2 if(flags >= Flag::ObjectIdTexture) - bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + out.bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); if(flags >= Flag::InstancedObjectId) - bindAttributeLocation(ObjectId::Location, "instanceObjectId"); + out.bindAttributeLocation(ObjectId::Location, "instanceObjectId"); #endif if(flags & Flag::InstancedTransformation) { - bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix"); + out.bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix"); #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) if(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection)) - bindAttributeLocation(NormalMatrix::Location, "instancedNormalMatrix"); + out.bindAttributeLocation(NormalMatrix::Location, "instancedNormalMatrix"); #endif } #ifndef MAGNUM_TARGET_GLES2 if(flags >= Flag::InstancedTextureOffset) - bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); + out.bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); #endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) if(flags & Flag::TangentDirection || flags & Flag::BitangentFromTangentDirection) - bindAttributeLocation(Tangent4::Location, "tangent"); + out.bindAttributeLocation(Tangent4::Location, "tangent"); if(flags & Flag::BitangentDirection) - bindAttributeLocation(Bitangent::Location, "bitangent"); + out.bindAttributeLocation(Bitangent::Location, "bitangent"); if(flags & Flag::NormalDirection || flags & Flag::BitangentFromTangentDirection) - bindAttributeLocation(Normal::Location, "normal"); + out.bindAttributeLocation(Normal::Location, "normal"); #endif #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) @@ -862,13 +889,37 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags if(!context.isVersionSupported(GL::Version::GL310)) #endif { - bindAttributeLocation(VertexIndex::Location, "vertexIndex"); + out.bindAttributeLocation(VertexIndex::Location, "vertexIndex"); } #endif } #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + out.submitLink(); + + return CompileState{std::move(out), std::move(vert), std::move(frag), std::move(geom), flags, version}; +} + +MeshVisualizerGL3D::MeshVisualizerGL3D(Flags flags) : MeshVisualizerGL3D{compile(flags)} {} + +#ifndef MAGNUM_TARGET_GLES2 +MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(Flags flags) { + return compile(flags, 1, 1); +} + +MeshVisualizerGL3D::MeshVisualizerGL3D(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount) + : MeshVisualizerGL3D{compile(flags, materialCount, drawCount)} {} +#endif + +MeshVisualizerGL3D::MeshVisualizerGL3D(CompileState&& cs) +: MeshVisualizerGL3D{static_cast(std::move(cs))} { + if (id() == 0) return; + + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink()); + + const GL::Context& context = GL::Context::current(); + const GL::Version version = cs._version; + Flags flags = cs._flags; #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) @@ -998,10 +1049,6 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags #endif } -#ifndef MAGNUM_TARGET_GLES2 -MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): MeshVisualizerGL3D{flags, 1, 1} {} -#endif - MeshVisualizerGL3D& MeshVisualizerGL3D::setTransformationMatrix(const Matrix4& matrix) { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers), diff --git a/src/Magnum/Shaders/MeshVisualizerGL.h b/src/Magnum/Shaders/MeshVisualizerGL.h index b217f1d39..33ec8e329 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.h +++ b/src/Magnum/Shaders/MeshVisualizerGL.h @@ -32,8 +32,10 @@ #include +#include #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" +#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/visibility.h" @@ -69,14 +71,17 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr CORRADE_ENUMSET_FRIEND_OPERATORS(FlagsBase) - explicit MeshVisualizerGLBase(FlagsBase flags + explicit MeshVisualizerGLBase(NoInitT) {} + + explicit MeshVisualizerGLBase(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {} + + static MAGNUM_SHADERS_LOCAL void assertExtensions(const FlagsBase flags); + static MAGNUM_SHADERS_LOCAL GL::Version setupShaders(GL::Shader& vert, GL::Shader& frag, const Utility::Resource& rs, + const FlagsBase flags #ifndef MAGNUM_TARGET_GLES2 , UnsignedInt materialCount, UnsignedInt drawCount #endif ); - explicit MeshVisualizerGLBase(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {} - - MAGNUM_SHADERS_LOCAL GL::Version setupShaders(GL::Shader& vert, GL::Shader& frag, const Utility::Resource& rs) const; #ifndef MAGNUM_TARGET_GLES2 MeshVisualizerGLBase& setTextureMatrix(const Matrix3& matrix); @@ -505,6 +510,20 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua */ explicit MeshVisualizerGL2D(NoCreateT) noexcept: Implementation::MeshVisualizerGLBase{NoCreate} {} + class CompileState; + + explicit MeshVisualizerGL2D(CompileState&& cs); + + static CompileState compile(Flags flags + #ifndef MAGNUM_TARGET_GLES2 + , UnsignedInt materialCount, UnsignedInt drawCount + #endif + ); + + #ifndef MAGNUM_TARGET_GLES2 + static CompileState compile(Flags flags); + #endif + /** @brief Copying is not allowed */ MeshVisualizerGL2D(const MeshVisualizerGL2D&) = delete; @@ -862,9 +881,26 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua #endif private: + explicit MeshVisualizerGL2D(NoInitT) : Implementation::MeshVisualizerGLBase{NoInit} {} + Int _transformationProjectionMatrixUniform{9}; }; +class MeshVisualizerGL2D::CompileState : public MeshVisualizerGL2D { +private: + friend class MeshVisualizerGL2D; + + explicit CompileState(NoCreateT) : MeshVisualizerGL2D{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + + CompileState(MeshVisualizerGL2D&& shader, GL::Shader&& vert, GL::Shader&& frag, Containers::Optional&& geom, Flags flags, GL::Version version) : + MeshVisualizerGL2D{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _geom{std::move(geom)}, _flags{flags}, _version{version} {} + + GL::Shader _vert, _frag; + Containers::Optional _geom; + Flags _flags; + GL::Version _version; +}; + /** @brief 3D mesh visualization OpenGL shader @m_since_latest @@ -1639,7 +1675,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua * @m_deprecated_since{2020,06} Use @ref MeshVisualizerGL3D(Flags) * instead. */ - explicit CORRADE_DEPRECATED("use MeshVisualizerGL3D(Flags) instead") MeshVisualizerGL3D(): MeshVisualizerGL3D{{}} {} + explicit CORRADE_DEPRECATED("use MeshVisualizerGL3D(Flags) instead") MeshVisualizerGL3D(): MeshVisualizerGL3D{Flags{}} {} #endif #ifndef MAGNUM_TARGET_GLES2 @@ -1698,6 +1734,21 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua */ explicit MeshVisualizerGL3D(NoCreateT) noexcept: Implementation::MeshVisualizerGLBase{NoCreate} {} + class CompileState; + + explicit MeshVisualizerGL3D(CompileState&& cs); + + static CompileState compile(Flags flags + #ifndef MAGNUM_TARGET_GLES2 + , UnsignedInt materialCount, UnsignedInt drawCount + #endif + ); + + #ifndef MAGNUM_TARGET_GLES2 + static CompileState compile(Flags flags); + #endif + + /** @brief Copying is not allowed */ MeshVisualizerGL3D(const MeshVisualizerGL3D&) = delete; @@ -2326,6 +2377,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua #endif private: + explicit MeshVisualizerGL3D(NoInitT) : Implementation::MeshVisualizerGLBase{NoInit} {} + Int _transformationMatrixUniform{9}, _projectionMatrixUniform{10}; #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) @@ -2335,6 +2388,22 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua #endif }; +class MeshVisualizerGL3D::CompileState : public MeshVisualizerGL3D { +private: + friend class MeshVisualizerGL3D; + + explicit CompileState(NoCreateT) : MeshVisualizerGL3D{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + + CompileState(MeshVisualizerGL3D&& shader, GL::Shader&& vert, GL::Shader&& frag, Containers::Optional&& geom, Flags flags, GL::Version version) : + MeshVisualizerGL3D{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _geom{std::move(geom)}, _flags{flags}, _version{version} {} + + GL::Shader _vert, _frag; + Containers::Optional _geom; + Flags _flags; + GL::Version _version; +}; + + /** @debugoperatorclassenum{MeshVisualizerGL2D,MeshVisualizerGL2D::Flag} */ MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, MeshVisualizerGL2D::Flag value); diff --git a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp index 7ac0ac612..ce9289789 100644 --- a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp +++ b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef CORRADE_TARGET_APPLE @@ -88,12 +89,16 @@ struct MeshVisualizerGLTest: GL::OpenGLTester { explicit MeshVisualizerGLTest(); void construct2D(); + void construct2DAsync(); #ifndef MAGNUM_TARGET_GLES2 void constructUniformBuffers2D(); + void constructUniformBuffers2DAsync(); #endif void construct3D(); + void construct3DAsync(); #ifndef MAGNUM_TARGET_GLES2 void constructUniformBuffers3D(); + void constructUniformBuffers3DAsync(); #endif void construct2DInvalid(); @@ -1055,17 +1060,23 @@ MeshVisualizerGLTest::MeshVisualizerGLTest() { addInstancedTests({&MeshVisualizerGLTest::construct2D}, Containers::arraySize(ConstructData2D)); + addTests({&MeshVisualizerGLTest::construct2DAsync}); + #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({&MeshVisualizerGLTest::constructUniformBuffers2D}, Containers::arraySize(ConstructUniformBuffersData2D)); + addTests({&MeshVisualizerGLTest::constructUniformBuffers2DAsync}); #endif addInstancedTests({&MeshVisualizerGLTest::construct3D}, Containers::arraySize(ConstructData3D)); + addTests({&MeshVisualizerGLTest::construct3DAsync}); + #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({&MeshVisualizerGLTest::constructUniformBuffers3D}, Containers::arraySize(ConstructUniformBuffersData3D)); + addTests({&MeshVisualizerGLTest::constructUniformBuffers3DAsync}); #endif addInstancedTests({&MeshVisualizerGLTest::construct2DInvalid}, @@ -1403,6 +1414,78 @@ void MeshVisualizerGLTest::construct2D() { MAGNUM_VERIFY_NO_GL_ERROR(); } + +void MeshVisualizerGLTest::construct2DAsync() { + constexpr struct { + const char* name; + MeshVisualizerGL2D::Flags flags; + } data { + "wireframe w/o GS", MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader + }; + setTestCaseDescription(data.name); + + #ifndef MAGNUM_TARGET_GLES + if((data.flags & MeshVisualizerGL2D::Flag::InstancedObjectId) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); + #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if(data.flags >= MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL300) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES300) + #endif + ) CORRADE_SKIP("gl_VertexID not supported."); + #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if(data.flags & MeshVisualizerGL2D::Flag::PrimitiveId && !(data.flags >= MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId) && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL320) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES320) + #endif + ) CORRADE_SKIP("gl_PrimitiveID not supported."); + #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if((data.flags & MeshVisualizerGL2D::Flag::Wireframe) && !(data.flags & MeshVisualizerGL2D::Flag::NoGeometryShader)) { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() << "is not supported."); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() << "is not supported."); + #endif + + #ifdef MAGNUM_TARGET_GLES + if(GL::Context::current().isExtensionSupported()) + CORRADE_INFO("Using" << GL::Extensions::NV::shader_noperspective_interpolation::string()); + #endif + } + #endif + + auto compileState = MeshVisualizerGL2D::compile(data.flags); + CORRADE_COMPARE(compileState.flags(), data.flags); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL2D shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), data.flags); + CORRADE_VERIFY(shader.isLinkFinished()); + CORRADE_VERIFY(shader.id()); + { + #if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) + CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); + #endif + CORRADE_VERIFY(shader.validate().first); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} + #ifndef MAGNUM_TARGET_GLES2 void MeshVisualizerGLTest::constructUniformBuffers2D() { auto&& data = ConstructUniformBuffersData2D[testCaseInstanceId()]; @@ -1480,6 +1563,99 @@ void MeshVisualizerGLTest::constructUniformBuffers2D() { MAGNUM_VERIFY_NO_GL_ERROR(); } + + +void MeshVisualizerGLTest::constructUniformBuffers2DAsync() { + constexpr struct { + const char* name; + MeshVisualizerGL2D::Flags flags; + UnsignedInt materialCount, drawCount; + } data { + "multidraw with wireframe w/o GS and vertex ID", MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader|MeshVisualizerGL2D::Flag::VertexId, 8, 55 + }; + setTestCaseDescription(data.name); + + #ifndef MAGNUM_TARGET_GLES + if((data.flags & MeshVisualizerGL2D::Flag::InstancedObjectId) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); + #endif + + #ifndef MAGNUM_TARGET_WEBGL + if(data.flags >= MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL300) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES300) + #endif + ) CORRADE_SKIP("gl_VertexID not supported."); + #endif + + #ifndef MAGNUM_TARGET_WEBGL + if(data.flags & MeshVisualizerGL2D::Flag::PrimitiveId && !(data.flags >= MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId) && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL320) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES320) + #endif + ) CORRADE_SKIP("gl_PrimitiveID not supported."); + #endif + + #ifndef MAGNUM_TARGET_WEBGL + if((data.flags & MeshVisualizerGL2D::Flag::Wireframe) && !(data.flags & MeshVisualizerGL2D::Flag::NoGeometryShader)) { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() << "is not supported."); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() << "is not supported."); + #endif + + #ifdef MAGNUM_TARGET_GLES + if(GL::Context::current().isExtensionSupported()) + CORRADE_INFO("Using" << GL::Extensions::NV::shader_noperspective_interpolation::string()); + #endif + } + #endif + + #ifndef MAGNUM_TARGET_GLES + if(data.flags & MeshVisualizerGL2D::Flag::UniformBuffers && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + if(data.flags >= MeshVisualizerGL2D::Flag::MultiDraw) { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported."); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported."); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported."); + #endif + } + + auto compileState = MeshVisualizerGL2D::compile(data.flags, data.materialCount, data.drawCount); + CORRADE_COMPARE(compileState.flags(), data.flags); + CORRADE_COMPARE(compileState.materialCount(), data.materialCount); + CORRADE_COMPARE(compileState.drawCount(), data.drawCount); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL2D shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), data.flags); + CORRADE_VERIFY(shader.isLinkFinished()); + CORRADE_VERIFY(shader.id()); + { + #if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) + CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); + #endif + CORRADE_VERIFY(shader.validate().first); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} #endif void MeshVisualizerGLTest::construct3D() { @@ -1541,6 +1717,77 @@ void MeshVisualizerGLTest::construct3D() { MAGNUM_VERIFY_NO_GL_ERROR(); } +void MeshVisualizerGLTest::construct3DAsync() { + constexpr struct { + const char* name; + MeshVisualizerGL3D::Flags flags; + } data { + "object ID texture array", MeshVisualizerGL3D::Flag::ObjectIdTexture|MeshVisualizerGL3D::Flag::TextureArrays + }; + setTestCaseDescription(data.name); + + #ifndef MAGNUM_TARGET_GLES + if((data.flags & MeshVisualizerGL3D::Flag::InstancedObjectId) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); + #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if(data.flags >= MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL300) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES300) + #endif + ) CORRADE_SKIP("gl_VertexID not supported."); + #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if(data.flags & MeshVisualizerGL3D::Flag::PrimitiveId && !(data.flags >= MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId) && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL320) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES320) + #endif + ) CORRADE_SKIP("gl_PrimitiveID not supported."); + #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if(((data.flags & MeshVisualizerGL3D::Flag::Wireframe) && !(data.flags & MeshVisualizerGL3D::Flag::NoGeometryShader)) || (data.flags & (MeshVisualizerGL3D::Flag::TangentDirection|MeshVisualizerGL3D::Flag::BitangentDirection|MeshVisualizerGL3D::Flag::BitangentFromTangentDirection|MeshVisualizerGL3D::Flag::NormalDirection))) { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() << "is not supported."); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() << "is not supported."); + #endif + + #ifdef MAGNUM_TARGET_GLES + if(GL::Context::current().isExtensionSupported()) + CORRADE_INFO("Using" << GL::Extensions::NV::shader_noperspective_interpolation::string()); + #endif + } + #endif + + auto compileState = MeshVisualizerGL3D::compile(data.flags); + CORRADE_COMPARE(compileState.flags(), data.flags); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL3D shader{data.flags}; + CORRADE_COMPARE(shader.flags(), data.flags); + CORRADE_VERIFY(compileState.isLinkFinished()); + CORRADE_VERIFY(shader.id()); + { + #if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) + CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); + #endif + CORRADE_VERIFY(shader.validate().first); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} + #ifndef MAGNUM_TARGET_GLES2 void MeshVisualizerGLTest::constructUniformBuffers3D() { auto&& data = ConstructUniformBuffersData3D[testCaseInstanceId()]; @@ -1618,6 +1865,98 @@ void MeshVisualizerGLTest::constructUniformBuffers3D() { MAGNUM_VERIFY_NO_GL_ERROR(); } + +void MeshVisualizerGLTest::constructUniformBuffers3DAsync() { + constexpr struct { + const char* name; + MeshVisualizerGL3D::Flags flags; + UnsignedInt materialCount, drawCount; + } data { + "multidraw with wireframe w/o GS and vertex ID", MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader|MeshVisualizerGL3D::Flag::VertexId, 6, 28 + }; + setTestCaseDescription(data.name); + + #ifndef MAGNUM_TARGET_GLES + if((data.flags & MeshVisualizerGL3D::Flag::InstancedObjectId) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); + #endif + + #ifndef MAGNUM_TARGET_WEBGL + if(data.flags >= MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL300) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES300) + #endif + ) CORRADE_SKIP("gl_VertexID not supported."); + #endif + + #ifndef MAGNUM_TARGET_WEBGL + if(data.flags & MeshVisualizerGL3D::Flag::PrimitiveId && !(data.flags >= MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId) && + #ifndef MAGNUM_TARGET_GLES + !GL::Context::current().isVersionSupported(GL::Version::GL320) + #else + !GL::Context::current().isVersionSupported(GL::Version::GLES320) + #endif + ) CORRADE_SKIP("gl_PrimitiveID not supported."); + #endif + + #ifndef MAGNUM_TARGET_WEBGL + if(((data.flags & MeshVisualizerGL3D::Flag::Wireframe) && !(data.flags & MeshVisualizerGL3D::Flag::NoGeometryShader)) || (data.flags & (MeshVisualizerGL3D::Flag::TangentDirection|MeshVisualizerGL3D::Flag::BitangentDirection|MeshVisualizerGL3D::Flag::BitangentFromTangentDirection|MeshVisualizerGL3D::Flag::NormalDirection))) { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() << "is not supported."); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() << "is not supported."); + #endif + + #ifdef MAGNUM_TARGET_GLES + if(GL::Context::current().isExtensionSupported()) + CORRADE_INFO("Using" << GL::Extensions::NV::shader_noperspective_interpolation::string()); + #endif + } + #endif + + #ifndef MAGNUM_TARGET_GLES + if(data.flags & MeshVisualizerGL3D::Flag::UniformBuffers && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + if(data.flags >= MeshVisualizerGL3D::Flag::MultiDraw) { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported."); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported."); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported."); + #endif + } + + auto compileState = MeshVisualizerGL3D::compile(data.flags, data.materialCount, data.drawCount); + CORRADE_COMPARE(compileState.flags(), data.flags); + CORRADE_COMPARE(compileState.materialCount(), data.materialCount); + CORRADE_COMPARE(compileState.drawCount(), data.drawCount); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL3D shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), data.flags); + CORRADE_VERIFY(shader.isLinkFinished()); + CORRADE_VERIFY(shader.id()); + { + #if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) + CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); + #endif + CORRADE_VERIFY(shader.validate().first); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} #endif void MeshVisualizerGLTest::construct2DInvalid() { diff --git a/src/Magnum/Shaders/VectorGL.cpp b/src/Magnum/Shaders/VectorGL.cpp index d5f8224fd..af6b38550 100644 --- a/src/Magnum/Shaders/VectorGL.cpp +++ b/src/Magnum/Shaders/VectorGL.cpp @@ -138,7 +138,7 @@ template typename VectorGL::CompileState Vec vert.submitCompile(); frag.submitCompile(); - + VectorGL out{NoInit}; out._flags = flags; #ifndef MAGNUM_TARGET_GLES2 @@ -162,10 +162,9 @@ template typename VectorGL::CompileState Vec out.submitLink(); return CompileState{std::move(out), std::move(vert), std::move(frag), version}; - } -template VectorGL::VectorGL(CompileState&& cs) +template VectorGL::VectorGL(CompileState&& cs) : VectorGL{static_cast(std::move(cs))} { if (id() == 0) return;