mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
* Extract CEF rendered UI into a separate process and crate * Review * Review * Review * Review * Remove necessary workarounds * Block on frame copy ack * Crop and resample frames correctly * Skip blank frames * Fix deps * Fix fmt * Fix clippy warning * Review * Fix todo
132 lines
3.6 KiB
Rust
132 lines
3.6 KiB
Rust
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
|
use std::sync::Arc;
|
|
|
|
use super::FrameSurface;
|
|
#[cfg(feature = "accelerated_paint")]
|
|
use super::plane;
|
|
use super::sink::FrameSink;
|
|
use crate::UiEvent;
|
|
use crate::events::EventQueue;
|
|
use crate::remote::messages::HostControlMessage;
|
|
|
|
pub(crate) enum PendingFrame {
|
|
Software {
|
|
seq: u64,
|
|
segment: u32,
|
|
width: u32,
|
|
height: u32,
|
|
},
|
|
#[cfg(all(target_os = "windows", feature = "accelerated_paint"))]
|
|
Accelerated(plane::WireFrame),
|
|
}
|
|
|
|
impl PendingFrame {
|
|
pub(crate) fn seq(&self) -> u64 {
|
|
match self {
|
|
PendingFrame::Software { seq, .. } => *seq,
|
|
#[cfg(all(target_os = "windows", feature = "accelerated_paint"))]
|
|
PendingFrame::Accelerated(frame) => frame.seq(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) struct SegmentTable(Vec<Option<IpcSharedMemory>>);
|
|
|
|
impl SegmentTable {
|
|
pub(crate) fn new() -> Self {
|
|
Self(Vec::new())
|
|
}
|
|
|
|
pub(crate) fn advertise(&mut self, index: u32, shm: IpcSharedMemory) {
|
|
let index = index as usize;
|
|
if self.0.len() <= index {
|
|
self.0.resize_with(index + 1, || None);
|
|
}
|
|
self.0[index] = Some(shm);
|
|
}
|
|
|
|
fn frame(&self, seq: u64, segment: u32, width: u32, height: u32) -> Option<&[u8]> {
|
|
let frame_bytes = width as usize * height as usize * 4;
|
|
match self.0.get(segment as usize).and_then(Option::as_ref) {
|
|
Some(shm) if shm.len() >= frame_bytes => Some(&shm[..frame_bytes]),
|
|
Some(shm) => {
|
|
tracing::error!("Frame {seq} needs {frame_bytes} bytes but segment {segment} holds {}", shm.len());
|
|
None
|
|
}
|
|
None => {
|
|
tracing::error!("Frame {seq} references unadvertised segment {segment}");
|
|
None
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) struct FrameConsumer {
|
|
surface: FrameSurface,
|
|
events: EventQueue,
|
|
sender: IpcSender<HostControlMessage>,
|
|
sink: Arc<FrameSink>,
|
|
}
|
|
|
|
impl FrameConsumer {
|
|
pub(crate) fn new(surface: FrameSurface, events: EventQueue, sender: IpcSender<HostControlMessage>) -> Self {
|
|
Self {
|
|
surface,
|
|
events,
|
|
sender,
|
|
sink: Arc::new(FrameSink::new()),
|
|
}
|
|
}
|
|
|
|
fn deliver(&self, seq: u64, install: impl FnOnce(&FrameSurface) -> Option<wgpu::Texture>) {
|
|
self.sink.deliver(&self.sender, seq, || match install(&self.surface) {
|
|
Some(texture) => {
|
|
self.events.send(UiEvent::Frame(texture));
|
|
true
|
|
}
|
|
None => false,
|
|
});
|
|
}
|
|
|
|
pub(crate) fn deliver_pending(&self, frame: PendingFrame, segments: &SegmentTable) {
|
|
match frame {
|
|
PendingFrame::Software { seq, segment, width, height } => {
|
|
self.deliver(seq, |surface| {
|
|
segments.frame(seq, segment, width, height).and_then(|pixels| surface.upload_buffer(pixels, width, height))
|
|
});
|
|
}
|
|
#[cfg(all(target_os = "windows", feature = "accelerated_paint"))]
|
|
PendingFrame::Accelerated(frame) => self.deliver_accelerated(frame),
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "accelerated_paint")]
|
|
pub(crate) fn deliver_accelerated(&self, frame: plane::WireFrame) {
|
|
let seq = frame.seq();
|
|
self.deliver(seq, |surface| frame.import(surface));
|
|
}
|
|
}
|
|
|
|
#[cfg(all(any(target_os = "linux", target_os = "macos"), feature = "accelerated_paint"))]
|
|
pub(crate) fn plane_receiver_loop(receiver: plane::PlaneReceiver, consumer: FrameConsumer) {
|
|
loop {
|
|
let mut frame = loop {
|
|
match receiver.recv_blocking() {
|
|
Ok(plane::RecvResult::Frame(frame)) => break frame,
|
|
Ok(plane::RecvResult::WouldBlock) => continue,
|
|
Ok(plane::RecvResult::Closed) => return,
|
|
Err(e) => {
|
|
tracing::error!("Accelerated frame plane failed: {e}");
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
// Drain any newer frames that have arrived since the blocking receive
|
|
while let Ok(plane::RecvResult::Frame(newer)) = receiver.try_recv() {
|
|
frame = newer;
|
|
}
|
|
consumer.deliver_accelerated(frame);
|
|
}
|
|
}
|