-
Notifications
You must be signed in to change notification settings - Fork 440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async GL shader compilation #534
Comments
Seeing all these |
(My STL skepticism immediately kicked in, sorry 😆) If I understand correctly, |
|
Hi! I've taken this up, I hope a draft will be ready in a few days |
Oh? That's very cool :) Since this would be I think your very first contribution to Magnum, feel free to post a WIP state as soon as you have something so we can agree on the direction and workflow early on. |
Implemented with #576. |
The goal is figuring out a way how to use
KHR_parallel_shader_compile
without having to give up on the current way shaders are compiled, linked and initialized in a single constructor expression:Right now, shader compiler parallelization is only partially exploited in list-taking
GL::Shader::compile()
andGL::AbstractShaderProgram::link()
which first submit compile/link command for all shaders and then check for errors. Since those are always called from the constructor, the max amount of parallelization is only 2 (or 3 when GS is used), which really isn't much. One option to improve this would be to callcompile()
andlink()
outside of the constructor, on multiple shader/program instances, but that means we lose the convenient single-expression RAII setup, and because the status is still checked right after all compilation jobs is submitted it won't help much on certain backends such as the shitty old D3D compiler that can sometimes take several seconds to compile a single shader.The requirements are thus:
A proposal that could check out all of the above is:
void Shader::submitCompile()
andvoid AbstractShaderProgram::submitLink()
(better naming?) that only submit the compilation/link and don't check for the statusbool Shader::checkCompile()
andbool AbstractShaderProgram::checkLink()
(naming??) that returnsfalse
and prints an error message// Never check compile status unless subsequent linking fails.
so maybe the desired workflow isShader::compile(...)
andAbstractShaderProgram::link(...)
just wrappers that callsubmitCompile()
/submitLink()
on all instances and thencheckCompile()
/checkLink()
on all of thembool Shader::isCompileFinished()
/bool AbstractShaderProgram::isLinkFinished()
(naming??) that exposes the new query ofKHR_parallel_shader_compile
Shaders::FooGL::CompileState
that contains the intermediate state of the compilation as private fields (vertex, fragmentGL::Shader
instances, construction parameters like flags, light count)AbstractShaderProgram::CompileState
base, which is able to hold the program object and allows us to callsubmitLink()
/checkLink()
/isLinkFinished()
without having anyAbstractShaderProgram
instance yetShaders::FooGL::submitCompile(...) -> Shaders::FooGL::CompileState
(or justcompile()
?) that populates the output structure and callssubmitCompile()
/submitLink()
on each, but without checking status -- basically the "first half" of the existing constructorsubmitLink()
done separately as well, to be able to submit 200 shader compilations first, 100 shader links second and then 100 error checks last? The WebGL extension spec suggests that, but does it actually matter whether I interleave compilations and linkings or not if I don't check for any status until the end?Shaders::FooGL::FooGL(Shaders::FooGL::CompileState&&)
that then creates the real shader instance from the intermediate state by checking for errors, querying uniform locations and performing initialization -- the "second half" of the existing constructorShaders::FooGL::FooGL(...)
constructor simply delegate toFooGL{compile(...)}
This would then allow workflows such as the following where one populates intermediates for desired shader variants, does independent work in the meantime and then (either after checking for completion or forcibly) populates real instances:
Further work:
Containers::Either<T, U>
which would be like anOptional
but providing an actual value for the "disengaged" state, with the usual->
accessing theT
and asserts if not thereValueExceptIfNotThenItsThisOtherThing
Containers::Either<Shaders::FooGL, Shaders::FooGL::CompileState>
could then hold the intermediate for as long as the compilation is happening in the background, and then when it's finished it gets flipped to the final typeAbstractShaderProgram
could provide some wrapper around (AsyncShader<T>: Containers::Either<T, T::CompileState>
), which automatically switches the underlying type when compilation is done or forces a stall if the user actually accesses the to-be-populated instance with->
Example:
Cc: @Squareys
The text was updated successfully, but these errors were encountered: