implements PLN-0021
This commit is contained in:
parent
5ef43045bc
commit
a1bd60671b
@ -251,7 +251,7 @@ impl FrameComposer {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx.render_all();
|
||||
gfx.render_no_scene_frame();
|
||||
}
|
||||
|
||||
fn build_scene_runtime(
|
||||
|
||||
@ -209,8 +209,8 @@ impl GfxBridge for Gfx {
|
||||
fn present(&mut self) {
|
||||
self.present()
|
||||
}
|
||||
fn render_all(&mut self) {
|
||||
self.render_all()
|
||||
fn render_no_scene_frame(&mut self) {
|
||||
self.render_no_scene_frame()
|
||||
}
|
||||
fn render_scene_from_cache(&mut self, cache: &SceneViewportCache, update: &ResolverUpdate) {
|
||||
self.render_scene_from_cache(cache, update)
|
||||
@ -552,7 +552,7 @@ impl Gfx {
|
||||
/// This method composes the final frame by rasterizing layers and sprites in the
|
||||
/// correct priority order into the back buffer.
|
||||
/// Follows the hardware model where layers and sprites are composed every frame.
|
||||
pub fn render_all(&mut self) {
|
||||
pub fn render_no_scene_frame(&mut self) {
|
||||
self.populate_layer_buckets();
|
||||
for bucket in &self.layer_buckets {
|
||||
Self::draw_bucket_on_buffer(
|
||||
|
||||
@ -9,6 +9,7 @@ use crate::memory_banks::{
|
||||
use crate::pad::Pad;
|
||||
use crate::touch::Touch;
|
||||
use prometeu_hal::cartridge::AssetsPayloadSource;
|
||||
use prometeu_hal::sprite::Sprite;
|
||||
use prometeu_hal::{AssetBridge, AudioBridge, GfxBridge, HardwareBridge, PadBridge, TouchBridge};
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -46,6 +47,18 @@ impl Default for Hardware {
|
||||
}
|
||||
|
||||
impl HardwareBridge for Hardware {
|
||||
fn begin_frame(&mut self) {
|
||||
self.frame_composer.begin_frame();
|
||||
}
|
||||
|
||||
fn emit_sprite(&mut self, sprite: Sprite) {
|
||||
let _ = self.frame_composer.emit_sprite(sprite);
|
||||
}
|
||||
|
||||
fn render_frame(&mut self) {
|
||||
self.frame_composer.render_frame(&mut self.gfx);
|
||||
}
|
||||
|
||||
fn gfx(&self) -> &dyn GfxBridge {
|
||||
&self.gfx
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ pub trait GfxBridge {
|
||||
fn draw_horizontal_line(&mut self, x0: i32, x1: i32, y: i32, color: Color);
|
||||
fn draw_vertical_line(&mut self, x: i32, y0: i32, y1: i32, color: Color);
|
||||
fn present(&mut self);
|
||||
fn render_all(&mut self);
|
||||
fn render_no_scene_frame(&mut self);
|
||||
fn render_scene_from_cache(&mut self, cache: &SceneViewportCache, update: &ResolverUpdate);
|
||||
fn load_frame_sprites(&mut self, sprites: &[Sprite]);
|
||||
fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Color);
|
||||
|
||||
@ -2,9 +2,14 @@ use crate::asset_bridge::AssetBridge;
|
||||
use crate::audio_bridge::AudioBridge;
|
||||
use crate::gfx_bridge::GfxBridge;
|
||||
use crate::pad_bridge::PadBridge;
|
||||
use crate::sprite::Sprite;
|
||||
use crate::touch_bridge::TouchBridge;
|
||||
|
||||
pub trait HardwareBridge {
|
||||
fn begin_frame(&mut self);
|
||||
fn emit_sprite(&mut self, sprite: Sprite);
|
||||
fn render_frame(&mut self);
|
||||
|
||||
fn gfx(&self) -> &dyn GfxBridge;
|
||||
fn gfx_mut(&mut self) -> &mut dyn GfxBridge;
|
||||
|
||||
|
||||
@ -162,17 +162,19 @@ impl NativeInterface for VirtualMachineRuntime {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
*hw.gfx_mut().sprite_mut(index) = Sprite {
|
||||
if active {
|
||||
hw.emit_sprite(Sprite {
|
||||
glyph: Glyph { glyph_id, palette_id },
|
||||
x,
|
||||
y,
|
||||
layer: 0,
|
||||
bank_id,
|
||||
active,
|
||||
active: false,
|
||||
flip_x,
|
||||
flip_y,
|
||||
priority,
|
||||
};
|
||||
});
|
||||
}
|
||||
ret.push_int(GfxOpStatus::Ok as i64);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ use prometeu_bytecode::Value;
|
||||
use prometeu_bytecode::assembler::assemble;
|
||||
use prometeu_bytecode::model::{BytecodeModule, ConstantPoolEntry, FunctionMeta, SyscallDecl};
|
||||
use prometeu_drivers::hardware::Hardware;
|
||||
use prometeu_drivers::{GlyphBankPoolInstaller, MemoryBanks, SceneBankPoolInstaller};
|
||||
use prometeu_hal::AudioOpStatus;
|
||||
use prometeu_hal::GfxOpStatus;
|
||||
use prometeu_hal::InputSignals;
|
||||
@ -12,10 +13,17 @@ use prometeu_hal::asset::{
|
||||
AssetCodec, AssetEntry, AssetLoadError, AssetOpStatus, BankType, LoadStatus,
|
||||
};
|
||||
use prometeu_hal::cartridge::{AssetsPayloadSource, Cartridge};
|
||||
use prometeu_hal::glyph_bank::GLYPH_BANK_PALETTE_COUNT_V1;
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::glyph::Glyph;
|
||||
use prometeu_hal::glyph_bank::{GLYPH_BANK_PALETTE_COUNT_V1, GlyphBank, TileSize};
|
||||
use prometeu_hal::scene_bank::SceneBank;
|
||||
use prometeu_hal::scene_layer::{ParallaxFactor, SceneLayer};
|
||||
use prometeu_hal::syscalls::caps;
|
||||
use prometeu_hal::tile::Tile;
|
||||
use prometeu_hal::tilemap::TileMap;
|
||||
use prometeu_vm::VmInitError;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
#[derive(Default)]
|
||||
@ -129,6 +137,40 @@ fn test_glyph_asset_data() -> Vec<u8> {
|
||||
data
|
||||
}
|
||||
|
||||
fn runtime_test_glyph_bank(tile_size: TileSize, palette_id: u8, color: Color) -> GlyphBank {
|
||||
let size = tile_size as usize;
|
||||
let mut bank = GlyphBank::new(tile_size, size, size);
|
||||
bank.palettes[palette_id as usize][1] = color;
|
||||
for pixel in &mut bank.pixel_indices {
|
||||
*pixel = 1;
|
||||
}
|
||||
bank
|
||||
}
|
||||
|
||||
fn runtime_test_scene(glyph_bank_id: u8, palette_id: u8, tile_size: TileSize) -> SceneBank {
|
||||
let layer = SceneLayer {
|
||||
active: true,
|
||||
glyph_bank_id,
|
||||
tile_size,
|
||||
parallax_factor: ParallaxFactor { x: 1.0, y: 1.0 },
|
||||
tilemap: TileMap {
|
||||
width: 2,
|
||||
height: 2,
|
||||
tiles: vec![
|
||||
Tile {
|
||||
active: true,
|
||||
glyph: Glyph { glyph_id: 0, palette_id },
|
||||
flip_x: false,
|
||||
flip_y: false,
|
||||
};
|
||||
4
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
SceneBank { layers: std::array::from_fn(|_| layer.clone()) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_vm_applies_cartridge_capabilities_before_loader_resolution() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
@ -233,6 +275,29 @@ fn tick_returns_panic_report_distinct_from_trap() {
|
||||
assert!(matches!(runtime.last_crash_report, Some(CrashReport::VmPanic { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_renders_bound_eight_pixel_scene_through_frame_composer_path() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let signals = InputSignals::default();
|
||||
let program =
|
||||
serialized_single_function_module(assemble("FRAME_SYNC\nHALT").expect("assemble"), vec![]);
|
||||
let cartridge = cartridge_with_program(program, caps::NONE);
|
||||
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
banks.install_glyph_bank(0, Arc::new(runtime_test_glyph_bank(TileSize::Size8, 2, Color::BLUE)));
|
||||
banks.install_scene_bank(0, Arc::new(runtime_test_scene(0, 2, TileSize::Size8)));
|
||||
let mut hardware = Hardware::new_with_memory_banks(Arc::clone(&banks));
|
||||
assert!(hardware.frame_composer.bind_scene(0));
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
|
||||
assert!(report.is_none(), "frame render path must not crash");
|
||||
hardware.gfx.present();
|
||||
assert_eq!(hardware.gfx.front_buffer()[0], Color::BLUE.raw());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_vm_success_clears_previous_crash_report() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
|
||||
@ -145,7 +145,7 @@ impl VirtualMachineRuntime {
|
||||
if run.reason == LogicalFrameEndingReason::FrameSync
|
||||
|| run.reason == LogicalFrameEndingReason::EndOfRom
|
||||
{
|
||||
hw.gfx_mut().render_all();
|
||||
hw.render_frame();
|
||||
|
||||
// 1. Snapshot full telemetry at logical frame end
|
||||
let (glyph_bank, sound_bank) = Self::bank_telemetry_summary(hw);
|
||||
@ -250,6 +250,7 @@ impl VirtualMachineRuntime {
|
||||
_signals: &InputSignals,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
) {
|
||||
hw.begin_frame();
|
||||
hw.audio_mut().clear_commands();
|
||||
self.logs_written_this_frame.clear();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user