Merge branch 'master' into input/remove-dispatch-new

This commit is contained in:
i509VCB 2021-11-22 18:19:46 +00:00 committed by GitHub
commit d1fae4ba4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 270 additions and 237 deletions

View File

@ -22,6 +22,7 @@
- All winit backend internal event types now use `WinitInput` as the backend type. - 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. - `WinitEventLoop::dispatch_new_events` is now used to receive some `WinitEvent`s.
- Added `TabletToolType::Unknown` as an option for tablet events - 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::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. - 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`. - `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. - 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`. - The button code for a `PointerButtonEvent` may now be obtained using `PointerButtonEvent::button_code`.
- `Renderer` now allows texture filtering methods to be set.
### Bugfixes ### Bugfixes

View File

@ -4,10 +4,6 @@ use crate::AnvilState;
#[cfg(feature = "udev")] #[cfg(feature = "udev")]
use crate::udev::UdevData; use crate::udev::UdevData;
#[cfg(feature = "winit")]
use crate::winit::WinitData;
#[cfg(feature = "x11")]
use crate::x11::X11Data;
use smithay::{ use smithay::{
backend::input::{ backend::input::{
@ -38,6 +34,34 @@ use smithay::{
}; };
impl<Backend> AnvilState<Backend> { impl<Backend> AnvilState<Backend> {
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<B: InputBackend>(&mut self, evt: B::KeyboardKeyEvent) -> KeyAction { fn keyboard_key_to_action<B: InputBackend>(&mut self, evt: B::KeyboardKeyEvent) -> KeyAction {
let keycode = evt.key_code(); let keycode = evt.key_code();
let state = evt.state(); let state = evt.state();
@ -143,72 +167,72 @@ impl<Backend> AnvilState<Backend> {
} }
} }
#[cfg(feature = "winit")] #[cfg(any(feature = "winit", feature = "x11"))]
impl AnvilState<WinitData> { impl<Backend> AnvilState<Backend> {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) { pub fn process_input_event_windowed<B: InputBackend>(&mut self, event: InputEvent<B>, output_name: &str) {
match event { match event {
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(event) { InputEvent::Keyboard { event } => match self.keyboard_key_to_action::<B>(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 => { KeyAction::ScaleUp => {
let current_scale = { let current_scale = {
self.output_map self.output_map
.borrow() .borrow()
.find_by_name(crate::winit::OUTPUT_NAME) .find_by_name(output_name)
.map(|o| o.scale()) .map(|o| o.scale())
.unwrap_or(1.0) .unwrap_or(1.0)
}; };
self.output_map self.output_map
.borrow_mut() .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 => { KeyAction::ScaleDown => {
let current_scale = { let current_scale = {
self.output_map self.output_map
.borrow() .borrow()
.find_by_name(crate::winit::OUTPUT_NAME) .find_by_name(output_name)
.map(|o| o.scale()) .map(|o| o.scale())
.unwrap_or(1.0) .unwrap_or(1.0)
}; };
self.output_map.borrow_mut().update_scale_by_name( self.output_map
f32::max(1.0f32, current_scale - 0.25f32), .borrow_mut()
crate::winit::OUTPUT_NAME, .update_scale_by_name(f32::max(1.0f32, current_scale + 0.25f32), output_name);
);
}
action => {
warn!(self.log, "Key action {:?} unsupported on winit backend.", action);
} }
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::<B>(event),
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event), InputEvent::PointerMotionAbsolute { event } => {
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event), self.on_pointer_move_absolute_windowed::<B>(event, output_name)
_ => {
// other events are not handled in anvil (yet)
} }
InputEvent::PointerButton { event } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event } => self.on_pointer_axis::<B>(event),
_ => (), // other events are not handled in anvil (yet)
} }
} }
fn on_pointer_move_absolute<B: InputBackend>(&mut self, evt: B::PointerMotionAbsoluteEvent) { fn on_pointer_move_absolute_windowed<B: InputBackend>(
&mut self,
evt: B::PointerMotionAbsoluteEvent,
output_name: &str,
) {
let output_size = self let output_size = self
.output_map .output_map
.borrow() .borrow()
.find_by_name(crate::winit::OUTPUT_NAME) .find_by_name(output_name)
.map(|o| o.size()) .map(|o| o.size())
.unwrap(); .unwrap();
let pos = evt.position_transformed(output_size); let pos = evt.position_transformed(output_size);
self.pointer_location = pos; self.pointer_location = pos;
let serial = SCOUNTER.next_serial(); let serial = SCOUNTER.next_serial();
@ -222,11 +246,6 @@ impl AnvilState<UdevData> {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) { pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
match event { match event {
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(event) { InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(event) {
KeyAction::None => {}
KeyAction::Quit => {
info!(self.log, "Quitting.");
self.running.store(false, Ordering::SeqCst);
}
#[cfg(feature = "udev")] #[cfg(feature = "udev")]
KeyAction::VtSwitch(vt) => { KeyAction::VtSwitch(vt) => {
info!(self.log, "Trying to switch to vt {}", vt); info!(self.log, "Trying to switch to vt {}", vt);
@ -234,16 +253,6 @@ impl AnvilState<UdevData> {
error!(self.log, "Error switching to vt {}: {}", vt, err); 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) => { KeyAction::Screen(num) => {
let geometry = self.output_map.borrow().find_by_index(num).map(|o| o.geometry()); let geometry = self.output_map.borrow().find_by_index(num).map(|o| o.geometry());
@ -300,6 +309,14 @@ impl AnvilState<UdevData> {
.motion(self.pointer_location, under, SCOUNTER.next_serial(), 0); .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::<B>(event), InputEvent::PointerMotion { event, .. } => self.on_pointer_move::<B>(event),
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event), InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
@ -486,87 +503,6 @@ impl AnvilState<UdevData> {
} }
} }
#[cfg(feature = "x11")]
impl AnvilState<X11Data> {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
match event {
InputEvent::Keyboard { event } => match self.keyboard_key_to_action::<B>(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::<B>(event),
InputEvent::PointerButton { event } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event } => self.on_pointer_axis::<B>(event),
_ => (), // other events are not handled in anvil (yet)
}
}
fn on_pointer_move_absolute<B: InputBackend>(&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 /// Possible results of a keyboard action
#[derive(Debug)] #[derive(Debug)]
enum KeyAction { enum KeyAction {

View File

@ -132,16 +132,16 @@ pub fn run_winit(log: Logger) {
size, size,
refresh: 60_000, refresh: 60_000,
}, },
crate::winit::OUTPUT_NAME, OUTPUT_NAME,
); );
let output_mut = state.output_map.borrow(); 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); 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),
_ => (), _ => (),
}) })

View File

@ -164,7 +164,7 @@ pub fn run_x11(log: Logger) {
state.backend_data.render = true; 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"); .expect("Failed to insert X11 Backend into event loop");

View File

@ -62,16 +62,21 @@ where
// Once we have proper color management and possibly HDR support, // Once we have proper color management and possibly HDR support,
// we need to have a more sophisticated picker. // we need to have a more sophisticated picker.
// (Or maybe just pick ARGB2101010, if available, we will see.) // (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")); let logger = crate::slog_or_fallback(log).new(o!("backend" => "drm_render"));
// select a format // select a format
let plane_formats = drm let mut plane_formats = drm
.supported_formats(drm.plane())? .supported_formats(drm.plane())?
.iter() .iter()
.filter(|fmt| fmt.code == code)
.cloned() .cloned()
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
// 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); renderer_formats.retain(|fmt| fmt.code == code);
trace!(logger, "Plane formats: {:?}", plane_formats); trace!(logger, "Plane formats: {:?}", plane_formats);

View File

@ -11,12 +11,12 @@ use std::sync::{
}; };
use std::{collections::HashSet, os::raw::c_char}; use std::{collections::HashSet, os::raw::c_char};
use cgmath::{prelude::*, Matrix3, Vector2}; use cgmath::{prelude::*, Matrix3, Vector2, Vector3};
mod shaders; mod shaders;
mod version; mod version;
use super::{Bind, Frame, Renderer, Texture, Transform, Unbind}; use super::{Bind, Frame, Renderer, Texture, TextureFilter, Transform, Unbind};
use crate::backend::allocator::{ use crate::backend::allocator::{
dmabuf::{Dmabuf, WeakDmabuf}, dmabuf::{Dmabuf, WeakDmabuf},
Format, Format,
@ -26,7 +26,7 @@ use crate::backend::egl::{
EGLContext, EGLSurface, MakeCurrentError, EGLContext, EGLSurface, MakeCurrentError,
}; };
use crate::backend::SwapBuffersError; 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"))] #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
use super::ImportEgl; use super::ImportEgl;
@ -35,8 +35,6 @@ use super::{ImportDma, ImportShm};
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
use crate::backend::egl::{display::EGLBufferReader, Format as EGLFormat}; use crate::backend::egl::{display::EGLBufferReader, Format as EGLFormat};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use crate::utils::Rectangle;
#[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_buffer, wl_shm}; use wayland_server::protocol::{wl_buffer, wl_shm};
use slog::{debug, error, info, o, trace, warn}; 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. /// - 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. /// - 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. /// - 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<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error> pub unsafe fn new<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
@ -495,7 +494,7 @@ impl Gles2Renderer {
]; ];
let (tx, rx) = channel(); let (tx, rx) = channel();
let renderer = Gles2Renderer { let mut renderer = Gles2Renderer {
id: RENDERER_COUNTER.fetch_add(1, Ordering::SeqCst), id: RENDERER_COUNTER.fetch_add(1, Ordering::SeqCst),
gl, gl,
egl: context, egl: context,
@ -514,6 +513,8 @@ impl Gles2Renderer {
logger: log, logger: log,
_not_send: std::ptr::null_mut(), _not_send: std::ptr::null_mut(),
}; };
renderer.downscale_filter(TextureFilter::Nearest)?;
renderer.upscale_filter(TextureFilter::Linear)?;
renderer.egl.unbind()?; renderer.egl.unbind()?;
Ok(renderer) Ok(renderer)
} }
@ -1007,6 +1008,35 @@ impl Renderer for Gles2Renderer {
type TextureId = Gles2Texture; type TextureId = Gles2Texture;
type Frame = Gles2Frame; 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<F, R>( fn render<F, R>(
&mut self, &mut self,
size: Size<i32, Physical>, size: Size<i32, Physical>,
@ -1100,13 +1130,60 @@ impl Frame for Gles2Frame {
Ok(()) Ok(())
} }
fn render_texture( fn render_texture_from_to(
&mut self, &mut self,
tex: &Self::TextureId, texture: &Self::TextureId,
src: Rectangle<i32, Buffer>,
dest: Rectangle<f64, Physical>,
transform: Transform,
alpha: f32,
) -> Result<(), Self::Error> {
let mut mat = Matrix3::<f32>::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::<f32>::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<f32>, mut matrix: Matrix3<f32>,
tex_coords: [Vector2<f32>; 4], tex_coords: [Vector2<f32>; 4],
alpha: f32, alpha: f32,
) -> Result<(), Self::Error> { ) -> Result<(), Gles2Error> {
//apply output transformation //apply output transformation
matrix = self.current_projection * matrix; matrix = self.current_projection * matrix;

View File

@ -14,7 +14,7 @@ use crate::utils::{Buffer, Physical, Point, Rectangle, Size};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use crate::wayland::compositor::SurfaceData; use crate::wayland::compositor::SurfaceData;
use cgmath::{prelude::*, Matrix3, Vector2, Vector3}; use cgmath::Matrix3;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_buffer, wl_shm}; use wayland_server::protocol::{wl_buffer, wl_shm};
@ -53,6 +53,15 @@ pub enum Transform {
Flipped270, 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 { impl Transform {
/// A projection matrix to apply this transformation /// A projection matrix to apply this transformation
pub fn matrix(&self) -> Matrix3<f32> { pub fn matrix(&self) -> Matrix3<f32> {
@ -163,25 +172,17 @@ pub trait Frame {
/// This operation is only valid in between a `begin` and `finish`-call. /// 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. /// 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>; 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<f32>,
tex_coords: [Vector2<f32>; 4],
alpha: f32,
) -> Result<(), Self::Error>;
/// Render a texture to the current target as a flat 2d-plane at a given /// 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. /// 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( fn render_texture_at(
&mut self, &mut self,
texture: &Self::TextureId, texture: &Self::TextureId,
pos: Point<f64, Physical>, pos: Point<f64, Physical>,
texture_scale: i32, texture_scale: i32,
output_scale: f64, output_scale: f64,
transform: Transform, src_transform: Transform,
alpha: f32, alpha: f32,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
self.render_texture_from_to( self.render_texture_from_to(
@ -195,55 +196,22 @@ pub trait Frame {
.to_f64() .to_f64()
.to_physical(output_scale), .to_physical(output_scale),
), ),
transform, src_transform,
alpha, alpha,
) )
} }
/// Render part of a texture as given by src to the current target into the rectangle described by dest /// 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 given transformations. /// 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( fn render_texture_from_to(
&mut self, &mut self,
texture: &Self::TextureId, texture: &Self::TextureId,
src: Rectangle<i32, Buffer>, src: Rectangle<i32, Buffer>,
dest: Rectangle<f64, Physical>, dst: Rectangle<f64, Physical>,
transform: Transform, src_transform: Transform,
alpha: f32, alpha: f32,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error>;
let mut mat = Matrix3::<f32>::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::<f32>::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)
}
} }
/// Abstraction of commonly used rendering operations for compositors. /// 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 representing a currently in-progress frame during the [`Renderer::render`]-call
type Frame: Frame<Error = Self::Error, TextureId = Self::TextureId>; type Frame: Frame<Error = Self::Error, TextureId = Self::TextureId>;
/// 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. /// Initialize a rendering context on the current rendering target with given dimensions and transformation.
/// ///
/// This function *may* error, if: /// This function *may* error, if:
@ -265,7 +238,7 @@ pub trait Renderer {
fn render<F, R>( fn render<F, R>(
&mut self, &mut self,
size: Size<i32, Physical>, size: Size<i32, Physical>,
transform: Transform, dst_transform: Transform,
rendering: F, rendering: F,
) -> Result<R, Self::Error> ) -> Result<R, Self::Error>
where where

View File

@ -129,7 +129,7 @@ where
} }
// We need dri3 >= 1.2 in order to use the enhanced dri3_pixmap_from_buffers function. // 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 { if dmabuf.num_planes() > 4 {
return Err(CreatePixmapError::TooManyPlanes); return Err(CreatePixmapError::TooManyPlanes);
} }

View File

@ -25,6 +25,7 @@ macro_rules! extensions {
$( $(
$extension:ident { // Extension name for path lookup $extension:ident { // Extension name for path lookup
$extension_fn:ident, // Function used to look up the version of the extension $extension_fn:ident, // Function used to look up the version of the extension
required: $required:expr,
minimum: ($min_major:expr, $min_minor:expr), minimum: ($min_major:expr, $min_minor:expr),
request: ($req_major:expr, $req_minor:expr), request: ($req_major:expr, $req_minor:expr),
}, },
@ -34,7 +35,7 @@ macro_rules! extensions {
pub struct Extensions { pub struct Extensions {
$( $(
#[doc = concat!(" The version of the `", stringify!($extension), "` extension.")] #[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.minor_version,
); );
(version.major_version, version.minor_version) Some((version.major_version, version.minor_version))
} else { } else {
slog::error!( if $required {
logger, slog::error!(
"{} extension version is too low (have {}.{}, expected {}.{})", logger,
X11_EXTENSION_NAME, "required extension {} version is too low (have {}.{}, expected {}.{})",
version.major_version, X11_EXTENSION_NAME,
version.minor_version, version.major_version,
$req_major, version.minor_version,
$req_minor, $req_major,
); $req_minor,
);
return Err(MissingExtensionError::WrongVersion { return Err(MissingExtensionError::WrongVersion {
name: X11_EXTENSION_NAME, name: X11_EXTENSION_NAME,
required_major: $req_major, required_major: $req_major,
required_minor: $req_minor, required_minor: $req_minor,
available_major: version.major_version, available_major: version.major_version,
available_minor: version.minor_version, available_minor: version.minor_version,
}.into()); }.into());
} else {
None
}
} }
} else { } 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 { return Err(MissingExtensionError::NotFound {
name: X11_EXTENSION_NAME, name: X11_EXTENSION_NAME,
major: $min_major, major: $min_major,
minor: $min_minor, minor: $min_minor,
}
.into());
} else {
None
} }
.into());
} }
}; };
)* )*
@ -105,18 +114,21 @@ macro_rules! extensions {
extensions! { extensions! {
present { present {
present_query_version, present_query_version,
required: true,
minimum: (1, 0), minimum: (1, 0),
request: (1, 0), request: (1, 0),
}, },
xfixes { xfixes {
xfixes_query_version, xfixes_query_version,
required: true,
minimum: (4, 0), minimum: (4, 0),
request: (4, 0), request: (4, 0),
}, },
dri3 { dri3 {
dri3_query_version, dri3_query_version,
required: true,
minimum: (1, 0), minimum: (1, 0),
request: (1, 2), request: (1, 2),
}, },

View File

@ -4,7 +4,7 @@
//! # Smithay: the Wayland compositor smithy //! # 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. //! 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 //! The window management and drawing logic is however at the time not provided (but helpers for this
//! are planned for future version). //! are planned for future version).

View File

@ -18,7 +18,7 @@ pub struct Buffer;
pub struct Raw; pub struct Raw;
pub trait Coordinate: pub trait Coordinate:
Sized + Add<Self, Output = Self> + Sub<Self, Output = Self> + PartialOrd + Default + Copy + std::fmt::Debug Sized + Add<Self, Output = Self> + Sub<Self, Output = Self> + PartialOrd + Default + Copy + fmt::Debug
{ {
fn downscale(self, scale: Self) -> Self; fn downscale(self, scale: Self) -> Self;
fn upscale(self, scale: Self) -> Self; fn upscale(self, scale: Self) -> Self;
@ -637,6 +637,21 @@ impl<N: AddAssign, Kind> AddAssign for Size<N, Kind> {
} }
} }
impl<N: SubAssign + fmt::Debug + PartialOrd, Kind> SubAssign for Size<N, Kind> {
#[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<N: Clone, Kind> Clone for Size<N, Kind> { impl<N: Clone, Kind> Clone for Size<N, Kind> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {

View File

@ -903,6 +903,11 @@ impl ToplevelSurface {
self.shell_surface.as_ref().is_alive() && self.wl_surface.as_ref().is_alive() 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 /// Retrieve the shell client owning this toplevel surface
/// ///
/// Returns `None` if the surface does actually no longer exist. /// Returns `None` if the surface does actually no longer exist.

View File

@ -1,10 +1,9 @@
use std::cell::Cell; use std::cell::Cell;
use cgmath::Vector2;
use smithay::{ use smithay::{
backend::{ backend::{
allocator::dmabuf::Dmabuf, allocator::dmabuf::Dmabuf,
renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, Transform}, renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, TextureFilter, Transform},
SwapBuffersError, SwapBuffersError,
}, },
reexports::wayland_server::protocol::wl_buffer, reexports::wayland_server::protocol::wl_buffer,
@ -28,7 +27,7 @@ impl Renderer for DummyRenderer {
fn render<F, R>( fn render<F, R>(
&mut self, &mut self,
_size: Size<i32, Physical>, _size: Size<i32, Physical>,
_transform: Transform, _dst_transform: Transform,
rendering: F, rendering: F,
) -> Result<R, Self::Error> ) -> Result<R, Self::Error>
where where
@ -37,6 +36,14 @@ impl Renderer for DummyRenderer {
let mut frame = DummyFrame {}; let mut frame = DummyFrame {};
Ok(rendering(self, &mut frame)) 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 { impl ImportShm for DummyRenderer {
@ -94,11 +101,12 @@ impl Frame for DummyFrame {
Ok(()) Ok(())
} }
fn render_texture( fn render_texture_from_to(
&mut self, &mut self,
_texture: &Self::TextureId, _texture: &Self::TextureId,
_matrix: cgmath::Matrix3<f32>, _src: Rectangle<i32, Buffer>,
_tex_coords: [Vector2<f32>; 4], _dst: Rectangle<f64, Physical>,
_src_transform: Transform,
_alpha: f32, _alpha: f32,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
Ok(()) Ok(())