dev/render-worker-establishment #32

Merged
bquarkz merged 47 commits from dev/real-render-worker-establishment into master 2026-06-20 16:11:08 +00:00
7 changed files with 193 additions and 49 deletions
Showing only changes of commit d0a2682366 - Show all commits

View File

@ -232,11 +232,11 @@ impl RuntimePlatform for Hardware {
self
}
fn audio(&self) -> &dyn prometeu_hal::AudioPlatform {
fn audio(&self) -> &dyn AudioBridge {
&self.audio
}
fn audio_mut(&mut self) -> &mut dyn prometeu_hal::AudioPlatform {
fn audio_mut(&mut self) -> &mut dyn AudioBridge {
&mut self.audio
}
@ -248,11 +248,11 @@ impl RuntimePlatform for Hardware {
self
}
fn assets(&self) -> &dyn prometeu_hal::AssetStoragePlatform {
fn assets(&self) -> &dyn AssetBridge {
&self.assets
}
fn assets_mut(&mut self) -> &mut dyn prometeu_hal::AssetStoragePlatform {
fn assets_mut(&mut self) -> &mut dyn AssetBridge {
&mut self.assets
}

View File

@ -1,7 +1,7 @@
use crate::hardware::Hardware;
use crate::memory_banks::MemoryBanks;
use prometeu_hal::{
AssetStoragePlatform, AudioPlatform, Game2DFrameComposer, InputPlatform, RenderBackend,
AssetBridge, AudioBridge, Game2DFrameComposer, InputPlatform, RenderBackend,
RenderSubmissionSink, RuntimePlatform, TelemetryPlatform,
};
use std::sync::Arc;
@ -47,11 +47,11 @@ impl RuntimePlatform for TestPlatform {
self.hardware.game2d_frame_composer()
}
fn audio(&self) -> &dyn AudioPlatform {
fn audio(&self) -> &dyn AudioBridge {
self.hardware.audio()
}
fn audio_mut(&mut self) -> &mut dyn AudioPlatform {
fn audio_mut(&mut self) -> &mut dyn AudioBridge {
self.hardware.audio_mut()
}
@ -63,11 +63,11 @@ impl RuntimePlatform for TestPlatform {
self.hardware.input_mut()
}
fn assets(&self) -> &dyn AssetStoragePlatform {
fn assets(&self) -> &dyn AssetBridge {
self.hardware.assets()
}
fn assets_mut(&mut self) -> &mut dyn AssetStoragePlatform {
fn assets_mut(&mut self) -> &mut dyn AssetBridge {
self.hardware.assets_mut()
}

View File

@ -1,13 +1,19 @@
use crate::hardware_bridge::HardwareBridge;
use crate::platform::RuntimePlatform;
use crate::vm_fault::VmFault;
pub struct HostContext<'a> {
pub hw: Option<&'a mut dyn HardwareBridge>,
pub platform: Option<&'a mut dyn RuntimePlatform>,
}
impl<'a> HostContext<'a> {
pub fn new(hw: Option<&'a mut dyn HardwareBridge>) -> Self {
Self { hw }
Self { hw, platform: None }
}
pub fn new_platform(platform: Option<&'a mut dyn RuntimePlatform>) -> Self {
Self { hw: None, platform }
}
#[inline]
@ -17,6 +23,14 @@ impl<'a> HostContext<'a> {
None => Err(VmFault::Unavailable),
}
}
#[inline]
pub fn require_platform(&mut self) -> Result<&mut dyn RuntimePlatform, VmFault> {
match &mut self.platform {
Some(platform) => Ok(*platform),
None => Err(VmFault::Unavailable),
}
}
}
pub trait HostContextProvider {

View File

@ -49,9 +49,9 @@ pub use native_interface::{NativeInterface, SyscallId};
pub use pad_bridge::PadBridge;
pub use platform::{
AssetStoragePlatform, AudioPlatform, ClockPacingPlatform, Game2DFrameComposer, InputPlatform,
LegacyHardwareGame2DFrameComposer, LegacyHardwareRenderSubmissionSink, NoopTelemetryPlatform,
RenderBackend, RenderSubmissionSink, RenderSubmitError, RuntimePlatform, TelemetryPlatform,
TestPlatform,
LegacyHardwareGame2DFrameComposer, LegacyHardwareRenderSubmissionSink,
LegacyHardwareRuntimePlatform, NoopTelemetryPlatform, RenderBackend, RenderSubmissionSink,
RenderSubmitError, RuntimePlatform, TelemetryPlatform, TestPlatform,
};
pub use render_submission::{
BoundScenePacket, Camera2D, ComposerFramePacket, FrameId, Game2DFramePacket, GameSpritePacket,

View File

@ -103,6 +103,89 @@ impl Game2DFrameComposer for LegacyHardwareGame2DFrameComposer<'_> {
}
}
pub struct LegacyHardwareRuntimePlatform<'a> {
hw: &'a mut dyn HardwareBridge,
}
impl<'a> LegacyHardwareRuntimePlatform<'a> {
pub fn new(hw: &'a mut dyn HardwareBridge) -> Self {
Self { hw }
}
}
impl RenderSubmissionSink for LegacyHardwareRuntimePlatform<'_> {
fn submit_render_submission(
&mut self,
submission: RenderSubmission,
) -> Result<(), RenderSubmitError> {
self.hw.publish_render_submission(&submission);
Ok(())
}
}
impl RenderBackend for LegacyHardwareRuntimePlatform<'_> {
fn render_frame(&mut self) {
self.hw.render_frame();
}
}
impl Game2DFrameComposer for LegacyHardwareRuntimePlatform<'_> {
fn begin_frame(&mut self) {
self.hw.begin_frame();
}
fn bind_scene(&mut self, scene_bank_id: usize) -> ComposerOpStatus {
if self.hw.bind_scene(scene_bank_id) {
ComposerOpStatus::Ok
} else {
ComposerOpStatus::SceneUnavailable
}
}
fn unbind_scene(&mut self) {
self.hw.unbind_scene();
}
fn set_camera(&mut self, x: i32, y: i32) -> ComposerOpStatus {
self.hw.set_camera(x, y);
ComposerOpStatus::Ok
}
fn emit_sprite(&mut self, sprite: Sprite) -> ComposerOpStatus {
if !self.hw.has_glyph_bank(sprite.bank_id as usize) {
return ComposerOpStatus::BankInvalid;
}
if self.hw.emit_sprite(sprite) {
ComposerOpStatus::Ok
} else {
ComposerOpStatus::SpriteOverflow
}
}
fn close_game2d_packet(&self) -> Game2DFramePacket {
self.hw.close_game2d_packet()
}
}
impl InputPlatform for LegacyHardwareRuntimePlatform<'_> {
fn pad(&self) -> &dyn PadBridge {
self.hw.pad()
}
fn pad_mut(&mut self) -> &mut dyn PadBridge {
self.hw.pad_mut()
}
fn touch(&self) -> &dyn TouchBridge {
self.hw.touch()
}
fn touch_mut(&mut self) -> &mut dyn TouchBridge {
self.hw.touch_mut()
}
}
pub trait AudioPlatform: AudioBridge {}
impl<T: AudioBridge + ?Sized> AudioPlatform for T {}
@ -129,19 +212,63 @@ pub struct NoopTelemetryPlatform;
impl TelemetryPlatform for NoopTelemetryPlatform {}
static LEGACY_NOOP_TELEMETRY: NoopTelemetryPlatform = NoopTelemetryPlatform;
pub trait RuntimePlatform {
fn render_submission_sink(&mut self) -> &mut dyn RenderSubmissionSink;
fn render_backend(&mut self) -> &mut dyn RenderBackend;
fn game2d_frame_composer(&mut self) -> &mut dyn Game2DFrameComposer;
fn audio(&self) -> &dyn AudioPlatform;
fn audio_mut(&mut self) -> &mut dyn AudioPlatform;
fn audio(&self) -> &dyn AudioBridge;
fn audio_mut(&mut self) -> &mut dyn AudioBridge;
fn input(&self) -> &dyn InputPlatform;
fn input_mut(&mut self) -> &mut dyn InputPlatform;
fn assets(&self) -> &dyn AssetStoragePlatform;
fn assets_mut(&mut self) -> &mut dyn AssetStoragePlatform;
fn assets(&self) -> &dyn AssetBridge;
fn assets_mut(&mut self) -> &mut dyn AssetBridge;
fn telemetry(&self) -> &dyn TelemetryPlatform;
}
impl RuntimePlatform for LegacyHardwareRuntimePlatform<'_> {
fn render_submission_sink(&mut self) -> &mut dyn RenderSubmissionSink {
self
}
fn render_backend(&mut self) -> &mut dyn RenderBackend {
self
}
fn game2d_frame_composer(&mut self) -> &mut dyn Game2DFrameComposer {
self
}
fn audio(&self) -> &dyn AudioBridge {
self.hw.audio()
}
fn audio_mut(&mut self) -> &mut dyn AudioBridge {
self.hw.audio_mut()
}
fn input(&self) -> &dyn InputPlatform {
self
}
fn input_mut(&mut self) -> &mut dyn InputPlatform {
self
}
fn assets(&self) -> &dyn AssetBridge {
self.hw.assets()
}
fn assets_mut(&mut self) -> &mut dyn AssetBridge {
self.hw.assets_mut()
}
fn telemetry(&self) -> &dyn TelemetryPlatform {
&LEGACY_NOOP_TELEMETRY
}
}
pub trait TestPlatform: RuntimePlatform {}
impl<T: RuntimePlatform + ?Sized> TestPlatform for T {}

View File

@ -12,9 +12,8 @@ use prometeu_hal::sprite::Sprite;
use prometeu_hal::syscalls::Syscall;
use prometeu_hal::vm_fault::VmFault;
use prometeu_hal::{
AudioOpStatus, ComposerOpStatus, Game2DFrameComposer, Gfx2dCommand, GfxUiCommand, HostContext,
HostReturn, LegacyHardwareGame2DFrameComposer, NativeInterface, SyscallId, expect_bool,
expect_int,
AudioOpStatus, ComposerOpStatus, Gfx2dCommand, GfxUiCommand, HostContext, HostReturn,
NativeInterface, SyscallId, expect_bool, expect_int,
};
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
@ -180,7 +179,7 @@ impl NativeInterface for VmRuntimeHost<'_> {
self.ensure_game_profile_syscall(syscall)?;
let hw = ctx.require_hw()?;
let platform = ctx.require_platform()?;
match syscall {
Syscall::SystemHasCart => unreachable!(),
@ -387,8 +386,7 @@ impl NativeInterface for VmRuntimeHost<'_> {
};
let status = catch_unwind(AssertUnwindSafe(|| {
let mut composer = LegacyHardwareGame2DFrameComposer::new(hw);
composer.bind_scene(scene_bank_id)
platform.game2d_frame_composer().bind_scene(scene_bank_id)
}))
.map_err(|payload| VmFault::Panic(Self::panic_payload_to_string(payload)))?;
@ -396,14 +394,14 @@ impl NativeInterface for VmRuntimeHost<'_> {
Ok(())
}
Syscall::ComposerUnbindScene => {
LegacyHardwareGame2DFrameComposer::new(hw).unbind_scene();
platform.game2d_frame_composer().unbind_scene();
ret.push_int(ComposerOpStatus::Ok as i64);
Ok(())
}
Syscall::ComposerSetCamera => {
let x = Self::int_arg_to_i32_trap(expect_int(args, 0)?, "camera x")?;
let y = Self::int_arg_to_i32_trap(expect_int(args, 1)?, "camera y")?;
LegacyHardwareGame2DFrameComposer::new(hw).set_camera(x, y);
platform.game2d_frame_composer().set_camera(x, y);
Ok(())
}
Syscall::ComposerEmitSprite => {
@ -451,7 +449,7 @@ impl NativeInterface for VmRuntimeHost<'_> {
}
};
let status = LegacyHardwareGame2DFrameComposer::new(hw).emit_sprite(Sprite {
let status = platform.game2d_frame_composer().emit_sprite(Sprite {
glyph: Glyph { glyph_id, palette_id },
x,
y,
@ -488,7 +486,7 @@ impl NativeInterface for VmRuntimeHost<'_> {
return Ok(());
}
let status = hw.audio_mut().play(
let status = platform.audio_mut().play(
0,
sample_id_raw as u16,
voice_id_raw as usize,
@ -518,7 +516,8 @@ impl NativeInterface for VmRuntimeHost<'_> {
return Ok(());
}
if hw.assets().slot_info(SlotRef::audio(bank_id as usize)).asset_id.is_none() {
if platform.assets().slot_info(SlotRef::audio(bank_id as usize)).asset_id.is_none()
{
ret.push_int(AudioOpStatus::BankInvalid as i64);
return Ok(());
}
@ -534,7 +533,7 @@ impl NativeInterface for VmRuntimeHost<'_> {
return Ok(());
}
let status = hw.audio_mut().play(
let status = platform.audio_mut().play(
bank_id,
sample_id_raw as u16,
voice_id_raw as usize,
@ -731,7 +730,7 @@ impl NativeInterface for VmRuntimeHost<'_> {
})?;
let slot_index = expect_int(args, 1)? as usize;
match hw.assets().load(asset_id, slot_index) {
match platform.assets().load(asset_id, slot_index) {
Ok(handle) => {
ret.push_int(AssetOpStatus::Ok as i64);
ret.push_int(handle as i64);
@ -745,16 +744,16 @@ impl NativeInterface for VmRuntimeHost<'_> {
}
}
Syscall::AssetStatus => {
ret.push_int(hw.assets().status(expect_int(args, 0)? as u32) as i64);
ret.push_int(platform.assets().status(expect_int(args, 0)? as u32) as i64);
Ok(())
}
Syscall::AssetCommit => {
let status = hw.assets().commit(expect_int(args, 0)? as u32);
let status = platform.assets().commit(expect_int(args, 0)? as u32);
ret.push_int(status as i64);
Ok(())
}
Syscall::AssetCancel => {
let status = hw.assets().cancel(expect_int(args, 0)? as u32);
let status = platform.assets().cancel(expect_int(args, 0)? as u32);
ret.push_int(status as i64);
Ok(())
}
@ -764,7 +763,7 @@ impl NativeInterface for VmRuntimeHost<'_> {
1 => BankType::SOUNDS,
_ => return Err(VmFault::Trap(TRAP_TYPE, "Invalid asset type".to_string())),
};
let telemetry = hw
let telemetry = platform
.assets()
.bank_telemetry()
.into_iter()

View File

@ -9,8 +9,9 @@ use crate::services::memcard::MemcardService;
use prometeu_hal::asset::{BankTelemetry, BankType};
use prometeu_hal::log::{LogLevel, LogService, LogSource};
use prometeu_hal::{
FrameId, HardwareBridge, HostContext, InputSignals, LegacyHardwareRenderSubmissionSink,
RenderSubmission, RenderSubmissionPacket, RenderSubmissionSink, ShellUiFramePacket,
FrameId, HardwareBridge, HostContext, InputSignals, LegacyHardwareRuntimePlatform,
RenderSubmission, RenderSubmissionPacket, RenderSubmissionSink, RuntimePlatform,
ShellUiFramePacket,
};
use prometeu_vm::LogicalFrameEndingReason;
use std::collections::HashMap;
@ -53,9 +54,9 @@ impl VirtualMachineRuntime {
}
fn bank_telemetry_summary(
hw: &dyn HardwareBridge,
platform: &dyn RuntimePlatform,
) -> (BankTelemetry, BankTelemetry, BankTelemetry) {
let telemetry = hw.assets().bank_telemetry();
let telemetry = platform.assets().bank_telemetry();
let glyph =
telemetry.iter().find(|entry| entry.bank_type == BankType::GLYPH).cloned().unwrap_or(
BankTelemetry { bank_type: BankType::GLYPH, used_slots: 0, total_slots: 0 },
@ -79,7 +80,8 @@ impl VirtualMachineRuntime {
hw: &mut dyn HardwareBridge,
) -> Option<CrashReport> {
let step_result = {
let mut ctx = HostContext::new(Some(hw));
let mut platform = LegacyHardwareRuntimePlatform::new(hw);
let mut ctx = HostContext::new_platform(Some(&mut platform));
let mut fs = VirtualFS::new();
let mut fs_state = FsState::Unmounted;
let mut memcard = MemcardService::new();
@ -143,6 +145,7 @@ impl VirtualMachineRuntime {
}
self.update_fs(log_service, fs, fs_state);
let mut platform = LegacyHardwareRuntimePlatform::new(hw);
if !self.logical_frame_active {
if RenderManager::policy_for_app_mode(self.current_cartridge_app_mode)
@ -154,7 +157,7 @@ impl VirtualMachineRuntime {
}
self.logical_frame_active = true;
self.logical_frame_remaining_cycles = Self::CYCLES_PER_LOGICAL_FRAME;
self.begin_logical_frame(signals, hw);
self.begin_logical_frame(signals, &mut platform);
if self.needs_prepare_entry_call || vm.call_stack_is_empty() {
vm.prepare_boot_call();
@ -182,7 +185,7 @@ impl VirtualMachineRuntime {
if budget > 0 {
let run_result = {
let mut ctx = HostContext::new(Some(hw));
let mut ctx = HostContext::new_platform(Some(&mut platform));
let mut host = VmRuntimeHost {
runtime: self,
log_service,
@ -250,7 +253,7 @@ impl VirtualMachineRuntime {
self.current_app_id,
);
if self.current_cartridge_app_mode == AppMode::Game {
let mut packet = hw.close_game2d_packet();
let mut packet = platform.game2d_frame_composer().close_game2d_packet();
packet.gfx2d = std::mem::take(&mut self.gfx2d_commands);
self.render_manager
.close_frame_with_packet(RenderSubmissionPacket::Game2D(packet))
@ -264,8 +267,8 @@ impl VirtualMachineRuntime {
}
let render_outcome = catch_unwind(AssertUnwindSafe(|| {
let mut sink = LegacyHardwareRenderSubmissionSink::new(hw);
let mut surface = HardwareRenderSurface { sink: &mut sink };
let mut surface =
HardwareRenderSurface { sink: platform.render_submission_sink() };
match self
.render_manager
.active_render_policy()
@ -307,7 +310,8 @@ impl VirtualMachineRuntime {
}
// 1. Snapshot full telemetry at logical frame end
let (glyph_bank, sound_bank, scene_bank) = Self::bank_telemetry_summary(hw);
let (glyph_bank, sound_bank, scene_bank) =
Self::bank_telemetry_summary(&platform);
self.atomic_telemetry
.glyph_slots_used
.store(glyph_bank.used_slots as u32, Ordering::Relaxed);
@ -398,7 +402,7 @@ impl VirtualMachineRuntime {
// 2. High-frequency telemetry update (only if inspection is active)
if self.inspection_active {
let (glyph_bank, sound_bank, scene_bank) = Self::bank_telemetry_summary(hw);
let (glyph_bank, sound_bank, scene_bank) = Self::bank_telemetry_summary(&platform);
self.atomic_telemetry
.glyph_slots_used
.store(glyph_bank.used_slots as u32, Ordering::Relaxed);
@ -435,10 +439,10 @@ impl VirtualMachineRuntime {
pub(crate) fn begin_logical_frame(
&mut self,
_signals: &InputSignals,
hw: &mut dyn HardwareBridge,
platform: &mut dyn RuntimePlatform,
) {
hw.begin_frame();
hw.audio_mut().clear_commands();
platform.game2d_frame_composer().begin_frame();
platform.audio_mut().clear_commands();
self.logs_written_this_frame.clear();
}
}