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 <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-03-09 14:12:53 +00:00
parent 6ff0facae6
commit 0a2dd8aa72
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
3 changed files with 48 additions and 40 deletions

View File

@ -39,6 +39,8 @@
} \ } \
while (0) while (0)
#define GLSL(version, ...) "#version " #version "\n" #__VA_ARGS__
GLuint gl_create_shader(GLenum shader_type, const char *shader_str) { GLuint gl_create_shader(GLenum shader_type, const char *shader_str) {
log_trace("===\n%s\n===", 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; 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 #if 0
/** /**
* Blur contents in a particular region. * 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. * Load a GLSL main program from shader strings.
*/ */
int gl_win_shader_from_string(session_t *ps, const char *vshader_str, static int gl_win_shader_from_string(const char *vshader_str, const char *fshader_str,
const char *fshader_str, gl_win_shader_t *ret) { gl_win_shader_t *ret) {
// Build program // Build program
ret->prog = gl_create_program_from_str(vshader_str, fshader_str); ret->prog = gl_create_program_from_str(vshader_str, fshader_str);
if (!ret->prog) { if (!ret->prog) {
@ -798,6 +784,22 @@ err:
} }
#endif #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) { bool gl_init(struct gl_data *gd, session_t *ps) {
// Initialize GLX data structure // Initialize GLX data structure
for (int i = 0; i < MAX_BLUR_PASS; ++i) { 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 // Initialize blur filters
// gl_create_blur_filters(ps, gd->blur_shader, &gd->cap); // gl_create_blur_filters(ps, gd->blur_shader, &gd->cap);
gl_win_shader_from_string(NULL, win_shader_glsl, &gd->win_shader);
return true; return true;
} }
@ -881,6 +884,7 @@ GLuint gl_new_texture(GLenum target) {
return 0; return 0;
} }
glEnable(target);
glBindTexture(target, texture); glBindTexture(target, texture);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_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 /// stub for backend_operations::image_op
bool gl_image_op(backend_t *base, enum image_operations op, void *image_data, 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) { 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; 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) { bool gl_is_image_transparent(backend_t *base, void *image_data) {
gl_texture_t *img = image_data; gl_texture_t *img = image_data;
return img->has_alpha; return img->has_alpha;

View File

@ -43,7 +43,7 @@ typedef struct {
/// @brief Wrapper of a binded GLX texture. /// @brief Wrapper of a binded GLX texture.
typedef struct gl_texture { typedef struct gl_texture {
double opacity; double opacity;
int refcount; int *refcount;
GLuint texture; GLuint texture;
GLenum target; GLenum target;
unsigned width; 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, void gl_compose(backend_t *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt,
const region_t *reg_visible); 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); 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); 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, 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); 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, bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
const region_t *reg_visible); const region_t *reg_visible);

View File

@ -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) { void glx_release_image(backend_t *base, void *image_data) {
struct _glx_image_data *wd = image_data; struct _glx_image_data *wd = image_data;
struct _glx_data *gd = (void *)base; struct _glx_data *gd = (void *)base;
wd->texture.refcount--; (*wd->texture.refcount)--;
if (wd->texture.refcount != 0) { if (*wd->texture.refcount != 0) {
return; return;
} }
// Release binding // Release binding
@ -300,8 +300,8 @@ end:
return &gd->gl.base; return &gd->gl.base;
} }
static void *glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, static void *
struct xvisual_info fmt, bool owned) { glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
struct _glx_data *gd = (void *)base; struct _glx_data *gd = (void *)base;
// Retrieve pixmap parameters, if they aren't provided // Retrieve pixmap parameters, if they aren't provided
if (fmt.visual_depth > OPENGL_MAX_DEPTH) { 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.depth = fmt.visual_depth;
wd->texture.color_inverted = false; wd->texture.color_inverted = false;
wd->texture.has_alpha = fmt.alpha_size != 0; 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); glBindTexture(wd->texture.target, wd->texture.texture);
glXBindTexImageEXT(gd->display, wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL); glXBindTexImageEXT(gd->display, wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
glBindTexture(wd->texture.target, 0); glBindTexture(wd->texture.target, 0);
@ -404,6 +405,14 @@ static int glx_buffer_age(backend_t *base) {
return (int)val ?: -1; 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 = { struct backend_operations glx_ops = {
.init = glx_init, .init = glx_init,
.deinit = glx_deinit, .deinit = glx_deinit,
@ -411,7 +420,7 @@ struct backend_operations glx_ops = {
.release_image = glx_release_image, .release_image = glx_release_image,
.compose = gl_compose, .compose = gl_compose,
.image_op = gl_image_op, .image_op = gl_image_op,
.copy = gl_copy, .copy = glx_copy,
.blur = gl_blur, .blur = gl_blur,
.is_image_transparent = gl_is_image_transparent, .is_image_transparent = gl_is_image_transparent,
.present = glx_present, .present = glx_present,