Merge branch 'master' into input/remove-dispatch-new
This commit is contained in:
commit
d1fae4ba4e
|
@ -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
|
||||
|
||||
|
|
|
@ -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<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 {
|
||||
let keycode = evt.key_code();
|
||||
let state = evt.state();
|
||||
|
@ -143,72 +167,72 @@ impl<Backend> AnvilState<Backend> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
impl AnvilState<WinitData> {
|
||||
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
|
||||
#[cfg(any(feature = "winit", feature = "x11"))]
|
||||
impl<Backend> AnvilState<Backend> {
|
||||
pub fn process_input_event_windowed<B: InputBackend>(&mut self, event: InputEvent<B>, output_name: &str) {
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
InputEvent::Keyboard { event } => match self.keyboard_key_to_action::<B>(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::<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)
|
||||
|
||||
InputEvent::PointerMotionAbsolute { event } => {
|
||||
self.on_pointer_move_absolute_windowed::<B>(event, output_name)
|
||||
}
|
||||
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
|
||||
.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<UdevData> {
|
|||
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);
|
||||
}
|
||||
#[cfg(feature = "udev")]
|
||||
KeyAction::VtSwitch(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);
|
||||
}
|
||||
}
|
||||
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<UdevData> {
|
|||
.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::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
|
||||
#[derive(Debug)]
|
||||
enum KeyAction {
|
||||
|
|
|
@ -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),
|
||||
|
||||
_ => (),
|
||||
})
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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::<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);
|
||||
|
||||
trace!(logger, "Plane formats: {:?}", plane_formats);
|
||||
|
|
|
@ -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<L>(context: EGLContext, logger: L) -> Result<Gles2Renderer, Gles2Error>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
|
@ -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<F, R>(
|
||||
&mut self,
|
||||
size: Size<i32, Physical>,
|
||||
|
@ -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<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>,
|
||||
tex_coords: [Vector2<f32>; 4],
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error> {
|
||||
) -> Result<(), Gles2Error> {
|
||||
//apply output transformation
|
||||
matrix = self.current_projection * matrix;
|
||||
|
||||
|
|
|
@ -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<f32> {
|
||||
|
@ -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<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
|
||||
/// 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<f64, Physical>,
|
||||
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<i32, Buffer>,
|
||||
dest: Rectangle<f64, Physical>,
|
||||
transform: Transform,
|
||||
dst: Rectangle<f64, Physical>,
|
||||
src_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)
|
||||
}
|
||||
) -> 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<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.
|
||||
///
|
||||
/// This function *may* error, if:
|
||||
|
@ -265,7 +238,7 @@ pub trait Renderer {
|
|||
fn render<F, R>(
|
||||
&mut self,
|
||||
size: Size<i32, Physical>,
|
||||
transform: Transform,
|
||||
dst_transform: Transform,
|
||||
rendering: F,
|
||||
) -> Result<R, Self::Error>
|
||||
where
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -18,7 +18,7 @@ pub struct Buffer;
|
|||
pub struct Raw;
|
||||
|
||||
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 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> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<F, R>(
|
||||
&mut self,
|
||||
_size: Size<i32, Physical>,
|
||||
_transform: Transform,
|
||||
_dst_transform: Transform,
|
||||
rendering: F,
|
||||
) -> Result<R, Self::Error>
|
||||
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<f32>,
|
||||
_tex_coords: [Vector2<f32>; 4],
|
||||
_src: Rectangle<i32, Buffer>,
|
||||
_dst: Rectangle<f64, Physical>,
|
||||
_src_transform: Transform,
|
||||
_alpha: f32,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in New Issue