mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Change custom-shader to a prelude-epilogue system
This commit is contained in:
@@ -63,8 +63,8 @@ unsafe fn compile_program(
|
||||
let vert_position = CStr::from_bytes_with_nul(b"vert_position\0").expect("NULL terminated");
|
||||
let matrix = CStr::from_bytes_with_nul(b"matrix\0").expect("NULL terminated");
|
||||
let tex_matrix = CStr::from_bytes_with_nul(b"tex_matrix\0").expect("NULL terminated");
|
||||
let size = CStr::from_bytes_with_nul(b"size\0").expect("NULL terminated");
|
||||
let alpha = CStr::from_bytes_with_nul(b"alpha\0").expect("NULL terminated");
|
||||
let size = CStr::from_bytes_with_nul(b"niri_size\0").expect("NULL terminated");
|
||||
let alpha = CStr::from_bytes_with_nul(b"niri_alpha\0").expect("NULL terminated");
|
||||
|
||||
Ok(PixelWithTexturesProgram(Rc::new(
|
||||
PixelWithTexturesProgramInner {
|
||||
|
||||
@@ -74,10 +74,9 @@ impl ResizeRenderElement {
|
||||
// Compute the transformation matrices.
|
||||
let input_to_curr_geo = Mat3::from_scale(area_size / curr_geo_size)
|
||||
* Mat3::from_translation((area_loc - curr_geo_loc) / area_size);
|
||||
let input_to_prev_geo = Mat3::from_scale(area_size / size_prev)
|
||||
* Mat3::from_translation((area_loc - curr_geo_loc) / area_size);
|
||||
let input_to_next_geo = Mat3::from_scale(area_size / size_next)
|
||||
* Mat3::from_translation((area_loc - curr_geo_loc) / area_size);
|
||||
|
||||
let curr_geo_to_prev_geo = Mat3::from_scale(curr_geo_size / size_prev);
|
||||
let curr_geo_to_next_geo = Mat3::from_scale(curr_geo_size / size_next);
|
||||
|
||||
let geo_to_tex_prev = Mat3::from_translation(-tex_prev_geo_loc / tex_prev_geo_size)
|
||||
* Mat3::from_scale(size_prev / tex_prev_geo_size * scale);
|
||||
@@ -99,21 +98,21 @@ impl ResizeRenderElement {
|
||||
Self(PrimaryGpuPixelShaderWithTexturesRenderElement::new(
|
||||
shader,
|
||||
HashMap::from([
|
||||
(String::from("tex_prev"), texture_prev),
|
||||
(String::from("tex_next"), texture_next),
|
||||
(String::from("niri_tex_prev"), texture_prev),
|
||||
(String::from("niri_tex_next"), texture_next),
|
||||
]),
|
||||
area,
|
||||
size,
|
||||
None,
|
||||
result_alpha,
|
||||
vec![
|
||||
make_uniform("input_to_curr_geo", input_to_curr_geo),
|
||||
make_uniform("input_to_prev_geo", input_to_prev_geo),
|
||||
make_uniform("input_to_next_geo", input_to_next_geo),
|
||||
make_uniform("geo_to_tex_prev", geo_to_tex_prev),
|
||||
make_uniform("geo_to_tex_next", geo_to_tex_next),
|
||||
Uniform::new("progress", progress),
|
||||
Uniform::new("clamped_progress", clamped_progress),
|
||||
make_uniform("niri_input_to_curr_geo", input_to_curr_geo),
|
||||
make_uniform("niri_curr_geo_to_prev_geo", curr_geo_to_prev_geo),
|
||||
make_uniform("niri_curr_geo_to_next_geo", curr_geo_to_next_geo),
|
||||
make_uniform("niri_geo_to_tex_prev", geo_to_tex_prev),
|
||||
make_uniform("niri_geo_to_tex_next", geo_to_tex_next),
|
||||
Uniform::new("niri_progress", progress),
|
||||
Uniform::new("niri_clamped_progress", clamped_progress),
|
||||
],
|
||||
Kind::Unspecified,
|
||||
))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use smithay::backend::renderer::gles::{GlesPixelProgram, GlesRenderer, UniformName, UniformType};
|
||||
use smithay::backend::renderer::gles::{
|
||||
GlesError, GlesPixelProgram, GlesRenderer, UniformName, UniformType,
|
||||
};
|
||||
|
||||
use super::primary_gpu_pixel_shader_with_textures::PixelWithTexturesProgram;
|
||||
use super::renderer::NiriRenderer;
|
||||
@@ -31,24 +33,11 @@ impl Shaders {
|
||||
})
|
||||
.ok();
|
||||
|
||||
let resize = PixelWithTexturesProgram::compile(
|
||||
renderer,
|
||||
include_str!("resize.frag"),
|
||||
&[
|
||||
UniformName::new("input_to_curr_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("input_to_prev_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("input_to_next_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("geo_to_tex_prev", UniformType::Matrix3x3),
|
||||
UniformName::new("geo_to_tex_next", UniformType::Matrix3x3),
|
||||
UniformName::new("progress", UniformType::_1f),
|
||||
UniformName::new("clamped_progress", UniformType::_1f),
|
||||
],
|
||||
&["tex_prev", "tex_next"],
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("error compiling resize shader: {err:?}");
|
||||
})
|
||||
.ok();
|
||||
let resize = compile_resize_program(renderer, include_str!("resize.frag"))
|
||||
.map_err(|err| {
|
||||
warn!("error compiling resize shader: {err:?}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
Self {
|
||||
gradient_border,
|
||||
@@ -87,22 +76,33 @@ pub fn init(renderer: &mut GlesRenderer) {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_resize_program(
|
||||
renderer: &mut GlesRenderer,
|
||||
src: &str,
|
||||
) -> Result<PixelWithTexturesProgram, GlesError> {
|
||||
let mut program = include_str!("resize-prelude.frag").to_string();
|
||||
program.push_str(src);
|
||||
program.push_str(include_str!("resize-epilogue.frag"));
|
||||
|
||||
PixelWithTexturesProgram::compile(
|
||||
renderer,
|
||||
&program,
|
||||
&[
|
||||
UniformName::new("niri_input_to_curr_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("niri_curr_geo_to_prev_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("niri_curr_geo_to_next_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("niri_geo_to_tex_prev", UniformType::Matrix3x3),
|
||||
UniformName::new("niri_geo_to_tex_next", UniformType::Matrix3x3),
|
||||
UniformName::new("niri_progress", UniformType::_1f),
|
||||
UniformName::new("niri_clamped_progress", UniformType::_1f),
|
||||
],
|
||||
&["niri_tex_prev", "niri_tex_next"],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_custom_resize_program(renderer: &mut GlesRenderer, src: Option<&str>) {
|
||||
let program = if let Some(src) = src {
|
||||
match PixelWithTexturesProgram::compile(
|
||||
renderer,
|
||||
src,
|
||||
&[
|
||||
UniformName::new("input_to_curr_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("input_to_prev_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("input_to_next_geo", UniformType::Matrix3x3),
|
||||
UniformName::new("geo_to_tex_prev", UniformType::Matrix3x3),
|
||||
UniformName::new("geo_to_tex_next", UniformType::Matrix3x3),
|
||||
UniformName::new("progress", UniformType::_1f),
|
||||
UniformName::new("clamped_progress", UniformType::_1f),
|
||||
],
|
||||
&["tex_prev", "tex_next"],
|
||||
) {
|
||||
match compile_resize_program(renderer, src) {
|
||||
Ok(program) => Some(program),
|
||||
Err(err) => {
|
||||
warn!("error compiling custom resize shader: {err:?}");
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
void main() {
|
||||
vec3 coords_curr_geo = niri_input_to_curr_geo * vec3(niri_v_coords, 1.0);
|
||||
vec3 size_curr_geo = niri_input_to_curr_geo * vec3(niri_size, 1.0);
|
||||
|
||||
vec4 color = resize_color(coords_curr_geo, size_curr_geo);
|
||||
|
||||
gl_FragColor = color * niri_alpha;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 niri_v_coords;
|
||||
uniform vec2 niri_size;
|
||||
|
||||
uniform mat3 niri_input_to_curr_geo;
|
||||
uniform mat3 niri_curr_geo_to_prev_geo;
|
||||
uniform mat3 niri_curr_geo_to_next_geo;
|
||||
|
||||
uniform sampler2D niri_tex_prev;
|
||||
uniform mat3 niri_geo_to_tex_prev;
|
||||
|
||||
uniform sampler2D niri_tex_next;
|
||||
uniform mat3 niri_geo_to_tex_next;
|
||||
|
||||
uniform float niri_progress;
|
||||
uniform float niri_clamped_progress;
|
||||
|
||||
uniform float niri_alpha;
|
||||
@@ -1,41 +1,10 @@
|
||||
#version 100
|
||||
vec4 resize_color(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
vec3 coords_tex_prev = niri_geo_to_tex_prev * coords_curr_geo;
|
||||
vec4 color_prev = texture2D(niri_tex_prev, coords_tex_prev.st);
|
||||
|
||||
precision mediump float;
|
||||
vec3 coords_tex_next = niri_geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color_next = texture2D(niri_tex_next, coords_tex_next.st);
|
||||
|
||||
varying vec2 v_coords;
|
||||
uniform vec2 size;
|
||||
|
||||
uniform mat3 input_to_curr_geo;
|
||||
uniform mat3 input_to_prev_geo;
|
||||
uniform mat3 input_to_next_geo;
|
||||
|
||||
uniform sampler2D tex_prev;
|
||||
uniform mat3 geo_to_tex_prev;
|
||||
|
||||
uniform sampler2D tex_next;
|
||||
uniform mat3 geo_to_tex_next;
|
||||
|
||||
uniform float progress;
|
||||
uniform float clamped_progress;
|
||||
|
||||
uniform float alpha;
|
||||
|
||||
vec4 crossfade() {
|
||||
vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
|
||||
|
||||
vec3 coords_tex_prev = geo_to_tex_prev * coords_curr_geo;
|
||||
vec4 color_prev = texture2D(tex_prev, vec2(coords_tex_prev));
|
||||
|
||||
vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color_next = texture2D(tex_next, vec2(coords_tex_next));
|
||||
|
||||
vec4 color = mix(color_prev, color_next, clamped_progress);
|
||||
vec4 color = mix(color_prev, color_next, niri_clamped_progress);
|
||||
return color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 color = crossfade();
|
||||
|
||||
gl_FragColor = color * alpha;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ uniform mat3 tex_matrix;
|
||||
attribute vec2 vert;
|
||||
attribute vec4 vert_position;
|
||||
|
||||
varying vec2 v_coords;
|
||||
varying vec2 niri_v_coords;
|
||||
|
||||
mat2 scale(vec2 scale_vec){
|
||||
return mat2(
|
||||
@@ -19,7 +19,7 @@ void main() {
|
||||
vec2 vert_transform_translation = vert_position.xy;
|
||||
vec2 vert_transform_scale = vert_position.zw;
|
||||
vec3 position = vec3(vert * scale(vert_transform_scale) + vert_transform_translation, 1.0);
|
||||
v_coords = (tex_matrix * position).xy;
|
||||
niri_v_coords = (tex_matrix * position).xy;
|
||||
gl_Position = vec4(matrix * position, 1.0);
|
||||
}
|
||||
|
||||
|
||||
@@ -234,31 +234,23 @@ See [this example shader](./examples/resize-custom-shader.frag) for a full docum
|
||||
|
||||
If a custom shader fails to compile, niri will print a warning and fall back to the default, or previous successfully compiled shader.
|
||||
|
||||
> [!NOTE]
|
||||
> [!WARNING]
|
||||
>
|
||||
> Custom shaders do not have a backwards compatibility guarantee.
|
||||
> I may need to change their interface as I'm developing new features.
|
||||
|
||||
Example: resize will show the next (after resize) window texture right away, stretched to the current geometry.
|
||||
|
||||
```
|
||||
animations {
|
||||
window-resize {
|
||||
spring damping-ratio=1.0 stiffness=800 epsilon=0.0001
|
||||
|
||||
custom-shader r"
|
||||
#version 100
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 v_coords;
|
||||
uniform mat3 input_to_curr_geo;
|
||||
uniform sampler2D tex_next;
|
||||
uniform mat3 geo_to_tex_next;
|
||||
uniform float alpha;
|
||||
|
||||
void main() {
|
||||
vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
|
||||
vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color = texture2D(tex_next, vec2(coords_tex_next));
|
||||
gl_FragColor = color * alpha;
|
||||
vec4 resize_color(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
vec3 coords_tex_next = niri_geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color = texture2D(niri_tex_next, coords_tex_next.st);
|
||||
return color;
|
||||
}
|
||||
"
|
||||
}
|
||||
|
||||
@@ -1,72 +1,87 @@
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Coordinates of the current pixel.
|
||||
// Your shader must contain one function (see the bottom of this file).
|
||||
//
|
||||
// These range from 0 to 1 over the whole area of the shader. The location and
|
||||
// the size of the area are unspecified, but niri will make it large enough to
|
||||
// accomodate a crossfade.
|
||||
// It should not contain any uniform definitions or anything else, as niri
|
||||
// provides them for you.
|
||||
//
|
||||
// You very likely want to convert these coordinates to geometry coordinates
|
||||
// before using them (see below).
|
||||
varying vec2 v_coords;
|
||||
// All symbols defined by niri will have a niri_ prefix, so don't use it for
|
||||
// your own variables and functions.
|
||||
|
||||
// Pixel size of the whole area of the shader.
|
||||
uniform vec2 size;
|
||||
// The function that you must define looks like this:
|
||||
vec4 resize_color(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
vec4 color = /* ...compute the color... */;
|
||||
return color;
|
||||
}
|
||||
|
||||
// Matrix that converts the input v_coords into coordinates inside the current
|
||||
// It takes as input:
|
||||
//
|
||||
// * coords_curr_geo: coordinates of the current pixel relative to the current
|
||||
// window geometry.
|
||||
//
|
||||
// These are homogeneous (the Z component is equal to 1) and scaled in such a
|
||||
// way that the 0 to 1 coordinates lie within the current window geometry (in
|
||||
// the middle of a resize). Pixels outside the window geometry will have
|
||||
// coordinates below 0 or above 1.
|
||||
//
|
||||
// The window geometry is its "visible bounds" from the user's perspective.
|
||||
// After applying this matrix, the 0 to 1 coordinate range will correspond to
|
||||
// the current geometry (in the middle of a resize), and pixels outside the
|
||||
// geometry will have coordinates below 0 or above 1.
|
||||
uniform mat3 input_to_curr_geo;
|
||||
//
|
||||
// The shader runs over an area of unspecified size and location, so you must
|
||||
// expect and handle coordinates outside the [0, 1] range. The area will be
|
||||
// large enough to accomodate a crossfade effect.
|
||||
//
|
||||
// * size_curr_geo: size of the current window geometry in physical pixels.
|
||||
//
|
||||
// It is homogeneous (the Z component is equal to 1).
|
||||
//
|
||||
// The function must return the color of the pixel (with premultiplied alpha).
|
||||
// The pixel color will be further processed by niri (for example, to apply the
|
||||
// final opacity from window rules).
|
||||
|
||||
// Matrix that converts the input v_coords into coordinates inside the previous
|
||||
// (before resize) window geometry.
|
||||
uniform mat3 input_to_prev_geo;
|
||||
|
||||
// Matrix that converts the input v_coords into coordinates inside the next
|
||||
// (after resize) window geometry.
|
||||
uniform mat3 input_to_next_geo;
|
||||
// Now let's go over the uniforms that niri defines.
|
||||
|
||||
// Previous (before resize) window texture.
|
||||
uniform sampler2D tex_prev;
|
||||
uniform sampler2D niri_tex_prev;
|
||||
|
||||
// Matrix that converts geometry coordinates into the previous window texture
|
||||
// coordinates.
|
||||
//
|
||||
// The window texture can and will go outside the geometry (for client-side
|
||||
// decoration shadows for example), which is why this matrix is necessary.
|
||||
uniform mat3 geo_to_tex_prev;
|
||||
uniform mat3 niri_geo_to_tex_prev;
|
||||
|
||||
// Next (after resize) window texture.
|
||||
uniform sampler2D tex_next;
|
||||
uniform sampler2D niri_tex_next;
|
||||
|
||||
// Matrix that converts geometry coordinates into the next window texture
|
||||
// coordinates.
|
||||
uniform mat3 geo_to_tex_next;
|
||||
uniform mat3 niri_geo_to_tex_next;
|
||||
|
||||
|
||||
// Matrix that converts coords_curr_geo into coordinates inside the previous
|
||||
// (before resize) window geometry.
|
||||
uniform mat3 niri_curr_geo_to_prev_geo;
|
||||
|
||||
// Matrix that converts coords_curr_geo into coordinates inside the next
|
||||
// (after resize) window geometry.
|
||||
uniform mat3 niri_curr_geo_to_next_geo;
|
||||
|
||||
|
||||
// Unclamped progress of the resize.
|
||||
//
|
||||
// Goes from 0 to 1 but may overshoot and oscillate.
|
||||
uniform float progress;
|
||||
uniform float niri_progress;
|
||||
|
||||
// Clamped progress of the resize.
|
||||
//
|
||||
// Goes from 0 to 1, but will stop at 1 as soon as it first reaches 1. Will not
|
||||
// overshoot or oscillate.
|
||||
uniform float clamped_progress;
|
||||
uniform float niri_clamped_progress;
|
||||
|
||||
// Additional opacity to apply to the final color.
|
||||
uniform float alpha;
|
||||
// Now let's look at some examples. You can copy everything below this line
|
||||
// into your custom-shader to experiment.
|
||||
|
||||
// Example: fill the current geometry with a solid vertical gradient.
|
||||
vec4 solid_gradient() {
|
||||
vec3 coords = input_to_curr_geo * vec3(v_coords, 1.0);
|
||||
|
||||
vec4 solid_gradient(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
vec3 coords = coords_curr_geo;
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
// Paint only the area inside the current geometry.
|
||||
@@ -83,35 +98,33 @@ vec4 solid_gradient() {
|
||||
|
||||
// Example: crossfade between previous and next texture, stretched to the
|
||||
// current geometry.
|
||||
vec4 crossfade() {
|
||||
vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
|
||||
vec4 crossfade(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
// Convert coordinates into the texture space for sampling.
|
||||
vec3 coords_tex_prev = niri_geo_to_tex_prev * coords_curr_geo;
|
||||
vec4 color_prev = texture2D(niri_tex_prev, coords_tex_prev.st);
|
||||
|
||||
vec3 coords_tex_prev = geo_to_tex_prev * coords_curr_geo;
|
||||
vec4 color_prev = texture2D(tex_prev, vec2(coords_tex_prev));
|
||||
// Convert coordinates into the texture space for sampling.
|
||||
vec3 coords_tex_next = niri_geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color_next = texture2D(niri_tex_next, coords_tex_next.st);
|
||||
|
||||
vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color_next = texture2D(tex_next, vec2(coords_tex_next));
|
||||
|
||||
vec4 color = mix(color_prev, color_next, clamped_progress);
|
||||
vec4 color = mix(color_prev, color_next, niri_clamped_progress);
|
||||
return color;
|
||||
}
|
||||
|
||||
// Example: next texture, stretched to the current geometry.
|
||||
vec4 stretch_next() {
|
||||
vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
|
||||
vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color = texture2D(tex_next, vec2(coords_tex_next));
|
||||
vec4 stretch_next(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
vec3 coords_tex_next = niri_geo_to_tex_next * coords_curr_geo;
|
||||
vec4 color = texture2D(niri_tex_next, coords_tex_next.st);
|
||||
return color;
|
||||
}
|
||||
|
||||
// Example: next texture, stretched to the current geometry if smaller, and
|
||||
// cropped if bigger.
|
||||
vec4 stretch_or_crop_next() {
|
||||
vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
|
||||
vec3 coords_next_geo = input_to_next_geo * vec3(v_coords, 1.0);
|
||||
vec4 stretch_or_crop_next(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
vec3 coords_next_geo = niri_curr_geo_to_next_geo * coords_curr_geo;
|
||||
|
||||
vec3 coords_stretch = geo_to_tex_next * coords_curr_geo;
|
||||
vec3 coords_crop = geo_to_tex_next * coords_next_geo;
|
||||
vec3 coords_stretch = niri_geo_to_tex_next * coords_curr_geo;
|
||||
vec3 coords_crop = niri_geo_to_tex_next * coords_next_geo;
|
||||
|
||||
// If the crop coord is smaller than the stretch coord, then the next
|
||||
// texture size is bigger than the current geometry, which means that we
|
||||
@@ -122,7 +135,7 @@ vec4 stretch_or_crop_next() {
|
||||
if (coords_crop.y < coords_stretch.y)
|
||||
coords.y = coords_crop.y;
|
||||
|
||||
vec4 color = texture2D(tex_next, vec2(coords));
|
||||
vec4 color = texture2D(niri_tex_next, coords.st);
|
||||
|
||||
// However, when we crop, we also want to crop out anything outside the
|
||||
// current geometry. This is because the area of the shader is unspecified
|
||||
@@ -142,11 +155,9 @@ vec4 stretch_or_crop_next() {
|
||||
return color;
|
||||
}
|
||||
|
||||
// The main entry point of the shader.
|
||||
void main() {
|
||||
// This is the function that you must define.
|
||||
vec4 resize_color(vec3 coords_curr_geo, vec3 size_curr_geo) {
|
||||
// You can pick one of the example functions or write your own.
|
||||
vec4 color = stretch_or_crop_next();
|
||||
|
||||
gl_FragColor = color * alpha;
|
||||
return stretch_or_crop_next(coords_curr_geo, size_curr_geo);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user