Browse Source

Move shader compilation/linking to member functions

pull/576/head
Vladislav Oleshko 4 years ago
parent
commit
66015a2f4e
  1. 39
      src/Magnum/GL/AbstractShaderProgram.cpp
  2. 20
      src/Magnum/GL/AbstractShaderProgram.h
  3. 78
      src/Magnum/GL/Shader.cpp
  4. 17
      src/Magnum/GL/Shader.h
  5. 6
      src/Magnum/Shaders/FlatGL.cpp

39
src/Magnum/GL/AbstractShaderProgram.cpp

@ -585,61 +585,48 @@ void AbstractShaderProgram::transformFeedbackVaryingsImplementationDanglingWorka
bool AbstractShaderProgram::link() { return link({*this}); } bool AbstractShaderProgram::link() { return link({*this}); }
bool AbstractShaderProgram::link(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders) { void AbstractShaderProgram::submitLink() {
submitLink(shaders); glLinkProgram(_id);
return checkLink(shaders);
}
void AbstractShaderProgram::submitLink() { submitLink({*this}); }
bool AbstractShaderProgram::checkLink() { return checkLink({*this}); }
void AbstractShaderProgram::submitLink(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders) {
/* Invoke (possibly parallel) linking on all shaders */
for(AbstractShaderProgram& shader: shaders) glLinkProgram(shader._id);
} }
bool AbstractShaderProgram::checkLink(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders) { bool AbstractShaderProgram::checkLink() {
bool allSuccess = true;
/* After linking phase, check status of all shaders */
Int i = 1;
for(AbstractShaderProgram& shader: shaders) {
GLint success, logLength; GLint success, logLength;
glGetProgramiv(shader._id, GL_LINK_STATUS, &success); glGetProgramiv(_id, GL_LINK_STATUS, &success);
glGetProgramiv(shader._id, GL_INFO_LOG_LENGTH, &logLength); glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength);
/* Error or warning message. The string is returned null-terminated, /* Error or warning message. The string is returned null-terminated,
strip the \0 at the end afterwards. */ strip the \0 at the end afterwards. */
std::string message(logLength, '\n'); std::string message(logLength, '\n');
if(message.size() > 1) if(message.size() > 1)
glGetProgramInfoLog(shader._id, message.size(), nullptr, &message[0]); glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]);
message.resize(Math::max(logLength, 1)-1); message.resize(Math::max(logLength, 1)-1);
/* Some drivers are chatty and can't keep shut when there's nothing to /* Some drivers are chatty and can't keep shut when there's nothing to
be said, handle that as well. */ be said, handle that as well. */
Context::current().state().shaderProgram.cleanLogImplementation(message); Context::current().state().shaderProgram.cleanLogImplementation(message);
/** @todo update log messages */
/* Show error log */ /* Show error log */
if(!success) { if(!success) {
Error out{Debug::Flag::NoNewlineAtTheEnd}; Error out{Debug::Flag::NoNewlineAtTheEnd};
out << "GL::AbstractShaderProgram::link(): linking"; out << "GL::AbstractShaderProgram::link(): linking";
if(shaders.size() != 1) out << "of shader" << i;
out << "failed with the following message:" << Debug::newline << message; out << "failed with the following message:" << Debug::newline << message;
/* Or just warnings, if any */ /* Or just warnings, if any */
} else if(!message.empty()) { } else if(!message.empty()) {
Warning out{Debug::Flag::NoNewlineAtTheEnd}; Warning out{Debug::Flag::NoNewlineAtTheEnd};
out << "GL::AbstractShaderProgram::link(): linking"; out << "GL::AbstractShaderProgram::link(): linking";
if(shaders.size() != 1) out << "of shader" << i;
out << "succeeded with the following message:" << Debug::newline << message; out << "succeeded with the following message:" << Debug::newline << message;
} }
/* Success of all depends on each of them */ return success;
allSuccess = allSuccess && success;
++i;
} }
bool AbstractShaderProgram::link(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders) {
for(AbstractShaderProgram& shader: shaders) shader.submitLink();
bool allSuccess = true;
for(AbstractShaderProgram& shader: shaders) allSuccess &= shader.checkLink();
return allSuccess; return allSuccess;
} }

20
src/Magnum/GL/AbstractShaderProgram.h

@ -1280,26 +1280,6 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject {
*/ */
static bool link(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders); static bool link(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders);
/**
* @brief Submit shaders for linking
*
* The operation is batched in a
* way that allows the driver to link multiple shaders simultaneously
* (i.e. in multiple threads).
*
*/
static void submitLink(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders);
/**
* @brief Check linking status of shaders and await completion
*
* Returns @cpp false @ce if linking of any shader failed, @cpp true @ce
* if everything succeeded. Linker message (if any) is printed to error
* output.
*
*/
static bool checkLink(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders);
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
/** /**
* @brief Allow retrieving program binary * @brief Allow retrieving program binary

78
src/Magnum/GL/Shader.cpp

@ -749,91 +749,71 @@ Shader& Shader::addFile(const std::string& filename) {
bool Shader::compile() { return compile({*this}); } bool Shader::compile() { return compile({*this}); }
void Shader::submitCompile() { submitCompile({*this}); } void Shader::submitCompile() {
CORRADE_ASSERT(_sources.size() > 1, "GL::Shader::compile(): no files added", );
bool Shader::checkCompile() { return checkCompile({*this}); }
bool Shader::compile(std::initializer_list<Containers::Reference<Shader>> shaders) {
submitCompile(shaders);
return checkCompile(shaders);
}
bool Shader::isCompileFinished() {
GLint success;
glGetShaderiv(_id, GL_COMPLETION_STATUS_KHR, &success);
return success == GL_TRUE;
}
void Shader::submitCompile(std::initializer_list<Containers::Reference<Shader>> shaders) {
/* Allocate large enough array for source pointers and sizes (to avoid
reallocating it for each of them) */
std::size_t maxSourceCount = 0;
for(Shader& shader: shaders) {
CORRADE_ASSERT(shader._sources.size() > 1, "GL::Shader::compile(): no files added", );
maxSourceCount = Math::max(shader._sources.size(), maxSourceCount);
}
/** @todo ArrayTuple/VLAs */ /** @todo ArrayTuple/VLAs */
Containers::Array<const GLchar*> pointers(maxSourceCount); Containers::Array<const GLchar*> pointers(_sources.size());
Containers::Array<GLint> sizes(maxSourceCount); Containers::Array<GLint> sizes(_sources.size());
/* Upload sources of all shaders */ /* Upload sources of all shaders */
for(Shader& shader: shaders) { for(std::size_t i = 0; i != _sources.size(); ++i) {
for(std::size_t i = 0; i != shader._sources.size(); ++i) { pointers[i] = static_cast<const GLchar*>(_sources[i].data());
pointers[i] = static_cast<const GLchar*>(shader._sources[i].data()); sizes[i] = _sources[i].size();
sizes[i] = shader._sources[i].size();
}
glShaderSource(shader._id, shader._sources.size(), pointers, sizes);
} }
/* Invoke (possibly parallel) compilation on all shaders */ glShaderSource(_id, _sources.size(), pointers, sizes);
for(Shader& shader: shaders) glCompileShader(shader._id); glCompileShader(_id);
} }
bool Shader::checkCompile(std::initializer_list<Containers::Reference<Shader>> shaders) { bool Shader::checkCompile() { /* After compilation phase, check status of all shaders */
bool allSuccess = true;
/* After compilation phase, check status of all shaders */
Int i = 1;
for(Shader& shader: shaders) {
GLint success, logLength; GLint success, logLength;
glGetShaderiv(shader._id, GL_COMPILE_STATUS, &success); glGetShaderiv(_id, GL_COMPILE_STATUS, &success);
glGetShaderiv(shader._id, GL_INFO_LOG_LENGTH, &logLength); glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength);
/* Error or warning message. The string is returned null-terminated, /* Error or warning message. The string is returned null-terminated,
strip the \0 at the end afterwards. */ strip the \0 at the end afterwards. */
std::string message(logLength, '\0'); std::string message(logLength, '\0');
if(message.size() > 1) if(message.size() > 1)
glGetShaderInfoLog(shader._id, message.size(), nullptr, &message[0]); glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]);
message.resize(Math::max(logLength, 1)-1); message.resize(Math::max(logLength, 1)-1);
/* Some drivers are chatty and can't keep shut when there's nothing to /* Some drivers are chatty and can't keep shut when there's nothing to
be said, handle that as well. */ be said, handle that as well. */
Context::current().state().shader.cleanLogImplementation(message); Context::current().state().shader.cleanLogImplementation(message);
/** @todo update log messages */
/* Show error log */ /* Show error log */
if(!success) { if(!success) {
Error out{Debug::Flag::NoNewlineAtTheEnd}; Error out{Debug::Flag::NoNewlineAtTheEnd};
out << "GL::Shader::compile(): compilation of" << shaderName(shader._type) << "shader"; out << "GL::Shader::compile(): compilation of" << shaderName(_type) << "shader";
if(shaders.size() != 1) out << i;
out << "failed with the following message:" << Debug::newline << message; out << "failed with the following message:" << Debug::newline << message;
/* Or just warnings, if any */ /* Or just warnings, if any */
} else if(!message.empty()) { } else if(!message.empty()) {
Warning out{Debug::Flag::NoNewlineAtTheEnd}; Warning out{Debug::Flag::NoNewlineAtTheEnd};
out << "GL::Shader::compile(): compilation of" << shaderName(shader._type) << "shader"; out << "GL::Shader::compile(): compilation of" << shaderName(_type) << "shader";
if(shaders.size() != 1) out << i;
out << "succeeded with the following message:" << Debug::newline << message; out << "succeeded with the following message:" << Debug::newline << message;
} }
/* Success of all depends on each of them */ return success;
allSuccess = allSuccess && success;
++i;
} }
bool Shader::compile(std::initializer_list<Containers::Reference<Shader>> shaders) {
/* Invoke (possibly parallel) compilation on all shaders */
for(Shader& shader: shaders) shader.submitCompile();
bool allSuccess = true;
for(Shader& shader: shaders) allSuccess &= shader.checkCompile();
return allSuccess; return allSuccess;
} }
bool Shader::isCompileFinished() {
GLint success;
glGetShaderiv(_id, GL_COMPLETION_STATUS_KHR, &success);
return success == GL_TRUE;
}
void Shader::cleanLogImplementationNoOp(std::string&) {} void Shader::cleanLogImplementationNoOp(std::string&) {}
#if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES) #if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES)

17
src/Magnum/GL/Shader.h

@ -521,23 +521,6 @@ class MAGNUM_GL_EXPORT Shader: public AbstractObject {
*/ */
static bool compile(std::initializer_list<Containers::Reference<Shader>> shaders); static bool compile(std::initializer_list<Containers::Reference<Shader>> shaders);
/**
* @brief Submit multiple shaders for compilation
*
* The operation is batched in a way that
* allows the driver to perform multiple compilations simultaneously
* (i.e. in multiple threads).
*/
static void submitCompile(std::initializer_list<Containers::Reference<Shader>> shaders);
/**
* @brief Check compilations status of multiple shaders and await completion
*
* Returns @cpp false @ce if compilation of any shader failed,
* @cpp true @ce if everything succeeded.
*/
static bool checkCompile(std::initializer_list<Containers::Reference<Shader>> shaders);
/** /**
* @brief Constructor * @brief Constructor
* @param version Target version * @param version Target version

6
src/Magnum/Shaders/FlatGL.cpp

@ -189,7 +189,8 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
frag.addSource(rs.getString("generic.glsl")) frag.addSource(rs.getString("generic.glsl"))
.addSource(rs.getString("Flat.frag")); .addSource(rs.getString("Flat.frag"));
GL::Shader::submitCompile({vert, frag}); vert.submitCompile();
frag.submitCompile();
CompileState cs{std::move(frag), std::move(vert), version, flags CompileState cs{std::move(frag), std::move(vert), version, flags
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -236,7 +237,8 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(CompileState&& cs) template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(CompileState&& cs)
: FlatGL{static_cast<FlatGL&&>(std::move(cs))} { : FlatGL{static_cast<FlatGL&&>(std::move(cs))} {
CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::checkCompile({cs._vert, cs._frag})); CORRADE_INTERNAL_ASSERT_OUTPUT(cs._vert.checkCompile());
CORRADE_INTERNAL_ASSERT_OUTPUT(cs._frag.checkCompile());
CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink()); CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink());
const GL::Context& context = GL::Context::current(); const GL::Context& context = GL::Context::current();

Loading…
Cancel
Save