kms: Use DrmCompositor
This commit is contained in:
parent
ef894aebfc
commit
7caae686fe
4 changed files with 277 additions and 105 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -3302,7 +3302,7 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay"
|
name = "smithay"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/pop-os/smithay?rev=19f7c9aad6#19f7c9aad6e164ad78e0913e4371585441a14702"
|
source = "git+https://github.com/pop-os/smithay?rev=5293a69580#5293a6958095dc5bca439d0b6da795ca933f4da2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"appendlist",
|
"appendlist",
|
||||||
"ash",
|
"ash",
|
||||||
|
|
|
||||||
|
|
@ -70,4 +70,4 @@ debug = true
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
|
||||||
[patch."https://github.com/Smithay/smithay.git"]
|
[patch."https://github.com/Smithay/smithay.git"]
|
||||||
smithay = { git = "https://github.com/pop-os/smithay", rev = "19f7c9aad6" }
|
smithay = { git = "https://github.com/pop-os/smithay", rev = "5293a69580" }
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,42 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render,
|
backend::render::{element::CosmicElement, workspace_elements, CLEAR_COLOR},
|
||||||
config::OutputConfig,
|
config::OutputConfig,
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
state::{BackendData, ClientState, Common, Data, Fps},
|
state::{BackendData, ClientState, Common, Data, Fps},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::screencopy::UserdataExt,
|
handlers::screencopy::{render_session, UserdataExt},
|
||||||
protocols::screencopy::{BufferParams, Session as ScreencopySession},
|
protocols::screencopy::{BufferParams, Session as ScreencopySession},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::FailureReason;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::{
|
allocator::{
|
||||||
dmabuf::{AnyError, Dmabuf, DmabufAllocator},
|
dmabuf::{AnyError, AsDmabuf, Dmabuf, DmabufAllocator},
|
||||||
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
||||||
vulkan::{ImageUsageFlags, VulkanAllocator},
|
vulkan::{ImageUsageFlags, VulkanAllocator},
|
||||||
Allocator, Format,
|
Allocator, Format,
|
||||||
},
|
},
|
||||||
drm::{
|
drm::{
|
||||||
DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType,
|
compositor::{DrmCompositor, PrimaryPlaneElement},
|
||||||
|
DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, NodeType,
|
||||||
},
|
},
|
||||||
egl::{EGLContext, EGLDevice, EGLDisplay},
|
egl::{EGLContext, EGLDevice, EGLDisplay},
|
||||||
input::InputEvent,
|
input::InputEvent,
|
||||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||||
renderer::{
|
renderer::{
|
||||||
damage::DamageTrackedRenderer,
|
buffer_dimensions,
|
||||||
|
damage::{DamageTrackedRendererError as RenderError, OutputNoMode},
|
||||||
gles2::Gles2Renderbuffer,
|
gles2::Gles2Renderbuffer,
|
||||||
glow::GlowRenderer,
|
glow::GlowRenderer,
|
||||||
multigpu::{gbm::GbmGlesBackend, GpuManager},
|
multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager},
|
||||||
|
utils::draw_render_elements,
|
||||||
|
Bind, Blit, Offscreen, Renderer, TextureFilter,
|
||||||
},
|
},
|
||||||
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
||||||
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
||||||
|
|
@ -45,7 +50,10 @@ use smithay::{
|
||||||
timer::{TimeoutAction, Timer},
|
timer::{TimeoutAction, Timer},
|
||||||
Dispatcher, EventLoop, InsertError, LoopHandle, RegistrationToken,
|
Dispatcher, EventLoop, InsertError, LoopHandle, RegistrationToken,
|
||||||
},
|
},
|
||||||
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
drm::{
|
||||||
|
control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
||||||
|
Device as _,
|
||||||
|
},
|
||||||
input::Libinput,
|
input::Libinput,
|
||||||
nix::{fcntl::OFlag, sys::stat::dev_t},
|
nix::{fcntl::OFlag, sys::stat::dev_t},
|
||||||
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback,
|
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback,
|
||||||
|
|
@ -53,7 +61,9 @@ use smithay::{
|
||||||
},
|
},
|
||||||
utils::{DeviceFd, Size, Transform},
|
utils::{DeviceFd, Size, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::DmabufGlobal, relative_pointer::RelativePointerManagerState, seat::WaylandFocus,
|
dmabuf::{get_dmabuf, DmabufGlobal},
|
||||||
|
relative_pointer::RelativePointerManagerState,
|
||||||
|
seat::WaylandFocus,
|
||||||
},
|
},
|
||||||
xwayland::XWaylandClientData,
|
xwayland::XWaylandClientData,
|
||||||
};
|
};
|
||||||
|
|
@ -97,9 +107,7 @@ pub struct Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Surface {
|
pub struct Surface {
|
||||||
surface:
|
surface: Option<GbmDrmCompositor>,
|
||||||
Option<GbmBufferedSurface<GbmAllocator<DrmDeviceFd>, Option<OutputPresentationFeedback>>>,
|
|
||||||
damage_tracker: DamageTrackedRenderer,
|
|
||||||
connector: connector::Handle,
|
connector: connector::Handle,
|
||||||
output: Output,
|
output: Output,
|
||||||
refresh_rate: u32,
|
refresh_rate: u32,
|
||||||
|
|
@ -110,6 +118,13 @@ pub struct Surface {
|
||||||
fps: Fps,
|
fps: Fps,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GbmDrmCompositor = DrmCompositor<
|
||||||
|
GbmAllocator<DrmDeviceFd>,
|
||||||
|
GbmDevice<DrmDeviceFd>,
|
||||||
|
Option<OutputPresentationFeedback>,
|
||||||
|
DrmDeviceFd,
|
||||||
|
>;
|
||||||
|
|
||||||
pub fn init_backend(
|
pub fn init_backend(
|
||||||
dh: &DisplayHandle,
|
dh: &DisplayHandle,
|
||||||
event_loop: &mut EventLoop<'static, Data>,
|
event_loop: &mut EventLoop<'static, Data>,
|
||||||
|
|
@ -854,7 +869,6 @@ impl Device {
|
||||||
|
|
||||||
let data = Surface {
|
let data = Surface {
|
||||||
output: output.clone(),
|
output: output.clone(),
|
||||||
damage_tracker: DamageTrackedRenderer::from_output(&output),
|
|
||||||
surface: None,
|
surface: None,
|
||||||
connector: conn,
|
connector: conn,
|
||||||
vrr,
|
vrr,
|
||||||
|
|
@ -924,52 +938,153 @@ impl Surface {
|
||||||
state: &mut Common,
|
state: &mut Common,
|
||||||
screencopy: Option<&[(ScreencopySession, BufferParams)]>,
|
screencopy: Option<&[(ScreencopySession, BufferParams)]>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
puffin::profile_function!();
|
||||||
|
|
||||||
if self.surface.is_none() {
|
if self.surface.is_none() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let surface = self.surface.as_mut().unwrap();
|
self.fps.start();
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
if let Some(rd) = self.fps.rd.as_mut() {
|
||||||
|
rd.start_frame_capture(
|
||||||
|
renderer.glow_renderer().egl_context().get_context_handle(),
|
||||||
|
std::ptr::null(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let compositor = self.surface.as_mut().unwrap();
|
||||||
let (render_node, mut renderer) = match render_node {
|
let (render_node, mut renderer) = match render_node {
|
||||||
Some((render_node, allocator)) => (
|
Some((render_node, allocator)) => (
|
||||||
render_node,
|
render_node,
|
||||||
api.renderer(&render_node, &target_node, allocator, surface.format())
|
api.renderer(&render_node, &target_node, allocator, compositor.format())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
None => (target_node, api.single_renderer(&target_node).unwrap()),
|
None => (target_node, api.single_renderer(&target_node).unwrap()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (buffer, age) = surface
|
let handle = state.shell.workspaces.active(&self.output).handle;
|
||||||
.next_buffer()
|
let elements: Vec<CosmicElement<GlMultiRenderer<'_, '_>>> = workspace_elements(
|
||||||
.with_context(|| "Failed to allocate buffer")?;
|
|
||||||
|
|
||||||
match render::render_output::<GlMultiRenderer, _, Gles2Renderbuffer, _>(
|
|
||||||
Some(&render_node),
|
Some(&render_node),
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
buffer.clone(),
|
|
||||||
&mut self.damage_tracker,
|
|
||||||
age as usize,
|
|
||||||
state,
|
state,
|
||||||
&self.output,
|
&self.output,
|
||||||
|
&handle,
|
||||||
CursorMode::All,
|
CursorMode::All,
|
||||||
screencopy.map(|sessions| (buffer, sessions)),
|
&mut Some(&mut self.fps),
|
||||||
Some(&mut self.fps),
|
false,
|
||||||
) {
|
)?;
|
||||||
Ok((damage, states)) => {
|
self.fps.elements();
|
||||||
let feedback = if damage.is_some() {
|
|
||||||
Some(state.take_presentation_feedback(&self.output, &states))
|
let res = compositor.render_frame::<_, _, Gles2Renderbuffer>(
|
||||||
|
&mut renderer,
|
||||||
|
&elements,
|
||||||
|
CLEAR_COLOR,
|
||||||
|
);
|
||||||
|
self.fps.render();
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(frame_result) => {
|
||||||
|
if let Some(screencopy) = screencopy {
|
||||||
|
let primary_element = frame_result.primary_element;
|
||||||
|
let mut plane_elements = frame_result
|
||||||
|
.cursor_element
|
||||||
|
.into_iter()
|
||||||
|
.chain(frame_result.overlay_elements.into_iter())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for (session, params) in screencopy {
|
||||||
|
match render_session(
|
||||||
|
Some(*render_node),
|
||||||
|
&mut renderer,
|
||||||
|
&session,
|
||||||
|
params,
|
||||||
|
self.output.current_transform(),
|
||||||
|
|_node, buffer, renderer, dtr, age| {
|
||||||
|
let res = dtr.damage_output(age, &elements)?;
|
||||||
|
|
||||||
|
if let (Some(ref damage), _) = &res {
|
||||||
|
if let Ok(dmabuf) = get_dmabuf(buffer) {
|
||||||
|
renderer.bind(dmabuf).map_err(RenderError::Rendering)?;
|
||||||
|
} else {
|
||||||
|
let size = buffer_dimensions(buffer).unwrap();
|
||||||
|
let render_buffer =
|
||||||
|
Offscreen::<Gles2Renderbuffer>::create_buffer(
|
||||||
|
renderer, size,
|
||||||
|
)
|
||||||
|
.map_err(RenderError::Rendering)?;
|
||||||
|
renderer
|
||||||
|
.bind(render_buffer)
|
||||||
|
.map_err(RenderError::Rendering)?;
|
||||||
|
}
|
||||||
|
match primary_element {
|
||||||
|
PrimaryPlaneElement::Swapchain { slot, .. } => {
|
||||||
|
let source = slot.export().map_err(|_| {
|
||||||
|
// TODO AnyError::from
|
||||||
|
RenderError::Rendering(MultiError::ImportFailed)
|
||||||
|
})?;
|
||||||
|
for rect in damage {
|
||||||
|
renderer
|
||||||
|
.blit_from(
|
||||||
|
source.clone(),
|
||||||
|
*rect,
|
||||||
|
*rect,
|
||||||
|
TextureFilter::Nearest,
|
||||||
|
)
|
||||||
|
.map_err(RenderError::Rendering)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrimaryPlaneElement::Element(e) => plane_elements.push(e),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (output_size, output_scale, output_transform) = (
|
||||||
|
self.output.current_mode().ok_or(OutputNoMode)?.size,
|
||||||
|
self.output.current_scale().fractional_scale(),
|
||||||
|
self.output.current_transform(),
|
||||||
|
);
|
||||||
|
{
|
||||||
|
let mut frame = renderer
|
||||||
|
.render(output_size, output_transform)
|
||||||
|
.map_err(RenderError::Rendering)?;
|
||||||
|
draw_render_elements(
|
||||||
|
&mut frame,
|
||||||
|
output_scale,
|
||||||
|
&plane_elements,
|
||||||
|
damage,
|
||||||
|
)
|
||||||
|
.map_err(RenderError::Rendering)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Ok(true) => {} // success
|
||||||
|
Ok(false) => state.still_pending(session.clone(), params.clone()),
|
||||||
|
Err(err) => {
|
||||||
|
warn!(?err, "Error rendering to screencopy session.");
|
||||||
|
session.failed(FailureReason::Unspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.fps.screencopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
let feedback = if frame_result.damage.is_some() {
|
||||||
|
Some(state.take_presentation_feedback(&self.output, &frame_result.states))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
state.send_frames(&self.output, &states);
|
state.send_frames(&self.output, &frame_result.states);
|
||||||
surface
|
compositor
|
||||||
.queue_buffer(damage, feedback)
|
.queue_frame(feedback)
|
||||||
.with_context(|| "Failed to submit buffer for display")?;
|
.with_context(|| "Failed to submit result for display")?
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
surface.reset_buffers();
|
compositor.reset_buffers();
|
||||||
anyhow::bail!("Rendering failed: {}", err);
|
anyhow::bail!("Rendering failed: {}", err);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1034,7 +1149,7 @@ impl KmsState {
|
||||||
.ok_or(anyhow::anyhow!("Unknown mode"))?;
|
.ok_or(anyhow::anyhow!("Unknown mode"))?;
|
||||||
|
|
||||||
if !test_only {
|
if !test_only {
|
||||||
let res = if let Some(gbm_surface) = surface.surface.as_mut() {
|
let res = if let Some(compositor) = surface.surface.as_mut() {
|
||||||
if output_config.vrr != surface.vrr {
|
if output_config.vrr != surface.vrr {
|
||||||
surface.vrr = drm_helpers::set_vrr(
|
surface.vrr = drm_helpers::set_vrr(
|
||||||
drm,
|
drm,
|
||||||
|
|
@ -1043,7 +1158,7 @@ impl KmsState {
|
||||||
output_config.vrr,
|
output_config.vrr,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
gbm_surface.use_mode(*mode).unwrap();
|
compositor.use_mode(*mode).unwrap();
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
surface.vrr = drm_helpers::set_vrr(drm, *crtc, conn, output_config.vrr)
|
surface.vrr = drm_helpers::set_vrr(drm, *crtc, conn, output_config.vrr)
|
||||||
|
|
@ -1051,17 +1166,38 @@ impl KmsState {
|
||||||
surface.refresh_rate = drm_helpers::calculate_refresh_rate(*mode);
|
surface.refresh_rate = drm_helpers::calculate_refresh_rate(*mode);
|
||||||
|
|
||||||
let drm_surface = drm.create_surface(*crtc, *mode, &[conn])?;
|
let drm_surface = drm.create_surface(*crtc, *mode, &[conn])?;
|
||||||
let target = GbmBufferedSurface::new(
|
let driver = drm
|
||||||
|
.get_driver()
|
||||||
|
.with_context(|| "Failed to query drm driver")?;
|
||||||
|
let mut planes = drm_surface
|
||||||
|
.planes()
|
||||||
|
.with_context(|| "Failed to query drm planes")?;
|
||||||
|
// QUIRK: Using an overlay plane on a nvidia card breaks the display controller (wtf...)
|
||||||
|
if driver
|
||||||
|
.name()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_lowercase()
|
||||||
|
.contains("nvidia")
|
||||||
|
{
|
||||||
|
planes.overlay = vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = DrmCompositor::new(
|
||||||
|
&surface.output,
|
||||||
drm_surface,
|
drm_surface,
|
||||||
|
Some(planes),
|
||||||
GbmAllocator::new(
|
GbmAllocator::new(
|
||||||
device.gbm.clone(),
|
device.gbm.clone(),
|
||||||
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
||||||
),
|
),
|
||||||
|
device.gbm.clone(),
|
||||||
device.formats.clone(),
|
device.formats.clone(),
|
||||||
|
drm.cursor_size(),
|
||||||
|
Some(device.gbm.clone()),
|
||||||
)
|
)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to initialize Gbm surface for {}",
|
"Failed to initialize drm surface for {}",
|
||||||
drm_helpers::interface_name(drm, conn)
|
drm_helpers::interface_name(drm, conn)
|
||||||
.unwrap_or_else(|_| String::from("Unknown"))
|
.unwrap_or_else(|_| String::from("Unknown"))
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ use crate::{
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::{layout::floating::SeatMoveGrabState, CosmicMappedRenderElement},
|
shell::{
|
||||||
|
layout::floating::SeatMoveGrabState, CosmicMappedRenderElement, WorkspaceRenderElement,
|
||||||
|
},
|
||||||
state::{Common, Fps},
|
state::{Common, Fps},
|
||||||
utils::prelude::SeatExt,
|
utils::prelude::SeatExt,
|
||||||
wayland::{
|
wayland::{
|
||||||
|
|
@ -220,6 +222,94 @@ where
|
||||||
elements
|
elements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn workspace_elements<R, E>(
|
||||||
|
_gpu: Option<&DrmNode>,
|
||||||
|
renderer: &mut R,
|
||||||
|
state: &mut Common,
|
||||||
|
output: &Output,
|
||||||
|
handle: &WorkspaceHandle,
|
||||||
|
cursor_mode: CursorMode,
|
||||||
|
_fps: &mut Option<&mut Fps>,
|
||||||
|
exclude_workspace_overview: bool,
|
||||||
|
) -> Result<Vec<E>, OutputNoMode>
|
||||||
|
where
|
||||||
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
|
<R as Renderer>::TextureId: Clone + 'static,
|
||||||
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
|
E: From<CursorRenderElement<R>>
|
||||||
|
+ From<CosmicMappedRenderElement<R>>
|
||||||
|
+ From<WorkspaceRenderElement<R>>,
|
||||||
|
{
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
puffin::profile_function!();
|
||||||
|
|
||||||
|
let mut elements: Vec<E> = cursor_elements(renderer, state, output, cursor_mode);
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
let output_geo = output.geometry();
|
||||||
|
let scale = output.current_scale().fractional_scale();
|
||||||
|
|
||||||
|
if let Some(fps) = _fps.as_mut() {
|
||||||
|
let fps_overlay = fps_ui(
|
||||||
|
_gpu,
|
||||||
|
state,
|
||||||
|
renderer.glow_renderer_mut(),
|
||||||
|
*fps,
|
||||||
|
Rectangle::from_loc_and_size(
|
||||||
|
(0, 0),
|
||||||
|
(output_geo.size.w.min(400), output_geo.size.h.min(800)),
|
||||||
|
),
|
||||||
|
scale,
|
||||||
|
)
|
||||||
|
.map_err(<R as Renderer>::Error::from)
|
||||||
|
.map_err(RenderError::Rendering)?;
|
||||||
|
elements.push(fps_overlay.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.shell.outputs.first() == Some(output) {
|
||||||
|
if let Some(profiler_overlay) = profiler_ui(
|
||||||
|
state,
|
||||||
|
renderer.glow_renderer_mut(),
|
||||||
|
Rectangle::from_loc_and_size((0, 0), output_geo.size),
|
||||||
|
scale,
|
||||||
|
)
|
||||||
|
.map_err(<R as Renderer>::Error::from)
|
||||||
|
.map_err(RenderError::Rendering)?
|
||||||
|
{
|
||||||
|
elements.push(profiler_overlay.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = state.shell.space_for_handle(&handle).ok_or(OutputNoMode)?;
|
||||||
|
let last_active_seat = state.last_active_seat().clone();
|
||||||
|
let move_active = last_active_seat
|
||||||
|
.user_data()
|
||||||
|
.get::<SeatMoveGrabState>()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.is_some();
|
||||||
|
let active_output = &last_active_seat.active_output() == output;
|
||||||
|
|
||||||
|
elements.extend(
|
||||||
|
workspace
|
||||||
|
.render_output::<R>(
|
||||||
|
renderer,
|
||||||
|
output,
|
||||||
|
&state.shell.override_redirect_windows,
|
||||||
|
state.xwayland_state.values_mut(),
|
||||||
|
(!move_active && active_output).then_some(&last_active_seat),
|
||||||
|
exclude_workspace_overview,
|
||||||
|
)
|
||||||
|
.map_err(|_| OutputNoMode)?
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(elements)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render_output<'frame, R, Target, OffTarget, Source>(
|
pub fn render_output<'frame, R, Target, OffTarget, Source>(
|
||||||
gpu: Option<&DrmNode>,
|
gpu: Option<&DrmNode>,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
|
|
@ -326,70 +416,16 @@ where
|
||||||
cursor_mode = CursorMode::All;
|
cursor_mode = CursorMode::All;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut elements: Vec<CosmicElement<R>> = cursor_elements(renderer, state, output, cursor_mode);
|
let elements: Vec<CosmicElement<R>> = workspace_elements(
|
||||||
|
gpu,
|
||||||
#[cfg(feature = "debug")]
|
renderer,
|
||||||
{
|
state,
|
||||||
let output_geo = output.geometry();
|
output,
|
||||||
let scale = output.current_scale().fractional_scale();
|
handle,
|
||||||
|
cursor_mode,
|
||||||
if let Some(fps) = fps.as_mut() {
|
&mut fps,
|
||||||
let fps_overlay = fps_ui(
|
exclude_workspace_overview,
|
||||||
gpu,
|
)?;
|
||||||
state,
|
|
||||||
renderer.glow_renderer_mut(),
|
|
||||||
fps,
|
|
||||||
Rectangle::from_loc_and_size(
|
|
||||||
(0, 0),
|
|
||||||
(output_geo.size.w.min(400), output_geo.size.h.min(800)),
|
|
||||||
),
|
|
||||||
scale,
|
|
||||||
)
|
|
||||||
.map_err(<R as Renderer>::Error::from)
|
|
||||||
.map_err(RenderError::Rendering)?;
|
|
||||||
elements.push(fps_overlay.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if state.shell.outputs.first() == Some(output) {
|
|
||||||
if let Some(profiler_overlay) = profiler_ui(
|
|
||||||
state,
|
|
||||||
renderer.glow_renderer_mut(),
|
|
||||||
Rectangle::from_loc_and_size((0, 0), output_geo.size),
|
|
||||||
scale,
|
|
||||||
)
|
|
||||||
.map_err(<R as Renderer>::Error::from)
|
|
||||||
.map_err(RenderError::Rendering)?
|
|
||||||
{
|
|
||||||
elements.push(profiler_overlay.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let workspace = state.shell.space_for_handle(&handle).ok_or(OutputNoMode)?;
|
|
||||||
let last_active_seat = state.last_active_seat().clone();
|
|
||||||
let move_active = last_active_seat
|
|
||||||
.user_data()
|
|
||||||
.get::<SeatMoveGrabState>()
|
|
||||||
.unwrap()
|
|
||||||
.borrow()
|
|
||||||
.is_some();
|
|
||||||
let active_output = &last_active_seat.active_output() == output;
|
|
||||||
|
|
||||||
elements.extend(
|
|
||||||
workspace
|
|
||||||
.render_output::<R>(
|
|
||||||
renderer,
|
|
||||||
output,
|
|
||||||
&state.shell.override_redirect_windows,
|
|
||||||
state.xwayland_state.values_mut(),
|
|
||||||
(!move_active && active_output).then_some(&last_active_seat),
|
|
||||||
exclude_workspace_overview,
|
|
||||||
)
|
|
||||||
.map_err(|_| OutputNoMode)?
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(fps) = fps.as_mut() {
|
if let Some(fps) = fps.as_mut() {
|
||||||
fps.elements();
|
fps.elements();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue