diff --git a/src/Magnum/Shaders/Test/VertexColorGLTest.cpp b/src/Magnum/Shaders/Test/VertexColorGLTest.cpp index abbd56bf4..233850198 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,57 @@ template void VertexColorGLTest::constructUniformBuffers MAGNUM_VERIFY_NO_GL_ERROR(); } + +template void VertexColorGLTest::constructUniformBuffersAsync() { + setTestCaseTemplateName(Utility::format("{}", dimensions)); + + constexpr struct { + const char* name; + VertexColorGL2D::Flags flags; + UnsignedInt drawCount; + } data { + "multiple draws", VertexColorGL2D::Flag::UniformBuffers, 63 + }; + setTestCaseDescription(data.name); + + #ifndef MAGNUM_TARGET_GLES + if((data.flags & VertexColorGL::Flag::UniformBuffers) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); + #endif + + if(data.flags >= VertexColorGL2D::Flag::MultiDraw) { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported."); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported."); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported."); + #endif + } + auto compileState = VertexColorGL::compile(data.flags, data.drawCount); + CORRADE_COMPARE(compileState.flags(), data.flags); + CORRADE_COMPARE(compileState.drawCount(), data.drawCount); + + while(!compileState.isLinkFinished()) + Utility::System::sleep(100); + + VertexColorGL shader{std::move(compileState)}; + CORRADE_COMPARE(shader.flags(), data.flags); + CORRADE_COMPARE(shader.drawCount(), data.drawCount); + 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/VertexColorGL.cpp b/src/Magnum/Shaders/VertexColorGL.cpp index 31d6e4821..70c502fac 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,33 @@ 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()); + CORRADE_INTERNAL_ASSERT_OUTPUT(cs._vert.checkCompile()); + CORRADE_INTERNAL_ASSERT_OUTPUT(cs._frag.checkCompile()); + + 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 +168,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 +180,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,11 +188,10 @@ template VertexColorGL::VertexColorGL(const setTransformationProjectionMatrix(MatrixTypeFor{Math::IdentityInit}); } #endif -} -#ifndef MAGNUM_TARGET_GLES2 -template VertexColorGL::VertexColorGL(const Flags flags): VertexColorGL{flags, 1} {} -#endif + static_cast(context); + static_cast(version); +} template VertexColorGL& VertexColorGL::setTransformationProjectionMatrix(const MatrixTypeFor& matrix) { #ifndef MAGNUM_TARGET_GLES2 diff --git a/src/Magnum/Shaders/VertexColorGL.h b/src/Magnum/Shaders/VertexColorGL.h index 3ecdd673f..69ad1e87a 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" @@ -216,7 +217,7 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL: publ * @ref VertexColorGL(Flags, UnsignedInt) with @p drawCount set to * @cpp 1 @ce. */ - explicit VertexColorGL(Flags flags = {}); + explicit VertexColorGL(Flags flags = {}): VertexColorGL{compile(flags)} {} #ifndef MAGNUM_TARGET_GLES2 /** @@ -247,7 +248,8 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL: publ for this might be too confusing); what if some parameters won't be (unsigned) integers? like a string with shader extensions? make a whole Configuration class? */ - explicit VertexColorGL(Flags flags, UnsignedInt drawCount); + explicit VertexColorGL(Flags flags, UnsignedInt drawCount): + VertexColorGL{compile(flags, drawCount)} {} #endif /** @@ -264,6 +266,22 @@ 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) { + return compile(flags, 1); + } + #endif + /** @brief Copying is not allowed */ VertexColorGL(const VertexColorGL&) = delete; @@ -406,6 +424,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 +446,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