1
0
Fork 0
forked from wry/wry

state: split render context handling

This commit is contained in:
kossLAN 2026-05-29 19:48:26 -04:00
parent c4655d4641
commit 16c402825f
No known key found for this signature in database
2 changed files with 250 additions and 232 deletions

View file

@ -2,6 +2,7 @@ mod animations;
mod connectors;
mod idle;
mod rendering;
mod render_context;
mod settings;
mod tree_ops;
mod xwayland;
@ -43,8 +44,7 @@ use {
},
eventfd_cache::EventfdCache,
forker::ForkerProxy,
gfx_api::{GfxApi, GfxContext, GfxError},
gfx_apis::create_gfx_context,
gfx_api::{GfxApi, GfxContext},
globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal},
icons::Icons,
ifs::{
@ -90,9 +90,9 @@ use {
theme::Theme,
time::Time,
tree::{
ContainerNode, DisplayNode, FloatNode, FoundNode, LatchListener, Node, NodeIds,
NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelIdentifier,
ToplevelNode, VrrMode, WorkspaceDisplayOrder, WorkspaceNode, WorkspaceNodeId,
ContainerNode, DisplayNode, FloatNode, FoundNode, LatchListener, NodeIds, OutputNode,
PlaceholderNode, TearingMode, ToplevelIdentifier, ToplevelNode, VrrMode,
WorkspaceDisplayOrder, WorkspaceNode, WorkspaceNodeId,
},
udmabuf::UdmabufHolder,
utils::{
@ -110,10 +110,7 @@ use {
refcounted::RefCounted,
run_toplevel::RunToplevel,
},
video::{
dmabuf::DmaBufIds,
drm::{Drm, wait_for_syncobj::WaitForSyncobj},
},
video::{dmabuf::DmaBufIds, drm::wait_for_syncobj::WaitForSyncobj},
virtual_output::VirtualOutputs,
wheel::Wheel,
wire::{
@ -123,7 +120,6 @@ use {
},
},
ahash::AHashMap,
bstr::ByteSlice,
std::{
cell::{Cell, RefCell},
fmt::{Debug, Formatter},
@ -329,229 +325,7 @@ pub struct DeviceHandlerData {
pub mods_listener: EventListener<dyn LedsListener>,
}
struct UpdateTextTexturesVisitor;
impl NodeVisitorBase for UpdateTextTexturesVisitor {
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
node.node_visit_children(self);
}
fn visit_output(&mut self, node: &Rc<OutputNode>) {
node.schedule_update_render_data();
node.node_visit_children(self);
}
fn visit_float(&mut self, node: &Rc<FloatNode>) {
node.node_visit_children(self);
}
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
node.title_texture.take();
node.node_visit_children(self);
}
fn visit_placeholder(&mut self, node: &Rc<PlaceholderNode>) {
node.textures.borrow_mut().clear();
node.schedule_update_texture();
node.node_visit_children(self);
}
}
impl State {
pub fn create_gfx_context(
&self,
drm: &Drm,
api: Option<GfxApi>,
) -> Result<Rc<dyn GfxContext>, GfxError> {
create_gfx_context(
&self.eng,
&self.ring,
&self.eventfd_cache,
drm,
api.unwrap_or(self.default_gfx_api.get()),
self.caps_thread.as_ref(),
)
}
pub fn add_output_scale(&self, scale: Scale) {
if self.scales.add(scale) {
self.output_scales_changed();
}
}
pub fn remove_output_scale(&self, scale: Scale) {
if self.scales.remove(&scale) {
self.output_scales_changed();
}
}
pub fn add_cursor_size(&self, size: u32) {
if self.cursor_sizes.add(size) {
self.cursor_sizes_changed();
}
}
pub fn remove_cursor_size(&self, size: u32) {
if self.cursor_sizes.remove(&size) {
self.cursor_sizes_changed();
}
}
fn output_scales_changed(&self) {
UpdateTextTexturesVisitor.visit_display(&self.root);
self.reload_cursors();
self.update_xwayland_wire_scale();
self.icons.update_sizes(self);
}
fn cursor_sizes_changed(&self) {
self.reload_cursors();
}
pub fn devices_enumerated(&self) {
if let Some(config) = self.config.get() {
config.devices_enumerated()
}
if self.render_ctx.is_none() {
for dev in self.drm_devs.lock().values() {
if let Ok(version) = dev.dev.version()
&& version.name.contains_str("nvidia")
{
continue;
}
if dev.dev.gfx_fast_ram_access() {
continue;
}
dev.make_render_device();
if self.render_ctx.is_some() {
break;
}
}
if self.render_ctx.is_none()
&& let Some(dev) = self.drm_devs.lock().values().next()
{
dev.make_render_device();
}
}
}
pub fn set_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
self.explicit_sync_supported.set(false);
self.render_ctx.set(ctx.clone());
self.render_ctx_version.fetch_add(1);
self.cursors.set(None);
self.drm_feedback.set(None);
self.icons.clear();
self.wait_for_syncobj
.set_ctx(ctx.as_ref().and_then(|c| c.syncobj_ctx().cloned()));
self.virtual_outputs.handle_render_ctx_change(self);
'handle_new_feedback: {
if let Some(ctx) = &ctx {
let feedback = match DrmFeedback::new(&self.drm_feedback_ids, &**ctx) {
Ok(fb) => fb,
Err(e) => {
log::error!("Could not create new DRM feedback: {}", ErrorFmt(e));
break 'handle_new_feedback;
}
};
for watcher in self.drm_feedback_consumers.lock().values() {
watcher.send_feedback(&feedback);
}
self.drm_feedback.set(Some(Rc::new(feedback)));
}
}
{
struct Walker;
impl NodeVisitorBase for Walker {
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
node.node_visit_children(self);
}
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
node.title_texture.take();
node.node_visit_children(self);
}
fn visit_output(&mut self, node: &Rc<OutputNode>) {
node.render_data.borrow_mut().titles.clear();
node.render_data.borrow_mut().status.take();
node.set_hardware_cursor(None);
node.node_visit_children(self);
}
fn visit_float(&mut self, node: &Rc<FloatNode>) {
node.node_visit_children(self);
}
fn visit_placeholder(&mut self, node: &Rc<PlaceholderNode>) {
node.textures.borrow_mut().clear();
node.node_visit_children(self);
}
}
Walker.visit_display(&self.root);
let mut updated_buffers = AHashMap::new();
for buffer in self.gfx_ctx_changed.iter() {
let had_buffer_texture = buffer.handle_gfx_context_change();
updated_buffers.insert(Rc::as_ptr(&buffer), had_buffer_texture);
}
for client in self.clients.clients.borrow_mut().values() {
for surface in client.data.objects.surfaces.lock().values() {
let had_shm_texture = surface.reset_shm_textures();
if let Some(buffer) = surface.buffer.get() {
let buf = &buffer.buffer.buf;
let had_buffer_texture = *updated_buffers.get(&Rc::as_ptr(buf)).unwrap();
if had_shm_texture || had_buffer_texture {
buf.update_texture_or_log(surface, true);
}
}
}
}
}
if ctx.is_some() {
self.reload_cursors();
UpdateTextTexturesVisitor.visit_display(&self.root);
}
for cursor_user_groups in self.cursor_user_groups.lock().values() {
cursor_user_groups.render_ctx_changed();
}
if let Some(ctx) = &ctx {
if let Some(ctx) = ctx.syncobj_ctx()
&& ctx.supports_async_wait()
{
self.explicit_sync_supported.set(true);
}
if !self.render_ctx_ever_initialized.replace(true)
&& let Some(config) = self.config.get()
{
config.graphics_initialized();
}
}
for watcher in self.render_ctx_watchers.lock().values() {
watcher.send_render_ctx(ctx.clone());
}
for client in self.clients.clients.borrow_mut().values() {
for sc in client.data.objects.ext_copy_sessions.lock().values() {
sc.stop();
}
}
self.expose_new_singletons();
}
fn reload_cursors(&self) {
if let Some(ctx) = self.render_ctx.get() {
let cursors = match ServerCursors::load(&ctx, self) {
Ok(c) => c.map(Rc::new),
Err(e) => {
log::error!("Could not load the cursors: {}", ErrorFmt(e));
None
}
};
self.cursors.set(cursors);
for cursor_user_group in self.cursor_user_groups.lock().values() {
cursor_user_group.reload_known_cursor();
}
}
}
pub fn add_global<T: WaylandGlobal>(&self, global: &Rc<T>) {
self.globals.add_global(self, global)
}

244
src/state/render_context.rs Normal file
View file

@ -0,0 +1,244 @@
use {
crate::{
cursor::ServerCursors,
drm_feedback::DrmFeedback,
gfx_api::{GfxApi, GfxContext, GfxError},
gfx_apis::create_gfx_context,
scale::Scale,
tree::{
ContainerNode, FloatNode, Node, NodeVisitorBase, OutputNode, PlaceholderNode,
WorkspaceNode,
},
utils::errorfmt::ErrorFmt,
video::drm::Drm,
},
ahash::AHashMap,
bstr::ByteSlice,
std::rc::Rc,
};
use super::State;
struct UpdateTextTexturesVisitor;
impl NodeVisitorBase for UpdateTextTexturesVisitor {
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
node.node_visit_children(self);
}
fn visit_output(&mut self, node: &Rc<OutputNode>) {
node.schedule_update_render_data();
node.node_visit_children(self);
}
fn visit_float(&mut self, node: &Rc<FloatNode>) {
node.node_visit_children(self);
}
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
node.title_texture.take();
node.node_visit_children(self);
}
fn visit_placeholder(&mut self, node: &Rc<PlaceholderNode>) {
node.textures.borrow_mut().clear();
node.schedule_update_texture();
node.node_visit_children(self);
}
}
impl State {
pub fn create_gfx_context(
&self,
drm: &Drm,
api: Option<GfxApi>,
) -> Result<Rc<dyn GfxContext>, GfxError> {
create_gfx_context(
&self.eng,
&self.ring,
&self.eventfd_cache,
drm,
api.unwrap_or(self.default_gfx_api.get()),
self.caps_thread.as_ref(),
)
}
pub fn add_output_scale(&self, scale: Scale) {
if self.scales.add(scale) {
self.output_scales_changed();
}
}
pub fn remove_output_scale(&self, scale: Scale) {
if self.scales.remove(&scale) {
self.output_scales_changed();
}
}
pub fn add_cursor_size(&self, size: u32) {
if self.cursor_sizes.add(size) {
self.cursor_sizes_changed();
}
}
pub fn remove_cursor_size(&self, size: u32) {
if self.cursor_sizes.remove(&size) {
self.cursor_sizes_changed();
}
}
fn output_scales_changed(&self) {
UpdateTextTexturesVisitor.visit_display(&self.root);
self.reload_cursors();
self.update_xwayland_wire_scale();
self.icons.update_sizes(self);
}
fn cursor_sizes_changed(&self) {
self.reload_cursors();
}
pub fn devices_enumerated(&self) {
if let Some(config) = self.config.get() {
config.devices_enumerated()
}
if self.render_ctx.is_none() {
for dev in self.drm_devs.lock().values() {
if let Ok(version) = dev.dev.version()
&& version.name.contains_str("nvidia")
{
continue;
}
if dev.dev.gfx_fast_ram_access() {
continue;
}
dev.make_render_device();
if self.render_ctx.is_some() {
break;
}
}
if self.render_ctx.is_none()
&& let Some(dev) = self.drm_devs.lock().values().next()
{
dev.make_render_device();
}
}
}
pub fn set_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
self.explicit_sync_supported.set(false);
self.render_ctx.set(ctx.clone());
self.render_ctx_version.fetch_add(1);
self.cursors.set(None);
self.drm_feedback.set(None);
self.icons.clear();
self.wait_for_syncobj
.set_ctx(ctx.as_ref().and_then(|c| c.syncobj_ctx().cloned()));
self.virtual_outputs.handle_render_ctx_change(self);
'handle_new_feedback: {
if let Some(ctx) = &ctx {
let feedback = match DrmFeedback::new(&self.drm_feedback_ids, &**ctx) {
Ok(fb) => fb,
Err(e) => {
log::error!("Could not create new DRM feedback: {}", ErrorFmt(e));
break 'handle_new_feedback;
}
};
for watcher in self.drm_feedback_consumers.lock().values() {
watcher.send_feedback(&feedback);
}
self.drm_feedback.set(Some(Rc::new(feedback)));
}
}
{
struct Walker;
impl NodeVisitorBase for Walker {
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
node.node_visit_children(self);
}
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
node.title_texture.take();
node.node_visit_children(self);
}
fn visit_output(&mut self, node: &Rc<OutputNode>) {
node.render_data.borrow_mut().titles.clear();
node.render_data.borrow_mut().status.take();
node.set_hardware_cursor(None);
node.node_visit_children(self);
}
fn visit_float(&mut self, node: &Rc<FloatNode>) {
node.node_visit_children(self);
}
fn visit_placeholder(&mut self, node: &Rc<PlaceholderNode>) {
node.textures.borrow_mut().clear();
node.node_visit_children(self);
}
}
Walker.visit_display(&self.root);
let mut updated_buffers = AHashMap::new();
for buffer in self.gfx_ctx_changed.iter() {
let had_buffer_texture = buffer.handle_gfx_context_change();
updated_buffers.insert(Rc::as_ptr(&buffer), had_buffer_texture);
}
for client in self.clients.clients.borrow_mut().values() {
for surface in client.data.objects.surfaces.lock().values() {
let had_shm_texture = surface.reset_shm_textures();
if let Some(buffer) = surface.buffer.get() {
let buf = &buffer.buffer.buf;
let had_buffer_texture = *updated_buffers.get(&Rc::as_ptr(buf)).unwrap();
if had_shm_texture || had_buffer_texture {
buf.update_texture_or_log(surface, true);
}
}
}
}
}
if ctx.is_some() {
self.reload_cursors();
UpdateTextTexturesVisitor.visit_display(&self.root);
}
for cursor_user_groups in self.cursor_user_groups.lock().values() {
cursor_user_groups.render_ctx_changed();
}
if let Some(ctx) = &ctx {
if let Some(ctx) = ctx.syncobj_ctx()
&& ctx.supports_async_wait()
{
self.explicit_sync_supported.set(true);
}
if !self.render_ctx_ever_initialized.replace(true)
&& let Some(config) = self.config.get()
{
config.graphics_initialized();
}
}
for watcher in self.render_ctx_watchers.lock().values() {
watcher.send_render_ctx(ctx.clone());
}
for client in self.clients.clients.borrow_mut().values() {
for sc in client.data.objects.ext_copy_sessions.lock().values() {
sc.stop();
}
}
self.expose_new_singletons();
}
fn reload_cursors(&self) {
if let Some(ctx) = self.render_ctx.get() {
let cursors = match ServerCursors::load(&ctx, self) {
Ok(c) => c.map(Rc::new),
Err(e) => {
log::error!("Could not load the cursors: {}", ErrorFmt(e));
None
}
};
self.cursors.set(cursors);
for cursor_user_group in self.cursor_user_groups.lock().values() {
cursor_user_group.reload_known_cursor();
}
}
}
}