1
0
Fork 0
forked from wry/wry

wp-presentation: implement version 2

This commit is contained in:
Julian Orth 2024-09-25 16:25:20 +02:00
parent de47705a32
commit 03dce4af06
8 changed files with 51 additions and 16 deletions

View file

@ -161,7 +161,7 @@ Jay supports the following wayland protocols:
| wp_drm_lease_device_v1 | 1 | | | wp_drm_lease_device_v1 | 1 | |
| wp_fractional_scale_manager_v1 | 1 | | | wp_fractional_scale_manager_v1 | 1 | |
| wp_linux_drm_syncobj_manager_v1 | 1 | | | wp_linux_drm_syncobj_manager_v1 | 1 | |
| wp_presentation | 1 | | | wp_presentation | 2 | |
| wp_security_context_manager_v1 | 1 | | | wp_security_context_manager_v1 | 1 | |
| wp_single_pixel_buffer_manager_v1 | 1 | | | wp_single_pixel_buffer_manager_v1 | 1 | |
| wp_tearing_control_manager_v1 | 1 | | | wp_tearing_control_manager_v1 | 1 | |

View file

@ -15,7 +15,7 @@ use {
MetalBackend, MetalError, MetalBackend, MetalError,
}, },
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
edid::Descriptor, edid::{CtaDataBlock, Descriptor, EdidExtension},
format::{Format, ARGB8888, XRGB8888}, format::{Format, ARGB8888, XRGB8888},
gfx_api::{ gfx_api::{
needs_render_usage, AcquireSync, GfxContext, GfxFramebuffer, GfxTexture, ReleaseSync, needs_render_usage, AcquireSync, GfxContext, GfxFramebuffer, GfxTexture, ReleaseSync,
@ -331,6 +331,7 @@ pub struct ConnectorDisplayData {
pub non_desktop: bool, pub non_desktop: bool,
pub non_desktop_effective: bool, pub non_desktop_effective: bool,
pub vrr_capable: bool, pub vrr_capable: bool,
pub _vrr_refresh_max_nsec: u64,
pub connector_id: ConnectorKernelId, pub connector_id: ConnectorKernelId,
pub output_id: Rc<OutputId>, pub output_id: Rc<OutputId>,
@ -1129,6 +1130,7 @@ fn create_connector_display_data(
let mut name = String::new(); let mut name = String::new();
let mut manufacturer = String::new(); let mut manufacturer = String::new();
let mut serial_number = String::new(); let mut serial_number = String::new();
let mut vrr_refresh_max_nsec = u64::MAX;
let connector_id = ConnectorKernelId { let connector_id = ConnectorKernelId {
ty: ConnectorType::from_drm(info.connector_type), ty: ConnectorType::from_drm(info.connector_type),
idx: info.connector_type_id, idx: info.connector_type_id,
@ -1194,6 +1196,28 @@ fn create_connector_display_data(
); );
serial_number = edid.base_block.id_serial_number.to_string(); serial_number = edid.base_block.id_serial_number.to_string();
} }
let min_vrr_hz = 'fetch_min_hz: {
for ext in &edid.extension_blocks {
if let EdidExtension::CtaV3(cta) = ext {
for data_block in &cta.data_blocks {
if let CtaDataBlock::VendorAmd(amd) = data_block {
break 'fetch_min_hz amd.minimum_refresh_hz as u64;
}
}
}
}
for desc in &edid.base_block.descriptors {
if let Some(desc) = desc {
if let Descriptor::DisplayRangeLimitsAndAdditionalTiming(timings) = desc {
break 'fetch_min_hz timings.vertical_field_rate_min as u64;
}
}
}
0
};
if min_vrr_hz > 0 {
vrr_refresh_max_nsec = 1_000_000_000 / min_vrr_hz;
}
} }
let output_id = Rc::new(OutputId::new( let output_id = Rc::new(OutputId::new(
connector_id.to_string(), connector_id.to_string(),
@ -1249,6 +1273,7 @@ fn create_connector_display_data(
non_desktop, non_desktop,
non_desktop_effective: non_desktop_override.unwrap_or(non_desktop), non_desktop_effective: non_desktop_override.unwrap_or(non_desktop),
vrr_capable, vrr_capable,
_vrr_refresh_max_nsec: vrr_refresh_max_nsec,
connection, connection,
mm_width: info.mm_width, mm_width: info.mm_width,
mm_height: info.mm_height, mm_height: info.mm_height,
@ -2002,17 +2027,14 @@ impl MetalBackend {
if connector.presentation_is_zero_copy.get() { if connector.presentation_is_zero_copy.get() {
flags |= KIND_ZERO_COPY; flags |= KIND_ZERO_COPY;
} }
let refresh = match crtc.vrr_enabled.value.get() {
true => 0,
false => dd.refresh,
};
if let Some(g) = &global { if let Some(g) = &global {
g.presented( g.presented(
tv_sec as _, tv_sec as _,
tv_usec * 1000, tv_usec * 1000,
refresh, dd.refresh,
connector.sequence.get(), connector.sequence.get(),
flags, flags,
crtc.vrr_enabled.value.get(),
); );
} }
} }

View file

@ -1161,32 +1161,28 @@ pub struct EdidBaseBlock {
#[derive(Debug)] #[derive(Debug)]
pub enum EdidExtension { pub enum EdidExtension {
Unknown, Unknown,
#[expect(dead_code)]
CtaV3(CtaExtensionV3), CtaV3(CtaExtensionV3),
} }
#[derive(Debug)] #[derive(Debug)]
pub struct CtaExtensionV3 { pub struct CtaExtensionV3 {
#[expect(dead_code)]
pub data_blocks: Vec<CtaDataBlock>, pub data_blocks: Vec<CtaDataBlock>,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum CtaDataBlock { pub enum CtaDataBlock {
Unknown, Unknown,
#[expect(dead_code)]
VendorAmd(CtaAmdVendorDataBlock), VendorAmd(CtaAmdVendorDataBlock),
} }
#[derive(Debug)] #[derive(Debug)]
#[expect(dead_code)]
pub struct CtaAmdVendorDataBlock { pub struct CtaAmdVendorDataBlock {
pub minimum_refresh_hz: u8, pub minimum_refresh_hz: u8,
#[expect(dead_code)]
pub maximum_refresh_hz: u8, pub maximum_refresh_hz: u8,
} }
#[derive(Debug)] #[derive(Debug)]
#[expect(dead_code)]
pub struct EdidFile { pub struct EdidFile {
pub base_block: EdidBaseBlock, pub base_block: EdidBaseBlock,
pub extension_blocks: Vec<EdidExtension>, pub extension_blocks: Vec<EdidExtension>,

View file

@ -301,6 +301,7 @@ impl PresentationListener for ExtImageCopyCaptureSessionV1 {
_refresh: u32, _refresh: u32,
_seq: u64, _seq: u64,
_flags: u32, _flags: u32,
_vrr: bool,
) { ) {
self.presentation_listener.detach(); self.presentation_listener.detach();
let Some(frame) = self.frame.get() else { let Some(frame) = self.frame.get() else {

View file

@ -55,7 +55,7 @@ use {
zwlr_layer_surface_v1::{PendingLayerSurfaceData, ZwlrLayerSurfaceV1Error}, zwlr_layer_surface_v1::{PendingLayerSurfaceData, ZwlrLayerSurfaceV1Error},
}, },
wp_content_type_v1::ContentType, wp_content_type_v1::ContentType,
wp_presentation_feedback::WpPresentationFeedback, wp_presentation_feedback::{WpPresentationFeedback, VRR_REFRESH_SINCE},
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1, zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
}, },
leaks::Tracker, leaks::Tracker,
@ -2135,6 +2135,7 @@ impl PresentationListener for WlSurface {
refresh: u32, refresh: u32,
seq: u64, seq: u64,
flags: u32, flags: u32,
vrr: bool,
) { ) {
let bindings = output.global.bindings.borrow(); let bindings = output.global.bindings.borrow();
let bindings = bindings.get(&self.client.id); let bindings = bindings.get(&self.client.id);
@ -2144,6 +2145,10 @@ impl PresentationListener for WlSurface {
pf.send_sync_output(binding); pf.send_sync_output(binding);
} }
} }
let mut refresh = refresh;
if vrr && pf.version < VRR_REFRESH_SINCE {
refresh = 0;
}
pf.send_presented(tv_sec, tv_nsec, refresh, seq, flags); pf.send_presented(tv_sec, tv_nsec, refresh, seq, flags);
let _ = pf.client.remove_obj(&*pf); let _ = pf.client.remove_obj(&*pf);
} }

View file

@ -48,7 +48,7 @@ impl Global for WpPresentationGlobal {
} }
fn version(&self) -> u32 { fn version(&self) -> u32 {
1 2
} }
} }

View file

@ -24,6 +24,8 @@ pub const KIND_HW_CLOCK: u32 = 0x2;
pub const KIND_HW_COMPLETION: u32 = 0x4; pub const KIND_HW_COMPLETION: u32 = 0x4;
pub const KIND_ZERO_COPY: u32 = 0x8; pub const KIND_ZERO_COPY: u32 = 0x8;
pub const VRR_REFRESH_SINCE: Version = Version(2);
impl WpPresentationFeedback { impl WpPresentationFeedback {
pub fn send_sync_output(&self, output: &WlOutput) { pub fn send_sync_output(&self, output: &WlOutput) {
self.client.event(SyncOutput { self.client.event(SyncOutput {

View file

@ -111,6 +111,7 @@ pub trait PresentationListener {
refresh: u32, refresh: u32,
seq: u64, seq: u64,
flags: u32, flags: u32,
vrr: bool,
); );
} }
@ -158,9 +159,17 @@ impl OutputNode {
} }
} }
pub fn presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) { pub fn presented(
&self,
tv_sec: u64,
tv_nsec: u32,
refresh: u32,
seq: u64,
flags: u32,
vrr: bool,
) {
for listener in self.presentation_event.iter() { for listener in self.presentation_event.iter() {
listener.presented(self, tv_sec, tv_nsec, refresh, seq, flags); listener.presented(self, tv_sec, tv_nsec, refresh, seq, flags, vrr);
} }
} }