implements PLN-0119
This commit is contained in:
parent
6b5b27d068
commit
67a629dbe4
@ -33,6 +33,8 @@ use std::sync::Arc;
|
||||
/// - **Audio**: Stereo, Command-based mixing.
|
||||
/// - **Input**: 12-button Digital Gamepad + Absolute Touch/Mouse.
|
||||
pub struct Hardware {
|
||||
/// Shared physical memory bank ownership used by peripherals and worker backends.
|
||||
pub memory_banks: Arc<MemoryBanks>,
|
||||
/// The Graphics Processing Unit (GPU). Handles drawing primitives, sprites, and tilemaps.
|
||||
pub gfx: Gfx,
|
||||
/// Canonical frame orchestration owner for scene/camera/cache/resolver/sprites.
|
||||
@ -216,6 +218,7 @@ impl Hardware {
|
||||
);
|
||||
let glyph_slot_index = assets.glyph_asset_slot_index();
|
||||
Self {
|
||||
memory_banks: Arc::clone(&memory_banks),
|
||||
gfx: Gfx::new(
|
||||
Self::W,
|
||||
Self::H,
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
use crate::asset::GlyphAssetSlotIndex;
|
||||
use crate::frame_composer::FrameComposer;
|
||||
use crate::gfx::Gfx;
|
||||
use crate::memory_banks::GlyphBankPoolAccess;
|
||||
use crate::memory_banks::{GlyphBankPoolAccess, MemoryBanks, SceneBankPoolAccess};
|
||||
use prometeu_hal::app_mode::AppMode;
|
||||
use prometeu_hal::{
|
||||
OwnedRgba8888Frame, RenderSubmission, RenderSubmissionPacket, RenderWorkerBackend,
|
||||
@ -9,11 +11,51 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
pub struct LocalFramebufferRenderBackend {
|
||||
gfx: Mutex<Gfx>,
|
||||
frame_composer: Mutex<FrameComposer>,
|
||||
}
|
||||
|
||||
impl LocalFramebufferRenderBackend {
|
||||
pub fn new(width: usize, height: usize, glyph_banks: Arc<dyn GlyphBankPoolAccess>) -> Self {
|
||||
Self { gfx: Mutex::new(Gfx::new(width, height, glyph_banks)) }
|
||||
Self::new_with_parts(
|
||||
width,
|
||||
height,
|
||||
glyph_banks,
|
||||
Arc::new(MemoryBanks::new()),
|
||||
GlyphAssetSlotIndex::new(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_with_memory_banks(
|
||||
width: usize,
|
||||
height: usize,
|
||||
memory_banks: Arc<MemoryBanks>,
|
||||
glyph_slot_index: GlyphAssetSlotIndex,
|
||||
) -> Self {
|
||||
Self::new_with_parts(
|
||||
width,
|
||||
height,
|
||||
Arc::clone(&memory_banks) as Arc<dyn GlyphBankPoolAccess>,
|
||||
memory_banks,
|
||||
glyph_slot_index,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_with_parts(
|
||||
width: usize,
|
||||
height: usize,
|
||||
glyph_banks: Arc<dyn GlyphBankPoolAccess>,
|
||||
scene_banks: Arc<dyn SceneBankPoolAccess>,
|
||||
glyph_slot_index: GlyphAssetSlotIndex,
|
||||
) -> Self {
|
||||
Self {
|
||||
gfx: Mutex::new(Gfx::new(width, height, glyph_banks)),
|
||||
frame_composer: Mutex::new(FrameComposer::new(
|
||||
width,
|
||||
height,
|
||||
scene_banks,
|
||||
glyph_slot_index,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_submission(
|
||||
@ -23,7 +65,16 @@ impl LocalFramebufferRenderBackend {
|
||||
let mut gfx = self.gfx.lock().map_err(|_| RenderWorkerError::InternalFailure)?;
|
||||
match &submission.packet {
|
||||
RenderSubmissionPacket::Game2D(packet) if submission.app_mode == AppMode::Game => {
|
||||
gfx.render_game2d_frame_packet(packet);
|
||||
if packet.composer.bound_scene.is_none() {
|
||||
gfx.render_game2d_frame_packet(packet);
|
||||
} else {
|
||||
let mut frame_composer = self
|
||||
.frame_composer
|
||||
.lock()
|
||||
.map_err(|_| RenderWorkerError::InternalFailure)?;
|
||||
frame_composer.render_game2d_frame_packet(packet, &mut *gfx);
|
||||
gfx.apply_gfx2d_commands(&packet.gfx2d);
|
||||
}
|
||||
}
|
||||
RenderSubmissionPacket::ShellUi(packet) if submission.app_mode == AppMode::Shell => {
|
||||
gfx.render_shell_ui_frame_packet(packet);
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
use crate::CrashReport;
|
||||
use crate::os::SystemOS;
|
||||
use crate::{RenderWorkerConfig, RenderWorkerController};
|
||||
use prometeu_hal::app_mode::AppMode;
|
||||
use prometeu_hal::cartridge::Cartridge;
|
||||
use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame};
|
||||
use prometeu_hal::{InputSignals, RuntimePlatform};
|
||||
use prometeu_hal::{
|
||||
InputSignals, OwnedRgba8888Frame, RenderWorkerBackend, RenderWorkerError,
|
||||
RenderWorkerFrameSink, RuntimePlatform,
|
||||
};
|
||||
use prometeu_vm::VirtualMachine;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
@ -96,6 +100,30 @@ impl<'a> VmFacade<'a> {
|
||||
self.os.vm_runtime.atomic_telemetry.snapshot()
|
||||
}
|
||||
|
||||
pub fn start_render_worker<B, S>(&mut self, config: RenderWorkerConfig, backend: B, sink: S)
|
||||
where
|
||||
B: RenderWorkerBackend,
|
||||
S: RenderWorkerFrameSink,
|
||||
{
|
||||
self.os.vm_runtime.start_render_worker(config, backend, sink);
|
||||
}
|
||||
|
||||
pub fn stop_render_worker(&mut self) -> Result<(), RenderWorkerError> {
|
||||
self.os.vm_runtime.stop_render_worker()
|
||||
}
|
||||
|
||||
pub fn render_worker_controller(&self) -> Option<&RenderWorkerController> {
|
||||
self.os.vm_runtime.render_worker_controller.as_ref()
|
||||
}
|
||||
|
||||
pub fn latest_render_worker_frame(&self) -> Option<OwnedRgba8888Frame> {
|
||||
self.os.vm_runtime.latest_render_worker_frame()
|
||||
}
|
||||
|
||||
pub fn repeat_latest_render_worker_frame(&self) -> Option<OwnedRgba8888Frame> {
|
||||
self.os.vm_runtime.repeat_latest_render_worker_frame()
|
||||
}
|
||||
|
||||
pub fn cert_config(&self) -> &CertificationConfig {
|
||||
&self.os.vm_runtime.certifier.config
|
||||
}
|
||||
|
||||
@ -3,7 +3,9 @@ use crate::CrashReport;
|
||||
use crate::fs::{FsBackend, FsState, VirtualFS};
|
||||
use prometeu_hal::cartridge::Cartridge;
|
||||
use prometeu_hal::log::{LogLevel, LogSource};
|
||||
use prometeu_hal::{RenderWorkerBackend, RenderWorkerError, RenderWorkerFrameSink};
|
||||
use prometeu_hal::{
|
||||
OwnedRgba8888Frame, RenderWorkerBackend, RenderWorkerError, RenderWorkerFrameSink,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
impl VirtualMachineRuntime {
|
||||
@ -193,6 +195,14 @@ impl VirtualMachineRuntime {
|
||||
self.render_worker_ownership.set(self.render_manager.active_ownership());
|
||||
}
|
||||
|
||||
pub fn latest_render_worker_frame(&self) -> Option<OwnedRgba8888Frame> {
|
||||
self.render_worker_controller.as_ref()?.latest_published_frame()
|
||||
}
|
||||
|
||||
pub fn repeat_latest_render_worker_frame(&self) -> Option<OwnedRgba8888Frame> {
|
||||
self.render_worker_controller.as_ref()?.repeat_latest_frame()
|
||||
}
|
||||
|
||||
pub fn initialize_vm(
|
||||
&mut self,
|
||||
log_service: &mut LogService,
|
||||
|
||||
@ -4,14 +4,16 @@ use crate::fs_backend::HostDirBackend;
|
||||
use crate::input::HostInputHandler;
|
||||
use crate::log_sink::HostConsoleSink;
|
||||
use crate::stats::HostStats;
|
||||
use crate::utilities::draw_rgba8888_to_rgba8;
|
||||
use crate::utilities::{draw_owned_rgba8888_frame_to_rgba8, draw_rgba8888_to_rgba8};
|
||||
use pixels::wgpu::PresentMode;
|
||||
use pixels::{Pixels, PixelsBuilder, SurfaceTexture};
|
||||
use prometeu_drivers::AudioCommand;
|
||||
use prometeu_drivers::hardware::Hardware;
|
||||
use prometeu_drivers::{AudioCommand, LocalFramebufferRenderBackend, MemoryBanks};
|
||||
use prometeu_firmware::{BootTarget, Firmware, FirmwareState};
|
||||
use prometeu_hal::RuntimePlatform;
|
||||
use prometeu_hal::telemetry::CertificationConfig;
|
||||
use prometeu_hal::{OwnedRgba8888Frame, RenderWorkerError, RenderWorkerFrameSink, RuntimePlatform};
|
||||
use prometeu_system::RenderWorkerConfig;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::LogicalSize;
|
||||
@ -22,6 +24,15 @@ use winit::window::{Window, WindowAttributes, WindowId};
|
||||
|
||||
const IDLE_HOST_POLL_DT: Duration = Duration::from_millis(100);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct HostWorkerFrameSink;
|
||||
|
||||
impl RenderWorkerFrameSink for HostWorkerFrameSink {
|
||||
fn publish(&self, _frame: OwnedRgba8888Frame) -> Result<(), RenderWorkerError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct PresentationState {
|
||||
latest_published_frame: u64,
|
||||
@ -153,8 +164,20 @@ impl HostRunner {
|
||||
firmware.os.fs().mount(Box::new(backend));
|
||||
}
|
||||
|
||||
let hardware = Hardware::new();
|
||||
let memory_banks = Arc::new(MemoryBanks::new());
|
||||
let hardware = Hardware::new_with_memory_banks(Arc::clone(&memory_banks));
|
||||
let display_size = hardware.display_size();
|
||||
let worker_backend = LocalFramebufferRenderBackend::new_with_memory_banks(
|
||||
display_size.0,
|
||||
display_size.1,
|
||||
memory_banks,
|
||||
hardware.assets.glyph_asset_slot_index(),
|
||||
);
|
||||
firmware.os.vm().start_render_worker(
|
||||
RenderWorkerConfig::default(),
|
||||
worker_backend,
|
||||
HostWorkerFrameSink,
|
||||
);
|
||||
|
||||
Self {
|
||||
window: None,
|
||||
@ -278,10 +301,17 @@ impl ApplicationHandler for HostRunner {
|
||||
// Mutable borrow of the frame (lasts only within this block)
|
||||
let frame = pixels.frame_mut();
|
||||
|
||||
// Immutable borrow of prometeu-core (different field, ok)
|
||||
let src = self.hardware.gfx.front_buffer();
|
||||
|
||||
draw_rgba8888_to_rgba8(src, frame);
|
||||
let use_worker_frame =
|
||||
matches!(self.firmware.state, FirmwareState::GameRunning(_));
|
||||
if use_worker_frame
|
||||
&& let Some(worker_frame) =
|
||||
self.firmware.os.vm().repeat_latest_render_worker_frame()
|
||||
{
|
||||
draw_owned_rgba8888_frame_to_rgba8(&worker_frame, frame);
|
||||
} else {
|
||||
let src = self.hardware.gfx.front_buffer();
|
||||
draw_rgba8888_to_rgba8(src, frame);
|
||||
}
|
||||
} // <- frame borrow ends here
|
||||
|
||||
if pixels.render().is_err() {
|
||||
@ -372,7 +402,14 @@ impl ApplicationHandler for HostRunner {
|
||||
self.stats.record_frame();
|
||||
}
|
||||
|
||||
self.presentation.note_published_frame(self.firmware.os.frame_index());
|
||||
let use_worker_frame = matches!(self.firmware.state, FirmwareState::GameRunning(_));
|
||||
if use_worker_frame
|
||||
&& let Some(worker_frame) = self.firmware.os.vm().latest_render_worker_frame()
|
||||
{
|
||||
self.presentation.note_published_frame(worker_frame.frame_id.get());
|
||||
} else {
|
||||
self.presentation.note_published_frame(self.firmware.os.frame_index());
|
||||
}
|
||||
|
||||
if was_debugger_connected != self.debugger.stream.is_some()
|
||||
|| was_waiting_for_start != self.debugger.waiting_for_start
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use prometeu_hal::OwnedRgba8888Frame;
|
||||
|
||||
/// Copies RGBA8888 pixels in canonical RGBA raw order into the `pixels` RGBA8 frame.
|
||||
pub fn draw_rgba8888_to_rgba8(src: &[u32], dst_rgba: &mut [u8]) {
|
||||
for (i, &px) in src.iter().enumerate() {
|
||||
@ -9,9 +11,15 @@ pub fn draw_rgba8888_to_rgba8(src: &[u32], dst_rgba: &mut [u8]) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_owned_rgba8888_frame_to_rgba8(frame: &OwnedRgba8888Frame, dst_rgba: &mut [u8]) {
|
||||
draw_rgba8888_to_rgba8(&frame.pixels[..frame.required_pixel_len()], dst_rgba);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::draw_rgba8888_to_rgba8;
|
||||
use super::{draw_owned_rgba8888_frame_to_rgba8, draw_rgba8888_to_rgba8};
|
||||
use prometeu_hal::app_mode::AppMode;
|
||||
use prometeu_hal::{FrameId, OwnedRgba8888Frame, RenderOwnership};
|
||||
|
||||
#[test]
|
||||
fn draw_rgba8888_to_rgba8_preserves_channel_order_and_alpha() {
|
||||
@ -22,4 +30,21 @@ mod tests {
|
||||
|
||||
assert_eq!(dst, [0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0x01]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draw_owned_frame_to_rgba8_uses_owned_rgba8888_pixels() {
|
||||
let frame = OwnedRgba8888Frame::packed(
|
||||
FrameId::new(3),
|
||||
RenderOwnership::new(1, AppMode::Game, 7),
|
||||
1,
|
||||
1,
|
||||
vec![0x10203040],
|
||||
)
|
||||
.expect("test frame should be valid");
|
||||
let mut dst = [0; 4];
|
||||
|
||||
draw_owned_rgba8888_frame_to_rgba8(&frame, &mut dst);
|
||||
|
||||
assert_eq!(dst, [0x10, 0x20, 0x30, 0x40]);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
||||
id: PLN-0119
|
||||
ticket: real-render-worker-establishment
|
||||
title: Integrate Desktop Host Worker Presentation
|
||||
status: open
|
||||
status: done
|
||||
created: 2026-06-15
|
||||
completed:
|
||||
ref_decisions: [DEC-0033]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user