picom/src/backend/gl/gl_common.h

281 lines
9.0 KiB
C

// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <epoxy/gl.h>
#include <stdbool.h>
#include <string.h>
#include <xcb/xproto.h>
#include "backend/backend.h"
#include "backend/backend_common.h"
#include "log.h"
#include "region.h"
#define CASESTRRET(s) \
case s: return #s
struct gl_blur_context;
static inline GLint glGetUniformLocationChecked(GLuint p, const char *name) {
auto ret = glGetUniformLocation(p, name);
if (ret < 0) {
log_info("Failed to get location of uniform '%s'. This is normal when "
"using custom shaders.",
name);
}
return ret;
}
#define bind_uniform(shader, uniform) \
(shader)->uniform_##uniform = glGetUniformLocationChecked((shader)->prog, #uniform)
// Program and uniforms for window shader
typedef struct {
GLuint prog;
GLint uniform_opacity;
GLint uniform_invert_color;
GLint uniform_tex;
GLint uniform_effective_size;
GLint uniform_dim;
GLint uniform_brightness;
GLint uniform_max_brightness;
GLint uniform_corner_radius;
GLint uniform_border_width;
GLint uniform_time;
GLint uniform_mask_tex;
GLint uniform_mask_offset;
GLint uniform_mask_corner_radius;
GLint uniform_mask_inverted;
} gl_win_shader_t;
// Program and uniforms for brightness shader
typedef struct {
GLuint prog;
} gl_brightness_shader_t;
typedef struct {
GLuint prog;
GLint uniform_color;
} gl_shadow_shader_t;
// Program and uniforms for blur shader
typedef struct {
GLuint prog;
GLint uniform_pixel_norm;
GLint uniform_opacity;
GLint texorig_loc;
GLint scale_loc;
GLint uniform_mask_tex;
GLint uniform_mask_offset;
GLint uniform_mask_corner_radius;
GLint uniform_mask_inverted;
} gl_blur_shader_t;
typedef struct {
GLuint prog;
GLint color_loc;
} gl_fill_shader_t;
/// @brief Wrapper of a bound GL texture.
struct gl_texture {
int refcount;
bool has_alpha;
GLuint texture;
int width, height;
bool y_inverted;
xcb_pixmap_t pixmap;
// Textures for auxiliary uses.
GLuint auxiliary_texture[2];
const gl_win_shader_t *shader;
void *user_data;
};
struct gl_data {
backend_t base;
// If we are using proprietary NVIDIA driver
bool is_nvidia;
// If ARB_robustness extension is present
bool has_robustness;
// If EXT_EGL_image_storage extension is present
bool has_egl_image_storage;
// Height and width of the root window
int height, width;
// Hash-table of window shaders
gl_win_shader_t *default_shader;
gl_brightness_shader_t brightness_shader;
gl_fill_shader_t fill_shader;
gl_shadow_shader_t shadow_shader;
GLuint back_texture, back_fbo;
GLint back_format;
GLuint frame_timing[2];
int current_frame_timing;
GLuint present_prog;
GLuint dummy_prog;
bool dithered_present;
GLuint default_mask_texture;
/// Called when an gl_texture is decoupled from the texture it refers. Returns
/// the decoupled user_data
void *(*decouple_texture_user_data)(backend_t *base, void *user_data);
/// Release the user data attached to a gl_texture
void (*release_user_data)(backend_t *base, struct gl_texture *);
struct log_target *logger;
};
typedef struct session session_t;
#define GL_PROG_MAIN_INIT \
{ .prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, .unifm_tex = -1, }
void gl_prepare(backend_t *base, const region_t *reg);
void x_rect_to_coords(int nrects, const rect_t *rects, coord_t image_dst,
int extent_height, int texture_height, int root_height,
bool y_inverted, GLint *coord, GLuint *indices);
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);
GLuint gl_create_program_from_strv(const char **vert_shaders, const char **frag_shaders);
void *gl_create_window_shader(backend_t *backend_data, const char *source);
void gl_destroy_window_shader(backend_t *backend_data, void *shader);
uint64_t gl_get_shader_attributes(backend_t *backend_data, void *shader);
bool gl_set_image_property(backend_t *backend_data, enum image_properties prop,
image_handle image, const void *args);
bool gl_last_render_time(backend_t *backend_data, struct timespec *time);
/**
* @brief Render a region with texture data.
*/
void gl_compose(backend_t *, image_handle image, coord_t image_dst, image_handle mask,
coord_t mask_dst, const region_t *reg_tgt, const region_t *reg_visible);
void gl_root_change(backend_t *base, session_t *);
void gl_resize(struct gl_data *, int width, int height);
bool gl_init(struct gl_data *gd, session_t *);
void gl_deinit(struct gl_data *gd);
GLuint gl_new_texture(GLenum target);
bool gl_image_op(backend_t *base, enum image_operations op, image_handle image,
const region_t *reg_op, const region_t *reg_visible, void *arg);
xcb_pixmap_t gl_release_image(backend_t *base, image_handle image);
image_handle gl_make_mask(backend_t *base, geometry_t size, const region_t *reg);
image_handle gl_clone(backend_t *base, image_handle image, const region_t *reg_visible);
bool gl_blur(backend_t *base, double opacity, void *ctx, image_handle mask,
coord_t mask_dst, const region_t *reg_blur, const region_t *reg_visible);
bool gl_blur_impl(double opacity, struct gl_blur_context *bctx,
struct backend_image *mask, coord_t mask_dst, const region_t *reg_blur,
const region_t *reg_visible attr_unused, GLuint source_texture,
geometry_t source_size, GLuint target_fbo, GLuint default_mask,
bool high_precision);
void *gl_create_blur_context(backend_t *base, enum blur_method, void *args);
void gl_destroy_blur_context(backend_t *base, void *ctx);
struct backend_shadow_context *gl_create_shadow_context(backend_t *base, double radius);
void gl_destroy_shadow_context(backend_t *base attr_unused, struct backend_shadow_context *ctx);
image_handle gl_shadow_from_mask(backend_t *base, image_handle mask,
struct backend_shadow_context *sctx, struct color color);
void gl_get_blur_size(void *blur_context, int *width, int *height);
void gl_fill(backend_t *base, struct color, const region_t *clip);
void gl_present(backend_t *base, const region_t *);
enum device_status gl_device_status(backend_t *base);
/**
* Get a textual representation of an OpenGL error.
*/
static inline const char *gl_get_err_str(GLenum err) {
switch (err) {
CASESTRRET(GL_NO_ERROR);
CASESTRRET(GL_INVALID_ENUM);
CASESTRRET(GL_INVALID_VALUE);
CASESTRRET(GL_INVALID_OPERATION);
CASESTRRET(GL_INVALID_FRAMEBUFFER_OPERATION);
CASESTRRET(GL_OUT_OF_MEMORY);
CASESTRRET(GL_STACK_UNDERFLOW);
CASESTRRET(GL_STACK_OVERFLOW);
CASESTRRET(GL_FRAMEBUFFER_UNDEFINED);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER);
CASESTRRET(GL_FRAMEBUFFER_UNSUPPORTED);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS);
}
return NULL;
}
/**
* Check for GL error.
*
* http://blog.nobel-joergensen.com/2013/01/29/debugging-opengl-using-glgeterror/
*/
static inline void gl_check_err_(const char *func, int line) {
GLenum err = GL_NO_ERROR;
while (GL_NO_ERROR != (err = glGetError())) {
const char *errtext = gl_get_err_str(err);
if (errtext) {
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
"GL error at line %d: %s", line, errtext);
} else {
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
"GL error at line %d: %d", line, err);
}
}
}
static inline void gl_clear_err(void) {
while (glGetError() != GL_NO_ERROR)
;
}
#define gl_check_err() gl_check_err_(__func__, __LINE__)
/**
* Check for GL framebuffer completeness.
*/
static inline bool gl_check_fb_complete_(const char *func, int line, GLenum fb) {
GLenum status = glCheckFramebufferStatus(fb);
if (status == GL_FRAMEBUFFER_COMPLETE) {
return true;
}
const char *stattext = gl_get_err_str(status);
if (stattext) {
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
"Framebuffer attachment failed at line %d: %s", line, stattext);
} else {
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
"Framebuffer attachment failed at line %d: %d", line, status);
}
return false;
}
#define gl_check_fb_complete(fb) gl_check_fb_complete_(__func__, __LINE__, (fb))
static const GLuint vert_coord_loc = 0;
static const GLuint vert_in_texcoord_loc = 1;
#define GLSL(version, ...) "#version " #version "\n" #__VA_ARGS__
#define QUOTE(...) #__VA_ARGS__
extern const char vertex_shader[], blend_with_mask_frag[], masking_glsl[], dummy_frag[],
present_frag[], fill_frag[], fill_vert[], interpolating_frag[], interpolating_vert[],
win_shader_glsl[], win_shader_default[], present_vertex_shader[], dither_glsl[],
shadow_colorization_frag[];