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]] [[package]]
name = "smithay" name = "smithay"
version = "0.3.0" 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 = [ dependencies = [
"appendlist", "appendlist",
"bitflags 2.4.2", "bitflags 2.4.2",
@@ -3077,7 +3077,7 @@ dependencies = [
[[package]] [[package]]
name = "smithay-drm-extras" name = "smithay-drm-extras"
version = "0.1.0" 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 = [ dependencies = [
"drm", "drm",
"edid-rs", "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 } tracy-client = { version = "0.16.5", default-features = false }
[workspace.dependencies.smithay] [workspace.dependencies.smithay]
git = "https://github.com/Smithay/smithay.git" git = "https://github.com/YaLTeR/smithay.git"
rev = "0c06b7889b72e4392d89fab91f2d2cf4f272db83"
# path = "../smithay" # path = "../smithay"
default-features = false default-features = false
[workspace.dependencies.smithay-drm-extras] [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" # path = "../smithay/smithay-drm-extras"
[package] [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::animation::Animation;
use crate::niri::WindowOffscreenId; use crate::niri::WindowOffscreenId;
use crate::niri_render_elements; use crate::niri_render_elements;
use crate::render_helpers::nearest_integer_scale::NearestIntegerScale;
use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::renderer::NiriRenderer;
use crate::utils::output_size; use crate::utils::output_size;
@@ -65,7 +66,7 @@ pub mod workspace;
niri_render_elements! { niri_render_elements! {
LayoutElementRenderElement => { LayoutElementRenderElement => {
Wayland = WaylandSurfaceRenderElement<R>, Wayland = NearestIntegerScale<WaylandSurfaceRenderElement<R>>,
SolidColor = SolidColorRenderElement, SolidColor = SolidColorRenderElement,
} }
} }
@@ -238,12 +239,17 @@ impl LayoutElement for Window {
scale: Scale<f64>, scale: Scale<f64>,
) -> Vec<LayoutElementRenderElement<R>> { ) -> Vec<LayoutElementRenderElement<R>> {
let buf_pos = location - self.geometry().loc; let buf_pos = location - self.geometry().loc;
self.render_elements( let elements: Vec<WaylandSurfaceRenderElement<R>> = self.render_elements(
renderer, renderer,
buf_pos.to_physical_precise_round(scale), buf_pos.to_physical_precise_round(scale),
scale, scale,
1., 1.,
) );
elements
.into_iter()
.map(NearestIntegerScale::from)
.map(LayoutElementRenderElement::from)
.collect()
} }
fn request_size(&self, size: Size<i32, Logical>) { 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 before = self.workspaces[before_idx].render_elements(renderer);
let after = self.workspaces[after_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| { let before = before.into_iter().filter_map(|elem| {
Some(RelocateRenderElement::from_element( Some(RelocateRenderElement::from_element(
CropRenderElement::from_element( CropRenderElement::from_element(
elem, elem,
output_scale, 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), (0, -offset),
Relocate::Relative, Relocate::Relative,
@@ -645,7 +651,10 @@ impl<W: LayoutElement> Monitor<W> {
CropRenderElement::from_element( CropRenderElement::from_element(
elem, elem,
output_scale, 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), (0, -offset + size.h),
Relocate::Relative, Relocate::Relative,
+45 -26
View File
@@ -101,6 +101,7 @@ use crate::ipc::server::IpcServer;
use crate::layout::{Layout, MonitorRenderElement}; use crate::layout::{Layout, MonitorRenderElement};
use crate::protocols::foreign_toplevel::{self, ForeignToplevelManagerState}; use crate::protocols::foreign_toplevel::{self, ForeignToplevelManagerState};
use crate::pw_utils::{Cast, PipeWire}; use crate::pw_utils::{Cast, PipeWire};
use crate::render_helpers::nearest_integer_scale::NearestIntegerScale;
use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::{render_to_texture, render_to_vec}; use crate::render_helpers::{render_to_texture, render_to_vec};
use crate::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement}; use crate::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement};
@@ -1693,14 +1694,20 @@ impl Niri {
let pointer_pos = let pointer_pos =
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale); (pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
let pointer_elements = render_elements_from_surface_tree( let pointer_elements: Vec<WaylandSurfaceRenderElement<_>> =
renderer, render_elements_from_surface_tree(
&surface, renderer,
pointer_pos, &surface,
output_scale, pointer_pos,
1., output_scale,
Kind::Cursor, 1.,
); Kind::Cursor,
);
let pointer_elements = pointer_elements
.into_iter()
.map(NearestIntegerScale::from)
.map(OutputRenderElements::from)
.collect();
(pointer_elements, pointer_pos) (pointer_elements, pointer_pos)
} }
@@ -1740,14 +1747,20 @@ impl Niri {
}; };
if let Some(dnd_icon) = &self.dnd_icon { if let Some(dnd_icon) = &self.dnd_icon {
pointer_elements.extend(render_elements_from_surface_tree( let dnd_elements: Vec<WaylandSurfaceRenderElement<_>> =
renderer, render_elements_from_surface_tree(
dnd_icon, renderer,
pointer_pos, dnd_icon,
output_scale, pointer_pos,
1., output_scale,
Kind::Unspecified, 1.,
)); Kind::Unspecified,
);
let dnd_elements = dnd_elements
.into_iter()
.map(NearestIntegerScale::from)
.map(OutputRenderElements::from);
pointer_elements.extend(dnd_elements);
} }
pointer_elements pointer_elements
@@ -1923,14 +1936,20 @@ impl Niri {
if self.is_locked() { if self.is_locked() {
let state = self.output_state.get(output).unwrap(); let state = self.output_state.get(output).unwrap();
if let Some(surface) = state.lock_surface.as_ref() { if let Some(surface) = state.lock_surface.as_ref() {
elements.extend(render_elements_from_surface_tree( let lock_elements: Vec<WaylandSurfaceRenderElement<_>> =
renderer, render_elements_from_surface_tree(
surface.wl_surface(), renderer,
(0, 0), surface.wl_surface(),
output_scale, (0, 0),
1., output_scale,
Kind::Unspecified, 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. // Draw the solid color background.
@@ -2688,7 +2707,7 @@ impl Niri {
scale, scale,
1., 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)?; let pixels = render_to_vec(renderer, size, scale, Fourcc::Abgr8888, elements)?;
self.save_screenshot(size, pixels) self.save_screenshot(size, pixels)
@@ -2945,7 +2964,7 @@ impl ClientData for ClientState {
niri_render_elements! { niri_render_elements! {
OutputRenderElements => { OutputRenderElements => {
Monitor = MonitorRenderElement<R>, Monitor = MonitorRenderElement<R>,
Wayland = WaylandSurfaceRenderElement<R>, Wayland = NearestIntegerScale<WaylandSurfaceRenderElement<R>>,
NamedPointer = MemoryRenderBufferRenderElement<R>, NamedPointer = MemoryRenderBufferRenderElement<R>,
SolidColor = SolidColorRenderElement, SolidColor = SolidColorRenderElement,
ScreenshotUi = ScreenshotUiRenderElement, 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::backend::renderer::{Bind, ExportMem, Frame, Offscreen, Renderer};
use smithay::utils::{Physical, Rectangle, Scale, Size, Transform}; use smithay::utils::{Physical, Rectangle, Scale, Size, Transform};
pub mod nearest_integer_scale;
pub mod offscreen; pub mod offscreen;
pub mod primary_gpu_texture; pub mod primary_gpu_texture;
pub mod render_elements; 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)
}
}