Merge pull request #247 from Jauler/dim_bright_windows
Brightness clamping
This commit is contained in:
commit
c98e7fa39f
|
@ -39,6 +39,8 @@ blur-background-exclude = [
|
||||||
];
|
];
|
||||||
# opacity-rule = [ "80:class_g = 'URxvt'" ];
|
# opacity-rule = [ "80:class_g = 'URxvt'" ];
|
||||||
|
|
||||||
|
# max-brightness = 0.66
|
||||||
|
|
||||||
# Fading
|
# Fading
|
||||||
fading = true;
|
fading = true;
|
||||||
# fade-delta = 30;
|
# fade-delta = 30;
|
||||||
|
|
|
@ -251,6 +251,13 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
pixman_region32_fini(®_shadow);
|
pixman_region32_fini(®_shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set max brightness
|
||||||
|
if (ps->o.max_brightness < 1.0) {
|
||||||
|
ps->backend_data->ops->image_op(
|
||||||
|
ps->backend_data, IMAGE_OP_MAX_BRIGHTNESS, w->win_image,
|
||||||
|
NULL, ®_visible, &ps->o.max_brightness);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw window on target
|
// Draw window on target
|
||||||
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
|
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
|
||||||
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
|
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
|
||||||
|
|
|
@ -47,6 +47,8 @@ enum image_operations {
|
||||||
// effective size. `reg_op` and `reg_visible` is ignored. `arg` is two integers,
|
// effective size. `reg_op` and `reg_visible` is ignored. `arg` is two integers,
|
||||||
// width and height, in that order.
|
// width and height, in that order.
|
||||||
IMAGE_OP_RESIZE_TILE,
|
IMAGE_OP_RESIZE_TILE,
|
||||||
|
// Limit how bright image can be
|
||||||
|
IMAGE_OP_MAX_BRIGHTNESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gaussian_blur_args {
|
struct gaussian_blur_args {
|
||||||
|
|
|
@ -183,6 +183,165 @@ static void gl_free_prog_main(gl_win_shader_t *pprogram) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Implements recursive part of gl_average_texture_color.
|
||||||
|
*
|
||||||
|
* @note In order to reduce number of textures which needs to be
|
||||||
|
* allocated and deleted during this recursive render
|
||||||
|
* we reuse the same two textures for render source and
|
||||||
|
* destination simply by alterating between them.
|
||||||
|
* Unfortunately on first iteration source_texture might
|
||||||
|
* be read-only. In this case we will select auxilary_texture as
|
||||||
|
* destination_texture in order not to touch that read-only source
|
||||||
|
* texture in following render iteration.
|
||||||
|
* Otherwise we simply will switch source and destination textures
|
||||||
|
* between each other on each render iteration.
|
||||||
|
*/
|
||||||
|
static GLuint _gl_average_texture_color(backend_t *base, GLuint source_texture,
|
||||||
|
GLuint destination_texture, GLuint auxilary_texture,
|
||||||
|
GLuint fbo, int width, int height) {
|
||||||
|
const int max_width = 1;
|
||||||
|
const int max_height = 1;
|
||||||
|
const int from_width = next_power_of_two(width);
|
||||||
|
const int from_height = next_power_of_two(height);
|
||||||
|
const int to_width = from_width > max_width ? from_width / 2 : from_width;
|
||||||
|
const int to_height = from_height > max_height ? from_height / 2 : from_height;
|
||||||
|
|
||||||
|
// Prepare coordinates
|
||||||
|
GLint coord[] = {
|
||||||
|
// top left
|
||||||
|
0, 0, // vertex coord
|
||||||
|
0, 0, // texture coord
|
||||||
|
|
||||||
|
// top right
|
||||||
|
to_width, 0, // vertex coord
|
||||||
|
1, 0, // texture coord
|
||||||
|
|
||||||
|
// bottom right
|
||||||
|
to_width, to_height, // vertex coord
|
||||||
|
1, 1, // texture coord
|
||||||
|
|
||||||
|
// bottom left
|
||||||
|
0, to_height, // vertex coord
|
||||||
|
0, 1, // texture coord
|
||||||
|
};
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, (long)sizeof(*coord) * 16, coord);
|
||||||
|
|
||||||
|
// Prepare framebuffer for new render iteration
|
||||||
|
glBindTexture(GL_TEXTURE_2D, destination_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, to_width, to_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destination_texture, 0);
|
||||||
|
|
||||||
|
// Bind source texture as downscaling shader uniform input
|
||||||
|
glBindTexture(GL_TEXTURE_2D, source_texture);
|
||||||
|
|
||||||
|
// Render into framebuffer
|
||||||
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
|
||||||
|
|
||||||
|
// Have we downscaled enough?
|
||||||
|
GLuint result;
|
||||||
|
if (to_width > max_width || to_height > max_height) {
|
||||||
|
GLuint new_source_texture = destination_texture;
|
||||||
|
GLuint new_destination_texture = auxilary_texture != 0 ? auxilary_texture : source_texture;
|
||||||
|
result = _gl_average_texture_color(base, new_source_texture,
|
||||||
|
new_destination_texture, 0,
|
||||||
|
fbo, to_width, to_height);
|
||||||
|
} else {
|
||||||
|
result = destination_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Builds a 1x1 texture which has color corresponding to the average of all
|
||||||
|
* pixels of img by recursively rendering into texture of quorter the size (half
|
||||||
|
* width and half height).
|
||||||
|
* Returned texture must be deleted by the caller (use glDeleteTextures).
|
||||||
|
*/
|
||||||
|
static GLuint gl_average_texture_color(backend_t *base, struct gl_image *img) {
|
||||||
|
|
||||||
|
struct gl_data *gd = (void *)base;
|
||||||
|
|
||||||
|
// Prepare textures which will be used for destination and source of rendering
|
||||||
|
// during downscaling.
|
||||||
|
GLuint textures[2] = {0};
|
||||||
|
const int texture_count = sizeof(textures)/sizeof(textures[0]);
|
||||||
|
glGenTextures(texture_count, textures);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
for (int i = 0; i < texture_count; i++) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, (GLint []){0, 0, 0, 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare framebuffer used for rendering and bind it
|
||||||
|
GLuint fbo;
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||||
|
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
|
|
||||||
|
// Enable shaders
|
||||||
|
glUseProgram(gd->brightness_shader.prog);
|
||||||
|
|
||||||
|
// Prepare vertex attributes
|
||||||
|
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]);
|
||||||
|
glEnableVertexAttribArray(vert_coord_loc);
|
||||||
|
glEnableVertexAttribArray(vert_in_texcoord_loc);
|
||||||
|
glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE,
|
||||||
|
sizeof(GLint) * 4, NULL);
|
||||||
|
glVertexAttribPointer(vert_in_texcoord_loc, 2, GL_INT, GL_FALSE,
|
||||||
|
sizeof(GLint) * 4, (void *)(sizeof(GLint) * 2));
|
||||||
|
|
||||||
|
// Allocate buffers for render input
|
||||||
|
GLint coord[16] = {0};
|
||||||
|
GLuint indices[] = {0, 1, 2, 2, 3, 0};
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 16, coord, GL_DYNAMIC_DRAW);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * 6, indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Do actual recursive render to 1x1 texture
|
||||||
|
GLuint result_texture = _gl_average_texture_color(base, img->inner->texture,
|
||||||
|
textures[0], textures[1],
|
||||||
|
fbo, img->inner->width,
|
||||||
|
img->inner->height);
|
||||||
|
|
||||||
|
// Cleanup vertex attributes
|
||||||
|
glDisableVertexAttribArray(vert_coord_loc);
|
||||||
|
glDisableVertexAttribArray(vert_in_texcoord_loc);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
glDeleteBuffers(2, bo);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glDeleteVertexArrays(1, &vao);
|
||||||
|
|
||||||
|
// Cleanup shaders
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
|
// Cleanup framebuffers
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
glDrawBuffer(GL_BACK);
|
||||||
|
|
||||||
|
// Cleanup render textures
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
for (int i = 0; i < texture_count; i++) {
|
||||||
|
if (result_texture != textures[i])
|
||||||
|
glDeleteTextures(1, &textures[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_check_err();
|
||||||
|
|
||||||
|
return result_texture;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a region with texture data.
|
* Render a region with texture data.
|
||||||
*
|
*
|
||||||
|
@ -202,7 +361,9 @@ static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dual_texture = false;
|
GLuint brightness = 0;
|
||||||
|
if (img->max_brightness < 1.0)
|
||||||
|
brightness = gl_average_texture_color(base, img);
|
||||||
|
|
||||||
assert(gd->win_shader.prog);
|
assert(gd->win_shader.prog);
|
||||||
glUseProgram(gd->win_shader.prog);
|
glUseProgram(gd->win_shader.prog);
|
||||||
|
@ -218,17 +379,21 @@ static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target,
|
||||||
if (gd->win_shader.unifm_dim >= 0) {
|
if (gd->win_shader.unifm_dim >= 0) {
|
||||||
glUniform1f(gd->win_shader.unifm_dim, (float)img->dim);
|
glUniform1f(gd->win_shader.unifm_dim, (float)img->dim);
|
||||||
}
|
}
|
||||||
|
if (gd->win_shader.unifm_brightness >= 0) {
|
||||||
|
glUniform1i(gd->win_shader.unifm_brightness, 1);
|
||||||
|
}
|
||||||
|
if (gd->win_shader.unifm_max_brightness >= 0) {
|
||||||
|
glUniform1f(gd->win_shader.unifm_max_brightness, (float)img->max_brightness);
|
||||||
|
}
|
||||||
|
|
||||||
// log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n",
|
// log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n",
|
||||||
// x, y, width, height, dx, dy, ptex->width, ptex->height, z);
|
// x, y, width, height, dx, dy, ptex->width, ptex->height, z);
|
||||||
|
|
||||||
// Bind texture
|
// Bind texture
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, brightness);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, img->inner->texture);
|
glBindTexture(GL_TEXTURE_2D, img->inner->texture);
|
||||||
if (dual_texture) {
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, img->inner->texture);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint vao;
|
GLuint vao;
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
|
@ -259,15 +424,10 @@ static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target,
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
glDrawBuffer(GL_BACK);
|
glDrawBuffer(GL_BACK);
|
||||||
|
|
||||||
if (dual_texture) {
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
glDeleteBuffers(2, bo);
|
glDeleteBuffers(2, bo);
|
||||||
|
glDeleteTextures(1, &brightness);
|
||||||
|
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
|
||||||
|
@ -597,6 +757,8 @@ static int gl_win_shader_from_string(const char *vshader_str, const char *fshade
|
||||||
ret->unifm_invert_color = glGetUniformLocationChecked(ret->prog, "invert_color");
|
ret->unifm_invert_color = glGetUniformLocationChecked(ret->prog, "invert_color");
|
||||||
ret->unifm_tex = glGetUniformLocationChecked(ret->prog, "tex");
|
ret->unifm_tex = glGetUniformLocationChecked(ret->prog, "tex");
|
||||||
ret->unifm_dim = glGetUniformLocationChecked(ret->prog, "dim");
|
ret->unifm_dim = glGetUniformLocationChecked(ret->prog, "dim");
|
||||||
|
ret->unifm_brightness = glGetUniformLocationChecked(ret->prog, "brightness");
|
||||||
|
ret->unifm_max_brightness = glGetUniformLocationChecked(ret->prog, "max_brightness");
|
||||||
|
|
||||||
glUseProgram(ret->prog);
|
glUseProgram(ret->prog);
|
||||||
int orig_loc = glGetUniformLocation(ret->prog, "orig");
|
int orig_loc = glGetUniformLocation(ret->prog, "orig");
|
||||||
|
@ -635,6 +797,10 @@ void gl_resize(struct gl_data *gd, int width, int height) {
|
||||||
pml = glGetUniformLocationChecked(gd->present_prog, "projection");
|
pml = glGetUniformLocationChecked(gd->present_prog, "projection");
|
||||||
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||||
|
|
||||||
|
glUseProgram(gd->brightness_shader.prog);
|
||||||
|
pml = glGetUniformLocationChecked(gd->brightness_shader.prog, "projection");
|
||||||
|
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
|
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_BGR,
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_BGR,
|
||||||
GL_UNSIGNED_BYTE, NULL);
|
GL_UNSIGNED_BYTE, NULL);
|
||||||
|
@ -665,6 +831,25 @@ static const char fill_vert[] = GLSL(330,
|
||||||
gl_Position = projection * vec4(in_coord, 0, 1);
|
gl_Position = projection * vec4(in_coord, 0, 1);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static const char interpolating_frag[] = GLSL(330,
|
||||||
|
uniform sampler2D tex;
|
||||||
|
in vec2 texcoord;
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = vec4(texture2D(tex, vec2(texcoord.xy), 0).rgb, 1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
static const char interpolating_vert[] = GLSL(330,
|
||||||
|
uniform mat4 projection;
|
||||||
|
layout(location = 0) in vec2 in_coord;
|
||||||
|
layout(location = 1) in vec2 in_texcoord;
|
||||||
|
out vec2 texcoord;
|
||||||
|
void main() {
|
||||||
|
gl_Position = projection * vec4(in_coord, 0, 1);
|
||||||
|
texcoord = in_texcoord;
|
||||||
|
}
|
||||||
|
);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
/// Fill a given region in bound framebuffer.
|
/// Fill a given region in bound framebuffer.
|
||||||
|
@ -960,6 +1145,8 @@ const char *win_shader_glsl = GLSL(330,
|
||||||
uniform bool invert_color;
|
uniform bool invert_color;
|
||||||
in vec2 texcoord;
|
in vec2 texcoord;
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
uniform sampler2D brightness;
|
||||||
|
uniform float max_brightness;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 c = texelFetch(tex, ivec2(texcoord), 0);
|
vec4 c = texelFetch(tex, ivec2(texcoord), 0);
|
||||||
|
@ -967,6 +1154,12 @@ const char *win_shader_glsl = GLSL(330,
|
||||||
c = vec4(c.aaa - c.rgb, c.a);
|
c = vec4(c.aaa - c.rgb, c.a);
|
||||||
}
|
}
|
||||||
c = vec4(c.rgb * (1.0 - dim), c.a) * opacity;
|
c = vec4(c.rgb * (1.0 - dim), c.a) * opacity;
|
||||||
|
|
||||||
|
vec3 rgb_brightness = texture2D(brightness, vec2(0.5, 0.5), 0).rgb;
|
||||||
|
float brightness = (rgb_brightness[0] + rgb_brightness[1] + rgb_brightness[2]) / 3;
|
||||||
|
if (brightness > max_brightness)
|
||||||
|
c.rgb = c.rgb * (max_brightness / brightness);
|
||||||
|
|
||||||
gl_FragColor = c;
|
gl_FragColor = c;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1026,6 +1219,15 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
||||||
glUniform1i(glGetUniformLocationChecked(gd->present_prog, "tex"), 0);
|
glUniform1i(glGetUniformLocationChecked(gd->present_prog, "tex"), 0);
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
|
||||||
|
gd->brightness_shader.prog = gl_create_program_from_str(interpolating_vert, interpolating_frag);
|
||||||
|
if (!gd->brightness_shader.prog) {
|
||||||
|
log_error("Failed to create the brightness shader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glUseProgram(gd->brightness_shader.prog);
|
||||||
|
glUniform1i(glGetUniformLocationChecked(gd->brightness_shader.prog, "tex"), 0);
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
// Set up the size of the viewport. We do this last because it expects the blur
|
// Set up the size of the viewport. We do this last because it expects the blur
|
||||||
// textures are already set up.
|
// textures are already set up.
|
||||||
gl_resize(gd, ps->root_width, ps->root_height);
|
gl_resize(gd, ps->root_width, ps->root_height);
|
||||||
|
@ -1236,6 +1438,9 @@ bool gl_image_op(backend_t *base, enum image_operations op, void *image_data,
|
||||||
tex->ewidth = iargs[0];
|
tex->ewidth = iargs[0];
|
||||||
tex->eheight = iargs[1];
|
tex->eheight = iargs[1];
|
||||||
break;
|
break;
|
||||||
|
case IMAGE_OP_MAX_BRIGHTNESS:
|
||||||
|
tex->max_brightness = *(double *)arg;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,8 +20,15 @@ typedef struct {
|
||||||
GLint unifm_invert_color;
|
GLint unifm_invert_color;
|
||||||
GLint unifm_tex;
|
GLint unifm_tex;
|
||||||
GLint unifm_dim;
|
GLint unifm_dim;
|
||||||
|
GLint unifm_brightness;
|
||||||
|
GLint unifm_max_brightness;
|
||||||
} gl_win_shader_t;
|
} gl_win_shader_t;
|
||||||
|
|
||||||
|
// Program and uniforms for brightness shader
|
||||||
|
typedef struct {
|
||||||
|
GLuint prog;
|
||||||
|
} gl_brightness_shader_t;
|
||||||
|
|
||||||
// Program and uniforms for blur shader
|
// Program and uniforms for blur shader
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GLuint prog;
|
GLuint prog;
|
||||||
|
@ -48,6 +55,7 @@ typedef struct gl_image {
|
||||||
struct gl_texture *inner;
|
struct gl_texture *inner;
|
||||||
double opacity;
|
double opacity;
|
||||||
double dim;
|
double dim;
|
||||||
|
double max_brightness;
|
||||||
int ewidth, eheight;
|
int ewidth, eheight;
|
||||||
bool has_alpha;
|
bool has_alpha;
|
||||||
bool color_inverted;
|
bool color_inverted;
|
||||||
|
@ -60,6 +68,7 @@ struct gl_data {
|
||||||
// Height and width of the viewport
|
// Height and width of the viewport
|
||||||
int height, width;
|
int height, width;
|
||||||
gl_win_shader_t win_shader;
|
gl_win_shader_t win_shader;
|
||||||
|
gl_brightness_shader_t brightness_shader;
|
||||||
gl_fill_shader_t fill_shader;
|
gl_fill_shader_t fill_shader;
|
||||||
GLuint back_texture, back_fbo;
|
GLuint back_texture, back_fbo;
|
||||||
GLuint present_prog;
|
GLuint present_prog;
|
||||||
|
|
|
@ -390,6 +390,7 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
|
||||||
|
|
||||||
log_trace("Binding pixmap %#010x", pixmap);
|
log_trace("Binding pixmap %#010x", pixmap);
|
||||||
auto wd = ccalloc(1, struct gl_image);
|
auto wd = ccalloc(1, struct gl_image);
|
||||||
|
wd->max_brightness = 1;
|
||||||
wd->inner = ccalloc(1, struct gl_texture);
|
wd->inner = ccalloc(1, struct gl_texture);
|
||||||
wd->inner->width = wd->ewidth = r->width;
|
wd->inner->width = wd->ewidth = r->width;
|
||||||
wd->inner->height = wd->eheight = r->height;
|
wd->inner->height = wd->eheight = r->height;
|
||||||
|
|
|
@ -458,6 +458,7 @@ static bool image_op(backend_t *base, enum image_operations op, void *image,
|
||||||
img->eheight = iargs[1];
|
img->eheight = iargs[1];
|
||||||
break;
|
break;
|
||||||
case IMAGE_OP_APPLY_ALPHA_ALL: assert(false);
|
case IMAGE_OP_APPLY_ALPHA_ALL: assert(false);
|
||||||
|
case IMAGE_OP_MAX_BRIGHTNESS: assert(false);
|
||||||
}
|
}
|
||||||
pixman_region32_fini(®);
|
pixman_region32_fini(®);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -549,6 +549,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
||||||
.inactive_dim_fixed = false,
|
.inactive_dim_fixed = false,
|
||||||
.invert_color_list = NULL,
|
.invert_color_list = NULL,
|
||||||
.opacity_rules = NULL,
|
.opacity_rules = NULL,
|
||||||
|
.max_brightness = 1.0,
|
||||||
|
|
||||||
.use_ewmh_active_win = false,
|
.use_ewmh_active_win = false,
|
||||||
.focus_blacklist = NULL,
|
.focus_blacklist = NULL,
|
||||||
|
|
|
@ -210,6 +210,8 @@ typedef struct options {
|
||||||
c2_lptr_t *invert_color_list;
|
c2_lptr_t *invert_color_list;
|
||||||
/// Rules to change window opacity.
|
/// Rules to change window opacity.
|
||||||
c2_lptr_t *opacity_rules;
|
c2_lptr_t *opacity_rules;
|
||||||
|
/// Limit window brightness
|
||||||
|
double max_brightness;
|
||||||
|
|
||||||
// === Focus related ===
|
// === Focus related ===
|
||||||
/// Whether to try to detect WM windows and mark them as focused.
|
/// Whether to try to detect WM windows and mark them as focused.
|
||||||
|
|
|
@ -422,6 +422,13 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||||
}
|
}
|
||||||
// --use-damage
|
// --use-damage
|
||||||
lcfg_lookup_bool(&cfg, "use-damage", &opt->use_damage);
|
lcfg_lookup_bool(&cfg, "use-damage", &opt->use_damage);
|
||||||
|
|
||||||
|
// --max-brightness
|
||||||
|
if (config_lookup_float(&cfg, "max-brightness", &opt->max_brightness) && opt->use_damage) {
|
||||||
|
log_warn("max-brightness requires use-damage = false. Falling back to 1.0");
|
||||||
|
opt->max_brightness = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
// --glx-use-gpushader4
|
// --glx-use-gpushader4
|
||||||
if (config_lookup_bool(&cfg, "glx-use-gpushader4", &ival) && ival) {
|
if (config_lookup_bool(&cfg, "glx-use-gpushader4", &ival) && ival) {
|
||||||
log_warn("glx-use-gpushader4 is deprecated since v6, please remove it "
|
log_warn("glx-use-gpushader4 is deprecated since v6, please remove it "
|
||||||
|
|
|
@ -1035,6 +1035,8 @@ static bool cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
|
||||||
cdbus_m_opts_get_do(inactive_dim, cdbus_reply_double);
|
cdbus_m_opts_get_do(inactive_dim, cdbus_reply_double);
|
||||||
cdbus_m_opts_get_do(inactive_dim_fixed, cdbus_reply_bool);
|
cdbus_m_opts_get_do(inactive_dim_fixed, cdbus_reply_bool);
|
||||||
|
|
||||||
|
cdbus_m_opts_get_do(max_brightness, cdbus_reply_double);
|
||||||
|
|
||||||
cdbus_m_opts_get_do(use_ewmh_active_win, cdbus_reply_bool);
|
cdbus_m_opts_get_do(use_ewmh_active_win, cdbus_reply_bool);
|
||||||
cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool);
|
cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool);
|
||||||
cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool);
|
cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool);
|
||||||
|
|
|
@ -185,6 +185,11 @@ static void usage(const char *argv0, int ret) {
|
||||||
"--inactive-dim-fixed\n"
|
"--inactive-dim-fixed\n"
|
||||||
" Use fixed inactive dim value.\n"
|
" Use fixed inactive dim value.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"--max-brightness\n"
|
||||||
|
" Dims windows which average brightness is above this threshold.\n"
|
||||||
|
" Requires --no-use-damage.\n"
|
||||||
|
" Default: 1.0 or no dimming.\n"
|
||||||
|
"\n"
|
||||||
"--detect-transient\n"
|
"--detect-transient\n"
|
||||||
" Use WM_TRANSIENT_FOR to group windows, and consider windows in\n"
|
" Use WM_TRANSIENT_FOR to group windows, and consider windows in\n"
|
||||||
" the same group focused at the same time.\n"
|
" the same group focused at the same time.\n"
|
||||||
|
@ -410,6 +415,7 @@ static const struct option longopts[] = {
|
||||||
{"use-damage", no_argument, NULL, 323},
|
{"use-damage", no_argument, NULL, 323},
|
||||||
{"no-use-damage", no_argument, NULL, 324},
|
{"no-use-damage", no_argument, NULL, 324},
|
||||||
{"no-vsync", no_argument, NULL, 325},
|
{"no-vsync", no_argument, NULL, 325},
|
||||||
|
{"max-brightness", required_argument, NULL, 326},
|
||||||
{"experimental-backends", no_argument, NULL, 733},
|
{"experimental-backends", no_argument, NULL, 733},
|
||||||
{"monitor-repaint", no_argument, NULL, 800},
|
{"monitor-repaint", no_argument, NULL, 800},
|
||||||
{"diagnostics", no_argument, NULL, 801},
|
{"diagnostics", no_argument, NULL, 801},
|
||||||
|
@ -791,6 +797,11 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||||
case 325:
|
case 325:
|
||||||
opt->vsync = false;
|
opt->vsync = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 326:
|
||||||
|
opt->max_brightness = atof(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
P_CASEBOOL(733, experimental_backends);
|
P_CASEBOOL(733, experimental_backends);
|
||||||
P_CASEBOOL(800, monitor_repaint);
|
P_CASEBOOL(800, monitor_repaint);
|
||||||
case 801: opt->print_diagnostics = true; break;
|
case 801: opt->print_diagnostics = true; break;
|
||||||
|
@ -822,6 +833,12 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||||
opt->shadow_opacity = normalize_d(opt->shadow_opacity);
|
opt->shadow_opacity = normalize_d(opt->shadow_opacity);
|
||||||
opt->refresh_rate = normalize_i_range(opt->refresh_rate, 0, 300);
|
opt->refresh_rate = normalize_i_range(opt->refresh_rate, 0, 300);
|
||||||
|
|
||||||
|
opt->max_brightness = normalize_d(opt->max_brightness);
|
||||||
|
if (opt->max_brightness < 1.0 && opt->use_damage) {
|
||||||
|
log_warn("--max-brightness requires --no-use-damage. Falling back to 1.0");
|
||||||
|
opt->max_brightness = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply default wintype options that are dependent on global options
|
// Apply default wintype options that are dependent on global options
|
||||||
set_default_winopts(opt, winopt_mask, shadow_enable, fading_enable);
|
set_default_winopts(opt, winopt_mask, shadow_enable, fading_enable);
|
||||||
|
|
||||||
|
|
16
src/utils.c
16
src/utils.c
|
@ -32,4 +32,20 @@ void report_allocation_failure(const char *func, const char *file, unsigned int
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Calculates next closest power of two of 32bit integer n
|
||||||
|
/// ref: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
|
///
|
||||||
|
int next_power_of_two(int n)
|
||||||
|
{
|
||||||
|
n--;
|
||||||
|
n |= n >> 1;
|
||||||
|
n |= n >> 2;
|
||||||
|
n |= n >> 4;
|
||||||
|
n |= n >> 8;
|
||||||
|
n |= n >> 16;
|
||||||
|
n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
// vim: set noet sw=8 ts=8 :
|
// vim: set noet sw=8 ts=8 :
|
||||||
|
|
|
@ -261,4 +261,12 @@ allocchk_(const char *func_name, const char *file, unsigned int line, void *ptr)
|
||||||
void name##_ref(type *a); \
|
void name##_ref(type *a); \
|
||||||
void name##_unref(type **a);
|
void name##_unref(type **a);
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Calculates next closest power of two of 32bit integer n
|
||||||
|
/// ref: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
|
///
|
||||||
|
int next_power_of_two(int n);
|
||||||
|
|
||||||
|
|
||||||
// vim: set noet sw=8 ts=8 :
|
// vim: set noet sw=8 ts=8 :
|
||||||
|
|
Loading…
Reference in New Issue