dev/render-frame-packet-boundary #31
@ -286,6 +286,9 @@ pub enum Capability {
|
||||
None,
|
||||
System,
|
||||
Gfx,
|
||||
Composer,
|
||||
Gfx2d,
|
||||
Gfxui,
|
||||
Audio,
|
||||
Fs,
|
||||
Log,
|
||||
|
||||
@ -117,6 +117,9 @@ fn normalize_capabilities(capabilities: &[Capability]) -> Result<CapFlags, Cartr
|
||||
Capability::None => caps::NONE,
|
||||
Capability::System => caps::SYSTEM,
|
||||
Capability::Gfx => caps::GFX,
|
||||
Capability::Composer => caps::COMPOSER,
|
||||
Capability::Gfx2d => caps::GFX2D,
|
||||
Capability::Gfxui => caps::GFXUI,
|
||||
Capability::Audio => caps::AUDIO,
|
||||
Capability::Fs => caps::FS,
|
||||
Capability::Log => caps::LOG,
|
||||
|
||||
@ -18,7 +18,7 @@ pub use resolver::{
|
||||
///
|
||||
/// Each Syscall has a unique 32-bit ID. The IDs are grouped by category:
|
||||
/// - **0x0xxx**: System & OS Control
|
||||
/// - **0x1xxx**: Graphics (GFX)
|
||||
/// - **0x1xxx**: Game 2D primitives (`gfx2d`) and Shell UI primitives (`gfxui`)
|
||||
/// - **0x11xx**: Frame Composer orchestration
|
||||
/// - **0x2xxx**: Reserved for legacy input syscalls (disabled for v1 VM-owned input)
|
||||
/// - **0x3xxx**: Audio (PCM & Mixing)
|
||||
@ -37,6 +37,13 @@ pub enum Syscall {
|
||||
GfxDrawDisc = 0x1005,
|
||||
GfxDrawSquare = 0x1006,
|
||||
GfxDrawText = 0x1008,
|
||||
GfxUiClear = 0x1201,
|
||||
GfxUiFillRect = 0x1202,
|
||||
GfxUiDrawLine = 0x1203,
|
||||
GfxUiDrawCircle = 0x1204,
|
||||
GfxUiDrawDisc = 0x1205,
|
||||
GfxUiDrawSquare = 0x1206,
|
||||
GfxUiDrawText = 0x1208,
|
||||
ComposerBindScene = 0x1101,
|
||||
ComposerUnbindScene = 0x1102,
|
||||
ComposerSetCamera = 0x1103,
|
||||
|
||||
@ -2,10 +2,13 @@ use super::CapFlags;
|
||||
|
||||
pub const NONE: CapFlags = 0;
|
||||
pub const SYSTEM: CapFlags = 1 << 0;
|
||||
pub const GFX: CapFlags = 1 << 1;
|
||||
pub const COMPOSER: CapFlags = 1 << 1;
|
||||
pub const AUDIO: CapFlags = 1 << 2;
|
||||
pub const FS: CapFlags = 1 << 3;
|
||||
pub const LOG: CapFlags = 1 << 4;
|
||||
pub const ASSET: CapFlags = 1 << 5;
|
||||
pub const BANK: CapFlags = 1 << 6;
|
||||
pub const ALL: CapFlags = SYSTEM | GFX | AUDIO | FS | LOG | ASSET | BANK;
|
||||
pub const GFX2D: CapFlags = 1 << 7;
|
||||
pub const GFXUI: CapFlags = 1 << 8;
|
||||
pub const GFX: CapFlags = COMPOSER | GFX2D;
|
||||
pub const ALL: CapFlags = SYSTEM | COMPOSER | AUDIO | FS | LOG | ASSET | BANK | GFX2D | GFXUI;
|
||||
|
||||
@ -4,19 +4,19 @@ pub(crate) const ENTRIES: &[SyscallRegistryEntry] = &[
|
||||
SyscallRegistryEntry::builder(Syscall::ComposerBindScene, "composer", "bind_scene")
|
||||
.args(1)
|
||||
.rets(1)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::COMPOSER)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::ComposerUnbindScene, "composer", "unbind_scene")
|
||||
.rets(1)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::COMPOSER)
|
||||
.cost(2),
|
||||
SyscallRegistryEntry::builder(Syscall::ComposerSetCamera, "composer", "set_camera")
|
||||
.args(2)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::COMPOSER)
|
||||
.cost(2),
|
||||
SyscallRegistryEntry::builder(Syscall::ComposerEmitSprite, "composer", "emit_sprite")
|
||||
.args(9)
|
||||
.rets(1)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::COMPOSER)
|
||||
.cost(5),
|
||||
];
|
||||
|
||||
@ -1,32 +1,32 @@
|
||||
use crate::syscalls::{Syscall, SyscallRegistryEntry, caps};
|
||||
|
||||
pub(crate) const ENTRIES: &[SyscallRegistryEntry] = &[
|
||||
SyscallRegistryEntry::builder(Syscall::GfxClear, "gfx", "clear")
|
||||
SyscallRegistryEntry::builder(Syscall::GfxClear, "gfx2d", "clear")
|
||||
.args(1)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::GFX2D)
|
||||
.cost(20),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxFillRect, "gfx", "fill_rect")
|
||||
SyscallRegistryEntry::builder(Syscall::GfxFillRect, "gfx2d", "fill_rect")
|
||||
.args(5)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::GFX2D)
|
||||
.cost(20),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawLine, "gfx", "draw_line")
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawLine, "gfx2d", "draw_line")
|
||||
.args(5)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::GFX2D)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawCircle, "gfx", "draw_circle")
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawCircle, "gfx2d", "draw_circle")
|
||||
.args(4)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::GFX2D)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawDisc, "gfx", "draw_disc")
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawDisc, "gfx2d", "draw_disc")
|
||||
.args(5)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::GFX2D)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawSquare, "gfx", "draw_square")
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawSquare, "gfx2d", "draw_square")
|
||||
.args(6)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::GFX2D)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawText, "gfx", "draw_text")
|
||||
SyscallRegistryEntry::builder(Syscall::GfxDrawText, "gfx2d", "draw_text")
|
||||
.args(4)
|
||||
.caps(caps::GFX)
|
||||
.caps(caps::GFX2D)
|
||||
.cost(20),
|
||||
];
|
||||
|
||||
32
crates/console/prometeu-hal/src/syscalls/domains/gfxui.rs
Normal file
32
crates/console/prometeu-hal/src/syscalls/domains/gfxui.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use crate::syscalls::{Syscall, SyscallRegistryEntry, caps};
|
||||
|
||||
pub(crate) const ENTRIES: &[SyscallRegistryEntry] = &[
|
||||
SyscallRegistryEntry::builder(Syscall::GfxUiClear, "gfxui", "clear")
|
||||
.args(1)
|
||||
.caps(caps::GFXUI)
|
||||
.cost(20),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxUiFillRect, "gfxui", "fill_rect")
|
||||
.args(5)
|
||||
.caps(caps::GFXUI)
|
||||
.cost(20),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxUiDrawLine, "gfxui", "draw_line")
|
||||
.args(5)
|
||||
.caps(caps::GFXUI)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxUiDrawCircle, "gfxui", "draw_circle")
|
||||
.args(4)
|
||||
.caps(caps::GFXUI)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxUiDrawDisc, "gfxui", "draw_disc")
|
||||
.args(5)
|
||||
.caps(caps::GFXUI)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxUiDrawSquare, "gfxui", "draw_square")
|
||||
.args(6)
|
||||
.caps(caps::GFXUI)
|
||||
.cost(5),
|
||||
SyscallRegistryEntry::builder(Syscall::GfxUiDrawText, "gfxui", "draw_text")
|
||||
.args(4)
|
||||
.caps(caps::GFXUI)
|
||||
.cost(20),
|
||||
];
|
||||
@ -4,6 +4,7 @@ mod bank;
|
||||
mod composer;
|
||||
mod fs;
|
||||
mod gfx;
|
||||
mod gfxui;
|
||||
mod log;
|
||||
mod system;
|
||||
|
||||
@ -13,6 +14,7 @@ pub(crate) fn all_entries() -> impl Iterator<Item = &'static SyscallRegistryEntr
|
||||
system::ENTRIES
|
||||
.iter()
|
||||
.chain(gfx::ENTRIES.iter())
|
||||
.chain(gfxui::ENTRIES.iter())
|
||||
.chain(composer::ENTRIES.iter())
|
||||
.chain(audio::ENTRIES.iter())
|
||||
.chain(fs::ENTRIES.iter())
|
||||
|
||||
@ -21,6 +21,13 @@ impl Syscall {
|
||||
0x1005 => Some(Self::GfxDrawDisc),
|
||||
0x1006 => Some(Self::GfxDrawSquare),
|
||||
0x1008 => Some(Self::GfxDrawText),
|
||||
0x1201 => Some(Self::GfxUiClear),
|
||||
0x1202 => Some(Self::GfxUiFillRect),
|
||||
0x1203 => Some(Self::GfxUiDrawLine),
|
||||
0x1204 => Some(Self::GfxUiDrawCircle),
|
||||
0x1205 => Some(Self::GfxUiDrawDisc),
|
||||
0x1206 => Some(Self::GfxUiDrawSquare),
|
||||
0x1208 => Some(Self::GfxUiDrawText),
|
||||
0x1101 => Some(Self::ComposerBindScene),
|
||||
0x1102 => Some(Self::ComposerUnbindScene),
|
||||
0x1103 => Some(Self::ComposerSetCamera),
|
||||
@ -70,6 +77,13 @@ impl Syscall {
|
||||
Self::GfxDrawDisc => "GfxDrawDisc",
|
||||
Self::GfxDrawSquare => "GfxDrawSquare",
|
||||
Self::GfxDrawText => "GfxDrawText",
|
||||
Self::GfxUiClear => "GfxUiClear",
|
||||
Self::GfxUiFillRect => "GfxUiFillRect",
|
||||
Self::GfxUiDrawLine => "GfxUiDrawLine",
|
||||
Self::GfxUiDrawCircle => "GfxUiDrawCircle",
|
||||
Self::GfxUiDrawDisc => "GfxUiDrawDisc",
|
||||
Self::GfxUiDrawSquare => "GfxUiDrawSquare",
|
||||
Self::GfxUiDrawText => "GfxUiDrawText",
|
||||
Self::ComposerBindScene => "ComposerBindScene",
|
||||
Self::ComposerUnbindScene => "ComposerUnbindScene",
|
||||
Self::ComposerSetCamera => "ComposerSetCamera",
|
||||
|
||||
@ -39,23 +39,23 @@ fn every_syscall_has_metadata() {
|
||||
|
||||
#[test]
|
||||
fn resolver_returns_expected_id_for_known_identity() {
|
||||
let id = resolve_syscall("gfx", "clear", 1).expect("known identity must resolve");
|
||||
let id = resolve_syscall("gfx2d", "clear", 1).expect("known identity must resolve");
|
||||
assert_eq!(id.id, 0x1001);
|
||||
assert_eq!(id.meta.module, "gfx");
|
||||
assert_eq!(id.meta.module, "gfx2d");
|
||||
assert_eq!(id.meta.name, "clear");
|
||||
assert_eq!(id.meta.version, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolver_rejects_unknown_identity() {
|
||||
let res = resolve_syscall("gfx", "nonexistent", 1);
|
||||
let res = resolve_syscall("gfx2d", "nonexistent", 1);
|
||||
assert!(res.is_none());
|
||||
|
||||
let requested = [SyscallIdentity { module: "gfx", name: "nonexistent", version: 1 }];
|
||||
let requested = [SyscallIdentity { module: "gfx2d", name: "nonexistent", version: 1 }];
|
||||
let err = resolve_program_syscalls(&requested, 0).unwrap_err();
|
||||
match err {
|
||||
LoadError::UnknownSyscall { module, name, version } => {
|
||||
assert_eq!(module, "gfx");
|
||||
assert_eq!(module, "gfx2d");
|
||||
assert_eq!(name, "nonexistent");
|
||||
assert_eq!(version, 1);
|
||||
}
|
||||
@ -65,23 +65,23 @@ fn resolver_rejects_unknown_identity() {
|
||||
|
||||
#[test]
|
||||
fn resolver_rejects_removed_legacy_gfx_set_sprite_identity() {
|
||||
assert!(resolve_syscall("gfx", "set_sprite", 1).is_none());
|
||||
assert!(resolve_syscall("gfx2d", "set_sprite", 1).is_none());
|
||||
|
||||
let requested = [SyscallIdentity { module: "gfx", name: "set_sprite", version: 1 }];
|
||||
let requested = [SyscallIdentity { module: "gfx2d", name: "set_sprite", version: 1 }];
|
||||
let err = resolve_program_syscalls(&requested, caps::ALL).unwrap_err();
|
||||
assert_eq!(
|
||||
err,
|
||||
LoadError::UnknownSyscall { module: "gfx".into(), name: "set_sprite".into(), version: 1 }
|
||||
LoadError::UnknownSyscall { module: "gfx2d".into(), name: "set_sprite".into(), version: 1 }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolver_enforces_capabilities() {
|
||||
let requested = [SyscallIdentity { module: "gfx", name: "clear", version: 1 }];
|
||||
let requested = [SyscallIdentity { module: "gfx2d", name: "clear", version: 1 }];
|
||||
let err = resolve_program_syscalls(&requested, 0).unwrap_err();
|
||||
match err {
|
||||
LoadError::MissingCapability { required, provided, module, name, version } => {
|
||||
assert_eq!(module, "gfx");
|
||||
assert_eq!(module, "gfx2d");
|
||||
assert_eq!(name, "clear");
|
||||
assert_eq!(version, 1);
|
||||
assert_ne!(required, 0);
|
||||
@ -90,15 +90,30 @@ fn resolver_enforces_capabilities() {
|
||||
_ => panic!("expected MissingCapability error"),
|
||||
}
|
||||
|
||||
let ok = resolve_program_syscalls(&requested, caps::GFX).expect("must resolve with caps");
|
||||
let ok = resolve_program_syscalls(&requested, caps::GFX2D).expect("must resolve with caps");
|
||||
assert_eq!(ok.len(), 1);
|
||||
assert_eq!(ok[0].id, 0x1001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolver_exposes_split_render_capabilities() {
|
||||
let composer = resolve_syscall("composer", "bind_scene", 1).expect("composer resolves");
|
||||
assert_eq!(composer.meta.caps, caps::COMPOSER);
|
||||
|
||||
let gfx2d = resolve_syscall("gfx2d", "clear", 1).expect("gfx2d resolves");
|
||||
assert_eq!(gfx2d.meta.caps, caps::GFX2D);
|
||||
|
||||
let gfxui = resolve_syscall("gfxui", "clear", 1).expect("gfxui resolves");
|
||||
assert_eq!(gfxui.id, 0x1201);
|
||||
assert_eq!(gfxui.meta.caps, caps::GFXUI);
|
||||
|
||||
assert!(resolve_syscall("gfx", "clear", 1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn declared_resolver_returns_expected_id_for_known_identity() {
|
||||
let declared = [prometeu_bytecode::SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -106,7 +121,7 @@ fn declared_resolver_returns_expected_id_for_known_identity() {
|
||||
}];
|
||||
|
||||
let ok =
|
||||
resolve_declared_program_syscalls(&declared, caps::GFX).expect("must resolve with ABI");
|
||||
resolve_declared_program_syscalls(&declared, caps::GFX2D).expect("must resolve with ABI");
|
||||
assert_eq!(ok.len(), 1);
|
||||
assert_eq!(ok[0].id, 0x1001);
|
||||
}
|
||||
@ -114,18 +129,18 @@ fn declared_resolver_returns_expected_id_for_known_identity() {
|
||||
#[test]
|
||||
fn declared_resolver_rejects_unknown_identity() {
|
||||
let declared = [prometeu_bytecode::SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "nonexistent".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 0,
|
||||
}];
|
||||
|
||||
let err = resolve_declared_program_syscalls(&declared, caps::GFX).unwrap_err();
|
||||
let err = resolve_declared_program_syscalls(&declared, caps::GFX2D).unwrap_err();
|
||||
assert_eq!(
|
||||
err,
|
||||
DeclaredLoadError::UnknownSyscall {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "nonexistent".into(),
|
||||
version: 1,
|
||||
}
|
||||
@ -135,7 +150,7 @@ fn declared_resolver_rejects_unknown_identity() {
|
||||
#[test]
|
||||
fn declared_resolver_rejects_missing_capability() {
|
||||
let declared = [prometeu_bytecode::SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -146,9 +161,9 @@ fn declared_resolver_rejects_missing_capability() {
|
||||
assert_eq!(
|
||||
err,
|
||||
DeclaredLoadError::MissingCapability {
|
||||
required: caps::GFX,
|
||||
required: caps::GFX2D,
|
||||
provided: caps::NONE,
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
}
|
||||
@ -158,18 +173,18 @@ fn declared_resolver_rejects_missing_capability() {
|
||||
#[test]
|
||||
fn declared_resolver_rejects_abi_mismatch() {
|
||||
let declared = [prometeu_bytecode::SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_line".into(),
|
||||
version: 1,
|
||||
arg_slots: 4,
|
||||
ret_slots: 0,
|
||||
}];
|
||||
|
||||
let err = resolve_declared_program_syscalls(&declared, caps::GFX).unwrap_err();
|
||||
let err = resolve_declared_program_syscalls(&declared, caps::GFX2D).unwrap_err();
|
||||
assert_eq!(
|
||||
err,
|
||||
DeclaredLoadError::AbiMismatch {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_line".into(),
|
||||
version: 1,
|
||||
declared_arg_slots: 4,
|
||||
@ -386,7 +401,7 @@ fn declared_resolver_accepts_mixed_status_first_surface_as_a_single_module() {
|
||||
];
|
||||
|
||||
let resolved =
|
||||
resolve_declared_program_syscalls(&declared, caps::GFX | caps::AUDIO | caps::ASSET)
|
||||
resolve_declared_program_syscalls(&declared, caps::COMPOSER | caps::AUDIO | caps::ASSET)
|
||||
.expect("mixed status-first surface must resolve together");
|
||||
|
||||
assert_eq!(resolved.len(), declared.len());
|
||||
|
||||
@ -188,6 +188,17 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
||||
hw.gfx_mut().clear(color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxUiClear => {
|
||||
if self.current_cartridge_app_mode != AppMode::Shell {
|
||||
return Err(VmFault::Trap(
|
||||
TRAP_INVALID_SYSCALL,
|
||||
format!("{} is only available to the Shell profile", syscall.name()),
|
||||
));
|
||||
}
|
||||
let color = self.get_color(expect_int(args, 0)?)?;
|
||||
hw.gfx_mut().clear(color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxFillRect => {
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
@ -197,6 +208,21 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
||||
hw.gfx_mut().fill_rect(x, y, w, h, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxUiFillRect => {
|
||||
if self.current_cartridge_app_mode != AppMode::Shell {
|
||||
return Err(VmFault::Trap(
|
||||
TRAP_INVALID_SYSCALL,
|
||||
format!("{} is only available to the Shell profile", syscall.name()),
|
||||
));
|
||||
}
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
let w = expect_int(args, 2)? as i32;
|
||||
let h = expect_int(args, 3)? as i32;
|
||||
let color = self.get_color(expect_int(args, 4)?)?;
|
||||
hw.gfx_mut().fill_rect(x, y, w, h, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxDrawLine => {
|
||||
let x1 = expect_int(args, 0)? as i32;
|
||||
let y1 = expect_int(args, 1)? as i32;
|
||||
@ -206,6 +232,21 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
||||
hw.gfx_mut().draw_line(x1, y1, x2, y2, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxUiDrawLine => {
|
||||
if self.current_cartridge_app_mode != AppMode::Shell {
|
||||
return Err(VmFault::Trap(
|
||||
TRAP_INVALID_SYSCALL,
|
||||
format!("{} is only available to the Shell profile", syscall.name()),
|
||||
));
|
||||
}
|
||||
let x1 = expect_int(args, 0)? as i32;
|
||||
let y1 = expect_int(args, 1)? as i32;
|
||||
let x2 = expect_int(args, 2)? as i32;
|
||||
let y2 = expect_int(args, 3)? as i32;
|
||||
let color = self.get_color(expect_int(args, 4)?)?;
|
||||
hw.gfx_mut().draw_line(x1, y1, x2, y2, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxDrawCircle => {
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
@ -214,6 +255,20 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
||||
hw.gfx_mut().draw_circle(x, y, r, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxUiDrawCircle => {
|
||||
if self.current_cartridge_app_mode != AppMode::Shell {
|
||||
return Err(VmFault::Trap(
|
||||
TRAP_INVALID_SYSCALL,
|
||||
format!("{} is only available to the Shell profile", syscall.name()),
|
||||
));
|
||||
}
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
let r = expect_int(args, 2)? as i32;
|
||||
let color = self.get_color(expect_int(args, 3)?)?;
|
||||
hw.gfx_mut().draw_circle(x, y, r, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxDrawDisc => {
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
@ -223,6 +278,21 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
||||
hw.gfx_mut().draw_disc(x, y, r, border_color, fill_color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxUiDrawDisc => {
|
||||
if self.current_cartridge_app_mode != AppMode::Shell {
|
||||
return Err(VmFault::Trap(
|
||||
TRAP_INVALID_SYSCALL,
|
||||
format!("{} is only available to the Shell profile", syscall.name()),
|
||||
));
|
||||
}
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
let r = expect_int(args, 2)? as i32;
|
||||
let border_color = self.get_color(expect_int(args, 3)?)?;
|
||||
let fill_color = self.get_color(expect_int(args, 4)?)?;
|
||||
hw.gfx_mut().draw_disc(x, y, r, border_color, fill_color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxDrawSquare => {
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
@ -233,6 +303,22 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
||||
hw.gfx_mut().draw_square(x, y, w, h, border_color, fill_color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxUiDrawSquare => {
|
||||
if self.current_cartridge_app_mode != AppMode::Shell {
|
||||
return Err(VmFault::Trap(
|
||||
TRAP_INVALID_SYSCALL,
|
||||
format!("{} is only available to the Shell profile", syscall.name()),
|
||||
));
|
||||
}
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
let w = expect_int(args, 2)? as i32;
|
||||
let h = expect_int(args, 3)? as i32;
|
||||
let border_color = self.get_color(expect_int(args, 4)?)?;
|
||||
let fill_color = self.get_color(expect_int(args, 5)?)?;
|
||||
hw.gfx_mut().draw_square(x, y, w, h, border_color, fill_color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxDrawText => {
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
@ -241,6 +327,20 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
||||
hw.gfx_mut().draw_text(x, y, &msg, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::GfxUiDrawText => {
|
||||
if self.current_cartridge_app_mode != AppMode::Shell {
|
||||
return Err(VmFault::Trap(
|
||||
TRAP_INVALID_SYSCALL,
|
||||
format!("{} is only available to the Shell profile", syscall.name()),
|
||||
));
|
||||
}
|
||||
let x = expect_int(args, 0)? as i32;
|
||||
let y = expect_int(args, 1)? as i32;
|
||||
let msg = expect_string(args, 2, "message")?;
|
||||
let color = self.get_color(expect_int(args, 3)?)?;
|
||||
hw.gfx_mut().draw_text(x, y, &msg, color);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::ComposerBindScene => {
|
||||
let scene_bank_id = match Self::int_arg_to_usize_status(expect_int(args, 0)?) {
|
||||
Ok(id) => id,
|
||||
|
||||
@ -195,7 +195,7 @@ fn initialize_vm_applies_cartridge_capabilities_before_loader_resolution() {
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -221,7 +221,7 @@ fn initialize_vm_succeeds_when_cartridge_capabilities_cover_hostcalls() {
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -253,7 +253,7 @@ fn tick_returns_error_when_vm_ends_slice_with_trap() {
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -304,7 +304,7 @@ fn tick_system_profile_rejects_gfx_game_surface() {
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -388,6 +388,55 @@ fn tick_system_profile_rejects_composer_game_surface() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_game_profile_rejects_gfxui_shell_surface() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut log_service = LogService::new(4096);
|
||||
let mut fs = VirtualFS::new();
|
||||
let mut fs_state = FsState::Unmounted;
|
||||
let mut memcard = MemcardService::new();
|
||||
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||
let mut next_handle = 1;
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfxui".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 0,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program_and_mode(program, caps::GFXUI, AppMode::Game);
|
||||
|
||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime
|
||||
.tick(
|
||||
&mut log_service,
|
||||
&mut fs,
|
||||
&mut fs_state,
|
||||
&mut memcard,
|
||||
&mut open_files,
|
||||
&mut next_handle,
|
||||
&mut vm,
|
||||
&signals,
|
||||
&mut hardware,
|
||||
)
|
||||
.expect("game gfxui call must trap");
|
||||
|
||||
match report {
|
||||
CrashReport::VmTrap { trap } => {
|
||||
assert_eq!(trap.code, prometeu_bytecode::TRAP_INVALID_SYSCALL);
|
||||
assert!(trap.message.contains("GfxUiClear is only available to the Shell profile"));
|
||||
}
|
||||
other => panic!("expected VmTrap crash report, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_system_profile_rejects_bank_game_surface() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
@ -655,7 +704,7 @@ fn tick_draw_text_survives_no_scene_frame_path() {
|
||||
code,
|
||||
vec![ConstantPoolEntry::String("I".into())],
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_text".into(),
|
||||
version: 1,
|
||||
arg_slots: 4,
|
||||
@ -696,7 +745,7 @@ fn initialize_vm_success_clears_previous_crash_report() {
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -856,7 +905,7 @@ fn initialize_vm_failure_clears_previous_identity_and_handles() {
|
||||
let good_program = serialized_single_function_module(
|
||||
assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble"),
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -878,7 +927,7 @@ fn initialize_vm_failure_clears_previous_identity_and_handles() {
|
||||
let bad_program = serialized_single_function_module(
|
||||
assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble"),
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
|
||||
@ -2707,7 +2707,7 @@ mod tests {
|
||||
let bytes = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -2733,7 +2733,7 @@ mod tests {
|
||||
let bytes = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -2765,14 +2765,14 @@ mod tests {
|
||||
code,
|
||||
vec![
|
||||
SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 0,
|
||||
},
|
||||
SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_text".into(),
|
||||
version: 1,
|
||||
arg_slots: 4,
|
||||
@ -2788,7 +2788,7 @@ mod tests {
|
||||
Err(VmInitError::LoaderPatchFailed(
|
||||
crate::vm_init_error::LoaderPatchError::UnusedSyscallDecl {
|
||||
sysc_index: 1,
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_text".into(),
|
||||
version: 1,
|
||||
},
|
||||
@ -2805,7 +2805,7 @@ mod tests {
|
||||
let bytes = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -2835,7 +2835,7 @@ mod tests {
|
||||
let bytes = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "missing".into(),
|
||||
version: 1,
|
||||
arg_slots: 0,
|
||||
@ -2850,7 +2850,7 @@ mod tests {
|
||||
Err(VmInitError::LoaderPatchFailed(
|
||||
crate::vm_init_error::LoaderPatchError::ResolveFailed(
|
||||
prometeu_hal::syscalls::DeclaredLoadError::UnknownSyscall {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "missing".into(),
|
||||
version: 1,
|
||||
},
|
||||
@ -2868,7 +2868,7 @@ mod tests {
|
||||
let bytes = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
@ -2883,9 +2883,9 @@ mod tests {
|
||||
Err(VmInitError::LoaderPatchFailed(
|
||||
crate::vm_init_error::LoaderPatchError::ResolveFailed(
|
||||
prometeu_hal::syscalls::DeclaredLoadError::MissingCapability {
|
||||
required: prometeu_hal::syscalls::caps::GFX,
|
||||
required: prometeu_hal::syscalls::caps::GFX2D,
|
||||
provided: prometeu_hal::syscalls::caps::NONE,
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
},
|
||||
@ -2903,7 +2903,7 @@ mod tests {
|
||||
let bytes = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_line".into(),
|
||||
version: 1,
|
||||
arg_slots: 4,
|
||||
@ -2918,7 +2918,7 @@ mod tests {
|
||||
Err(VmInitError::LoaderPatchFailed(
|
||||
crate::vm_init_error::LoaderPatchError::ResolveFailed(
|
||||
prometeu_hal::syscalls::DeclaredLoadError::AbiMismatch {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_line".into(),
|
||||
version: 1,
|
||||
declared_arg_slots: 4,
|
||||
|
||||
@ -42,14 +42,14 @@ pub fn generate() -> Result<()> {
|
||||
let mut rom: Vec<u8> = Vec::new();
|
||||
let syscalls = vec![
|
||||
SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "clear".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 0,
|
||||
},
|
||||
SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
module: "gfx2d".into(),
|
||||
name: "draw_text".into(),
|
||||
version: 1,
|
||||
arg_slots: 4,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{"type":"meta","next_id":{"DSC":39,"AGD":39,"DEC":31,"PLN":87,"LSN":47,"CLSN":1}}
|
||||
{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0035","status":"done","ticket":"task-owned-shell-windows","title":"Agenda - Task-Owned Shell Windows","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","task","window-manager","shell","lifecycle"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0044","file":"discussion/lessons/DSC-0035-task-owned-shell-windows/LSN-0044-task-window-liveness-belongs-to-the-task.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
||||
{"type":"discussion","id":"DSC-0034","status":"done","ticket":"system-os-domain-facades","title":"Agenda - SystemOS Domain Facades","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","services","api-surface","lifecycle","fs"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0043","file":"discussion/lessons/DSC-0034-system-os-domain-facades/LSN-0043-systemos-domain-facades.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
||||
{"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"discussion/lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
id: PLN-0076
|
||||
ticket: render-frame-packet-boundary
|
||||
title: Capabilities and ABI Domain Split
|
||||
status: open
|
||||
status: done
|
||||
created: 2026-05-25
|
||||
ref_decisions: [DEC-0030]
|
||||
tags: [gfx, renderer, runtime, frame-composer, architecture, ui, pipeline]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user