desktop: Made WinitAsyncExecutor not depend on winit
This commit is contained in:
parent
a188962306
commit
3529a2d12d
|
@ -1,6 +1,5 @@
|
||||||
//! Async executor
|
//! Async executor
|
||||||
|
|
||||||
use crate::custom_event::RuffleEvent;
|
|
||||||
use crate::task::Task;
|
use crate::task::Task;
|
||||||
use async_channel::{unbounded, Receiver, Sender};
|
use async_channel::{unbounded, Receiver, Sender};
|
||||||
use ruffle_core::backend::navigator::OwnedFuture;
|
use ruffle_core::backend::navigator::OwnedFuture;
|
||||||
|
@ -9,7 +8,10 @@ use slotmap::{new_key_type, SlotMap};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak};
|
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak};
|
||||||
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
||||||
use winit::event_loop::EventLoopProxy;
|
|
||||||
|
pub trait PollRequester: Clone {
|
||||||
|
fn request_poll(&self);
|
||||||
|
}
|
||||||
|
|
||||||
new_key_type! {
|
new_key_type! {
|
||||||
// This is what we would call `TaskHandle` everywhere else, but that name is already taken.
|
// This is what we would call `TaskHandle` everywhere else, but that name is already taken.
|
||||||
|
@ -21,7 +23,7 @@ new_key_type! {
|
||||||
/// All task handles are identical and interchangeable. Cloning a `TaskHandle`
|
/// All task handles are identical and interchangeable. Cloning a `TaskHandle`
|
||||||
/// does not clone the underlying task.
|
/// does not clone the underlying task.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TaskHandle {
|
struct TaskHandle<R: PollRequester> {
|
||||||
/// The arena handle for a given task.
|
/// The arena handle for a given task.
|
||||||
handle: TaskKey,
|
handle: TaskKey,
|
||||||
|
|
||||||
|
@ -29,12 +31,12 @@ struct TaskHandle {
|
||||||
///
|
///
|
||||||
/// Weak reference ensures that the executor along
|
/// Weak reference ensures that the executor along
|
||||||
/// with its tasks is dropped properly.
|
/// with its tasks is dropped properly.
|
||||||
executor: Weak<WinitAsyncExecutor>,
|
executor: Weak<WinitAsyncExecutor<R>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskHandle {
|
impl<R: PollRequester> TaskHandle<R> {
|
||||||
/// Construct a handle to a given task.
|
/// Construct a handle to a given task.
|
||||||
fn for_task(task: TaskKey, executor: Weak<WinitAsyncExecutor>) -> Self {
|
fn for_task(task: TaskKey, executor: Weak<WinitAsyncExecutor<R>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
handle: task,
|
handle: task,
|
||||||
executor,
|
executor,
|
||||||
|
@ -97,28 +99,29 @@ impl TaskHandle {
|
||||||
///
|
///
|
||||||
/// This is part of the vtable methods of our `RawWaker` impl.
|
/// This is part of the vtable methods of our `RawWaker` impl.
|
||||||
unsafe fn clone_as_ptr(almost_self: *const ()) -> RawWaker {
|
unsafe fn clone_as_ptr(almost_self: *const ()) -> RawWaker {
|
||||||
let selfish = TaskHandle::from_const_ptr(almost_self).expect("non-null context ptr");
|
let selfish = TaskHandle::<R>::from_const_ptr(almost_self).expect("non-null context ptr");
|
||||||
|
|
||||||
selfish.raw_waker()
|
selfish.raw_waker()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wake the given task, then drop it.
|
/// Wake the given task, then drop it.
|
||||||
unsafe fn wake_as_ptr(almost_self: *const ()) {
|
unsafe fn wake_as_ptr(almost_self: *const ()) {
|
||||||
let selfish = TaskHandle::box_from_const_ptr(almost_self).expect("non-null context ptr");
|
let selfish =
|
||||||
|
TaskHandle::<R>::box_from_const_ptr(almost_self).expect("non-null context ptr");
|
||||||
|
|
||||||
selfish.wake();
|
selfish.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wake the given task.
|
/// Wake the given task.
|
||||||
unsafe fn wake_by_ref_as_ptr(almost_self: *const ()) {
|
unsafe fn wake_by_ref_as_ptr(almost_self: *const ()) {
|
||||||
let selfish = TaskHandle::from_const_ptr(almost_self).expect("non-null context ptr");
|
let selfish = TaskHandle::<R>::from_const_ptr(almost_self).expect("non-null context ptr");
|
||||||
|
|
||||||
selfish.wake();
|
selfish.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drop the async executor.
|
/// Drop the async executor.
|
||||||
unsafe fn drop_as_ptr(almost_self: *const ()) {
|
unsafe fn drop_as_ptr(almost_self: *const ()) {
|
||||||
let _ = TaskHandle::box_from_const_ptr(almost_self).expect("non-null context ptr");
|
let _ = TaskHandle::<R>::box_from_const_ptr(almost_self).expect("non-null context ptr");
|
||||||
}
|
}
|
||||||
|
|
||||||
const VTABLE: RawWakerVTable = RawWakerVTable::new(
|
const VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||||
|
@ -129,7 +132,7 @@ impl TaskHandle {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WinitAsyncExecutor {
|
pub struct WinitAsyncExecutor<R: PollRequester> {
|
||||||
/// List of all spawned tasks.
|
/// List of all spawned tasks.
|
||||||
task_queue: RwLock<SlotMap<TaskKey, Mutex<Task>>>,
|
task_queue: RwLock<SlotMap<TaskKey, Mutex<Task>>>,
|
||||||
|
|
||||||
|
@ -140,29 +143,29 @@ pub struct WinitAsyncExecutor {
|
||||||
self_ref: Weak<Self>,
|
self_ref: Weak<Self>,
|
||||||
|
|
||||||
/// Event injector for the main thread event loop.
|
/// Event injector for the main thread event loop.
|
||||||
event_loop: EventLoopProxy<RuffleEvent>,
|
poll_requester: R,
|
||||||
|
|
||||||
/// Whether we have already queued a `TaskPoll` event.
|
/// Whether we have already queued a `TaskPoll` event.
|
||||||
waiting_for_poll: AtomicBool,
|
waiting_for_poll: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WinitAsyncExecutor {
|
impl<R: PollRequester> WinitAsyncExecutor<R> {
|
||||||
/// Construct a new executor for the winit event loop.
|
/// Construct a new executor for the winit event loop.
|
||||||
///
|
///
|
||||||
/// This function returns the executor itself, plus the `Sender` necessary
|
/// This function returns the executor itself, plus the `Sender` necessary
|
||||||
/// to spawn new tasks.
|
/// to spawn new tasks.
|
||||||
pub fn new(event_loop: EventLoopProxy<RuffleEvent>) -> (Arc<Self>, WinitFutureSpawner) {
|
pub fn new(poll_requester: R) -> (Arc<Self>, WinitFutureSpawner<R>) {
|
||||||
let (send, recv) = unbounded();
|
let (send, recv) = unbounded();
|
||||||
let new_self = Arc::new_cyclic(|self_ref| Self {
|
let new_self = Arc::new_cyclic(|self_ref| Self {
|
||||||
task_queue: RwLock::new(SlotMap::with_key()),
|
task_queue: RwLock::new(SlotMap::with_key()),
|
||||||
channel: recv,
|
channel: recv,
|
||||||
self_ref: self_ref.clone(),
|
self_ref: self_ref.clone(),
|
||||||
event_loop: event_loop.clone(),
|
poll_requester: poll_requester.clone(),
|
||||||
waiting_for_poll: AtomicBool::new(false),
|
waiting_for_poll: AtomicBool::new(false),
|
||||||
});
|
});
|
||||||
(
|
(
|
||||||
new_self,
|
new_self,
|
||||||
WinitFutureSpawner::send_and_poll(send, event_loop),
|
WinitFutureSpawner::send_and_poll(send, poll_requester),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,9 +207,7 @@ impl WinitAsyncExecutor {
|
||||||
if !task.is_completed() {
|
if !task.is_completed() {
|
||||||
task.set_ready();
|
task.set_ready();
|
||||||
if !self.waiting_for_poll.swap(true, Ordering::SeqCst) {
|
if !self.waiting_for_poll.swap(true, Ordering::SeqCst) {
|
||||||
if self.event_loop.send_event(RuffleEvent::TaskPoll).is_err() {
|
self.poll_requester.request_poll();
|
||||||
tracing::warn!("A task was queued on an event loop that has already ended. It will not be polled.");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("Double polling");
|
tracing::info!("Double polling");
|
||||||
}
|
}
|
||||||
|
@ -247,32 +248,28 @@ pub trait FutureSpawner {
|
||||||
fn spawn(&self, future: OwnedFuture<(), Error>);
|
fn spawn(&self, future: OwnedFuture<(), Error>);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WinitFutureSpawner {
|
pub struct WinitFutureSpawner<R: PollRequester> {
|
||||||
channel: Sender<OwnedFuture<(), Error>>,
|
channel: Sender<OwnedFuture<(), Error>>,
|
||||||
event_loop: EventLoopProxy<RuffleEvent>,
|
poll_requester: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WinitFutureSpawner {
|
impl<R: PollRequester> WinitFutureSpawner<R> {
|
||||||
pub fn send_and_poll(
|
pub fn send_and_poll(
|
||||||
channel: Sender<OwnedFuture<(), Error>>,
|
channel: Sender<OwnedFuture<(), Error>>,
|
||||||
event_loop: EventLoopProxy<RuffleEvent>,
|
request_poll: R,
|
||||||
) -> WinitFutureSpawner {
|
) -> WinitFutureSpawner<R> {
|
||||||
WinitFutureSpawner {
|
WinitFutureSpawner {
|
||||||
channel,
|
channel,
|
||||||
event_loop,
|
poll_requester: request_poll,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FutureSpawner for WinitFutureSpawner {
|
impl<R: PollRequester> FutureSpawner for WinitFutureSpawner<R> {
|
||||||
fn spawn(&self, future: OwnedFuture<(), Error>) {
|
fn spawn(&self, future: OwnedFuture<(), Error>) {
|
||||||
self.channel
|
self.channel
|
||||||
.send_blocking(future)
|
.send_blocking(future)
|
||||||
.expect("working channel send");
|
.expect("working channel send");
|
||||||
if self.event_loop.send_event(RuffleEvent::TaskPoll).is_err() {
|
self.poll_requester.request_poll()
|
||||||
tracing::warn!(
|
|
||||||
"A task was queued on an event loop that has already ended. It will not be polled."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::backends::{
|
||||||
ExternalNavigatorBackend,
|
ExternalNavigatorBackend,
|
||||||
};
|
};
|
||||||
use crate::custom_event::RuffleEvent;
|
use crate::custom_event::RuffleEvent;
|
||||||
use crate::executor::WinitAsyncExecutor;
|
use crate::executor::{PollRequester, WinitAsyncExecutor};
|
||||||
use crate::gui::MovieView;
|
use crate::gui::MovieView;
|
||||||
use crate::preferences::GlobalPreferences;
|
use crate::preferences::GlobalPreferences;
|
||||||
use crate::{CALLSTACK, RENDER_INFO, SWF_INFO};
|
use crate::{CALLSTACK, RENDER_INFO, SWF_INFO};
|
||||||
|
@ -186,11 +186,22 @@ impl PlayingContent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct WinitWaker(EventLoopProxy<RuffleEvent>);
|
||||||
|
|
||||||
|
impl PollRequester for WinitWaker {
|
||||||
|
fn request_poll(&self) {
|
||||||
|
if self.0.send_event(RuffleEvent::TaskPoll).is_err() {
|
||||||
|
tracing::error!("Couldn't request poll - event loop is closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a current Player and any associated state with that player,
|
/// Represents a current Player and any associated state with that player,
|
||||||
/// which may be lost when this Player is closed (dropped)
|
/// which may be lost when this Player is closed (dropped)
|
||||||
struct ActivePlayer {
|
struct ActivePlayer {
|
||||||
player: Arc<Mutex<Player>>,
|
player: Arc<Mutex<Player>>,
|
||||||
executor: Arc<WinitAsyncExecutor>,
|
executor: Arc<WinitAsyncExecutor<WinitWaker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActivePlayer {
|
impl ActivePlayer {
|
||||||
|
@ -244,7 +255,7 @@ impl ActivePlayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (executor, future_spawner) = WinitAsyncExecutor::new(event_loop.clone());
|
let (executor, future_spawner) = WinitAsyncExecutor::new(WinitWaker(event_loop.clone()));
|
||||||
let movie_url = content.initial_swf_url().clone();
|
let movie_url = content.initial_swf_url().clone();
|
||||||
let readable_name = content.name();
|
let readable_name = content.name();
|
||||||
let navigator = ExternalNavigatorBackend::new(
|
let navigator = ExternalNavigatorBackend::new(
|
||||||
|
|
Loading…
Reference in New Issue