mirror of
https://github.com/CloudNebulaProject/wayray.git
synced 2026-04-10 13:10:41 +00:00
Add rendering pipeline for client surfaces via OutputDamageTracker
- Create render module using Smithay's desktop::space::render_output for damage-tracked frame rendering to the Winit backend window - Store backend and damage_tracker in CalloopData so the Winit event callback can trigger rendering on Redraw events - Send initial xdg toplevel configure on first commit so clients can begin drawing - Send frame callbacks after each render so clients schedule redraws
This commit is contained in:
parent
50c8f68906
commit
cbfc6e95df
3 changed files with 138 additions and 7 deletions
|
|
@ -7,6 +7,7 @@ use smithay::{
|
||||||
wayland::{
|
wayland::{
|
||||||
buffer::BufferHandler,
|
buffer::BufferHandler,
|
||||||
compositor::{CompositorClientState, CompositorHandler, CompositorState},
|
compositor::{CompositorClientState, CompositorHandler, CompositorState},
|
||||||
|
seat::WaylandFocus,
|
||||||
shm::{ShmHandler, ShmState},
|
shm::{ShmHandler, ShmState},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -44,6 +45,22 @@ impl CompositorHandler for WayRay {
|
||||||
fn commit(&mut self, surface: &WlSurface) {
|
fn commit(&mut self, surface: &WlSurface) {
|
||||||
trace!(?surface, "surface commit");
|
trace!(?surface, "surface commit");
|
||||||
smithay::backend::renderer::utils::on_commit_buffer_handler::<Self>(surface);
|
smithay::backend::renderer::utils::on_commit_buffer_handler::<Self>(surface);
|
||||||
|
|
||||||
|
// If this surface belongs to an xdg toplevel that hasn't received
|
||||||
|
// its initial configure yet, send it now so the client can start
|
||||||
|
// drawing.
|
||||||
|
if let Some(window) = self
|
||||||
|
.space
|
||||||
|
.elements()
|
||||||
|
.find(|w| w.wl_surface().map(|s| s.into_owned()) == Some(surface.clone()))
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
if let Some(toplevel) = window.toplevel() {
|
||||||
|
if !toplevel.is_initial_configure_sent() {
|
||||||
|
toplevel.send_configure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mod errors;
|
mod errors;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
|
mod render;
|
||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -11,8 +12,8 @@ use crate::state::WayRay;
|
||||||
use miette::Result;
|
use miette::Result;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
renderer::gles::GlesRenderer,
|
renderer::{damage::OutputDamageTracker, gles::GlesRenderer},
|
||||||
winit::{self, WinitEvent},
|
winit::{self, WinitEvent, WinitGraphicsBackend},
|
||||||
},
|
},
|
||||||
output::{Mode, Output, PhysicalProperties, Subpixel},
|
output::{Mode, Output, PhysicalProperties, Subpixel},
|
||||||
reexports::wayland_server::Display,
|
reexports::wayland_server::Display,
|
||||||
|
|
@ -25,6 +26,8 @@ use tracing::info;
|
||||||
struct CalloopData {
|
struct CalloopData {
|
||||||
state: WayRay,
|
state: WayRay,
|
||||||
display: Display<WayRay>,
|
display: Display<WayRay>,
|
||||||
|
backend: WinitGraphicsBackend<GlesRenderer>,
|
||||||
|
damage_tracker: OutputDamageTracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
|
@ -118,7 +121,7 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
// Insert the Winit event loop as a calloop source.
|
// Insert the Winit event loop as a calloop source.
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(winit_event_loop, move |event, _, _data| match event {
|
.insert_source(winit_event_loop, move |event, _, data| match event {
|
||||||
WinitEvent::Resized { size, scale_factor } => {
|
WinitEvent::Resized { size, scale_factor } => {
|
||||||
info!(?size, scale_factor, "window resized");
|
info!(?size, scale_factor, "window resized");
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +132,11 @@ fn main() -> Result<()> {
|
||||||
// Input handling is Task 7 -- ignore for now.
|
// Input handling is Task 7 -- ignore for now.
|
||||||
}
|
}
|
||||||
WinitEvent::Redraw => {
|
WinitEvent::Redraw => {
|
||||||
// Rendering is Task 6 -- ignore for now.
|
render::render_output_frame(
|
||||||
|
&mut data.state,
|
||||||
|
&mut data.backend,
|
||||||
|
&mut data.damage_tracker,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
WinitEvent::CloseRequested => {
|
WinitEvent::CloseRequested => {
|
||||||
info!("close requested, shutting down");
|
info!("close requested, shutting down");
|
||||||
|
|
@ -138,10 +145,15 @@ fn main() -> Result<()> {
|
||||||
})
|
})
|
||||||
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e.error)))?;
|
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e.error)))?;
|
||||||
|
|
||||||
// Keep a handle to the backend (needed for rendering in Task 6).
|
// Create a damage tracker for efficient rendering.
|
||||||
let _backend = backend;
|
let damage_tracker = OutputDamageTracker::from_output(&output);
|
||||||
|
|
||||||
let mut calloop_data = CalloopData { state, display };
|
let mut calloop_data = CalloopData {
|
||||||
|
state,
|
||||||
|
display,
|
||||||
|
backend,
|
||||||
|
damage_tracker,
|
||||||
|
};
|
||||||
|
|
||||||
info!("entering main event loop");
|
info!("entering main event loop");
|
||||||
|
|
||||||
|
|
|
||||||
102
crates/wrsrvd/src/render.rs
Normal file
102
crates/wrsrvd/src/render.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
use smithay::{
|
||||||
|
backend::{
|
||||||
|
renderer::{
|
||||||
|
damage::OutputDamageTracker,
|
||||||
|
element::texture::TextureRenderElement,
|
||||||
|
gles::{GlesRenderer, GlesTexture},
|
||||||
|
},
|
||||||
|
winit::WinitGraphicsBackend,
|
||||||
|
},
|
||||||
|
desktop::{Window, space::render_output},
|
||||||
|
};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
use crate::state::WayRay;
|
||||||
|
|
||||||
|
/// Dark grey clear color for the compositor background.
|
||||||
|
const CLEAR_COLOR: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
|
||||||
|
|
||||||
|
/// Render the compositor space to the Winit backend window.
|
||||||
|
///
|
||||||
|
/// Uses `OutputDamageTracker` for efficient re-rendering: only
|
||||||
|
/// damaged regions are redrawn each frame.
|
||||||
|
///
|
||||||
|
/// Returns `true` if any damage was present and submitted.
|
||||||
|
pub fn render_output_frame(
|
||||||
|
state: &mut WayRay,
|
||||||
|
backend: &mut WinitGraphicsBackend<GlesRenderer>,
|
||||||
|
damage_tracker: &mut OutputDamageTracker,
|
||||||
|
) -> bool {
|
||||||
|
let output = state.output.clone();
|
||||||
|
|
||||||
|
// Get buffer age before bind (avoids borrow conflict).
|
||||||
|
let age = backend.buffer_age().unwrap_or(0);
|
||||||
|
|
||||||
|
// Render within a block so framebuffer is dropped before submit.
|
||||||
|
let render_damage = {
|
||||||
|
let (renderer, mut framebuffer) = match backend.bind() {
|
||||||
|
Ok(pair) => pair,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(?err, "failed to bind winit backend for rendering");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The empty custom elements slice needs a concrete type.
|
||||||
|
let custom_elements: &[TextureRenderElement<GlesTexture>] = &[];
|
||||||
|
|
||||||
|
let render_result = render_output::<_, _, Window, _>(
|
||||||
|
&output,
|
||||||
|
renderer,
|
||||||
|
&mut framebuffer,
|
||||||
|
1.0, // alpha
|
||||||
|
age,
|
||||||
|
[&state.space],
|
||||||
|
custom_elements,
|
||||||
|
damage_tracker,
|
||||||
|
CLEAR_COLOR,
|
||||||
|
);
|
||||||
|
|
||||||
|
match render_result {
|
||||||
|
Ok(result) => {
|
||||||
|
// Clone the damage rectangles so we can use them after
|
||||||
|
// the framebuffer is dropped.
|
||||||
|
Ok(result.damage.cloned())
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!(?err, "damage tracker render failed");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// framebuffer is now dropped, backend is no longer borrowed.
|
||||||
|
|
||||||
|
match render_damage {
|
||||||
|
Ok(damage) => {
|
||||||
|
let has_damage = damage.is_some();
|
||||||
|
|
||||||
|
let submit_result = if let Some(ref rects) = damage {
|
||||||
|
backend.submit(Some(rects))
|
||||||
|
} else {
|
||||||
|
backend.submit(None)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = submit_result {
|
||||||
|
warn!(?err, "failed to submit frame");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send frame callbacks to all mapped surfaces so clients
|
||||||
|
// know they can draw the next frame.
|
||||||
|
let time = state.clock.now();
|
||||||
|
for window in state.space.elements() {
|
||||||
|
window.send_frame(&output, time, Some(std::time::Duration::ZERO), |_, _| {
|
||||||
|
Some(output.clone())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
has_damage
|
||||||
|
}
|
||||||
|
Err(()) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue