mirror of
https://github.com/yshui/picom.git
synced 2025-02-24 16:06:42 -05:00
Merge pull request #428 from tryone144/better-blur-texture-sampling
Better blur texture sampling (in experimental backends)
This commit is contained in:
commit
6eb6a247a5
3 changed files with 95 additions and 28 deletions
|
@ -629,20 +629,27 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blu
|
|||
|
||||
// The origin to use when sampling from the source texture
|
||||
GLint texorig_x, texorig_y;
|
||||
GLint tex_width, tex_height;
|
||||
GLuint src_texture;
|
||||
|
||||
if (i == 0) {
|
||||
texorig_x = extent_resized->x1;
|
||||
texorig_y = dst_y_resized_screen_coord;
|
||||
tex_width = gd->width;
|
||||
tex_height = gd->height;
|
||||
src_texture = gd->back_texture;
|
||||
} else {
|
||||
texorig_x = 0;
|
||||
texorig_y = 0;
|
||||
tex_width = bctx->texture_width;
|
||||
tex_height = bctx->texture_height;
|
||||
src_texture = bctx->blur_texture[curr];
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, src_texture);
|
||||
glUseProgram(p->prog);
|
||||
glUniform2f(p->unifm_pixel_norm, 1.0f / (GLfloat)tex_width,
|
||||
1.0f / (GLfloat)tex_height);
|
||||
if (i < bctx->npasses - 1) {
|
||||
// not last pass, draw into framebuffer, with resized regions
|
||||
glBindVertexArray(vao[1]);
|
||||
|
@ -976,19 +983,20 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
|
|||
// clang-format off
|
||||
static const char *FRAG_SHADER_BLUR = GLSL(330,
|
||||
%s\n // other extension pragmas
|
||||
uniform sampler2D tex_scr;
|
||||
uniform sampler2D tex_src;
|
||||
uniform vec2 pixel_norm;
|
||||
uniform float opacity;
|
||||
in vec2 texcoord;
|
||||
out vec4 out_color;
|
||||
void main() {
|
||||
vec2 uv = texcoord * pixel_norm;
|
||||
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
%s //body of the convolution
|
||||
out_color = sum / float(%.7g) * opacity;
|
||||
}
|
||||
);
|
||||
static const char *FRAG_SHADER_BLUR_ADD = QUOTE(
|
||||
sum += float(%.7g) *
|
||||
texelFetch(tex_scr, ivec2(texcoord + vec2(%d, %d)), 0);
|
||||
sum += float(%.7g) * texture2D(tex_src, uv + pixel_norm * vec2(%.7g, %.7g));
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
|
@ -1000,25 +1008,68 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
|
|||
// Build shader
|
||||
int width = kern->w, height = kern->h;
|
||||
int nele = width * height;
|
||||
// '%.7g' is at most 14 characters, inserted 3 times
|
||||
size_t body_len = (strlen(shader_add) + 42) * (uint)nele;
|
||||
char *shader_body = ccalloc(body_len, char);
|
||||
char *pc = shader_body;
|
||||
|
||||
// Make use of the linear interpolation hardware by sampling 2 pixels with
|
||||
// one texture access by sampling between both pixels based on their
|
||||
// relative weight. Easiest done in a single dimension as 2D bilinear
|
||||
// filtering would raise additional constraints on the kernels. Therefore
|
||||
// only use interpolation along the larger dimension.
|
||||
double sum = 0.0;
|
||||
if (width > height) {
|
||||
// use interpolation in x dimension (width)
|
||||
for (int j = 0; j < height; ++j) {
|
||||
for (int k = 0; k < width; ++k) {
|
||||
double val;
|
||||
val = kern->data[j * width + k];
|
||||
if (val == 0) {
|
||||
for (int k = 0; k < width; k += 2) {
|
||||
double val1, val2;
|
||||
val1 = kern->data[j * width + k];
|
||||
val2 = (k + 1 < width)
|
||||
? kern->data[j * width + k + 1]
|
||||
: 0;
|
||||
|
||||
double combined_weight = val1 + val2;
|
||||
if (combined_weight == 0) {
|
||||
continue;
|
||||
}
|
||||
sum += val;
|
||||
pc += snprintf(pc, body_len - (ulong)(pc - shader_body),
|
||||
FRAG_SHADER_BLUR_ADD, val, k - width / 2,
|
||||
j - height / 2);
|
||||
sum += combined_weight;
|
||||
|
||||
double offset_x =
|
||||
k + (val2 / combined_weight) - (width / 2);
|
||||
double offset_y = j - (height / 2);
|
||||
pc += snprintf(
|
||||
pc, body_len - (ulong)(pc - shader_body),
|
||||
shader_add, combined_weight, offset_x, offset_y);
|
||||
assert(pc < shader_body + body_len);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// use interpolation in y dimension (height)
|
||||
for (int j = 0; j < height; j += 2) {
|
||||
for (int k = 0; k < width; ++k) {
|
||||
double val1, val2;
|
||||
val1 = kern->data[j * width + k];
|
||||
val2 = (j + 1 < height)
|
||||
? kern->data[(j + 1) * width + k]
|
||||
: 0;
|
||||
|
||||
double combined_weight = val1 + val2;
|
||||
if (combined_weight == 0) {
|
||||
continue;
|
||||
}
|
||||
sum += combined_weight;
|
||||
|
||||
double offset_x = k - (width / 2);
|
||||
double offset_y =
|
||||
j + (val2 / combined_weight) - (height / 2);
|
||||
pc += snprintf(
|
||||
pc, body_len - (ulong)(pc - shader_body),
|
||||
shader_add, combined_weight, offset_x, offset_y);
|
||||
assert(pc < shader_body + body_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto pass = ctx->blur_shader + i;
|
||||
size_t shader_len = strlen(FRAG_SHADER_BLUR) + strlen(extension) +
|
||||
|
@ -1042,6 +1093,8 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
|
|||
glBindFragDataLocation(pass->prog, 0, "out_color");
|
||||
|
||||
// Get uniform addresses
|
||||
pass->unifm_pixel_norm =
|
||||
glGetUniformLocationChecked(pass->prog, "pixel_norm");
|
||||
pass->unifm_opacity = glGetUniformLocationChecked(pass->prog, "opacity");
|
||||
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
|
||||
pass->texorig_loc = glGetUniformLocationChecked(pass->prog, "texorig");
|
||||
|
@ -1061,6 +1114,7 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
|
|||
// the single pass case
|
||||
auto pass = &ctx->blur_shader[1];
|
||||
pass->prog = gl_create_program_from_str(vertex_shader, dummy_frag);
|
||||
pass->unifm_pixel_norm = -1;
|
||||
pass->unifm_opacity = -1;
|
||||
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
|
||||
pass->texorig_loc = glGetUniformLocationChecked(pass->prog, "texorig");
|
||||
|
@ -1079,11 +1133,15 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
|
|||
// Texture size will be defined by gl_blur
|
||||
glGenTextures(2, ctx->blur_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, ctx->blur_texture[0]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_2D, ctx->blur_texture[1]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
// Generate FBO and textures when needed
|
||||
glGenFramebuffers(1, &ctx->blur_fbo);
|
||||
if (!ctx->blur_fbo) {
|
||||
|
@ -1196,8 +1254,10 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
|||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Set projection matrix to gl viewport dimensions so we can use screen
|
||||
|
|
|
@ -32,6 +32,7 @@ typedef struct {
|
|||
// Program and uniforms for blur shader
|
||||
typedef struct {
|
||||
GLuint prog;
|
||||
GLint unifm_pixel_norm;
|
||||
GLint unifm_opacity;
|
||||
GLint orig_loc;
|
||||
GLint texorig_loc;
|
||||
|
@ -168,7 +169,8 @@ static inline void gl_check_err_(const char *func, int line) {
|
|||
}
|
||||
|
||||
static inline void gl_clear_err(void) {
|
||||
while (glGetError() != GL_NO_ERROR);
|
||||
while (glGetError() != GL_NO_ERROR)
|
||||
;
|
||||
}
|
||||
|
||||
#define gl_check_err() gl_check_err_(__func__, __LINE__)
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
#include "backend/backend.h"
|
||||
#include "backend/backend_common.h"
|
||||
#include "common.h"
|
||||
#include "picom.h"
|
||||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
#include "types.h"
|
||||
|
||||
typedef struct _xrender_data {
|
||||
backend_t base;
|
||||
|
@ -157,11 +157,13 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
|||
|
||||
// Create a buffer for storing blurred picture, make it just big enough
|
||||
// for the blur region
|
||||
const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT;
|
||||
const xcb_render_create_picture_value_list_t pic_attrs = {.repeat = XCB_RENDER_REPEAT_PAD};
|
||||
xcb_render_picture_t tmp_picture[2] = {
|
||||
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized,
|
||||
height_resized, xd->default_visual, 0, NULL),
|
||||
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized,
|
||||
height_resized, xd->default_visual, 0, NULL)};
|
||||
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized,
|
||||
xd->default_visual, pic_attrs_mask, &pic_attrs),
|
||||
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized,
|
||||
xd->default_visual, pic_attrs_mask, &pic_attrs)};
|
||||
|
||||
if (!tmp_picture[0] || !tmp_picture[1]) {
|
||||
log_error("Failed to build intermediate Picture.");
|
||||
|
@ -611,8 +613,11 @@ backend_t *backend_xrender_init(session_t *ps) {
|
|||
xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root,
|
||||
to_u16_checked(ps->root_width),
|
||||
to_u16_checked(ps->root_height));
|
||||
const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT;
|
||||
const xcb_render_create_picture_value_list_t pic_attrs = {
|
||||
.repeat = XCB_RENDER_REPEAT_PAD};
|
||||
xd->back[i] = x_create_picture_with_pictfmt_and_pixmap(
|
||||
ps->c, pictfmt, xd->back_pixmap[i], 0, NULL);
|
||||
ps->c, pictfmt, xd->back_pixmap[i], pic_attrs_mask, &pic_attrs);
|
||||
xd->buffer_age[i] = -1;
|
||||
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
|
||||
log_error("Cannot create pixmap for rendering");
|
||||
|
|
Loading…
Add table
Reference in a new issue