Skip to content

Commit

Permalink
Merge pull request #109 from mahkoh/jorth/output-transform
Browse files Browse the repository at this point in the history
Implement output transforms
  • Loading branch information
mahkoh authored Feb 29, 2024
2 parents 69d63b7 + b7d2964 commit 7a67784
Show file tree
Hide file tree
Showing 37 changed files with 872 additions and 647 deletions.
9 changes: 8 additions & 1 deletion jay-config/src/_private/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use {
timer::Timer,
video::{
connector_type::{ConnectorType, CON_UNKNOWN},
Connector, DrmDevice, GfxApi, Mode,
Connector, DrmDevice, GfxApi, Mode, Transform,
},
Axis, Direction, ModifiedKeySym, PciId, Workspace,
},
Expand Down Expand Up @@ -473,6 +473,13 @@ impl Client {
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> {
let res = self.send_with_response(&ClientMessage::GetDeviceConnectors { device });
get_response!(res, vec![], GetDeviceConnectors { connectors });
Expand Down
6 changes: 5 additions & 1 deletion jay-config/src/_private/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use {
logging::LogLevel,
theme::{colors::Colorable, sized::Resizable, Color},
timer::Timer,
video::{connector_type::ConnectorType, Connector, DrmDevice, GfxApi},
video::{connector_type::ConnectorType, Connector, DrmDevice, GfxApi, Transform},
Axis, Direction, PciId, Workspace,
},
serde::{Deserialize, Serialize},
Expand Down Expand Up @@ -342,6 +342,10 @@ pub enum ClientMessage<'a> {
device: Option<DrmDevice>,
enabled: bool,
},
ConnectorSetTransform {
connector: Connector,
transform: Transform,
},
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down
31 changes: 31 additions & 0 deletions jay-config/src/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ impl Connector {
}
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.
Expand Down Expand Up @@ -403,3 +412,25 @@ pub fn set_gfx_api(gfx_api: GfxApi) {
pub fn set_direct_scanout_enabled(enabled: bool) {
get!().set_direct_scanout_enabled(None, enabled);
}

/// A transformation.
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub enum Transform {
/// No transformation.
#[default]
None,
/// Rotate 90 degrees counter-clockwise.
Rotate90,
/// Rotate 180 degrees counter-clockwise.
Rotate180,
/// Rotate 270 degrees counter-clockwise.
Rotate270,
/// Flip around the vertical axis.
Flip,
/// Flip around the vertical axis, then rotate 90 degrees counter-clockwise.
FlipRotate90,
/// Flip around the vertical axis, then rotate 180 degrees counter-clockwise.
FlipRotate180,
/// Flip around the vertical axis, then rotate 270 degrees counter-clockwise.
FlipRotate270,
}
2 changes: 1 addition & 1 deletion src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub trait HardwareCursor: Debug {
fn set_position(&self, x: i32, y: i32);
fn swap_buffer(&self);
fn commit(&self);
fn max_size(&self) -> (i32, i32);
fn size(&self) -> (i32, i32);
}

pub type TransformMatrix = [[f64; 2]; 2];
Expand Down
68 changes: 32 additions & 36 deletions src/backends/metal/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ use {
drm_feedback::DrmFeedback,
edid::Descriptor,
format::{Format, ARGB8888, XRGB8888},
gfx_api::{
AbsoluteRect, BufferPoints, GfxApiOpt, GfxContext, GfxFramebuffer, GfxRenderPass,
GfxTexture,
},
gfx_api::{GfxApiOpt, GfxContext, GfxFramebuffer, GfxRenderPass, GfxTexture},
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
renderer::RenderResult,
state::State,
Expand All @@ -23,6 +20,7 @@ use {
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell,
opaque_cell::OpaqueCell, oserror::OsError, syncqueue::SyncQueue,
transform_ext::TransformExt,
},
video::{
dmabuf::DmaBufId,
Expand Down Expand Up @@ -287,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_height as _,
Expand Down Expand Up @@ -428,8 +426,6 @@ impl MetalConnector {
pass: &GfxRenderPass,
plane: &Rc<MetalPlane>,
) -> Option<DirectScanoutData> {
let plane_w = plane.mode_w.get();
let plane_h = plane.mode_h.get();
let ct = 'ct: {
let mut ops = pass.ops.iter().rev();
let ct = 'ct2: {
Expand All @@ -445,13 +441,7 @@ impl MetalConnector {
}
return None;
};
let plane_rect = AbsoluteRect {
x1: 0.0,
x2: plane_w as f32,
y1: 0.0,
y2: plane_h as f32,
};
if !ct.tex.format().has_alpha && ct.target == plane_rect {
if !ct.tex.format().has_alpha && ct.target.is_covering() {
// Texture covers the entire screen and is opaque.
break 'ct ct;
}
Expand All @@ -461,7 +451,7 @@ impl MetalConnector {
GfxApiOpt::FillRect(fr) => {
if fr.color == Color::SOLID_BLACK {
// Black fills can be ignored because this is the CRTC background color.
if fr.rect == plane_rect {
if fr.rect.is_covering() {
// If fill covers the entire screen, we don't have to look further.
break 'ct ct;
}
Expand All @@ -484,20 +474,34 @@ impl MetalConnector {
}
ct
};
if ct.source != BufferPoints::identity() {
// Non-trivial transforms are not supported.
if ct.source.buffer_transform != ct.target.output_transform {
// Rotations and mirroring are not supported.
return None;
}
if ct.target.x1 < 0.0
|| ct.target.y1 < 0.0
|| ct.target.x2 > plane_w as f32
|| ct.target.y2 > plane_h as f32
{
if !ct.source.is_covering() {
// Viewports are not supported.
return None;
}
if ct.target.x1 < -1.0 || ct.target.y1 < -1.0 || ct.target.x2 > 1.0 || ct.target.y2 > 1.0 {
// Rendering outside the screen is not supported.
return None;
}
let (tex_w, tex_h) = ct.tex.size();
let (crtc_w, crtc_h) = (ct.target.x2 - ct.target.x1, ct.target.y2 - ct.target.y1);
let (x1, x2, y1, y2) = {
let plane_w = plane.mode_w.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)));
(
(x1 + 1.0) * plane_w / 2.0,
(x2 + 1.0) * plane_w / 2.0,
(y1 + 1.0) * plane_h / 2.0,
(y2 + 1.0) * plane_h / 2.0,
)
};
let (crtc_w, crtc_h) = (x2 - x1, y2 - y1);
if crtc_w < 0.0 || crtc_h < 0.0 {
// Flipping x or y axis is not supported.
return None;
Expand All @@ -513,8 +517,8 @@ impl MetalConnector {
let position = DirectScanoutPosition {
src_width: tex_w,
src_height: tex_h,
crtc_x: ct.target.x1 as _,
crtc_y: ct.target.y1 as _,
crtc_x: x1 as _,
crtc_y: y1 as _,
crtc_width: crtc_w as _,
crtc_height: crtc_h as _,
};
Expand Down Expand Up @@ -595,9 +599,9 @@ impl MetalConnector {
output.global.preferred_scale.get(),
render_hw_cursor,
output.has_fullscreen(),
output.global.transform.get(),
);
let try_direct_scanout = try_direct_scanout
&& !output.global.have_shm_screencopies()
&& self.direct_scanout_enabled()
// at least on AMD, using a FB on a different device for rendering will fail
// and destroy the render context. it's possible to work around this by waiting
Expand All @@ -609,7 +613,6 @@ impl MetalConnector {
if try_direct_scanout {
if let Some(dsd) = self.prepare_direct_scanout(&pass, plane) {
output.perform_screencopies(
None,
&dsd.tex,
!render_hw_cursor,
dsd.position.crtc_x,
Expand All @@ -634,14 +637,7 @@ impl MetalConnector {
if let Some(tex) = &buffer.dev_tex {
buffer.dev_fb.copy_texture(tex, 0, 0);
}
output.perform_screencopies(
Some(&*buffer_fb),
&buffer.render_tex,
!render_hw_cursor,
0,
0,
None,
);
output.perform_screencopies(&buffer.render_tex, !render_hw_cursor, 0, 0, None);
buffer.drm.clone()
}
Some(dsd) => dsd.fb.clone(),
Expand Down Expand Up @@ -729,7 +725,7 @@ impl MetalConnector {
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| {
c.change(plane.fb_id, buffer.drm.id().0 as _);
c.change(plane.crtc_id.id, crtc.id.0 as _);
Expand Down
1 change: 1 addition & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ fn start_compositor2(
dma_buf_ids: Default::default(),
drm_feedback_ids: Default::default(),
direct_scanout_enabled: Cell::new(true),
output_transforms: Default::default(),
});
state.tracker.register(ClientId::from_raw(0));
create_dummy_output(&state);
Expand Down
19 changes: 18 additions & 1 deletion src/config/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use {
logging::LogLevel,
theme::{colors::Colorable, sized::Resizable},
timer::Timer as JayTimer,
video::{Connector, DrmDevice, GfxApi},
video::{Connector, DrmDevice, GfxApi, Transform},
Axis, Direction, Workspace,
},
libloading::Library,
Expand Down Expand Up @@ -751,6 +751,17 @@ impl ConfigProxyHandler {
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(
&self,
connector: Connector,
Expand Down Expand Up @@ -1338,6 +1349,12 @@ impl ConfigProxyHandler {
ClientMessage::SetDirectScanoutEnabled { device, enabled } => self
.handle_set_direct_scanout_enabled(device, enabled)
.wrn("set_direct_scanout_enabled")?,
ClientMessage::ConnectorSetTransform {
connector,
transform,
} => self
.handle_connector_set_transform(connector, transform)
.wrn("connector_set_transform")?,
}
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed
} else {
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(
&img.tex,
extents.x1(),
Expand Down
7 changes: 6 additions & 1 deletion src/format.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{
gfx_apis::gl::sys::{GLint, GL_BGRA_EXT, GL_RGBA, GL_UNSIGNED_BYTE},
gfx_apis::gl::sys::{GLenum, GLint, GL_BGRA_EXT, GL_RGBA, GL_RGBA8, GL_UNSIGNED_BYTE},
pipewire::pw_pod::{
SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx, SpaVideoFormat, SPA_VIDEO_FORMAT_BGRA,
SPA_VIDEO_FORMAT_RGBA,
Expand All @@ -18,6 +18,7 @@ pub struct Format {
pub name: &'static str,
pub bpp: u32,
pub gl_format: GLint,
pub gl_internal_format: GLenum,
pub gl_type: GLint,
pub vk_format: vk::Format,
pub drm: u32,
Expand Down Expand Up @@ -92,6 +93,7 @@ pub static ARGB8888: &Format = &Format {
name: "argb8888",
bpp: 4,
gl_format: GL_BGRA_EXT,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
vk_format: vk::Format::B8G8R8A8_UNORM,
drm: ARGB8888_DRM,
Expand All @@ -107,6 +109,7 @@ pub static XRGB8888: &Format = &Format {
name: "xrgb8888",
bpp: 4,
gl_format: GL_BGRA_EXT,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
vk_format: vk::Format::B8G8R8A8_UNORM,
drm: XRGB8888_DRM,
Expand All @@ -122,6 +125,7 @@ static ABGR8888: &Format = &Format {
name: "abgr8888",
bpp: 4,
gl_format: GL_RGBA,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
vk_format: vk::Format::R8G8B8A8_UNORM,
drm: fourcc_code('A', 'B', '2', '4'),
Expand All @@ -137,6 +141,7 @@ static XBGR8888: &Format = &Format {
name: "xbgr8888",
bpp: 4,
gl_format: GL_RGBA,
gl_internal_format: GL_RGBA8,
gl_type: GL_UNSIGNED_BYTE,
vk_format: vk::Format::R8G8B8A8_UNORM,
drm: fourcc_code('X', 'B', '2', '4'),
Expand Down
Loading

0 comments on commit 7a67784

Please sign in to comment.