fix stress render packet scene composition

This commit is contained in:
bQUARKz 2026-06-06 11:53:48 +01:00
parent 8cd218dc04
commit df0d7949c8
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
4 changed files with 100 additions and 20 deletions

View File

@ -327,6 +327,55 @@ impl FrameComposer {
gfx.render_no_scene_frame();
}
pub fn render_game2d_frame_packet(
&mut self,
packet: &Game2DFramePacket,
gfx: &mut dyn GfxBridge,
) {
let sprites: Vec<Sprite> =
packet.composer.sprites.iter().map(Self::sprite_from_packet).collect();
gfx.load_frame_sprites(&sprites);
let Some(bound_scene) = packet.composer.bound_scene else {
gfx.render_no_scene_frame();
return;
};
let scene_bank_id = bound_scene.bank_id as usize;
if self.active_scene_id != Some(scene_bank_id) && !self.bind_scene(scene_bank_id) {
gfx.render_no_scene_frame();
return;
}
self.camera_x_px = packet.composer.camera.x;
self.camera_y_px = packet.composer.camera.y;
let scene =
self.active_scene.as_deref().expect("active scene should exist after packet bind");
let resolved_glyph_slots = self.resolve_glyph_slots(scene, scene_bank_id, "render_packet");
let (Some(cache), Some(resolver)) = (self.cache.as_mut(), self.resolver.as_mut()) else {
panic!("SCENE runtime invariant broken: packet scene without cache/resolver");
};
let update = resolver.update(scene, self.camera_x_px, self.camera_y_px);
Self::sync_cache_windows(cache, &update);
Self::apply_refresh_requests(cache, scene, &update.refresh_requests);
gfx.render_scene_from_cache(cache, &update, &resolved_glyph_slots);
}
fn sprite_from_packet(sprite: &GameSpritePacket) -> Sprite {
Sprite {
glyph: Glyph { glyph_id: sprite.glyph_id as u16, palette_id: sprite.palette_id as u8 },
x: sprite.x,
y: sprite.y,
layer: sprite.layer as u8,
bank_id: sprite.bank_id as u8,
active: true,
flip_x: sprite.flip_x,
flip_y: sprite.flip_y,
priority: sprite.priority as u8,
}
}
fn build_scene_runtime(
viewport_width_px: usize,
viewport_height_px: usize,

View File

@ -75,10 +75,10 @@ impl HardwareBridge for Hardware {
fn publish_render_submission(&mut self, submission: &RenderSubmission) {
match &submission.packet {
RenderSubmissionPacket::Game2D(packet) => {
if self.frame_composer.active_scene_id().is_none() {
if packet.composer.bound_scene.is_none() {
self.gfx.render_game2d_frame_packet(packet);
} else {
self.frame_composer.render_frame(&mut self.gfx);
self.frame_composer.render_game2d_frame_packet(packet, &mut self.gfx);
self.gfx.apply_gfx2d_commands(&packet.gfx2d);
}
}
@ -195,7 +195,9 @@ mod tests {
use prometeu_hal::scene_viewport_resolver::SceneViewportResolver;
use prometeu_hal::tile::Tile;
use prometeu_hal::tilemap::TileMap;
use prometeu_hal::{FrameId, Gfx2dCommand};
use prometeu_hal::{
BoundScenePacket, Camera2D, ComposerFramePacket, FrameId, GameSpritePacket, Gfx2dCommand,
};
fn make_glyph_bank() -> GlyphBank {
let mut bank = GlyphBank::new(TileSize::Size8, 8, 8);
@ -292,4 +294,42 @@ mod tests {
assert_eq!(hardware.gfx.front_buffer()[0], Color::BLUE.raw());
}
#[test]
fn publish_game2d_submission_uses_packet_scene_and_sprites_not_live_frame_state() {
let banks = Arc::new(MemoryBanks::new());
banks.install_glyph_bank(0, Arc::new(make_glyph_bank()));
banks.install_scene_bank(0, Arc::new(make_scene_with_glyph_asset_id(0)));
let mut hardware = Hardware::new_with_memory_banks(banks);
let mut glyph_slots = [None; 16];
glyph_slots[0] = Some(0);
hardware.assets.glyph_asset_slot_index().rebuild_from_slots(&glyph_slots);
assert!(hardware.bind_scene(0));
let packet = Game2DFramePacket::new(
ComposerFramePacket {
bound_scene: Some(BoundScenePacket { bank_id: 0 }),
camera: Camera2D::default(),
sprites: vec![GameSpritePacket {
glyph_id: 0,
palette_id: 0,
x: 0,
y: 0,
layer: 0,
bank_id: 0,
flip_x: false,
flip_y: false,
priority: 0,
}],
hud: Default::default(),
},
Vec::new(),
);
hardware.begin_frame();
hardware.publish_render_submission(&RenderSubmission::game2d(FrameId::ZERO, packet));
assert_eq!(hardware.gfx.front_buffer()[0], Color::RED.raw());
}
}

View File

@ -41,13 +41,6 @@ fn asm(s: &str) -> Vec<u8> {
pub fn generate() -> Result<()> {
let mut rom: Vec<u8> = Vec::new();
let syscalls = vec![
SyscallDecl {
module: "gfx2d".into(),
name: "clear".into(),
version: 1,
arg_slots: 1,
ret_slots: 0,
},
SyscallDecl {
module: "gfx2d".into(),
name: "draw_text".into(),
@ -143,17 +136,15 @@ fn heavy_load(rom: &mut Vec<u8>) {
let jif_bind_done_offset = rom.len() + 2;
rom.extend(asm("JMP_IF_FALSE 0"));
rom.extend(asm("PUSH_I32 0\nHOSTCALL 3\nPOP_N 1\nPUSH_I32 1\nSET_GLOBAL 1"));
rom.extend(asm("PUSH_I32 0\nHOSTCALL 2\nPOP_N 1\nPUSH_I32 1\nSET_GLOBAL 1"));
let bind_done_target = rom.len() as u32;
rom.extend(asm("PUSH_I32 0\nHOSTCALL 0"));
let scene_width_px = (STRESS_SCENE_TILE_W * 8) as i32;
let scene_height_px = (STRESS_SCENE_TILE_H * 8) as i32;
let camera_x_span = scene_width_px - STRESS_VIEWPORT_W;
let camera_y_span = scene_height_px - STRESS_VIEWPORT_H;
rom.extend(asm(&format!(
"GET_GLOBAL 0\nPUSH_I32 2\nMUL\nPUSH_I32 {camera_x_span}\nMOD\nGET_GLOBAL 0\nPUSH_I32 {camera_y_span}\nMOD\nHOSTCALL 4"
"GET_GLOBAL 0\nPUSH_I32 2\nMUL\nPUSH_I32 {camera_x_span}\nMOD\nGET_GLOBAL 0\nPUSH_I32 {camera_y_span}\nMOD\nHOSTCALL 3"
)));
rom.extend(asm("PUSH_I32 0\nSET_LOCAL 0"));
@ -178,7 +169,7 @@ fn heavy_load(rom: &mut Vec<u8>) {
GET_LOCAL 1\nGET_GLOBAL 0\nADD\nPUSH_I32 1\nBIT_AND\nPUSH_I32 0\nNEQ\n\
GET_LOCAL 0\nGET_GLOBAL 0\nADD\nPUSH_I32 1\nBIT_AND\nPUSH_I32 0\nNEQ\n\
GET_LOCAL 0\nGET_LOCAL 1\nADD\nPUSH_I32 4\nMOD\n\
HOSTCALL 5\nPOP_N 1"
HOSTCALL 4\nPOP_N 1"
)));
rom.extend(asm("GET_LOCAL 1\nPUSH_I32 1\nADD\nSET_LOCAL 1"));
@ -195,27 +186,27 @@ fn heavy_load(rom: &mut Vec<u8>) {
PUSH_I32 8\n\
PUSH_CONST 0\n\
GET_GLOBAL 0\nPUSH_I32 2047\nMUL\nPUSH_I32 65535\nBIT_AND\n\
HOSTCALL 1"));
HOSTCALL 0"));
rom.extend(asm("PUSH_I32 16\n\
GET_GLOBAL 0\nPUSH_I32 2\nMUL\nPUSH_I32 186\nMOD\nPUSH_I32 32\nADD\n\
PUSH_CONST 1\n\
GET_GLOBAL 0\nPUSH_I32 4093\nMUL\nPUSH_I32 65535\nBIT_AND\n\
HOSTCALL 1"));
HOSTCALL 0"));
rom.extend(asm("PUSH_I32 336\n\
GET_GLOBAL 0\nPUSH_I32 5\nMUL\nPUSH_I32 194\nMOD\n\
PUSH_CONST 2\n\
GET_GLOBAL 0\nPUSH_I32 1237\nMUL\nPUSH_I32 65535\nBIT_AND\n\
HOSTCALL 1"));
HOSTCALL 0"));
rom.extend(asm("GET_GLOBAL 0\nPUSH_I32 4\nMUL\nPUSH_I32 240\nMOD\nPUSH_I32 112\nADD\n\
GET_GLOBAL 0\nPUSH_I32 3\nMUL\nPUSH_I32 120\nMOD\nPUSH_I32 88\nADD\n\
PUSH_CONST 3\n\
GET_GLOBAL 0\nPUSH_I32 3001\nMUL\nPUSH_I32 65535\nBIT_AND\n\
HOSTCALL 1"));
HOSTCALL 0"));
rom.extend(asm("GET_GLOBAL 0\nPUSH_I32 60\nMOD\nPUSH_I32 0\nEQ"));
let jif_log_offset = rom.len() + 2;
rom.extend(asm("JMP_IF_FALSE 0"));
rom.extend(asm("PUSH_I32 2\nPUSH_CONST 0\nHOSTCALL 2"));
rom.extend(asm("PUSH_I32 2\nPUSH_CONST 0\nHOSTCALL 1"));
let after_log = rom.len() as u32;
rom.extend(asm("FRAME_SYNC\nRET"));