Skip to content

Commit

Permalink
Add presentation mode preference in RenderElement
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Feb 23, 2024
1 parent 24b1033 commit a7e1c32
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 27 deletions.
13 changes: 7 additions & 6 deletions anvil/src/udev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use smithay::{
},
drm::{
compositor::DrmCompositor, CreateDrmNodeError, DrmAccessError, DrmDevice, DrmDeviceFd, DrmError,
DrmEvent, DrmEventMetadata, DrmNode, DrmSurface, GbmBufferedSurface, NodeType, PresentationMode,
DrmEvent, DrmEventMetadata, DrmNode, DrmSurface, GbmBufferedSurface, NodeType,
},
egl::{self, context::ContextPriority, EGLDevice, EGLDisplay},
input::InputEvent,
Expand All @@ -42,7 +42,7 @@ use smithay::{
gles::{GlesRenderer, GlesTexture},
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer},
sync::SyncPoint,
Bind, DebugFlags, ExportMem, ImportDma, ImportMemWl, Offscreen, Renderer,
Bind, DebugFlags, ExportMem, ImportDma, ImportMemWl, Offscreen, PresentationMode, Renderer,
},
session::{
libseat::{self, LibSeatSession},
Expand Down Expand Up @@ -635,6 +635,7 @@ struct SurfaceCompositorRenderResult {
states: RenderElementStates,
sync: Option<SyncPoint>,
damage: Option<Vec<Rectangle<i32, Physical>>>,
presentation_mode: PresentationMode,
}

impl SurfaceComposition {
Expand Down Expand Up @@ -731,6 +732,7 @@ impl SurfaceComposition {
damage: res.damage,
states: res.states,
sync: rendered.then_some(res.sync),
presentation_mode: PresentationMode::VSync,
}
})
.map_err(|err| match err {
Expand All @@ -747,11 +749,13 @@ impl SurfaceComposition {
if let PrimaryPlaneElement::Swapchain(element) = render_frame_result.primary_element {
element.sync.wait();
}
let presentation_mode = render_frame_result.presentation_mode();
SurfaceCompositorRenderResult {
rendered: !render_frame_result.is_empty,
damage: None,
states: render_frame_result.states,
sync: None,
presentation_mode,
}
})
.map_err(|err| match err {
Expand Down Expand Up @@ -1715,9 +1719,6 @@ fn render_surface<'a, 'b>(
clock.now(),
);

// TODO: Plug this in, either in DRM compositor or directly here
let presentation_mode = PresentationMode::VSync;

if res.rendered {
let output_presentation_feedback = take_presentation_feedback(output, space, &res.states);
surface
Expand All @@ -1726,7 +1727,7 @@ fn render_surface<'a, 'b>(
res.sync,
res.damage,
Some(output_presentation_feedback),
presentation_mode,
res.presentation_mode,
)
.map_err(Into::<SwapBuffersError>::into)?;
}
Expand Down
57 changes: 49 additions & 8 deletions src/backend/drm/compositor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ use crate::{
},
sync::SyncPoint,
utils::{CommitCounter, DamageBag, DamageSnapshot},
Bind, Blit, DebugFlags, Frame as RendererFrame, Renderer, Texture,
Bind, Blit, DebugFlags, Frame as RendererFrame, PresentationMode, Renderer, Texture,
},
SwapBuffersError,
},
Expand All @@ -172,9 +172,7 @@ use crate::{
wayland::shm,
};

use super::{
error::AccessError, DrmDeviceFd, DrmSurface, Framebuffer, PlaneClaim, PlaneInfo, Planes, PresentationMode,
};
use super::{error::AccessError, DrmDeviceFd, DrmSurface, Framebuffer, PlaneClaim, PlaneInfo, Planes};

pub mod dumb;
mod elements;
Expand Down Expand Up @@ -877,6 +875,9 @@ pub struct PrimarySwapchainElement<B: Buffer, F: Framebuffer> {
pub transform: Transform,
/// The damage on the primary plane
pub damage: DamageSnapshot<i32, BufferCoords>,
/// Presentation preference for this swapchain element, created by combining mode of all elements
/// rendered on this buffer
pub presentation_mode: Option<PresentationMode>,
}

impl<B: Buffer, F: Framebuffer> PrimarySwapchainElement<B, F> {
Expand Down Expand Up @@ -933,7 +934,22 @@ pub struct RenderFrameResult<'a, B: Buffer, F: Framebuffer, E> {
supports_fencing: bool,
}

impl<'a, B: Buffer, F: Framebuffer, E> RenderFrameResult<'a, B, F, E> {
fn combine_modes(a: Option<PresentationMode>, b: Option<PresentationMode>) -> Option<PresentationMode> {
match (a, b) {
// If either one wants VSync we go with VSync
(Some(PresentationMode::VSync), _) | (_, Some(PresentationMode::VSync)) => {
Some(PresentationMode::VSync)
}
// If neither wants VSync, and one wants Async we go with Async
(Some(PresentationMode::Async), _) | (_, Some(PresentationMode::Async)) => {
Some(PresentationMode::Async)
}
// Elements have no preference
(None, None) => None,
}
}

impl<'a, B: Buffer, F: Framebuffer, E: Element> RenderFrameResult<'a, B, F, E> {
/// Returns if synchronization with kms submission can't be guaranteed through the available apis.
pub fn needs_sync(&self) -> bool {
if let PrimaryPlaneElement::Swapchain(ref element) = self.primary_element {
Expand All @@ -942,6 +958,24 @@ impl<'a, B: Buffer, F: Framebuffer, E> RenderFrameResult<'a, B, F, E> {
false
}
}

/// Hint for DRM backend on how the surface should be presented
pub fn presentation_mode(&self) -> PresentationMode {
let mut res = None;

res = match &self.primary_element {
PrimaryPlaneElement::Swapchain(e) => combine_modes(res, e.presentation_mode),
PrimaryPlaneElement::Element(e) => combine_modes(res, e.presentation_mode()),
};

for e in self.overlay_elements.iter() {
res = combine_modes(res, e.presentation_mode());
}

// Let's assume that cursor element does not care about tearing

res.unwrap_or(PresentationMode::VSync)
}
}

struct SwapchainElement<'a, 'b, B: Buffer> {
Expand Down Expand Up @@ -2276,6 +2310,7 @@ where
.map(|config| matches!(&config.buffer, ScanoutBuffer::Swapchain(_)))
.unwrap_or(false);

let mut swapchain_presentation_mode = None;
if render {
trace!(
"rendering {} elements on the primary {:?}",
Expand Down Expand Up @@ -2340,6 +2375,11 @@ where
.map(|e| DrmRenderElements::Other(*e)),
);

for e in elements.iter() {
swapchain_presentation_mode =
combine_modes(swapchain_presentation_mode, e.presentation_mode());
}

let render_res =
self.damage_tracker
.render_output_with(renderer, dmabuf, age, &elements, clear_color);
Expand Down Expand Up @@ -2453,6 +2493,7 @@ where
transform: output_transform,
damage: self.primary_plane_damage_bag.snapshot(),
sync,
presentation_mode: swapchain_presentation_mode,
})
} else {
PrimaryPlaneElement::Element(primary_plane_scanout_element.unwrap())
Expand All @@ -2476,7 +2517,7 @@ where
supports_fencing: self.supports_fencing,
};

// We only store the next frame if it acutaly contains any changes or if a commit is pending
// We only store the next frame if it actually contains any changes or if a commit is pending
// Storing the (empty) frame could keep a reference to wayland buffers which
// could otherwise be potentially released on `frame_submitted`
if !next_frame.is_empty() {
Expand Down Expand Up @@ -3400,7 +3441,7 @@ where
let previous_fb_cache = self
.element_states
.get_mut(element_id)
// Note: We can mem::take the old fb_cache here here as we guarante that
// Note: We can mem::take the old fb_cache here here as we guarantee that
// the element state will always overwrite the current state at the end of render_frame
.map(|state| std::mem::take(&mut state.fb_cache))
.unwrap_or_default();
Expand Down Expand Up @@ -3561,7 +3602,7 @@ where
});

if !(primary_plane_changed || overlay_plane_changed) {
// we now know that nothing changed and we can assume any previouly failed
// we now know that nothing changed and we can assume any previously failed
// test will again fail
let instance_state = element_state
.instances
Expand Down
9 changes: 0 additions & 9 deletions src/backend/drm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,6 @@ fn warn_legacy_fb_export() {
});
}

/// Hint for DRM backend on how the surface should be presented
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PresentationMode {
/// Vertical synchronization
VSync,
/// Tearing presentationres
Async,
}

/// Common framebuffer operations
pub trait Framebuffer: AsRef<framebuffer::Handle> {
/// Retrieve the format of the framebuffer
Expand Down
4 changes: 2 additions & 2 deletions src/backend/drm/surface/gbm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::backend::allocator::gbm::GbmConvertError;
use crate::backend::allocator::{Allocator, Format, Fourcc, Modifier, Slot, Swapchain};
use crate::backend::drm::error::AccessError;
use crate::backend::drm::gbm::{framebuffer_from_bo, GbmFramebuffer};
use crate::backend::drm::{plane_has_property, DrmError, DrmSurface, PresentationMode};
use crate::backend::renderer::sync::SyncPoint;
use crate::backend::drm::{plane_has_property, DrmError, DrmSurface};
use crate::backend::renderer::{sync::SyncPoint, PresentationMode};
use crate::backend::SwapBuffersError;
use crate::utils::{DevPath, Physical, Point, Rectangle, Transform};

Expand Down
27 changes: 26 additions & 1 deletion src/backend/renderer/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{

#[cfg(feature = "wayland_frontend")]
use super::utils::Buffer;
use super::{utils::CommitCounter, Renderer};
use super::{utils::CommitCounter, PresentationMode, Renderer};

pub mod memory;
pub mod solid;
Expand Down Expand Up @@ -378,6 +378,10 @@ pub trait Element {
fn kind(&self) -> Kind {
Kind::default()
}
/// Hint for DRM backend on how the surface should be presented
fn presentation_mode(&self) -> Option<PresentationMode> {
None
}
}

/// A single render element
Expand Down Expand Up @@ -462,6 +466,10 @@ where
fn kind(&self) -> Kind {
(*self).kind()
}

fn presentation_mode(&self) -> Option<PresentationMode> {
(*self).presentation_mode()
}
}

impl<R, E> RenderElement<R> for &E
Expand Down Expand Up @@ -754,6 +762,19 @@ macro_rules! render_elements_internal {
Self::_GenericCatcher(_) => unreachable!(),
}
}

fn presentation_mode(&self) -> Option<$crate::backend::renderer::PresentationMode> {
match self {
$(
#[allow(unused_doc_comments)]
$(
#[$meta]
)*
Self::$body(x) => $crate::render_elements_internal!(@call presentation_mode; x)
),*,
Self::_GenericCatcher(_) => unreachable!(),
}
}
};
(@draw <$renderer:ty>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
fn draw(
Expand Down Expand Up @@ -1455,6 +1476,10 @@ where
fn kind(&self) -> Kind {
self.0.kind()
}

fn presentation_mode(&self) -> Option<PresentationMode> {
self.0.presentation_mode()
}
}

impl<R, C> RenderElement<R> for Wrap<C>
Expand Down
10 changes: 9 additions & 1 deletion src/backend/renderer/element/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ use tracing::{instrument, warn};
use wayland_server::protocol::wl_surface;

use crate::{
backend::renderer::{utils::RendererSurfaceStateUserData, Frame, ImportAll, Renderer, Texture},
backend::renderer::{
utils::RendererSurfaceStateUserData, Frame, ImportAll, PresentationMode, Renderer, Texture,
},
utils::{Buffer, Physical, Point, Rectangle, Scale, Size, Transform},
wayland::compositor::{self, SurfaceData, TraversalAction},
};
Expand Down Expand Up @@ -494,6 +496,12 @@ impl<R: Renderer + ImportAll> Element for WaylandSurfaceRenderElement<R> {
fn kind(&self) -> Kind {
self.kind
}

fn presentation_mode(&self) -> Option<PresentationMode> {
// On Wayland assume VSync as default preference
Some(PresentationMode::VSync)
// TODO: Return Async in case wp_tearing is attatched to the surface
}
}

impl<R> RenderElement<R> for WaylandSurfaceRenderElement<R>
Expand Down
9 changes: 9 additions & 0 deletions src/backend/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ pub mod sync;
#[cfg(feature = "renderer_test")]
pub mod test;

/// Hint for DRM backend on how the surface should be presented
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PresentationMode {
/// Vertical synchronization
VSync,
/// Tearing presentationres
Async,
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
/// Texture filtering methods
pub enum TextureFilter {
Expand Down

0 comments on commit a7e1c32

Please sign in to comment.