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:
parent
6ff0facae6
commit
0a2dd8aa72
|
@ -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,14 +898,16 @@ 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) {
|
||||||
return true;
|
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) {
|
bool gl_is_image_transparent(backend_t *base, void *image_data) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue