mirror of https://github.com/yshui/picom.git
backend: gl: implement create_shader/destroy_shader
This commit is contained in:
parent
947077f329
commit
81768f4a11
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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?
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue