Use EGL_MESA_device_software as fallback for screen capture
Previously, screenshots and screencopy panicked if no DRM render nodes are present. Instead, create a `GlowRenderer` using llvmpipe, if available. This should work as a fallback until pixman is integrated.
This commit is contained in:
parent
87020c79ba
commit
5537fa4822
2 changed files with 48 additions and 12 deletions
|
|
@ -12,7 +12,7 @@ use smithay::{
|
||||||
gbm::{GbmAllocator, GbmBufferFlags},
|
gbm::{GbmAllocator, GbmBufferFlags},
|
||||||
},
|
},
|
||||||
drm::{DrmDeviceFd, DrmNode, NodeType},
|
drm::{DrmDeviceFd, DrmNode, NodeType},
|
||||||
egl::{context::ContextPriority, EGLContext},
|
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
||||||
input::InputEvent,
|
input::InputEvent,
|
||||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||||
renderer::{glow::GlowRenderer, multigpu::GpuManager},
|
renderer::{glow::GlowRenderer, multigpu::GpuManager},
|
||||||
|
|
@ -54,6 +54,8 @@ pub struct KmsState {
|
||||||
pub drm_devices: HashMap<DrmNode, Device>,
|
pub drm_devices: HashMap<DrmNode, Device>,
|
||||||
pub input_devices: HashMap<String, input::Device>,
|
pub input_devices: HashMap<String, input::Device>,
|
||||||
pub primary_node: Option<DrmNode>,
|
pub primary_node: Option<DrmNode>,
|
||||||
|
// Mesa llvmpipe renderer, if supported and there are no render nodes
|
||||||
|
pub software_renderer: Option<GlowRenderer>,
|
||||||
pub api: GpuManager<GbmGlowBackend<DrmDeviceFd>>,
|
pub api: GpuManager<GbmGlowBackend<DrmDeviceFd>>,
|
||||||
|
|
||||||
session: LibSeatSession,
|
session: LibSeatSession,
|
||||||
|
|
@ -78,6 +80,18 @@ pub fn init_backend(
|
||||||
info!("Using {} as primary gpu for rendering.", primary);
|
info!("Using {} as primary gpu for rendering.", primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let software_renderer = if primary.is_none() {
|
||||||
|
match software_renderer() {
|
||||||
|
Ok(renderer) => Some(renderer),
|
||||||
|
Err(err) => {
|
||||||
|
error!(?err, "Failed to initialize software EGL renderer.");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// watch for gpu events
|
// watch for gpu events
|
||||||
let udev_dispatcher = init_udev(session.seat(), &event_loop.handle())
|
let udev_dispatcher = init_udev(session.seat(), &event_loop.handle())
|
||||||
.context("Failed to initialize udev connection")?;
|
.context("Failed to initialize udev connection")?;
|
||||||
|
|
@ -107,6 +121,7 @@ pub fn init_backend(
|
||||||
drm_devices: HashMap::new(),
|
drm_devices: HashMap::new(),
|
||||||
input_devices: HashMap::new(),
|
input_devices: HashMap::new(),
|
||||||
primary_node: primary,
|
primary_node: primary,
|
||||||
|
software_renderer,
|
||||||
api: GpuManager::new(GbmGlowBackend::new()).context("Failed to initialize gpu backend")?,
|
api: GpuManager::new(GbmGlowBackend::new()).context("Failed to initialize gpu backend")?,
|
||||||
|
|
||||||
session,
|
session,
|
||||||
|
|
@ -193,6 +208,22 @@ fn determine_primary_gpu(seat: String) -> Option<DrmNode> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create `GlowRenderer` for `EGL_MESA_device_software` device, if present
|
||||||
|
fn software_renderer() -> anyhow::Result<GlowRenderer> {
|
||||||
|
let mut devices = EGLDevice::enumerate()?;
|
||||||
|
let device = devices
|
||||||
|
.find(|device| {
|
||||||
|
device
|
||||||
|
.extensions()
|
||||||
|
.iter()
|
||||||
|
.any(|ext| ext == "EGL_MESA_device_software")
|
||||||
|
})
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("no EGL device found with `EGL_MESA_device_software`"))?;
|
||||||
|
let display = unsafe { EGLDisplay::new(device)? };
|
||||||
|
let context = EGLContext::new(&display)?;
|
||||||
|
unsafe { Ok(GlowRenderer::new(context)?) }
|
||||||
|
}
|
||||||
|
|
||||||
fn init_udev(
|
fn init_udev(
|
||||||
seat: String,
|
seat: String,
|
||||||
evlh: &LoopHandle<'static, State>,
|
evlh: &LoopHandle<'static, State>,
|
||||||
|
|
|
||||||
27
src/state.rs
27
src/state.rs
|
|
@ -389,23 +389,28 @@ impl BackendData {
|
||||||
/// Get an offscreen renderer for screen capture / screenshot rendering
|
/// Get an offscreen renderer for screen capture / screenshot rendering
|
||||||
///
|
///
|
||||||
/// `kms_node_cb` callback use used to determine nodes to render with when using kms backend.
|
/// `kms_node_cb` callback use used to determine nodes to render with when using kms backend.
|
||||||
/// Panics if this returns `None`.
|
/// If this returns `None`, it will attempt to use llvmpipe, then panic if no renderer is
|
||||||
|
/// found.
|
||||||
pub fn offscreen_renderer<N: Into<KmsNodes>, F: FnOnce(&mut KmsState) -> Option<N>>(
|
pub fn offscreen_renderer<N: Into<KmsNodes>, F: FnOnce(&mut KmsState) -> Option<N>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
kms_node_cb: F,
|
kms_node_cb: F,
|
||||||
) -> Result<RendererRef, GlMultiError> {
|
) -> Result<RendererRef, GlMultiError> {
|
||||||
match self {
|
match self {
|
||||||
BackendData::Kms(kms) => {
|
BackendData::Kms(kms) => {
|
||||||
let KmsNodes {
|
if let Some(nodes) = kms_node_cb(kms) {
|
||||||
render_node,
|
let nodes = nodes.into();
|
||||||
target_node,
|
Ok(RendererRef::GlMulti(kms.api.renderer(
|
||||||
copy_format,
|
&nodes.render_node,
|
||||||
} = kms_node_cb(kms).expect("No Software Rendering").into();
|
&nodes.target_node,
|
||||||
Ok(RendererRef::GlMulti(kms.api.renderer(
|
nodes.copy_format,
|
||||||
&render_node,
|
)?))
|
||||||
&target_node,
|
} else {
|
||||||
copy_format,
|
Ok(RendererRef::Glow(
|
||||||
)?))
|
kms.software_renderer
|
||||||
|
.as_mut()
|
||||||
|
.expect("No Software Rendering"),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BackendData::Winit(winit) => Ok(RendererRef::Glow(winit.backend.renderer())),
|
BackendData::Winit(winit) => Ok(RendererRef::Glow(winit.backend.renderer())),
|
||||||
BackendData::X11(x11) => Ok(RendererRef::Glow(&mut x11.renderer)),
|
BackendData::X11(x11) => Ok(RendererRef::Glow(&mut x11.renderer)),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue