2024-05-12 09:52:21 +04:00
|
|
|
use std::collections::HashMap;
|
2024-04-09 22:37:10 +04:00
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
|
|
use anyhow::Context as _;
|
2024-05-12 09:52:21 +04:00
|
|
|
use glam::{Mat3, Vec2};
|
2024-04-09 22:37:10 +04:00
|
|
|
use niri_config::BlockOutFrom;
|
|
|
|
|
use smithay::backend::allocator::Fourcc;
|
|
|
|
|
use smithay::backend::renderer::element::utils::{
|
|
|
|
|
Relocate, RelocateRenderElement, RescaleRenderElement,
|
|
|
|
|
};
|
2024-06-01 12:27:30 +03:00
|
|
|
use smithay::backend::renderer::element::{Kind, RenderElement};
|
2024-05-12 09:52:21 +04:00
|
|
|
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture, Uniform};
|
2024-06-01 12:27:30 +03:00
|
|
|
use smithay::backend::renderer::Texture;
|
2024-05-12 08:46:02 +04:00
|
|
|
use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
|
2024-04-09 22:37:10 +04:00
|
|
|
|
|
|
|
|
use crate::animation::Animation;
|
|
|
|
|
use crate::niri_render_elements;
|
|
|
|
|
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
2024-05-12 09:52:21 +04:00
|
|
|
use crate::render_helpers::shader_element::ShaderRenderElement;
|
|
|
|
|
use crate::render_helpers::shaders::{mat3_uniform, ProgramType, Shaders};
|
2024-04-13 14:16:07 +04:00
|
|
|
use crate::render_helpers::snapshot::RenderSnapshot;
|
2024-06-01 12:27:30 +03:00
|
|
|
use crate::render_helpers::texture::{TextureBuffer, TextureRenderElement};
|
2024-04-13 14:16:07 +04:00
|
|
|
use crate::render_helpers::{render_to_encompassing_texture, RenderTarget};
|
2024-04-09 22:37:10 +04:00
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct ClosingWindow {
|
|
|
|
|
/// Contents of the window.
|
2024-06-01 12:27:30 +03:00
|
|
|
buffer: TextureBuffer<GlesTexture>,
|
2024-04-09 22:37:10 +04:00
|
|
|
|
|
|
|
|
/// Blocked-out contents of the window.
|
2024-06-01 12:27:30 +03:00
|
|
|
blocked_out_buffer: TextureBuffer<GlesTexture>,
|
2024-04-09 22:37:10 +04:00
|
|
|
|
|
|
|
|
/// Where the window should be blocked out from.
|
|
|
|
|
block_out_from: Option<BlockOutFrom>,
|
|
|
|
|
|
2024-05-12 08:46:02 +04:00
|
|
|
/// Size of the window geometry.
|
2024-06-17 09:16:28 +03:00
|
|
|
geo_size: Size<f64, Logical>,
|
2024-04-09 22:37:10 +04:00
|
|
|
|
|
|
|
|
/// Position in the workspace.
|
2024-06-17 09:16:28 +03:00
|
|
|
pos: Point<f64, Logical>,
|
2024-04-09 22:37:10 +04:00
|
|
|
|
2024-05-11 17:54:27 +04:00
|
|
|
/// How much the texture should be offset.
|
2024-06-01 12:27:30 +03:00
|
|
|
buffer_offset: Point<f64, Logical>,
|
2024-04-09 22:37:10 +04:00
|
|
|
|
2024-05-11 17:54:27 +04:00
|
|
|
/// How much the blocked-out texture should be offset.
|
2024-06-01 12:27:30 +03:00
|
|
|
blocked_out_buffer_offset: Point<f64, Logical>,
|
2024-04-09 22:37:10 +04:00
|
|
|
|
|
|
|
|
/// The closing animation.
|
|
|
|
|
anim: Animation,
|
2024-05-12 09:52:21 +04:00
|
|
|
|
|
|
|
|
/// Random seed for the shader.
|
|
|
|
|
random_seed: f32,
|
2024-04-09 22:37:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
niri_render_elements! {
|
|
|
|
|
ClosingWindowRenderElement => {
|
|
|
|
|
Texture = RelocateRenderElement<RescaleRenderElement<PrimaryGpuTextureRenderElement>>,
|
2024-05-12 09:52:21 +04:00
|
|
|
Shader = ShaderRenderElement,
|
2024-04-09 22:37:10 +04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ClosingWindow {
|
|
|
|
|
pub fn new<E: RenderElement<GlesRenderer>>(
|
|
|
|
|
renderer: &mut GlesRenderer,
|
2024-04-10 08:53:35 +04:00
|
|
|
snapshot: RenderSnapshot<E, E>,
|
2024-05-11 17:54:27 +04:00
|
|
|
scale: Scale<f64>,
|
2024-06-17 09:16:28 +03:00
|
|
|
geo_size: Size<f64, Logical>,
|
|
|
|
|
pos: Point<f64, Logical>,
|
2024-04-09 22:37:10 +04:00
|
|
|
anim: Animation,
|
|
|
|
|
) -> anyhow::Result<Self> {
|
|
|
|
|
let _span = tracy_client::span!("ClosingWindow::new");
|
|
|
|
|
|
2024-05-11 17:54:27 +04:00
|
|
|
let mut render_to_texture = |elements: Vec<E>| -> anyhow::Result<_> {
|
2024-04-12 20:38:51 +04:00
|
|
|
let (texture, _sync_point, geo) = render_to_encompassing_texture(
|
2024-04-09 22:37:10 +04:00
|
|
|
renderer,
|
2024-05-11 17:54:27 +04:00
|
|
|
scale,
|
2024-04-09 22:37:10 +04:00
|
|
|
Transform::Normal,
|
|
|
|
|
Fourcc::Abgr8888,
|
2024-04-12 20:38:51 +04:00
|
|
|
&elements,
|
2024-04-09 22:37:10 +04:00
|
|
|
)
|
|
|
|
|
.context("error rendering to texture")?;
|
|
|
|
|
|
2024-06-01 12:27:30 +03:00
|
|
|
let buffer = TextureBuffer::from_texture(
|
|
|
|
|
renderer,
|
|
|
|
|
texture,
|
|
|
|
|
scale,
|
|
|
|
|
Transform::Normal,
|
|
|
|
|
Vec::new(),
|
|
|
|
|
);
|
|
|
|
|
|
2024-05-11 17:54:27 +04:00
|
|
|
let offset = geo.loc.to_f64().to_logical(scale);
|
2024-04-12 20:38:51 +04:00
|
|
|
|
2024-06-01 12:27:30 +03:00
|
|
|
Ok((buffer, offset))
|
2024-04-09 22:37:10 +04:00
|
|
|
};
|
|
|
|
|
|
2024-06-01 12:27:30 +03:00
|
|
|
let (buffer, buffer_offset) =
|
2024-05-11 17:54:27 +04:00
|
|
|
render_to_texture(snapshot.contents).context("error rendering contents")?;
|
2024-06-01 12:27:30 +03:00
|
|
|
let (blocked_out_buffer, blocked_out_buffer_offset) =
|
2024-05-11 17:54:27 +04:00
|
|
|
render_to_texture(snapshot.blocked_out_contents)
|
2024-04-09 22:37:10 +04:00
|
|
|
.context("error rendering blocked-out contents")?;
|
|
|
|
|
|
|
|
|
|
Ok(Self {
|
2024-06-01 12:27:30 +03:00
|
|
|
buffer,
|
|
|
|
|
blocked_out_buffer,
|
2024-04-09 22:37:10 +04:00
|
|
|
block_out_from: snapshot.block_out_from,
|
2024-05-12 08:46:02 +04:00
|
|
|
geo_size,
|
2024-04-09 22:37:10 +04:00
|
|
|
pos,
|
2024-06-01 12:27:30 +03:00
|
|
|
buffer_offset,
|
|
|
|
|
blocked_out_buffer_offset,
|
2024-04-09 22:37:10 +04:00
|
|
|
anim,
|
2024-05-12 09:52:21 +04:00
|
|
|
random_seed: fastrand::f32(),
|
2024-04-09 22:37:10 +04:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn advance_animations(&mut self, current_time: Duration) {
|
|
|
|
|
self.anim.set_current_time(current_time);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn are_animations_ongoing(&self) -> bool {
|
2024-05-12 09:52:21 +04:00
|
|
|
!self.anim.is_done()
|
2024-04-09 22:37:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn render(
|
|
|
|
|
&self,
|
2024-05-12 09:52:21 +04:00
|
|
|
renderer: &mut GlesRenderer,
|
2024-06-17 09:16:28 +03:00
|
|
|
view_rect: Rectangle<f64, Logical>,
|
2024-04-09 22:37:10 +04:00
|
|
|
scale: Scale<f64>,
|
|
|
|
|
target: RenderTarget,
|
|
|
|
|
) -> ClosingWindowRenderElement {
|
2024-05-12 09:52:21 +04:00
|
|
|
let progress = self.anim.value();
|
|
|
|
|
let clamped_progress = self.anim.clamped_value().clamp(0., 1.);
|
2024-04-09 22:37:10 +04:00
|
|
|
|
2024-06-01 12:27:30 +03:00
|
|
|
let (buffer, offset) = if target.should_block_out(self.block_out_from) {
|
|
|
|
|
(&self.blocked_out_buffer, self.blocked_out_buffer_offset)
|
2024-04-09 22:37:10 +04:00
|
|
|
} else {
|
2024-06-01 12:27:30 +03:00
|
|
|
(&self.buffer, self.buffer_offset)
|
2024-04-09 22:37:10 +04:00
|
|
|
};
|
|
|
|
|
|
2024-05-12 09:52:21 +04:00
|
|
|
if Shaders::get(renderer).program(ProgramType::Close).is_some() {
|
|
|
|
|
let area_loc = Vec2::new(view_rect.loc.x as f32, view_rect.loc.y as f32);
|
|
|
|
|
let area_size = Vec2::new(view_rect.size.w as f32, view_rect.size.h as f32);
|
|
|
|
|
|
2024-06-17 09:16:28 +03:00
|
|
|
// Round to physical pixels relative to the view position. This is similar to what
|
|
|
|
|
// happens when rendering normal windows.
|
|
|
|
|
let relative = self.pos - view_rect.loc;
|
|
|
|
|
let pos = view_rect.loc + relative.to_physical_precise_round(scale).to_logical(scale);
|
|
|
|
|
|
|
|
|
|
let geo_loc = Vec2::new(pos.x as f32, pos.y as f32);
|
2024-05-12 09:52:21 +04:00
|
|
|
let geo_size = Vec2::new(self.geo_size.w as f32, self.geo_size.h as f32);
|
|
|
|
|
|
|
|
|
|
let input_to_geo = Mat3::from_scale(area_size / geo_size)
|
|
|
|
|
* Mat3::from_translation((area_loc - geo_loc) / area_size);
|
|
|
|
|
|
2024-06-01 12:27:30 +03:00
|
|
|
let tex_scale = self.buffer.texture_scale();
|
|
|
|
|
let tex_scale = Vec2::new(tex_scale.x as f32, tex_scale.y as f32);
|
2024-05-12 09:52:21 +04:00
|
|
|
let tex_loc = Vec2::new(offset.x as f32, offset.y as f32);
|
2024-06-01 12:27:30 +03:00
|
|
|
let tex_size = self.buffer.texture().size();
|
|
|
|
|
let tex_size = Vec2::new(tex_size.w as f32, tex_size.h as f32) / tex_scale;
|
2024-05-12 09:52:21 +04:00
|
|
|
|
|
|
|
|
let geo_to_tex =
|
|
|
|
|
Mat3::from_translation(-tex_loc / tex_size) * Mat3::from_scale(geo_size / tex_size);
|
|
|
|
|
|
|
|
|
|
return ShaderRenderElement::new(
|
|
|
|
|
ProgramType::Close,
|
|
|
|
|
view_rect.size,
|
|
|
|
|
None,
|
|
|
|
|
1.,
|
|
|
|
|
vec![
|
|
|
|
|
mat3_uniform("niri_input_to_geo", input_to_geo),
|
|
|
|
|
Uniform::new("niri_geo_size", geo_size.to_array()),
|
|
|
|
|
mat3_uniform("niri_geo_to_tex", geo_to_tex),
|
|
|
|
|
Uniform::new("niri_progress", progress as f32),
|
|
|
|
|
Uniform::new("niri_clamped_progress", clamped_progress as f32),
|
|
|
|
|
Uniform::new("niri_random_seed", self.random_seed),
|
|
|
|
|
],
|
2024-06-01 12:27:30 +03:00
|
|
|
HashMap::from([(String::from("niri_tex"), buffer.texture().clone())]),
|
2024-05-12 09:52:21 +04:00
|
|
|
Kind::Unspecified,
|
|
|
|
|
)
|
2024-06-17 09:16:28 +03:00
|
|
|
.with_location(Point::from((0., 0.)))
|
2024-05-12 09:52:21 +04:00
|
|
|
.into();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-01 12:27:30 +03:00
|
|
|
let elem = TextureRenderElement::from_texture_buffer(
|
|
|
|
|
buffer.clone(),
|
2024-04-09 22:37:10 +04:00
|
|
|
Point::from((0., 0.)),
|
2024-06-01 12:27:30 +03:00
|
|
|
1. - clamped_progress as f32,
|
2024-04-09 22:37:10 +04:00
|
|
|
None,
|
2024-05-11 17:54:27 +04:00
|
|
|
None,
|
2024-04-09 22:37:10 +04:00
|
|
|
Kind::Unspecified,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let elem = PrimaryGpuTextureRenderElement(elem);
|
|
|
|
|
|
2024-06-17 09:16:28 +03:00
|
|
|
let center = self.geo_size.to_point().downscale(2.);
|
2024-04-09 22:37:10 +04:00
|
|
|
let elem = RescaleRenderElement::from_element(
|
|
|
|
|
elem,
|
2024-05-12 08:46:02 +04:00
|
|
|
(center - offset).to_physical_precise_round(scale),
|
2024-05-12 09:52:21 +04:00
|
|
|
((1. - clamped_progress) / 5. + 0.8).max(0.),
|
2024-04-09 22:37:10 +04:00
|
|
|
);
|
|
|
|
|
|
2024-06-17 09:16:28 +03:00
|
|
|
let mut location = self.pos + offset;
|
|
|
|
|
location.x -= view_rect.loc.x;
|
2024-04-09 22:37:10 +04:00
|
|
|
let elem = RelocateRenderElement::from_element(
|
|
|
|
|
elem,
|
|
|
|
|
location.to_physical_precise_round(scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
elem.into()
|
|
|
|
|
}
|
|
|
|
|
}
|