1
0
Fork 0
forked from wry/wry

metal: emulate vblank events on the nvidia driver

This commit is contained in:
Julian Orth 2024-10-03 08:54:15 +02:00
parent d2b6831ce4
commit ed65fa07a4
7 changed files with 41 additions and 4 deletions

View file

@ -740,8 +740,19 @@ impl MetalConnector {
fn queue_sequence(&self) {
if let Some(crtc) = self.crtc.get() {
if crtc.needs_vblank_emulation.get() {
return;
}
if let Err(e) = self.master.queue_sequence(crtc.id) {
log::error!("Could not queue a CRTC sequence: {}", ErrorFmt(e));
log::error!("Could not queue a CRTC sequence: {}", ErrorFmt(&e));
if let DrmError::QueueSequence(OsError(c::EOPNOTSUPP)) = e {
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
log::warn!("{}: Switching to vblank emulation", self.kernel_id());
crtc.needs_vblank_emulation.set(true);
node.global.connector.needs_vblank_emulation.set(true);
node.vblank();
}
}
} else {
crtc.have_queued_sequence.set(true);
}
@ -944,6 +955,7 @@ pub struct MetalCrtc {
pub mode_blob: CloneCell<Option<Rc<PropBlob>>>,
pub have_queued_sequence: Cell<bool>,
pub needs_vblank_emulation: Cell<bool>,
}
impl Debug for MetalCrtc {
@ -1291,6 +1303,7 @@ fn create_crtc(
vrr_enabled: props.get("VRR_ENABLED")?.map(|v| v == 1),
mode_blob: Default::default(),
have_queued_sequence: Cell::new(false),
needs_vblank_emulation: Cell::new(false),
})
}
@ -1955,6 +1968,10 @@ impl MetalBackend {
connector.queue_sequence();
}
self.update_u32_sequence(&connector, sequence);
let time_ns = tv_sec as u64 * 1_000_000_000 + tv_usec as u64 * 1000;
if crtc.needs_vblank_emulation.get() {
self.handle_drm_sequence_event(dev, crtc_id, time_ns as _, connector.sequence.get());
}
connector.can_present.set(true);
if let Some(fb) = connector.next_framebuffer.take() {
*connector.active_framebuffer.borrow_mut() = Some(fb);
@ -1976,9 +1993,7 @@ impl MetalBackend {
{
connector.schedule_present();
}
connector
.next_flip_nsec
.set(tv_sec as u64 * 1_000_000_000 + tv_usec as u64 * 1000 + dd.refresh as u64);
connector.next_flip_nsec.set(time_ns + dd.refresh as u64);
{
let mut flags = KIND_HW_COMPLETION;
if connector.presentation_is_sync.get() {

View file

@ -521,6 +521,7 @@ fn create_dummy_output(state: &Rc<State>) {
drm_dev: None,
async_event: Default::default(),
damaged: Cell::new(false),
needs_vblank_emulation: Cell::new(false),
});
let schedule = Rc::new(OutputSchedule::new(
&state.ring,

View file

@ -305,6 +305,7 @@ pub struct ConnectorData {
pub drm_dev: Option<Rc<DrmDevData>>,
pub async_event: Rc<AsyncEvent>,
pub damaged: Cell<bool>,
pub needs_vblank_emulation: Cell<bool>,
}
pub struct OutputData {

View file

@ -32,6 +32,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
drm_dev: drm_dev.clone(),
async_event: Rc::new(AsyncEvent::default()),
damaged: Cell::new(false),
needs_vblank_emulation: Cell::new(false),
});
if let Some(dev) = drm_dev {
dev.connectors.set(id, data.clone());

View file

@ -141,6 +141,16 @@ impl OutputNode {
for listener in self.vblank_event.iter() {
listener.after_vblank();
}
if self.global.connector.needs_vblank_emulation.get() {
if self.vblank_event.has_listeners() {
self.global.connector.damage();
} else {
let connector = self.global.connector.clone();
self.vblank_event.on_attach(Box::new(move || {
connector.damage();
}));
}
}
}
pub fn presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) {

View file

@ -30,6 +30,14 @@ impl<T: ?Sized> EventSource<T> {
iter: self.listeners.iter(),
}
}
pub fn has_listeners(&self) -> bool {
self.listeners.is_not_empty()
}
pub fn on_attach(&self, f: Box<dyn FnOnce()>) {
self.on_attach.set(Some(f));
}
}
pub struct EventSourceIter<T: ?Sized> {