diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fed074..5e26a0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - All winit backend internal event types now use `WinitInput` as the backend type. - `WinitEventLoop::dispatch_new_events` is now used to receive some `WinitEvent`s. - Added `TabletToolType::Unknown` as an option for tablet events +- `render_texture` was removed from `Frame`, use `render_texture_at` or `render_texture_from_to` instead or use `Gles2Renderer::render_texture` as a direct replacement. - Remove `InputBackend::dispatch_new_events`, turning `InputBackend` into a definition of backend event types. Future input backends should be a `calloop::EventSource`. - Remove `InputBackend::EventError` associated type as it is unneeded since `dispatch_new_events` was removed. @@ -46,6 +47,7 @@ - `KeyState`, `MouseButton`, `ButtonState` and `Axis` in `backend::input` now derive `Hash`. - New `DrmNode` type in drm backend. This is primarily for use a backend which needs to run as client inside another session. - The button code for a `PointerButtonEvent` may now be obtained using `PointerButtonEvent::button_code`. +- `Renderer` now allows texture filtering methods to be set. ### Bugfixes diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 2f8d290..79e54eb 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -4,10 +4,6 @@ use crate::AnvilState; #[cfg(feature = "udev")] use crate::udev::UdevData; -#[cfg(feature = "winit")] -use crate::winit::WinitData; -#[cfg(feature = "x11")] -use crate::x11::X11Data; use smithay::{ backend::input::{ @@ -38,6 +34,34 @@ use smithay::{ }; impl AnvilState { + fn process_common_key_action(&mut self, action: KeyAction) { + match action { + KeyAction::None => (), + + KeyAction::Quit => { + info!(self.log, "Quitting."); + self.running.store(false, Ordering::SeqCst); + } + + KeyAction::Run(cmd) => { + info!(self.log, "Starting program"; "cmd" => cmd.clone()); + + if let Err(e) = Command::new(&cmd).spawn() { + error!(self.log, + "Failed to start program"; + "cmd" => cmd, + "err" => format!("{:?}", e) + ); + } + } + + _ => unreachable!( + "Common key action handler encountered backend specific action {:?}", + action + ), + } + } + fn keyboard_key_to_action(&mut self, evt: B::KeyboardKeyEvent) -> KeyAction { let keycode = evt.key_code(); let state = evt.state(); @@ -143,72 +167,72 @@ impl AnvilState { } } -#[cfg(feature = "winit")] -impl AnvilState { - pub fn process_input_event(&mut self, event: InputEvent) { +#[cfg(any(feature = "winit", feature = "x11"))] +impl AnvilState { + pub fn process_input_event_windowed(&mut self, event: InputEvent, output_name: &str) { match event { - InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::(event) { - KeyAction::None => {} - KeyAction::Quit => { - info!(self.log, "Quitting."); - self.running.store(false, Ordering::SeqCst); - } - KeyAction::Run(cmd) => { - info!(self.log, "Starting program"; "cmd" => cmd.clone()); - if let Err(e) = Command::new(&cmd).spawn() { - error!(self.log, - "Failed to start program"; - "cmd" => cmd, - "err" => format!("{:?}", e) - ); - } - } + InputEvent::Keyboard { event } => match self.keyboard_key_to_action::(event) { KeyAction::ScaleUp => { let current_scale = { self.output_map .borrow() - .find_by_name(crate::winit::OUTPUT_NAME) + .find_by_name(output_name) .map(|o| o.scale()) .unwrap_or(1.0) }; + self.output_map .borrow_mut() - .update_scale_by_name(current_scale + 0.25f32, crate::winit::OUTPUT_NAME); + .update_scale_by_name(current_scale + 0.25f32, output_name); } + KeyAction::ScaleDown => { let current_scale = { self.output_map .borrow() - .find_by_name(crate::winit::OUTPUT_NAME) + .find_by_name(output_name) .map(|o| o.scale()) .unwrap_or(1.0) }; - self.output_map.borrow_mut().update_scale_by_name( - f32::max(1.0f32, current_scale - 0.25f32), - crate::winit::OUTPUT_NAME, - ); - } - action => { - warn!(self.log, "Key action {:?} unsupported on winit backend.", action); + self.output_map + .borrow_mut() + .update_scale_by_name(f32::max(1.0f32, current_scale + 0.25f32), output_name); } + + action => match action { + KeyAction::None | KeyAction::Quit | KeyAction::Run(_) => { + self.process_common_key_action(action) + } + + _ => warn!( + self.log, + "Key action {:?} unsupported on on output {} backend.", action, output_name + ), + }, }, - InputEvent::PointerMotionAbsolute { event, .. } => self.on_pointer_move_absolute::(event), - InputEvent::PointerButton { event, .. } => self.on_pointer_button::(event), - InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::(event), - _ => { - // other events are not handled in anvil (yet) + + InputEvent::PointerMotionAbsolute { event } => { + self.on_pointer_move_absolute_windowed::(event, output_name) } + InputEvent::PointerButton { event } => self.on_pointer_button::(event), + InputEvent::PointerAxis { event } => self.on_pointer_axis::(event), + _ => (), // other events are not handled in anvil (yet) } } - fn on_pointer_move_absolute(&mut self, evt: B::PointerMotionAbsoluteEvent) { + fn on_pointer_move_absolute_windowed( + &mut self, + evt: B::PointerMotionAbsoluteEvent, + output_name: &str, + ) { let output_size = self .output_map .borrow() - .find_by_name(crate::winit::OUTPUT_NAME) + .find_by_name(output_name) .map(|o| o.size()) .unwrap(); + let pos = evt.position_transformed(output_size); self.pointer_location = pos; let serial = SCOUNTER.next_serial(); @@ -222,11 +246,6 @@ impl AnvilState { pub fn process_input_event(&mut self, event: InputEvent) { match event { InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::(event) { - KeyAction::None => {} - KeyAction::Quit => { - info!(self.log, "Quitting."); - self.running.store(false, Ordering::SeqCst); - } #[cfg(feature = "udev")] KeyAction::VtSwitch(vt) => { info!(self.log, "Trying to switch to vt {}", vt); @@ -234,16 +253,6 @@ impl AnvilState { error!(self.log, "Error switching to vt {}: {}", vt, err); } } - KeyAction::Run(cmd) => { - info!(self.log, "Starting program"; "cmd" => cmd.clone()); - if let Err(e) = Command::new(&cmd).spawn() { - error!(self.log, - "Failed to start program"; - "cmd" => cmd, - "err" => format!("{:?}", e) - ); - } - } KeyAction::Screen(num) => { let geometry = self.output_map.borrow().find_by_index(num).map(|o| o.geometry()); @@ -300,6 +309,14 @@ impl AnvilState { .motion(self.pointer_location, under, SCOUNTER.next_serial(), 0); } } + + action => match action { + KeyAction::None | KeyAction::Quit | KeyAction::Run(_) => { + self.process_common_key_action(action) + } + + _ => unreachable!(), + }, }, InputEvent::PointerMotion { event, .. } => self.on_pointer_move::(event), InputEvent::PointerButton { event, .. } => self.on_pointer_button::(event), @@ -486,87 +503,6 @@ impl AnvilState { } } -#[cfg(feature = "x11")] -impl AnvilState { - pub fn process_input_event(&mut self, event: InputEvent) { - match event { - InputEvent::Keyboard { event } => match self.keyboard_key_to_action::(event) { - KeyAction::None => (), - - KeyAction::Quit => { - info!(self.log, "Quitting."); - self.running.store(false, Ordering::SeqCst); - } - - KeyAction::Run(cmd) => { - info!(self.log, "Starting program"; "cmd" => cmd.clone()); - - if let Err(e) = Command::new(&cmd).spawn() { - error!(self.log, - "Failed to start program"; - "cmd" => cmd, - "err" => format!("{:?}", e) - ); - } - } - - KeyAction::ScaleUp => { - let current_scale = { - self.output_map - .borrow() - .find_by_name(crate::x11::OUTPUT_NAME) - .map(|o| o.scale()) - .unwrap_or(1.0) - }; - - self.output_map - .borrow_mut() - .update_scale_by_name(current_scale + 0.25f32, crate::x11::OUTPUT_NAME); - } - - KeyAction::ScaleDown => { - let current_scale = { - self.output_map - .borrow() - .find_by_name(crate::x11::OUTPUT_NAME) - .map(|o| o.scale()) - .unwrap_or(1.0) - }; - - self.output_map.borrow_mut().update_scale_by_name( - f32::max(1.0f32, current_scale + 0.25f32), - crate::x11::OUTPUT_NAME, - ); - } - - action => { - warn!(self.log, "Key action {:?} unsupported on x11 backend.", action); - } - }, - - InputEvent::PointerMotionAbsolute { event } => self.on_pointer_move_absolute::(event), - InputEvent::PointerButton { event } => self.on_pointer_button::(event), - InputEvent::PointerAxis { event } => self.on_pointer_axis::(event), - _ => (), // other events are not handled in anvil (yet) - } - } - - fn on_pointer_move_absolute(&mut self, evt: B::PointerMotionAbsoluteEvent) { - let output_size = self - .output_map - .borrow() - .find_by_name(crate::x11::OUTPUT_NAME) - .map(|o| o.size()) - .unwrap(); - - let pos = evt.position_transformed(output_size); - self.pointer_location = pos; - let serial = SCOUNTER.next_serial(); - let under = self.window_map.borrow().get_surface_under(pos); - self.pointer.motion(pos, under, serial, evt.time()); - } -} - /// Possible results of a keyboard action #[derive(Debug)] enum KeyAction { diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index ddcf30e..a137cf4 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -132,16 +132,16 @@ pub fn run_winit(log: Logger) { size, refresh: 60_000, }, - crate::winit::OUTPUT_NAME, + OUTPUT_NAME, ); let output_mut = state.output_map.borrow(); - let output = output_mut.find_by_name(crate::winit::OUTPUT_NAME).unwrap(); + let output = output_mut.find_by_name(OUTPUT_NAME).unwrap(); state.window_map.borrow_mut().layers.arange_layers(output); } - WinitEvent::Input(event) => state.process_input_event(event), + WinitEvent::Input(event) => state.process_input_event_windowed(event, OUTPUT_NAME), _ => (), }) diff --git a/anvil/src/x11.rs b/anvil/src/x11.rs index f12cf3e..d06ae83 100644 --- a/anvil/src/x11.rs +++ b/anvil/src/x11.rs @@ -164,7 +164,7 @@ pub fn run_x11(log: Logger) { state.backend_data.render = true; } - X11Event::Input(event) => state.process_input_event(event), + X11Event::Input(event) => state.process_input_event_windowed(event, OUTPUT_NAME), }) .expect("Failed to insert X11 Backend into event loop"); diff --git a/src/backend/drm/surface/gbm.rs b/src/backend/drm/surface/gbm.rs index 12a94ef..c75c606 100644 --- a/src/backend/drm/surface/gbm.rs +++ b/src/backend/drm/surface/gbm.rs @@ -62,16 +62,21 @@ where // Once we have proper color management and possibly HDR support, // we need to have a more sophisticated picker. // (Or maybe just pick ARGB2101010, if available, we will see.) - let code = Fourcc::Argb8888; + let mut code = Fourcc::Argb8888; let logger = crate::slog_or_fallback(log).new(o!("backend" => "drm_render")); // select a format - let plane_formats = drm + let mut plane_formats = drm .supported_formats(drm.plane())? .iter() - .filter(|fmt| fmt.code == code) .cloned() .collect::>(); + + // try non alpha variant if not available + if !plane_formats.iter().any(|fmt| fmt.code == code) { + code = Fourcc::Xrgb8888; + } + plane_formats.retain(|fmt| fmt.code == code); renderer_formats.retain(|fmt| fmt.code == code); trace!(logger, "Plane formats: {:?}", plane_formats); diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index 5be1a90..3a8c49b 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -11,12 +11,12 @@ use std::sync::{ }; use std::{collections::HashSet, os::raw::c_char}; -use cgmath::{prelude::*, Matrix3, Vector2}; +use cgmath::{prelude::*, Matrix3, Vector2, Vector3}; mod shaders; mod version; -use super::{Bind, Frame, Renderer, Texture, Transform, Unbind}; +use super::{Bind, Frame, Renderer, Texture, TextureFilter, Transform, Unbind}; use crate::backend::allocator::{ dmabuf::{Dmabuf, WeakDmabuf}, Format, @@ -26,7 +26,7 @@ use crate::backend::egl::{ EGLContext, EGLSurface, MakeCurrentError, }; use crate::backend::SwapBuffersError; -use crate::utils::{Buffer, Physical, Size}; +use crate::utils::{Buffer, Physical, Rectangle, Size}; #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] use super::ImportEgl; @@ -35,8 +35,6 @@ use super::{ImportDma, ImportShm}; #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] use crate::backend::egl::{display::EGLBufferReader, Format as EGLFormat}; #[cfg(feature = "wayland_frontend")] -use crate::utils::Rectangle; -#[cfg(feature = "wayland_frontend")] use wayland_server::protocol::{wl_buffer, wl_shm}; use slog::{debug, error, info, o, trace, warn}; @@ -420,6 +418,7 @@ impl Gles2Renderer { /// - This renderer has no default framebuffer, use `Bind::bind` before rendering. /// - Binding a new target, while another one is already bound, will replace the current target. /// - Shm buffers can be released after a successful import, without the texture handle becoming invalid. + /// - Texture filtering starts with Nearest-downscaling and Linear-upscaling pub unsafe fn new(context: EGLContext, logger: L) -> Result where L: Into>, @@ -495,7 +494,7 @@ impl Gles2Renderer { ]; let (tx, rx) = channel(); - let renderer = Gles2Renderer { + let mut renderer = Gles2Renderer { id: RENDERER_COUNTER.fetch_add(1, Ordering::SeqCst), gl, egl: context, @@ -514,6 +513,8 @@ impl Gles2Renderer { logger: log, _not_send: std::ptr::null_mut(), }; + renderer.downscale_filter(TextureFilter::Nearest)?; + renderer.upscale_filter(TextureFilter::Linear)?; renderer.egl.unbind()?; Ok(renderer) } @@ -1007,6 +1008,35 @@ impl Renderer for Gles2Renderer { type TextureId = Gles2Texture; type Frame = Gles2Frame; + fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> { + self.make_current()?; + unsafe { + self.gl.TexParameteri( + ffi::TEXTURE_2D, + ffi::TEXTURE_MIN_FILTER, + match filter { + TextureFilter::Nearest => ffi::NEAREST as i32, + TextureFilter::Linear => ffi::LINEAR as i32, + }, + ); + } + Ok(()) + } + fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> { + self.make_current()?; + unsafe { + self.gl.TexParameteri( + ffi::TEXTURE_2D, + ffi::TEXTURE_MAG_FILTER, + match filter { + TextureFilter::Nearest => ffi::NEAREST as i32, + TextureFilter::Linear => ffi::LINEAR as i32, + }, + ); + } + Ok(()) + } + fn render( &mut self, size: Size, @@ -1100,13 +1130,60 @@ impl Frame for Gles2Frame { Ok(()) } - fn render_texture( + fn render_texture_from_to( &mut self, - tex: &Self::TextureId, + texture: &Self::TextureId, + src: Rectangle, + dest: Rectangle, + transform: Transform, + alpha: f32, + ) -> Result<(), Self::Error> { + let mut mat = Matrix3::::identity(); + + // position and scale + mat = mat * Matrix3::from_translation(Vector2::new(dest.loc.x as f32, dest.loc.y as f32)); + mat = mat * Matrix3::from_nonuniform_scale(dest.size.w as f32, dest.size.h as f32); + + //apply surface transformation + mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5)); + if transform == Transform::Normal { + assert_eq!(mat, mat * transform.invert().matrix()); + assert_eq!(transform.matrix(), Matrix3::::identity()); + } + mat = mat * transform.invert().matrix(); + mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5)); + + // this matrix should be regular, we can expect invert to succeed + let tex_size = texture.size(); + let texture_mat = Matrix3::from_nonuniform_scale(tex_size.w as f32, tex_size.h as f32) + .invert() + .unwrap(); + let verts = [ + (texture_mat * Vector3::new((src.loc.x + src.size.w) as f32, src.loc.y as f32, 0.0)).truncate(), // top-right + (texture_mat * Vector3::new(src.loc.x as f32, src.loc.y as f32, 0.0)).truncate(), // top-left + (texture_mat + * Vector3::new( + (src.loc.x + src.size.w) as f32, + (src.loc.y + src.size.h) as f32, + 0.0, + )) + .truncate(), // bottom-right + (texture_mat * Vector3::new(src.loc.x as f32, (src.loc.y + src.size.h) as f32, 0.0)).truncate(), // bottom-left + ]; + self.render_texture(texture, mat, verts, alpha) + } +} + +impl Gles2Frame { + /// Render a texture to the current target using given projection matrix and alpha. + /// The given vertices are used to source the texture. This is mostly useful for cropping the texture. + pub fn render_texture( + &mut self, + tex: &Gles2Texture, mut matrix: Matrix3, tex_coords: [Vector2; 4], alpha: f32, - ) -> Result<(), Self::Error> { + ) -> Result<(), Gles2Error> { //apply output transformation matrix = self.current_projection * matrix; diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index f664d84..a975894 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -14,7 +14,7 @@ use crate::utils::{Buffer, Physical, Point, Rectangle, Size}; #[cfg(feature = "wayland_frontend")] use crate::wayland::compositor::SurfaceData; -use cgmath::{prelude::*, Matrix3, Vector2, Vector3}; +use cgmath::Matrix3; #[cfg(feature = "wayland_frontend")] use wayland_server::protocol::{wl_buffer, wl_shm}; @@ -53,6 +53,15 @@ pub enum Transform { Flipped270, } +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +/// Texture filtering methods +pub enum TextureFilter { + /// Returns the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured. + Linear, + /// Returns the weighted average of the four texture elements that are closest to the center of the pixel being textured. + Nearest, +} + impl Transform { /// A projection matrix to apply this transformation pub fn matrix(&self) -> Matrix3 { @@ -163,25 +172,17 @@ pub trait Frame { /// This operation is only valid in between a `begin` and `finish`-call. /// If called outside this operation may error-out, do nothing or modify future rendering results in any way. fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>; - /// Render a texture to the current target using given projection matrix and alpha. - /// The given vertices are used to source the texture. This is mostly useful for cropping the texture. - fn render_texture( - &mut self, - texture: &Self::TextureId, - matrix: Matrix3, - tex_coords: [Vector2; 4], - alpha: f32, - ) -> Result<(), Self::Error>; /// Render a texture to the current target as a flat 2d-plane at a given /// position and applying the given transformation with the given alpha value. + /// (Meaning `src_transform` should match the orientation of surface being rendered). fn render_texture_at( &mut self, texture: &Self::TextureId, pos: Point, texture_scale: i32, output_scale: f64, - transform: Transform, + src_transform: Transform, alpha: f32, ) -> Result<(), Self::Error> { self.render_texture_from_to( @@ -195,55 +196,22 @@ pub trait Frame { .to_f64() .to_physical(output_scale), ), - transform, + src_transform, alpha, ) } - /// Render part of a texture as given by src to the current target into the rectangle described by dest - /// as a flat 2d-plane after applying the given transformations. + /// Render part of a texture as given by src to the current target into the rectangle described by dst + /// as a flat 2d-plane after applying the inverse of the given transformation. + /// (Meaning `src_transform` should match the orientation of surface being rendered). fn render_texture_from_to( &mut self, texture: &Self::TextureId, src: Rectangle, - dest: Rectangle, - transform: Transform, + dst: Rectangle, + src_transform: Transform, alpha: f32, - ) -> Result<(), Self::Error> { - let mut mat = Matrix3::::identity(); - - // position and scale - mat = mat * Matrix3::from_translation(Vector2::new(dest.loc.x as f32, dest.loc.y as f32)); - mat = mat * Matrix3::from_nonuniform_scale(dest.size.w as f32, dest.size.h as f32); - - //apply surface transformation - mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5)); - if transform == Transform::Normal { - assert_eq!(mat, mat * transform.invert().matrix()); - assert_eq!(transform.matrix(), Matrix3::::identity()); - } - mat = mat * transform.invert().matrix(); - mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5)); - - // this matrix should be regular, we can expect invert to succeed - let tex_size = texture.size(); - let texture_mat = Matrix3::from_nonuniform_scale(tex_size.w as f32, tex_size.h as f32) - .invert() - .unwrap(); - let verts = [ - (texture_mat * Vector3::new((src.loc.x + src.size.w) as f32, src.loc.y as f32, 0.0)).truncate(), // top-right - (texture_mat * Vector3::new(src.loc.x as f32, src.loc.y as f32, 0.0)).truncate(), // top-left - (texture_mat - * Vector3::new( - (src.loc.x + src.size.w) as f32, - (src.loc.y + src.size.h) as f32, - 0.0, - )) - .truncate(), // bottom-right - (texture_mat * Vector3::new(src.loc.x as f32, (src.loc.y + src.size.h) as f32, 0.0)).truncate(), // bottom-left - ]; - self.render_texture(texture, mat, verts, alpha) - } + ) -> Result<(), Self::Error>; } /// Abstraction of commonly used rendering operations for compositors. @@ -255,6 +223,11 @@ pub trait Renderer { /// Type representing a currently in-progress frame during the [`Renderer::render`]-call type Frame: Frame; + /// Set the filter method to be used when rendering a texture into a smaller area than its size + fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error>; + /// Set the filter method to be used when rendering a texture into a larger area than its size + fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error>; + /// Initialize a rendering context on the current rendering target with given dimensions and transformation. /// /// This function *may* error, if: @@ -265,7 +238,7 @@ pub trait Renderer { fn render( &mut self, size: Size, - transform: Transform, + dst_transform: Transform, rendering: F, ) -> Result where diff --git a/src/backend/x11/buffer.rs b/src/backend/x11/buffer.rs index 82a755f..ea2aa15 100644 --- a/src/backend/x11/buffer.rs +++ b/src/backend/x11/buffer.rs @@ -129,7 +129,7 @@ where } // We need dri3 >= 1.2 in order to use the enhanced dri3_pixmap_from_buffers function. - let xid = if window_inner.extensions.dri3 >= (1, 2) { + let xid = if window_inner.extensions.dri3 >= Some((1, 2)) { if dmabuf.num_planes() > 4 { return Err(CreatePixmapError::TooManyPlanes); } diff --git a/src/backend/x11/extension.rs b/src/backend/x11/extension.rs index 5ac8b5a..d5f5c2d 100644 --- a/src/backend/x11/extension.rs +++ b/src/backend/x11/extension.rs @@ -25,6 +25,7 @@ macro_rules! extensions { $( $extension:ident { // Extension name for path lookup $extension_fn:ident, // Function used to look up the version of the extension + required: $required:expr, minimum: ($min_major:expr, $min_minor:expr), request: ($req_major:expr, $req_minor:expr), }, @@ -34,7 +35,7 @@ macro_rules! extensions { pub struct Extensions { $( #[doc = concat!(" The version of the `", stringify!($extension), "` extension.")] - pub $extension: (u32, u32), + pub $extension: Option<(u32, u32)>, )* } @@ -59,35 +60,43 @@ macro_rules! extensions { version.minor_version, ); - (version.major_version, version.minor_version) + Some((version.major_version, version.minor_version)) } else { - slog::error!( - logger, - "{} extension version is too low (have {}.{}, expected {}.{})", - X11_EXTENSION_NAME, - version.major_version, - version.minor_version, - $req_major, - $req_minor, - ); + if $required { + slog::error!( + logger, + "required extension {} version is too low (have {}.{}, expected {}.{})", + X11_EXTENSION_NAME, + version.major_version, + version.minor_version, + $req_major, + $req_minor, + ); - return Err(MissingExtensionError::WrongVersion { - name: X11_EXTENSION_NAME, - required_major: $req_major, - required_minor: $req_minor, - available_major: version.major_version, - available_minor: version.minor_version, - }.into()); + return Err(MissingExtensionError::WrongVersion { + name: X11_EXTENSION_NAME, + required_major: $req_major, + required_minor: $req_minor, + available_major: version.major_version, + available_minor: version.minor_version, + }.into()); + } else { + None + } } } else { - slog::error!(logger, "{} extension not found", X11_EXTENSION_NAME); + if $required { + slog::error!(logger, "required extension {} not found", X11_EXTENSION_NAME); - return Err(MissingExtensionError::NotFound { - name: X11_EXTENSION_NAME, - major: $min_major, - minor: $min_minor, + return Err(MissingExtensionError::NotFound { + name: X11_EXTENSION_NAME, + major: $min_major, + minor: $min_minor, + } + .into()); + } else { + None } - .into()); } }; )* @@ -105,18 +114,21 @@ macro_rules! extensions { extensions! { present { present_query_version, + required: true, minimum: (1, 0), request: (1, 0), }, xfixes { xfixes_query_version, + required: true, minimum: (4, 0), request: (4, 0), }, dri3 { dri3_query_version, + required: true, minimum: (1, 0), request: (1, 2), }, diff --git a/src/lib.rs b/src/lib.rs index 86dbe45..bee4d66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ //! # Smithay: the Wayland compositor smithy //! -//! This crate is a general framework for build wayland compositors. It currently focuses on low-level, +//! This crate is a general framework for building wayland compositors. It currently focuses on low-level, //! helpers and abstractions, handling most of the system-level and wayland protocol interactions. //! The window management and drawing logic is however at the time not provided (but helpers for this //! are planned for future version). diff --git a/src/utils/geometry.rs b/src/utils/geometry.rs index 45652e4..80b6823 100644 --- a/src/utils/geometry.rs +++ b/src/utils/geometry.rs @@ -18,7 +18,7 @@ pub struct Buffer; pub struct Raw; pub trait Coordinate: - Sized + Add + Sub + PartialOrd + Default + Copy + std::fmt::Debug + Sized + Add + Sub + PartialOrd + Default + Copy + fmt::Debug { fn downscale(self, scale: Self) -> Self; fn upscale(self, scale: Self) -> Self; @@ -637,6 +637,21 @@ impl AddAssign for Size { } } +impl SubAssign for Size { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + debug_assert!( + self.w >= rhs.w && self.h >= rhs.h, + "Attempting to subtract bigger from smaller size: {:?} - {:?}", + (&self.w, &self.h), + (&rhs.w, &rhs.h), + ); + + self.w -= rhs.w; + self.h -= rhs.h + } +} + impl Clone for Size { #[inline] fn clone(&self) -> Self { diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index 4a0205c..34beb6e 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -903,6 +903,11 @@ impl ToplevelSurface { self.shell_surface.as_ref().is_alive() && self.wl_surface.as_ref().is_alive() } + /// Supported XDG shell protocol version. + pub fn version(&self) -> u32 { + self.shell_surface.as_ref().version() + } + /// Retrieve the shell client owning this toplevel surface /// /// Returns `None` if the surface does actually no longer exist. diff --git a/wlcs_anvil/src/renderer.rs b/wlcs_anvil/src/renderer.rs index dda1962..640cf10 100644 --- a/wlcs_anvil/src/renderer.rs +++ b/wlcs_anvil/src/renderer.rs @@ -1,10 +1,9 @@ use std::cell::Cell; -use cgmath::Vector2; use smithay::{ backend::{ allocator::dmabuf::Dmabuf, - renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, Transform}, + renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, TextureFilter, Transform}, SwapBuffersError, }, reexports::wayland_server::protocol::wl_buffer, @@ -28,7 +27,7 @@ impl Renderer for DummyRenderer { fn render( &mut self, _size: Size, - _transform: Transform, + _dst_transform: Transform, rendering: F, ) -> Result where @@ -37,6 +36,14 @@ impl Renderer for DummyRenderer { let mut frame = DummyFrame {}; Ok(rendering(self, &mut frame)) } + + fn upscale_filter(&mut self, _filter: TextureFilter) -> Result<(), Self::Error> { + Ok(()) + } + + fn downscale_filter(&mut self, _filter: TextureFilter) -> Result<(), Self::Error> { + Ok(()) + } } impl ImportShm for DummyRenderer { @@ -94,11 +101,12 @@ impl Frame for DummyFrame { Ok(()) } - fn render_texture( + fn render_texture_from_to( &mut self, _texture: &Self::TextureId, - _matrix: cgmath::Matrix3, - _tex_coords: [Vector2; 4], + _src: Rectangle, + _dst: Rectangle, + _src_transform: Transform, _alpha: f32, ) -> Result<(), Self::Error> { Ok(())