198 lines
4.7 KiB
C++
198 lines
4.7 KiB
C++
/* SPDX-License-Identifier: Apache-2.0
|
|
* Copyright 2011-2022 Blender Foundation */
|
|
|
|
#include "app/opengl/shader.h"
|
|
|
|
#include "util/log.h"
|
|
#include "util/string.h"
|
|
|
|
#include <GL/glew.h>
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* --------------------------------------------------------------------
|
|
* OpenGLShader.
|
|
*/
|
|
|
|
static const char *VERTEX_SHADER =
|
|
"#version 330\n"
|
|
"uniform vec2 fullscreen;\n"
|
|
"in vec2 texCoord;\n"
|
|
"in vec2 pos;\n"
|
|
"out vec2 texCoord_interp;\n"
|
|
"\n"
|
|
"vec2 normalize_coordinates()\n"
|
|
"{\n"
|
|
" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
|
|
"}\n"
|
|
"\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
|
|
" texCoord_interp = texCoord;\n"
|
|
"}\n\0";
|
|
|
|
static const char *FRAGMENT_SHADER =
|
|
"#version 330\n"
|
|
"uniform sampler2D image_texture;\n"
|
|
"in vec2 texCoord_interp;\n"
|
|
"out vec4 fragColor;\n"
|
|
"\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" vec4 rgba = texture(image_texture, texCoord_interp);\n"
|
|
/* Harcoded Rec.709 gamma, should use OpenColorIO eventually. */
|
|
" fragColor = pow(rgba, vec4(0.45, 0.45, 0.45, 1.0));\n"
|
|
"}\n\0";
|
|
|
|
static void shader_print_errors(const char *task, const char *log, const char *code)
|
|
{
|
|
LOG(ERROR) << "Shader: " << task << " error:";
|
|
LOG(ERROR) << "===== shader string ====";
|
|
|
|
stringstream stream(code);
|
|
string partial;
|
|
|
|
int line = 1;
|
|
while (getline(stream, partial, '\n')) {
|
|
if (line < 10) {
|
|
LOG(ERROR) << " " << line << " " << partial;
|
|
}
|
|
else {
|
|
LOG(ERROR) << line << " " << partial;
|
|
}
|
|
line++;
|
|
}
|
|
LOG(ERROR) << log;
|
|
}
|
|
|
|
static int compile_shader_program(void)
|
|
{
|
|
const struct Shader {
|
|
const char *source;
|
|
const GLenum type;
|
|
} shaders[2] = {{VERTEX_SHADER, GL_VERTEX_SHADER}, {FRAGMENT_SHADER, GL_FRAGMENT_SHADER}};
|
|
|
|
const GLuint program = glCreateProgram();
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
const GLuint shader = glCreateShader(shaders[i].type);
|
|
|
|
string source_str = shaders[i].source;
|
|
const char *c_str = source_str.c_str();
|
|
|
|
glShaderSource(shader, 1, &c_str, NULL);
|
|
glCompileShader(shader);
|
|
|
|
GLint compile_status;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
|
|
|
|
if (!compile_status) {
|
|
GLchar log[5000];
|
|
GLsizei length = 0;
|
|
glGetShaderInfoLog(shader, sizeof(log), &length, log);
|
|
shader_print_errors("compile", log, c_str);
|
|
return 0;
|
|
}
|
|
|
|
glAttachShader(program, shader);
|
|
}
|
|
|
|
/* Link output. */
|
|
glBindFragDataLocation(program, 0, "fragColor");
|
|
|
|
/* Link and error check. */
|
|
glLinkProgram(program);
|
|
|
|
GLint link_status;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &link_status);
|
|
if (!link_status) {
|
|
GLchar log[5000];
|
|
GLsizei length = 0;
|
|
glGetShaderInfoLog(program, sizeof(log), &length, log);
|
|
shader_print_errors("linking", log, VERTEX_SHADER);
|
|
shader_print_errors("linking", log, FRAGMENT_SHADER);
|
|
return 0;
|
|
}
|
|
|
|
return program;
|
|
}
|
|
|
|
int OpenGLShader::get_position_attrib_location()
|
|
{
|
|
if (position_attribute_location_ == -1) {
|
|
const uint shader_program = get_shader_program();
|
|
position_attribute_location_ = glGetAttribLocation(shader_program, position_attribute_name);
|
|
}
|
|
return position_attribute_location_;
|
|
}
|
|
|
|
int OpenGLShader::get_tex_coord_attrib_location()
|
|
{
|
|
if (tex_coord_attribute_location_ == -1) {
|
|
const uint shader_program = get_shader_program();
|
|
tex_coord_attribute_location_ = glGetAttribLocation(shader_program, tex_coord_attribute_name);
|
|
}
|
|
return tex_coord_attribute_location_;
|
|
}
|
|
|
|
void OpenGLShader::bind(int width, int height)
|
|
{
|
|
create_shader_if_needed();
|
|
|
|
if (!shader_program_) {
|
|
return;
|
|
}
|
|
|
|
glUseProgram(shader_program_);
|
|
glUniform1i(image_texture_location_, 0);
|
|
glUniform2f(fullscreen_location_, width, height);
|
|
}
|
|
|
|
void OpenGLShader::unbind()
|
|
{
|
|
}
|
|
|
|
uint OpenGLShader::get_shader_program()
|
|
{
|
|
return shader_program_;
|
|
}
|
|
|
|
void OpenGLShader::create_shader_if_needed()
|
|
{
|
|
if (shader_program_ || shader_compile_attempted_) {
|
|
return;
|
|
}
|
|
|
|
shader_compile_attempted_ = true;
|
|
|
|
shader_program_ = compile_shader_program();
|
|
if (!shader_program_) {
|
|
return;
|
|
}
|
|
|
|
glUseProgram(shader_program_);
|
|
|
|
image_texture_location_ = glGetUniformLocation(shader_program_, "image_texture");
|
|
if (image_texture_location_ < 0) {
|
|
LOG(ERROR) << "Shader doesn't contain the 'image_texture' uniform.";
|
|
destroy_shader();
|
|
return;
|
|
}
|
|
|
|
fullscreen_location_ = glGetUniformLocation(shader_program_, "fullscreen");
|
|
if (fullscreen_location_ < 0) {
|
|
LOG(ERROR) << "Shader doesn't contain the 'fullscreen' uniform.";
|
|
destroy_shader();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void OpenGLShader::destroy_shader()
|
|
{
|
|
glDeleteProgram(shader_program_);
|
|
shader_program_ = 0;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|