Compare commits

...

2 Commits

Author SHA1 Message Date
Ivan Molodetskikh 88b74f4a3a Remove unnecessary crop bounds during workspace switch 2024-02-13 09:32:49 +04:00
Ivan Molodetskikh b94b0c7fa4 Use nearest scaling for integer-upscaled surfaces 2024-02-13 09:32:49 +04:00
7 changed files with 172 additions and 35 deletions
Generated
+2 -2
View File
@@ -3005,7 +3005,7 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
[[package]]
name = "smithay"
version = "0.3.0"
source = "git+https://github.com/Smithay/smithay.git#91e61f13501f21d66803efac947bfafed43080c5"
source = "git+https://github.com/YaLTeR/smithay.git?rev=0c06b7889b72e4392d89fab91f2d2cf4f272db83#0c06b7889b72e4392d89fab91f2d2cf4f272db83"
dependencies = [
"appendlist",
"bitflags 2.4.2",
@@ -3077,7 +3077,7 @@ dependencies = [
[[package]]
name = "smithay-drm-extras"
version = "0.1.0"
source = "git+https://github.com/Smithay/smithay.git#91e61f13501f21d66803efac947bfafed43080c5"
source = "git+https://github.com/YaLTeR/smithay.git?rev=0c06b7889b72e4392d89fab91f2d2cf4f272db83#0c06b7889b72e4392d89fab91f2d2cf4f272db83"
dependencies = [
"drm",
"edid-rs",
+4 -2
View File
@@ -19,12 +19,14 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracy-client = { version = "0.16.5", default-features = false }
[workspace.dependencies.smithay]
git = "https://github.com/Smithay/smithay.git"
git = "https://github.com/YaLTeR/smithay.git"
rev = "0c06b7889b72e4392d89fab91f2d2cf4f272db83"
# path = "../smithay"
default-features = false
[workspace.dependencies.smithay-drm-extras]
git = "https://github.com/Smithay/smithay.git"
git = "https://github.com/YaLTeR/smithay.git"
rev = "0c06b7889b72e4392d89fab91f2d2cf4f272db83"
# path = "../smithay/smithay-drm-extras"
[package]
+9 -3
View File
@@ -55,6 +55,7 @@ use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Works
use crate::animation::Animation;
use crate::niri::WindowOffscreenId;
use crate::niri_render_elements;
use crate::render_helpers::nearest_integer_scale::NearestIntegerScale;
use crate::render_helpers::renderer::NiriRenderer;
use crate::utils::output_size;
@@ -65,7 +66,7 @@ pub mod workspace;
niri_render_elements! {
LayoutElementRenderElement => {
Wayland = WaylandSurfaceRenderElement<R>,
Wayland = NearestIntegerScale<WaylandSurfaceRenderElement<R>>,
SolidColor = SolidColorRenderElement,
}
}
@@ -238,12 +239,17 @@ impl LayoutElement for Window {
scale: Scale<f64>,
) -> Vec<LayoutElementRenderElement<R>> {
let buf_pos = location - self.geometry().loc;
self.render_elements(
let elements: Vec<WaylandSurfaceRenderElement<R>> = self.render_elements(
renderer,
buf_pos.to_physical_precise_round(scale),
scale,
1.,
)
);
elements
.into_iter()
.map(NearestIntegerScale::from)
.map(LayoutElementRenderElement::from)
.collect()
}
fn request_size(&self, size: Size<i32, Logical>) {
+11 -2
View File
@@ -629,12 +629,18 @@ impl<W: LayoutElement> Monitor<W> {
let before = self.workspaces[before_idx].render_elements(renderer);
let after = self.workspaces[after_idx].render_elements(renderer);
// HACK: crop to infinite bounds for all sides except the side where the workspaces
// join, to decrease the chance of cutting a lower-scale surface in the middle of a
// pixel, thereby disabling its nearest-neighbor upscaling.
let before = before.into_iter().filter_map(|elem| {
Some(RelocateRenderElement::from_element(
CropRenderElement::from_element(
elem,
output_scale,
Rectangle::from_extemities((0, offset), (size.w, size.h)),
Rectangle::from_extemities(
(-i32::MAX / 2, -i32::MAX / 2),
(i32::MAX / 2, size.h),
),
)?,
(0, -offset),
Relocate::Relative,
@@ -645,7 +651,10 @@ impl<W: LayoutElement> Monitor<W> {
CropRenderElement::from_element(
elem,
output_scale,
Rectangle::from_extemities((0, 0), (size.w, offset)),
Rectangle::from_extemities(
(-i32::MAX / 2, 0),
(i32::MAX / 2, i32::MAX / 2),
),
)?,
(0, -offset + size.h),
Relocate::Relative,
+45 -26
View File
@@ -101,6 +101,7 @@ use crate::ipc::server::IpcServer;
use crate::layout::{Layout, MonitorRenderElement};
use crate::protocols::foreign_toplevel::{self, ForeignToplevelManagerState};
use crate::pw_utils::{Cast, PipeWire};
use crate::render_helpers::nearest_integer_scale::NearestIntegerScale;
use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::{render_to_texture, render_to_vec};
use crate::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement};
@@ -1693,14 +1694,20 @@ impl Niri {
let pointer_pos =
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
let pointer_elements = render_elements_from_surface_tree(
renderer,
&surface,
pointer_pos,
output_scale,
1.,
Kind::Cursor,
);
let pointer_elements: Vec<WaylandSurfaceRenderElement<_>> =
render_elements_from_surface_tree(
renderer,
&surface,
pointer_pos,
output_scale,
1.,
Kind::Cursor,
);
let pointer_elements = pointer_elements
.into_iter()
.map(NearestIntegerScale::from)
.map(OutputRenderElements::from)
.collect();
(pointer_elements, pointer_pos)
}
@@ -1740,14 +1747,20 @@ impl Niri {
};
if let Some(dnd_icon) = &self.dnd_icon {
pointer_elements.extend(render_elements_from_surface_tree(
renderer,
dnd_icon,
pointer_pos,
output_scale,
1.,
Kind::Unspecified,
));
let dnd_elements: Vec<WaylandSurfaceRenderElement<_>> =
render_elements_from_surface_tree(
renderer,
dnd_icon,
pointer_pos,
output_scale,
1.,
Kind::Unspecified,
);
let dnd_elements = dnd_elements
.into_iter()
.map(NearestIntegerScale::from)
.map(OutputRenderElements::from);
pointer_elements.extend(dnd_elements);
}
pointer_elements
@@ -1923,14 +1936,20 @@ impl Niri {
if self.is_locked() {
let state = self.output_state.get(output).unwrap();
if let Some(surface) = state.lock_surface.as_ref() {
elements.extend(render_elements_from_surface_tree(
renderer,
surface.wl_surface(),
(0, 0),
output_scale,
1.,
Kind::Unspecified,
));
let lock_elements: Vec<WaylandSurfaceRenderElement<_>> =
render_elements_from_surface_tree(
renderer,
surface.wl_surface(),
(0, 0),
output_scale,
1.,
Kind::Unspecified,
);
let lock_elements = lock_elements
.into_iter()
.map(NearestIntegerScale::from)
.map(OutputRenderElements::from);
elements.extend(lock_elements);
}
// Draw the solid color background.
@@ -2688,7 +2707,7 @@ impl Niri {
scale,
1.,
);
let elements = elements.iter().rev();
let elements = elements.iter().map(NearestIntegerScale::from).rev();
let pixels = render_to_vec(renderer, size, scale, Fourcc::Abgr8888, elements)?;
self.save_screenshot(size, pixels)
@@ -2945,7 +2964,7 @@ impl ClientData for ClientState {
niri_render_elements! {
OutputRenderElements => {
Monitor = MonitorRenderElement<R>,
Wayland = WaylandSurfaceRenderElement<R>,
Wayland = NearestIntegerScale<WaylandSurfaceRenderElement<R>>,
NamedPointer = MemoryRenderBufferRenderElement<R>,
SolidColor = SolidColorRenderElement,
ScreenshotUi = ScreenshotUiRenderElement,
+1
View File
@@ -6,6 +6,7 @@ use smithay::backend::renderer::sync::SyncPoint;
use smithay::backend::renderer::{Bind, ExportMem, Frame, Offscreen, Renderer};
use smithay::utils::{Physical, Rectangle, Scale, Size, Transform};
pub mod nearest_integer_scale;
pub mod offscreen;
pub mod primary_gpu_texture;
pub mod render_elements;
+100
View File
@@ -0,0 +1,100 @@
use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
use smithay::backend::renderer::utils::CommitCounter;
use smithay::backend::renderer::{Frame, Renderer, TextureFilter};
use smithay::utils::{Buffer, Physical, Rectangle, Scale, Transform};
#[derive(Debug)]
pub struct NearestIntegerScale<E: Element>(E);
impl<E: Element> From<E> for NearestIntegerScale<E> {
fn from(value: E) -> Self {
Self(value)
}
}
impl<E: Element> Element for NearestIntegerScale<E> {
fn id(&self) -> &Id {
self.0.id()
}
fn current_commit(&self) -> CommitCounter {
self.0.current_commit()
}
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
self.0.geometry(scale)
}
fn transform(&self) -> Transform {
self.0.transform()
}
fn src(&self) -> Rectangle<f64, Buffer> {
self.0.src()
}
fn damage_since(
&self,
scale: Scale<f64>,
commit: Option<CommitCounter>,
) -> Vec<Rectangle<i32, Physical>> {
self.0.damage_since(scale, commit)
}
fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
self.0.opaque_regions(scale)
}
fn alpha(&self) -> f32 {
self.0.alpha()
}
fn kind(&self) -> Kind {
self.0.kind()
}
}
impl<R: Renderer, E: RenderElement<R>> RenderElement<R> for NearestIntegerScale<E> {
fn draw(
&self,
frame: &mut <R as Renderer>::Frame<'_>,
src: Rectangle<f64, Buffer>,
dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
) -> Result<(), R::Error> {
let mut use_nearest = false;
// Check that we don't need to interpolate between src pixels.
let src_i32 = src.to_i32_down::<i32>();
if src_i32.to_f64() == src {
// Check that the src is not zero.
if !src_i32.size.is_empty() {
// Check that the scale factor is an integer.
let scale_x = dst.size.w / src_i32.size.w;
let scale_y = dst.size.h / src_i32.size.h;
if scale_x * src_i32.size.w == dst.size.w && scale_y * src_i32.size.h == dst.size.h
{
use_nearest = true;
}
}
}
let mut prev_filter = TextureFilter::Linear;
if use_nearest {
prev_filter = frame.upscale_filter();
frame.set_upscale_filter(TextureFilter::Nearest);
}
let rv = self.0.draw(frame, src, dst, damage);
if use_nearest {
frame.set_upscale_filter(prev_filter);
}
rv
}
fn underlying_storage(&self, renderer: &mut R) -> Option<UnderlyingStorage> {
self.0.underlying_storage(renderer)
}
}