mirror of https://github.com/yshui/picom.git
ackend: gl: implement shadow_from_mask
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
9ac046c2ba
commit
a29caeaf3d
|
@ -379,10 +379,10 @@ bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask,
|
|||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(4, bo);
|
||||
|
|
|
@ -881,6 +881,17 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
|||
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||
glUseProgram(0);
|
||||
|
||||
gd->shadow_shader.prog =
|
||||
gl_create_program_from_str(present_vertex_shader, shadow_colorization_frag);
|
||||
gd->shadow_shader.uniform_color =
|
||||
glGetUniformLocationChecked(gd->shadow_shader.prog, "color");
|
||||
pml = glGetUniformLocationChecked(gd->shadow_shader.prog, "projection");
|
||||
glUseProgram(gd->shadow_shader.prog);
|
||||
glUniform1i(glGetUniformLocationChecked(gd->shadow_shader.prog, "tex"), 0);
|
||||
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||
glUseProgram(0);
|
||||
glBindFragDataLocation(gd->shadow_shader.prog, 0, "out_color");
|
||||
|
||||
gd->brightness_shader.prog =
|
||||
gl_create_program_from_str(interpolating_vert, interpolating_frag);
|
||||
if (!gd->brightness_shader.prog) {
|
||||
|
@ -919,6 +930,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
|||
gd->is_nvidia = false;
|
||||
}
|
||||
gd->has_robustness = gl_has_extension("GL_ARB_robustness");
|
||||
gl_check_err();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1150,6 +1162,163 @@ bool gl_set_image_property(backend_t *backend_data, enum image_properties prop,
|
|||
return true;
|
||||
}
|
||||
|
||||
struct gl_shadow_context {
|
||||
double radius;
|
||||
void *blur_context;
|
||||
};
|
||||
|
||||
struct backend_shadow_context *gl_create_shadow_context(backend_t *base, double radius) {
|
||||
auto ctx = ccalloc(1, struct gl_shadow_context);
|
||||
ctx->radius = radius;
|
||||
|
||||
struct dual_kawase_blur_args args = {
|
||||
.size = (int)radius,
|
||||
.strength = 0,
|
||||
};
|
||||
ctx->blur_context = gl_create_blur_context(base, BLUR_METHOD_DUAL_KAWASE, &args);
|
||||
return (struct backend_shadow_context *)ctx;
|
||||
}
|
||||
|
||||
void gl_destroy_shadow_context(backend_t *base attr_unused, struct backend_shadow_context *ctx) {
|
||||
auto ctx_ = (struct gl_shadow_context *)ctx;
|
||||
gl_destroy_blur_context(base, (struct backend_blur_context *)ctx_->blur_context);
|
||||
free(ctx_);
|
||||
}
|
||||
|
||||
void *gl_shadow_from_mask(backend_t *base, void *mask,
|
||||
struct backend_shadow_context *sctx, struct color color) {
|
||||
log_debug("Create shadow from mask");
|
||||
auto gd = (struct gl_data *)base;
|
||||
auto img = (struct backend_image *)mask;
|
||||
auto inner = (struct gl_texture *)img->inner;
|
||||
auto gsctx = (struct gl_shadow_context *)sctx;
|
||||
int radius = (int)gsctx->radius;
|
||||
|
||||
auto new_inner = ccalloc(1, struct gl_texture);
|
||||
new_inner->width = inner->width + radius * 2;
|
||||
new_inner->height = inner->height + radius * 2;
|
||||
new_inner->texture = gl_new_texture(GL_TEXTURE_2D);
|
||||
new_inner->has_alpha = inner->has_alpha;
|
||||
new_inner->y_inverted = false;
|
||||
auto new_img = default_new_backend_image(new_inner->width, new_inner->height);
|
||||
new_img->inner = (struct backend_image_inner_base *)new_inner;
|
||||
new_img->inner->refcount = 1;
|
||||
|
||||
// Render the mask to a texture, so inversion and corner radius can be
|
||||
// applied.
|
||||
auto source_texture = gl_new_texture(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, source_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, new_inner->width, new_inner->height, 0,
|
||||
GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
source_texture, 0);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
if (img->color_inverted) {
|
||||
// If the mask is inverted, clear the source_texture to white, so the
|
||||
// "outside" of the mask would be correct
|
||||
glClearColor(1, 1, 1, 1);
|
||||
} else {
|
||||
glClearColor(0, 0, 0, 1);
|
||||
}
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
{
|
||||
// clang-format off
|
||||
// interleaved vertex coordinates and texture coordinates
|
||||
GLint coords[] = {radius , radius , 0 , 0,
|
||||
radius + inner->width, radius , inner->width, 0,
|
||||
radius + inner->width, radius + inner->height, inner->width, inner->height,
|
||||
radius , radius + inner->height, 0 , inner->height,};
|
||||
// clang-format on
|
||||
GLuint indices[] = {0, 1, 2, 2, 3, 0};
|
||||
_gl_compose(base, mask, fbo, NULL, (coord_t){0}, coords, indices, 1);
|
||||
}
|
||||
|
||||
gl_check_err();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
auto tmp_texture = gl_new_texture(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, tmp_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, new_inner->width, new_inner->height, 0,
|
||||
GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
tmp_texture, 0);
|
||||
|
||||
region_t reg_blur;
|
||||
pixman_region32_init_rect(®_blur, 0, 0, (unsigned int)new_inner->width,
|
||||
(unsigned int)new_inner->height);
|
||||
// gl_blur expects reg_blur to be in X coordinate system (i.e. y flipped), but we
|
||||
// are covering the whole texture so we don't need to worry about that.
|
||||
gl_blur_impl(1.0, gsctx->blur_context, NULL, (coord_t){0}, ®_blur, NULL,
|
||||
source_texture,
|
||||
(geometry_t){.width = new_inner->width, .height = new_inner->height},
|
||||
fbo, gd->default_mask_texture);
|
||||
pixman_region32_fini(®_blur);
|
||||
|
||||
// Colorize the shadow with color.
|
||||
log_debug("Colorize shadow");
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, new_inner->texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, new_inner->width, new_inner->height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
new_inner->texture, 0);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tmp_texture);
|
||||
glUseProgram(gd->shadow_shader.prog);
|
||||
glUniform4f(gd->shadow_shader.uniform_color, (GLfloat)color.red,
|
||||
(GLfloat)color.green, (GLfloat)color.blue, (GLfloat)color.alpha);
|
||||
|
||||
// clang-format off
|
||||
GLuint indices[] = {0, 1, 2, 2, 3, 0};
|
||||
GLint coord[] = {0 , 0 ,
|
||||
new_inner->width , 0 ,
|
||||
new_inner->width , new_inner->height,
|
||||
0 , new_inner->height,};
|
||||
// clang-format on
|
||||
|
||||
GLuint vao;
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
GLuint bo[2];
|
||||
glGenBuffers(2, bo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, bo[0]);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]);
|
||||
glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 8, coord, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * 6, indices,
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(vert_coord_loc);
|
||||
glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 2, NULL);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
glDisableVertexAttribArray(vert_coord_loc);
|
||||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(2, bo);
|
||||
|
||||
glDeleteTextures(1, (GLuint[]){source_texture, tmp_texture});
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
gl_check_err();
|
||||
return new_img;
|
||||
}
|
||||
|
||||
enum device_status gl_device_status(backend_t *base) {
|
||||
auto gd = (struct gl_data *)base;
|
||||
if (!gd->has_robustness) {
|
||||
|
|
|
@ -53,6 +53,11 @@ 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;
|
||||
|
@ -98,6 +103,7 @@ struct gl_data {
|
|||
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;
|
||||
GLuint present_prog;
|
||||
|
||||
|
@ -155,8 +161,16 @@ void *gl_clone(backend_t *base, const void *image_data, const region_t *reg_visi
|
|||
|
||||
bool gl_blur(backend_t *base, double opacity, void *ctx, void *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, void *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);
|
||||
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);
|
||||
void *gl_shadow_from_mask(backend_t *base, void *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);
|
||||
|
@ -272,5 +286,5 @@ static const GLuint vert_in_texcoord_loc = 1;
|
|||
#define QUOTE(...) #__VA_ARGS__
|
||||
|
||||
extern const char vertex_shader[], copy_with_mask_frag[], masking_glsl[], dummy_frag[],
|
||||
fill_frag[], fill_vert[], interpolating_frag[], interpolating_vert[],
|
||||
win_shader_glsl[], win_shader_default[], present_vertex_shader[];
|
||||
fill_frag[], fill_vert[], interpolating_frag[], interpolating_vert[], win_shader_glsl[],
|
||||
win_shader_default[], present_vertex_shader[], shadow_colorization_frag[];
|
||||
|
|
|
@ -536,9 +536,10 @@ struct backend_operations glx_ops = {
|
|||
.is_image_transparent = default_is_image_transparent,
|
||||
.present = glx_present,
|
||||
.buffer_age = glx_buffer_age,
|
||||
.create_shadow_context = default_create_shadow_context,
|
||||
.destroy_shadow_context = default_destroy_shadow_context,
|
||||
.render_shadow = default_backend_render_shadow,
|
||||
.create_shadow_context = gl_create_shadow_context,
|
||||
.destroy_shadow_context = gl_destroy_shadow_context,
|
||||
.render_shadow = backend_render_shadow_from_mask,
|
||||
.shadow_from_mask = gl_shadow_from_mask,
|
||||
.make_mask = gl_make_mask,
|
||||
.fill = gl_fill,
|
||||
.create_blur_context = gl_create_blur_context,
|
||||
|
|
|
@ -174,4 +174,14 @@ const char vertex_shader[] = GLSL(330,
|
|||
texcoord = in_texcoord + texorig;
|
||||
}
|
||||
);
|
||||
const char shadow_colorization_frag[] = GLSL(330,
|
||||
uniform vec4 color;
|
||||
uniform sampler2D tex;
|
||||
in vec2 texcoord;
|
||||
out vec4 out_color;
|
||||
void main() {
|
||||
vec4 c = texelFetch(tex, ivec2(texcoord), 0);
|
||||
out_color = c.r * color;
|
||||
}
|
||||
);
|
||||
// clang-format on
|
||||
|
|
Loading…
Reference in New Issue