all: implement output transforms
This commit is contained in:
parent
79df8d69f4
commit
b7d2964e19
20 changed files with 254 additions and 71 deletions
|
|
@ -15,7 +15,7 @@ use {
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
video::{
|
video::{
|
||||||
connector_type::{ConnectorType, CON_UNKNOWN},
|
connector_type::{ConnectorType, CON_UNKNOWN},
|
||||||
Connector, DrmDevice, GfxApi, Mode,
|
Connector, DrmDevice, GfxApi, Mode, Transform,
|
||||||
},
|
},
|
||||||
Axis, Direction, ModifiedKeySym, PciId, Workspace,
|
Axis, Direction, ModifiedKeySym, PciId, Workspace,
|
||||||
},
|
},
|
||||||
|
|
@ -473,6 +473,13 @@ impl Client {
|
||||||
self.send(&ClientMessage::ConnectorSetEnabled { connector, enabled });
|
self.send(&ClientMessage::ConnectorSetEnabled { connector, enabled });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connector_set_transform(&self, connector: Connector, transform: Transform) {
|
||||||
|
self.send(&ClientMessage::ConnectorSetTransform {
|
||||||
|
connector,
|
||||||
|
transform,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn device_connectors(&self, device: DrmDevice) -> Vec<Connector> {
|
pub fn device_connectors(&self, device: DrmDevice) -> Vec<Connector> {
|
||||||
let res = self.send_with_response(&ClientMessage::GetDeviceConnectors { device });
|
let res = self.send_with_response(&ClientMessage::GetDeviceConnectors { device });
|
||||||
get_response!(res, vec![], GetDeviceConnectors { connectors });
|
get_response!(res, vec![], GetDeviceConnectors { connectors });
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
logging::LogLevel,
|
logging::LogLevel,
|
||||||
theme::{colors::Colorable, sized::Resizable, Color},
|
theme::{colors::Colorable, sized::Resizable, Color},
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
video::{connector_type::ConnectorType, Connector, DrmDevice, GfxApi},
|
video::{connector_type::ConnectorType, Connector, DrmDevice, GfxApi, Transform},
|
||||||
Axis, Direction, PciId, Workspace,
|
Axis, Direction, PciId, Workspace,
|
||||||
},
|
},
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
|
|
@ -342,6 +342,10 @@ pub enum ClientMessage<'a> {
|
||||||
device: Option<DrmDevice>,
|
device: Option<DrmDevice>,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
},
|
},
|
||||||
|
ConnectorSetTransform {
|
||||||
|
connector: Connector,
|
||||||
|
transform: Transform,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,15 @@ impl Connector {
|
||||||
}
|
}
|
||||||
get!().connector_set_enabled(self, enabled);
|
get!().connector_set_enabled(self, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the transformation to apply to the content of this connector.
|
||||||
|
pub fn set_transform(self, transform: Transform) {
|
||||||
|
if !self.exists() {
|
||||||
|
log::warn!("set_transform called on a connector that does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
get!().connector_set_transform(self, transform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all available DRM devices.
|
/// Returns all available DRM devices.
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ pub trait HardwareCursor: Debug {
|
||||||
fn set_position(&self, x: i32, y: i32);
|
fn set_position(&self, x: i32, y: i32);
|
||||||
fn swap_buffer(&self);
|
fn swap_buffer(&self);
|
||||||
fn commit(&self);
|
fn commit(&self);
|
||||||
fn max_size(&self) -> (i32, i32);
|
fn size(&self) -> (i32, i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TransformMatrix = [[f64; 2]; 2];
|
pub type TransformMatrix = [[f64; 2]; 2];
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use {
|
||||||
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
|
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell,
|
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell,
|
||||||
opaque_cell::OpaqueCell, oserror::OsError, syncqueue::SyncQueue,
|
opaque_cell::OpaqueCell, oserror::OsError, syncqueue::SyncQueue,
|
||||||
|
transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBufId,
|
dmabuf::DmaBufId,
|
||||||
|
|
@ -37,7 +38,7 @@ use {
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
bstr::{BString, ByteSlice},
|
bstr::{BString, ByteSlice},
|
||||||
indexmap::{indexset, IndexSet},
|
indexmap::{indexset, IndexSet},
|
||||||
jay_config::video::{GfxApi, Transform},
|
jay_config::video::GfxApi,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
|
|
@ -284,7 +285,7 @@ impl HardwareCursor for MetalHardwareCursor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_size(&self) -> (i32, i32) {
|
fn size(&self) -> (i32, i32) {
|
||||||
(
|
(
|
||||||
self.connector.dev.cursor_width as _,
|
self.connector.dev.cursor_width as _,
|
||||||
self.connector.dev.cursor_height as _,
|
self.connector.dev.cursor_height as _,
|
||||||
|
|
@ -473,7 +474,7 @@ impl MetalConnector {
|
||||||
}
|
}
|
||||||
ct
|
ct
|
||||||
};
|
};
|
||||||
if ct.source.buffer_transform != Transform::None {
|
if ct.source.buffer_transform != ct.target.output_transform {
|
||||||
// Rotations and mirroring are not supported.
|
// Rotations and mirroring are not supported.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -489,11 +490,15 @@ impl MetalConnector {
|
||||||
let (x1, x2, y1, y2) = {
|
let (x1, x2, y1, y2) = {
|
||||||
let plane_w = plane.mode_w.get() as f32;
|
let plane_w = plane.mode_w.get() as f32;
|
||||||
let plane_h = plane.mode_h.get() as f32;
|
let plane_h = plane.mode_h.get() as f32;
|
||||||
|
let ((x1, x2), (y1, y2)) = ct
|
||||||
|
.target
|
||||||
|
.output_transform
|
||||||
|
.maybe_swap(((ct.target.x1, ct.target.x2), (ct.target.y1, ct.target.y2)));
|
||||||
(
|
(
|
||||||
(ct.target.x1 + 1.0) * plane_w / 2.0,
|
(x1 + 1.0) * plane_w / 2.0,
|
||||||
(ct.target.x2 + 1.0) * plane_w / 2.0,
|
(x2 + 1.0) * plane_w / 2.0,
|
||||||
(ct.target.y1 + 1.0) * plane_h / 2.0,
|
(y1 + 1.0) * plane_h / 2.0,
|
||||||
(ct.target.y2 + 1.0) * plane_h / 2.0,
|
(y2 + 1.0) * plane_h / 2.0,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let (crtc_w, crtc_h) = (x2 - x1, y2 - y1);
|
let (crtc_w, crtc_h) = (x2 - x1, y2 - y1);
|
||||||
|
|
@ -594,6 +599,7 @@ impl MetalConnector {
|
||||||
output.global.preferred_scale.get(),
|
output.global.preferred_scale.get(),
|
||||||
render_hw_cursor,
|
render_hw_cursor,
|
||||||
output.has_fullscreen(),
|
output.has_fullscreen(),
|
||||||
|
output.global.transform.get(),
|
||||||
);
|
);
|
||||||
let try_direct_scanout = try_direct_scanout
|
let try_direct_scanout = try_direct_scanout
|
||||||
&& self.direct_scanout_enabled()
|
&& self.direct_scanout_enabled()
|
||||||
|
|
@ -719,7 +725,7 @@ impl MetalConnector {
|
||||||
buffer.dev_fb.copy_texture(tex, 0, 0);
|
buffer.dev_fb.copy_texture(tex, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (width, height) = buffer.dev_fb.size();
|
let (width, height) = buffer.dev_fb.physical_size();
|
||||||
changes.change_object(plane.id, |c| {
|
changes.change_object(plane.id, |c| {
|
||||||
c.change(plane.fb_id, buffer.drm.id().0 as _);
|
c.change(plane.fb_id, buffer.drm.id().0 as _);
|
||||||
c.change(plane.crtc_id.id, crtc.id.0 as _);
|
c.change(plane.crtc_id.id, crtc.id.0 as _);
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,7 @@ fn start_compositor2(
|
||||||
dma_buf_ids: Default::default(),
|
dma_buf_ids: Default::default(),
|
||||||
drm_feedback_ids: Default::default(),
|
drm_feedback_ids: Default::default(),
|
||||||
direct_scanout_enabled: Cell::new(true),
|
direct_scanout_enabled: Cell::new(true),
|
||||||
|
output_transforms: Default::default(),
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ use {
|
||||||
logging::LogLevel,
|
logging::LogLevel,
|
||||||
theme::{colors::Colorable, sized::Resizable},
|
theme::{colors::Colorable, sized::Resizable},
|
||||||
timer::Timer as JayTimer,
|
timer::Timer as JayTimer,
|
||||||
video::{Connector, DrmDevice, GfxApi},
|
video::{Connector, DrmDevice, GfxApi, Transform},
|
||||||
Axis, Direction, Workspace,
|
Axis, Direction, Workspace,
|
||||||
},
|
},
|
||||||
libloading::Library,
|
libloading::Library,
|
||||||
|
|
@ -751,6 +751,17 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_connector_set_transform(
|
||||||
|
&self,
|
||||||
|
connector: Connector,
|
||||||
|
transform: Transform,
|
||||||
|
) -> Result<(), CphError> {
|
||||||
|
let connector = self.get_output(connector)?;
|
||||||
|
connector.node.update_transform(transform);
|
||||||
|
self.state.damage();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_connector_set_position(
|
fn handle_connector_set_position(
|
||||||
&self,
|
&self,
|
||||||
connector: Connector,
|
connector: Connector,
|
||||||
|
|
@ -1338,6 +1349,12 @@ impl ConfigProxyHandler {
|
||||||
ClientMessage::SetDirectScanoutEnabled { device, enabled } => self
|
ClientMessage::SetDirectScanoutEnabled { device, enabled } => self
|
||||||
.handle_set_direct_scanout_enabled(device, enabled)
|
.handle_set_direct_scanout_enabled(device, enabled)
|
||||||
.wrn("set_direct_scanout_enabled")?,
|
.wrn("set_direct_scanout_enabled")?,
|
||||||
|
ClientMessage::ConnectorSetTransform {
|
||||||
|
connector,
|
||||||
|
transform,
|
||||||
|
} => self
|
||||||
|
.handle_connector_set_transform(connector, transform)
|
||||||
|
.wrn("connector_set_transform")?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,7 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed
|
||||||
} else {
|
} else {
|
||||||
img.extents.move_(x.round_down(), y.round_down())
|
img.extents.move_(x.round_down(), y.round_down())
|
||||||
};
|
};
|
||||||
if extents.intersects(&renderer.physical_extents()) {
|
if extents.intersects(&renderer.pixel_extents()) {
|
||||||
renderer.base.render_texture(
|
renderer.base.render_texture(
|
||||||
&img.tex,
|
&img.tex,
|
||||||
extents.x1(),
|
extents.x1(),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use {
|
||||||
state::State,
|
state::State,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
tree::{Node, OutputNode},
|
tree::{Node, OutputNode},
|
||||||
utils::numcell::NumCell,
|
utils::{numcell::NumCell, transform_ext::TransformExt},
|
||||||
video::{dmabuf::DmaBuf, gbm::GbmDevice, Modifier},
|
video::{dmabuf::DmaBuf, gbm::GbmDevice, Modifier},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
@ -86,24 +86,44 @@ pub struct FramebufferRect {
|
||||||
pub x2: f32,
|
pub x2: f32,
|
||||||
pub y1: f32,
|
pub y1: f32,
|
||||||
pub y2: f32,
|
pub y2: f32,
|
||||||
|
pub output_transform: Transform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FramebufferRect {
|
impl FramebufferRect {
|
||||||
pub fn new(x1: f32, y1: f32, x2: f32, y2: f32, width: f32, height: f32) -> Self {
|
pub fn new(
|
||||||
|
x1: f32,
|
||||||
|
y1: f32,
|
||||||
|
x2: f32,
|
||||||
|
y2: f32,
|
||||||
|
transform: Transform,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x1: 2.0 * x1 / width - 1.0,
|
x1: 2.0 * x1 / width - 1.0,
|
||||||
x2: 2.0 * x2 / width - 1.0,
|
x2: 2.0 * x2 / width - 1.0,
|
||||||
y1: 2.0 * y1 / height - 1.0,
|
y1: 2.0 * y1 / height - 1.0,
|
||||||
y2: 2.0 * y2 / height - 1.0,
|
y2: 2.0 * y2 / height - 1.0,
|
||||||
|
output_transform: transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_points(&self) -> [[f32; 2]; 4] {
|
pub fn to_points(&self) -> [[f32; 2]; 4] {
|
||||||
|
use Transform::*;
|
||||||
let x1 = self.x1;
|
let x1 = self.x1;
|
||||||
let x2 = self.x2;
|
let x2 = self.x2;
|
||||||
let y1 = self.y1;
|
let y1 = self.y1;
|
||||||
let y2 = self.y2;
|
let y2 = self.y2;
|
||||||
[[x2, y1], [x1, y1], [x2, y2], [x1, y2]]
|
match self.output_transform {
|
||||||
|
None => [[x2, y1], [x1, y1], [x2, y2], [x1, y2]],
|
||||||
|
Rotate90 => [[y1, -x2], [y1, -x1], [y2, -x2], [y2, -x1]],
|
||||||
|
Rotate180 => [[-x2, -y1], [-x1, -y1], [-x2, -y2], [-x1, -y2]],
|
||||||
|
Rotate270 => [[-y1, x2], [-y1, x1], [-y2, x2], [-y2, x1]],
|
||||||
|
Flip => [[-x2, y1], [-x1, y1], [-x2, y2], [-x1, y2]],
|
||||||
|
FlipRotate90 => [[y1, x2], [y1, x1], [y2, x2], [y2, x1]],
|
||||||
|
FlipRotate180 => [[x2, -y1], [x1, -y1], [x2, -y2], [x1, -y2]],
|
||||||
|
FlipRotate270 => [[-y1, -x2], [-y1, -x1], [-y2, -x2], [-y2, -x1]],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_covering(&self) -> bool {
|
pub fn is_covering(&self) -> bool {
|
||||||
|
|
@ -136,7 +156,7 @@ pub trait GfxFramebuffer: Debug {
|
||||||
|
|
||||||
fn take_render_ops(&self) -> Vec<GfxApiOpt>;
|
fn take_render_ops(&self) -> Vec<GfxApiOpt>;
|
||||||
|
|
||||||
fn size(&self) -> (i32, i32);
|
fn physical_size(&self) -> (i32, i32);
|
||||||
|
|
||||||
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>);
|
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>);
|
||||||
|
|
||||||
|
|
@ -164,13 +184,23 @@ impl dyn GfxFramebuffer {
|
||||||
self.render(ops, Some(&Color { r, g, b, a }));
|
self.render(ops, Some(&Color { r, g, b, a }));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn renderer_base<'a>(&self, ops: &'a mut Vec<GfxApiOpt>, scale: Scale) -> RendererBase<'a> {
|
pub fn logical_size(&self, transform: Transform) -> (i32, i32) {
|
||||||
let (width, height) = self.size();
|
transform.maybe_swap(self.physical_size())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn renderer_base<'a>(
|
||||||
|
&self,
|
||||||
|
ops: &'a mut Vec<GfxApiOpt>,
|
||||||
|
scale: Scale,
|
||||||
|
transform: Transform,
|
||||||
|
) -> RendererBase<'a> {
|
||||||
|
let (width, height) = self.logical_size(transform);
|
||||||
RendererBase {
|
RendererBase {
|
||||||
ops,
|
ops,
|
||||||
scaled: scale != 1,
|
scaled: scale != 1,
|
||||||
scale,
|
scale,
|
||||||
scalef: scale.to_f64(),
|
scalef: scale.to_f64(),
|
||||||
|
transform,
|
||||||
fb_width: width as _,
|
fb_width: width as _,
|
||||||
fb_height: height as _,
|
fb_height: height as _,
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +209,7 @@ impl dyn GfxFramebuffer {
|
||||||
pub fn copy_texture(&self, texture: &Rc<dyn GfxTexture>, x: i32, y: i32) {
|
pub fn copy_texture(&self, texture: &Rc<dyn GfxTexture>, x: i32, y: i32) {
|
||||||
let mut ops = self.take_render_ops();
|
let mut ops = self.take_render_ops();
|
||||||
let scale = Scale::from_int(1);
|
let scale = Scale::from_int(1);
|
||||||
let mut renderer = self.renderer_base(&mut ops, scale);
|
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
|
||||||
renderer.render_texture(texture, x, y, None, None, scale, None);
|
renderer.render_texture(texture, x, y, None, None, scale, None);
|
||||||
let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT);
|
let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT);
|
||||||
self.render(ops, clear);
|
self.render(ops, clear);
|
||||||
|
|
@ -192,7 +222,7 @@ impl dyn GfxFramebuffer {
|
||||||
f: &mut dyn FnMut(&mut RendererBase),
|
f: &mut dyn FnMut(&mut RendererBase),
|
||||||
) {
|
) {
|
||||||
let mut ops = self.take_render_ops();
|
let mut ops = self.take_render_ops();
|
||||||
let mut renderer = self.renderer_base(&mut ops, scale);
|
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
|
||||||
f(&mut renderer);
|
f(&mut renderer);
|
||||||
self.render(ops, clear);
|
self.render(ops, clear);
|
||||||
}
|
}
|
||||||
|
|
@ -206,15 +236,18 @@ impl dyn GfxFramebuffer {
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
render_hardware_cursor: bool,
|
render_hardware_cursor: bool,
|
||||||
black_background: bool,
|
black_background: bool,
|
||||||
|
transform: Transform,
|
||||||
) -> GfxRenderPass {
|
) -> GfxRenderPass {
|
||||||
let mut ops = self.take_render_ops();
|
let mut ops = self.take_render_ops();
|
||||||
let (width, height) = self.size();
|
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
base: self.renderer_base(&mut ops, scale),
|
base: self.renderer_base(&mut ops, scale, transform),
|
||||||
state,
|
state,
|
||||||
result,
|
result,
|
||||||
logical_extents: node.node_absolute_position().at_point(0, 0),
|
logical_extents: node.node_absolute_position().at_point(0, 0),
|
||||||
physical_extents: Rect::new(0, 0, width, height).unwrap(),
|
pixel_extents: {
|
||||||
|
let (width, height) = self.logical_size(transform);
|
||||||
|
Rect::new(0, 0, width, height).unwrap()
|
||||||
|
},
|
||||||
};
|
};
|
||||||
node.node_render(&mut renderer, 0, 0, None);
|
node.node_render(&mut renderer, 0, 0, None);
|
||||||
if let Some(rect) = cursor_rect {
|
if let Some(rect) = cursor_rect {
|
||||||
|
|
@ -272,6 +305,7 @@ impl dyn GfxFramebuffer {
|
||||||
scale,
|
scale,
|
||||||
render_hardware_cursor,
|
render_hardware_cursor,
|
||||||
node.has_fullscreen(),
|
node.has_fullscreen(),
|
||||||
|
node.global.transform.get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,6 +318,7 @@ impl dyn GfxFramebuffer {
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
render_hardware_cursor: bool,
|
render_hardware_cursor: bool,
|
||||||
black_background: bool,
|
black_background: bool,
|
||||||
|
transform: Transform,
|
||||||
) {
|
) {
|
||||||
let pass = self.create_render_pass(
|
let pass = self.create_render_pass(
|
||||||
node,
|
node,
|
||||||
|
|
@ -293,19 +328,28 @@ impl dyn GfxFramebuffer {
|
||||||
scale,
|
scale,
|
||||||
render_hardware_cursor,
|
render_hardware_cursor,
|
||||||
black_background,
|
black_background,
|
||||||
|
transform,
|
||||||
);
|
);
|
||||||
self.perform_render_pass(pass);
|
self.perform_render_pass(pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_hardware_cursor(&self, cursor: &dyn Cursor, state: &State, scale: Scale) {
|
pub fn render_hardware_cursor(
|
||||||
|
&self,
|
||||||
|
cursor: &dyn Cursor,
|
||||||
|
state: &State,
|
||||||
|
scale: Scale,
|
||||||
|
transform: Transform,
|
||||||
|
) {
|
||||||
let mut ops = self.take_render_ops();
|
let mut ops = self.take_render_ops();
|
||||||
let (width, height) = self.size();
|
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
base: self.renderer_base(&mut ops, scale),
|
base: self.renderer_base(&mut ops, scale, transform),
|
||||||
state,
|
state,
|
||||||
result: None,
|
result: None,
|
||||||
logical_extents: Rect::new_empty(0, 0),
|
logical_extents: Rect::new_empty(0, 0),
|
||||||
physical_extents: Rect::new(0, 0, width, height).unwrap(),
|
pixel_extents: {
|
||||||
|
let (width, height) = self.logical_size(transform);
|
||||||
|
Rect::new(0, 0, width, height).unwrap()
|
||||||
|
},
|
||||||
};
|
};
|
||||||
cursor.render_hardware_cursor(&mut renderer);
|
cursor.render_hardware_cursor(&mut renderer);
|
||||||
self.render(ops, Some(&Color::TRANSPARENT));
|
self.render(ops, Some(&Color::TRANSPARENT));
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ impl GfxFramebuffer for Framebuffer {
|
||||||
ops
|
ops
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> (i32, i32) {
|
fn physical_size(&self) -> (i32, i32) {
|
||||||
(self.gl.width, self.gl.height)
|
(self.gl.width, self.gl.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -524,7 +524,7 @@ impl GfxFramebuffer for VulkanImage {
|
||||||
self.render_ops.take()
|
self.render_ops.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> (i32, i32) {
|
fn physical_size(&self) -> (i32, i32) {
|
||||||
(self.width as _, self.height as _)
|
(self.width as _, self.height as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@ impl JayScreencast {
|
||||||
x_off,
|
x_off,
|
||||||
y_off,
|
y_off,
|
||||||
size,
|
size,
|
||||||
|
on.global.transform.get(),
|
||||||
);
|
);
|
||||||
self.client.event(Ready {
|
self.client.event(Ready {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
|
|
@ -217,7 +218,7 @@ impl JayScreencast {
|
||||||
_ => return Err(JayScreencastError::XRGB8888),
|
_ => return Err(JayScreencastError::XRGB8888),
|
||||||
};
|
};
|
||||||
if let Some(output) = self.output.get() {
|
if let Some(output) = self.output.get() {
|
||||||
let mode = output.global.mode.get();
|
let (width, height) = output.global.pixel_size();
|
||||||
let num = 3;
|
let num = 3;
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
let mut usage = GBM_BO_USE_RENDERING;
|
let mut usage = GBM_BO_USE_RENDERING;
|
||||||
|
|
@ -241,8 +242,8 @@ impl JayScreencast {
|
||||||
};
|
};
|
||||||
let buffer = ctx.gbm().create_bo(
|
let buffer = ctx.gbm().create_bo(
|
||||||
&self.client.state.dma_buf_ids,
|
&self.client.state.dma_buf_ids,
|
||||||
mode.width,
|
width,
|
||||||
mode.height,
|
height,
|
||||||
XRGB8888,
|
XRGB8888,
|
||||||
modifiers,
|
modifiers,
|
||||||
usage,
|
usage,
|
||||||
|
|
@ -492,10 +493,7 @@ efrom!(JayScreencastError, ClientError);
|
||||||
|
|
||||||
fn output_size(output: &Option<Rc<OutputNode>>) -> (i32, i32) {
|
fn output_size(output: &Option<Rc<OutputNode>>) -> (i32, i32) {
|
||||||
match output {
|
match output {
|
||||||
Some(o) => {
|
Some(o) => o.global.pixel_size(),
|
||||||
let mode = o.global.mode.get();
|
|
||||||
(mode.width, mode.height)
|
|
||||||
}
|
|
||||||
_ => (0, 0),
|
_ => (0, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,12 @@ use {
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
linkedlist::LinkedList,
|
linkedlist::LinkedList,
|
||||||
|
transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
wire::{wl_output::*, WlOutputId, ZxdgOutputV1Id},
|
wire::{wl_output::*, WlOutputId, ZxdgOutputV1Id},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
jay_config::video::Transform,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::hash_map::Entry,
|
collections::hash_map::Entry,
|
||||||
|
|
@ -73,9 +75,10 @@ pub struct WlOutputGlobal {
|
||||||
pub destroyed: Cell<bool>,
|
pub destroyed: Cell<bool>,
|
||||||
pub legacy_scale: Cell<u32>,
|
pub legacy_scale: Cell<u32>,
|
||||||
pub preferred_scale: Cell<crate::scale::Scale>,
|
pub preferred_scale: Cell<crate::scale::Scale>,
|
||||||
|
pub transform: Cell<Transform>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq, Hash)]
|
||||||
pub struct OutputId {
|
pub struct OutputId {
|
||||||
pub manufacturer: String,
|
pub manufacturer: String,
|
||||||
pub model: String,
|
pub model: String,
|
||||||
|
|
@ -100,16 +103,24 @@ impl WlOutputGlobal {
|
||||||
width_mm: i32,
|
width_mm: i32,
|
||||||
height_mm: i32,
|
height_mm: i32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let output_id = Rc::new(OutputId {
|
||||||
|
manufacturer: manufacturer.to_string(),
|
||||||
|
model: product.to_string(),
|
||||||
|
serial_number: serial_number.to_string(),
|
||||||
|
});
|
||||||
|
let transform = state
|
||||||
|
.output_transforms
|
||||||
|
.borrow()
|
||||||
|
.get(&output_id)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(Transform::None);
|
||||||
|
let (width, height) = transform.maybe_swap((mode.width, mode.height));
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
connector: connector.clone(),
|
connector: connector.clone(),
|
||||||
pos: Cell::new(Rect::new_sized(x1, 0, mode.width, mode.height).unwrap()),
|
pos: Cell::new(Rect::new_sized(x1, 0, width, height).unwrap()),
|
||||||
output_id: Rc::new(OutputId {
|
output_id,
|
||||||
manufacturer: manufacturer.to_string(),
|
|
||||||
model: product.to_string(),
|
|
||||||
serial_number: serial_number.to_string(),
|
|
||||||
}),
|
|
||||||
mode: Cell::new(*mode),
|
mode: Cell::new(*mode),
|
||||||
node: Default::default(),
|
node: Default::default(),
|
||||||
width_mm,
|
width_mm,
|
||||||
|
|
@ -120,6 +131,7 @@ impl WlOutputGlobal {
|
||||||
destroyed: Cell::new(false),
|
destroyed: Cell::new(false),
|
||||||
legacy_scale: Cell::new(1),
|
legacy_scale: Cell::new(1),
|
||||||
preferred_scale: Cell::new(crate::scale::Scale::from_int(1)),
|
preferred_scale: Cell::new(crate::scale::Scale::from_int(1)),
|
||||||
|
transform: Cell::new(transform),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,6 +252,7 @@ impl WlOutputGlobal {
|
||||||
mem,
|
mem,
|
||||||
*stride,
|
*stride,
|
||||||
wl_buffer.format,
|
wl_buffer.format,
|
||||||
|
Transform::None,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let fb = match wl_buffer.famebuffer.get() {
|
let fb = match wl_buffer.famebuffer.get() {
|
||||||
|
|
@ -258,6 +271,7 @@ impl WlOutputGlobal {
|
||||||
x_off - capture.rect.x1(),
|
x_off - capture.rect.x1(),
|
||||||
y_off - capture.rect.y1(),
|
y_off - capture.rect.y1(),
|
||||||
size,
|
size,
|
||||||
|
Transform::None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if capture.with_damage.get() {
|
if capture.with_damage.get() {
|
||||||
|
|
@ -269,6 +283,11 @@ impl WlOutputGlobal {
|
||||||
capture.output_link.take();
|
capture.output_link.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pixel_size(&self) -> (i32, i32) {
|
||||||
|
let mode = self.mode.get();
|
||||||
|
self.transform.get().maybe_swap((mode.width, mode.height))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global_base!(WlOutputGlobal, WlOutput, WlOutputError);
|
global_base!(WlOutputGlobal, WlOutput, WlOutputError);
|
||||||
|
|
@ -314,7 +333,7 @@ impl WlOutput {
|
||||||
subpixel: SP_UNKNOWN,
|
subpixel: SP_UNKNOWN,
|
||||||
make: &self.global.output_id.manufacturer,
|
make: &self.global.output_id.manufacturer,
|
||||||
model: &self.global.output_id.model,
|
model: &self.global.output_id.model,
|
||||||
transform: TF_NORMAL,
|
transform: self.global.transform.get().to_wl(),
|
||||||
};
|
};
|
||||||
self.client.event(event);
|
self.client.event(event);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ use {
|
||||||
linkedlist::LinkedNode,
|
linkedlist::LinkedNode,
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
rc_eq::rc_eq,
|
rc_eq::rc_eq,
|
||||||
|
transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
wire::{
|
wire::{
|
||||||
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
||||||
|
|
@ -264,11 +265,13 @@ impl WlSeatGlobal {
|
||||||
let (x, y) = self.get_position();
|
let (x, y) = self.get_position();
|
||||||
for output in self.state.root.outputs.lock().values() {
|
for output in self.state.root.outputs.lock().values() {
|
||||||
if let Some(hc) = output.hardware_cursor.get() {
|
if let Some(hc) = output.hardware_cursor.get() {
|
||||||
|
let transform = output.global.transform.get();
|
||||||
let render = render | output.hardware_cursor_needs_render.take();
|
let render = render | output.hardware_cursor_needs_render.take();
|
||||||
let scale = output.global.preferred_scale.get();
|
let scale = output.global.preferred_scale.get();
|
||||||
let extents = cursor.extents_at_scale(scale);
|
let extents = cursor.extents_at_scale(scale);
|
||||||
|
let (hc_width, hc_height) = hc.size();
|
||||||
if render {
|
if render {
|
||||||
let (max_width, max_height) = hc.max_size();
|
let (max_width, max_height) = transform.maybe_swap((hc_width, hc_height));
|
||||||
if extents.width() > max_width || extents.height() > max_height {
|
if extents.width() > max_width || extents.height() > max_height {
|
||||||
hc.set_enabled(false);
|
hc.set_enabled(false);
|
||||||
hc.commit();
|
hc.commit();
|
||||||
|
|
@ -285,17 +288,25 @@ impl WlSeatGlobal {
|
||||||
x_rel = ((x - Fixed::from_int(opos.x1())).to_f64() * scalef).round() as i32;
|
x_rel = ((x - Fixed::from_int(opos.x1())).to_f64() * scalef).round() as i32;
|
||||||
y_rel = ((y - Fixed::from_int(opos.y1())).to_f64() * scalef).round() as i32;
|
y_rel = ((y - Fixed::from_int(opos.y1())).to_f64() * scalef).round() as i32;
|
||||||
}
|
}
|
||||||
let mode = output.global.mode.get();
|
let (width, height) = output.global.pixel_size();
|
||||||
if extents
|
if extents.intersects(&Rect::new_sized(-x_rel, -y_rel, width, height).unwrap()) {
|
||||||
.intersects(&Rect::new_sized(-x_rel, -y_rel, mode.width, mode.height).unwrap())
|
|
||||||
{
|
|
||||||
if render {
|
if render {
|
||||||
let buffer = hc.get_buffer();
|
let buffer = hc.get_buffer();
|
||||||
buffer.render_hardware_cursor(cursor.deref(), &self.state, scale);
|
buffer.render_hardware_cursor(
|
||||||
|
cursor.deref(),
|
||||||
|
&self.state,
|
||||||
|
scale,
|
||||||
|
transform,
|
||||||
|
);
|
||||||
hc.swap_buffer();
|
hc.swap_buffer();
|
||||||
}
|
}
|
||||||
hc.set_enabled(true);
|
hc.set_enabled(true);
|
||||||
hc.set_position(x_rel + extents.x1(), y_rel + extents.y1());
|
let mode = output.global.mode.get();
|
||||||
|
let (x_rel, y_rel) =
|
||||||
|
transform.apply_point(mode.width, mode.height, (x_rel, y_rel));
|
||||||
|
let (hot_x, hot_y) =
|
||||||
|
transform.apply_point(hc_width, hc_height, (-extents.x1(), -extents.y1()));
|
||||||
|
hc.set_position(x_rel - hot_x, y_rel - hot_y);
|
||||||
} else {
|
} else {
|
||||||
if render {
|
if render {
|
||||||
output.hardware_cursor_needs_render.set(true);
|
output.hardware_cursor_needs_render.set(true);
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ const INVALID_SIZE: u32 = 2;
|
||||||
|
|
||||||
const OFFSET_SINCE: u32 = 5;
|
const OFFSET_SINCE: u32 = 5;
|
||||||
const BUFFER_SCALE_SINCE: u32 = 6;
|
const BUFFER_SCALE_SINCE: u32 = 6;
|
||||||
|
const TRANSFORM_SINCE: u32 = 6;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum SurfaceRole {
|
pub enum SurfaceRole {
|
||||||
|
|
@ -117,6 +118,14 @@ impl NodeVisitorBase for SurfaceSendPreferredScaleVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SurfaceSendPreferredTransformVisitor;
|
||||||
|
impl NodeVisitorBase for SurfaceSendPreferredTransformVisitor {
|
||||||
|
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
|
||||||
|
node.send_preferred_buffer_transform();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WlSurface {
|
pub struct WlSurface {
|
||||||
pub id: WlSurfaceId,
|
pub id: WlSurfaceId,
|
||||||
pub node_id: SurfaceNodeId,
|
pub node_id: SurfaceNodeId,
|
||||||
|
|
@ -350,6 +359,9 @@ impl WlSurface {
|
||||||
if old.global.preferred_scale.get() != output.global.preferred_scale.get() {
|
if old.global.preferred_scale.get() != output.global.preferred_scale.get() {
|
||||||
self.on_scale_change();
|
self.on_scale_change();
|
||||||
}
|
}
|
||||||
|
if old.global.transform.get() != output.global.transform.get() {
|
||||||
|
self.send_preferred_buffer_transform();
|
||||||
|
}
|
||||||
let children = self.children.borrow_mut();
|
let children = self.children.borrow_mut();
|
||||||
if let Some(children) = &*children {
|
if let Some(children) = &*children {
|
||||||
for ss in children.subsurfaces.values() {
|
for ss in children.subsurfaces.values() {
|
||||||
|
|
@ -442,6 +454,15 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_preferred_buffer_transform(&self) {
|
||||||
|
if self.version >= TRANSFORM_SINCE {
|
||||||
|
self.client.event(PreferredBufferTransform {
|
||||||
|
self_id: self.id,
|
||||||
|
transform: self.output.get().global.transform.get().to_wl() as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_toplevel(&self, tl: Option<Rc<dyn ToplevelNode>>) {
|
fn set_toplevel(&self, tl: Option<Rc<dyn ToplevelNode>>) {
|
||||||
let ch = self.children.borrow();
|
let ch = self.children.borrow();
|
||||||
if let Some(ch) = &*ch {
|
if let Some(ch) = &*ch {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ pub struct Renderer<'a> {
|
||||||
pub state: &'a State,
|
pub state: &'a State,
|
||||||
pub result: Option<&'a mut RenderResult>,
|
pub result: Option<&'a mut RenderResult>,
|
||||||
pub logical_extents: Rect,
|
pub logical_extents: Rect,
|
||||||
pub physical_extents: Rect,
|
pub pixel_extents: Rect,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer<'_> {
|
impl Renderer<'_> {
|
||||||
|
|
@ -63,8 +63,8 @@ impl Renderer<'_> {
|
||||||
self.base.scale
|
self.base.scale
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn physical_extents(&self) -> Rect {
|
pub fn pixel_extents(&self) -> Rect {
|
||||||
self.physical_extents
|
self.pixel_extents
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn logical_extents(&self) -> Rect {
|
pub fn logical_extents(&self) -> Rect {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use {
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::transform_ext::TransformExt,
|
utils::transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
|
jay_config::video::Transform,
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -14,6 +15,7 @@ pub struct RendererBase<'a> {
|
||||||
pub scaled: bool,
|
pub scaled: bool,
|
||||||
pub scale: Scale,
|
pub scale: Scale,
|
||||||
pub scalef: f64,
|
pub scalef: f64,
|
||||||
|
pub transform: Transform,
|
||||||
pub fb_width: f32,
|
pub fb_width: f32,
|
||||||
pub fb_height: f32,
|
pub fb_height: f32,
|
||||||
}
|
}
|
||||||
|
|
@ -78,6 +80,7 @@ impl RendererBase<'_> {
|
||||||
(bx.y1() + dy) as f32,
|
(bx.y1() + dy) as f32,
|
||||||
(bx.x2() + dx) as f32,
|
(bx.x2() + dx) as f32,
|
||||||
(bx.y2() + dy) as f32,
|
(bx.y2() + dy) as f32,
|
||||||
|
self.transform,
|
||||||
self.fb_width,
|
self.fb_width,
|
||||||
self.fb_height,
|
self.fb_height,
|
||||||
),
|
),
|
||||||
|
|
@ -109,6 +112,7 @@ impl RendererBase<'_> {
|
||||||
y1 + dy,
|
y1 + dy,
|
||||||
x2 + dx,
|
x2 + dx,
|
||||||
y2 + dy,
|
y2 + dy,
|
||||||
|
self.transform,
|
||||||
self.fb_width,
|
self.fb_width,
|
||||||
self.fb_height,
|
self.fb_height,
|
||||||
),
|
),
|
||||||
|
|
@ -158,6 +162,7 @@ impl RendererBase<'_> {
|
||||||
target_y[0] as f32,
|
target_y[0] as f32,
|
||||||
target_x[1] as f32,
|
target_x[1] as f32,
|
||||||
target_y[1] as f32,
|
target_y[1] as f32,
|
||||||
|
self.transform,
|
||||||
self.fb_width,
|
self.fb_width,
|
||||||
self.fb_height,
|
self.fb_height,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use {
|
||||||
INVALID_MODIFIER, LINEAR_MODIFIER,
|
INVALID_MODIFIER, LINEAR_MODIFIER,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
jay_config::video::Transform,
|
||||||
std::{ops::Deref, rc::Rc},
|
std::{ops::Deref, rc::Rc},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::OwnedFd,
|
uapi::OwnedFd,
|
||||||
|
|
@ -76,6 +77,7 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
|
||||||
Scale::from_int(1),
|
Scale::from_int(1),
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
Transform::None,
|
||||||
);
|
);
|
||||||
let drm = gbm.drm.dup_render()?.fd().clone();
|
let drm = gbm.drm.dup_render()?.fd().clone();
|
||||||
Ok(Screenshot { drm, bo })
|
Ok(Screenshot { drm, bo })
|
||||||
|
|
|
||||||
37
src/state.rs
37
src/state.rs
|
|
@ -17,7 +17,7 @@ use {
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture, SampleRect},
|
||||||
gfx_apis::create_gfx_context,
|
gfx_apis::create_gfx_context,
|
||||||
globals::{Globals, GlobalsError, WaylandGlobal},
|
globals::{Globals, GlobalsError, WaylandGlobal},
|
||||||
ifs::{
|
ifs::{
|
||||||
|
|
@ -27,6 +27,7 @@ use {
|
||||||
jay_seat_events::JaySeatEvents,
|
jay_seat_events::JaySeatEvents,
|
||||||
jay_workspace_watcher::JayWorkspaceWatcher,
|
jay_workspace_watcher::JayWorkspaceWatcher,
|
||||||
wl_drm::WlDrmGlobal,
|
wl_drm::WlDrmGlobal,
|
||||||
|
wl_output::OutputId,
|
||||||
wl_seat::{SeatIds, WlSeatGlobal},
|
wl_seat::{SeatIds, WlSeatGlobal},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
zwp_idle_inhibitor_v1::{IdleInhibitorId, IdleInhibitorIds, ZwpIdleInhibitorV1},
|
zwp_idle_inhibitor_v1::{IdleInhibitorId, IdleInhibitorIds, ZwpIdleInhibitorV1},
|
||||||
|
|
@ -65,7 +66,10 @@ use {
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
jay_config::{video::GfxApi, PciId},
|
jay_config::{
|
||||||
|
video::{GfxApi, Transform},
|
||||||
|
PciId,
|
||||||
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
|
|
@ -149,6 +153,7 @@ pub struct State {
|
||||||
pub dma_buf_ids: DmaBufIds,
|
pub dma_buf_ids: DmaBufIds,
|
||||||
pub drm_feedback_ids: DrmFeedbackIds,
|
pub drm_feedback_ids: DrmFeedbackIds,
|
||||||
pub direct_scanout_enabled: Cell<bool>,
|
pub direct_scanout_enabled: Cell<bool>,
|
||||||
|
pub output_transforms: RefCell<AHashMap<Rc<OutputId>, Transform>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Drop for State {
|
// impl Drop for State {
|
||||||
|
|
@ -767,19 +772,30 @@ impl State {
|
||||||
x_off: i32,
|
x_off: i32,
|
||||||
y_off: i32,
|
y_off: i32,
|
||||||
size: Option<(i32, i32)>,
|
size: Option<(i32, i32)>,
|
||||||
|
transform: Transform,
|
||||||
) {
|
) {
|
||||||
let mut ops = target.take_render_ops();
|
let mut ops = target.take_render_ops();
|
||||||
let (width, height) = target.size();
|
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
base: target.renderer_base(&mut ops, Scale::from_int(1)),
|
base: target.renderer_base(&mut ops, Scale::from_int(1), Transform::None),
|
||||||
state: self,
|
state: self,
|
||||||
result: None,
|
result: None,
|
||||||
logical_extents: position.at_point(0, 0),
|
logical_extents: position.at_point(0, 0),
|
||||||
physical_extents: Rect::new_sized(0, 0, width, height).unwrap(),
|
pixel_extents: {
|
||||||
|
let (width, height) = target.logical_size(Transform::None);
|
||||||
|
Rect::new_sized(0, 0, width, height).unwrap()
|
||||||
|
},
|
||||||
};
|
};
|
||||||
renderer
|
let mut sample_rect = SampleRect::identity();
|
||||||
.base
|
sample_rect.buffer_transform = transform;
|
||||||
.render_texture(src, x_off, y_off, None, size, Scale::from_int(1), None);
|
renderer.base.render_texture(
|
||||||
|
src,
|
||||||
|
x_off,
|
||||||
|
y_off,
|
||||||
|
Some(sample_rect),
|
||||||
|
size,
|
||||||
|
Scale::from_int(1),
|
||||||
|
None,
|
||||||
|
);
|
||||||
if render_hardware_cursors {
|
if render_hardware_cursors {
|
||||||
for seat in self.globals.lock_seats().values() {
|
for seat in self.globals.lock_seats().values() {
|
||||||
if let Some(cursor) = seat.get_cursor() {
|
if let Some(cursor) = seat.get_cursor() {
|
||||||
|
|
@ -817,13 +833,15 @@ impl State {
|
||||||
mem: &ClientMemOffset,
|
mem: &ClientMemOffset,
|
||||||
stride: i32,
|
stride: i32,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
|
transform: Transform,
|
||||||
) {
|
) {
|
||||||
let (src_width, src_height) = src.size();
|
let (src_width, src_height) = src.size();
|
||||||
let mut needs_copy = capture.rect.x1() < x_off
|
let mut needs_copy = capture.rect.x1() < x_off
|
||||||
|| capture.rect.x2() > x_off + src_width
|
|| capture.rect.x2() > x_off + src_width
|
||||||
|| capture.rect.y1() < y_off
|
|| capture.rect.y1() < y_off
|
||||||
|| capture.rect.y2() > y_off + src_height
|
|| capture.rect.y2() > y_off + src_height
|
||||||
|| self.have_hardware_cursor();
|
|| self.have_hardware_cursor()
|
||||||
|
|| transform != Transform::None;
|
||||||
if let Some((target_width, target_height)) = size {
|
if let Some((target_width, target_height)) = size {
|
||||||
if (target_width, target_height) != (src_width, src_height) {
|
if (target_width, target_height) != (src_width, src_height) {
|
||||||
needs_copy = true;
|
needs_copy = true;
|
||||||
|
|
@ -853,6 +871,7 @@ impl State {
|
||||||
x_off - capture.rect.x1(),
|
x_off - capture.rect.x1(),
|
||||||
y_off - capture.rect.y1(),
|
y_off - capture.rect.y1(),
|
||||||
size,
|
size,
|
||||||
|
transform,
|
||||||
);
|
);
|
||||||
mem.access(|mem| {
|
mem.access(|mem| {
|
||||||
fb.copy_to_shm(
|
fb.copy_to_shm(
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ use {
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
ext_session_lock_surface_v1::ExtSessionLockSurfaceV1,
|
ext_session_lock_surface_v1::ExtSessionLockSurfaceV1,
|
||||||
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, SurfaceSendPreferredScaleVisitor,
|
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, SurfaceSendPreferredScaleVisitor,
|
||||||
|
SurfaceSendPreferredTransformVisitor,
|
||||||
},
|
},
|
||||||
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
||||||
},
|
},
|
||||||
|
|
@ -34,6 +35,7 @@ use {
|
||||||
wire::{JayOutputId, JayScreencastId},
|
wire::{JayOutputId, JayScreencastId},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
jay_config::video::Transform,
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
@ -386,15 +388,30 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_mode(self: &Rc<Self>, mode: Mode) {
|
pub fn update_mode(self: &Rc<Self>, mode: Mode) {
|
||||||
|
self.update_mode_and_transform(mode, self.global.transform.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_transform(self: &Rc<Self>, transform: Transform) {
|
||||||
|
self.update_mode_and_transform(self.global.mode.get(), transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_mode_and_transform(self: &Rc<Self>, mode: Mode, transform: Transform) {
|
||||||
let old_mode = self.global.mode.get();
|
let old_mode = self.global.mode.get();
|
||||||
if old_mode == mode {
|
let old_transform = self.global.transform.get();
|
||||||
|
if (old_mode, old_transform) == (mode, transform) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let (old_width, old_height) = self.global.pixel_size();
|
||||||
self.global.mode.set(mode);
|
self.global.mode.set(mode);
|
||||||
let rect = self.calculate_extents();
|
self.state
|
||||||
self.change_extents_(&rect);
|
.output_transforms
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(self.global.output_id.clone(), transform);
|
||||||
|
self.global.transform.set(transform);
|
||||||
|
let (new_width, new_height) = self.global.pixel_size();
|
||||||
|
self.change_extents_(&self.calculate_extents());
|
||||||
|
|
||||||
if (old_mode.width, old_mode.height) != (mode.width, mode.height) {
|
if (old_width, old_height) != (new_width, new_height) {
|
||||||
let mut to_destroy = vec![];
|
let mut to_destroy = vec![];
|
||||||
if let Some(ctx) = self.state.render_ctx.get() {
|
if let Some(ctx) = self.state.render_ctx.get() {
|
||||||
for sc in self.screencasts.lock().values() {
|
for sc in self.screencasts.lock().values() {
|
||||||
|
|
@ -411,12 +428,15 @@ impl OutputNode {
|
||||||
sc.do_destroy();
|
sc.do_destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if transform != old_transform {
|
||||||
|
self.state.refresh_hardware_cursors();
|
||||||
|
self.node_visit_children(&mut SurfaceSendPreferredTransformVisitor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_extents(&self) -> Rect {
|
fn calculate_extents(&self) -> Rect {
|
||||||
let mode = self.global.mode.get();
|
let (mut width, mut height) = self.global.pixel_size();
|
||||||
let mut width = mode.width;
|
|
||||||
let mut height = mode.height;
|
|
||||||
let scale = self.global.preferred_scale.get();
|
let scale = self.global.preferred_scale.get();
|
||||||
if scale != 1 {
|
if scale != 1 {
|
||||||
let scale = scale.to_f64();
|
let scale = scale.to_f64();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue