diff --git a/src/Magnum/Shaders/DistanceFieldVectorGL.cpp b/src/Magnum/Shaders/DistanceFieldVectorGL.cpp index a33a9386d..6c627cf98 100644 --- a/src/Magnum/Shaders/DistanceFieldVectorGL.cpp +++ b/src/Magnum/Shaders/DistanceFieldVectorGL.cpp @@ -31,7 +31,6 @@ #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" -#include "Magnum/GL/Shader.h" #include "Magnum/GL/Texture.h" #include "Magnum/Math/Color.h" #include "Magnum/Math/Matrix3.h" @@ -63,22 +62,16 @@ namespace { #endif } -template DistanceFieldVectorGL::DistanceFieldVectorGL(const Flags flags +template typename DistanceFieldVectorGL::CompileState DistanceFieldVectorGL::compile(const Flags flags #ifndef MAGNUM_TARGET_GLES2 , const UnsignedInt materialCount, const UnsignedInt drawCount #endif -): - _flags{flags} - #ifndef MAGNUM_TARGET_GLES2 - , _materialCount{materialCount}, - _drawCount{drawCount} - #endif -{ +) { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, - "Shaders::DistanceFieldVectorGL: material count can't be zero", ); + "Shaders::DistanceFieldVectorGL: material count can't be zero", CompileState{NoCreate}); CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, - "Shaders::DistanceFieldVectorGL: draw count can't be zero", ); + "Shaders::DistanceFieldVectorGL: draw count can't be zero", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES @@ -142,9 +135,17 @@ template DistanceFieldVectorGL::DistanceFiel frag.addSource(rs.getString("generic.glsl")) .addSource(rs.getString("DistanceFieldVector.frag")); - CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); + vert.submitCompile(); + frag.submitCompile(); + + DistanceFieldVectorGL out{NoInit}; + out._flags = flags; + #ifndef MAGNUM_TARGET_GLES2 + out._materialCount = materialCount; + out._drawCount = drawCount; + #endif - attachShaders({vert, frag}); + out.attachShaders({vert, frag}); /* ES3 has this done in the shader directly */ #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) @@ -152,25 +153,35 @@ template DistanceFieldVectorGL::DistanceFiel if(!context.isExtensionSupported(version)) #endif { - bindAttributeLocation(Position::Location, "position"); - bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + out.bindAttributeLocation(Position::Location, "position"); + out.bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); } #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + out.submitLink(); + return CompileState{std::move(out), std::move(vert), std::move(frag), version}; +} + +template DistanceFieldVectorGL::DistanceFieldVectorGL(CompileState&& cs): DistanceFieldVectorGL{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; #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) #endif { #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"); } else #endif { _transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) _textureMatrixUniform = uniformLocation("textureMatrix"); _colorUniform = uniformLocation("color"); _outlineColorUniform = uniformLocation("outlineColor"); @@ -185,11 +196,11 @@ template DistanceFieldVectorGL::DistanceFiel { setUniform(uniformLocation("vectorTexture"), TextureUnit); #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding); } #endif @@ -198,13 +209,13 @@ template DistanceFieldVectorGL::DistanceFiel /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { /* Draw offset is zero by default */ } else #endif { setTransformationProjectionMatrix(MatrixTypeFor{Math::IdentityInit}); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setTextureMatrix(Matrix3{Math::IdentityInit}); setColor(Color4{1.0f}); /* Outline color is zero by default */ @@ -212,10 +223,22 @@ template DistanceFieldVectorGL::DistanceFiel setSmoothness(0.04f); } #endif + + static_cast(context); + static_cast(version); } +template DistanceFieldVectorGL::DistanceFieldVectorGL(NoInitT) {} + +template DistanceFieldVectorGL::DistanceFieldVectorGL(const Flags flags): DistanceFieldVectorGL{compile(flags)} {} + #ifndef MAGNUM_TARGET_GLES2 -template DistanceFieldVectorGL::DistanceFieldVectorGL(const Flags flags): DistanceFieldVectorGL{flags, 1, 1} {} +template typename DistanceFieldVectorGL::CompileState DistanceFieldVectorGL::compile(const Flags flags) { + return compile(flags, 1, 1); +} + +template DistanceFieldVectorGL::DistanceFieldVectorGL(const Flags flags, UnsignedInt materialCount, UnsignedInt drawCount): + DistanceFieldVectorGL{compile(flags, materialCount, drawCount)} {} #endif template DistanceFieldVectorGL& DistanceFieldVectorGL::setTransformationProjectionMatrix(const MatrixTypeFor& matrix) { diff --git a/src/Magnum/Shaders/DistanceFieldVectorGL.h b/src/Magnum/Shaders/DistanceFieldVectorGL.h index 42f21524f..f46773784 100644 --- a/src/Magnum/Shaders/DistanceFieldVectorGL.h +++ b/src/Magnum/Shaders/DistanceFieldVectorGL.h @@ -32,6 +32,7 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" +#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/visibility.h" @@ -280,6 +281,20 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector */ explicit DistanceFieldVectorGL(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {} + class CompileState; + + explicit DistanceFieldVectorGL(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 */ DistanceFieldVectorGL(const DistanceFieldVectorGL&) = delete; @@ -602,6 +617,8 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector #endif private: + explicit DistanceFieldVectorGL(NoInitT); + /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES using GL::AbstractShaderProgram::drawTransformFeedback; @@ -627,6 +644,20 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector #endif }; + +template class DistanceFieldVectorGL::CompileState: public DistanceFieldVectorGL { +private: + friend class DistanceFieldVectorGL; + + explicit CompileState(NoCreateT): DistanceFieldVectorGL{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + + CompileState(DistanceFieldVectorGL&& shader, GL::Shader&& vert, GL::Shader&& frag, GL::Version version): + DistanceFieldVectorGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _version{version} {} + + GL::Shader _vert, _frag; + GL::Version _version; +}; + /** @brief Two-dimensional distance field vector OpenGL shader @m_since_latest diff --git a/src/Magnum/Shaders/FlatGL.cpp b/src/Magnum/Shaders/FlatGL.cpp index 86504acad..645d7eade 100644 --- a/src/Magnum/Shaders/FlatGL.cpp +++ b/src/Magnum/Shaders/FlatGL.cpp @@ -31,7 +31,6 @@ #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" -#include "Magnum/GL/Shader.h" #include "Magnum/GL/Texture.h" #include "Magnum/Math/Color.h" #include "Magnum/Math/Matrix3.h" @@ -68,16 +67,11 @@ namespace { #endif } -template FlatGL::FlatGL(const Flags flags - #ifndef MAGNUM_TARGET_GLES2 - , const UnsignedInt materialCount, const UnsignedInt drawCount - #endif -): - _flags{flags} - #ifndef MAGNUM_TARGET_GLES2 - , _materialCount{materialCount}, _drawCount{drawCount} - #endif -{ +template typename FlatGL::CompileState FlatGL::compile(Flags flags +#ifndef MAGNUM_TARGET_GLES2 +, UnsignedInt materialCount, UnsignedInt drawCount +#endif +) { #ifndef CORRADE_NO_ASSERT { const bool textureTransformationNotEnabledOrTextured = !(flags & Flag::TextureTransformation) || flags & Flag::Textured @@ -86,22 +80,22 @@ template FlatGL::FlatGL(const Flags flags #endif ; CORRADE_ASSERT(textureTransformationNotEnabledOrTextured, - "Shaders::FlatGL: texture transformation enabled but the shader is not textured", ); + "Shaders::FlatGL: texture transformation enabled but the shader is not textured", CompileState{NoCreate}); } #endif #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, - "Shaders::FlatGL: material count can't be zero", ); + "Shaders::FlatGL: material count can't be zero", CompileState{NoCreate}); CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, - "Shaders::FlatGL: draw count can't be zero", ); + "Shaders::FlatGL: draw count can't be zero", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags & Flag::TextureArrays) || flags & Flag::Textured || flags >= Flag::ObjectIdTexture, - "Shaders::FlatGL: texture arrays enabled but the shader is not textured", ); + "Shaders::FlatGL: texture arrays enabled but the shader is not textured", CompileState{NoCreate}); CORRADE_ASSERT(!(flags & Flag::UniformBuffers) || !(flags & Flag::TextureArrays) || flags >= (Flag::TextureArrays|Flag::TextureTransformation), - "Shaders::FlatGL: texture arrays require texture transformation enabled as well if uniform buffers are used", ); + "Shaders::FlatGL: texture arrays require texture transformation enabled as well if uniform buffers are used", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES @@ -195,9 +189,17 @@ template FlatGL::FlatGL(const Flags flags frag.addSource(rs.getString("generic.glsl")) .addSource(rs.getString("Flat.frag")); - CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); + vert.submitCompile(); + frag.submitCompile(); - attachShaders({vert, frag}); + FlatGL out{NoInit}; + out._flags = flags; + #ifndef MAGNUM_TARGET_GLES2 + out._materialCount = materialCount; + out._drawCount = drawCount; + #endif + + out.attachShaders({vert, frag}); /* ES3 has this done in the shader directly and doesn't even provide bindFragmentDataLocation() */ @@ -206,53 +208,64 @@ template FlatGL::FlatGL(const Flags flags if(!context.isExtensionSupported(version)) #endif { - bindAttributeLocation(Position::Location, "position"); + out.bindAttributeLocation(Position::Location, "position"); if(flags & Flag::Textured #ifndef MAGNUM_TARGET_GLES2 || flags >= Flag::ObjectIdTexture #endif ) - bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + out.bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); if(flags & Flag::VertexColor) - bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ + out.bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ #ifndef MAGNUM_TARGET_GLES2 if(flags & Flag::ObjectId) { - bindFragmentDataLocation(ColorOutput, "color"); - bindFragmentDataLocation(ObjectIdOutput, "objectId"); + out.bindFragmentDataLocation(ColorOutput, "color"); + out.bindFragmentDataLocation(ObjectIdOutput, "objectId"); } 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(flags >= Flag::InstancedTextureOffset) - bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); + out.bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); } #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + out.submitLink(); + + return CompileState{std::move(out), std::move(vert), std::move(frag), version}; +} + +template FlatGL::FlatGL(CompileState&& cs): FlatGL{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; #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) #endif { #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"); } else #endif { _transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) _textureMatrixUniform = uniformLocation("textureMatrix"); #ifndef MAGNUM_TARGET_GLES2 - if(flags & Flag::TextureArrays) + if(_flags & Flag::TextureArrays) _textureLayerUniform = uniformLocation("textureLayer"); #endif _colorUniform = uniformLocation("color"); - if(flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask"); + if(_flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask"); #ifndef MAGNUM_TARGET_GLES2 - if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId"); + if(_flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId"); #endif } } @@ -261,13 +274,13 @@ template FlatGL::FlatGL(const Flags flags if(!context.isExtensionSupported(version)) #endif { - if(flags & Flag::Textured) setUniform(uniformLocation("textureData"), TextureUnit); + if(_flags & Flag::Textured) setUniform(uniformLocation("textureData"), TextureUnit); #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"), ObjectIdTextureUnit); - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"), ObjectIdTextureUnit); + if(_flags >= Flag::UniformBuffers) { setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding); setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding); } @@ -277,26 +290,38 @@ template FlatGL::FlatGL(const Flags flags /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { /* Draw offset is zero by default */ } else #endif { setTransformationProjectionMatrix(MatrixTypeFor{Math::IdentityInit}); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setTextureMatrix(Matrix3{Math::IdentityInit}); /* Texture layer is zero by default */ setColor(Magnum::Color4{1.0f}); - if(flags & Flag::AlphaMask) setAlphaMask(0.5f); + if(_flags & Flag::AlphaMask) setAlphaMask(0.5f); /* Object ID is zero by default */ } #endif + + static_cast(version); + static_cast(context); } +template FlatGL::FlatGL(Flags flags): FlatGL{compile(flags)} {} + #ifndef MAGNUM_TARGET_GLES2 -template FlatGL::FlatGL(const Flags flags): FlatGL{flags, 1, 1} {} +template typename FlatGL::CompileState FlatGL::compile(Flags flags) { + return compile(flags, 1, 1); +} + +template FlatGL::FlatGL(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount): + FlatGL{compile(flags, materialCount, drawCount)} {} #endif +template FlatGL::FlatGL(NoInitT) {} + template FlatGL& FlatGL::setTransformationProjectionMatrix(const MatrixTypeFor& matrix) { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), diff --git a/src/Magnum/Shaders/FlatGL.h b/src/Magnum/Shaders/FlatGL.h index bd76a49c8..354d43240 100644 --- a/src/Magnum/Shaders/FlatGL.h +++ b/src/Magnum/Shaders/FlatGL.h @@ -32,6 +32,7 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" +#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/visibility.h" @@ -602,6 +603,20 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: */ explicit FlatGL(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {} + class CompileState; + + explicit FlatGL(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 */ FlatGL(const FlatGL&) = delete; @@ -1011,6 +1026,9 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: #endif private: + /* Creates the GL shader program object but nothing else. Internal, used by compile(). */ + explicit FlatGL(NoInitT); + /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES using GL::AbstractShaderProgram::drawTransformFeedback; @@ -1038,6 +1056,19 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: #endif }; +template class FlatGL::CompileState: public FlatGL { +private: + friend class FlatGL; + + explicit CompileState(NoCreateT): FlatGL{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + + CompileState(FlatGL&& shader, GL::Shader&& vert, GL::Shader&& frag, GL::Version version): + FlatGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _version{version} {} + + GL::Shader _vert, _frag; + GL::Version _version; +}; + /** @brief 2D flat OpenGL shader @m_since_latest diff --git a/src/Magnum/Shaders/MeshVisualizerGL.cpp b/src/Magnum/Shaders/MeshVisualizerGL.cpp index 615231aa5..6aaaac536 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 +MeshVisualizerGL2D::CompileState MeshVisualizerGL2D::compile(Flags flags) { + return compile(flags, 1, 1); +} + +MeshVisualizerGL2D::MeshVisualizerGL2D(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount) + : MeshVisualizerGL2D{compile(flags, materialCount, drawCount)} {} +#endif + +MeshVisualizerGL2D::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)) @@ -608,11 +633,10 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags #endif } #endif -} -#ifndef MAGNUM_TARGET_GLES2 -MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): MeshVisualizerGL2D{flags, 1, 1} {} -#endif + static_cast(context); + static_cast(version); +} MeshVisualizerGL2D& MeshVisualizerGL2D::setViewportSize(const Vector2& size) { /* Not asserting here, since the relation to wireframe is a bit vague. @@ -674,33 +698,32 @@ 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", ); + "Shaders::MeshVisualizerGL3D: at least Flag::Wireframe has to be enabled", CompileState{NoCreate}); #endif #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 +731,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 +743,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 +796,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 +808,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 +827,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 +838,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 +892,25 @@ 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(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)) @@ -996,10 +1038,20 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags #endif } #endif + + static_cast(context); + static_cast(version); } +MeshVisualizerGL3D::MeshVisualizerGL3D(Flags flags) : MeshVisualizerGL3D{compile(flags)} {} + #ifndef MAGNUM_TARGET_GLES2 -MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): MeshVisualizerGL3D{flags, 1, 1} {} +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::setTransformationMatrix(const Matrix4& matrix) { diff --git a/src/Magnum/Shaders/MeshVisualizerGL.h b/src/Magnum/Shaders/MeshVisualizerGL.h index b217f1d39..aa58e7f45 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/PhongGL.cpp b/src/Magnum/Shaders/PhongGL.cpp index a23561463..bd8bf9e65 100644 --- a/src/Magnum/Shaders/PhongGL.cpp +++ b/src/Magnum/Shaders/PhongGL.cpp @@ -37,7 +37,6 @@ #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" -#include "Magnum/GL/Shader.h" #include "Magnum/GL/Texture.h" #include "Magnum/Math/Color.h" #include "Magnum/Math/Matrix3.h" @@ -74,21 +73,12 @@ namespace { #endif } -PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount +PhongGL::CompileState PhongGL::compile(const Flags flags, const UnsignedInt lightCount #ifndef MAGNUM_TARGET_GLES2 , const UnsignedInt materialCount, const UnsignedInt drawCount #endif -): - _flags{flags}, - _lightCount{lightCount}, - #ifndef MAGNUM_TARGET_GLES2 - _materialCount{materialCount}, - _drawCount{drawCount}, - #endif - _lightColorsUniform{_lightPositionsUniform + Int(lightCount)}, - _lightSpecularColorsUniform{_lightPositionsUniform + 2*Int(lightCount)}, - _lightRangesUniform{_lightPositionsUniform + 3*Int(lightCount)} -{ +) { + #ifndef CORRADE_NO_ASSERT { const bool textureTransformationNotEnabledOrTextured = !(flags & Flag::TextureTransformation) || (flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture)) #ifndef MAGNUM_TARGET_GLES2 @@ -96,32 +86,33 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount #endif ; CORRADE_ASSERT(textureTransformationNotEnabledOrTextured, - "Shaders::PhongGL: texture transformation enabled but the shader is not textured", ); + "Shaders::PhongGL: texture transformation enabled but the shader is not textured", CompileState{NoCreate}); } + #endif #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::InstancedObjectId) || !(flags & Flag::Bitangent), - "Shaders::PhongGL: Bitangent attribute binding conflicts with the ObjectId attribute, use a Tangent4 attribute with instanced object ID rendering instead", ); + "Shaders::PhongGL: Bitangent attribute binding conflicts with the ObjectId attribute, use a Tangent4 attribute with instanced object ID rendering instead", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, - "Shaders::PhongGL: material count can't be zero", ); + "Shaders::PhongGL: material count can't be zero", CompileState{NoCreate}); CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, - "Shaders::PhongGL: draw count can't be zero", ); + "Shaders::PhongGL: draw count can't be zero", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags & Flag::TextureArrays) || (flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture)) || flags >= Flag::ObjectIdTexture, - "Shaders::PhongGL: texture arrays enabled but the shader is not textured", ); + "Shaders::PhongGL: texture arrays enabled but the shader is not textured", CompileState{NoCreate}); CORRADE_ASSERT(!(flags & Flag::UniformBuffers) || !(flags & Flag::TextureArrays) || flags >= (Flag::TextureArrays|Flag::TextureTransformation), - "Shaders::PhongGL: texture arrays require texture transformation enabled as well if uniform buffers are used", ); + "Shaders::PhongGL: texture arrays require texture transformation enabled as well if uniform buffers are used", CompileState{NoCreate}); CORRADE_ASSERT(!(flags & Flag::LightCulling) || (flags & Flag::UniformBuffers), - "Shaders::PhongGL: light culling requires uniform buffers to be enabled", ); + "Shaders::PhongGL: light culling requires uniform buffers to be enabled", CompileState{NoCreate}); #endif CORRADE_ASSERT(!(flags & Flag::SpecularTexture) || !(flags & (Flag::NoSpecular)), - "Shaders::PhongGL: specular texture requires the shader to not have specular disabled", ); + "Shaders::PhongGL: specular texture requires the shader to not have specular disabled", CompileState{NoCreate}); #ifndef MAGNUM_TARGET_GLES if(flags >= Flag::UniformBuffers) @@ -154,7 +145,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount #ifndef MAGNUM_TARGET_GLES CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || context.isExtensionSupported(), - "Shaders::PhongGL: uniform buffers require" << GL::Extensions::ARB::uniform_buffer_object::string(), ); + "Shaders::PhongGL: uniform buffers require" << GL::Extensions::ARB::uniform_buffer_object::string(), CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES @@ -163,6 +154,17 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount const GL::Version version = context.supportedVersion({GL::Version::GLES300, GL::Version::GLES200}); #endif + PhongGL out{NoInit}; + out._flags = flags; + out._lightCount = lightCount; + out._lightColorsUniform = out._lightPositionsUniform + Int(lightCount); + out._lightSpecularColorsUniform = out._lightPositionsUniform + 2*Int(lightCount); + out._lightRangesUniform = out._lightPositionsUniform + 3*Int(lightCount); + #ifndef MAGNUM_TARGET_GLES2 + out._materialCount = materialCount; + out._drawCount = drawCount; + #endif + GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex); GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); @@ -283,9 +285,9 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount "#define LIGHT_SPECULAR_COLORS_LOCATION {}\n" "#define LIGHT_RANGES_LOCATION {}\n", lightCount, - _lightPositionsUniform + lightCount, - _lightPositionsUniform + 2*lightCount, - _lightPositionsUniform + 3*lightCount)); + out._lightPositionsUniform + lightCount, + out._lightPositionsUniform + 2*lightCount, + out._lightPositionsUniform + 3*lightCount)); } #ifndef MAGNUM_TARGET_GLES if(!(flags >= Flag::UniformBuffers) && lightCount) @@ -294,9 +296,10 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount frag.addSource(rs.getString("generic.glsl")) .addSource(rs.getString("Phong.frag")); - CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); + vert.submitCompile(); + frag.submitCompile(); - attachShaders({vert, frag}); + out.attachShaders({vert, frag}); /* ES3 has this done in the shader directly and doesn't even provide bindFragmentDataLocation() */ @@ -305,103 +308,114 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount if(!context.isExtensionSupported(version)) #endif { - bindAttributeLocation(Position::Location, "position"); + out.bindAttributeLocation(Position::Location, "position"); if(lightCount) - bindAttributeLocation(Normal::Location, "normal"); + out.bindAttributeLocation(Normal::Location, "normal"); if((flags & Flag::NormalTexture) && lightCount) { - bindAttributeLocation(Tangent::Location, "tangent"); + out.bindAttributeLocation(Tangent::Location, "tangent"); if(flags & Flag::Bitangent) - bindAttributeLocation(Bitangent::Location, "bitangent"); + out.bindAttributeLocation(Bitangent::Location, "bitangent"); } if(flags & Flag::VertexColor) - bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ + out.bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ if(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture) #ifndef MAGNUM_TARGET_GLES2 || flags >= Flag::ObjectIdTexture #endif ) - bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + out.bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); #ifndef MAGNUM_TARGET_GLES2 if(flags & Flag::ObjectId) { - bindFragmentDataLocation(ColorOutput, "color"); - bindFragmentDataLocation(ObjectIdOutput, "objectId"); + out.bindFragmentDataLocation(ColorOutput, "color"); + out.bindFragmentDataLocation(ObjectIdOutput, "objectId"); } 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(lightCount) - bindAttributeLocation(NormalMatrix::Location, "instancedNormalMatrix"); + out.bindAttributeLocation(NormalMatrix::Location, "instancedNormalMatrix"); } if(flags >= Flag::InstancedTextureOffset) - bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); + out.bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); } #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + out.submitLink(); + + return CompileState{std::move(out), std::move(vert), std::move(frag), version}; +} + +PhongGL::PhongGL(CompileState&& cs): PhongGL{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; #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) #endif { #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"); } else #endif { _transformationMatrixUniform = uniformLocation("transformationMatrix"); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) _textureMatrixUniform = uniformLocation("textureMatrix"); #ifndef MAGNUM_TARGET_GLES2 - if(flags & Flag::TextureArrays) + if(_flags & Flag::TextureArrays) _textureLayerUniform = uniformLocation("textureLayer"); #endif _projectionMatrixUniform = uniformLocation("projectionMatrix"); _ambientColorUniform = uniformLocation("ambientColor"); - if(lightCount) { + if(_lightCount) { _normalMatrixUniform = uniformLocation("normalMatrix"); _diffuseColorUniform = uniformLocation("diffuseColor"); - if(!(flags & Flag::NoSpecular)) { + if(!(_flags & Flag::NoSpecular)) { _specularColorUniform = uniformLocation("specularColor"); _shininessUniform = uniformLocation("shininess"); } - if(flags & Flag::NormalTexture) + if(_flags & Flag::NormalTexture) _normalTextureScaleUniform = uniformLocation("normalTextureScale"); _lightPositionsUniform = uniformLocation("lightPositions"); _lightColorsUniform = uniformLocation("lightColors"); - if(!(flags & Flag::NoSpecular)) + if(!(_flags & Flag::NoSpecular)) _lightSpecularColorsUniform = uniformLocation("lightSpecularColors"); _lightRangesUniform = uniformLocation("lightRanges"); } - if(flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask"); + if(_flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask"); #ifndef MAGNUM_TARGET_GLES2 - if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId"); + if(_flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId"); #endif } } #ifndef MAGNUM_TARGET_GLES - if(flags && !context.isExtensionSupported(version)) + if(_flags && !context.isExtensionSupported(version)) #endif { - if(flags & Flag::AmbientTexture) setUniform(uniformLocation("ambientTexture"), AmbientTextureUnit); - if(lightCount) { - if(flags & Flag::DiffuseTexture) setUniform(uniformLocation("diffuseTexture"), DiffuseTextureUnit); - if(flags & Flag::SpecularTexture) setUniform(uniformLocation("specularTexture"), SpecularTextureUnit); - if(flags & Flag::NormalTexture) setUniform(uniformLocation("normalTexture"), NormalTextureUnit); + if(_flags & Flag::AmbientTexture) setUniform(uniformLocation("ambientTexture"), AmbientTextureUnit); + if(_lightCount) { + if(_flags & Flag::DiffuseTexture) setUniform(uniformLocation("diffuseTexture"), DiffuseTextureUnit); + if(_flags & Flag::SpecularTexture) setUniform(uniformLocation("specularTexture"), SpecularTextureUnit); + if(_flags & Flag::NormalTexture) setUniform(uniformLocation("normalTexture"), NormalTextureUnit); } #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"), ObjectIdTextureUnit); - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"), ObjectIdTextureUnit); + if(_flags >= Flag::UniformBuffers) { setUniformBlockBinding(uniformBlockIndex("Projection"), ProjectionBufferBinding); setUniformBlockBinding(uniformBlockIndex("Transformation"), TransformationBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding); - if(lightCount) + if(_lightCount) setUniformBlockBinding(uniformBlockIndex("Light"), LightBufferBinding); } #endif @@ -410,44 +424,54 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { /* Draw offset is zero by default */ } else #endif { /* Default to fully opaque white so we can see the textures */ - if(flags & Flag::AmbientTexture) setAmbientColor(Magnum::Color4{1.0f}); + if(_flags & Flag::AmbientTexture) setAmbientColor(Magnum::Color4{1.0f}); else setAmbientColor(Magnum::Color4{0.0f}); setTransformationMatrix(Matrix4{Math::IdentityInit}); setProjectionMatrix(Matrix4{Math::IdentityInit}); - if(lightCount) { + if(_lightCount) { setDiffuseColor(Magnum::Color4{1.0f}); - if(!(flags & Flag::NoSpecular)) { + if(!(_flags & Flag::NoSpecular)) { setSpecularColor(Magnum::Color4{1.0f, 0.0f}); setShininess(80.0f); } - if(flags & Flag::NormalTexture) + if(_flags & Flag::NormalTexture) setNormalTextureScale(1.0f); - setLightPositions(Containers::Array{DirectInit, lightCount, Vector4{0.0f, 0.0f, 1.0f, 0.0f}}); - Containers::Array colors{DirectInit, lightCount, Magnum::Color3{1.0f}}; + setLightPositions(Containers::Array{DirectInit, _lightCount, Vector4{0.0f, 0.0f, 1.0f, 0.0f}}); + Containers::Array colors{DirectInit, _lightCount, Magnum::Color3{1.0f}}; setLightColors(colors); - if(!(flags & Flag::NoSpecular)) + if(!(_flags & Flag::NoSpecular)) setLightSpecularColors(colors); - setLightRanges(Containers::Array{DirectInit, lightCount, Constants::inf()}); + setLightRanges(Containers::Array{DirectInit, _lightCount, Constants::inf()}); /* Light position is zero by default */ setNormalMatrix(Matrix3x3{Math::IdentityInit}); } - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setTextureMatrix(Matrix3{Math::IdentityInit}); /* Texture layer is zero by default */ - if(flags & Flag::AlphaMask) setAlphaMask(0.5f); + if(_flags & Flag::AlphaMask) setAlphaMask(0.5f); /* Object ID is zero by default */ } #endif + + static_cast(context); + static_cast(version); } +PhongGL::PhongGL(Flags flags, UnsignedInt lightCount): PhongGL{compile(flags, lightCount)} {} + #ifndef MAGNUM_TARGET_GLES2 -PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): PhongGL{flags, lightCount, 1, 1} {} +PhongGL::CompileState PhongGL::compile(Flags flags, UnsignedInt lightCount) { + return compile(flags, lightCount, 1, 1); +} + +PhongGL::PhongGL(Flags flags, UnsignedInt lightCount, UnsignedInt materialCount, UnsignedInt drawCount): + PhongGL{compile(flags, lightCount, materialCount, drawCount)} {} #endif PhongGL& PhongGL::setAmbientColor(const Magnum::Color4& color) { diff --git a/src/Magnum/Shaders/PhongGL.h b/src/Magnum/Shaders/PhongGL.h index 1a59c564b..8a06e2ccc 100644 --- a/src/Magnum/Shaders/PhongGL.h +++ b/src/Magnum/Shaders/PhongGL.h @@ -31,6 +31,7 @@ */ #include "Magnum/GL/AbstractShaderProgram.h" +#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/visibility.h" @@ -821,6 +822,20 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram { */ explicit PhongGL(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {} + class CompileState; + + explicit PhongGL(CompileState&& cs); + + static CompileState compile(Flags flags, UnsignedInt lightCount + #ifndef MAGNUM_TARGET_GLES2 + , UnsignedInt materialCount, UnsignedInt drawCount + #endif + ); + + #ifndef MAGNUM_TARGET_GLES2 + static CompileState compile(Flags flags, UnsignedInt lightCount); + #endif + /** @brief Copying is not allowed */ PhongGL(const PhongGL&) = delete; @@ -1744,6 +1759,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram { #endif private: + explicit PhongGL(NoInitT) {} + /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES using GL::AbstractShaderProgram::drawTransformFeedback; @@ -1784,6 +1801,19 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram { #endif }; +class PhongGL::CompileState: public PhongGL { +private: + friend class PhongGL; + + explicit CompileState(NoCreateT): PhongGL{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + + CompileState(PhongGL&& shader, GL::Shader&& vert, GL::Shader&& frag, GL::Version version): + PhongGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _version{version} {} + + GL::Shader _vert, _frag; + GL::Version _version; +}; + /** @debugoperatorclassenum{PhongGL,PhongGL::Flag} */ MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, PhongGL::Flag value); diff --git a/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp b/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp index d8bf027ac..e23db4a99 100644 --- a/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp +++ b/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef CORRADE_TARGET_APPLE @@ -84,8 +85,10 @@ struct DistanceFieldVectorGLTest: GL::OpenGLTester { explicit DistanceFieldVectorGLTest(); template void construct(); + template void constructAsync(); #ifndef MAGNUM_TARGET_GLES2 template void constructUniformBuffers(); + template void constructUniformBuffersAsync(); #endif template void constructMove(); @@ -251,11 +254,19 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() { &DistanceFieldVectorGLTest::construct<3>}, Containers::arraySize(ConstructData)); + addTests({ + &DistanceFieldVectorGLTest::constructAsync<2>, + &DistanceFieldVectorGLTest::constructAsync<3>}); + #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({ &DistanceFieldVectorGLTest::constructUniformBuffers<2>, &DistanceFieldVectorGLTest::constructUniformBuffers<3>}, Containers::arraySize(ConstructUniformBuffersData)); + + addTests({ + &DistanceFieldVectorGLTest::constructUniformBuffersAsync<2>, + &DistanceFieldVectorGLTest::constructUniformBuffersAsync<3>}); #endif addTests({ @@ -374,6 +385,29 @@ template void DistanceFieldVectorGLTest::construct() { MAGNUM_VERIFY_NO_GL_ERROR(); } +template void DistanceFieldVectorGLTest::constructAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + auto compileState = DistanceFieldVectorGL::compile(DistanceFieldVectorGL2D::Flag::TextureTransformation); + CORRADE_COMPARE(compileState.flags(), DistanceFieldVectorGL2D::Flag::TextureTransformation); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + DistanceFieldVectorGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), DistanceFieldVectorGL2D::Flag::TextureTransformation); + 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 template void DistanceFieldVectorGLTest::constructUniformBuffers() { setTestCaseTemplateName(Utility::format("{}", dimensions)); @@ -413,6 +447,39 @@ template void DistanceFieldVectorGLTest::constructUnifor MAGNUM_VERIFY_NO_GL_ERROR(); } + +template void DistanceFieldVectorGLTest::constructUniformBuffersAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + auto compileState = DistanceFieldVectorGL::compile(DistanceFieldVectorGL2D::Flag::UniformBuffers, 16, 4); + CORRADE_COMPARE(compileState.flags(), DistanceFieldVectorGL2D::Flag::UniformBuffers); + CORRADE_COMPARE(compileState.materialCount(), 16); + CORRADE_COMPARE(compileState.drawCount(), 4); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + DistanceFieldVectorGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), DistanceFieldVectorGL2D::Flag::UniformBuffers); + CORRADE_COMPARE(shader.materialCount(), 16); + CORRADE_COMPARE(shader.drawCount(), 4); + 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 template void DistanceFieldVectorGLTest::constructMove() { diff --git a/src/Magnum/Shaders/Test/FlatGLTest.cpp b/src/Magnum/Shaders/Test/FlatGLTest.cpp index 730bb0fad..192c5fca2 100644 --- a/src/Magnum/Shaders/Test/FlatGLTest.cpp +++ b/src/Magnum/Shaders/Test/FlatGLTest.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef CORRADE_TARGET_APPLE @@ -83,8 +84,10 @@ struct FlatGLTest: GL::OpenGLTester { explicit FlatGLTest(); template void construct(); + template void constructAsync(); #ifndef MAGNUM_TARGET_GLES2 template void constructUniformBuffers(); + template void constructUniformBuffersAsync(); #endif template void constructMove(); @@ -600,11 +603,19 @@ FlatGLTest::FlatGLTest() { &FlatGLTest::construct<3>}, Containers::arraySize(ConstructData)); + addTests({ + &FlatGLTest::constructAsync<2>, + &FlatGLTest::constructAsync<3>}); + #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({ &FlatGLTest::constructUniformBuffers<2>, &FlatGLTest::constructUniformBuffers<3>}, Containers::arraySize(ConstructUniformBuffersData)); + + addTests({ + &FlatGLTest::constructUniformBuffersAsync<2>, + &FlatGLTest::constructUniformBuffersAsync<3>}); #endif addTests({ @@ -853,6 +864,28 @@ template void FlatGLTest::construct() { MAGNUM_VERIFY_NO_GL_ERROR(); } +template void FlatGLTest::constructAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + auto compileState = FlatGL::compile(FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation); + CORRADE_COMPARE(compileState.flags(), FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + FlatGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation); + + 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 template void FlatGLTest::constructUniformBuffers() { setTestCaseTemplateName(Utility::format("{}", dimensions)); @@ -896,6 +929,38 @@ template void FlatGLTest::constructUniformBuffers() { MAGNUM_VERIFY_NO_GL_ERROR(); } + +template void FlatGLTest::constructUniformBuffersAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + auto compileState = FlatGL::compile(FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask, 1, 1); + CORRADE_COMPARE(compileState.flags(), FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask); + CORRADE_COMPARE(compileState.materialCount(), 1); + CORRADE_COMPARE(compileState.drawCount(), 1); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + FlatGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask); + CORRADE_COMPARE(shader.materialCount(), 1); + CORRADE_COMPARE(shader.drawCount(), 1); + 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 template void FlatGLTest::constructMove() { diff --git a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp index 7ac0ac612..fbe96056e 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,28 @@ void MeshVisualizerGLTest::construct2D() { MAGNUM_VERIFY_NO_GL_ERROR(); } + +void MeshVisualizerGLTest::construct2DAsync() { + auto compileState = MeshVisualizerGL2D::compile(MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader); + CORRADE_COMPARE(compileState.flags(), MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL2D shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader); + 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,8 +1513,40 @@ void MeshVisualizerGLTest::constructUniformBuffers2D() { MAGNUM_VERIFY_NO_GL_ERROR(); } + + +void MeshVisualizerGLTest::constructUniformBuffers2DAsync() { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + auto compileState = MeshVisualizerGL2D::compile( MeshVisualizerGL2D::Flag::UniformBuffers|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader, 8, 55); + CORRADE_COMPARE(compileState.flags(), MeshVisualizerGL2D::Flag::UniformBuffers|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader); + CORRADE_COMPARE(compileState.materialCount(), 8); + CORRADE_COMPARE(compileState.drawCount(), 55); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL2D shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), MeshVisualizerGL2D::Flag::UniformBuffers|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader); + CORRADE_COMPARE(shader.materialCount(), 8); + CORRADE_COMPARE(shader.drawCount(), 55); + 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() { auto&& data = ConstructData3D[testCaseInstanceId()]; setTestCaseDescription(data.name); @@ -1541,6 +1606,27 @@ void MeshVisualizerGLTest::construct3D() { MAGNUM_VERIFY_NO_GL_ERROR(); } +void MeshVisualizerGLTest::construct3DAsync() { + auto compileState = MeshVisualizerGL3D::compile(MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader); + CORRADE_COMPARE(compileState.flags(), MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL3D shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader); + 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::constructUniformBuffers3D() { auto&& data = ConstructUniformBuffersData3D[testCaseInstanceId()]; @@ -1618,6 +1704,36 @@ void MeshVisualizerGLTest::constructUniformBuffers3D() { MAGNUM_VERIFY_NO_GL_ERROR(); } + +void MeshVisualizerGLTest::constructUniformBuffers3DAsync() { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + auto compileState = MeshVisualizerGL3D::compile(MeshVisualizerGL3D::Flag::UniformBuffers|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader, 6, 28); + CORRADE_COMPARE(compileState.flags(), MeshVisualizerGL3D::Flag::UniformBuffers|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader); + CORRADE_COMPARE(compileState.materialCount(), 6); + CORRADE_COMPARE(compileState.drawCount(), 28); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + MeshVisualizerGL3D shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), MeshVisualizerGL3D::Flag::UniformBuffers|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader); + CORRADE_COMPARE(compileState.materialCount(), 6); + CORRADE_COMPARE(compileState.drawCount(), 28); + 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/Test/PhongGLTest.cpp b/src/Magnum/Shaders/Test/PhongGLTest.cpp index e6414a2c2..d0df58ec4 100644 --- a/src/Magnum/Shaders/Test/PhongGLTest.cpp +++ b/src/Magnum/Shaders/Test/PhongGLTest.cpp @@ -31,12 +31,12 @@ #include #include #include +#include #include #include #ifdef CORRADE_TARGET_APPLE #include -#include /* isSandboxed() */ #endif #include "Magnum/Image.h" @@ -83,8 +83,10 @@ struct PhongGLTest: GL::OpenGLTester { explicit PhongGLTest(); void construct(); + void constructAsync(); #ifndef MAGNUM_TARGET_GLES2 void constructUniformBuffers(); + void constructUniformBuffersAsync(); #endif void constructMove(); @@ -927,9 +929,13 @@ PhongGLTest::PhongGLTest() { addInstancedTests({&PhongGLTest::construct}, Containers::arraySize(ConstructData)); + addTests({&PhongGLTest::constructAsync}); + #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({&PhongGLTest::constructUniformBuffers}, Containers::arraySize(ConstructUniformBuffersData)); + + addTests({&PhongGLTest::constructUniformBuffersAsync}); #endif addTests({ @@ -1192,6 +1198,29 @@ void PhongGLTest::construct() { MAGNUM_VERIFY_NO_GL_ERROR(); } +void PhongGLTest::constructAsync() { + auto compileState = PhongGL::compile(PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset, 3); + CORRADE_COMPARE(compileState.flags(), PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset); + CORRADE_COMPARE(compileState.lightCount(), 3); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + PhongGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset); + CORRADE_COMPARE(shader.lightCount(), 3); + 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 PhongGLTest::constructUniformBuffers() { auto&& data = ConstructUniformBuffersData[testCaseInstanceId()]; @@ -1234,6 +1263,38 @@ void PhongGLTest::constructUniformBuffers() { MAGNUM_VERIFY_NO_GL_ERROR(); } + +void PhongGLTest::constructUniformBuffersAsync() { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + auto compileState = PhongGL::compile(PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling, 8, 8, 24); + CORRADE_COMPARE(compileState.flags(), PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling); + CORRADE_COMPARE(compileState.lightCount(), 8); + CORRADE_COMPARE(compileState.materialCount(), 8); + CORRADE_COMPARE(compileState.drawCount(), 24); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + PhongGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling); + CORRADE_COMPARE(shader.lightCount(), 8); + CORRADE_COMPARE(shader.materialCount(), 8); + CORRADE_COMPARE(shader.drawCount(), 24); + 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 PhongGLTest::constructMove() { diff --git a/src/Magnum/Shaders/Test/VectorGLTest.cpp b/src/Magnum/Shaders/Test/VectorGLTest.cpp index 670886fb7..715688e1e 100644 --- a/src/Magnum/Shaders/Test/VectorGLTest.cpp +++ b/src/Magnum/Shaders/Test/VectorGLTest.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef CORRADE_TARGET_APPLE @@ -83,8 +84,10 @@ struct VectorGLTest: GL::OpenGLTester { explicit VectorGLTest(); template void construct(); + template void constructAsync(); #ifndef MAGNUM_TARGET_GLES2 template void constructUniformBuffers(); + template void constructUniformBuffersAsync(); #endif template void constructMove(); @@ -247,11 +250,19 @@ VectorGLTest::VectorGLTest() { &VectorGLTest::construct<3>}, Containers::arraySize(ConstructData)); + addTests({ + &VectorGLTest::constructAsync<2>, + &VectorGLTest::constructAsync<3>}); + #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({ &VectorGLTest::constructUniformBuffers<2>, &VectorGLTest::constructUniformBuffers<3>}, Containers::arraySize(ConstructUniformBuffersData)); + + addTests({ + &VectorGLTest::constructUniformBuffersAsync<2>, + &VectorGLTest::constructUniformBuffersAsync<3>}); #endif addTests({ @@ -370,6 +381,30 @@ template void VectorGLTest::construct() { MAGNUM_VERIFY_NO_GL_ERROR(); } +template void VectorGLTest::constructAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + auto compileState = VectorGL::compile(VectorGL2D::Flag::TextureTransformation); + CORRADE_COMPARE(compileState.flags(), VectorGL2D::Flag::TextureTransformation); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + VectorGL shader{std::move(compileState)}; + CORRADE_VERIFY(shader.isLinkFinished()); + CORRADE_COMPARE(shader.flags(), VectorGL2D::Flag::TextureTransformation); + 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 template void VectorGLTest::constructUniformBuffers() { setTestCaseTemplateName(Utility::format("{}", dimensions)); @@ -408,6 +443,38 @@ template void VectorGLTest::constructUniformBuffers() { MAGNUM_VERIFY_NO_GL_ERROR(); } + +template void VectorGLTest::constructUniformBuffersAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + auto compileState = VectorGL::compile(VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 1, 1); + CORRADE_COMPARE(compileState.flags(), VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation); + CORRADE_COMPARE(compileState.materialCount(), 1); + CORRADE_COMPARE(compileState.drawCount(), 1); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + VectorGL shader{std::move(compileState)}; + CORRADE_VERIFY(shader.isLinkFinished()); + CORRADE_COMPARE(shader.flags(), VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation); + CORRADE_COMPARE(shader.materialCount(), 1); + CORRADE_COMPARE(shader.drawCount(), 1); + 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 template void VectorGLTest::constructMove() { diff --git a/src/Magnum/Shaders/Test/VertexColorGLTest.cpp b/src/Magnum/Shaders/Test/VertexColorGLTest.cpp index abbd56bf4..451c7348f 100644 --- a/src/Magnum/Shaders/Test/VertexColorGLTest.cpp +++ b/src/Magnum/Shaders/Test/VertexColorGLTest.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #ifdef CORRADE_TARGET_APPLE @@ -74,8 +75,10 @@ struct VertexColorGLTest: GL::OpenGLTester { explicit VertexColorGLTest(); template void construct(); + template void constructAsync(); #ifndef MAGNUM_TARGET_GLES2 template void constructUniformBuffers(); + template void constructUniformBuffersAsync(); #endif template void constructMove(); @@ -190,13 +193,19 @@ constexpr struct { VertexColorGLTest::VertexColorGLTest() { addTests({ &VertexColorGLTest::construct<2>, - &VertexColorGLTest::construct<3>}); + &VertexColorGLTest::construct<3>, + &VertexColorGLTest::constructAsync<2>, + &VertexColorGLTest::constructAsync<3>}); #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({ &VertexColorGLTest::constructUniformBuffers<2>, &VertexColorGLTest::constructUniformBuffers<3>}, Containers::arraySize(ConstructUniformBuffersData)); + + addTests({ + &VertexColorGLTest::constructUniformBuffersAsync<2>, + &VertexColorGLTest::constructUniformBuffersAsync<3>}); #endif addTests({ @@ -309,6 +318,28 @@ template void VertexColorGLTest::construct() { MAGNUM_VERIFY_NO_GL_ERROR(); } +template void VertexColorGLTest::constructAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + auto compileState = VertexColorGL::compile({}); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + VertexColorGL shader{std::move(compileState)}; + 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 template void VertexColorGLTest::constructUniformBuffers() { setTestCaseTemplateName(Utility::format("{}", dimensions)); @@ -347,6 +378,36 @@ template void VertexColorGLTest::constructUniformBuffers MAGNUM_VERIFY_NO_GL_ERROR(); } + +template void VertexColorGLTest::constructUniformBuffersAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + auto compileState = VertexColorGL::compile(VertexColorGL2D::Flag::UniformBuffers, 63); + CORRADE_COMPARE(compileState.flags(), VertexColorGL2D::Flag::UniformBuffers); + CORRADE_COMPARE(compileState.drawCount(), 63); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + VertexColorGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), VertexColorGL2D::Flag::UniformBuffers); + CORRADE_COMPARE(shader.drawCount(), 63); + 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 template void VertexColorGLTest::constructMove() { diff --git a/src/Magnum/Shaders/VectorGL.cpp b/src/Magnum/Shaders/VectorGL.cpp index addcb7433..dd6ff2c07 100644 --- a/src/Magnum/Shaders/VectorGL.cpp +++ b/src/Magnum/Shaders/VectorGL.cpp @@ -63,21 +63,16 @@ namespace { #endif } -template VectorGL::VectorGL(const Flags flags +template typename VectorGL::CompileState VectorGL::compile(const Flags flags #ifndef MAGNUM_TARGET_GLES2 , const UnsignedInt materialCount, const UnsignedInt drawCount #endif -): - _flags{flags} - #ifndef MAGNUM_TARGET_GLES2 - , _materialCount{materialCount}, _drawCount{drawCount} - #endif -{ +) { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, - "Shaders::VectorGL: material count can't be zero", ); + "Shaders::VectorGL: material count can't be zero", CompileState{NoCreate}); CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, - "Shaders::VectorGL: draw count can't be zero", ); + "Shaders::VectorGL: draw count can't be zero", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES @@ -141,9 +136,17 @@ template VectorGL::VectorGL(const Flags flag frag.addSource(rs.getString("generic.glsl")) .addSource(rs.getString("Vector.frag")); - CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); + vert.submitCompile(); + frag.submitCompile(); + + VectorGL out{NoInit}; + out._flags = flags; + #ifndef MAGNUM_TARGET_GLES2 + out._materialCount = materialCount; + out._drawCount = drawCount; + #endif - attachShaders({vert, frag}); + out.attachShaders({vert, frag}); /* ES3 has this done in the shader directly */ #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) @@ -151,25 +154,37 @@ template VectorGL::VectorGL(const Flags flag if(!context.isExtensionSupported(version)) #endif { - bindAttributeLocation(Position::Location, "position"); - bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); + out.bindAttributeLocation(Position::Location, "position"); + out.bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); } #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + out.submitLink(); + + return CompileState{std::move(out), std::move(vert), std::move(frag), version}; +} + +template VectorGL::VectorGL(CompileState&& cs): VectorGL{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; + #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) #endif { #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"); } else #endif { _transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) _textureMatrixUniform = uniformLocation("textureMatrix"); _backgroundColorUniform = uniformLocation("backgroundColor"); _colorUniform = uniformLocation("color"); @@ -182,10 +197,10 @@ template VectorGL::VectorGL(const Flags flag { setUniform(uniformLocation("vectorTexture"), TextureUnit); #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding); setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding); } @@ -195,24 +210,36 @@ template VectorGL::VectorGL(const Flags flag /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { /* Draw offset is zero by default */ } else #endif { setTransformationProjectionMatrix(MatrixTypeFor{Math::IdentityInit}); - if(flags & Flag::TextureTransformation) + if(_flags & Flag::TextureTransformation) setTextureMatrix(Matrix3{Math::IdentityInit}); /* Background color is zero by default */ setColor(Color4{1.0f}); } #endif + + static_cast(context); + static_cast(version); } +template VectorGL::VectorGL(Flags flags): VectorGL{compile(flags)} {} + #ifndef MAGNUM_TARGET_GLES2 -template VectorGL::VectorGL(const Flags flags): VectorGL{flags, 1, 1} {} +template typename VectorGL::CompileState VectorGL::compile(Flags flags) { + return compile(flags, 1, 1); +} + +template VectorGL::VectorGL(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount): + VectorGL{compile(flags, materialCount, drawCount)} {} #endif +template VectorGL::VectorGL(NoInitT) {} + template VectorGL& VectorGL::setTransformationProjectionMatrix(const MatrixTypeFor& matrix) { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), diff --git a/src/Magnum/Shaders/VectorGL.h b/src/Magnum/Shaders/VectorGL.h index 3b8519fa3..057dfc620 100644 --- a/src/Magnum/Shaders/VectorGL.h +++ b/src/Magnum/Shaders/VectorGL.h @@ -32,6 +32,7 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" +#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/visibility.h" @@ -273,6 +274,20 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL */ explicit VectorGL(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {} + class CompileState; + + explicit VectorGL(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 */ VectorGL(const VectorGL&) = delete; @@ -554,6 +569,9 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL #endif private: + /* Creates the GL shader program object but nothing else. Internal, used by compile(). */ + explicit VectorGL(NoInitT); + /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES using GL::AbstractShaderProgram::drawTransformFeedback; @@ -577,6 +595,19 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL #endif }; +template class VectorGL::CompileState: public VectorGL { +private: + friend class VectorGL; + + explicit CompileState(NoCreateT): VectorGL{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + + CompileState(VectorGL&& shader, GL::Shader&& vert, GL::Shader&& frag, GL::Version version): + VectorGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _version{version} {} + + GL::Shader _vert, _frag; + GL::Version _version; +}; + /** @brief Two-dimensional vector OpenGL shader @m_since_latest diff --git a/src/Magnum/Shaders/VertexColorGL.cpp b/src/Magnum/Shaders/VertexColorGL.cpp index 31d6e4821..01af44cd1 100644 --- a/src/Magnum/Shaders/VertexColorGL.cpp +++ b/src/Magnum/Shaders/VertexColorGL.cpp @@ -31,7 +31,6 @@ #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" -#include "Magnum/GL/Shader.h" #include "Magnum/Math/Color.h" #include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix4.h" @@ -57,19 +56,14 @@ namespace { #endif } -template VertexColorGL::VertexColorGL(const Flags flags +template typename VertexColorGL::CompileState VertexColorGL::compile(const Flags flags #ifndef MAGNUM_TARGET_GLES2 , const UnsignedInt drawCount #endif -): - _flags{flags} - #ifndef MAGNUM_TARGET_GLES2 - , _drawCount{drawCount} - #endif -{ +) { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, - "Shaders::VertexColorGL: draw count can't be zero", ); + "Shaders::VertexColorGL: draw count can't be zero", CompileState{NoCreate}); #endif #ifndef MAGNUM_TARGET_GLES @@ -121,9 +115,16 @@ template VertexColorGL::VertexColorGL(const frag.addSource(rs.getString("generic.glsl")) .addSource(rs.getString("VertexColor.frag")); - CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); + vert.submitCompile(); + frag.submitCompile(); + + VertexColorGL out{NoInit}; + out._flags = flags; + #ifndef MAGNUM_TARGET_GLES2 + out._drawCount = drawCount; + #endif - attachShaders({vert, frag}); + out.attachShaders({vert, frag}); /* ES3 has this done in the shader directly */ #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) @@ -131,19 +132,30 @@ template VertexColorGL::VertexColorGL(const if(!context.isExtensionSupported(version)) #endif { - bindAttributeLocation(Position::Location, "position"); - bindAttributeLocation(Color3::Location, "color"); /* Color4 is the same */ + out.bindAttributeLocation(Position::Location, "position"); + out.bindAttributeLocation(Color3::Location, "color"); /* Color4 is the same */ } #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + out.submitLink(); + + return CompileState{std::move(out), std::move(vert), std::move(frag), version}; +} + +template VertexColorGL::VertexColorGL(CompileState&& cs): VertexColorGL{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; #ifndef MAGNUM_TARGET_GLES if(!context.isExtensionSupported(version)) #endif { #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"); } else #endif @@ -153,7 +165,7 @@ template VertexColorGL::VertexColorGL(const } #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers + if(_flags >= Flag::UniformBuffers #ifndef MAGNUM_TARGET_GLES && !context.isExtensionSupported(version) #endif @@ -165,7 +177,7 @@ template VertexColorGL::VertexColorGL(const /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ #ifdef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2 - if(flags >= Flag::UniformBuffers) { + if(_flags >= Flag::UniformBuffers) { /* Draw offset is zero by default */ } else #endif @@ -173,12 +185,24 @@ template VertexColorGL::VertexColorGL(const setTransformationProjectionMatrix(MatrixTypeFor{Math::IdentityInit}); } #endif + + static_cast(context); + static_cast(version); } +template VertexColorGL::VertexColorGL(Flags flags): VertexColorGL{compile(flags)} {} + #ifndef MAGNUM_TARGET_GLES2 -template VertexColorGL::VertexColorGL(const Flags flags): VertexColorGL{flags, 1} {} +template typename VertexColorGL::CompileState VertexColorGL::compile(Flags flags) { + return compile(flags, 1); +} + +template VertexColorGL::VertexColorGL(Flags flags, UnsignedInt drawCount): + VertexColorGL{compile(flags, drawCount)} {} #endif +template VertexColorGL::VertexColorGL(NoInitT) {} + template VertexColorGL& VertexColorGL::setTransformationProjectionMatrix(const MatrixTypeFor& matrix) { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), diff --git a/src/Magnum/Shaders/VertexColorGL.h b/src/Magnum/Shaders/VertexColorGL.h index 3ecdd673f..988af7811 100644 --- a/src/Magnum/Shaders/VertexColorGL.h +++ b/src/Magnum/Shaders/VertexColorGL.h @@ -32,6 +32,7 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" +#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/visibility.h" @@ -264,6 +265,20 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL: publ */ explicit VertexColorGL(NoCreateT) noexcept: AbstractShaderProgram{NoCreate} {} + class CompileState; + + explicit VertexColorGL(CompileState&& cs); + + static CompileState compile(Flags flags + #ifndef MAGNUM_TARGET_GLES2 + , UnsignedInt drawCount + #endif + ); + + #ifndef MAGNUM_TARGET_GLES2 + static CompileState compile(Flags flags); + #endif + /** @brief Copying is not allowed */ VertexColorGL(const VertexColorGL&) = delete; @@ -406,6 +421,8 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL: publ #endif private: + explicit VertexColorGL(NoInitT); + /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES using GL::AbstractShaderProgram::drawTransformFeedback; @@ -426,6 +443,19 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL: publ #endif }; +template class VertexColorGL::CompileState: public VertexColorGL { +private: + friend class VertexColorGL; + + explicit CompileState(NoCreateT): VertexColorGL{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + + CompileState(VertexColorGL&& shader, GL::Shader&& vert, GL::Shader&& frag, GL::Version version): + VertexColorGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _version{version} {} + + GL::Shader _vert, _frag; + GL::Version _version; +}; + /** @brief 2D vertex color OpenGL shader @m_since_latest