Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DrmOutputManager #1576

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft

Conversation

cmeissl
Copy link
Collaborator

@cmeissl cmeissl commented Nov 3, 2024

highly wip of the ideas described here: pop-os/cosmic-comp#969 (comment)

it implements most of the stuff, except:

  • the capabilities stuff
  • the actual format selection
  • some things are stubs and need to be implemented properly

not extensively tested, but anvil seems to still be able to launch.
returning an error from DrmCompositor::new also successfully triggers the format selection
logic

TODO

A lot...

  • Verify that this does not mess up the render logic with multiple commits triggering vblanks
    If this turns out to be problematic we can disable the event for commit_frame, but we need to make sure
    to kick off rendering in this case somehow..

DrmDevice, DrmError, Planes,
};

type CompositorList<A, F, U, G> = Arc<RwLock<HashMap<crtc::Handle, RefCell<DrmCompositor<A, F, U, G>>>>>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i understand correctly, RefCell is !Sync, which would make CompositorList both !Sync and !Send, making Arc<RwLock<>> pointless.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, sigh. !Sync is intended/expected, it should be Send , I guess this is blocked on the PixmanRenderer not being Send :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I'm a little confused. Arc<T> is Sync or Send requires T to be both Sync and Send, but RefCell<T> is unconditional !Sync. I think RefCell<T> should be removed here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RwLock or Mutex add the Sync bound, so our T is just required to be Send, which is indeed blocked on pixman-rs

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at it again we indeed need to use Mutex instead of the Refcell because RwLock requires Sync for read access.

This is the easy part, unfortunately DrmCompositor is not Send atm. Currently looking into this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, DrmCompositor is now Send as long as the allocator buffer and the framebuffer are Send + Sync. This allows DrmOutputManager to be Send and DrmOutput to implement Send and Sync.

Notes

  • This currently needs unsafe impl Sync for GbmBuffer which should be removed when this lands
  • The unsafe Sync impl on PixmanRenderer should be fine atm, but we need to address this in pixman-rs

/// Allow to realize the frame by assigning elements on planes
const SCANOUT = Self::PRIMARY_PLANE_SCANOUT.bits() | Self::OVERLAY_PLANE_SCANOUT.bits() | Self::CURSOR_PLANE_SCANOUT.bits();

const ALL = Self::COMPOSITE.bits() | Self::SCANOUT.bits();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to make this even more complicated, but in the future I would really like to have the option to direct scanout a fullscreen surface in cosmic-comp and then composite the rest onto an overlay plane.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh I don't think this will fit in the current DrmCompositor API. This will require allowing custom assign algorithms. What I have in mind is that we make something similar to the FrameState public and actually externalize the whole assigning algorithm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. (And is also not a very important problem atm.)


let current_format = compositor.format();
if let Err(err) =
compositor.set_format(self.allocator.clone(), current_format, [DrmModifier::Invalid])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we want to first disable overlay planes and then fallback to no-modifer instead of doing both at the same time?

The former happens a lot more frequently on recent gpus.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, this is more to provide a PoC

src/backend/drm/output.rs Outdated Show resolved Hide resolved
@Paraworker
Copy link
Contributor

Paraworker commented Nov 11, 2024

Hey guys I have an idea about getting rid of the Mutex in CompositorList.

We access DrmCompositor through two ways, under RwLock::write() or RwLock::read(), let me discuss separately:

RwLock::write()

In this case, we can be sure that access is unique, Mutex is redundant here.

RwLock::read()

This is the case we really need to care about. From the code I can see RwLock::read() only happens in DrmOutput::with_compositor(). If we can mark the DrmOutput with !Sync or mark DrmOutput::with_compositor() with mut, then no race condition exists since DrmOutput only access it's own DrmCompositor under RwLock::read().

While the Mutex is not need, we do still need interior mutability. A kind of cell can be introduced, which depends on the caller to do proper unique access.

struct MutexCell<T> {
    inner: UnsafeCell<T>,
}

impl<T> MutexCell<T> {
    const fn new(value: T) -> Self {
        Self { inner: UnsafeCell::new(value) }
    }

    /// SAFETY: make sure unique access
    unsafe fn get(&self) -> &mut T {
        &mut *self.inner.get()
    }
}

unsafe impl<T: Send> Sync for MutexCell<T> {}
unsafe impl<T: Send> Send for MutexCell<T> {}

Then the CompositorList would be like:

type CompositorList<A, F, U, G> = Arc<RwLock<HashMap<crtc::Handle, MutexCell<DrmCompositor<A, F, U, G>>>>>;

And the DrmOutput::with_compositor() could be like:

pub fn with_compositor<T, R>(&mut self, f: T) -> R
where
    T: FnOnce(&mut DrmCompositor<A, F, U, G>) -> R,
{
    let reader = self.compositor.read().unwrap();

    // SAFETY: unique access to our `DrmCompositor`
    f(unsafe { reader.get(&self.crtc).unwrap().get() })
}

All these are just theoretical and may be too tricky😮‍💨. I don't know how you guys think about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants