Browse Source

Move shader compilation/linking to member functions

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

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

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