From 4d252ac6438bf58b20386d111fcb84124cf0de86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Jan 2014 00:20:51 +0100 Subject: [PATCH] Fully test shader functionality. --- src/Test/AbstractShaderProgramGLTest.cpp | 291 +++++++++++++++++- .../MyShader.frag | 7 + .../MyShader.vert | 7 + .../MyShaderFragmentOutputs.frag | 7 + .../resources.conf | 10 + src/Test/CMakeLists.txt | 13 +- src/Test/ShaderGLTest.cpp | 83 ++++- src/Test/ShaderGLTestConfigure.h.cmake | 25 ++ src/Test/ShaderGLTestFiles/shader.glsl | 1 + 9 files changed, 425 insertions(+), 19 deletions(-) create mode 100644 src/Test/AbstractShaderProgramGLTestFiles/MyShader.frag create mode 100644 src/Test/AbstractShaderProgramGLTestFiles/MyShader.vert create mode 100644 src/Test/AbstractShaderProgramGLTestFiles/MyShaderFragmentOutputs.frag create mode 100644 src/Test/AbstractShaderProgramGLTestFiles/resources.conf create mode 100644 src/Test/ShaderGLTestConfigure.h.cmake create mode 100644 src/Test/ShaderGLTestFiles/shader.glsl diff --git a/src/Test/AbstractShaderProgramGLTest.cpp b/src/Test/AbstractShaderProgramGLTest.cpp index 2f0ac36fe..3c9ef6fa7 100644 --- a/src/Test/AbstractShaderProgramGLTest.cpp +++ b/src/Test/AbstractShaderProgramGLTest.cpp @@ -22,9 +22,14 @@ DEALINGS IN THE SOFTWARE. */ +#include + +#include "Math/Matrix.h" +#include "Math/Vector4.h" #include "AbstractShaderProgram.h" #include "Context.h" #include "Extensions.h" +#include "Shader.h" #include "Test/AbstractOpenGLTester.h" namespace Magnum { namespace Test { @@ -38,6 +43,17 @@ class AbstractShaderProgramGLTest: public AbstractOpenGLTester { void constructMove(); void label(); + + void create(); + void createMultipleOutputs(); + #ifndef MAGNUM_TARGET_GLES + void createMultipleOutputsIndexed(); + #endif + + void uniform(); + void uniformVector(); + void uniformMatrix(); + void uniformArray(); }; AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() { @@ -45,21 +61,30 @@ AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() { &AbstractShaderProgramGLTest::constructCopy, &AbstractShaderProgramGLTest::constructMove, - &AbstractShaderProgramGLTest::label}); -} + &AbstractShaderProgramGLTest::label, -namespace { + &AbstractShaderProgramGLTest::create, + &AbstractShaderProgramGLTest::createMultipleOutputs, + #ifndef MAGNUM_TARGET_GLES + &AbstractShaderProgramGLTest::createMultipleOutputsIndexed, + #endif -class MyShader: public AbstractShaderProgram { - public: - explicit MyShader() {} -}; + &AbstractShaderProgramGLTest::uniform, + &AbstractShaderProgramGLTest::uniformVector, + &AbstractShaderProgramGLTest::uniformMatrix, + &AbstractShaderProgramGLTest::uniformArray}); +} +namespace { + class DummyShader: public AbstractShaderProgram { + public: + explicit DummyShader() {} + }; } void AbstractShaderProgramGLTest::construct() { { - const MyShader shader; + const DummyShader shader; MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(shader.id() > 0); @@ -69,26 +94,26 @@ void AbstractShaderProgramGLTest::construct() { } void AbstractShaderProgramGLTest::constructCopy() { - CORRADE_VERIFY(!(std::is_constructible{})); + CORRADE_VERIFY(!(std::is_constructible{})); /* GCC 4.6 doesn't have std::is_assignable */ #ifndef CORRADE_GCC46_COMPATIBILITY - CORRADE_VERIFY(!(std::is_assignable{})); + CORRADE_VERIFY(!(std::is_assignable{})); #endif } void AbstractShaderProgramGLTest::constructMove() { - MyShader a; + DummyShader a; const Int id = a.id(); MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(id > 0); - MyShader b(std::move(a)); + DummyShader b(std::move(a)); CORRADE_COMPARE(a.id(), 0); CORRADE_COMPARE(b.id(), id); - MyShader c; + DummyShader c; const Int cId = c.id(); c = std::move(b); @@ -104,11 +129,245 @@ void AbstractShaderProgramGLTest::label() { !Context::current()->isExtensionSupported()) CORRADE_SKIP("Required extension is not available"); - MyShader shader; + DummyShader shader; CORRADE_COMPARE(shader.label(), ""); - shader.setLabel("MyShader"); - CORRADE_COMPARE(shader.label(), "MyShader"); + shader.setLabel("DummyShader"); + CORRADE_COMPARE(shader.label(), "DummyShader"); + + MAGNUM_VERIFY_NO_ERROR(); +} + +namespace { + struct MyPublicShader: AbstractShaderProgram { + using AbstractShaderProgram::attachShader; + using AbstractShaderProgram::bindAttributeLocation; + #ifndef MAGNUM_TARGET_GLES + using AbstractShaderProgram::bindFragmentDataLocationIndexed; + using AbstractShaderProgram::bindFragmentDataLocation; + #endif + using AbstractShaderProgram::link; + using AbstractShaderProgram::uniformLocation; + }; +} + +void AbstractShaderProgramGLTest::create() { + Utility::Resource rs("MyShader"); + + #ifndef MAGNUM_TARGET_GLES + Shader vert(Version::GL210, Shader::Type::Vertex); + #else + Shader vert(Version::GLES200, Shader::Type::Vertex); + #endif + vert.addSource(rs.get("MyShader.vert")); + const bool vertCompiled = vert.compile(); + + #ifndef MAGNUM_TARGET_GLES + Shader frag(Version::GL210, Shader::Type::Fragment); + #else + Shader frag(Version::GLES200, Shader::Type::Fragment); + #endif + frag.addSource(rs.get("MyShader.frag")); + const bool fragCompiled = frag.compile(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(vertCompiled); + CORRADE_VERIFY(fragCompiled); + + MyPublicShader program; + program.attachShader(vert); + program.attachShader(frag); + + MAGNUM_VERIFY_NO_ERROR(); + + program.bindAttributeLocation(0, "position"); + const bool linked = program.link(); + const bool valid = program.validate().first; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(linked); + CORRADE_VERIFY(valid); + + const Int matrixUniform = program.uniformLocation("matrix"); + const Int multiplierUniform = program.uniformLocation("multiplier"); + const Int colorUniform = program.uniformLocation("color"); + const Int additionsUniform = program.uniformLocation("additions"); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(matrixUniform >= 0); + CORRADE_VERIFY(multiplierUniform >= 0); + CORRADE_VERIFY(colorUniform >= 0); + CORRADE_VERIFY(additionsUniform >= 0); + + program.use(); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void AbstractShaderProgramGLTest::createMultipleOutputs() { + #ifndef MAGNUM_TARGET_GLES + Utility::Resource rs("MyShader"); + + Shader vert(Version::GL210, Shader::Type::Vertex); + vert.addSource(rs.get("MyShader.vert")); + const bool vertCompiled = vert.compile(); + + Shader frag(Version::GL300, Shader::Type::Fragment); + frag.addSource(rs.get("MyShaderFragmentOutputs.frag")); + const bool fragCompiled = frag.compile(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(vertCompiled); + CORRADE_VERIFY(fragCompiled); + + MyPublicShader program; + program.attachShader(vert); + program.attachShader(frag); + + MAGNUM_VERIFY_NO_ERROR(); + + program.bindAttributeLocation(0, "position"); + program.bindFragmentDataLocation(0, "first"); + program.bindFragmentDataLocation(1, "second"); + const bool linked = program.link(); + const bool valid = program.validate().first; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(linked); + CORRADE_VERIFY(valid); + + program.use(); + + MAGNUM_VERIFY_NO_ERROR(); + #elif !defined(MAGNUM_TARGET_GLES2) + CORRADE_SKIP("Only explicit location specification supported in ES 3.0."); + #else + CORRADE_SKIP("Only gl_FragData[n] supported in ES 2.0."); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractShaderProgramGLTest::createMultipleOutputsIndexed() { + Utility::Resource rs("MyShader"); + + Shader vert(Version::GL210, Shader::Type::Vertex); + vert.addSource(rs.get("MyShader.vert")); + const bool vertCompiled = vert.compile(); + + Shader frag(Version::GL300, Shader::Type::Fragment); + frag.addSource(rs.get("MyShaderFragmentOutputs.frag")); + const bool fragCompiled = frag.compile(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(vertCompiled); + CORRADE_VERIFY(fragCompiled); + + MyPublicShader program; + program.attachShader(vert); + program.attachShader(frag); + + MAGNUM_VERIFY_NO_ERROR(); + + program.bindAttributeLocation(0, "position"); + program.bindFragmentDataLocationIndexed(0, 0, "first"); + program.bindFragmentDataLocationIndexed(0, 1, "second"); + const bool linked = program.link(); + const bool valid = program.validate().first; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(linked); + CORRADE_VERIFY(valid); + + program.use(); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +namespace { + struct MyShader: AbstractShaderProgram { + explicit MyShader(); + + using AbstractShaderProgram::setUniform; + + Int matrixUniform, + multiplierUniform, + colorUniform, + additionsUniform; + }; +} + +MyShader::MyShader() { + Utility::Resource rs("MyShader"); + + #ifndef MAGNUM_TARGET_GLES + Shader vert(Version::GL210, Shader::Type::Vertex); + #else + Shader vert(Version::GLES200, Shader::Type::Vertex); + #endif + vert.addSource(rs.get("MyShader.vert")) + .compile(); + attachShader(vert); + + #ifndef MAGNUM_TARGET_GLES + Shader frag(Version::GL210, Shader::Type::Fragment); + #else + Shader frag(Version::GLES200, Shader::Type::Fragment); + #endif + frag.addSource(rs.get("MyShader.frag")) + .compile(); + attachShader(frag); + + bindAttributeLocation(0, "position"); + link(); + + matrixUniform = uniformLocation("matrix"); + multiplierUniform = uniformLocation("multiplier"); + colorUniform = uniformLocation("color"); + additionsUniform = uniformLocation("additions"); +} + +void AbstractShaderProgramGLTest::uniform() { + MyShader shader; + + MAGNUM_VERIFY_NO_ERROR(); + + shader.setUniform(shader.multiplierUniform, 0.35f); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void AbstractShaderProgramGLTest::uniformVector() { + MyShader shader; + + MAGNUM_VERIFY_NO_ERROR(); + + shader.setUniform(shader.colorUniform, Vector4(0.3f, 0.7f, 1.0f, 0.25f)); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void AbstractShaderProgramGLTest::uniformMatrix() { + MyShader shader; + + MAGNUM_VERIFY_NO_ERROR(); + + shader.setUniform(shader.matrixUniform, Matrix4x4::fromDiagonal({0.3f, 0.7f, 1.0f, 0.25f})); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void AbstractShaderProgramGLTest::uniformArray() { + MyShader shader; + + MAGNUM_VERIFY_NO_ERROR(); + + constexpr Vector4 values[] = { + {0.5f, 1.0f, 0.4f, 0.0f}, + {0.0f, 0.1f, 0.7f, 0.3f}, + {0.9f, 0.8f, 0.3f, 0.1f} + }; + shader.setUniform(shader.additionsUniform, 3, values); MAGNUM_VERIFY_NO_ERROR(); } diff --git a/src/Test/AbstractShaderProgramGLTestFiles/MyShader.frag b/src/Test/AbstractShaderProgramGLTestFiles/MyShader.frag new file mode 100644 index 000000000..39b15b1a2 --- /dev/null +++ b/src/Test/AbstractShaderProgramGLTestFiles/MyShader.frag @@ -0,0 +1,7 @@ +uniform lowp float multiplier; +uniform lowp vec4 color; +uniform lowp vec4 additions[3]; + +void main() { + gl_FragColor = color*multiplier + additions[0] + additions[1] + additions[2]; +} diff --git a/src/Test/AbstractShaderProgramGLTestFiles/MyShader.vert b/src/Test/AbstractShaderProgramGLTestFiles/MyShader.vert new file mode 100644 index 000000000..3d2907e68 --- /dev/null +++ b/src/Test/AbstractShaderProgramGLTestFiles/MyShader.vert @@ -0,0 +1,7 @@ +attribute mediump vec4 position; + +uniform mediump mat4 matrix; + +void main() { + gl_Position = matrix*position; +} diff --git a/src/Test/AbstractShaderProgramGLTestFiles/MyShaderFragmentOutputs.frag b/src/Test/AbstractShaderProgramGLTestFiles/MyShaderFragmentOutputs.frag new file mode 100644 index 000000000..ae85b17ba --- /dev/null +++ b/src/Test/AbstractShaderProgramGLTestFiles/MyShaderFragmentOutputs.frag @@ -0,0 +1,7 @@ +out vec4 first; +out vec3 second; + +void main() { + first = vec4(1.0, 0.3, 0.5, 0.1); + second = vec3(0.5, 0.7, 0.4); +} diff --git a/src/Test/AbstractShaderProgramGLTestFiles/resources.conf b/src/Test/AbstractShaderProgramGLTestFiles/resources.conf new file mode 100644 index 000000000..51723f0ab --- /dev/null +++ b/src/Test/AbstractShaderProgramGLTestFiles/resources.conf @@ -0,0 +1,10 @@ +group=MyShader + +[file] +filename=MyShader.frag + +[file] +filename=MyShader.vert + +[file] +filename=MyShaderFragmentOutputs.frag diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 68a132084..9ad7c65f9 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -41,7 +41,6 @@ corrade_add_test(VersionTest VersionTest.cpp LIBRARIES Magnum) if(BUILD_GL_TESTS) corrade_add_test(AbstractObjectGLTest AbstractObjectGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(AbstractQueryGLTest AbstractQueryGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) - corrade_add_test(AbstractShaderProgramGLTest AbstractShaderProgramGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(AbstractTextureGLTest AbstractTextureGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(BufferGLTest BufferGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(ContextGLTest ContextGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) @@ -50,9 +49,19 @@ if(BUILD_GL_TESTS) corrade_add_test(FramebufferGLTest FramebufferGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(MeshGLTest MeshGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(RenderbufferGLTest RenderbufferGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) - corrade_add_test(ShaderGLTest ShaderGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(TextureGLTest TextureGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) + corrade_add_resource(AbstractShaderProgramGLTest_RES AbstractShaderProgramGLTestFiles/resources.conf) + corrade_add_test(AbstractShaderProgramGLTest + AbstractShaderProgramGLTest.cpp + ${AbstractShaderProgramGLTest_RES} + LIBRARIES ${GL_TEST_LIBRARIES}) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ShaderGLTestConfigure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ShaderGLTestConfigure.h) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + corrade_add_test(ShaderGLTest ShaderGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) + if(NOT MAGNUM_TARGET_GLES2) corrade_add_test(BufferImageGLTest BufferImageGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) endif() diff --git a/src/Test/ShaderGLTest.cpp b/src/Test/ShaderGLTest.cpp index 86d7fbeb0..37bba4647 100644 --- a/src/Test/ShaderGLTest.cpp +++ b/src/Test/ShaderGLTest.cpp @@ -22,11 +22,15 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Context.h" #include "Extensions.h" #include "Shader.h" #include "Test/AbstractOpenGLTester.h" +#include "ShaderGLTestConfigure.h" + namespace Magnum { namespace Test { class ShaderGLTest: public AbstractOpenGLTester { @@ -38,6 +42,10 @@ class ShaderGLTest: public AbstractOpenGLTester { void constructMove(); void label(); + + void addSource(); + void addFile(); + void compile(); }; ShaderGLTest::ShaderGLTest() { @@ -45,7 +53,11 @@ ShaderGLTest::ShaderGLTest() { &ShaderGLTest::constructCopy, &ShaderGLTest::constructMove, - &ShaderGLTest::label}); + &ShaderGLTest::label, + + &ShaderGLTest::addSource, + &ShaderGLTest::addFile, + &ShaderGLTest::compile}); } void ShaderGLTest::construct() { @@ -138,6 +150,75 @@ void ShaderGLTest::label() { MAGNUM_VERIFY_NO_ERROR(); } +void ShaderGLTest::addSource() { + #ifndef MAGNUM_TARGET_GLES + Shader shader(Version::GL210, Shader::Type::Fragment); + #else + Shader shader(Version::GLES200, Shader::Type::Fragment); + #endif + + shader.addSource("#define FOO BAR\n") + .addSource("void main() {}\n"); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(shader.sources(), (std::vector{ + "#version 120\n", + "#line 1 1\n", + "#define FOO BAR\n", + "#line 1 2\n", + "void main() {}\n" + })); + #else + CORRADE_COMPARE(shader.sources(), (std::vector{ + "#version 100\n", + "#line 1 1\n", + "#define FOO BAR\n", + "#line 1 2\n", + "void main() {}\n" + })); + #endif +} + +void ShaderGLTest::addFile() { + #ifndef MAGNUM_TARGET_GLES + Shader shader(Version::GL210, Shader::Type::Fragment); + #else + Shader shader(Version::GLES200, Shader::Type::Fragment); + #endif + + shader.addFile(Utility::Directory::join(SHADERGLTEST_FILES_DIR, "shader.glsl")); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(shader.sources(), (std::vector{ + "#version 120\n", + "#line 1 1\n", + "void main() {}\n" + })); + #else + CORRADE_COMPARE(shader.sources(), (std::vector{ + "#version 100\n", + "#line 1 1\n", + "void main() {}\n" + })); + #endif +} + +void ShaderGLTest::compile() { + #ifndef MAGNUM_TARGET_GLES + constexpr Version v = Version::GL210; + #else + constexpr Version v = Version::GLES200; + #endif + + Shader shader(v, Shader::Type::Fragment); + shader.addSource("void main() {}\n"); + CORRADE_VERIFY(shader.compile()); + + Shader shader2(v, Shader::Type::Fragment); + shader2.addSource("[fu] bleh error #:! stuff\n"); + CORRADE_VERIFY(!shader2.compile()); +} + }} CORRADE_TEST_MAIN(Magnum::Test::ShaderGLTest) diff --git a/src/Test/ShaderGLTestConfigure.h.cmake b/src/Test/ShaderGLTestConfigure.h.cmake new file mode 100644 index 000000000..7e0dfb21e --- /dev/null +++ b/src/Test/ShaderGLTestConfigure.h.cmake @@ -0,0 +1,25 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 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. +*/ + +#define SHADERGLTEST_FILES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ShaderGLTestFiles" diff --git a/src/Test/ShaderGLTestFiles/shader.glsl b/src/Test/ShaderGLTestFiles/shader.glsl new file mode 100644 index 000000000..ab73b3a23 --- /dev/null +++ b/src/Test/ShaderGLTestFiles/shader.glsl @@ -0,0 +1 @@ +void main() {}