implements PLN-0118
This commit is contained in:
parent
cfb5b1ac89
commit
6b5b27d068
@ -12,6 +12,6 @@ pub use services::process;
|
|||||||
pub use services::task;
|
pub use services::task;
|
||||||
pub use services::vm_runtime::{
|
pub use services::vm_runtime::{
|
||||||
RenderWorkerConfig, RenderWorkerController, RenderWorkerHandoff, RenderWorkerHandoffWait,
|
RenderWorkerConfig, RenderWorkerController, RenderWorkerHandoff, RenderWorkerHandoffWait,
|
||||||
VirtualMachineRuntime,
|
RenderWorkerOwnership, VirtualMachineRuntime,
|
||||||
};
|
};
|
||||||
pub use services::windows;
|
pub use services::windows;
|
||||||
|
|||||||
@ -27,6 +27,7 @@ impl VirtualMachineRuntime {
|
|||||||
render_capabilities: RenderRuntimeCapabilities::default(),
|
render_capabilities: RenderRuntimeCapabilities::default(),
|
||||||
render_manager: RenderManager::new(AppMode::Game),
|
render_manager: RenderManager::new(AppMode::Game),
|
||||||
render_worker_handoff: Arc::new(RenderWorkerHandoff::default()),
|
render_worker_handoff: Arc::new(RenderWorkerHandoff::default()),
|
||||||
|
render_worker_ownership: RenderWorkerOwnership::default(),
|
||||||
render_worker_controller: None,
|
render_worker_controller: None,
|
||||||
gfx2d_commands: Vec::new(),
|
gfx2d_commands: Vec::new(),
|
||||||
gfxui_commands: Vec::new(),
|
gfxui_commands: Vec::new(),
|
||||||
@ -129,6 +130,8 @@ impl VirtualMachineRuntime {
|
|||||||
self.render_manager = RenderManager::new(AppMode::Game);
|
self.render_manager = RenderManager::new(AppMode::Game);
|
||||||
let _ = self.stop_render_worker();
|
let _ = self.stop_render_worker();
|
||||||
self.render_worker_handoff = Arc::new(RenderWorkerHandoff::default());
|
self.render_worker_handoff = Arc::new(RenderWorkerHandoff::default());
|
||||||
|
self.render_worker_ownership =
|
||||||
|
RenderWorkerOwnership::new(self.render_manager.active_ownership());
|
||||||
self.gfx2d_commands.clear();
|
self.gfx2d_commands.clear();
|
||||||
self.gfxui_commands.clear();
|
self.gfxui_commands.clear();
|
||||||
self.logs_written_this_frame.clear();
|
self.logs_written_this_frame.clear();
|
||||||
@ -159,9 +162,11 @@ impl VirtualMachineRuntime {
|
|||||||
{
|
{
|
||||||
let _ = self.stop_render_worker();
|
let _ = self.stop_render_worker();
|
||||||
self.render_worker_handoff = Arc::new(RenderWorkerHandoff::default());
|
self.render_worker_handoff = Arc::new(RenderWorkerHandoff::default());
|
||||||
|
self.render_worker_ownership.set(self.render_manager.active_ownership());
|
||||||
self.render_worker_controller = Some(RenderWorkerController::start(
|
self.render_worker_controller = Some(RenderWorkerController::start(
|
||||||
config,
|
config,
|
||||||
Arc::clone(&self.render_worker_handoff),
|
Arc::clone(&self.render_worker_handoff),
|
||||||
|
self.render_worker_ownership.clone(),
|
||||||
backend,
|
backend,
|
||||||
sink,
|
sink,
|
||||||
));
|
));
|
||||||
@ -184,6 +189,10 @@ impl VirtualMachineRuntime {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sync_render_worker_ownership(&self) {
|
||||||
|
self.render_worker_ownership.set(self.render_manager.active_ownership());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn initialize_vm(
|
pub fn initialize_vm(
|
||||||
&mut self,
|
&mut self,
|
||||||
log_service: &mut LogService,
|
log_service: &mut LogService,
|
||||||
|
|||||||
@ -21,7 +21,7 @@ use prometeu_hal::telemetry::{AtomicTelemetry, CertificationConfig, Certifier};
|
|||||||
use prometeu_hal::{Gfx2dCommand, GfxUiCommand};
|
use prometeu_hal::{Gfx2dCommand, GfxUiCommand};
|
||||||
use prometeu_vm::VirtualMachine;
|
use prometeu_vm::VirtualMachine;
|
||||||
pub use render_manager::{RenderManager, RenderRuntimeCapabilities};
|
pub use render_manager::{RenderManager, RenderRuntimeCapabilities};
|
||||||
pub use render_worker::{RenderWorkerConfig, RenderWorkerController};
|
pub use render_worker::{RenderWorkerConfig, RenderWorkerController, RenderWorkerOwnership};
|
||||||
pub use render_worker_handoff::{RenderWorkerHandoff, RenderWorkerHandoffWait};
|
pub use render_worker_handoff::{RenderWorkerHandoff, RenderWorkerHandoffWait};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -42,6 +42,7 @@ pub struct VirtualMachineRuntime {
|
|||||||
pub render_capabilities: RenderRuntimeCapabilities,
|
pub render_capabilities: RenderRuntimeCapabilities,
|
||||||
pub render_manager: RenderManager,
|
pub render_manager: RenderManager,
|
||||||
pub render_worker_handoff: Arc<RenderWorkerHandoff>,
|
pub render_worker_handoff: Arc<RenderWorkerHandoff>,
|
||||||
|
pub render_worker_ownership: RenderWorkerOwnership,
|
||||||
pub render_worker_controller: Option<RenderWorkerController>,
|
pub render_worker_controller: Option<RenderWorkerController>,
|
||||||
pub gfx2d_commands: Vec<Gfx2dCommand>,
|
pub gfx2d_commands: Vec<Gfx2dCommand>,
|
||||||
pub gfxui_commands: Vec<GfxUiCommand>,
|
pub gfxui_commands: Vec<GfxUiCommand>,
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
use crate::services::vm_runtime::{RenderWorkerHandoff, RenderWorkerHandoffWait};
|
use crate::services::vm_runtime::{RenderWorkerHandoff, RenderWorkerHandoffWait};
|
||||||
|
use prometeu_hal::app_mode::AppMode;
|
||||||
use prometeu_hal::{
|
use prometeu_hal::{
|
||||||
FrameId, RenderWorkerBackend, RenderWorkerError, RenderWorkerFrameSink, RenderWorkerTelemetry,
|
FrameId, OwnedRgba8888Frame, RenderOwnership, RenderWorkerBackend, RenderWorkerError,
|
||||||
|
RenderWorkerFrameSink, RenderWorkerTelemetry,
|
||||||
};
|
};
|
||||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||||
use std::sync::mpsc::{self, Receiver, RecvTimeoutError};
|
use std::sync::mpsc::{self, Receiver, RecvTimeoutError};
|
||||||
@ -23,12 +25,39 @@ impl Default for RenderWorkerConfig {
|
|||||||
struct RenderWorkerState {
|
struct RenderWorkerState {
|
||||||
telemetry: RenderWorkerTelemetry,
|
telemetry: RenderWorkerTelemetry,
|
||||||
last_error: Option<RenderWorkerError>,
|
last_error: Option<RenderWorkerError>,
|
||||||
|
latest_published_frame: Option<OwnedRgba8888Frame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct RenderWorkerOwnership {
|
||||||
|
active: Arc<Mutex<RenderOwnership>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RenderWorkerOwnership {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(RenderOwnership::new(0, AppMode::Game, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderWorkerOwnership {
|
||||||
|
pub fn new(active: RenderOwnership) -> Self {
|
||||||
|
Self { active: Arc::new(Mutex::new(active)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn snapshot(&self) -> RenderOwnership {
|
||||||
|
*self.active.lock().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&self, active: RenderOwnership) {
|
||||||
|
*self.active.lock().unwrap() = active;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RenderWorkerController {
|
pub struct RenderWorkerController {
|
||||||
config: RenderWorkerConfig,
|
config: RenderWorkerConfig,
|
||||||
handoff: Arc<RenderWorkerHandoff>,
|
handoff: Arc<RenderWorkerHandoff>,
|
||||||
|
ownership: RenderWorkerOwnership,
|
||||||
state: Arc<Mutex<RenderWorkerState>>,
|
state: Arc<Mutex<RenderWorkerState>>,
|
||||||
handle: Option<JoinHandle<()>>,
|
handle: Option<JoinHandle<()>>,
|
||||||
done_rx: Receiver<Result<(), RenderWorkerError>>,
|
done_rx: Receiver<Result<(), RenderWorkerError>>,
|
||||||
@ -38,6 +67,7 @@ impl RenderWorkerController {
|
|||||||
pub fn start<B, S>(
|
pub fn start<B, S>(
|
||||||
config: RenderWorkerConfig,
|
config: RenderWorkerConfig,
|
||||||
handoff: Arc<RenderWorkerHandoff>,
|
handoff: Arc<RenderWorkerHandoff>,
|
||||||
|
ownership: RenderWorkerOwnership,
|
||||||
backend: B,
|
backend: B,
|
||||||
sink: S,
|
sink: S,
|
||||||
) -> Self
|
) -> Self
|
||||||
@ -47,13 +77,14 @@ impl RenderWorkerController {
|
|||||||
{
|
{
|
||||||
let state = Arc::new(Mutex::new(RenderWorkerState::default()));
|
let state = Arc::new(Mutex::new(RenderWorkerState::default()));
|
||||||
let worker_handoff = Arc::clone(&handoff);
|
let worker_handoff = Arc::clone(&handoff);
|
||||||
|
let worker_ownership = ownership.clone();
|
||||||
let worker_state = Arc::clone(&state);
|
let worker_state = Arc::clone(&state);
|
||||||
let panic_state = Arc::clone(&state);
|
let panic_state = Arc::clone(&state);
|
||||||
let (done_tx, done_rx) = mpsc::channel();
|
let (done_tx, done_rx) = mpsc::channel();
|
||||||
|
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
let result = catch_unwind(AssertUnwindSafe(|| {
|
let result = catch_unwind(AssertUnwindSafe(|| {
|
||||||
run_worker_loop(worker_handoff, worker_state, backend, sink);
|
run_worker_loop(worker_handoff, worker_ownership, worker_state, backend, sink);
|
||||||
}))
|
}))
|
||||||
.map_err(|_| RenderWorkerError::WorkerPanic);
|
.map_err(|_| RenderWorkerError::WorkerPanic);
|
||||||
if let Err(error) = result {
|
if let Err(error) = result {
|
||||||
@ -62,7 +93,7 @@ impl RenderWorkerController {
|
|||||||
let _ = done_tx.send(result);
|
let _ = done_tx.send(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
Self { config, handoff, state, handle: Some(handle), done_rx }
|
Self { config, handoff, ownership, state, handle: Some(handle), done_rx }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(&mut self) -> Result<(), RenderWorkerError> {
|
pub fn stop(&mut self) -> Result<(), RenderWorkerError> {
|
||||||
@ -95,8 +126,12 @@ impl RenderWorkerController {
|
|||||||
telemetry.render_failures = state.telemetry.render_failures;
|
telemetry.render_failures = state.telemetry.render_failures;
|
||||||
telemetry.publish_failures = state.telemetry.publish_failures;
|
telemetry.publish_failures = state.telemetry.publish_failures;
|
||||||
telemetry.present_failures = state.telemetry.present_failures;
|
telemetry.present_failures = state.telemetry.present_failures;
|
||||||
|
telemetry.stale_submission_discards = state.telemetry.stale_submission_discards;
|
||||||
|
telemetry.repeated_frames = state.telemetry.repeated_frames;
|
||||||
telemetry.shutdown_timeouts = state.telemetry.shutdown_timeouts;
|
telemetry.shutdown_timeouts = state.telemetry.shutdown_timeouts;
|
||||||
telemetry.worker_panics = state.telemetry.worker_panics;
|
telemetry.worker_panics = state.telemetry.worker_panics;
|
||||||
|
telemetry.last_presented_frame_id = state.telemetry.last_presented_frame_id;
|
||||||
|
telemetry.last_dropped_frame_id = state.telemetry.last_dropped_frame_id;
|
||||||
telemetry.last_published_frame_id = state.telemetry.last_published_frame_id;
|
telemetry.last_published_frame_id = state.telemetry.last_published_frame_id;
|
||||||
telemetry.last_error_frame_id = state.telemetry.last_error_frame_id;
|
telemetry.last_error_frame_id = state.telemetry.last_error_frame_id;
|
||||||
telemetry
|
telemetry
|
||||||
@ -105,6 +140,21 @@ impl RenderWorkerController {
|
|||||||
pub fn last_error(&self) -> Option<RenderWorkerError> {
|
pub fn last_error(&self) -> Option<RenderWorkerError> {
|
||||||
self.state.lock().unwrap().last_error
|
self.state.lock().unwrap().last_error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn active_ownership(&self) -> RenderOwnership {
|
||||||
|
self.ownership.snapshot()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn latest_published_frame(&self) -> Option<OwnedRgba8888Frame> {
|
||||||
|
self.state.lock().unwrap().latest_published_frame.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repeat_latest_frame(&self) -> Option<OwnedRgba8888Frame> {
|
||||||
|
let mut state = self.state.lock().unwrap();
|
||||||
|
let frame = state.latest_published_frame.clone()?;
|
||||||
|
state.telemetry.record_repeated_frame(frame.frame_id.get());
|
||||||
|
Some(frame)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for RenderWorkerController {
|
impl Drop for RenderWorkerController {
|
||||||
@ -117,6 +167,7 @@ impl Drop for RenderWorkerController {
|
|||||||
|
|
||||||
fn run_worker_loop<B, S>(
|
fn run_worker_loop<B, S>(
|
||||||
handoff: Arc<RenderWorkerHandoff>,
|
handoff: Arc<RenderWorkerHandoff>,
|
||||||
|
ownership: RenderWorkerOwnership,
|
||||||
state: Arc<Mutex<RenderWorkerState>>,
|
state: Arc<Mutex<RenderWorkerState>>,
|
||||||
backend: B,
|
backend: B,
|
||||||
sink: S,
|
sink: S,
|
||||||
@ -141,17 +192,28 @@ fn run_worker_loop<B, S>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let publish_result = catch_unwind(AssertUnwindSafe(|| sink.publish(frame)))
|
if frame.ownership != ownership.snapshot() {
|
||||||
|
record_stale_discard(&state, frame_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let publish_result = catch_unwind(AssertUnwindSafe(|| sink.publish(frame.clone())))
|
||||||
.map_err(|_| RenderWorkerError::WorkerPanic);
|
.map_err(|_| RenderWorkerError::WorkerPanic);
|
||||||
match publish_result {
|
match publish_result {
|
||||||
Ok(Ok(())) => record_published(&state, frame_id),
|
Ok(Ok(())) => record_published(&state, frame),
|
||||||
Ok(Err(error)) | Err(error) => record_error(&state, error, frame_id),
|
Ok(Err(error)) | Err(error) => record_error(&state, error, frame_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_published(state: &Arc<Mutex<RenderWorkerState>>, frame_id: FrameId) {
|
fn record_published(state: &Arc<Mutex<RenderWorkerState>>, frame: OwnedRgba8888Frame) {
|
||||||
state.lock().unwrap().telemetry.record_published(frame_id.get());
|
let mut state = state.lock().unwrap();
|
||||||
|
state.telemetry.record_published(frame.frame_id.get());
|
||||||
|
state.latest_published_frame = Some(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_stale_discard(state: &Arc<Mutex<RenderWorkerState>>, frame_id: FrameId) {
|
||||||
|
state.lock().unwrap().telemetry.record_stale_submission_discarded(frame_id.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_error(
|
fn record_error(
|
||||||
@ -171,7 +233,10 @@ mod tests {
|
|||||||
use crate::services::vm_runtime::render_worker_test_harness::{
|
use crate::services::vm_runtime::render_worker_test_harness::{
|
||||||
FakeRenderBackend, RenderGate, game_submission,
|
FakeRenderBackend, RenderGate, game_submission,
|
||||||
};
|
};
|
||||||
use prometeu_hal::{FrameId, Game2DFramePacket, OwnedRgba8888Frame, RenderSubmission};
|
use prometeu_hal::app_mode::AppMode;
|
||||||
|
use prometeu_hal::{
|
||||||
|
FrameId, Game2DFramePacket, OwnedRgba8888Frame, RenderOwnership, RenderSubmission,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct SharedFakeBackend(Arc<FakeRenderBackend>);
|
struct SharedFakeBackend(Arc<FakeRenderBackend>);
|
||||||
@ -220,6 +285,7 @@ mod tests {
|
|||||||
let mut controller = RenderWorkerController::start(
|
let mut controller = RenderWorkerController::start(
|
||||||
RenderWorkerConfig::default(),
|
RenderWorkerConfig::default(),
|
||||||
Arc::clone(&handoff),
|
Arc::clone(&handoff),
|
||||||
|
RenderWorkerOwnership::default(),
|
||||||
SharedFakeBackend(Arc::clone(&backend)),
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
SharedFakeBackend(backend),
|
SharedFakeBackend(backend),
|
||||||
);
|
);
|
||||||
@ -235,6 +301,7 @@ mod tests {
|
|||||||
let mut controller = RenderWorkerController::start(
|
let mut controller = RenderWorkerController::start(
|
||||||
RenderWorkerConfig::default(),
|
RenderWorkerConfig::default(),
|
||||||
Arc::clone(&handoff),
|
Arc::clone(&handoff),
|
||||||
|
RenderWorkerOwnership::new(RenderOwnership::new(1, AppMode::Game, 1)),
|
||||||
SharedFakeBackend(Arc::clone(&backend)),
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
SharedFakeBackend(Arc::clone(&backend)),
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
);
|
);
|
||||||
@ -256,6 +323,7 @@ mod tests {
|
|||||||
let mut controller = RenderWorkerController::start(
|
let mut controller = RenderWorkerController::start(
|
||||||
RenderWorkerConfig { shutdown_timeout: Duration::from_millis(1) },
|
RenderWorkerConfig { shutdown_timeout: Duration::from_millis(1) },
|
||||||
Arc::clone(&handoff),
|
Arc::clone(&handoff),
|
||||||
|
RenderWorkerOwnership::default(),
|
||||||
SharedFakeBackend(Arc::clone(&backend)),
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
SharedFakeBackend(Arc::clone(&backend)),
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
);
|
);
|
||||||
@ -278,6 +346,7 @@ mod tests {
|
|||||||
let mut controller = RenderWorkerController::start(
|
let mut controller = RenderWorkerController::start(
|
||||||
RenderWorkerConfig::default(),
|
RenderWorkerConfig::default(),
|
||||||
Arc::clone(&handoff),
|
Arc::clone(&handoff),
|
||||||
|
RenderWorkerOwnership::default(),
|
||||||
PanickingBackend,
|
PanickingBackend,
|
||||||
NoopSink,
|
NoopSink,
|
||||||
);
|
);
|
||||||
@ -290,6 +359,53 @@ mod tests {
|
|||||||
assert_eq!(controller.telemetry().last_error_frame_id, 13);
|
assert_eq!(controller.telemetry().last_error_frame_id, 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_worker_controller_discards_stale_frame_before_publish() {
|
||||||
|
let handoff = Arc::new(RenderWorkerHandoff::default());
|
||||||
|
let gate = RenderGate::default();
|
||||||
|
let backend = Arc::new(FakeRenderBackend::with_gate(gate.clone()));
|
||||||
|
let ownership = RenderWorkerOwnership::new(RenderOwnership::new(1, AppMode::Game, 1));
|
||||||
|
let mut controller = RenderWorkerController::start(
|
||||||
|
RenderWorkerConfig::default(),
|
||||||
|
Arc::clone(&handoff),
|
||||||
|
ownership.clone(),
|
||||||
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
|
);
|
||||||
|
|
||||||
|
handoff.publish(game_submission(21, 1, 1));
|
||||||
|
gate.wait_for_entries(1);
|
||||||
|
ownership.set(RenderOwnership::new(2, AppMode::Game, 1));
|
||||||
|
gate.release_one();
|
||||||
|
|
||||||
|
assert_eq!(controller.stop(), Ok(()));
|
||||||
|
assert!(backend.published_frames().is_empty());
|
||||||
|
assert_eq!(controller.telemetry().stale_submission_discards, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_worker_controller_repeats_latest_published_frame_without_rendering() {
|
||||||
|
let handoff = Arc::new(RenderWorkerHandoff::default());
|
||||||
|
let backend = Arc::new(FakeRenderBackend::default());
|
||||||
|
let mut controller = RenderWorkerController::start(
|
||||||
|
RenderWorkerConfig::default(),
|
||||||
|
Arc::clone(&handoff),
|
||||||
|
RenderWorkerOwnership::new(RenderOwnership::new(1, AppMode::Game, 1)),
|
||||||
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
|
SharedFakeBackend(Arc::clone(&backend)),
|
||||||
|
);
|
||||||
|
|
||||||
|
handoff.publish(game_submission(22, 1, 1));
|
||||||
|
assert_eq!(controller.stop(), Ok(()));
|
||||||
|
|
||||||
|
let latest = controller.latest_published_frame().expect("latest frame");
|
||||||
|
let repeated = controller.repeat_latest_frame().expect("repeated frame");
|
||||||
|
|
||||||
|
assert_eq!(latest, repeated);
|
||||||
|
assert_eq!(backend.published_frames().len(), 1);
|
||||||
|
assert_eq!(controller.telemetry().repeated_frames, 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runtime_publishes_game_submissions_to_worker_without_waiting_for_render() {
|
fn runtime_publishes_game_submissions_to_worker_without_waiting_for_render() {
|
||||||
let gate = RenderGate::default();
|
let gate = RenderGate::default();
|
||||||
|
|||||||
@ -72,7 +72,14 @@ impl FakeRenderBackend {
|
|||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(owned_frame(submission.frame_id, 0xff00_0000 | submission.frame_id.get() as u32))
|
OwnedRgba8888Frame::packed(
|
||||||
|
submission.frame_id,
|
||||||
|
submission.ownership,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
vec![0xff00_0000 | submission.frame_id.get() as u32],
|
||||||
|
)
|
||||||
|
.map_err(|_| RenderWorkerError::InternalFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn publish(&self, frame: OwnedRgba8888Frame) {
|
pub(crate) fn publish(&self, frame: OwnedRgba8888Frame) {
|
||||||
|
|||||||
@ -246,6 +246,7 @@ impl VirtualMachineRuntime {
|
|||||||
self.current_cartridge_app_mode,
|
self.current_cartridge_app_mode,
|
||||||
self.current_app_id,
|
self.current_app_id,
|
||||||
);
|
);
|
||||||
|
self.sync_render_worker_ownership();
|
||||||
if self.current_cartridge_app_mode == AppMode::Game {
|
if self.current_cartridge_app_mode == AppMode::Game {
|
||||||
let mut packet = platform.game2d_frame_composer().close_game2d_packet();
|
let mut packet = platform.game2d_frame_composer().close_game2d_packet();
|
||||||
packet.gfx2d = std::mem::take(&mut self.gfx2d_commands);
|
packet.gfx2d = std::mem::take(&mut self.gfx2d_commands);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
|||||||
id: PLN-0118
|
id: PLN-0118
|
||||||
ticket: real-render-worker-establishment
|
ticket: real-render-worker-establishment
|
||||||
title: Add Stale Epoch and Repeat Frame Behavior
|
title: Add Stale Epoch and Repeat Frame Behavior
|
||||||
status: open
|
status: done
|
||||||
created: 2026-06-15
|
created: 2026-06-15
|
||||||
completed:
|
completed:
|
||||||
ref_decisions: [DEC-0033]
|
ref_decisions: [DEC-0033]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user