state: split render context handling
This commit is contained in:
parent
c4655d4641
commit
16c402825f
2 changed files with 250 additions and 232 deletions
238
src/state.rs
238
src/state.rs
|
|
@ -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
244
src/state/render_context.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue