1
0
Fork 0
forked from wry/wry

state: split rendering helpers

This commit is contained in:
kossLAN 2026-05-29 19:41:55 -04:00
parent 19c2265400
commit 27750a31c4
No known key found for this signature in database
2 changed files with 217 additions and 203 deletions

View file

@ -1,5 +1,6 @@
mod animations;
mod connectors;
mod rendering;
pub(crate) use animations::LayoutAnimationCandidate;
pub use connectors::{ConnectorData, DrmDevData, OutputData};
@ -19,11 +20,7 @@ use {
backends::dummy::DummyBackend,
cli::RunArgs,
client::{Client, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
clientmem::ClientMemOffset,
cmm::{
cmm_description::ColorDescription, cmm_manager::ColorManager,
cmm_render_intent::RenderIntent,
},
cmm::cmm_manager::ColorManager,
compositor::LIBEI_SOCKET,
config::ConfigProxy,
copy_device::CopyDeviceRegistry,
@ -39,14 +36,8 @@ use {
ei_client::{EiClient, EiClients},
},
eventfd_cache::EventfdCache,
fixed::Fixed,
forker::ForkerProxy,
format::Format,
gfx_api::{
AcquireSync, AlphaMode, BufferResv, FdSync, GfxApi, GfxBlendBuffer, GfxContext,
GfxError, GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync,
STAGING_DOWNLOAD, SampleRect,
},
gfx_api::{GfxApi, GfxContext, GfxError},
gfx_apis::create_gfx_context,
globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal},
icons::Icons,
@ -83,7 +74,6 @@ use {
workspace_manager::WorkspaceManagerState,
xdg_activation_token_v1::ActivationToken,
zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1,
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
},
io_uring::IoUring,
@ -93,8 +83,7 @@ use {
leaks::Tracker,
logger::Logger,
pr_caps::PrCapsThread,
rect::{Rect, Region},
renderer::Renderer,
rect::Rect,
scale::Scale,
theme::{BarPosition, Color, Theme, ThemeColor, ThemeSized},
time::Time,
@ -102,7 +91,7 @@ use {
ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode,
FoundNode, LatchListener, Node, NodeIds, NodeVisitorBase, OutputNode,
PlaceholderNode, TearingMode, TileState, ToplevelData, ToplevelIdentifier,
ToplevelNode, ToplevelNodeBase, Transform, VrrMode, WorkspaceDisplayOrder,
ToplevelNode, ToplevelNodeBase, VrrMode, WorkspaceDisplayOrder,
WorkspaceNode, WorkspaceNodeId, WsMoveConfig, generic_node_visitor, move_ws_to_output,
},
udmabuf::UdmabufHolder,
@ -145,7 +134,6 @@ use {
sync::Arc,
time::{Duration, SystemTime},
},
thiserror::Error,
uapi::{OwnedFd, c},
};
@ -1102,180 +1090,6 @@ impl State {
}
}
pub fn present_output(
&self,
output: &OutputNode,
fb: &Rc<dyn GfxFramebuffer>,
cd: &Rc<ColorDescription>,
acquire_sync: AcquireSync,
release_sync: ReleaseSync,
tex: &Rc<dyn GfxTexture>,
render_hw_cursor: bool,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>,
) -> Result<Option<FdSync>, GfxError> {
let sync = fb.render_output(
acquire_sync,
release_sync,
cd,
output,
self,
Some(output.global.pos.get()),
output.global.persistent.scale.get(),
render_hw_cursor,
true,
blend_buffer,
blend_cd,
)?;
output.latched(false);
output.perform_screencopies(
tex,
cd,
None,
&AcquireSync::Unnecessary,
ReleaseSync::None,
!render_hw_cursor,
0,
0,
None,
);
Ok(sync)
}
pub fn perform_screencopy(
&self,
src: &Rc<dyn GfxTexture>,
resv: Option<&Rc<dyn BufferResv>>,
acquire_sync: &AcquireSync,
release_sync: ReleaseSync,
src_cd: &Rc<ColorDescription>,
target: &Rc<dyn GfxFramebuffer>,
target_acquire_sync: AcquireSync,
target_release_sync: ReleaseSync,
target_transform: Transform,
target_cd: &Rc<ColorDescription>,
position: Rect,
render_hardware_cursors: bool,
x_off: i32,
y_off: i32,
size: Option<(i32, i32)>,
transform: Transform,
scale: Scale,
) -> Result<Option<FdSync>, GfxError> {
let mut ops = vec![];
let mut renderer = Renderer {
base: target.renderer_base(&mut ops, scale, target_transform),
state: self,
logical_extents: position.at_point(0, 0),
pixel_extents: {
let (width, height) = target.logical_size(target_transform);
Rect::new_sized_saturating(0, 0, width, height)
},
stretch: None,
corner_radius: None,
};
let mut sample_rect = SampleRect::identity();
sample_rect.buffer_transform = transform;
renderer.base.render_texture(
src,
None,
x_off,
y_off,
Some(sample_rect),
size,
scale,
None,
resv.cloned(),
acquire_sync.clone(),
release_sync,
false,
src_cd,
RenderIntent::Perceptual,
AlphaMode::PremultipliedElectrical,
);
if render_hardware_cursors
&& let Some(cursor_user_group) = self.cursor_user_group_hardware_cursor.get()
&& let Some(cursor_user) = cursor_user_group.active()
&& let Some(cursor) = cursor_user.get()
{
let (mut x, mut y) = cursor_user.position();
x = x + x_off - Fixed::from_int(position.x1());
y = y + y_off - Fixed::from_int(position.y1());
cursor.render(&mut renderer, x, y);
}
target.render(
target_acquire_sync,
target_release_sync,
target_cd,
&ops,
Some(&Color::SOLID_BLACK),
&target_cd.linear,
None,
target_cd,
)
}
pub fn perform_shm_screencopy(
&self,
src: &Rc<dyn GfxTexture>,
src_cd: &Rc<ColorDescription>,
acquire_sync: &AcquireSync,
position: Rect,
x_off: i32,
y_off: i32,
size: Option<(i32, i32)>,
capture: &Rc<ZwlrScreencopyFrameV1>,
mem: &Rc<ClientMemOffset>,
stride: i32,
format: &'static Format,
transform: Transform,
scale: Scale,
) -> Result<Option<PendingShmTransfer>, ShmScreencopyError> {
let Some(ctx) = self.render_ctx.get() else {
return Err(ShmScreencopyError::NoRenderContext);
};
let fb = ctx
.clone()
.create_internal_fb(
&self.cpu_worker,
capture.rect.width(),
capture.rect.height(),
stride,
format,
)
.map_err(ShmScreencopyError::CreateTemporaryFb)?;
self.perform_screencopy(
src,
None,
acquire_sync,
ReleaseSync::None,
src_cd,
&(fb.clone() as Rc<dyn GfxFramebuffer>),
AcquireSync::Unnecessary,
ReleaseSync::None,
transform,
self.color_manager.srgb_gamma22(),
position,
true,
x_off - capture.rect.x1(),
y_off - capture.rect.y1(),
size,
transform,
scale,
)
.map_err(ShmScreencopyError::CopyToTemporary)?;
let staging = ctx.create_staging_buffer(fb.staging_size(), STAGING_DOWNLOAD);
let pending = fb
.download(
&staging,
capture.clone(),
mem.clone(),
Region::new(capture.rect.at_point(0, 0)),
)
.map_err(ShmScreencopyError::ReadPixels)?;
Ok(pending)
}
pub fn create_seat(self: &Rc<Self>, name: &str) -> Rc<WlSeatGlobal> {
let global_name = self.globals.name();
let seat = WlSeatGlobal::new(global_name, name, self);
@ -1881,15 +1695,3 @@ impl State {
})
}
}
#[derive(Debug, Error)]
pub enum ShmScreencopyError {
#[error("There is no render context")]
NoRenderContext,
#[error("Could not create a bridge framebuffer")]
CreateTemporaryFb(#[source] GfxError),
#[error("Could not copy texture to bridge framebuffer")]
CopyToTemporary(#[source] GfxError),
#[error("Could not read pixels from texture")]
ReadPixels(#[source] GfxError),
}

212
src/state/rendering.rs Normal file
View file

@ -0,0 +1,212 @@
use {
crate::{
clientmem::ClientMemOffset,
cmm::{cmm_description::ColorDescription, cmm_render_intent::RenderIntent},
fixed::Fixed,
format::Format,
gfx_api::{
AcquireSync, AlphaMode, BufferResv, FdSync, GfxBlendBuffer, GfxError,
GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync, STAGING_DOWNLOAD,
SampleRect,
},
ifs::zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
rect::{Rect, Region},
renderer::Renderer,
scale::Scale,
theme::Color,
tree::{OutputNode, Transform},
},
std::rc::Rc,
thiserror::Error,
};
use super::State;
impl State {
pub fn present_output(
&self,
output: &OutputNode,
fb: &Rc<dyn GfxFramebuffer>,
cd: &Rc<ColorDescription>,
acquire_sync: AcquireSync,
release_sync: ReleaseSync,
tex: &Rc<dyn GfxTexture>,
render_hw_cursor: bool,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>,
) -> Result<Option<FdSync>, GfxError> {
let sync = fb.render_output(
acquire_sync,
release_sync,
cd,
output,
self,
Some(output.global.pos.get()),
output.global.persistent.scale.get(),
render_hw_cursor,
true,
blend_buffer,
blend_cd,
)?;
output.latched(false);
output.perform_screencopies(
tex,
cd,
None,
&AcquireSync::Unnecessary,
ReleaseSync::None,
!render_hw_cursor,
0,
0,
None,
);
Ok(sync)
}
pub fn perform_screencopy(
&self,
src: &Rc<dyn GfxTexture>,
resv: Option<&Rc<dyn BufferResv>>,
acquire_sync: &AcquireSync,
release_sync: ReleaseSync,
src_cd: &Rc<ColorDescription>,
target: &Rc<dyn GfxFramebuffer>,
target_acquire_sync: AcquireSync,
target_release_sync: ReleaseSync,
target_transform: Transform,
target_cd: &Rc<ColorDescription>,
position: Rect,
render_hardware_cursors: bool,
x_off: i32,
y_off: i32,
size: Option<(i32, i32)>,
transform: Transform,
scale: Scale,
) -> Result<Option<FdSync>, GfxError> {
let mut ops = vec![];
let mut renderer = Renderer {
base: target.renderer_base(&mut ops, scale, target_transform),
state: self,
logical_extents: position.at_point(0, 0),
pixel_extents: {
let (width, height) = target.logical_size(target_transform);
Rect::new_sized_saturating(0, 0, width, height)
},
stretch: None,
corner_radius: None,
};
let mut sample_rect = SampleRect::identity();
sample_rect.buffer_transform = transform;
renderer.base.render_texture(
src,
None,
x_off,
y_off,
Some(sample_rect),
size,
scale,
None,
resv.cloned(),
acquire_sync.clone(),
release_sync,
false,
src_cd,
RenderIntent::Perceptual,
AlphaMode::PremultipliedElectrical,
);
if render_hardware_cursors
&& let Some(cursor_user_group) = self.cursor_user_group_hardware_cursor.get()
&& let Some(cursor_user) = cursor_user_group.active()
&& let Some(cursor) = cursor_user.get()
{
let (mut x, mut y) = cursor_user.position();
x = x + x_off - Fixed::from_int(position.x1());
y = y + y_off - Fixed::from_int(position.y1());
cursor.render(&mut renderer, x, y);
}
target.render(
target_acquire_sync,
target_release_sync,
target_cd,
&ops,
Some(&Color::SOLID_BLACK),
&target_cd.linear,
None,
target_cd,
)
}
pub fn perform_shm_screencopy(
&self,
src: &Rc<dyn GfxTexture>,
src_cd: &Rc<ColorDescription>,
acquire_sync: &AcquireSync,
position: Rect,
x_off: i32,
y_off: i32,
size: Option<(i32, i32)>,
capture: &Rc<ZwlrScreencopyFrameV1>,
mem: &Rc<ClientMemOffset>,
stride: i32,
format: &'static Format,
transform: Transform,
scale: Scale,
) -> Result<Option<PendingShmTransfer>, ShmScreencopyError> {
let Some(ctx) = self.render_ctx.get() else {
return Err(ShmScreencopyError::NoRenderContext);
};
let fb = ctx
.clone()
.create_internal_fb(
&self.cpu_worker,
capture.rect.width(),
capture.rect.height(),
stride,
format,
)
.map_err(ShmScreencopyError::CreateTemporaryFb)?;
self.perform_screencopy(
src,
None,
acquire_sync,
ReleaseSync::None,
src_cd,
&(fb.clone() as Rc<dyn GfxFramebuffer>),
AcquireSync::Unnecessary,
ReleaseSync::None,
transform,
self.color_manager.srgb_gamma22(),
position,
true,
x_off - capture.rect.x1(),
y_off - capture.rect.y1(),
size,
transform,
scale,
)
.map_err(ShmScreencopyError::CopyToTemporary)?;
let staging = ctx.create_staging_buffer(fb.staging_size(), STAGING_DOWNLOAD);
let pending = fb
.download(
&staging,
capture.clone(),
mem.clone(),
Region::new(capture.rect.at_point(0, 0)),
)
.map_err(ShmScreencopyError::ReadPixels)?;
Ok(pending)
}
}
#[derive(Debug, Error)]
pub enum ShmScreencopyError {
#[error("There is no render context")]
NoRenderContext,
#[error("Could not create a bridge framebuffer")]
CreateTemporaryFb(#[source] GfxError),
#[error("Could not copy texture to bridge framebuffer")]
CopyToTemporary(#[source] GfxError),
#[error("Could not read pixels from texture")]
ReadPixels(#[source] GfxError),
}