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. 10
      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(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders) {
submitLink(shaders);
return checkLink(shaders);
void AbstractShaderProgram::submitLink() {
glLinkProgram(_id);
}
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) {
/* Invoke (possibly parallel) linking on all shaders */
for(AbstractShaderProgram& shader: shaders) glLinkProgram(shader._id);
}
/** @todo update log messages */
bool AbstractShaderProgram::checkLink(std::initializer_list<Containers::Reference<AbstractShaderProgram>> shaders) {
bool allSuccess = true;
/* Show error log */
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 */
Int i = 1;
for(AbstractShaderProgram& shader: shaders) {
GLint success, logLength;
glGetProgramiv(shader._id, GL_LINK_STATUS, &success);
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;
/* Or just warnings, if any */
} else if(!message.empty()) {
Warning out{Debug::Flag::NoNewlineAtTheEnd};
out << "GL::AbstractShaderProgram::link(): linking";
out << "succeeded with the following message:" << Debug::newline << message;
}
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;
}

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);
/**
* @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)
/**
* @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}); }
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) {
submitCompile(shaders);
return checkCompile(shaders);
}
/* Upload sources of all shaders */
for(std::size_t i = 0; i != _sources.size(); ++i) {
pointers[i] = static_cast<const GLchar*>(_sources[i].data());
sizes[i] = _sources[i].size();
}
bool Shader::isCompileFinished() {
GLint success;
glGetShaderiv(_id, GL_COMPLETION_STATUS_KHR, &success);
return success == GL_TRUE;
glShaderSource(_id, _sources.size(), pointers, sizes);
glCompileShader(_id);
}
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 */
Containers::Array<const GLchar*> pointers(maxSourceCount);
Containers::Array<GLint> sizes(maxSourceCount);
bool Shader::checkCompile() { /* After compilation phase, check status of all shaders */
GLint success, logLength;
glGetShaderiv(_id, GL_COMPILE_STATUS, &success);
glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength);
/* Upload sources of all shaders */
for(Shader& shader: shaders) {
for(std::size_t i = 0; i != shader._sources.size(); ++i) {
pointers[i] = static_cast<const GLchar*>(shader._sources[i].data());
sizes[i] = shader._sources[i].size();
}
/* 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(_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 */
for(Shader& shader: shaders) glCompileShader(shader._id);
}
/** @todo update log messages */
bool Shader::checkCompile(std::initializer_list<Containers::Reference<Shader>> shaders) {
bool allSuccess = true;
/* Show error log */
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 */
Int i = 1;
for(Shader& shader: shaders) {
GLint success, logLength;
glGetShaderiv(shader._id, GL_COMPILE_STATUS, &success);
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;
/* Or just warnings, if any */
} else if(!message.empty()) {
Warning out{Debug::Flag::NoNewlineAtTheEnd};
out << "GL::Shader::compile(): compilation of" << shaderName(_type) << "shader";
out << "succeeded with the following message:" << Debug::newline << message;
}
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;
}
bool Shader::isCompileFinished() {
GLint success;
glGetShaderiv(_id, GL_COMPLETION_STATUS_KHR, &success);
return success == GL_TRUE;
}
void Shader::cleanLogImplementationNoOp(std::string&) {}
#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);
/**
* @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
* @param version Target version

10
src/Magnum/Shaders/FlatGL.cpp

@ -189,7 +189,8 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
frag.addSource(rs.getString("generic.glsl"))
.addSource(rs.getString("Flat.frag"));
GL::Shader::submitCompile({vert, frag});
vert.submitCompile();
frag.submitCompile();
CompileState cs{std::move(frag), std::move(vert), version, flags
#ifndef MAGNUM_TARGET_GLES
@ -236,7 +237,8 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(CompileState&& 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());
const GL::Context& context = GL::Context::current();
@ -319,10 +321,10 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(NoInitT, Flags flags
#ifndef MAGNUM_TARGET_GLES2
, UnsignedInt materialCount, UnsignedInt drawCount
#endif
) : GL::AbstractShaderProgram{}, _flags(flags),
) : GL::AbstractShaderProgram{}, _flags(flags),
#ifndef MAGNUM_TARGET_GLES2
_materialCount(materialCount), _drawCount(drawCount)
#endif
#endif
{}
#ifndef MAGNUM_TARGET_GLES2

Loading…
Cancel
Save