Merge branch 'master' into toplevel-effects

This commit is contained in:
Erik Reider 2023-04-29 18:36:24 +02:00 committed by GitHub
commit 24c072f586
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 204 additions and 113 deletions

View file

@ -36,7 +36,7 @@ shadow_blur_radius 20
shadow_color #0000007F shadow_color #0000007F
# inactive window fade amount. 0.0 = no dimming, 1.0 = fully dimmed # inactive window fade amount. 0.0 = no dimming, 1.0 = fully dimmed
dim_inactive 0.0 default_dim_inactive 0.0
dim_inactive_colors.unfocused #000000FF dim_inactive_colors.unfocused #000000FF
dim_inactive_colors.urgent #900000FF dim_inactive_colors.urgent #900000FF

View file

@ -12,10 +12,9 @@ struct fx_framebuffer {
GLuint fb; GLuint fb;
}; };
void fx_framebuffer_bind(struct fx_framebuffer *buffer, GLsizei width, GLsizei height); void fx_framebuffer_bind(struct fx_framebuffer *buffer);
void fx_framebuffer_create(struct wlr_output *output, struct fx_framebuffer *buffer, void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height, bool bind);
bool bind);
void fx_framebuffer_release(struct fx_framebuffer *buffer); void fx_framebuffer_release(struct fx_framebuffer *buffer);

View file

@ -4,11 +4,12 @@
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <GLES2/gl2ext.h> #include <GLES2/gl2ext.h>
#include <stdbool.h> #include <stdbool.h>
#include <wlr/render/egl.h>
#include "sway/desktop/fx_renderer/fx_framebuffer.h" #include "sway/desktop/fx_renderer/fx_framebuffer.h"
#include "sway/desktop/fx_renderer/fx_texture.h" #include "sway/desktop/fx_renderer/fx_texture.h"
enum corner_location { ALL, TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, NONE }; enum corner_location { TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, ALL, NONE };
enum fx_tex_shader_source { enum fx_tex_shader_source {
SHADER_SOURCE_TEXTURE_RGBA = 1, SHADER_SOURCE_TEXTURE_RGBA = 1,
@ -20,6 +21,8 @@ enum fx_rounded_quad_shader_source {
SHADER_SOURCE_QUAD_ROUND = 1, SHADER_SOURCE_QUAD_ROUND = 1,
SHADER_SOURCE_QUAD_ROUND_TOP_LEFT = 2, SHADER_SOURCE_QUAD_ROUND_TOP_LEFT = 2,
SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT = 3, SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT = 3,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_RIGHT = 4,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_LEFT = 5,
}; };
struct decoration_data { struct decoration_data {
@ -77,11 +80,9 @@ struct blur_shader {
}; };
struct fx_renderer { struct fx_renderer {
struct wlr_egl *egl;
float projection[9]; float projection[9];
struct sway_output *sway_output; int viewport_width, viewport_height;
GLuint stencil_buffer_id; GLuint stencil_buffer_id;
@ -115,6 +116,8 @@ struct fx_renderer {
struct rounded_quad_shader rounded_quad; struct rounded_quad_shader rounded_quad;
struct rounded_quad_shader rounded_tl_quad; struct rounded_quad_shader rounded_tl_quad;
struct rounded_quad_shader rounded_tr_quad; struct rounded_quad_shader rounded_tr_quad;
struct rounded_quad_shader rounded_bl_quad;
struct rounded_quad_shader rounded_br_quad;
struct blur_shader blur1; struct blur_shader blur1;
struct blur_shader blur2; struct blur_shader blur2;
@ -155,7 +158,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl);
void fx_renderer_fini(struct fx_renderer *renderer); void fx_renderer_fini(struct fx_renderer *renderer);
void fx_renderer_begin(struct fx_renderer *renderer, struct sway_output *output); void fx_renderer_begin(struct fx_renderer *renderer, int width, int height);
void fx_renderer_end(struct fx_renderer *renderer); void fx_renderer_end(struct fx_renderer *renderer);
@ -174,18 +177,19 @@ void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]); const float color[static 4], const float projection[static 9]);
void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], const float color[static 4], const float matrix[static 9], int radius,
int radius, enum corner_location corner_location); enum corner_location corner_location);
void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], const float color[static 4], const float matrix[static 9],
enum corner_location corner_location, int radius, int border_thickness); enum corner_location corner_location, int radius, int border_thickness);
void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], int radius, float blur_sigma); const float color[static 4], const float matrix[static 9], int radius,
float blur_sigma);
void fx_render_blur(struct fx_renderer *renderer, struct sway_output *output, void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
const float matrix[static 9], struct fx_framebuffer **buffer, struct fx_framebuffer **buffer, struct blur_shader *shader, const struct wlr_box *box,
struct blur_shader *shader, const struct wlr_box *box, int blur_radius); int blur_radius);
#endif #endif

View file

@ -1,12 +1,11 @@
#include "log.h" #include "log.h"
#include "sway/desktop/fx_renderer/fx_framebuffer.h" #include "sway/desktop/fx_renderer/fx_framebuffer.h"
void fx_framebuffer_bind(struct fx_framebuffer *buffer, GLsizei width, GLsizei height) { void fx_framebuffer_bind(struct fx_framebuffer *buffer) {
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fb); glBindFramebuffer(GL_FRAMEBUFFER, buffer->fb);
glViewport(0, 0, width, height);
} }
void fx_framebuffer_create(struct wlr_output *output, struct fx_framebuffer *buffer, bool bind) { void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height, bool bind) {
bool firstAlloc = false; bool firstAlloc = false;
// Create a new framebuffer // Create a new framebuffer
@ -25,9 +24,6 @@ void fx_framebuffer_create(struct wlr_output *output, struct fx_framebuffer *buf
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} }
int width, height;
wlr_output_transformed_resolution(output, &width, &height);
if (firstAlloc || buffer->texture.width != width || buffer->texture.height != height) { if (firstAlloc || buffer->texture.width != width || buffer->texture.height != height) {
glBindTexture(GL_TEXTURE_2D, buffer->texture.id); glBindTexture(GL_TEXTURE_2D, buffer->texture.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
@ -51,7 +47,7 @@ void fx_framebuffer_create(struct wlr_output *output, struct fx_framebuffer *buf
// Bind the default framebuffer // Bind the default framebuffer
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
if (bind) { if (bind) {
fx_framebuffer_bind(buffer, width, height); fx_framebuffer_bind(buffer);
} }
} }

View file

@ -15,7 +15,6 @@
#include "log.h" #include "log.h"
#include "sway/desktop/fx_renderer/fx_renderer.h" #include "sway/desktop/fx_renderer/fx_renderer.h"
#include "sway/desktop/fx_renderer/matrix.h" #include "sway/desktop/fx_renderer/matrix.h"
#include "sway/output.h"
#include "sway/server.h" #include "sway/server.h"
// shaders // shaders
@ -35,14 +34,11 @@ static const GLfloat verts[] = {
0, 1, // bottom left 0, 1, // bottom left
}; };
static void create_stencil_buffer(struct wlr_output* output, GLuint *buffer_id) { static void create_stencil_buffer(GLuint *buffer_id, int width, int height) {
if (*buffer_id != (uint32_t) -1) { if (*buffer_id != (uint32_t) -1) {
return; return;
} }
int width, height;
wlr_output_transformed_resolution(output, &width, &height);
glGenRenderbuffers(1, buffer_id); glGenRenderbuffers(1, buffer_id);
glBindRenderbuffer(GL_RENDERBUFFER, *buffer_id); glBindRenderbuffer(GL_RENDERBUFFER, *buffer_id);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
@ -205,8 +201,6 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not make EGL current"); sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not make EGL current");
return NULL; return NULL;
} }
// TODO: needed?
renderer->egl = egl;
renderer->main_buffer.fb = -1; renderer->main_buffer.fb = -1;
@ -263,6 +257,14 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT)) { SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT)) {
goto error; goto error;
} }
if (!link_rounded_quad_program(renderer, &renderer->shaders.rounded_bl_quad,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_LEFT)) {
goto error;
}
if (!link_rounded_quad_program(renderer, &renderer->shaders.rounded_br_quad,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_RIGHT)) {
goto error;
}
// Border corner shader // Border corner shader
prog = link_program(corner_frag_src); prog = link_program(corner_frag_src);
@ -337,7 +339,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
} }
if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl), if (!eglMakeCurrent(wlr_egl_get_display(egl),
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL"); sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
goto error; goto error;
@ -351,6 +353,8 @@ error:
glDeleteProgram(renderer->shaders.rounded_quad.program); glDeleteProgram(renderer->shaders.rounded_quad.program);
glDeleteProgram(renderer->shaders.rounded_tl_quad.program); glDeleteProgram(renderer->shaders.rounded_tl_quad.program);
glDeleteProgram(renderer->shaders.rounded_tr_quad.program); glDeleteProgram(renderer->shaders.rounded_tr_quad.program);
glDeleteProgram(renderer->shaders.rounded_bl_quad.program);
glDeleteProgram(renderer->shaders.rounded_br_quad.program);
glDeleteProgram(renderer->shaders.corner.program); glDeleteProgram(renderer->shaders.corner.program);
glDeleteProgram(renderer->shaders.box_shadow.program); glDeleteProgram(renderer->shaders.box_shadow.program);
glDeleteProgram(renderer->shaders.blur1.program); glDeleteProgram(renderer->shaders.blur1.program);
@ -359,7 +363,7 @@ error:
glDeleteProgram(renderer->shaders.tex_rgbx.program); glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program); glDeleteProgram(renderer->shaders.tex_ext.program);
if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl), if (!eglMakeCurrent(wlr_egl_get_display(egl),
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL"); sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
} }
@ -379,13 +383,11 @@ void fx_renderer_fini(struct fx_renderer *renderer) {
release_stencil_buffer(&renderer->stencil_buffer_id); release_stencil_buffer(&renderer->stencil_buffer_id);
} }
void fx_renderer_begin(struct fx_renderer *renderer, struct sway_output *sway_output) { void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) {
struct wlr_output *output = sway_output->wlr_output; glViewport(0, 0, width, height);
renderer->viewport_width = width;
renderer->viewport_height = height;
int width, height;
wlr_output_transformed_resolution(output, &width, &height);
renderer->sway_output = sway_output;
// Store the wlr framebuffer // Store the wlr framebuffer
GLint wlr_fb = -1; GLint wlr_fb = -1;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &wlr_fb); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &wlr_fb);
@ -395,14 +397,11 @@ void fx_renderer_begin(struct fx_renderer *renderer, struct sway_output *sway_ou
} }
renderer->wlr_buffer.fb = wlr_fb; renderer->wlr_buffer.fb = wlr_fb;
// Create the main framebuffer // Create the framebuffers
fx_framebuffer_create(output, &renderer->main_buffer, true); fx_framebuffer_create(&renderer->main_buffer, width, height, true);
// Create the stencil buffer and attach it to our main_buffer fx_framebuffer_create(&renderer->effects_buffer, width, height, false);
create_stencil_buffer(output, &renderer->stencil_buffer_id); fx_framebuffer_create(&renderer->effects_buffer_swapped, width, height, false);
create_stencil_buffer(&renderer->stencil_buffer_id, width, height);
// 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 // refresh projection matrix
matrix_projection(renderer->projection, width, height, matrix_projection(renderer->projection, width, height,
@ -411,7 +410,7 @@ void fx_renderer_begin(struct fx_renderer *renderer, struct sway_output *sway_ou
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Bind to our main framebuffer // Bind to our main framebuffer
fx_framebuffer_bind(&renderer->main_buffer, width, height); fx_framebuffer_bind(&renderer->main_buffer);
} }
void fx_renderer_end(struct fx_renderer *renderer) { void fx_renderer_end(struct fx_renderer *renderer) {
@ -578,8 +577,8 @@ void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
} }
void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], const float color[static 4], const float matrix[static 9], int radius,
int radius, enum corner_location corner_location) { enum corner_location corner_location) {
if (box->width == 0 || box->height == 0) { if (box->width == 0 || box->height == 0) {
return; return;
} }
@ -597,14 +596,17 @@ void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *
case TOP_RIGHT: case TOP_RIGHT:
shader = &renderer->shaders.rounded_tr_quad; shader = &renderer->shaders.rounded_tr_quad;
break; break;
case BOTTOM_LEFT:
shader = &renderer->shaders.rounded_bl_quad;
break;
case BOTTOM_RIGHT:
shader = &renderer->shaders.rounded_br_quad;
break;
default: default:
sway_log(SWAY_ERROR, "Invalid Corner Location. Aborting render"); sway_log(SWAY_ERROR, "Invalid Corner Location. Aborting render");
abort(); abort();
} }
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, projection);
float gl_matrix[9]; float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix); wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
@ -636,14 +638,12 @@ void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *
} }
void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], const float color[static 4], const float matrix[static 9],
enum corner_location corner_location, int radius, int border_thickness) { enum corner_location corner_location, int radius, int border_thickness) {
if (border_thickness == 0 || box->width == 0 || box->height == 0) { if (border_thickness == 0 || box->width == 0 || box->height == 0) {
return; return;
} }
assert(box->width > 0 && box->height > 0); assert(box->width > 0 && box->height > 0);
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, projection);
float gl_matrix[9]; float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix); wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
@ -686,14 +686,12 @@ void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box
// TODO: alpha input arg? // TODO: alpha input arg?
void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], const float color[static 4], const float matrix [static 9], int corner_radius,
int corner_radius, float blur_sigma) { float blur_sigma) {
if (box->width == 0 || box->height == 0) { if (box->width == 0 || box->height == 0) {
return; return;
} }
assert(box->width > 0 && box->height > 0); assert(box->width > 0 && box->height > 0);
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, projection);
float gl_matrix[9]; float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix); wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
@ -722,7 +720,7 @@ void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *bo
// Disable writing to color buffer // Disable writing to color buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// Draw the rounded rect as a mask // Draw the rounded rect as a mask
fx_render_rounded_rect(renderer, &inner_box, col, projection, corner_radius, ALL); fx_render_rounded_rect(renderer, &inner_box, col, matrix, corner_radius, ALL);
// Close the mask // Close the mask
glStencilFunc(GL_NOTEQUAL, 1, 0xFF); glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
@ -761,9 +759,9 @@ void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *bo
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
} }
void fx_render_blur(struct fx_renderer *renderer, struct sway_output *output, void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
const float matrix[static 9], struct fx_framebuffer **buffer, struct fx_framebuffer **buffer, struct blur_shader *shader,
struct blur_shader *shader, const struct wlr_box *box, int blur_radius) { const struct wlr_box *box, int blur_radius) {
glDisable(GL_BLEND); glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
@ -784,12 +782,10 @@ void fx_render_blur(struct fx_renderer *renderer, struct sway_output *output,
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
glUniform1f(shader->radius, blur_radius); glUniform1f(shader->radius, blur_radius);
int width, height;
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
if (shader == &renderer->shaders.blur1) { if (shader == &renderer->shaders.blur1) {
glUniform2f(shader->halfpixel, 0.5f / (width / 2.0f), 0.5f / (height / 2.0f)); glUniform2f(shader->halfpixel, 0.5f / (renderer->viewport_width / 2.0f), 0.5f / (renderer->viewport_height / 2.0f));
} else { } else {
glUniform2f(shader->halfpixel, 0.5f / (width * 2.0f), 0.5f / (height * 2.0f)); glUniform2f(shader->halfpixel, 0.5f / (renderer->viewport_width * 2.0f), 0.5f / (renderer->viewport_height * 2.0f));
} }
glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts); glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);

View file

@ -1,6 +1,8 @@
#define SOURCE_QUAD_ROUND 1 #define SOURCE_QUAD_ROUND 1
#define SOURCE_QUAD_ROUND_TOP_LEFT 2 #define SOURCE_QUAD_ROUND_TOP_LEFT 2
#define SOURCE_QUAD_ROUND_TOP_RIGHT 3 #define SOURCE_QUAD_ROUND_TOP_RIGHT 3
#define SOURCE_QUAD_ROUND_BOTTOM_RIGHT 4
#define SOURCE_QUAD_ROUND_BOTTOM_LEFT 5
#if !defined(SOURCE) #if !defined(SOURCE)
#error "Missing shader preamble" #error "Missing shader preamble"
@ -22,6 +24,10 @@ vec2 getCornerDist() {
return abs(gl_FragCoord.xy - position - size) - size + radius; return abs(gl_FragCoord.xy - position - size) - size + radius;
#elif SOURCE == SOURCE_QUAD_ROUND_TOP_RIGHT #elif SOURCE == SOURCE_QUAD_ROUND_TOP_RIGHT
return abs(gl_FragCoord.xy - position - vec2(0, size.y)) - size + radius; return abs(gl_FragCoord.xy - position - vec2(0, size.y)) - size + radius;
#elif SOURCE == SOURCE_QUAD_ROUND_BOTTOM_RIGHT
return abs(gl_FragCoord.xy - position) - size + radius;
#elif SOURCE == SOURCE_QUAD_ROUND_BOTTOM_LEFT
return abs(gl_FragCoord.xy - position - vec2(size.x, 0)) - size + radius;
#endif #endif
} }

View file

@ -64,6 +64,43 @@ bool should_parameters_shadow() {
return config->shadow_blur_sigma > 0 && config->shadow_color[3] > 0.0; return config->shadow_blur_sigma > 0 && config->shadow_color[3] > 0.0;
} }
// TODO: contribute wlroots function to allow creating an fbox from a box?
struct wlr_fbox wlr_fbox_from_wlr_box(struct wlr_box *box) {
return (struct wlr_fbox) {
.x = box->x,
.y = box->y,
.width = box->width,
.height = box->height,
};
}
// TODO: Remove this ugly abomination with a complete border rework...
enum corner_location get_rotated_corner(enum corner_location corner_location,
enum wl_output_transform transform) {
if (corner_location == ALL || corner_location == NONE) {
return corner_location;
}
switch (transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
return corner_location;
case WL_OUTPUT_TRANSFORM_90:
return (corner_location + 1) % 4;
case WL_OUTPUT_TRANSFORM_180:
return (corner_location + 2) % 4;
case WL_OUTPUT_TRANSFORM_270:
return (corner_location + 3) % 4;
case WL_OUTPUT_TRANSFORM_FLIPPED:
return (corner_location + (1 - 2 * (corner_location % 2))) % 4;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
return (corner_location + (4 - 2 * (corner_location % 2))) % 4;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
return (corner_location + (3 - 2 * (corner_location % 2))) % 4;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
return (corner_location + (2 - 2 * (corner_location % 2))) % 4;
}
return corner_location;
}
/** /**
* Apply scale to a width or height. * Apply scale to a width or height.
* *
@ -148,16 +185,23 @@ static void render_texture(struct wlr_output *wlr_output,
goto damage_finish; goto damage_finish;
} }
// ensure the box is updated as per the output orientation
struct wlr_box transformed_box;
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
wlr_box_transform(&transformed_box, dst_box,
wlr_output_transform_invert(wlr_output->transform), width, height);
int nrects; int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
scissor_output(wlr_output, &rects[i]); scissor_output(wlr_output, &rects[i]);
set_scale_filter(wlr_output, texture, output->scale_filter); set_scale_filter(wlr_output, texture, output->scale_filter);
if (src_box != NULL) { if (src_box != NULL) {
fx_render_subtexture_with_matrix(renderer, texture, src_box, dst_box, fx_render_subtexture_with_matrix(renderer, texture, src_box, &transformed_box,
matrix, deco_data); matrix, deco_data);
} else { } else {
fx_render_texture_with_matrix(renderer, texture, dst_box, matrix, deco_data); fx_render_texture_with_matrix(renderer, texture, &transformed_box, matrix, deco_data);
} }
} }
@ -166,17 +210,14 @@ damage_finish:
} }
/* Renders the blur for each damaged rect and swaps the buffer */ /* Renders the blur for each damaged rect and swaps the buffer */
void render_blur_segments(struct fx_renderer *renderer, struct sway_output *output, void render_blur_segments(struct fx_renderer *renderer,
const float matrix[static 9], pixman_region32_t* damage, const float matrix[static 9], pixman_region32_t* damage,
struct fx_framebuffer **buffer, struct blur_shader* shader, struct fx_framebuffer **buffer, struct blur_shader* shader,
const struct wlr_box *box, int blur_radius) { const struct wlr_box *box, int blur_radius) {
int width, height;
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
if (*buffer == &renderer->effects_buffer) { if (*buffer == &renderer->effects_buffer) {
fx_framebuffer_bind(&renderer->effects_buffer_swapped, width, height); fx_framebuffer_bind(&renderer->effects_buffer_swapped);
} else { } else {
fx_framebuffer_bind(&renderer->effects_buffer, width, height); fx_framebuffer_bind(&renderer->effects_buffer);
} }
if (pixman_region32_not_empty(damage)) { if (pixman_region32_not_empty(damage)) {
@ -186,7 +227,7 @@ void render_blur_segments(struct fx_renderer *renderer, struct sway_output *outp
const pixman_box32_t box = rects[i]; const pixman_box32_t box = rects[i];
struct wlr_box new_box = { box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1 }; struct wlr_box new_box = { box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1 };
fx_renderer_scissor(&new_box); fx_renderer_scissor(&new_box);
fx_render_blur(renderer, output, matrix, buffer, shader, &new_box, blur_radius); fx_render_blur(renderer, matrix, buffer, shader, &new_box, blur_radius);
} }
} }
@ -197,14 +238,15 @@ void render_blur_segments(struct fx_renderer *renderer, struct sway_output *outp
} }
} }
/** Blurs the main_buffer content and returns the blurred framebuffer */ // Blurs the main_buffer content and returns the blurred framebuffer
struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct sway_output *output, struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct sway_output *output,
pixman_region32_t *original_damage, const float box_matrix[static 9], const struct wlr_box *box) { pixman_region32_t *original_damage, const float box_matrix[static 9], const struct wlr_box *box) {
struct wlr_box monitor_box = get_monitor_box(output->wlr_output); struct wlr_output *wlr_output = output->wlr_output;
struct wlr_box monitor_box = get_monitor_box(wlr_output);
const enum wl_output_transform transform = wlr_output_transform_invert(output->wlr_output->transform); const enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, &monitor_box, transform, 0, output->wlr_output->transform_matrix); wlr_matrix_project_box(matrix, &monitor_box, transform, 0, wlr_output->transform_matrix);
float gl_matrix[9]; float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix); wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
@ -212,7 +254,7 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
pixman_region32_t damage; pixman_region32_t damage;
pixman_region32_init(&damage); pixman_region32_init(&damage);
pixman_region32_copy(&damage, original_damage); pixman_region32_copy(&damage, original_damage);
wlr_region_transform(&damage, &damage, wlr_output_transform_invert(output->wlr_output->transform), wlr_region_transform(&damage, &damage, transform,
monitor_box.width, monitor_box.height); monitor_box.width, monitor_box.height);
wlr_region_expand(&damage, &damage, get_blur_size()); wlr_region_expand(&damage, &damage, get_blur_size());
@ -220,7 +262,7 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
struct fx_framebuffer *current_buffer = &renderer->main_buffer; struct fx_framebuffer *current_buffer = &renderer->main_buffer;
// Bind to blur framebuffer // Bind to blur framebuffer
fx_framebuffer_bind(&renderer->effects_buffer, monitor_box.width, monitor_box.height); fx_framebuffer_bind(&renderer->effects_buffer);
glBindTexture(renderer->main_buffer.texture.target, renderer->main_buffer.texture.id); glBindTexture(renderer->main_buffer.texture.target, renderer->main_buffer.texture.id);
// damage region will be scaled, make a temp // damage region will be scaled, make a temp
@ -233,13 +275,13 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
int blur_passes = config->blur_params.num_passes; int blur_passes = config->blur_params.num_passes;
// First pass // First pass
render_blur_segments(renderer, output, gl_matrix, &tempDamage, &current_buffer, render_blur_segments(renderer, gl_matrix, &tempDamage, &current_buffer,
&renderer->shaders.blur1, box, blur_radius); &renderer->shaders.blur1, box, blur_radius);
// Downscale // Downscale
for (int i = 1; i < blur_passes; ++i) { for (int i = 1; i < blur_passes; ++i) {
wlr_region_scale(&tempDamage, &damage, 1.0f / (1 << (i + 1))); wlr_region_scale(&tempDamage, &damage, 1.0f / (1 << (i + 1)));
render_blur_segments(renderer, output, gl_matrix, &tempDamage, &current_buffer, render_blur_segments(renderer, gl_matrix, &tempDamage, &current_buffer,
&renderer->shaders.blur1, box, blur_radius); &renderer->shaders.blur1, box, blur_radius);
} }
@ -247,7 +289,7 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
for (int i = blur_passes - 1; i >= 0; --i) { for (int i = blur_passes - 1; i >= 0; --i) {
// when upsampling we make the region twice as big // when upsampling we make the region twice as big
wlr_region_scale(&tempDamage, &damage, 1.0f / (1 << i)); wlr_region_scale(&tempDamage, &damage, 1.0f / (1 << i));
render_blur_segments(renderer, output, gl_matrix, &tempDamage, &current_buffer, render_blur_segments(renderer, gl_matrix, &tempDamage, &current_buffer,
&renderer->shaders.blur2, box, blur_radius); &renderer->shaders.blur2, box, blur_radius);
} }
@ -255,7 +297,7 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
pixman_region32_fini(&damage); pixman_region32_fini(&damage);
// Bind back to the default buffer // Bind back to the default buffer
fx_framebuffer_bind(&renderer->main_buffer, monitor_box.width, monitor_box.height); fx_framebuffer_bind(&renderer->main_buffer);
return current_buffer; return current_buffer;
} }
@ -360,13 +402,24 @@ void render_box_shadow(struct sway_output *output, pixman_region32_t *output_dam
goto damage_finish; goto damage_finish;
} }
float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
wlr_output->transform_matrix);
// ensure the box is updated as per the output orientation
struct wlr_box transformed_box;
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
wlr_box_transform(&transformed_box, &box,
wlr_output_transform_invert(wlr_output->transform), width, height);
int nrects; int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
scissor_output(wlr_output, &rects[i]); scissor_output(wlr_output, &rects[i]);
fx_render_box_shadow(renderer, &box, color, fx_render_box_shadow(renderer, &transformed_box, color, matrix,
wlr_output->transform_matrix, corner_radius, blur_sigma); corner_radius, blur_sigma);
} }
damage_finish: damage_finish:
@ -387,6 +440,7 @@ static void render_surface_iterator(struct sway_output *output,
} }
struct wlr_box proj_box = *_box; struct wlr_box proj_box = *_box;
scale_box(&proj_box, wlr_output->scale); scale_box(&proj_box, wlr_output->scale);
float matrix[9]; float matrix[9];
@ -431,9 +485,10 @@ static void render_surface_iterator(struct sway_output *output,
} }
if (has_alpha) { if (has_alpha) {
int width, height; struct wlr_box monitor_box = get_monitor_box(wlr_output);
wlr_output_transformed_resolution(wlr_output, &width, &height); wlr_box_transform(&monitor_box, &monitor_box,
struct wlr_fbox blur_src_box = { 0, 0, width, height }; wlr_output_transform_invert(wlr_output->transform), monitor_box.width, monitor_box.height);
struct wlr_fbox blur_src_box = wlr_fbox_from_wlr_box(&monitor_box);
render_blur(should_optimize_blur, output, output_damage, &blur_src_box, &dst_box, &opaque_region, render_blur(should_optimize_blur, output, output_damage, &blur_src_box, &dst_box, &opaque_region,
surface->current.width, surface->current.height, surface->current.scale, deco_data.corner_radius); surface->current.width, surface->current.height, surface->current.scale, deco_data.corner_radius);
} }
@ -523,14 +578,13 @@ static void render_drag_icons(struct sway_output *output,
render_surface_iterator, &data); render_surface_iterator, &data);
} }
void render_whole_output(struct fx_renderer *renderer, pixman_region32_t *original_damage, void render_whole_output(struct fx_renderer *renderer, struct wlr_output *wlr_output,
struct fx_texture *texture) { pixman_region32_t *original_damage, struct fx_texture *texture) {
struct wlr_output *output = renderer->sway_output->wlr_output; struct wlr_box monitor_box = get_monitor_box(wlr_output);
struct wlr_box monitor_box = get_monitor_box(output);
enum wl_output_transform transform = wlr_output_transform_invert(output->transform); enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, &monitor_box, transform, 0.0, output->transform_matrix); wlr_matrix_project_box(matrix, &monitor_box, transform, 0.0, wlr_output->transform_matrix);
pixman_region32_t damage; pixman_region32_t damage;
pixman_region32_init(&damage); pixman_region32_init(&damage);
@ -545,7 +599,7 @@ void render_whole_output(struct fx_renderer *renderer, pixman_region32_t *origin
int nrects; int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
scissor_output(output, &rects[i]); scissor_output(wlr_output, &rects[i]);
fx_render_texture_with_matrix(renderer, texture, &monitor_box, matrix, get_undecorated_decoration_data()); fx_render_texture_with_matrix(renderer, texture, &monitor_box, matrix, get_undecorated_decoration_data());
} }
@ -566,7 +620,8 @@ void render_monitor_blur(struct sway_output *output, pixman_region32_t *damage)
wlr_output->transform_matrix, &monitor_box); wlr_output->transform_matrix, &monitor_box);
// Render the newly blurred content into the blur_buffer // Render the newly blurred content into the blur_buffer
fx_framebuffer_create(wlr_output, &renderer->blur_buffer, true); fx_framebuffer_create(&renderer->blur_buffer,
output->renderer->viewport_width, output->renderer->viewport_height, true);
// Clear the damaged region of the blur_buffer // Clear the damaged region of the blur_buffer
float clear_color[] = { 0, 0, 0, 0 }; float clear_color[] = { 0, 0, 0, 0 };
int nrects; int nrects;
@ -575,8 +630,8 @@ void render_monitor_blur(struct sway_output *output, pixman_region32_t *damage)
scissor_output(wlr_output, &rects[i]); scissor_output(wlr_output, &rects[i]);
fx_renderer_clear(clear_color); fx_renderer_clear(clear_color);
} }
render_whole_output(renderer, &fake_damage, &buffer->texture); render_whole_output(renderer, wlr_output, &fake_damage, &buffer->texture);
fx_framebuffer_bind(&renderer->main_buffer, monitor_box.width, monitor_box.height); fx_framebuffer_bind(&renderer->main_buffer);
pixman_region32_fini(&fake_damage); pixman_region32_fini(&fake_damage);
@ -630,11 +685,25 @@ void render_rounded_rect(struct sway_output *output, pixman_region32_t *output_d
goto damage_finish; goto damage_finish;
} }
float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
wlr_output->transform_matrix);
enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
// ensure the box is updated as per the output orientation
struct wlr_box transformed_box;
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
wlr_box_transform(&transformed_box, &box, transform, width, height);
corner_location = get_rotated_corner(corner_location, transform);
int nrects; int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
scissor_output(wlr_output, &rects[i]); scissor_output(wlr_output, &rects[i]);
fx_render_rounded_rect(renderer, &box, color, wlr_output->transform_matrix, fx_render_rounded_rect(renderer, &transformed_box, color, matrix,
corner_radius, corner_location); corner_radius, corner_location);
} }
@ -661,11 +730,25 @@ void render_border_corner(struct sway_output *output, pixman_region32_t *output_
goto damage_finish; goto damage_finish;
} }
float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
wlr_output->transform_matrix);
enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
// ensure the box is updated as per the output orientation
struct wlr_box transformed_box;
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
wlr_box_transform(&transformed_box, &box, transform, width, height);
corner_location = get_rotated_corner(corner_location, transform);
int nrects; int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
scissor_output(wlr_output, &rects[i]); scissor_output(wlr_output, &rects[i]);
fx_render_border_corner(renderer, &box, color, wlr_output->transform_matrix, fx_render_border_corner(renderer, &transformed_box, color, matrix,
corner_location, corner_radius, border_thickness); corner_location, corner_radius, border_thickness);
} }
@ -694,7 +777,8 @@ static void render_view_toplevels(struct sway_view *view, struct sway_output *ou
clip_box.y = state.y - output->ly; clip_box.y = state.y - output->ly;
clip_box.width = state.width; clip_box.width = state.width;
clip_box.height = state.height; clip_box.height = state.height;
if (state.border == B_PIXEL || state.border == B_NORMAL) { if (state.fullscreen_mode == FULLSCREEN_NONE
&& (state.border == B_PIXEL || state.border == B_NORMAL)) {
clip_box.x += state.border_thickness; clip_box.x += state.border_thickness;
clip_box.y += state.border_thickness; clip_box.y += state.border_thickness;
clip_box.width -= state.border_thickness * 2; clip_box.width -= state.border_thickness * 2;
@ -782,8 +866,9 @@ static void render_saved_view(struct sway_view *view, struct sway_output *output
pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0); pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0);
struct wlr_box monitor_box = get_monitor_box(wlr_output); struct wlr_box monitor_box = get_monitor_box(wlr_output);
// TODO: contribute wlroots function to allow creating an fbox from a box? wlr_box_transform(&monitor_box, &monitor_box,
struct wlr_fbox src_box = { monitor_box.x, monitor_box.y, monitor_box.width, monitor_box.height }; wlr_output_transform_invert(wlr_output->transform), monitor_box.width, monitor_box.height);
struct wlr_fbox src_box = wlr_fbox_from_wlr_box(&monitor_box);
bool should_optimize_blur = !container_is_floating(con); bool should_optimize_blur = !container_is_floating(con);
render_blur(should_optimize_blur, output, damage, &src_box, &dst_box, &opaque_region, render_blur(should_optimize_blur, output, damage, &src_box, &dst_box, &opaque_region,
saved_buf->width, saved_buf->height, 1, deco_data.corner_radius); saved_buf->width, saved_buf->height, 1, deco_data.corner_radius);
@ -1824,9 +1909,6 @@ void output_render(struct sway_output *output, struct timespec *when,
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
struct fx_renderer *renderer = output->renderer; struct fx_renderer *renderer = output->renderer;
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
struct sway_workspace *workspace = output->current.active_workspace; struct sway_workspace *workspace = output->current.active_workspace;
if (workspace == NULL) { if (workspace == NULL) {
return; return;
@ -1837,6 +1919,16 @@ void output_render(struct sway_output *output, struct timespec *when,
fullscreen_con = workspace->current.fullscreen; fullscreen_con = workspace->current.fullscreen;
} }
struct wlr_box monitor_box = get_monitor_box(wlr_output);
wlr_box_transform(&monitor_box, &monitor_box,
wlr_output_transform_invert(wlr_output->transform),
monitor_box.width, monitor_box.height);
fx_renderer_begin(renderer, monitor_box.width, monitor_box.height);
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
if (debug.damage == DAMAGE_RERENDER) { if (debug.damage == DAMAGE_RERENDER) {
pixman_region32_union_rect(damage, damage, 0, 0, width, height); pixman_region32_union_rect(damage, damage, 0, 0, width, height);
} }
@ -1880,8 +1972,6 @@ void output_render(struct sway_output *output, struct timespec *when,
fx_renderer_clear((float[]){1, 1, 0, 1}); fx_renderer_clear((float[]){1, 1, 0, 1});
} }
fx_renderer_begin(renderer, output);
if (!damage_not_empty) { if (!damage_not_empty) {
// Output isn't damaged but needs buffer swap // Output isn't damaged but needs buffer swap
goto renderer_end; goto renderer_end;
@ -2025,7 +2115,7 @@ render_overlay:
renderer_end: renderer_end:
// Draw the contents of our buffer into the wlr buffer // Draw the contents of our buffer into the wlr buffer
fx_framebuffer_bind(&renderer->wlr_buffer, width, height); fx_framebuffer_bind(&renderer->wlr_buffer);
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
if (pixman_region32_not_empty(&extended_damage)) { if (pixman_region32_not_empty(&extended_damage)) {
int nrects; int nrects;
@ -2035,7 +2125,7 @@ renderer_end:
fx_renderer_clear(clear_color); fx_renderer_clear(clear_color);
} }
} }
render_whole_output(renderer, &extended_damage, &renderer->main_buffer.texture); render_whole_output(renderer, wlr_output, &extended_damage, &renderer->main_buffer.texture);
fx_renderer_scissor(NULL); fx_renderer_scissor(NULL);
fx_renderer_end(renderer); fx_renderer_end(renderer);