backend: gl: implement create_shader/destroy_shader

This commit is contained in:
Yuxuan Shui 2022-07-17 14:24:46 +01:00
parent 947077f329
commit 81768f4a11
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
3 changed files with 139 additions and 68 deletions

View File

@ -140,47 +140,56 @@ end:
}
/**
* @brief Create a program from vertex and fragment shader strings.
* @brief Create a program from NULL-terminated arrays of vertex and fragment shader
* strings.
*/
GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str) {
GLuint vert_shader = 0;
GLuint frag_shader = 0;
GLuint prog = 0;
GLuint gl_create_program_from_strv(const char **vert_shaders, const char **frag_shaders) {
int vert_count, frag_count;
for (vert_count = 0; vert_shaders && vert_shaders[vert_count]; ++vert_count)
;
for (frag_count = 0; frag_shaders && frag_shaders[frag_count]; ++frag_count)
;
auto shaders = (GLuint *)ccalloc(vert_count + frag_count, GLuint);
if (vert_shader_str)
vert_shader = gl_create_shader(GL_VERTEX_SHADER, vert_shader_str);
if (frag_shader_str)
frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, frag_shader_str);
{
GLuint shaders[2];
int count = 0;
if (vert_shader) {
shaders[count++] = vert_shader;
}
if (frag_shader) {
shaders[count++] = frag_shader;
}
if (count) {
prog = gl_create_program(shaders, count);
}
for (int i = 0; i < vert_count; ++i) {
shaders[i] = gl_create_shader(GL_VERTEX_SHADER, vert_shaders[i]);
}
for (int i = 0; i < frag_count; ++i) {
shaders[vert_count + i] =
gl_create_shader(GL_FRAGMENT_SHADER, frag_shaders[i]);
}
GLuint prog = gl_create_program(shaders, vert_count + frag_count);
if (vert_shader)
glDeleteShader(vert_shader);
if (frag_shader)
glDeleteShader(frag_shader);
for (int i = 0; i < vert_count + frag_count; ++i) {
glDeleteShader(shaders[i]);
}
free(shaders);
return prog;
}
static void gl_free_prog_main(gl_win_shader_t *pprogram) {
if (!pprogram)
/**
* @brief Create a program from vertex and fragment shader strings.
*/
GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str) {
const char *vert_shaders[2] = {vert_shader_str, NULL};
const char *frag_shaders[2] = {frag_shader_str, NULL};
return gl_create_program_from_strv(vert_shaders, frag_shaders);
}
void gl_destroy_window_shader(backend_t *backend_data attr_unused, void *shader) {
if (!shader) {
return;
}
auto pprogram = (gl_win_shader_t *)shader;
if (pprogram->prog) {
glDeleteProgram(pprogram->prog);
pprogram->prog = 0;
}
free(shader);
}
/*
@ -371,35 +380,41 @@ static void _gl_compose(backend_t *base, struct backend_image *img, GLuint targe
brightness = gl_average_texture_color(base, img);
}
assert(gd->win_shader.prog);
glUseProgram(gd->win_shader.prog);
if (gd->win_shader.uniform_opacity >= 0) {
glUniform1f(gd->win_shader.uniform_opacity, (float)img->opacity);
auto win_shader = inner->shader;
if (!win_shader) {
win_shader = gd->default_shader;
}
if (gd->win_shader.uniform_invert_color >= 0) {
glUniform1i(gd->win_shader.uniform_invert_color, img->color_inverted);
assert(win_shader);
assert(win_shader->prog);
glUseProgram(win_shader->prog);
if (win_shader->uniform_opacity >= 0) {
glUniform1f(win_shader->uniform_opacity, (float)img->opacity);
}
if (gd->win_shader.uniform_tex >= 0) {
glUniform1i(gd->win_shader.uniform_tex, 0);
if (win_shader->uniform_invert_color >= 0) {
glUniform1i(win_shader->uniform_invert_color, img->color_inverted);
}
if (gd->win_shader.uniform_dim >= 0) {
glUniform1f(gd->win_shader.uniform_dim, (float)img->dim);
if (win_shader->uniform_tex >= 0) {
glUniform1i(win_shader->uniform_tex, 0);
}
if (gd->win_shader.uniform_brightness >= 0) {
glUniform1i(gd->win_shader.uniform_brightness, 1);
if (win_shader->uniform_dim >= 0) {
glUniform1f(win_shader->uniform_dim, (float)img->dim);
}
if (gd->win_shader.uniform_max_brightness >= 0) {
glUniform1f(gd->win_shader.uniform_max_brightness, (float)img->max_brightness);
if (win_shader->uniform_brightness >= 0) {
glUniform1i(win_shader->uniform_brightness, 1);
}
if (gd->win_shader.uniform_corner_radius >= 0) {
glUniform1f(gd->win_shader.uniform_corner_radius, (float)img->corner_radius);
if (win_shader->uniform_max_brightness >= 0) {
glUniform1f(win_shader->uniform_max_brightness, (float)img->max_brightness);
}
if (gd->win_shader.uniform_border_width >= 0) {
if (win_shader->uniform_corner_radius >= 0) {
glUniform1f(win_shader->uniform_corner_radius, (float)img->corner_radius);
}
if (win_shader->uniform_border_width >= 0) {
auto border_width = img->border_width;
if (border_width > img->corner_radius) {
border_width = 0;
}
glUniform1f(gd->win_shader.uniform_border_width, (float)border_width);
glUniform1f(win_shader->uniform_border_width, (float)border_width);
}
// log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n",
@ -883,13 +898,13 @@ const char *vertex_shader = GLSL(330,
/**
* Load a GLSL main program from shader strings.
*/
static int gl_win_shader_from_string(const char *vshader_str, const char *fshader_str,
gl_win_shader_t *ret) {
static bool gl_win_shader_from_stringv(const char **vshader_strv,
const char **fshader_strv, gl_win_shader_t *ret) {
// Build program
ret->prog = gl_create_program_from_str(vshader_str, fshader_str);
ret->prog = gl_create_program_from_strv(vshader_strv, fshader_strv);
if (!ret->prog) {
log_error("Failed to create GLSL program.");
return -1;
return false;
}
// Get uniform addresses
@ -1545,8 +1560,7 @@ const char *win_shader_glsl = GLSL(330,
return length(max(d, 0.0));
}
void main() {
vec4 c = texelFetch(tex, ivec2(texcoord), 0);
vec4 default_post_processing(vec4 c) {
vec4 border_color = texture(tex, vec2(0.0, 0.5));
if (invert_color) {
c = vec4(c.aaa - c.rgb, c.a);
@ -1581,7 +1595,23 @@ const char *win_shader_glsl = GLSL(330,
c = (1.0f - factor) * c + factor * border_color;
}
gl_FragColor = c;
return c;
}
vec4 window_shader();
void main() {
gl_FragColor = window_shader();
}
);
const char *win_shader_default = GLSL(330,
in vec2 texcoord;
uniform sampler2D tex;
vec4 default_post_processing(vec4 c);
vec4 window_shader() {
vec4 c = texelFetch(tex, ivec2(texcoord), 0);
return default_post_processing(c);
}
);
@ -1596,6 +1626,36 @@ const char *present_vertex_shader = GLSL(330,
);
// clang-format on
void *gl_create_window_shader(backend_t *backend_data attr_unused, const char *source) {
auto win_shader = (gl_win_shader_t *)ccalloc(1, gl_win_shader_t);
const char *vert_shaders[2] = {vertex_shader, NULL};
const char *frag_shaders[3] = {win_shader_glsl, source, NULL};
if (!gl_win_shader_from_stringv(vert_shaders, frag_shaders, win_shader)) {
free(win_shader);
return NULL;
}
GLint viewport_dimensions[2];
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport_dimensions);
// Set projection matrix to gl viewport dimensions so we can use screen
// coordinates for all vertices
// Note: OpenGL matrices are column major
GLfloat projection_matrix[4][4] = {{2.0F / (GLfloat)viewport_dimensions[0], 0, 0, 0},
{0, 2.0F / (GLfloat)viewport_dimensions[1], 0, 0},
{0, 0, 0, 0},
{-1, -1, 0, 1}};
int pml = glGetUniformLocationChecked(win_shader->prog, "projection");
glUseProgram(win_shader->prog);
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
glUseProgram(0);
return win_shader;
}
bool gl_init(struct gl_data *gd, session_t *ps) {
// Initialize GLX data structure
glDisable(GL_DEPTH_TEST);
@ -1637,24 +1697,24 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
// Initialize shaders
gd->default_shader = gl_create_window_shader(NULL, win_shader_default);
if (!gd->default_shader) {
log_error("Failed to create window shaders");
return false;
}
// Set projection matrix to gl viewport dimensions so we can use screen
// coordinates for all vertices
// Note: OpenGL matrices are column major
GLfloat projection_matrix[4][4] = {{2.0f / (GLfloat)viewport_dimensions[0], 0, 0, 0},
{0, 2.0f / (GLfloat)viewport_dimensions[1], 0, 0},
GLfloat projection_matrix[4][4] = {{2.0F / (GLfloat)viewport_dimensions[0], 0, 0, 0},
{0, 2.0F / (GLfloat)viewport_dimensions[1], 0, 0},
{0, 0, 0, 0},
{-1, -1, 0, 1}};
// Initialize shaders
gl_win_shader_from_string(vertex_shader, win_shader_glsl, &gd->win_shader);
int pml = glGetUniformLocationChecked(gd->win_shader.prog, "projection");
glUseProgram(gd->win_shader.prog);
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
glUseProgram(0);
gd->fill_shader.prog = gl_create_program_from_str(fill_vert, fill_frag);
gd->fill_shader.color_loc = glGetUniformLocation(gd->fill_shader.prog, "color");
pml = glGetUniformLocationChecked(gd->fill_shader.prog, "projection");
int pml = glGetUniformLocationChecked(gd->fill_shader.prog, "projection");
glUseProgram(gd->fill_shader.prog);
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
glUseProgram(0);
@ -1713,13 +1773,16 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
}
void gl_deinit(struct gl_data *gd) {
gl_free_prog_main(&gd->win_shader);
if (gd->logger) {
log_remove_target_tls(gd->logger);
gd->logger = NULL;
}
if (gd->default_shader) {
gl_destroy_window_shader(&gd->base, gd->default_shader);
gd->default_shader = NULL;
}
gl_check_err();
}

View File

@ -28,6 +28,8 @@ static inline GLint glGetUniformLocationChecked(GLuint p, const char *name) {
// Program and uniforms for window shader
typedef struct {
UT_hash_handle hh;
uint32_t id;
GLuint prog;
GLint uniform_opacity;
GLint uniform_invert_color;
@ -68,6 +70,7 @@ struct gl_texture {
// Textures for auxiliary uses.
GLuint auxiliary_texture[2];
gl_win_shader_t *shader;
void *user_data;
};
@ -79,7 +82,8 @@ struct gl_data {
bool has_robustness;
// Height and width of the root window
int height, width;
gl_win_shader_t win_shader;
// Hash-table of window shaders
gl_win_shader_t *default_shader;
gl_brightness_shader_t brightness_shader;
gl_fill_shader_t fill_shader;
GLuint back_texture, back_fbo;
@ -103,12 +107,14 @@ typedef struct session session_t;
GLuint gl_create_shader(GLenum shader_type, const char *shader_str);
GLuint gl_create_program(const GLuint *const shaders, int nshaders);
GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);
void *gl_create_window_shader(backend_t *backend_data, const char *source);
void gl_destroy_window_shader(backend_t *backend_data, void *shader);
/**
* @brief Render a region with texture data.
*/
void gl_compose(backend_t *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt,
const region_t *reg_visible);
void gl_compose(backend_t *, void *image_data, int dst_x, int dst_y,
const region_t *reg_tgt, const region_t *reg_visible);
void gl_resize(struct gl_data *, int width, int height);

View File

@ -547,6 +547,8 @@ struct backend_operations glx_ops = {
.get_blur_size = gl_get_blur_size,
.diagnostics = glx_diagnostics,
.device_status = gl_device_status,
.create_shader = gl_create_window_shader,
.destroy_shader = gl_destroy_window_shader,
.max_buffer_age = 5, // Why?
};