diff --git a/src/Magnum/Shaders/CMakeLists.txt b/src/Magnum/Shaders/CMakeLists.txt index 4a5f9532c7..3c05a0d498 100644 --- a/src/Magnum/Shaders/CMakeLists.txt +++ b/src/Magnum/Shaders/CMakeLists.txt @@ -42,7 +42,9 @@ set(MagnumShaders_GracefulAssert_SRCS MeshVisualizerGL.cpp PhongGL.cpp VectorGL.cpp - VertexColorGL.cpp) + VertexColorGL.cpp + + glShaderWrapper.cpp) set(MagnumShaders_HEADERS DistanceFieldVector.h @@ -60,6 +62,7 @@ set(MagnumShaders_HEADERS VectorGL.h VertexColorGL.h + glShaderWrapper.h visibility.h) if(MAGNUM_BUILD_DEPRECATED) diff --git a/src/Magnum/Shaders/DistanceFieldVectorGL.cpp b/src/Magnum/Shaders/DistanceFieldVectorGL.cpp index 6483301225..834c14b7b8 100644 --- a/src/Magnum/Shaders/DistanceFieldVectorGL.cpp +++ b/src/Magnum/Shaders/DistanceFieldVectorGL.cpp @@ -33,6 +33,7 @@ #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" @@ -171,7 +172,7 @@ template DistanceFieldVectorGL::DistanceFiel if(!id()) return; #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag})); + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); const GL::Context& context = GL::Context::current(); const GL::Version version = state._version; diff --git a/src/Magnum/Shaders/DistanceFieldVectorGL.h b/src/Magnum/Shaders/DistanceFieldVectorGL.h index cf1944a613..36f087e878 100644 --- a/src/Magnum/Shaders/DistanceFieldVectorGL.h +++ b/src/Magnum/Shaders/DistanceFieldVectorGL.h @@ -33,8 +33,8 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" -#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" +#include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" namespace Magnum { namespace Shaders { @@ -690,7 +690,7 @@ template class DistanceFieldVectorGL::Compil explicit 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; + Implementation::GLShaderWrapper _vert, _frag; GL::Version _version; }; diff --git a/src/Magnum/Shaders/FlatGL.cpp b/src/Magnum/Shaders/FlatGL.cpp index 1d61fed6cd..03a99e54b1 100644 --- a/src/Magnum/Shaders/FlatGL.cpp +++ b/src/Magnum/Shaders/FlatGL.cpp @@ -33,6 +33,7 @@ #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" @@ -246,7 +247,7 @@ template FlatGL::FlatGL(CompileState&& state if(!id()) return; #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag})); + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); const GL::Context& context = GL::Context::current(); const GL::Version version = state._version; diff --git a/src/Magnum/Shaders/FlatGL.h b/src/Magnum/Shaders/FlatGL.h index 98b33cafc0..adedb7c82d 100644 --- a/src/Magnum/Shaders/FlatGL.h +++ b/src/Magnum/Shaders/FlatGL.h @@ -33,8 +33,8 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" -#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" +#include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" namespace Magnum { namespace Shaders { @@ -1101,7 +1101,7 @@ template class FlatGL::CompileState: public explicit 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; + Implementation::GLShaderWrapper _vert, _frag; GL::Version _version; }; diff --git a/src/Magnum/Shaders/MeshVisualizerGL.cpp b/src/Magnum/Shaders/MeshVisualizerGL.cpp index 6c079655b9..e3c57d0441 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.cpp +++ b/src/Magnum/Shaders/MeshVisualizerGL.cpp @@ -517,7 +517,7 @@ MeshVisualizerGL2D::CompileState MeshVisualizerGL2D::compile(const Flags flags out.submitLink(); - return CompileState{std::move(out), std::move(vert), std::move(frag), std::move(geom), flags, version}; + return CompileState{std::move(out), std::move(vert), std::move(frag), geom ? &*geom : nullptr, flags, version}; } MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): MeshVisualizerGL2D{compile(flags)} {} @@ -537,10 +537,10 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(CompileState&& state): MeshVisualizerGL2D if(!id()) return; #endif - if(state._geom) - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag, *state._geom})); + if(state._geom.id) + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag), GL::Shader(state._geom)})); else - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag})); + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); const GL::Context& context = GL::Context::current(); const GL::Version version = state._version; @@ -906,7 +906,7 @@ MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(Flags flags out.submitLink(); - return CompileState{std::move(out), std::move(vert), std::move(frag), std::move(geom), flags, version}; + return CompileState{std::move(out), std::move(vert), std::move(frag), geom ? &*geom : nullptr, flags, version}; } MeshVisualizerGL3D::MeshVisualizerGL3D(CompileState&& state): MeshVisualizerGL3D{static_cast(std::move(state))} { @@ -916,10 +916,10 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(CompileState&& state): MeshVisualizerGL3D if(!id()) return; #endif - if(state._geom) - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag, *state._geom})); + if(state._geom.id) + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag), GL::Shader(state._geom)})); else - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag})); + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); const GL::Context& context = GL::Context::current(); const GL::Version version = state._version; diff --git a/src/Magnum/Shaders/MeshVisualizerGL.h b/src/Magnum/Shaders/MeshVisualizerGL.h index ab7667c9fc..2d2cd5e84c 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.h +++ b/src/Magnum/Shaders/MeshVisualizerGL.h @@ -33,11 +33,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/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" namespace Magnum { namespace Shaders { @@ -928,12 +927,13 @@ class MeshVisualizerGL2D::CompileState: public MeshVisualizerGL2D { /* Everything deliberately private except for the inheritance */ friend class MeshVisualizerGL2D; - explicit CompileState(NoCreateT): MeshVisualizerGL2D{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + explicit CompileState(NoCreateT): MeshVisualizerGL2D{NoCreate}, _vert{NoCreate}, _frag{NoCreate}, _geom{NoCreate} {} - explicit 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} {} + explicit CompileState(MeshVisualizerGL2D&& shader, GL::Shader&& vert, GL::Shader&& frag, GL::Shader* geom, Flags flags, GL::Version version): MeshVisualizerGL2D{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _geom{NoCreate}, _flags{flags}, _version{version} { + if(geom) _geom = Implementation::GLShaderWrapper{std::move(*geom)}; + } - GL::Shader _vert, _frag; - Containers::Optional _geom; + Implementation::GLShaderWrapper _vert, _frag, _geom; Flags _flags; GL::Version _version; }; @@ -2465,12 +2465,13 @@ class MeshVisualizerGL3D::CompileState: public MeshVisualizerGL3D { /* Everything deliberately private except for the inheritance */ friend class MeshVisualizerGL3D; - explicit CompileState(NoCreateT): MeshVisualizerGL3D{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} + explicit CompileState(NoCreateT): MeshVisualizerGL3D{NoCreate}, _vert{NoCreate}, _frag{NoCreate}, _geom{NoCreate} {} - explicit 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} {} + explicit CompileState(MeshVisualizerGL3D&& shader, GL::Shader&& vert, GL::Shader&& frag, GL::Shader* geom, Flags flags, GL::Version version): MeshVisualizerGL3D{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _geom{NoCreate}, _flags{flags}, _version{version} { + if(geom) _geom = Implementation::GLShaderWrapper{std::move(*geom)}; + } - GL::Shader _vert, _frag; - Containers::Optional _geom; + Implementation::GLShaderWrapper _vert, _frag, _geom; Flags _flags; GL::Version _version; }; diff --git a/src/Magnum/Shaders/PhongGL.cpp b/src/Magnum/Shaders/PhongGL.cpp index 6e511a0bab..d0fd391d9e 100644 --- a/src/Magnum/Shaders/PhongGL.cpp +++ b/src/Magnum/Shaders/PhongGL.cpp @@ -39,6 +39,7 @@ #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" @@ -356,7 +357,7 @@ PhongGL::PhongGL(CompileState&& state): PhongGL{static_cast(std::move if(!id()) return; #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag})); + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); const GL::Context& context = GL::Context::current(); const GL::Version version = state._version; diff --git a/src/Magnum/Shaders/PhongGL.h b/src/Magnum/Shaders/PhongGL.h index bd7a8cf521..12396bc305 100644 --- a/src/Magnum/Shaders/PhongGL.h +++ b/src/Magnum/Shaders/PhongGL.h @@ -32,8 +32,8 @@ */ #include "Magnum/GL/AbstractShaderProgram.h" -#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" +#include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" namespace Magnum { namespace Shaders { @@ -1847,7 +1847,7 @@ class PhongGL::CompileState: public PhongGL { explicit 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; + Implementation::GLShaderWrapper _vert, _frag; GL::Version _version; }; diff --git a/src/Magnum/Shaders/Test/CMakeLists.txt b/src/Magnum/Shaders/Test/CMakeLists.txt index 968adb16c8..91ab6651a7 100644 --- a/src/Magnum/Shaders/Test/CMakeLists.txt +++ b/src/Magnum/Shaders/Test/CMakeLists.txt @@ -30,6 +30,7 @@ set(CMAKE_FOLDER "Magnum/Shaders/Test") corrade_add_test(ShadersDistanceFieldVectorTest DistanceFieldVectorTest.cpp LIBRARIES MagnumShaders) corrade_add_test(ShadersFlatTest FlatTest.cpp LIBRARIES MagnumShaders) corrade_add_test(ShadersGenericTest GenericTest.cpp LIBRARIES MagnumShaders) +corrade_add_test(ShadersGLShaderWrapperTest GLShaderWrapperTest.cpp LIBRARIES MagnumShaders) corrade_add_test(ShadersMeshVisualizerTest MeshVisualizerTest.cpp LIBRARIES MagnumShaders) corrade_add_test(ShadersPhongTest PhongTest.cpp LIBRARIES MagnumShaders) corrade_add_test(ShadersVectorTest VectorTest.cpp LIBRARIES MagnumShaders) @@ -164,6 +165,8 @@ if(MAGNUM_BUILD_GL_TESTS) endif() endif() + corrade_add_test(ShadersGLShaderWrapperGLTest GLShaderWrapperGLTest.cpp LIBRARIES MagnumShaders MagnumOpenGLTester) + set(ShadersMeshVisualizerGLTest_SRCS MeshVisualizerGLTest.cpp) if(CORRADE_TARGET_IOS) list(APPEND ShadersMeshVisualizerGLTest_SRCS FlatTestFiles MeshVisualizerTestFiles) diff --git a/src/Magnum/Shaders/Test/GLShaderWrapperGLTest.cpp b/src/Magnum/Shaders/Test/GLShaderWrapperGLTest.cpp new file mode 100644 index 0000000000..f4a83ed58d --- /dev/null +++ b/src/Magnum/Shaders/Test/GLShaderWrapperGLTest.cpp @@ -0,0 +1,171 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/GL/OpenGLTester.h" +#include "Magnum/GL/Shader.h" +#include "Magnum/GL/Version.h" +#include "Magnum/Shaders/glShaderWrapper.h" + +namespace Magnum { namespace Shaders { namespace Test { namespace { + +struct GLShaderWrapperGLTest: GL::OpenGLTester { + explicit GLShaderWrapperGLTest(); + + void construct(); + void constructMove(); + + void convert(); + void convertRvalue(); +}; + +GLShaderWrapperGLTest::GLShaderWrapperGLTest() { + addTests({&GLShaderWrapperGLTest::construct, + &GLShaderWrapperGLTest::constructMove, + + &GLShaderWrapperGLTest::convert, + &GLShaderWrapperGLTest::convertRvalue}); +} + +void GLShaderWrapperGLTest::construct() { + { + GL::Shader glShader{ + #ifndef MAGNUM_TARGET_GLES + GL::Version::GL300, + #else + GL::Version::GLES300, + #endif + GL::Shader::Type::Fragment}; + + GLuint id = glShader.id(); + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_VERIFY(id > 0); + + Implementation::GLShaderWrapper shader{std::move(glShader)}; + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE(shader.id, id); + CORRADE_COMPARE(shader.type, GL_FRAGMENT_SHADER); + CORRADE_VERIFY(!glShader.id()); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} + +void GLShaderWrapperGLTest::constructMove() { + GL::Shader glShaderA{ + #ifndef MAGNUM_TARGET_GLES + GL::Version::GL300, + #else + GL::Version::GLES300, + #endif + GL::Shader::Type::Fragment}; + Implementation::GLShaderWrapper a{std::move(glShaderA)}; + + GLuint id = a.id; + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_VERIFY(id > 0); + + Implementation::GLShaderWrapper b{std::move(a)}; + CORRADE_VERIFY(!a.id); + CORRADE_COMPARE(b.id, id); + CORRADE_COMPARE(b.type, GL_FRAGMENT_SHADER); + + GL::Shader glShaderB{ + #ifndef MAGNUM_TARGET_GLES + GL::Version::GL210, + #else + GL::Version::GLES200, + #endif + GL::Shader::Type::Vertex}; + Implementation::GLShaderWrapper c{std::move(glShaderB)}; + + GLuint cId = c.id; + c = std::move(b); + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_VERIFY(cId > 0); + CORRADE_COMPARE(b.id, cId); + CORRADE_COMPARE(c.id, id); + CORRADE_COMPARE(c.type, GL_FRAGMENT_SHADER); + + CORRADE_VERIFY(std::is_nothrow_move_constructible::value); + CORRADE_VERIFY(std::is_nothrow_move_assignable::value); +} + +void GLShaderWrapperGLTest::convert() { + { + GL::Shader glShader{ + #ifndef MAGNUM_TARGET_GLES + GL::Version::GL300, + #else + GL::Version::GLES300, + #endif + GL::Shader::Type::Fragment}; + Implementation::GLShaderWrapper shader{std::move(glShader)}; + + GLuint id = shader.id; + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_VERIFY(id > 0); + + GL::Shader glShader2 = shader; + MAGNUM_VERIFY_NO_GL_ERROR(); + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE(glShader2.id(), id); + CORRADE_COMPARE(glShader2.type(), GL::Shader::Type::Fragment); + CORRADE_VERIFY(shader.id); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} + +void GLShaderWrapperGLTest::convertRvalue() { + { + GL::Shader glShader{ + #ifndef MAGNUM_TARGET_GLES + GL::Version::GL300, + #else + GL::Version::GLES300, + #endif + GL::Shader::Type::Fragment}; + Implementation::GLShaderWrapper shader{std::move(glShader)}; + + GLuint id = shader.id; + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_VERIFY(id > 0); + + GL::Shader glShader2 = std::move(shader); + MAGNUM_VERIFY_NO_GL_ERROR(); + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE(glShader2.id(), id); + CORRADE_COMPARE(glShader2.type(), GL::Shader::Type::Fragment); + CORRADE_VERIFY(!shader.id); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Shaders::Test::GLShaderWrapperGLTest) diff --git a/src/Magnum/Shaders/Test/GLShaderWrapperTest.cpp b/src/Magnum/Shaders/Test/GLShaderWrapperTest.cpp new file mode 100644 index 0000000000..aaf4629218 --- /dev/null +++ b/src/Magnum/Shaders/Test/GLShaderWrapperTest.cpp @@ -0,0 +1,58 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include "Magnum/Magnum.h" +#include "Magnum/Shaders/glShaderWrapper.h" + +namespace Magnum { namespace Shaders { namespace Test { namespace { + +struct GLShaderWrapperTest: TestSuite::Tester { + explicit GLShaderWrapperTest(); + + void constructNoCreate(); + void constructCopy(); +}; + +GLShaderWrapperTest::GLShaderWrapperTest() { + addTests({&GLShaderWrapperTest::constructNoCreate, + &GLShaderWrapperTest::constructCopy}); +} + +void GLShaderWrapperTest::constructNoCreate() { + Implementation::GLShaderWrapper shader{NoCreate}; + CORRADE_COMPARE(shader.type, 0); + CORRADE_COMPARE(shader.id, 0); +} + +void GLShaderWrapperTest::constructCopy() { + CORRADE_VERIFY(!std::is_copy_constructible{}); + CORRADE_VERIFY(!std::is_copy_assignable{}); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Shaders::Test::GLShaderWrapperTest) diff --git a/src/Magnum/Shaders/VectorGL.cpp b/src/Magnum/Shaders/VectorGL.cpp index 89b5353e3d..272d0c5e8b 100644 --- a/src/Magnum/Shaders/VectorGL.cpp +++ b/src/Magnum/Shaders/VectorGL.cpp @@ -173,7 +173,7 @@ template VectorGL::VectorGL(CompileState&& s if(!id()) return; #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag})); + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); const GL::Context& context = GL::Context::current(); const GL::Version version = state._version; diff --git a/src/Magnum/Shaders/VectorGL.h b/src/Magnum/Shaders/VectorGL.h index ecc4ccde78..5196ce5da9 100644 --- a/src/Magnum/Shaders/VectorGL.h +++ b/src/Magnum/Shaders/VectorGL.h @@ -33,8 +33,8 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" -#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" +#include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" namespace Magnum { namespace Shaders { @@ -640,7 +640,7 @@ template class VectorGL::CompileState: publi explicit 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; + Implementation::GLShaderWrapper _vert, _frag; GL::Version _version; }; diff --git a/src/Magnum/Shaders/VertexColorGL.cpp b/src/Magnum/Shaders/VertexColorGL.cpp index 048e956530..848ba907f0 100644 --- a/src/Magnum/Shaders/VertexColorGL.cpp +++ b/src/Magnum/Shaders/VertexColorGL.cpp @@ -151,7 +151,7 @@ template VertexColorGL::VertexColorGL(Compil if(!id()) return; #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({state._vert, state._frag})); + CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); const GL::Context& context = GL::Context::current(); const GL::Version version = state._version; diff --git a/src/Magnum/Shaders/VertexColorGL.h b/src/Magnum/Shaders/VertexColorGL.h index 7048b27435..d09e95bddf 100644 --- a/src/Magnum/Shaders/VertexColorGL.h +++ b/src/Magnum/Shaders/VertexColorGL.h @@ -33,8 +33,8 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" -#include "Magnum/GL/Shader.h" #include "Magnum/Shaders/GenericGL.h" +#include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" namespace Magnum { namespace Shaders { @@ -489,7 +489,7 @@ template class VertexColorGL::CompileState: explicit 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; + Implementation::GLShaderWrapper _vert, _frag; GL::Version _version; }; diff --git a/src/Magnum/Shaders/glShaderWrapper.cpp b/src/Magnum/Shaders/glShaderWrapper.cpp new file mode 100644 index 0000000000..63f43ca63b --- /dev/null +++ b/src/Magnum/Shaders/glShaderWrapper.cpp @@ -0,0 +1,61 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "glShaderWrapper.h" + +#include "Magnum/GL/Shader.h" + +namespace Magnum { namespace Shaders { namespace Implementation { + +GLShaderWrapper::GLShaderWrapper(GL::Shader&& shader) noexcept: type{GLenum(shader.type())}, id{shader.release()} {} + +GLShaderWrapper::GLShaderWrapper(GLShaderWrapper&& other) noexcept: type{other.type}, id{other.id} { + other.id = 0; +} + +GLShaderWrapper& GLShaderWrapper::operator=(GLShaderWrapper&& other) noexcept { + using std::swap; + swap(other.type, type); + swap(other.id, id); + return *this; +} + +GLShaderWrapper::~GLShaderWrapper() { + /* Convert itself to a temporary GL::Shader, triggering deletion in its + destructor */ + if(id) GL::Shader{std::move(*this)}; +} + +GLShaderWrapper::operator GL::Shader() & noexcept { + return GL::Shader::wrap(GL::Shader::Type(type), id); +} + +GLShaderWrapper::operator GL::Shader() && noexcept { + GL::Shader out = GL::Shader::wrap(GL::Shader::Type(type), id, GL::ObjectFlag::DeleteOnDestruction); + id = 0; + return out; +} + +}}} diff --git a/src/Magnum/Shaders/glShaderWrapper.h b/src/Magnum/Shaders/glShaderWrapper.h new file mode 100644 index 0000000000..bc4d77b2ff --- /dev/null +++ b/src/Magnum/Shaders/glShaderWrapper.h @@ -0,0 +1,62 @@ +#ifndef Magnum_Shaders_glShaderWrapper_h +#define Magnum_Shaders_glShaderWrapper_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/Tags.h" +#include "Magnum/GL/GL.h" +#include "Magnum/Shaders/visibility.h" + +namespace Magnum { namespace Shaders { namespace Implementation { + +/* A lightweight alternative to GL::Shader that holds just the type and ID, + used by CompileState instances of all shaders. There it's used just to + retrieve error messages in case of a compilation failures, so it doesn't + make sense to pull in stuff needed to store shader sources such as strings + and vectors/arrays. + + Might get revisited once GL::Shader gets the deSTLification treatment, but + even then this class seems significantly lighter weight. */ +struct MAGNUM_SHADERS_EXPORT GLShaderWrapper { + /*implicit*/ GLShaderWrapper(NoCreateT) noexcept: type{}, id{} {} + /*implicit*/ GLShaderWrapper(GL::Shader&& shader) noexcept; + + GLShaderWrapper(const GLShaderWrapper&) = delete; + GLShaderWrapper(GLShaderWrapper&& other) noexcept; + + GLShaderWrapper& operator=(const GLShaderWrapper&) = delete; + GLShaderWrapper& operator=(GLShaderWrapper&& other) noexcept; + + ~GLShaderWrapper(); + /*implicit*/ operator GL::Shader() & noexcept; + /*implicit*/ operator GL::Shader() && noexcept; + + GLenum type; + GLuint id; +}; + +}}} + +#endif