rewrite shader compilation code

Fixes #1737
This commit is contained in:
itsmattkc
2021-09-03 13:30:22 -07:00
parent cf1cb5e0a9
commit 5e66892e64
3 changed files with 98 additions and 56 deletions
+96 -49
View File
@@ -280,44 +280,38 @@ QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code)
PRINT_GL_ERRORS;
QOpenGLShaderProgram* program = new QOpenGLShaderProgram(context_);
GLuint vert = CompileShader(GL_VERTEX_SHADER, code.vert_code());
GLuint frag = CompileShader(GL_FRAGMENT_SHADER, code.frag_code());
QString vert_code = code.vert_code();
QString frag_code = code.frag_code();
GLuint program = 0;
QString shader_preamble = QStringLiteral("#version 110\n"
"\n");
if (frag && vert) {
program = functions_->glCreateProgram();
functions_->glAttachShader(program, frag);
functions_->glAttachShader(program, vert);
functions_->glLinkProgram(program);
vert_code.prepend(shader_preamble);
frag_code.prepend(shader_preamble);
if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code)) {
qCritical() << "Failed to add vertex code to shader";
goto error;
GLint success;
functions_->glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
qWarning() << "Failed to link OpenGL shader program";
functions_->glDeleteProgram(program);
program = 0;
}
}
if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code)) {
qCritical() << "Failed to add fragment code to shader";
goto error;
}
functions_->glDeleteShader(frag);
functions_->glDeleteShader(vert);
if (!program->link()) {
qCritical() << "Failed to link shader";
goto error;
}
return Node::PtrToValue(program);
error:
delete program;
return QVariant();
return program;
}
void OpenGLRenderer::DestroyNativeShader(QVariant shader)
{
GL_PREAMBLE;
delete Node::ValueToPtr<QOpenGLShaderProgram>(shader);
GLuint program = shader.value<GLuint>();
functions_->glDeleteProgram(program);
}
void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int linesize)
@@ -431,14 +425,14 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
GLuint iterative_input = 0;
QVector<TextureToBind> textures_to_bind;
QOpenGLShaderProgram* shader = Node::ValueToPtr<QOpenGLShaderProgram>(s);
GLuint shader = s.value<GLuint>();
shader->bind();
functions_->glUseProgram(shader);
NodeValueMap::const_iterator it;
for (it=job.GetValues().constBegin(); it!=job.GetValues().constEnd(); it++) {
// See if the shader has takes this parameter as an input
int variable_location = shader->uniformLocation(it.key());
GLint variable_location = functions_->glGetUniformLocation(shader, it.key().toUtf8().constData());
if (variable_location == -1) {
continue;
@@ -455,43 +449,51 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
case NodeValue::kInt:
// kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to
// over/underflows if the number is large enough, but the likelihood of that is quite low.
shader->setUniformValue(variable_location, value.data().toInt());
functions_->glUniform1i(variable_location, value.data().toInt());
break;
case NodeValue::kFloat:
// kFloat technically specifies a double but as above, OpenGL doesn't support those.
shader->setUniformValue(variable_location, value.data().toFloat());
functions_->glUniform1f(variable_location, value.data().toFloat());
break;
case NodeValue::kVec2:
shader->setUniformValue(variable_location, value.data().value<QVector2D>());
{
QVector2D v = value.data().value<QVector2D>();
functions_->glUniform2fv(variable_location, 1, reinterpret_cast<const GLfloat*>(&v));
break;
}
case NodeValue::kVec3:
shader->setUniformValue(variable_location, value.data().value<QVector3D>());
{
QVector3D v = value.data().value<QVector3D>();
functions_->glUniform3fv(variable_location, 1, reinterpret_cast<const GLfloat*>(&v));
break;
}
case NodeValue::kVec4:
shader->setUniformValue(variable_location, value.data().value<QVector4D>());
{
QVector4D v = value.data().value<QVector4D>();
functions_->glUniform4fv(variable_location, 1, reinterpret_cast<const GLfloat*>(&v));
break;
}
case NodeValue::kMatrix:
shader->setUniformValue(variable_location, value.data().value<QMatrix4x4>());
functions_->glUniformMatrix4fv(variable_location, 1, false, value.data().value<QMatrix4x4>().constData());
break;
case NodeValue::kCombo:
shader->setUniformValue(variable_location, value.data().value<int>());
functions_->glUniform1i(variable_location, value.data().value<int>());
break;
case NodeValue::kColor:
{
Color color = value.data().value<Color>();
shader->setUniformValue(variable_location,
color.red(), color.green(), color.blue(), color.alpha());
functions_->glUniform4f(variable_location, color.red(), color.green(), color.blue(), color.alpha());
break;
}
case NodeValue::kBoolean:
shader->setUniformValue(variable_location, value.data().toBool());
functions_->glUniform1i(variable_location, value.data().toBool());
break;
case NodeValue::kTexture:
{
TexturePtr texture = value.data().value<TexturePtr>();
// Set value to bound texture
shader->setUniformValue(variable_location, textures_to_bind.size());
functions_->glUniform1i(variable_location, textures_to_bind.size());
// If this texture binding is the iterative input, set it here
if (it.key() == job.GetIterativeInput()) {
@@ -503,10 +505,9 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
// Set enable flag if shader wants it
GLuint tex_id = texture ? texture->id().value<GLuint>() : 0;
int enable_param_location = shader->uniformLocation(QStringLiteral("%1_enabled").arg(it.key()));
int enable_param_location = functions_->glGetUniformLocation(shader, QStringLiteral("%1_enabled").arg(it.key()).toUtf8().constData());
if (enable_param_location > -1) {
shader->setUniformValue(enable_param_location,
tex_id > 0);
functions_->glUniform1i(enable_param_location, tex_id > 0);
}
break;
}
@@ -542,8 +543,10 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
}
// Ensure matrix is set, at least to identity
shader->setUniformValue("ove_mvpmat",
job.GetValue(QStringLiteral("ove_mvpmat")).data().value<QMatrix4x4>());
GLint mvpmat_location = functions_->glGetUniformLocation(shader, "ove_mvpmat");
if (mvpmat_location > -1) {
functions_->glUniformMatrix4fv(mvpmat_location, 1, false, job.GetValue(QStringLiteral("ove_mvpmat")).data().value<QMatrix4x4>().constData());
}
// Set the viewport to the "physical" resolution of the destination
functions_->glViewport(0, 0,
@@ -568,7 +571,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
frag_vbo_.allocate(blit_texcoords.constData(), blit_texcoords.size() * sizeof(GLfloat));
frag_vbo_.release();
int vertex_location = shader->attributeLocation("a_position");
GLint vertex_location = functions_->glGetAttribLocation(shader, "a_position");
if (vertex_location != -1) {
vert_vbo_.bind();
functions_->glEnableVertexAttribArray(vertex_location);
@@ -576,7 +579,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
vert_vbo_.release();
}
int tex_location = shader->attributeLocation("a_texcoord");
GLint tex_location = functions_->glGetAttribLocation(shader, "a_texcoord");
if (tex_location != -1) {
frag_vbo_.bind();
functions_->glEnableVertexAttribArray(tex_location);
@@ -608,9 +611,12 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
}
}
GLint iteration_location = functions_->glGetUniformLocation(shader, "ove_iteration");
for (int iteration=0; iteration<real_iteration_count; iteration++) {
// Set iteration number
shader->setUniformValue("ove_iteration", iteration);
if (iteration_location > -1) {
functions_->glUniform1i(iteration_location, iteration);
}
// Replace iterative input
if (iteration == real_iteration_count-1) {
@@ -666,7 +672,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
}
// Release shader
shader->release();
functions_->glUseProgram(0);
// Release vertex array object
frag_vbo_.destroy();
@@ -861,6 +867,47 @@ GLuint OpenGLRenderer::GetCachedTexture(int width, int height, int depth, VideoP
return 0;
}
GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
{
static const QString shader_preamble = QStringLiteral("#version 110\n\n"
"precision highp float;\n\n");
QString complete_code = shader_preamble;
if (code.isEmpty()) {
// Use default code
if (type == GL_FRAGMENT_SHADER) {
complete_code.append(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.frag")));
} else if (type == GL_VERTEX_SHADER) {
complete_code.append(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert")));
}
} else {
complete_code.append(code);
}
QByteArray code_utf8 = complete_code.toUtf8();
const char *code_cstr = code_utf8.constData();
GLuint shader = functions_->glCreateShader(type);
functions_->glShaderSource(shader, 1, &code_cstr, nullptr);
functions_->glCompileShader(shader);
GLint success;
functions_->glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
qWarning() << "Failed to compile OpenGL shader";
QByteArray error_log(10240, Qt::Uninitialized);
functions_->glGetShaderInfoLog(shader, error_log.size(), nullptr, error_log.data());
std::cout << error_log.constData() << std::endl << code_cstr << std::endl;
functions_->glDeleteShader(shader);
shader = 0;
}
return shader;
}
void OpenGLRenderer::GarbageCollectTextureCache()
{
qint64 max_age = QDateTime::currentMSecsSinceEpoch() - kTextureCacheMaxSize;
+2
View File
@@ -98,6 +98,8 @@ private:
GLuint GetCachedTexture(int width, int height, int depth, VideoParams::Format format, int channel_count);
GLuint CompileShader(GLenum type, const QString &code);
QTimer cache_timer_;
QOpenGLContext* context_;
-7
View File
@@ -31,13 +31,6 @@ public:
frag_code_(frag_code),
vert_code_(vert_code)
{
if (frag_code_.isEmpty()) {
frag_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.frag"));
}
if (vert_code_.isEmpty()) {
vert_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert"));
}
}
const QString& frag_code() const