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},
|
||||
},
|
||||
drm::{DrmDeviceFd, DrmNode, NodeType},
|
||||
egl::{context::ContextPriority, EGLContext},
|
||||
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
|
||||
input::InputEvent,
|
||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||
renderer::{glow::GlowRenderer, multigpu::GpuManager},
|
||||
|
|
@ -54,6 +54,8 @@ pub struct KmsState {
|
|||
pub drm_devices: HashMap<DrmNode, Device>,
|
||||
pub input_devices: HashMap<String, input::Device>,
|
||||
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>>,
|
||||
|
||||
session: LibSeatSession,
|
||||
|
|
@ -78,6 +80,18 @@ pub fn init_backend(
|
|||
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
|
||||
let udev_dispatcher = init_udev(session.seat(), &event_loop.handle())
|
||||
.context("Failed to initialize udev connection")?;
|
||||
|
|
@ -107,6 +121,7 @@ pub fn init_backend(
|
|||
drm_devices: HashMap::new(),
|
||||
input_devices: HashMap::new(),
|
||||
primary_node: primary,
|
||||
software_renderer,
|
||||
api: GpuManager::new(GbmGlowBackend::new()).context("Failed to initialize gpu backend")?,
|
||||
|
||||
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(
|
||||
seat: String,
|
||||
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
|
||||
///
|
||||
/// `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>>(
|
||||
&mut self,
|
||||
kms_node_cb: F,
|
||||
) -> Result<RendererRef, GlMultiError> {
|
||||
match self {
|
||||
BackendData::Kms(kms) => {
|
||||
let KmsNodes {
|
||||
render_node,
|
||||
target_node,
|
||||
copy_format,
|
||||
} = kms_node_cb(kms).expect("No Software Rendering").into();
|
||||
Ok(RendererRef::GlMulti(kms.api.renderer(
|
||||
&render_node,
|
||||
&target_node,
|
||||
copy_format,
|
||||
)?))
|
||||
if let Some(nodes) = kms_node_cb(kms) {
|
||||
let nodes = nodes.into();
|
||||
Ok(RendererRef::GlMulti(kms.api.renderer(
|
||||
&nodes.render_node,
|
||||
&nodes.target_node,
|
||||
nodes.copy_format,
|
||||
)?))
|
||||
} else {
|
||||
Ok(RendererRef::Glow(
|
||||
kms.software_renderer
|
||||
.as_mut()
|
||||
.expect("No Software Rendering"),
|
||||
))
|
||||
}
|
||||
}
|
||||
BackendData::Winit(winit) => Ok(RendererRef::Glow(winit.backend.renderer())),
|
||||
BackendData::X11(x11) => Ok(RendererRef::Glow(&mut x11.renderer)),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue