use crate::concurrent::executor::Executor;
use crate::gpu::renderer::Renderer;
use crate::gpu_data::RenderCommand;
use crate::options::{BuildOptions, RenderCommandListener};
use crate::scene::Scene;
use pathfinder_geometry::rect::RectF;
use pathfinder_gpu::Device;
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
const MAX_MESSAGES_IN_FLIGHT: usize = 1024;
pub struct SceneProxy {
sender: Sender<MainToWorkerMsg>,
}
impl SceneProxy {
pub fn new<E>(executor: E) -> SceneProxy where E: Executor + Send + 'static {
SceneProxy::from_scene(Scene::new(), executor)
}
pub fn from_scene<E>(scene: Scene, executor: E) -> SceneProxy
where E: Executor + Send + 'static {
let (main_to_worker_sender, main_to_worker_receiver) = mpsc::channel();
thread::spawn(move || scene_thread(scene, executor, main_to_worker_receiver));
SceneProxy { sender: main_to_worker_sender }
}
#[inline]
pub fn replace_scene(&self, new_scene: Scene) {
self.sender.send(MainToWorkerMsg::ReplaceScene(new_scene)).unwrap();
}
#[inline]
pub fn set_view_box(&self, new_view_box: RectF) {
self.sender.send(MainToWorkerMsg::SetViewBox(new_view_box)).unwrap();
}
#[inline]
pub fn build_with_listener(&self,
options: BuildOptions,
listener: Box<dyn RenderCommandListener>) {
self.sender.send(MainToWorkerMsg::Build(options, listener)).unwrap();
}
#[inline]
pub fn build_with_stream(&self, options: BuildOptions) -> RenderCommandStream {
let (sender, receiver) = mpsc::sync_channel(MAX_MESSAGES_IN_FLIGHT);
let listener = Box::new(move |command| drop(sender.send(command)));
self.build_with_listener(options, listener);
RenderCommandStream::new(receiver)
}
#[inline]
pub fn build_and_render<D>(&self, renderer: &mut Renderer<D>, build_options: BuildOptions)
where D: Device {
renderer.begin_scene();
for command in self.build_with_stream(build_options) {
renderer.render_command(&command);
}
renderer.end_scene();
}
#[inline]
pub fn copy_scene(&self) -> Scene {
let (sender, receiver) = mpsc::channel();
self.sender.send(MainToWorkerMsg::CopyScene(sender)).unwrap();
receiver.recv().unwrap()
}
}
fn scene_thread<E>(mut scene: Scene,
executor: E,
main_to_worker_receiver: Receiver<MainToWorkerMsg>)
where E: Executor {
while let Ok(msg) = main_to_worker_receiver.recv() {
match msg {
MainToWorkerMsg::ReplaceScene(new_scene) => scene = new_scene,
MainToWorkerMsg::CopyScene(sender) => sender.send(scene.clone()).unwrap(),
MainToWorkerMsg::SetViewBox(new_view_box) => scene.set_view_box(new_view_box),
MainToWorkerMsg::Build(options, listener) => scene.build(options, listener, &executor)
}
}
}
enum MainToWorkerMsg {
ReplaceScene(Scene),
CopyScene(Sender<Scene>),
SetViewBox(RectF),
Build(BuildOptions, Box<dyn RenderCommandListener>),
}
pub struct RenderCommandStream {
receiver: Receiver<RenderCommand>,
done: bool,
}
impl RenderCommandStream {
fn new(receiver: Receiver<RenderCommand>) -> RenderCommandStream {
RenderCommandStream { receiver, done: false }
}
}
impl Iterator for RenderCommandStream {
type Item = RenderCommand;
#[inline]
fn next(&mut self) -> Option<RenderCommand> {
if self.done {
None
} else {
let command = self.receiver.recv().unwrap();
if let RenderCommand::Finish { .. } = command {
self.done = true;
}
Some(command)
}
}
}