From 0a2dd8aa72713c84bba9af527be76179263eab83 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 9 Mar 2019 14:12:53 +0000 Subject: [PATCH] gl_common: implement image_op Implement image processing in gl_compose using a frag shader. gl_image_op is used to set flags corresponds to what processing is needed for a texture. Also implement proper reference counting for textures. Signed-off-by: Yuxuan Shui --- src/backend/gl/gl_common.c | 56 +++++++++++++++++++++----------------- src/backend/gl/gl_common.h | 9 +----- src/backend/gl/glx.c | 23 +++++++++++----- 3 files changed, 48 insertions(+), 40 deletions(-) diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index 2da8acd..7ff1a28 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -39,6 +39,8 @@ } \ while (0) +#define GLSL(version, ...) "#version " #version "\n" #__VA_ARGS__ + GLuint gl_create_shader(GLenum shader_type, const char *shader_str) { log_trace("===\n%s\n===", shader_str); @@ -366,22 +368,6 @@ bool gl_dim_reg(session_t *ps, int dx, int dy, int width, int height, float z, return true; } -static inline int gl_gen_texture(GLenum tex_tgt, int width, int height, GLuint *tex) { - glGenTextures(1, tex); - if (!*tex) - return -1; - glEnable(tex_tgt); - glBindTexture(tex_tgt, *tex); - glTexParameteri(tex_tgt, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex_tgt, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(tex_tgt, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindTexture(tex_tgt, 0); - - return 0; -} - #if 0 /** * Blur contents in a particular region. @@ -606,8 +592,8 @@ GLuint glGetUniformLocationChecked(GLuint p, const char *name) { /** * Load a GLSL main program from shader strings. */ -int gl_win_shader_from_string(session_t *ps, const char *vshader_str, - const char *fshader_str, gl_win_shader_t *ret) { +static int gl_win_shader_from_string(const char *vshader_str, const char *fshader_str, + gl_win_shader_t *ret) { // Build program ret->prog = gl_create_program_from_str(vshader_str, fshader_str); if (!ret->prog) { @@ -798,6 +784,22 @@ err: } #endif +// clang-format off +const char *win_shader_glsl = GLSL(110, + uniform float opacity; + uniform bool invert_color; + uniform sampler2D tex; + + void main() { + vec4 c = texture2D(tex, gl_TexCoord[0].xy); + if (invert_color) + c = vec4(c.aaa - c.rgb, c.a); + c *= opacity; + gl_FragColor = c; + } +); +// clang-format on + bool gl_init(struct gl_data *gd, session_t *ps) { // Initialize GLX data structure for (int i = 0; i < MAX_BLUR_PASS; ++i) { @@ -846,6 +848,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) { // Initialize blur filters // gl_create_blur_filters(ps, gd->blur_shader, &gd->cap); + gl_win_shader_from_string(NULL, win_shader_glsl, &gd->win_shader); return true; } @@ -881,6 +884,7 @@ GLuint gl_new_texture(GLenum target) { return 0; } + glEnable(target); glBindTexture(target, texture); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -894,16 +898,18 @@ GLuint gl_new_texture(GLenum target) { /// stub for backend_operations::image_op bool gl_image_op(backend_t *base, enum image_operations op, void *image_data, const region_t *reg_op, const region_t *reg_visible, void *arg) { + struct gl_texture *tex = image_data; + switch (op) { + case IMAGE_OP_INVERT_COLOR_ALL: tex->color_inverted = true; break; + case IMAGE_OP_DIM_ALL: log_warn("IMAGE_OP_DIM_ALL not implemented yet"); break; + case IMAGE_OP_APPLY_ALPHA_ALL: tex->opacity *= *(double *)arg; break; + case IMAGE_OP_APPLY_ALPHA: + log_warn("IMAGE_OP_APPLY_ALPHA not implemented yet"); + break; + } return true; } -/// stub for backend_operations::copy -void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visible) { - struct gl_texture *t = (void *)image_data; - t->refcount++; - return (void *)image_data; -} - bool gl_is_image_transparent(backend_t *base, void *image_data) { gl_texture_t *img = image_data; return img->has_alpha; diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index 24e5365..78a5309 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -43,7 +43,7 @@ typedef struct { /// @brief Wrapper of a binded GLX texture. typedef struct gl_texture { double opacity; - int refcount; + int *refcount; GLuint texture; GLenum target; unsigned width; @@ -89,12 +89,7 @@ GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_ void gl_compose(backend_t *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt, const region_t *reg_visible); -bool gl_load_prog_main(session_t *ps, const char *vshader_str, const char *fshader_str, - gl_win_shader_t *pprogram); - -unsigned char *gl_take_screenshot(session_t *ps, int *out_length); void gl_resize(struct gl_data *, int width, int height); -//bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_cap_t *cap); GLuint glGetUniformLocationChecked(GLuint p, const char *name); @@ -106,8 +101,6 @@ GLuint gl_new_texture(GLenum target); bool gl_image_op(backend_t *base, enum image_operations op, void *image_data, const region_t *reg_op, const region_t *reg_visible, void *arg); -void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visible); - bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur, const region_t *reg_visible); diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index c371021..98ef127 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -161,8 +161,8 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi void glx_release_image(backend_t *base, void *image_data) { struct _glx_image_data *wd = image_data; struct _glx_data *gd = (void *)base; - wd->texture.refcount--; - if (wd->texture.refcount != 0) { + (*wd->texture.refcount)--; + if (*wd->texture.refcount != 0) { return; } // Release binding @@ -300,8 +300,8 @@ end: return &gd->gl.base; } -static void *glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, - struct xvisual_info fmt, bool owned) { +static void * +glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) { struct _glx_data *gd = (void *)base; // Retrieve pixmap parameters, if they aren't provided if (fmt.visual_depth > OPENGL_MAX_DEPTH) { @@ -370,7 +370,8 @@ static void *glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, wd->texture.depth = fmt.visual_depth; wd->texture.color_inverted = false; wd->texture.has_alpha = fmt.alpha_size != 0; - wd->texture.refcount = 1; + wd->texture.refcount = ccalloc(1, int); + *wd->texture.refcount = 1; glBindTexture(wd->texture.target, wd->texture.texture); glXBindTexImageEXT(gd->display, wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL); glBindTexture(wd->texture.target, 0); @@ -404,6 +405,14 @@ static int glx_buffer_age(backend_t *base) { return (int)val ?: -1; } +static void *glx_copy(backend_t *base, const void *image_data, const region_t *reg_visible) { + const struct _glx_image_data *img = image_data; + auto new_img = ccalloc(1, struct _glx_image_data); + *new_img = *img; + (*new_img->texture.refcount)++; + return new_img; +} + struct backend_operations glx_ops = { .init = glx_init, .deinit = glx_deinit, @@ -411,13 +420,13 @@ struct backend_operations glx_ops = { .release_image = glx_release_image, .compose = gl_compose, .image_op = gl_image_op, - .copy = gl_copy, + .copy = glx_copy, .blur = gl_blur, .is_image_transparent = gl_is_image_transparent, .present = glx_present, .buffer_age = glx_buffer_age, .render_shadow = default_backend_render_shadow, - .max_buffer_age = 5, // Why? + .max_buffer_age = 5, // Why? }; /**