- Add optional modifier-only Super binding whose tap is cancelled by other input, focus changes, grabs, locks, and session teardown. - Ship the native ferese-rime user service, Rime defaults, installer inventory, package dependencies, session environment, and docs. - Vendor Smithay 8a27023 with the SHM texture-cache format fix and add GPU regressions for format changes and resize snapshots. - Release reused CRTC owners before staging output modes, then restore changed outputs before former owners when a transaction fails. - Wait for resize-capture GPU completion, expand filtered surface damage, and preserve IME popup origin under fractional scaling. - Mark weekends like holidays in both calendar layouts.
204 lines
4.7 KiB
Rust
204 lines
4.7 KiB
Rust
//! Utilities to attach [`framebuffer::Handle`]s to dumb buffers
|
|
|
|
use drm_fourcc::{DrmFormat, DrmModifier};
|
|
|
|
use drm::{
|
|
buffer::{Buffer as DrmBuffer, PlanarBuffer},
|
|
control::{Device, FbCmd2Flags, framebuffer},
|
|
};
|
|
use tracing::{trace, warn};
|
|
|
|
use crate::utils::DevPath;
|
|
use crate::{
|
|
backend::{
|
|
allocator::{
|
|
Buffer, Fourcc,
|
|
dumb::DumbBuffer,
|
|
format::{get_bpp, get_depth, get_opaque},
|
|
},
|
|
drm::DrmDeviceFd,
|
|
},
|
|
utils::{Buffer as BufferCoords, Size},
|
|
};
|
|
|
|
use super::{Framebuffer, error::AccessError, warn_legacy_fb_export};
|
|
|
|
/// A GBM backed framebuffer
|
|
#[derive(Debug)]
|
|
pub struct DumbFramebuffer {
|
|
fb: framebuffer::Handle,
|
|
format: drm_fourcc::DrmFormat,
|
|
drm: DrmDeviceFd,
|
|
}
|
|
|
|
impl Drop for DumbFramebuffer {
|
|
fn drop(&mut self) {
|
|
trace!(fb = ?self.fb, "destroying framebuffer");
|
|
if let Err(err) = self.drm.destroy_framebuffer(self.fb) {
|
|
warn!(fb = ?self.fb, ?err, "failed to destroy framebuffer");
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AsRef<framebuffer::Handle> for DumbFramebuffer {
|
|
#[inline]
|
|
fn as_ref(&self) -> &framebuffer::Handle {
|
|
&self.fb
|
|
}
|
|
}
|
|
|
|
impl Framebuffer for DumbFramebuffer {
|
|
#[inline]
|
|
fn format(&self) -> drm_fourcc::DrmFormat {
|
|
self.format
|
|
}
|
|
}
|
|
|
|
struct PlanarDumbBuffer<'a>(&'a DumbBuffer);
|
|
|
|
impl Buffer for PlanarDumbBuffer<'_> {
|
|
#[inline]
|
|
fn size(&self) -> Size<i32, BufferCoords> {
|
|
self.0.size()
|
|
}
|
|
|
|
#[inline]
|
|
fn format(&self) -> DrmFormat {
|
|
self.0.format()
|
|
}
|
|
}
|
|
|
|
impl PlanarBuffer for PlanarDumbBuffer<'_> {
|
|
#[inline]
|
|
fn size(&self) -> (u32, u32) {
|
|
let size = self.0.size();
|
|
(size.w as u32, size.h as u32)
|
|
}
|
|
|
|
#[inline]
|
|
fn format(&self) -> Fourcc {
|
|
self.0.format().code
|
|
}
|
|
|
|
#[inline]
|
|
fn modifier(&self) -> Option<DrmModifier> {
|
|
Some(self.0.format().modifier)
|
|
}
|
|
|
|
#[inline]
|
|
fn pitches(&self) -> [u32; 4] {
|
|
[self.0.handle().pitch(), 0, 0, 0]
|
|
}
|
|
|
|
#[inline]
|
|
fn handles(&self) -> [Option<drm::buffer::Handle>; 4] {
|
|
[Some(self.0.handle().handle()), None, None, None]
|
|
}
|
|
|
|
#[inline]
|
|
fn offsets(&self) -> [u32; 4] {
|
|
[0, 0, 0, 0]
|
|
}
|
|
}
|
|
|
|
struct OpaqueBufferWrapper<'a, B>(&'a B);
|
|
impl<B> PlanarBuffer for OpaqueBufferWrapper<'_, B>
|
|
where
|
|
B: PlanarBuffer,
|
|
{
|
|
#[inline]
|
|
fn size(&self) -> (u32, u32) {
|
|
self.0.size()
|
|
}
|
|
|
|
#[inline]
|
|
fn format(&self) -> Fourcc {
|
|
let fmt = self.0.format();
|
|
get_opaque(fmt).unwrap_or(fmt)
|
|
}
|
|
|
|
#[inline]
|
|
fn modifier(&self) -> Option<DrmModifier> {
|
|
self.0.modifier()
|
|
}
|
|
|
|
#[inline]
|
|
fn pitches(&self) -> [u32; 4] {
|
|
self.0.pitches()
|
|
}
|
|
|
|
#[inline]
|
|
fn handles(&self) -> [Option<drm::buffer::Handle>; 4] {
|
|
self.0.handles()
|
|
}
|
|
|
|
#[inline]
|
|
fn offsets(&self) -> [u32; 4] {
|
|
self.0.offsets()
|
|
}
|
|
}
|
|
|
|
/// Attach a [`framebuffer::Handle`] to an [`DumbBuffer`]
|
|
#[profiling::function]
|
|
pub fn framebuffer_from_dumb_buffer(
|
|
drm: &DrmDeviceFd,
|
|
buffer: &DumbBuffer,
|
|
use_opaque: bool,
|
|
) -> Result<DumbFramebuffer, AccessError> {
|
|
let buffer = PlanarDumbBuffer(buffer);
|
|
|
|
let format = Buffer::format(&buffer);
|
|
let modifier = buffer.modifier();
|
|
let flags = if modifier.is_some() {
|
|
FbCmd2Flags::MODIFIERS
|
|
} else {
|
|
FbCmd2Flags::empty()
|
|
};
|
|
|
|
let ret = if use_opaque {
|
|
let opaque_wrapper = OpaqueBufferWrapper(&buffer);
|
|
drm.add_planar_framebuffer(&opaque_wrapper, flags).map(|fb| {
|
|
(
|
|
fb,
|
|
drm_fourcc::DrmFormat {
|
|
code: opaque_wrapper.format(),
|
|
modifier: modifier.unwrap_or(DrmModifier::Invalid),
|
|
},
|
|
)
|
|
})
|
|
} else {
|
|
drm.add_planar_framebuffer(&buffer, flags).map(|fb| (fb, format))
|
|
};
|
|
|
|
let (fb, format) = match ret {
|
|
Ok(fb) => fb,
|
|
Err(source) => {
|
|
warn_legacy_fb_export();
|
|
|
|
let fourcc = format.code;
|
|
let (depth, bpp) = get_depth(fourcc)
|
|
.zip(get_bpp(fourcc))
|
|
.ok_or_else(|| AccessError {
|
|
errmsg: "Unknown format for legacy framebuffer",
|
|
dev: drm.dev_path(),
|
|
source,
|
|
})?;
|
|
|
|
let fb = drm
|
|
.add_framebuffer(buffer.0.handle(), depth as u32, bpp as u32)
|
|
.map_err(|source| AccessError {
|
|
errmsg: "Failed to add framebuffer",
|
|
dev: drm.dev_path(),
|
|
source,
|
|
})?;
|
|
(fb, format)
|
|
}
|
|
};
|
|
|
|
Ok(DumbFramebuffer {
|
|
fb,
|
|
format,
|
|
drm: drm.clone(),
|
|
})
|
|
}
|