diff options
author | Erik Reider <[email protected]> | 2023-04-17 23:24:48 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2023-04-17 23:24:48 +0200 |
commit | cbfb7af7fd4728f993124e81f8666a2e8cee6085 (patch) | |
tree | 081e51028d59da49480be6bff9c580bbdadca9cd /sway/desktop/fx_renderer/fx_renderer.c | |
parent | 7d774f769cec2faec25d01120b05589a34b4eb0b (diff) |
Add kawase blur (#120)
Co-authored-by: Erik Reider <[email protected]>
Co-authored-by: Will McKinnon <[email protected]>
Diffstat (limited to 'sway/desktop/fx_renderer/fx_renderer.c')
-rw-r--r-- | sway/desktop/fx_renderer/fx_renderer.c | 204 |
1 files changed, 169 insertions, 35 deletions
diff --git a/sway/desktop/fx_renderer/fx_renderer.c b/sway/desktop/fx_renderer/fx_renderer.c index 36c5bb61..715c5b15 100644 --- a/sway/desktop/fx_renderer/fx_renderer.c +++ b/sway/desktop/fx_renderer/fx_renderer.c @@ -19,6 +19,8 @@ #include "sway/server.h" // shaders +#include "blur1_frag_src.h" +#include "blur2_frag_src.h" #include "box_shadow_frag_src.h" #include "common_vert_src.h" #include "corner_frag_src.h" @@ -33,6 +35,33 @@ static const GLfloat verts[] = { 0, 1, // bottom left }; +static void create_stencil_buffer(struct wlr_output* output, GLuint *buffer_id) { + if (*buffer_id != (uint32_t) -1) { + return; + } + + int width, height; + wlr_output_transformed_resolution(output, &width, &height); + + glGenRenderbuffers(1, buffer_id); + glBindRenderbuffer(GL_RENDERBUFFER, *buffer_id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *buffer_id); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + sway_log(SWAY_ERROR, "Stencilbuffer incomplete, couldn't create! (FB status: %i)", status); + return; + } + sway_log(SWAY_DEBUG, "Stencilbuffer created, status %i", status); +} + +static void release_stencil_buffer(GLuint *buffer_id) { + if (*buffer_id != (uint32_t)-1 && buffer_id) { + glDeleteRenderbuffers(1, buffer_id); + } + *buffer_id = -1; +} + static GLuint compile_shader(GLuint type, const GLchar *src) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, NULL); @@ -179,6 +208,15 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) { // TODO: needed? renderer->egl = egl; + renderer->main_buffer.fb = -1; + + renderer->blur_buffer.fb = -1; + renderer->effects_buffer.fb = -1; + renderer->effects_buffer_swapped.fb = -1; + renderer->stencil_buffer_id = -1; + + renderer->blur_buffer_dirty = true; + // get extensions const char *exts_str = (const char *)glGetString(GL_EXTENSIONS); if (exts_str == NULL) { @@ -258,6 +296,32 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) { renderer->shaders.box_shadow.blur_sigma = glGetUniformLocation(prog, "blur_sigma"); renderer->shaders.box_shadow.corner_radius = glGetUniformLocation(prog, "corner_radius"); + // Blur 1 + prog = link_program(blur1_frag_src); + renderer->shaders.blur1.program = prog; + if (!renderer->shaders.blur1.program) { + goto error; + } + renderer->shaders.blur1.proj = glGetUniformLocation(prog, "proj"); + renderer->shaders.blur1.tex = glGetUniformLocation(prog, "tex"); + renderer->shaders.blur1.pos_attrib = glGetAttribLocation(prog, "pos"); + renderer->shaders.blur1.tex_attrib = glGetAttribLocation(prog, "texcoord"); + renderer->shaders.blur1.radius = glGetUniformLocation(prog, "radius"); + renderer->shaders.blur1.halfpixel = glGetUniformLocation(prog, "halfpixel"); + + // Blur 2 + prog = link_program(blur2_frag_src); + renderer->shaders.blur2.program = prog; + if (!renderer->shaders.blur2.program) { + goto error; + } + renderer->shaders.blur2.proj = glGetUniformLocation(prog, "proj"); + renderer->shaders.blur2.tex = glGetUniformLocation(prog, "tex"); + renderer->shaders.blur2.pos_attrib = glGetAttribLocation(prog, "pos"); + renderer->shaders.blur2.tex_attrib = glGetAttribLocation(prog, "texcoord"); + renderer->shaders.blur2.radius = glGetUniformLocation(prog, "radius"); + renderer->shaders.blur2.halfpixel = glGetUniformLocation(prog, "halfpixel"); + // fragment shaders if (!link_tex_program(renderer, &renderer->shaders.tex_rgba, SHADER_SOURCE_TEXTURE_RGBA)) { @@ -289,6 +353,8 @@ error: glDeleteProgram(renderer->shaders.rounded_tr_quad.program); glDeleteProgram(renderer->shaders.corner.program); glDeleteProgram(renderer->shaders.box_shadow.program); + glDeleteProgram(renderer->shaders.blur1.program); + glDeleteProgram(renderer->shaders.blur2.program); glDeleteProgram(renderer->shaders.tex_rgba.program); glDeleteProgram(renderer->shaders.tex_rgbx.program); glDeleteProgram(renderer->shaders.tex_ext.program); @@ -305,27 +371,53 @@ error: return NULL; } -void fx_renderer_begin(struct fx_renderer *renderer, uint32_t width, uint32_t height) { - // Create and render the stencil buffer - if (renderer->stencil_buffer_id == 0) { - glGenRenderbuffers(1, &renderer->stencil_buffer_id); +void fx_renderer_fini(struct fx_renderer *renderer) { + fx_framebuffer_release(&renderer->main_buffer); + fx_framebuffer_release(&renderer->blur_buffer); + fx_framebuffer_release(&renderer->effects_buffer); + fx_framebuffer_release(&renderer->effects_buffer_swapped); + release_stencil_buffer(&renderer->stencil_buffer_id); +} + +void fx_renderer_begin(struct fx_renderer *renderer, struct sway_output *sway_output) { + struct wlr_output *output = sway_output->wlr_output; + + int width, height; + wlr_output_transformed_resolution(output, &width, &height); + + renderer->sway_output = sway_output; + // Store the wlr framebuffer + GLint wlr_fb = -1; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &wlr_fb); + if (wlr_fb < 0) { + sway_log(SWAY_ERROR, "Failed to get wlr framebuffer!"); + abort(); } - glBindRenderbuffer(GL_RENDERBUFFER, renderer->stencil_buffer_id); - glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, renderer->stencil_buffer_id); + renderer->wlr_buffer.fb = wlr_fb; - glViewport(0, 0, width, height); + // Create the main framebuffer + fx_framebuffer_create(output, &renderer->main_buffer, true); + // Create the stencil buffer and attach it to our main_buffer + create_stencil_buffer(output, &renderer->stencil_buffer_id); + + // Create a new blur/effects framebuffers + fx_framebuffer_create(output, &renderer->effects_buffer, false); + fx_framebuffer_create(output, &renderer->effects_buffer_swapped, false); // refresh projection matrix matrix_projection(renderer->projection, width, height, WL_OUTPUT_TRANSFORM_FLIPPED_180); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + // Bind to our main framebuffer + fx_framebuffer_bind(&renderer->main_buffer, width, height); } -void fx_renderer_end() { - // TODO +void fx_renderer_end(struct fx_renderer *renderer) { + // Release the main buffer + fx_framebuffer_release(&renderer->main_buffer); + release_stencil_buffer(&renderer->stencil_buffer_id); } void fx_renderer_clear(const float color[static 4]) { @@ -335,26 +427,23 @@ void fx_renderer_clear(const float color[static 4]) { } void fx_renderer_scissor(struct wlr_box *box) { - if (box) { - glScissor(box->x, box->y, box->width, box->height); - glEnable(GL_SCISSOR_TEST); - } else { - glDisable(GL_SCISSOR_TEST); - } + if (box) { + glScissor(box->x, box->y, box->width, box->height); + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } } -bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, +bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct fx_texture *fx_texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9], struct decoration_data deco_data) { - assert(wlr_texture_is_gles2(wlr_texture)); - struct wlr_gles2_texture_attribs texture_attrs; - wlr_gles2_texture_get_attribs(wlr_texture, &texture_attrs); struct gles2_tex_shader *shader = NULL; - switch (texture_attrs.target) { + switch (fx_texture->target) { case GL_TEXTURE_2D: - if (texture_attrs.has_alpha) { + if (fx_texture->has_alpha) { shader = &renderer->shaders.tex_rgba; } else { shader = &renderer->shaders.tex_rgbx; @@ -382,16 +471,18 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t wlr_matrix_transpose(gl_matrix, gl_matrix); // if there's no opacity or rounded corners we don't need to blend - if (!texture_attrs.has_alpha && deco_data.alpha == 1.0 && !deco_data.corner_radius) { + if (!fx_texture->has_alpha && deco_data.alpha == 1.0 && !deco_data.corner_radius) { glDisable(GL_BLEND); } else { glEnable(GL_BLEND); } + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glActiveTexture(GL_TEXTURE0); - glBindTexture(texture_attrs.target, texture_attrs.tex); + glBindTexture(fx_texture->target, fx_texture->id); - glTexParameteri(texture_attrs.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(fx_texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(shader->program); @@ -408,10 +499,10 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t glUniform1f(shader->saturation, deco_data.saturation); glUniform1f(shader->radius, deco_data.corner_radius); - const GLfloat x1 = src_box->x / wlr_texture->width; - const GLfloat y1 = src_box->y / wlr_texture->height; - const GLfloat x2 = (src_box->x + src_box->width) / wlr_texture->width; - const GLfloat y2 = (src_box->y + src_box->height) / wlr_texture->height; + const GLfloat x1 = src_box->x / fx_texture->width; + const GLfloat y1 = src_box->y / fx_texture->height; + const GLfloat x2 = (src_box->x + src_box->width) / fx_texture->width; + const GLfloat y2 = (src_box->y + src_box->height) / fx_texture->height; const GLfloat texcoord[] = { x2, y1, // top right x1, y1, // top left @@ -430,21 +521,21 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t glDisableVertexAttribArray(shader->pos_attrib); glDisableVertexAttribArray(shader->tex_attrib); - glBindTexture(texture_attrs.target, 0); + glBindTexture(fx_texture->target, 0); return true; } -bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, +bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct fx_texture *texture, const struct wlr_box *dst_box, const float matrix[static 9], struct decoration_data deco_data) { struct wlr_fbox src_box = { .x = 0, .y = 0, - .width = wlr_texture->width, - .height = wlr_texture->height, + .width = texture->width, + .height = texture->height, }; - return fx_render_subtexture_with_matrix(renderer, wlr_texture, &src_box, + return fx_render_subtexture_with_matrix(renderer, texture, &src_box, dst_box, matrix, deco_data); } @@ -669,3 +760,46 @@ void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *bo glClear(GL_STENCIL_BUFFER_BIT); glDisable(GL_STENCIL_TEST); } + +void fx_render_blur(struct fx_renderer *renderer, struct sway_output *output, + const float matrix[static 9], struct fx_framebuffer **buffer, + struct blur_shader *shader, const struct wlr_box *box, int blur_radius) { + glDisable(GL_BLEND); + glDisable(GL_STENCIL_TEST); + + glActiveTexture(GL_TEXTURE0); + + glBindTexture((*buffer)->texture.target, (*buffer)->texture.id); + + glTexParameteri((*buffer)->texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glUseProgram(shader->program); + + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set + // to GL_FALSE + float gl_matrix[9]; + wlr_matrix_transpose(gl_matrix, matrix); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix); + + glUniform1i(shader->tex, 0); + glUniform1f(shader->radius, blur_radius); + + int width, height; + wlr_output_transformed_resolution(output->wlr_output, &width, &height); + if (shader == &renderer->shaders.blur1) { + glUniform2f(shader->halfpixel, 0.5f / (width / 2.0f), 0.5f / (height / 2.0f)); + } else { + glUniform2f(shader->halfpixel, 0.5f / (width * 2.0f), 0.5f / (height * 2.0f)); + } + + glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(shader->tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts); + + glEnableVertexAttribArray(shader->pos_attrib); + glEnableVertexAttribArray(shader->tex_attrib); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableVertexAttribArray(shader->pos_attrib); + glDisableVertexAttribArray(shader->tex_attrib); +} |