From 88ac752d9e79d4a49b46ed32c265e353d63532aa Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Fri, 22 May 2026 09:07:10 +0100 Subject: [PATCH 01/10] moved app_mode to its own file --- crates/console/prometeu-drivers/src/gfx.rs | 2 +- .../src/firmware/firmware.rs | 3 +- .../firmware/firmware_step_load_cartridge.rs | 3 +- crates/console/prometeu-hal/src/app_mode.rs | 7 + crates/console/prometeu-hal/src/cartridge.rs | 7 +- .../prometeu-hal/src/debugger_protocol.rs | 2 +- crates/console/prometeu-hal/src/lib.rs | 1 + .../prometeu-system/src/os/facades/vm.rs | 3 +- .../src/services/vm_runtime/dispatch.rs | 2 +- .../src/services/vm_runtime/mod.rs | 2 +- .../prometeu-host-desktop-winit/src/input.rs | 15 +- discussion/index.ndjson | 2 +- .../AGD-0036-prometeu-hub-ui-direction.md | 193 ------------------ ...ometeu-hub-initial-retro-shell-ui-slice.md | 153 -------------- ...ative-shell-launch-and-lifecycle-wiring.md | 107 ---------- ...-0063-hub-mouse-input-and-click-routing.md | 89 -------- ...N-0064-retro-hub-home-and-fake-shell-ui.md | 100 --------- ...LN-0065-pixel-operator-font-integration.md | 103 ---------- ...0066-hub-ui-slice-validation-and-lesson.md | 114 ----------- .../config/runtime-edge-coverage-domains.json | 2 +- 20 files changed, 24 insertions(+), 886 deletions(-) create mode 100644 crates/console/prometeu-hal/src/app_mode.rs delete mode 100644 discussion/workflow/agendas/AGD-0036-prometeu-hub-ui-direction.md delete mode 100644 discussion/workflow/decisions/DEC-0028-prometeu-hub-initial-retro-shell-ui-slice.md delete mode 100644 discussion/workflow/plans/PLN-0062-native-shell-launch-and-lifecycle-wiring.md delete mode 100644 discussion/workflow/plans/PLN-0063-hub-mouse-input-and-click-routing.md delete mode 100644 discussion/workflow/plans/PLN-0064-retro-hub-home-and-fake-shell-ui.md delete mode 100644 discussion/workflow/plans/PLN-0065-pixel-operator-font-integration.md delete mode 100644 discussion/workflow/plans/PLN-0066-hub-ui-slice-validation-and-lesson.md diff --git a/crates/console/prometeu-drivers/src/gfx.rs b/crates/console/prometeu-drivers/src/gfx.rs index 8cc86272..6fca0a2f 100644 --- a/crates/console/prometeu-drivers/src/gfx.rs +++ b/crates/console/prometeu-drivers/src/gfx.rs @@ -908,7 +908,7 @@ impl Gfx { let col_start = (-x).clamp(0, glyph_w) as usize; let col_end = (screen_w - x).clamp(0, glyph_w) as usize; - for row_idx in row_start..row_end { + for (row_idx, _) in glyph.iter().enumerate().take(row_end).skip(row_start) { let row = glyph[row_idx]; let py = (y + row_idx as i32) as usize; let base = py * self.w; diff --git a/crates/console/prometeu-firmware/src/firmware/firmware.rs b/crates/console/prometeu-firmware/src/firmware/firmware.rs index e97659f0..3679f393 100644 --- a/crates/console/prometeu-firmware/src/firmware/firmware.rs +++ b/crates/console/prometeu-firmware/src/firmware/firmware.rs @@ -175,7 +175,8 @@ mod tests { use prometeu_bytecode::assembler::assemble; use prometeu_bytecode::model::{BytecodeModule, FunctionMeta, SyscallDecl}; use prometeu_drivers::hardware::Hardware; - use prometeu_hal::cartridge::{AppMode, AssetsPayloadSource}; + use prometeu_hal::app_mode::AppMode; + use prometeu_hal::cartridge::AssetsPayloadSource; use prometeu_hal::color::Color; use prometeu_hal::primitives::Rect; use prometeu_hal::syscalls::caps; diff --git a/crates/console/prometeu-firmware/src/firmware/firmware_step_load_cartridge.rs b/crates/console/prometeu-firmware/src/firmware/firmware_step_load_cartridge.rs index b9d033c3..e8b1351e 100644 --- a/crates/console/prometeu-firmware/src/firmware/firmware_step_load_cartridge.rs +++ b/crates/console/prometeu-firmware/src/firmware/firmware_step_load_cartridge.rs @@ -2,7 +2,8 @@ use crate::firmware::firmware_state::{ AppCrashesStep, FirmwareState, GameRunningStep, ShellRunningStep, }; use crate::firmware::prometeu_context::PrometeuContext; -use prometeu_hal::cartridge::{AppMode, Cartridge}; +use prometeu_hal::app_mode::AppMode; +use prometeu_hal::cartridge::Cartridge; use prometeu_hal::color::Color; use prometeu_hal::log::{LogLevel, LogSource}; use prometeu_hal::primitives::Rect; diff --git a/crates/console/prometeu-hal/src/app_mode.rs b/crates/console/prometeu-hal/src/app_mode.rs new file mode 100644 index 00000000..01f35f08 --- /dev/null +++ b/crates/console/prometeu-hal/src/app_mode.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +pub enum AppMode { + Game, + Shell, +} diff --git a/crates/console/prometeu-hal/src/cartridge.rs b/crates/console/prometeu-hal/src/cartridge.rs index 8fa72386..42c7f735 100644 --- a/crates/console/prometeu-hal/src/cartridge.rs +++ b/crates/console/prometeu-hal/src/cartridge.rs @@ -1,3 +1,4 @@ +use crate::app_mode::AppMode; use crate::asset::{AssetEntry, PreloadEntry}; use crate::syscalls::CapFlags; use serde::{Deserialize, Serialize}; @@ -10,12 +11,6 @@ pub const ASSETS_PA_MAGIC: [u8; 4] = *b"ASPA"; pub const ASSETS_PA_SCHEMA_VERSION: u32 = 1; pub const ASSETS_PA_PRELUDE_SIZE: usize = 32; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] -pub enum AppMode { - Game, - Shell, -} - #[derive(Debug, Clone)] pub struct Cartridge { pub app_id: u32, diff --git a/crates/console/prometeu-hal/src/debugger_protocol.rs b/crates/console/prometeu-hal/src/debugger_protocol.rs index cc6e8950..e6428be7 100644 --- a/crates/console/prometeu-hal/src/debugger_protocol.rs +++ b/crates/console/prometeu-hal/src/debugger_protocol.rs @@ -1,4 +1,4 @@ -use crate::cartridge::AppMode; +use crate::app_mode::AppMode; use prometeu_bytecode::Value; use serde::{Deserialize, Serialize}; diff --git a/crates/console/prometeu-hal/src/lib.rs b/crates/console/prometeu-hal/src/lib.rs index 2e603b6b..fe0cd2e9 100644 --- a/crates/console/prometeu-hal/src/lib.rs +++ b/crates/console/prometeu-hal/src/lib.rs @@ -1,3 +1,4 @@ +pub mod app_mode; pub mod asset; pub mod asset_bridge; pub mod audio_bridge; diff --git a/crates/console/prometeu-system/src/os/facades/vm.rs b/crates/console/prometeu-system/src/os/facades/vm.rs index 4f38d314..1cf284b3 100644 --- a/crates/console/prometeu-system/src/os/facades/vm.rs +++ b/crates/console/prometeu-system/src/os/facades/vm.rs @@ -1,6 +1,7 @@ use crate::CrashReport; use crate::os::SystemOS; -use prometeu_hal::cartridge::{AppMode, Cartridge}; +use prometeu_hal::app_mode::AppMode; +use prometeu_hal::cartridge::Cartridge; use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame}; use prometeu_hal::{HardwareBridge, InputSignals}; use prometeu_vm::VirtualMachine; diff --git a/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs b/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs index e73c2d03..6ddf9bb2 100644 --- a/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs +++ b/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs @@ -2,8 +2,8 @@ use super::*; use crate::fs::{FsState, VirtualFS}; use crate::services::memcard::{MemcardService, MemcardSlotState, MemcardStatus}; use prometeu_bytecode::{TRAP_INVALID_SYSCALL, TRAP_OOB, TRAP_TYPE, Value}; +use prometeu_hal::app_mode::AppMode; use prometeu_hal::asset::{AssetId, AssetOpStatus, BankType, SlotRef}; -use prometeu_hal::cartridge::AppMode; use prometeu_hal::color::Color; use prometeu_hal::glyph::Glyph; use prometeu_hal::log::{LogLevel, LogSource}; diff --git a/crates/console/prometeu-system/src/services/vm_runtime/mod.rs b/crates/console/prometeu-system/src/services/vm_runtime/mod.rs index 8ecf6a5b..19e55af7 100644 --- a/crates/console/prometeu-system/src/services/vm_runtime/mod.rs +++ b/crates/console/prometeu-system/src/services/vm_runtime/mod.rs @@ -6,7 +6,7 @@ mod tick; use crate::CrashReport; use prometeu_bytecode::string_materialization_count; -use prometeu_hal::cartridge::AppMode; +use prometeu_hal::app_mode::AppMode; use prometeu_hal::log::LogService; use prometeu_hal::telemetry::{AtomicTelemetry, CertificationConfig, Certifier}; use prometeu_vm::VirtualMachine; diff --git a/crates/host/prometeu-host-desktop-winit/src/input.rs b/crates/host/prometeu-host-desktop-winit/src/input.rs index 53f71c62..ea58835e 100644 --- a/crates/host/prometeu-host-desktop-winit/src/input.rs +++ b/crates/host/prometeu-host-desktop-winit/src/input.rs @@ -38,13 +38,7 @@ impl FbViewport { let viewport_x = ((win_w - viewport_w) * 0.5).floor(); let viewport_y = ((win_h - viewport_h) * 0.5).floor(); - Some(FbViewport { - x: viewport_x, - y: viewport_y, - w: viewport_w, - h: viewport_h, - scale, - }) + Some(FbViewport { x: viewport_x, y: viewport_y, w: viewport_w, h: viewport_h, scale }) } } @@ -126,10 +120,7 @@ impl HostInputHandler { let fb_x = (local_x / viewport.scale).floor() as i32; let fb_y = (local_y / viewport.scale).floor() as i32; - Some(( - fb_x.clamp(0, Hardware::W as i32 - 1), - fb_y.clamp(0, Hardware::H as i32 - 1), - )) + Some((fb_x.clamp(0, Hardware::W as i32 - 1), fb_y.clamp(0, Hardware::H as i32 - 1))) } } -} \ No newline at end of file +} diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 74bc40e3..f23e712e 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -34,4 +34,4 @@ {"type":"discussion","id":"DSC-0031","status":"done","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0040","file":"discussion/lessons/DSC-0031-runtime-mode-separation-game-system/LSN-0040-system-pipeline-separation.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]} {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} -{"type":"discussion","id":"DSC-0036","status":"in_progress","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[{"id":"AGD-0036","file":"AGD-0036-prometeu-hub-ui-direction.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15"}],"decisions":[{"id":"DEC-0028","file":"DEC-0028-prometeu-hub-initial-retro-shell-ui-slice.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15","ref_agenda":"AGD-0036"}],"plans":[{"id":"PLN-0062","file":"PLN-0062-native-shell-launch-and-lifecycle-wiring.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0063","file":"PLN-0063-hub-mouse-input-and-click-routing.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0064","file":"PLN-0064-retro-hub-home-and-fake-shell-ui.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0065","file":"PLN-0065-pixel-operator-font-integration.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]},{"id":"PLN-0066","file":"PLN-0066-hub-ui-slice-validation-and-lesson.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0028"]}],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} +{"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} diff --git a/discussion/workflow/agendas/AGD-0036-prometeu-hub-ui-direction.md b/discussion/workflow/agendas/AGD-0036-prometeu-hub-ui-direction.md deleted file mode 100644 index 7b00eacf..00000000 --- a/discussion/workflow/agendas/AGD-0036-prometeu-hub-ui-direction.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -id: AGD-0036 -ticket: prometeu-hub-ui-direction -title: Agenda - Prometeu Hub UI Direction -status: accepted -created: 2026-05-15 -resolved: -decision: -tags: [hub, ui, shell, system-apps, lifecycle, design-system] ---- - -## Contexto - -O Prometeu Hub esta entrando em uma etapa em que a Shell precisa deixar de ser apenas uma superficie funcional e passar a expressar uma identidade visual propria do Prometeu OS. - -A direcao desejada e uma UI retro/minimalista inspirada em console portatil, fantasy console e Homebrew Channel: baixa resolucao, tipografia pixelada, poucos tons, bordas marcadas, componentes simples, leitura clara e navegacao confortavel por controle. - -O alvo inicial nao e criar um toolkit completo. A etapa deve estabelecer a linguagem visual e um conjunto pequeno de componentes suficientes para validar a Home do Hub e o fluxo de lifecycle ja construido. - -Componentes iniciais esperados: - -- Channel/Card -- Button -- Panel -- Tabs -- List -- Status bar -- Footer/help bar -- Focus highlight - -O Hub deve continuar respeitando a arquitetura atual: - -- Hub renderiza e navega. -- Hub emite acao. -- SystemOS/Firmware executa lifecycle, task, process e window. - -Portanto, a UI do Hub nao deve manipular diretamente VM, process/task lifecycle ou window ownership fora das facades do SystemOS. - -## Problema - -A ausencia de uma direcao visual clara cria risco de o Hub virar uma UI desktop/mobile generica ou um conjunto de componentes sem coesao. Ao mesmo tempo, tentar resolver um design system completo agora pode atrasar a validacao do fluxo mais importante: Home -> abrir app Shell nativo fake -> fechar app -> retornar ao Hub. - -O problema central e definir o primeiro contrato de direcao da UI: qual experiencia visual e interativa sera validada agora, quais componentes fazem parte do primeiro corte, e quais limites arquiteturais nao podem ser atravessados pela implementacao da Shell. - -## Pontos Criticos - -- A estetica retro precisa melhorar legibilidade e identidade, nao apenas adicionar decoracao. -- A baixa resolucao deve ser tratada como linguagem de composicao, escala e foco, sem comprometer leitura. -- Navegacao por controle precisa ser primeira classe: foco visivel, ordem previsivel e acoes claras. -- A Home precisa listar canais/apps e acionar apps sem assumir posse do lifecycle. -- Apps nativos fake devem existir para validar janela, retorno, fechamento e estado de foco, mas nao devem virar arquitetura definitiva de apps. -- Os componentes iniciais devem ser pequenos o bastante para evoluir depois para um toolkit, mas nao acoplados prematuramente a um toolkit completo. -- O Hub nao pode atravessar as facades do SystemOS para manipular VM, process/task lifecycle ou ownership de window. - -## Opcoes - -### Opcao A - Slice visual minimo dentro do Hub - -Criar uma primeira Home retro consistente diretamente no Hub, com componentes locais simples e dois apps Shell nativos fake para validar navegacao, abertura, fechamento e retorno. - -**Tradeoffs:** - -- Pro: entrega rapidamente a experiencia desejada e valida o fluxo real de Shell/lifecycle. -- Pro: evita desenhar um toolkit abstrato antes de entender as necessidades concretas. -- Contra: pode gerar componentes locais que precisarao ser extraidos ou reorganizados depois. -- Risco: se os componentes nao tiverem limites claros, a implementacao pode misturar visual, navegacao e chamadas de lifecycle. - -### Opcao B - Definir um mini toolkit antes da Home - -Criar primeiro um modulo formal de componentes retro do Hub, depois construir a Home sobre ele. - -**Tradeoffs:** - -- Pro: melhora consistencia e reaproveitamento desde o inicio. -- Pro: facilita testes isolados de componentes e futuras telas do sistema. -- Contra: aumenta escopo antes de validar a experiencia principal. -- Risco: o toolkit pode cristalizar abstracoes erradas antes de haver uso suficiente. - -### Opcao C - Prototipo descartavel de UI antes de integrar lifecycle - -Criar uma tela visual isolada, focada apenas em look and feel, sem acoplar ainda ao fluxo de lifecycle, tasks, process e windows. - -**Tradeoffs:** - -- Pro: permite iterar visualmente com baixo risco arquitetural. -- Pro: reduz chance de alterar indevidamente SystemOS durante exploracao visual. -- Contra: nao valida a parte mais importante do Hub como Shell operacional. -- Risco: o prototipo pode parecer aprovado visualmente, mas falhar quando integrado ao fluxo real. - -## Sugestao / Recomendacao - -Seguir pela Opcao A, mas com escopo reduzido pelas respostas da agenda: implementar um slice visual minimo dentro do Hub, com Home manual em 270p, dois botoes clicaveis e dois apps Shell nativos fake. - -A recomendacao e tratar essa etapa como uma direcao de Shell, nao como toolkit completo. O primeiro objetivo deve ser uma Home visualmente consistente que prove: - -- dois botoes manuais para abrir ShellA e ShellB; -- ShellA como app/janela verde simples; -- ShellB como app/janela azul simples; -- abertura de app via acao emitida pelo Hub e executada pelo SystemOS/Firmware; -- fechamento de app como comando da propria app/janela; -- retorno ao Hub apos fechamento; -- estilo retro/minimalista consistente em viewport 270p; -- uso de mouse/click como input inicial; -- respeito estrito ao limite Hub -> SystemOS facade. - -A extracao para toolkit, a lista/grid de canais, Tabs, Status bar e Footer/help bar devem ficar para waves futuras, guiadas por uso real dos componentes. - -## Perguntas em Aberto - -- [x] A Home deve priorizar grid de canais, lista vertical, ou alternar entre os dois via Tabs? na verdade eu tinha pensado em montar os dois shell fakes na mao mesmo, sem lista de canais e coisas mais sofisticadas -- [x] Qual resolucao logica deve orientar a composicao visual desta UI: a viewport interna atual do runtime, uma escala propria do Hub, ou uma convencao derivada da Shell? a viewport toda, 270p. -- [x] A fonte pixelada sera um asset proprio, uma fonte embutida existente, ou uma simulacao inicial via estilo/render atual? podemos ir de proprio mas temos um asset pronto em `assets/pixel_operator.zip` -- [x] Quais dois apps Shell nativos fake devem existir neste primeiro corte? ShellA e ShellB, uma simples tela verde e outro tela azul. -- [x] O fechamento de app deve ser exposto como comando da app, comando global da Shell, ou ambos? na primeira wave comando da app. toda app vai ser embrulhada em uma janela controle (como no windows) -- [x] O footer/help bar deve mapear acoes de controle de forma fixa ou depender do item/app focado? o footer fica para uma proxima wave -- [x] A navegacao inicial precisa suportar apenas controle/teclado, ou tambem mouse para debug/host desktop? vamos usar o mouse primeiramente (como clique) -- [x] Quais facades do SystemOS ja sao suficientes para abrir/fechar/retornar, e quais lacunas precisam virar trabalho separado? eu acredito que estamos bem com session e lifecycle, qq coisa a gente vai implementando no caminho - -## Criterio para Encerrar - -Esta agenda pode ser encerrada quando houver acordo sobre: - -- direcao visual inicial da Shell; -- escopo exato da Home e dos dois apps fake; -- componentes minimos do primeiro corte; -- comportamento esperado de foco/navegacao; -- fronteira operacional entre Hub UI e SystemOS/Firmware; -- se a implementacao deve seguir como slice local do Hub ou exigir uma decisao separada para toolkit. - -Com essas respostas, a agenda deve virar uma decisao normativa antes de qualquer plano ou edicao de codigo. - -## Discussao - -Entrada inicial: a UI deve ter aparencia de sistema embarcado/fantasy console, proxima em espirito a Switch/Homebrew Channel, mas com estetica propria de console retro. O objetivo pratico e inaugurar a identidade visual do Prometeu OS validando a Home do Hub e o lifecycle de apps Shell nativos fake. - -### Analise apos respostas iniciais - -As respostas mudam o primeiro corte de "Home com grid/lista de canais" para uma wave menor e mais direta: uma Shell/Home manual, em 270p, com dois apps nativos fake montados na mao. Isso reduz bastante o risco de criar um toolkit cedo demais. - -O escopo recomendado para a primeira wave passa a ser: - -- Hub em tela cheia 270p, com linguagem retro/minimalista consistente; -- dois affordances clicaveis para ShellA e ShellB, sem lista de canais generica; -- ShellA como janela/tela verde simples; -- ShellB como janela/tela azul simples; -- fonte pixelada propria usando o asset `assets/pixel_operator.zip`, se o pipeline de asset/font permitir sem abrir outro problema arquitetural; -- fechamento como comando da propria app/janela; -- mouse/click como input inicial; -- footer/help bar fora da primeira wave. - -Isso enfraquece a necessidade de `Tabs`, `List`, `Status bar` e `Footer/help bar` no primeiro corte. Eles podem continuar como direcao de linguagem, mas nao devem ser criterios de aceite da wave inicial. Os componentes realmente necessarios agora sao: - -- Panel ou frame de janela; -- Button/click target; -- Focus/hover/active highlight, mesmo que inicialmente guiado por mouse; -- Channel/Card apenas se os dois atalhos manuais da Home forem desenhados como cards. - -Sobre as facades do SystemOS, o codigo atual ja tem pecas importantes: - -- `os.sessions().create_native_shell_task(app_id, title)` cria process/task de Shell nativo e coloca a task em foreground. -- `os.lifecycle().close_task(task_id)` fecha task e marca o processo como stopped. -- `os.windows().add_window(...)`, `set_focus(...)`, `close_window(...)` e `focused_window_belongs_to_task(...)` permitem registrar, focar e observar janelas. -- `ShellRunningStep` ja retorna ao Hub quando a task fecha ou quando a janela focada nao pertence mais a task. - -Mas a superficie ainda nao esta ideal para o contrato da agenda: - -- o Hub atual cria janelas diretamente como `WindowOwner::Hub`, nao como `WindowOwner::Task(task_id)`; -- `PrometeuHub::update_shell_profile` retorna apenas crash, entao nao ha ainda um resultado explicito tipo "launch ShellA/ShellB" para o Firmware transicionar para `ShellRunningStep(task_id)`; -- `sessions().create_native_shell_task` cria task/process, mas nao cria uma janela owned-by-task em uma unica operacao de alto nivel; -- `WindowFacade::remove_all_windows()` e `WindowOwner` exposto no Hub facilitam um corte rapido, mas tambem permitem a UI atravessar demais o contrato de ownership se virarem padrao; -- fechar apenas a janela nao e semanticamente igual a fechar a app; para Shell nativa, o comando de fechar deve terminar em `lifecycle().close_task(task_id)`, e a janela deve ser removida como consequencia operacional ou mantida coerente pela mesma facade. - -Sugestao para fechar a lacuna sem criar toolkit: - -- manter a UI local no Hub; -- introduzir um resultado de Hub mais explicito, por exemplo `HubAction::LaunchNativeShell { app_id, title, kind }` ou equivalente, em vez de o Hub executar tudo diretamente; -- deixar Firmware/SystemOS criar a task nativa via `sessions().create_native_shell_task`; -- criar a janela com `WindowOwner::Task(task_id)` no mesmo fluxo de launch, preferencialmente por uma facade de sessao/janela de nivel mais alto, para nao espalhar ownership manual no Hub; -- fazer o comando de fechar da app chamar `lifecycle().close_task(task_id)` ou emitir uma acao equivalente para o SystemOS, nao apenas remover a janela; -- manter `ShellRunningStep` como responsavel pelo retorno ao Hub quando a task fechar. - -Com isso, a arquitetura continua: Hub renderiza/navega e emite acao; SystemOS/Firmware executa lifecycle, task, process e window. - -### Pontos que ainda precisam de resposta - -- Confirmar se a primeira wave deve abandonar completamente grid/lista/tabs/footer, ou apenas deixar isso fora dos criterios de aceite. -- nao vamos nos ater no componentes nessa wave, mas caso seja necessario, podemos criar alguns. -- Confirmar se a Home manual tera dois cards/botoes clicaveis para ShellA/ShellB ou se as janelas fake aparecem direto na Home. -- Um btn para cada shell. -- Confirmar se `assets/pixel_operator` deve ser extraido/registrado como asset de fonte nesta wave ou se pode entrar como follow-up caso o pipeline de fonte nao esteja pronto. -- jah estah extraido -- Confirmar se a decisao deve exigir uma nova facade de alto nivel para launch de Shell nativa com janela owned-by-task, ou se o plano pode aceitar um uso transitorio de `sessions()` + `windows()` desde que fique encapsulado fora dos componentes visuais. -- vamos tentar usar o que temos. - -## Resolucao - -Validada para decisao, pendente apenas de confirmacao explicita para aceitar a agenda e iniciar o artefato de decisao. diff --git a/discussion/workflow/decisions/DEC-0028-prometeu-hub-initial-retro-shell-ui-slice.md b/discussion/workflow/decisions/DEC-0028-prometeu-hub-initial-retro-shell-ui-slice.md deleted file mode 100644 index c7b5da5f..00000000 --- a/discussion/workflow/decisions/DEC-0028-prometeu-hub-initial-retro-shell-ui-slice.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -id: DEC-0028 -ticket: prometeu-hub-ui-direction -title: Prometeu Hub Initial Retro Shell UI Slice -status: accepted -created: 2026-05-15 -ref_agenda: AGD-0036 -tags: [hub, ui, shell, system-apps, lifecycle, design-system] ---- - -## Context - -AGD-0036 resolved the first visual direction for Prometeu Hub after the runtime gained the basic SystemOS, lifecycle, task, process, and task-owned window contracts. - -The target is not a general UI toolkit yet. The target is the first executable Hub/Shell UI slice that establishes the Prometeu OS visual identity and validates the existing lifecycle flow with native fake Shell apps. - -The accepted agenda narrowed the original "channel grid/list" idea into a smaller wave: - -- a manual Hub/Home surface rendered in the full 270p viewport; -- two clickable entries, one for `ShellA` and one for `ShellB`; -- `ShellA` as a simple green native Shell fake app; -- `ShellB` as a simple blue native Shell fake app; -- mouse/click input first; -- app close initiated from the app/window itself; -- no Footer/help bar, Tabs, generic List, or complete Channel/Card system in this wave; -- use of the existing SystemOS session, lifecycle, and window facades unless implementation proves a narrower helper is required. - -The decision depends on the existing operating model captured by the related lessons: - -- System apps belong to the Runtime/Hub system pipeline, not the game pipeline. -- SystemOS owns lifecycle semantics. -- SystemOS owns shared OS services through domain facades. -- Shell window liveness is tied to a task-owned focused window. - -## Decision - -Prometeu Hub SHALL implement the first retro Shell UI as a narrow, local Hub slice rather than a reusable UI toolkit. - -The first slice SHALL provide a full-viewport 270p Hub/Home with a retro/minimalist visual style inspired by portable console and fantasy-console UI: low-resolution composition, pixel-style typography, limited color use, strong borders, simple panels, and clear clickable affordances. - -The first Hub/Home SHALL expose exactly two manual launch buttons: - -- `ShellA` -- `ShellB` - -The first slice SHALL launch two native fake Shell apps: - -- `ShellA` SHALL render as a simple green app/window. -- `ShellB` SHALL render as a simple blue app/window. - -The first slice SHALL use mouse/click input as the initial navigation and activation mechanism. Controller-first focus navigation MAY be added later, but it is not part of this decision's first acceptance surface. - -The first slice SHALL treat app close as an app/window command. Closing a Shell app MUST result in the corresponding Shell task being closed through SystemOS lifecycle semantics and returning to Hub/Home. - -The first slice MUST NOT introduce a complete UI toolkit, generic app catalog, channel grid, Tabs, List, Status bar, or Footer/help bar. Small local primitives such as button, panel/frame, text drawing, hover/active highlight, and simple window chrome MAY be created when needed to implement the slice. - -The Hub MUST remain a visual Shell/Home program: - -- Hub SHALL render and handle local UI navigation. -- Hub SHALL emit user-intent actions such as "launch ShellA", "launch ShellB", or "close current Shell app". -- SystemOS/Firmware SHALL execute lifecycle, task, process, and window ownership effects. -- Hub MUST NOT directly own VM execution, task/process lifecycle policy, or final window ownership semantics outside SystemOS facades. - -The implementation SHOULD first attempt to use the existing `sessions()`, `lifecycle()`, and `windows()` facades. A new high-level facade is not required by this decision, but if implementation starts duplicating cross-domain launch/close policy in Hub components, the plan MUST introduce a small SystemOS/Firmware helper instead of spreading that policy through visual code. - -## Rationale - -This decision keeps the first UI wave small enough to execute while still validating the important architecture. - -Building a complete toolkit now would force abstractions before there are enough Hub surfaces to justify them. A local slice lets the project discover real component needs from a concrete Home and two Shell apps. - -Skipping lifecycle integration would validate only aesthetics and would not prove the console OS model. The first UI slice must exercise the route from Hub/Home to a native Shell task, task-owned window liveness, app close, lifecycle close, and return to Hub. - -Starting with mouse/click is acceptable because this wave is primarily about visual identity and lifecycle integration. Controller navigation remains part of the broader Hub direction, but making it a hard requirement now would expand the first slice beyond the accepted agenda. - -Using the existing facades respects the current architecture and avoids inventing a new OS API prematurely. The guardrail is that the Hub may compose calls at a local boundary, but visual components must not become lifecycle or ownership authorities. - -## Invariants / Contract - -- The internal composition target for this UI slice is the current 270p viewport. -- `assets/pixel_operator.zip` or its already-extracted content SHOULD be used for pixel-style typography when the existing rendering/font path can support it without unrelated architecture work. -- `ShellA` and `ShellB` are fake native Shell apps for lifecycle and UI validation. They MUST NOT be treated as a final app model or plugin/catalog contract. -- A launched Shell app MUST have task/process state created through SystemOS session/lifecycle pathways. -- A Shell app window used for liveness MUST be owned by `WindowOwner::Task(task_id)`, not by `WindowOwner::Hub`. -- Returning to Hub after app close MUST follow lifecycle closure. Removing a window alone is not a valid app-close semantic. -- The first wave MAY use local Hub UI primitives. Those primitives MUST remain scoped to the slice until a later decision defines a shared toolkit. -- Game cartridges MUST NOT be pulled into this windowed Shell model by implication. This decision applies to native fake Shell apps only. - -## Impacts - -### Specs - -No canonical runtime spec change is required before the first implementation unless the plan introduces a new public SystemOS, Shell, or asset/font contract. If a new public contract is introduced, the canonical specs must be updated in English. - -### Runtime / SystemOS - -Implementation may need small integration work around native Shell launch and task-owned windows. The preferred path is: - -1. Hub emits a launch intent for `ShellA` or `ShellB`. -2. Firmware/SystemOS creates the native Shell task through `sessions().create_native_shell_task(...)`. -3. The launch flow creates/focuses a window owned by `WindowOwner::Task(task_id)`. -4. `ShellRunningStep` drives the Shell app and returns to Hub when lifecycle/window liveness says the app is closed. - -If this cannot be expressed cleanly with current facades, the plan may add a narrow helper/facade that coordinates session creation and task-owned window creation. - -### Hub UI - -The Hub UI should be reshaped from the current button-to-window debug surface into a first-person Shell/Home surface with: - -- retro background/panel treatment; -- two clickable launch buttons; -- simple hover/active visual state for mouse input; -- app/window chrome sufficient to expose close from the app/window; -- clear visual distinction between Hub/Home and an opened Shell app. - -### Host / Input - -The first wave relies on existing host mouse mapping/click input if available. Keyboard/controller focus is not required by this decision. - -### Firmware - -Firmware remains the coordinator for state transitions between Hub/Home and Shell-running state. It must not delegate lifecycle authority to visual components. - -### Tooling / Tests - -Tests should cover the behavior that matters architecturally: - -- launch `ShellA` creates a native Shell task and task-owned window; -- launch `ShellB` creates a native Shell task and task-owned window; -- closing the app closes lifecycle state rather than only removing the window; -- closed Shell returns to Hub/Home; -- Hub UI actions do not require direct task/process manager access. - -## Propagation Targets - -- specs: only if a new public Shell/SystemOS/font contract is introduced. -- plans: create an execution plan from this decision before code changes. -- code: `crates/console/prometeu-system`, `crates/console/prometeu-firmware`, and possibly host/input/rendering code if mouse/font integration requires it. -- tests: SystemOS/Firmware tests for launch/close/return behavior; UI rendering tests only if the repository already has an appropriate surface. -- docs: post-execution lesson in English after the implementation is complete. - -## References - -- Agenda: AGD-0036 -- `LSN-0040` - System Pipeline Separation -- `LSN-0041` - SystemOS Lifecycle Authority -- `LSN-0042` - SystemOS Service Ownership Boundary -- `LSN-0043` - SystemOS Domain Facades -- `LSN-0044` - Task Window Liveness Belongs to the Task - -## Revision Log - -- 2026-05-15: Initial decision draft from AGD-0036. diff --git a/discussion/workflow/plans/PLN-0062-native-shell-launch-and-lifecycle-wiring.md b/discussion/workflow/plans/PLN-0062-native-shell-launch-and-lifecycle-wiring.md deleted file mode 100644 index 12e98a9d..00000000 --- a/discussion/workflow/plans/PLN-0062-native-shell-launch-and-lifecycle-wiring.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -id: PLN-0062 -ticket: prometeu-hub-ui-direction -title: Native Shell Launch and Lifecycle Wiring -status: done -created: 2026-05-15 -ref_decisions: [DEC-0028] -tags: [hub, ui, shell, system-apps, lifecycle, design-system] ---- - -## Briefing - -Implement the OS/Firmware wiring required by `DEC-0028` so the Hub can emit a launch intent for `ShellA` or `ShellB`, and SystemOS/Firmware can create a native Shell task, create a task-owned window, run the Shell state, close through lifecycle, and return to Hub/Home. - -Source decision: `DEC-0028`. - -## Objective - -Make the launch/close path architecturally correct before the visual slice depends on it: - -- Hub emits launch intent. -- SystemOS/Firmware creates native Shell task/process. -- The Shell app has a `WindowOwner::Task(task_id)` window. -- Close uses `os.lifecycle().close_task(task_id)`. -- `ShellRunningStep` returns to Hub/Home after close. - -## Dependencies - -- `DEC-0028` must remain accepted. -- This plan should execute before `PLN-0064`, because the UI buttons need a real launch target. -- This plan may execute before or alongside `PLN-0063` if tests can trigger Hub actions without mouse input. - -## Scope - -- Update the Hub update result shape so it can report launch/close actions, not only crashes. -- Add native fake Shell app identity for `ShellA` and `ShellB`. -- Wire Firmware/SystemOS launch handling from Hub intent to `sessions().create_native_shell_task(...)`. -- Create and focus a task-owned window for the launched native Shell task. -- Ensure app close routes to lifecycle close, not only window removal. -- Preserve the existing task-owned window liveness rule in `ShellRunningStep`. - -## Non-Goals - -- No generic app catalog. -- No reusable UI toolkit. -- No game cartridge window model. -- No background/minimize/overlay preservation semantics. -- No controller focus navigation. -- No public spec change unless implementation introduces a new public API. - -## Execution Method - -1. Inspect current launch state. - - What changes: identify the exact update path from `HubHomeStep` to `PrometeuHub::update_shell_profile` and `ShellRunningStep`. - - How: read the current firmware state transitions and Hub update result. - - Files: `crates/console/prometeu-firmware/src/firmware/firmware_step_hub_home.rs`, `crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs`, `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`. - -2. Replace crash-only Hub output with an action-bearing result. - - What changes: extend or replace `SystemProfileUpdate` so it can carry `LaunchNativeShell(ShellA|ShellB)` and close intent while preserving crash reporting. - - How: add a small enum local to the Hub/system profile boundary; keep visual components free of lifecycle mutation. - - Files: `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs` and firmware call sites. - -3. Handle launch in Firmware/SystemOS. - - What changes: when Hub emits launch intent, create the native Shell task through `os.sessions().create_native_shell_task(app_id, title)`. - - How: map `ShellA` and `ShellB` to stable local app ids/titles for this fake-app slice. - - Files: `crates/console/prometeu-firmware/src/firmware/firmware_step_hub_home.rs`; add helper code in `prometeu-system` only if needed to avoid duplication. - -4. Create the task-owned Shell window. - - What changes: after task creation, create and focus a window with `WindowOwner::Task(task_id)`. - - How: use the existing window facade first; introduce a narrow helper only if the launch sequence becomes duplicated or leaks into visual components. - - Files: `crates/console/prometeu-system/src/os/facades/sessions.rs`, `crates/console/prometeu-system/src/os/facades/window.rs`, or firmware step depending on the smallest clean integration point. - -5. Route close through lifecycle. - - What changes: app/window close must call `os.lifecycle().close_task(task_id)` or emit an equivalent action handled by Firmware/SystemOS. - - How: keep window removal separate from lifecycle semantics; do not treat `close_window` as app close. - - Files: `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`, `crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs`. - -6. Add behavior tests. - - What changes: add tests proving launch creates native Shell task/window and close returns to Hub. - - How: test at SystemOS/Firmware boundary rather than only manager internals. - - Files: existing firmware/system test modules, preferably near current lifecycle/window tests. - -## Acceptance Criteria - -- [x] Launching `ShellA` creates a native Shell task/process. -- [x] Launching `ShellB` creates a native Shell task/process. -- [x] Each launched Shell app receives a focused `WindowOwner::Task(task_id)` window. -- [x] Closing the Shell app closes lifecycle state through `os.lifecycle().close_task(task_id)`. -- [x] Closing the Shell app returns firmware to `HubHome`. -- [x] Hub visual code does not directly mutate task/process managers. -- [x] Existing shell liveness behavior remains intact. - -## Tests - -- Unit tests for any new Hub action enum or mapping logic. -- SystemOS tests for any new helper/facade that creates native Shell task plus task-owned window. -- Firmware tests for HubHome launch to ShellRunning and ShellRunning close to HubHome. -- Regression tests for `focused_window_belongs_to_task(task_id)` behavior if touched. - -## Affected Artifacts - -- `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs` -- `crates/console/prometeu-firmware/src/firmware/firmware_step_hub_home.rs` -- `crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs` -- `crates/console/prometeu-system/src/os/facades/sessions.rs` -- `crates/console/prometeu-system/src/os/facades/window.rs` -- Existing SystemOS/Firmware tests diff --git a/discussion/workflow/plans/PLN-0063-hub-mouse-input-and-click-routing.md b/discussion/workflow/plans/PLN-0063-hub-mouse-input-and-click-routing.md deleted file mode 100644 index 6d967108..00000000 --- a/discussion/workflow/plans/PLN-0063-hub-mouse-input-and-click-routing.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: PLN-0063 -ticket: prometeu-hub-ui-direction -title: Hub Mouse Input and Click Routing -status: done -created: 2026-05-15 -ref_decisions: [DEC-0028] -tags: [hub, ui, shell, system-apps, lifecycle, design-system] ---- - -## Briefing - -Implement the input path needed by `DEC-0028`: Hub/Home must support mouse/click activation for the two manual Shell launch buttons and, in Shell app view, for the app/window close command. - -Source decision: `DEC-0028`. - -## Objective - -Provide reliable 270p mouse hit testing and click routing for the initial Hub UI slice without introducing controller navigation or a generic input framework. - -## Dependencies - -- `DEC-0028` must remain accepted. -- This plan should execute before or alongside `PLN-0064`, because the visual buttons need clickable behavior. -- It depends on existing host pointer mapping if available; if unavailable, this plan must add the narrowest input bridge required for Hub clicks. - -## Scope - -- Confirm how host mouse coordinates are mapped into the internal framebuffer/viewport. -- Expose pointer position and click edge to the Hub update path. -- Add deterministic hit testing for `ShellA`, `ShellB`, and close controls. -- Preserve current game/controller input behavior. - -## Non-Goals - -- No controller focus navigation in this wave. -- No keyboard navigation beyond existing debug behavior. -- No drag/drop, resize, window move, scroll, hover menus, or double-click behavior. -- No generic retained-mode UI event system. - -## Execution Method - -1. Inspect current input bridge. - - What changes: identify existing pointer position and click signals. - - How: trace host `winit` input into HAL/runtime input signals. - - Files: `crates/host/prometeu-host-desktop-winit/src/input.rs`, HAL input signal definitions, firmware context wiring. - -2. Add or expose a minimal pointer snapshot. - - What changes: make Hub update code able to read current pointer coordinates in 270p logical space and click pressed/released edge. - - How: reuse existing `window_to_fb` mapping and input structures if present; add a small field/method only if needed. - - Files: host input module, HAL input signal structures, firmware context. - -3. Define Hub hit-test rectangles. - - What changes: create explicit rects for `ShellA`, `ShellB`, and close command. - - How: keep rect definitions close to the local Hub UI slice so visual and hit target stay synchronized. - - Files: `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`; optional local submodule if the file grows too large. - -4. Route click results to Hub actions. - - What changes: clicking `ShellA` or `ShellB` emits the launch action from `PLN-0062`; clicking close emits close intent. - - How: hit test only on click edge; avoid repeated launch while button is held. - - Files: `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`. - -5. Add tests around pure hit-test logic. - - What changes: test button rect boundaries and click-edge behavior without needing a desktop window. - - How: isolate hit-test/action selection into pure functions where practical. - - Files: Hub module tests or a local Hub UI submodule test. - -## Acceptance Criteria - -- [x] Pointer coordinates are interpreted in the internal 270p coordinate space. -- [x] Clicking the `ShellA` button emits the `ShellA` launch action exactly once per click. -- [x] Clicking the `ShellB` button emits the `ShellB` launch action exactly once per click. -- [x] Clicking the close command emits close intent for the active Shell app. -- [x] Holding the mouse button does not repeatedly launch apps. -- [x] Existing controller/game input paths are not regressed. - -## Tests - -- Unit tests for hit-test rectangles. -- Unit tests for click edge to action mapping. -- Existing host/system tests to ensure input changes compile across crates. -- Manual verification in desktop host: click `ShellA`, close, click `ShellB`, close. - -## Affected Artifacts - -- `crates/host/prometeu-host-desktop-winit/src/input.rs` -- HAL input signal definitions, if pointer data is not already exposed -- Firmware context/input plumbing, if needed -- `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs` diff --git a/discussion/workflow/plans/PLN-0064-retro-hub-home-and-fake-shell-ui.md b/discussion/workflow/plans/PLN-0064-retro-hub-home-and-fake-shell-ui.md deleted file mode 100644 index 8ee30c86..00000000 --- a/discussion/workflow/plans/PLN-0064-retro-hub-home-and-fake-shell-ui.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -id: PLN-0064 -ticket: prometeu-hub-ui-direction -title: Retro Hub Home and Fake Shell UI -status: done -created: 2026-05-15 -ref_decisions: [DEC-0028] -tags: [hub, ui, shell, system-apps, lifecycle, design-system] ---- - -## Briefing - -Implement the visible Hub/Home and fake Shell app surfaces required by `DEC-0028`: a retro/minimalist 270p Hub with two manual buttons, plus green `ShellA` and blue `ShellB` native fake app/window views. - -Source decision: `DEC-0028`. - -## Objective - -Replace the current debug-style window surface with the first Prometeu OS visual identity slice while keeping all UI primitives local and avoiding a reusable toolkit. - -## Dependencies - -- `PLN-0062` should provide the launch/close/lifecycle wiring. -- `PLN-0063` should provide click routing. -- `PLN-0065` may provide pixel font rendering; this plan must still remain executable with current text rendering if font integration is deferred. - -## Scope - -- Full 270p Hub/Home composition. -- Retro/minimalist palette, borders, panels, and two clickable launch buttons. -- Local drawing primitives for panel/frame/button/highlight only when needed. -- `ShellA` fake app view as green. -- `ShellB` fake app view as blue. -- App/window chrome with close affordance. -- Clear visual separation between Hub/Home and Shell app state. - -## Non-Goals - -- No full UI toolkit. -- No generic app catalog. -- No Tabs/List/Status bar/Footer/help bar. -- No controller focus UI. -- No production app plugin model. -- No game cartridge visual changes. - -## Execution Method - -1. Define the 270p layout constants. - - What changes: establish local coordinates for Hub background, title area, two buttons, and optional simple panel/frame. - - How: use fixed 480x270 logical viewport coordinates consistent with the runtime viewport. - - Files: `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs` or local Hub UI submodule. - -2. Add local retro drawing primitives. - - What changes: add small helper functions for panel/frame, button, highlight, and simple text placement. - - How: keep them private/local to the Hub slice; do not expose as a toolkit. - - Files: Hub module or `crates/console/prometeu-system/src/programs/prometeu_hub/` submodules. - -3. Render Hub/Home. - - What changes: draw a consistent retro/minimalist Home surface with exactly two launch buttons. - - How: use low-resolution composition, strong outlines, limited color use, and button labels `ShellA` and `ShellB`. - - Files: Hub render path. - -4. Render native fake Shell app views. - - What changes: draw `ShellA` as a green app/window and `ShellB` as a blue app/window, with a visible close command. - - How: use the task-owned window information and app identity established by `PLN-0062`. - - Files: Hub render path and any local fake-app state/mapping. - -5. Keep visual state separate from lifecycle state. - - What changes: UI code may know the current view/app identity but must not mutate lifecycle directly. - - How: return actions to the boundary defined by `PLN-0062`. - - Files: Hub update/render code. - -6. Add lightweight tests for layout/action coupling. - - What changes: ensure visible button rects match clickable rects from `PLN-0063`. - - How: put button definitions in a shared local data structure used by render and hit testing. - - Files: Hub module tests. - -## Acceptance Criteria - -- [x] Hub/Home renders full-screen in the 270p viewport. -- [x] Hub/Home shows exactly two manual launch buttons: `ShellA` and `ShellB`. -- [x] The visual style is retro/minimalist with strong borders and limited palette. -- [x] `ShellA` renders as a simple green native fake Shell app/window. -- [x] `ShellB` renders as a simple blue native fake Shell app/window. -- [x] Each Shell app view exposes a visible close command. -- [x] Local primitives are not exported as a general toolkit. -- [x] No Tabs/List/Status bar/Footer/help bar are added in this wave. - -## Tests - -- Unit tests for shared local layout/button definitions. -- Compile and runtime tests from `PLN-0062` and `PLN-0063`. -- Manual desktop verification of the full flow: Hub -> ShellA -> close -> Hub -> ShellB -> close -> Hub. -- Screenshot/manual visual check at 480x270 internal composition if repository tooling supports it. - -## Affected Artifacts - -- `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs` -- Possible local modules under `crates/console/prometeu-system/src/programs/prometeu_hub/` -- Tests colocated with Hub module diff --git a/discussion/workflow/plans/PLN-0065-pixel-operator-font-integration.md b/discussion/workflow/plans/PLN-0065-pixel-operator-font-integration.md deleted file mode 100644 index a2047fd6..00000000 --- a/discussion/workflow/plans/PLN-0065-pixel-operator-font-integration.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -id: PLN-0065 -ticket: prometeu-hub-ui-direction -title: Pixel Operator Font Integration -status: done -created: 2026-05-15 -ref_decisions: [DEC-0028] -tags: [hub, ui, shell, system-apps, lifecycle, design-system] ---- - -## Briefing - -Integrate the already-available Pixel Operator font asset into the first Hub UI slice when the existing rendering path can support it without creating a new public font system. - -Source decision: `DEC-0028`. - -## Objective - -Use pixel-style typography for the Hub/Home and fake Shell app labels while keeping font work scoped to the initial UI slice. - -## Dependencies - -- `DEC-0028` must remain accepted. -- `PLN-0064` can proceed without this plan if font integration exposes unrelated architecture work. -- The asset is expected to exist already under `assets/pixel_operator` or from `assets/pixel_operator.zip`. - -## Scope - -- Locate and verify the extracted Pixel Operator asset. -- Determine the current text rendering path available to Hub/System UI. -- Add a local font binding or asset loading path if one already fits the runtime. -- Use the font for Hub button labels and simple Shell app text. -- Document any reason this must be deferred. - -## Non-Goals - -- No general font manager unless one already exists and only needs registration. -- No text layout engine. -- No multilingual shaping. -- No public asset/font spec change unless implementation requires a durable contract. -- No dependency download. - -## Execution Method - -1. Verify the asset. - - What changes: confirm exact files and format under `assets/pixel_operator`. - - How: inspect asset directory and identify usable font/bitmap files. - - Files: `assets/pixel_operator*`. - -2. Inspect current text rendering. - - What changes: determine whether Hub can draw text through existing HAL/GFX primitives or asset-backed glyph rendering. - - How: search current text/glyph/font rendering APIs and examples. - - Files: `crates/console/prometeu-hal`, `crates/console/prometeu-system`, current asset/glyph code. - -3. Add the narrowest local integration. - - What changes: make Hub text use Pixel Operator if the path is straightforward. - - How: register/load the asset in the same style as existing assets; keep code local to Hub UI if there is no general font contract. - - Files: Hub module and asset-loading modules identified in step 2. - -4. Add fallback behavior. - - What changes: if font rendering is not currently suitable, keep the visual slice working with existing text/primitive rendering and record a follow-up. - - How: do not block `PLN-0064` on broad font architecture. - - Files: Hub module and this plan's execution notes. - -5. Validate typography use. - - What changes: button labels and simple Shell app labels render legibly in 270p. - - How: manual visual verification plus any available render tests. - - Files: Hub render path. - -## Acceptance Criteria - -- [x] Pixel Operator asset location and format are verified. -- [x] Hub text rendering uses Pixel Operator when the existing rendering path supports it. -- [x] If deferred, the reason is recorded and `PLN-0064` remains executable. -- [x] No broad font/text toolkit is introduced. -- [x] Text remains legible at 270p. - -## Tests - -- Compile tests for any asset/font binding. -- Unit tests only if new parsing/registration logic is added. -- Manual visual verification of button labels and Shell labels. - -## Affected Artifacts - -- `assets/pixel_operator*` -- `crates/console/prometeu-system/src/programs/prometeu_hub/` -- Existing HAL/GFX/asset modules if they already host font or glyph rendering - -## Execution Notes - -The asset is present under `assets/pixel-operator/` as TrueType files, including: - -- `PixelOperator.ttf` -- `PixelOperator8.ttf` -- `PixelOperatorMono.ttf` -- `PixelOperatorMono8.ttf` - -The included license is CC0 1.0 Universal. - -The current runtime text path does not have a TTF loader, font manager, glyph rasterizer, or asset-backed font registration path. Hub/System UI currently reaches text through `GfxBridge::draw_text`, backed by the built-in 3x5 bitmap glyph path in `crates/console/prometeu-drivers/src/gfx.rs`. - -Because `DEC-0028` explicitly forbids expanding this wave into a broad toolkit and this plan forbids introducing a general font manager/text engine, Pixel Operator rendering is deferred. `PLN-0064` remains executable and tested with the existing bitmap text path, which is already pixel-style and legible at 270p. diff --git a/discussion/workflow/plans/PLN-0066-hub-ui-slice-validation-and-lesson.md b/discussion/workflow/plans/PLN-0066-hub-ui-slice-validation-and-lesson.md deleted file mode 100644 index daa75453..00000000 --- a/discussion/workflow/plans/PLN-0066-hub-ui-slice-validation-and-lesson.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -id: PLN-0066 -ticket: prometeu-hub-ui-direction -title: Hub UI Slice Validation and Lesson -status: done -created: 2026-05-15 -ref_decisions: [DEC-0028] -tags: [hub, ui, shell, system-apps, lifecycle, design-system] ---- - -## Briefing - -Validate the completed `DEC-0028` implementation family, collect evidence, and prepare the post-execution lesson required by the repository workflow. - -Source decision: `DEC-0028`. - -## Objective - -Prove that the initial Hub retro Shell UI slice satisfies the accepted decision and leave the discussion workflow ready for housekeeping after implementation. - -## Dependencies - -- `PLN-0062` must be implemented. -- `PLN-0063` must be implemented or explicitly documented as unnecessary because mouse/click was already available. -- `PLN-0064` must be implemented. -- `PLN-0065` must be implemented or explicitly deferred with evidence. - -## Scope - -- Run relevant crate tests. -- Perform manual desktop verification of the end-to-end flow. -- Check that no forbidden scope leaked into implementation. -- Record evidence in plan execution notes or final implementation summary. -- Draft an English lesson after execution is complete. - -## Non-Goals - -- No new UI implementation work except small fixes required to satisfy acceptance criteria. -- No new architecture decisions. -- No lesson before code/spec state is published. -- No housekeeping until plans are done. - -## Execution Method - -1. Run automated tests. - - What changes: execute the crates affected by plans `PLN-0062` through `PLN-0065`. - - How: run targeted cargo tests for firmware/system/host crates. - - Files: test output only; no source changes unless failures expose implementation bugs. - -2. Verify end-to-end desktop behavior. - - What changes: manually exercise Hub -> ShellA -> close -> Hub -> ShellB -> close -> Hub. - - How: run the desktop host or project runner used for Hub boot, click the buttons, and observe lifecycle return. - - Files: none, unless bugs are found. - -3. Check decision compliance. - - What changes: inspect implementation against `DEC-0028` invariants. - - How: verify no toolkit, no catalog, no Tabs/List/Footer, no direct task/process manager mutation from visual components, and task-owned Shell windows. - - Files: implementation files from the prior plans. - -4. Record validation evidence. - - What changes: update the relevant plans or implementation summary with commands run, manual checks, failures, and fixes. - - How: keep evidence concise and tied to acceptance criteria. - - Files: plan artifacts if the workflow records execution notes there. - -5. Prepare post-execution lesson. - - What changes: create an English lesson only after implementation is complete and published. - - How: use `discussion-housekeep` when all plans are done; lesson should explain how to think about Hub visual slices without making lessons normative. - - Files: `discussion/lessons/DSC-0036-prometeu-hub-ui-direction/...`. - -## Acceptance Criteria - -- [x] Automated tests for affected crates pass or failures are documented as unrelated. -- [x] Manual flow passes: Hub -> ShellA -> close -> Hub. -- [x] Manual flow passes: Hub -> ShellB -> close -> Hub. -- [x] Shell windows are task-owned. -- [x] App close uses lifecycle close. -- [x] No complete UI toolkit or catalog was introduced. -- [x] Pixel font integration outcome is recorded. -- [x] A post-execution lesson is ready for housekeeping after plans are marked done. - -## Execution Notes - -Validation evidence: - -- `cargo test -p prometeu-system`: 83 passed. -- `cargo test -p prometeu-firmware`: 17 passed. -- `cargo test -p prometeu-host-desktop-winit`: 25 passed, 5 ignored. -- `discussion validate`: passed. - -The ShellA/ShellB flows were verified through firmware integration tests that -simulate Hub click input and Shell close input. A live desktop manual click -session was not run in this environment; the host crate still compiles and its -test suite passes. - -Lesson prepared: - -- `discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md` - -## Tests - -- `cargo test -p prometeu-system` -- `cargo test -p prometeu-firmware` -- `cargo test -p prometeu-host-desktop-winit` if host/input code changed -- Manual desktop host verification -- `discussion validate` after marking plans and housekeeping artifacts - -## Affected Artifacts - -- Implementation files touched by `PLN-0062` through `PLN-0065` -- `discussion/workflow/plans/PLN-0062-native-shell-launch-and-lifecycle-wiring.md` -- `discussion/workflow/plans/PLN-0063-hub-mouse-input-and-click-routing.md` -- `discussion/workflow/plans/PLN-0064-retro-hub-home-and-fake-shell-ui.md` -- `discussion/workflow/plans/PLN-0065-pixel-operator-font-integration.md` -- Future lesson under `discussion/lessons/DSC-0036-prometeu-hub-ui-direction/` diff --git a/files/config/runtime-edge-coverage-domains.json b/files/config/runtime-edge-coverage-domains.json index bd9321bc..8a4a77b4 100644 --- a/files/config/runtime-edge-coverage-domains.json +++ b/files/config/runtime-edge-coverage-domains.json @@ -40,7 +40,7 @@ ] }, "firmware": { - "baseline_percent": 72, + "baseline_percent": 80, "paths": [ "crates/console/prometeu-firmware/src/" ] From 4d5818c244751eb2e3eef9d7636e0473c30c28b7 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 19:12:53 +0100 Subject: [PATCH 02/10] RGBA8888 Framebuffer and Pixel Format Direction --- discussion/index.ndjson | 3 +- ...-framebuffer-and-pixel-format-direction.md | 763 ++++++++++++++++++ ...-rgba8888-runtime-pixel-format-contract.md | 203 +++++ ...-rgba8888-published-contracts-and-specs.md | 106 +++ ...rgba8888-color-type-hal-and-abi-surface.md | 118 +++ ...9-rgba8888-cpu-renderer-and-composition.md | 109 +++ ...888-asset-palettes-tooling-and-fixtures.md | 114 +++ ...LN-0071-rgba8888-host-presentation-path.md | 103 +++ ...sidue-removal-and-end-to-end-validation.md | 109 +++ 9 files changed, 1627 insertions(+), 1 deletion(-) create mode 100644 discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md create mode 100644 discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md create mode 100644 discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md create mode 100644 discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md create mode 100644 discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md create mode 100644 discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md create mode 100644 discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md create mode 100644 discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md diff --git a/discussion/index.ndjson b/discussion/index.ndjson index f23e712e..57896bbc 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -1,4 +1,4 @@ -{"type":"meta","next_id":{"DSC":37,"AGD":37,"DEC":29,"PLN":67,"LSN":46,"CLSN":1}} +{"type":"meta","next_id":{"DSC":38,"AGD":38,"DEC":30,"PLN":73,"LSN":46,"CLSN":1}} {"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"}]} @@ -35,3 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} +{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} diff --git a/discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md b/discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md new file mode 100644 index 00000000..b3aaf731 --- /dev/null +++ b/discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md @@ -0,0 +1,763 @@ +--- +id: AGD-0037 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: Agenda - RGBA8888 Framebuffer and Pixel Format Direction +status: accepted +created: 2026-05-22 +resolved: 2026-05-23 +decision: DEC-0029 +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Contexto + +Estamos avaliando uma possivel mudanca no Prometeu de framebuffer/cor RGB565 +para RGBA8888. + +O Prometeu hoje usa um modelo grafico baseado em blit destrutivo, framebuffer +proprio, tiles/sprites/layers, scene cache, paletas, fonte de hardware e +primitivas basicas de desenho. Historicamente, RGB565 foi escolhido para +reforcar a identidade de console 16-bit / fantasy handheld, reduzir memoria e +manter uma estetica simples. + +Agora existe pressao legitima por RGBA8888: + +- e o formato natural de muitos hosts modernos, texturas e APIs de janela; +- facilita UI mais polida, alpha real, transicoes e efeitos; +- combina melhor com a direcao do Hub estilo Homebrew Channel; +- pode reduzir conversoes no host desktop; +- abre uma ponte mais direta para backends GPU futuros. + +Ao mesmo tempo, o objetivo do Prometeu continua sendo: + +- hardware agnostico; +- barato/DIY quando possivel, mas sem manter RGB565 como contrato de + compatibilidade nesta mudanca; +- bom em portateis modernos; +- 480x270 a 60 Hz; +- estetica de fantasy console; +- Hub visualmente mais rico sem perder o modelo operacional; +- caminho futuro para pipeline grafico mais avancado. + +Direcao atual da discussao: seguir pela Opcao B. RGB565 deve sair por completo +do contrato runtime/HAL/renderer/host/asset decode desta frente. RGBA8888 deve +ser o formato unico fisico do framebuffer e tambem a representacao normal de +cor do runtime. Esta mudanca nao deve abrir compatibilidade dupla, backend +RGB565, render thread, GPU backend ou abstracao generica de pixel format. + +Esta agenda e somente analise arquitetural. Nenhum codigo deve ser alterado +como parte desta discussao. + +## Estado Atual do Codigo + +### Acoplamento direto a RGB565 + +O acoplamento central esta em `crates/console/prometeu-hal/src/color.rs`: + +- `Color(pub u16)` representa explicitamente RGB565. +- `Color::rgb(r, g, b)` quantiza componentes 8-bit para 5/6/5. +- `Color::from_raw(raw: u16)` e `Color::raw() -> u16` expõem o formato fisico. +- `Color::COLOR_KEY` e `Color::TRANSPARENT` usam magenta RGB565 como chave de + transparencia. +- `unpack_to_native` e `pack_from_native` operam nos canais 5/6/5. + +Isso significa que `Color` hoje nao e uma cor logica independente; ele e o +proprio pixel RGB565. + +### HAL e API publica de GFX + +`crates/console/prometeu-hal/src/gfx_bridge.rs` fixa RGB565 no contrato: + +- `front_buffer(&self) -> &[u16]`; +- todos os draws recebem `Color`; +- fades expõem `Color`; +- o nome de syscall `GfxClear565` reforca RGB565 no contrato VM/HAL. + +Impacto: qualquer migracao direta para `Vec` quebra a API do HAL, testes, +VM dispatch e host. + +### Buffers do renderer + +`crates/console/prometeu-drivers/src/gfx.rs` fixa o formato fisico: + +- `front: Vec`; +- `back: Vec`; +- `RenderTarget.back: &mut [u16]`; +- `front_buffer() -> &[u16]`; +- `clear`, `draw_pixel`, `draw_char`, tile draw e sprite draw escrevem `u16`; +- `present()` faz swap dos dois buffers, sem copia; +- `render_scene_from_cache()` limpa o back com `Color::BLACK.raw()`; +- tiles/sprites resolvem `Color` e gravam `color.raw()`; +- fades percorrem `&mut [u16]` e fazem blend em canais RGB565. + +O modelo destrutivo em si nao depende conceitualmente de RGB565, mas a +implementacao atual depende. + +### Host/window layer + +`crates/host/prometeu-host-desktop-winit/src/runner.rs` assume que o runtime +publica RGB565: + +- le `self.hardware.gfx.front_buffer()`; +- chama `draw_rgb565_to_rgba8(src, frame)`. + +`crates/host/prometeu-host-desktop-winit/src/utilities.rs` contem: + +- `draw_rgb565_to_rgba8(src: &[u16], dst_rgba: &mut [u8])`; +- `rgb565_to_rgb888(px: u16)`. + +Ou seja, o host `pixels` ja apresenta RGBA8, mas o runtime entrega RGB565 e o +host converte a cada redraw necessario. + +### GlyphBank, paletas, sprites e scene cache + +`crates/console/prometeu-hal/src/glyph_bank.rs` preserva uma separacao util: + +- pixels de glyph/tile sao indices `u8`; +- payload serializado usa indices 4bpp; +- runtime expande para um `u8` por pixel; +- indice 0 e reservado para transparencia; +- a tabela de paletas e `[[Color; 16]; 64]`. + +Isso acopla a resolucao final de cor a RGB565, mas nao obriga os tiles/sprites +a deixarem de ser indexados. A estrutura mais importante para preservar a +estetica fantasy console ja existe: indices + paletas limitadas. + +`crates/console/prometeu-drivers/src/asset.rs` fixa o formato serializado de +paleta: + +- `GLYPH_BANK_PALETTE_BYTES_V1 = 64 * 16 * size_of::()`; +- decode le cada cor como `u16::from_le_bytes`; +- escreve `Color(color_raw)`; +- testes e `pbxgen-stress` tambem assumem paletas RGB565 little-endian. + +O asset pipeline atual, portanto, e v1/RGB565 para paletas, mas os indices dos +tiles/sprites podem permanecer iguais. + +### Fade, blend e primitivas + +`gfx.rs` implementa blend/fade em RGB565: + +- `blend_rgb565(dst: u16, src: u16, mode: BlendMode) -> u16`; +- `apply_fade_to_buffer(back: &mut [u16], level, fade_color)`; +- `fill_rect_blend` mistura por pixel nos canais 5/6/5; +- `draw_text` e fonte de hardware escrevem cor opaca direta. + +RGBA8888 simplificaria alguns efeitos alpha, mas tambem exigiria disciplina +para nao transformar todos os draws em blend caro por pixel. + +### VM e syscall + +`crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs` usa: + +- `get_color(value: i64) -> Color` via `Color::from_raw(value as u16)`; +- `GfxClear565`, com range `0xFFFF`. + +Essa e uma fronteira importante: o PBS/VM conhece hoje o valor bruto RGB565. +Se a cor logica mudar para RGBA8888, a VM API precisa de compatibilidade ou de +uma transicao clara. + +## Problema + +O problema nao e apenas trocar `Vec` por `Vec`. + +Existem quatro conceitos misturados hoje: + +1. cor logica usada pelo runtime e HAL; +2. formato fisico do framebuffer; +3. formato serializado das paletas em `assets.pa`; +4. formato de apresentacao do host/backend. + +RGB565 hoje ocupa os quatro papeis. A direcao escolhida e remove-lo desses +papeis, aceitando a quebra coordenada de HAL, asset pipeline, testes, VM, host +e renderer como o custo da limpeza arquitetural. + +A pergunta arquitetural restante nao e mais se RGBA8888 deve substituir RGB565. +A resposta operacional e sim. A pergunta agora e como fazer essa substituicao +sem misturar a migracao de pixel format com render thread, GPU backend, +abstracao de backend, asset pipeline v2 amplo ou outras frentes. + +## Pontos Criticos + +### Identidade visual nao precisa ser formato de memoria + +O Prometeu pode continuar sendo uma maquina com estetica 16-bit mesmo usando +RGBA8888 em algum ponto do pipeline. A limitacao artistica pode morar em: + +- assets indexados; +- paletas limitadas; +- regras de composicao; +- resolucao 480x270; +- fontes/pixel art; +- ferramentas de autoria; +- validadores do asset pipeline. + +O formato fisico do framebuffer e uma decisao de implementacao, nao +necessariamente uma promessa estetica. + +### RGBA8888 como cor logica e formato fisico unico + +Um tipo `Color` semanticamente RGBA8888, ou um tipo explicito +`ColorRgba8888`, deve substituir `Color(pub u16)`: + +- representar alpha real; +- evitar quantizacao precoce; +- facilitar UI/HUB; +- alinhar com texturas modernas; +- eliminar a conversao obrigatoria RGB565 -> RGBA8 no host desktop. + +Nesta agenda, RGBA8888 nao e apenas um backend alternativo. Ele e o formato +unico fisico do framebuffer. + +### RGB565 deve sair do contrato + +RGB565 continua sendo historicamente importante, mas nao deve permanecer como +compatibilidade operacional nesta mudanca. A migracao deve remover: + +- `Color(pub u16)` como cor publica; +- `Vec` como front/back buffer; +- `front_buffer() -> &[u16]`; +- APIs `Gfx*565` ou qualquer outra superficie publica com formato RGB565 no + nome como APIs canonicas; +- paletas runtime armazenadas como `Color` RGB565; +- conversao host `draw_rgb565_to_rgba8` no caminho normal; +- helpers `blend_rgb565`, `pack_from_native`, `unpack_to_native` como base do + renderer. + +Se algum alvo futuro precisar RGB565 por hardware, isso deve ser tratado como +uma nova discussao depois, nao como requisito desta migracao. + +### O blit destrutivo pode sobreviver + +RGBA8888 nao exige scene graph, GPU obrigatoria ou renderer retained. O modelo +pode continuar: + +```text +frame state -> compose into back buffer -> present/publish +``` + +O que muda e o tipo do pixel no alvo de materializacao. + +### Evitar abrir backend abstraction nesta mudanca + +A VM nao deveria tocar diretamente no framebuffer. Ela deve produzir estado ou +pacotes imutaveis de frame, e o renderer deve ser dono exclusivo dos buffers. + +Essa direcao continua correta no longo prazo, mas esta agenda agora restringe o +escopo. A migracao RGBA8888 deve mudar o formato atual do renderer existente, +nao introduzir uma matriz de backends. Render thread, `RenderFramePacket` +formal, SDL/GPU backend e bare-metal backend ficam fora deste corte. + +O limite pragmatico: a VM/HAL nao deve expor buffer mutavel direto, mas a +implementacao deste passo pode continuar com o renderer CPU destrutivo atual, +apenas migrado para RGBA8888. + +## Trade-offs Numericos + +Resolucao interna atual: `480x270 = 129600` pixels. + +### Memoria de framebuffer + +RGB565: + +- 2 bytes por pixel; +- 1 buffer: `259200` bytes = `253.125 KiB`; +- front + back: `518400` bytes = `506.25 KiB`. + +RGBA8888: + +- 4 bytes por pixel; +- 1 buffer: `518400` bytes = `506.25 KiB`; +- front + back: `1036800` bytes = `1012.5 KiB`. + +Conclusao: RGBA8888 dobra a memoria dos framebuffers. Em desktop isso e +irrelevante; em alvo DIY/barato pode ser significativo, mas ainda e pequeno em +termos absolutos para muitos portateis modernos. + +### Largura de banda por full-frame touch + +Um passe que toca um buffer inteiro: + +- RGB565: `253.125 KiB/frame`, cerca de `14.8 MiB/s` a 60 Hz; +- RGBA8888: `506.25 KiB/frame`, cerca de `29.7 MiB/s` a 60 Hz. + +O custo real pode multiplicar isso, porque o frame atual pode fazer: + +- clear; +- raster de layers; +- raster de sprites; +- scene fade fullscreen; +- hud fade fullscreen; +- conversao/apresentacao no host. + +No desktop atual, a conversao host RGB565 -> RGBA8 le `253.125 KiB` e escreve +`506.25 KiB` por frame convertido, cerca de `44.5 MiB/s` a 60 Hz so nessa +etapa. Um backend RGBA8888 pode eliminar essa conversao, mas so se evitar uma +copia equivalente para o frame do host. + +### CPU + +Impacto esperado por operacao: + +- opaque blit: RGBA8888 pode ser simples (`dst = src`), mas move o dobro de + bytes; pode ficar mais rapido em CPUs modernas se alinhar melhor a `u32`; +- masked blit: continua barato se entradas com alpha transparente pulam antes + de blendar; +- alpha blit: fica mais expressivo, mas custa multiplicacoes/interpolacoes por + canal se usado indiscriminadamente; +- fade: RGBA8888 usa canais 8-bit e pode ser mais simples conceitualmente, mas + ainda e passe fullscreen caro; +- fill_rect: pode ser rapido com fill de `u32`, desde que seja opaco; +- draw_text: continua opaco e simples, nao deve virar alpha blend por padrao; +- sprites: devem manter fast path indexado opaco/mascarado; alpha por sprite + deve ser opt-in; +- scene composition: deve continuar priorizando writes opacos e masked skips. + +### Bateria + +Em portateis baratos, dobrar bytes movimentados pode afetar bateria se a CPU +fizer toda composicao. Por outro lado, em portateis modernos com GPU, RGBA8888 +pode economizar conversoes e usar caminhos nativos de textura/composicao. + +Conclusao da agenda atual: aceitar o custo de memoria/banda do RGBA8888 como +preco de simplificacao e futuro visual. A arquitetura nao deve exigir GPU, mas +tambem nao deve manter RGB565 como fallback no escopo desta mudanca. + +### Simplicidade + +RGBA8888 simplifica: + +- alpha real; +- integracao com host moderno; +- efeitos UI; +- raciocinio em canais 8-bit; +- possivel upload de textura. + +RGBA8888 complica: + +- contrato atual da VM/HAL; +- asset palette v1; +- testes que comparam `u16`; +- risco de alpha blend virar caminho padrao; +- necessidade de remover RGB565 de forma coordenada, sem camada dupla de + compatibilidade. + +## Blit Destrutivo com RGBA8888 + +O modelo destrutivo continuaria valido: + +```text +clear/fill/raster tiles/raster sprites/fades/overlay -> back buffer -> present +``` + +Os caminhos rapidos precisam ser explicitos: + +1. Opaque blit: + - `dst = src`; + - usado para background, tiles totalmente opacos, fills, texto opaco e UI + sem alpha; + - deve ser o caminho dominante. + +2. Masked blit: + - se a entrada resolvida tiver alpha transparente, pula; + - caso contrario, `dst = resolved_color`; + - deve ser o caminho dominante para sprites e tiles com recorte. + +3. Alpha blit: + - `dst = src-over(dst)`; + - usado apenas quando o asset/comando declarar alpha real ou efeito; + - nao deve ser implicito para todo sprite/tile. + +Para evitar que tudo vire alpha blend caro: + +- manter assets indexados como opacos/mascarados por padrao; +- resolver paletas para RGBA; transparencia deve vir do canal alpha da entrada + resolvida, nao de um indice reservado; +- separar APIs/comandos `draw_opaque`, `draw_masked`, `draw_alpha`; +- manter `BlendMode` classico como efeito opt-in; +- medir alpha paths separadamente; +- nao usar RGBA8888 como desculpa para tratar cada pixel como translucido. + +## Compatibilidade com Asset Pipeline + +Tiles/sprites podem continuar indexados e paletizados. + +Recomendacao conceitual: + +- `pixel_indices: Vec` permanece; +- indices de paleta sao indices comuns; transparencia vem do canal alpha da + entrada RGBA8888 resolvida; +- limites 16 cores por paleta e 64 paletas permanecem como contrato artistico; +- paletas passam a resolver para RGBA8888; +- o payload de paleta deve deixar de ser RGB565; +- `assets.pa` e as ferramentas que geram/validam glyph banks precisam migrar + para paletas RGBA8888 no mesmo contrato desta frente. + +Isso preserva o modelo artistico indexado/paletizado, mas nao preserva +compatibilidade binaria RGB565 de paleta. + +Forma alvo: + +```text +asset palette RGBA8888 -> decode -> [[ColorRgba8888; 16]; 64] +``` + +Forma transitoria aceitavel apenas durante execucao da migracao, nao como +estado final: + +```text +old RGB565 test fixture -> one-time conversion -> RGBA8888 fixture +``` + +A decisao importante e evitar conversao por pixel a cada frame. Depois da +migracao, o renderer deve compor diretamente em RGBA8888. + +## Hardware Agnostico e Backends + +O jogo/PBS/VM nao deve saber detalhes de apresentacao do host, mas nesta agenda +nao criaremos multiplos backends de pixel format. + +Arquitetura alvo restrita desta mudanca: + +```text +VM/game tick + -> estado/comandos atuais + -> renderer CPU destrutivo compoe RGBA8888 + -> host apresenta RGBA8888 +``` + +Fora de escopo desta agenda: + +- CPU RGB565 reference backend; +- suporte simultaneo RGB565/RGBA8888; +- SDL texture backend como abstracao nova; +- OpenGL ES / wgpu GPU backend; +- bare-metal framebuffer backend; +- `FrameSurface` generico com matriz de formatos. + +O contrato publico deve parar de expor `&[u16]`. No alvo desta migracao, a +saida normal deve ser RGBA8888, por exemplo `&[u32]` ou bytes RGBA8 com ordem +explicitamente documentada. + +Se uma abstracao generica de surface for criada, ela deve ter apenas um formato +suportado inicialmente: RGBA8888. Nao deve reintroduzir RGB565 por design. + +## VM e Render Thread + +A separacao VM/render thread ajuda a migracao, mas nao deve ser feita no mesmo +passo da troca de pixel format. + +Modelo desejado: + +- VM thread executa logica, syscalls, `frame()`, estado de sprites/cenas; +- VM nao toca diretamente no framebuffer; +- VM publica pacote imutavel de frame; +- render thread e dona exclusiva do framebuffer; +- host consome frame publicado. + +Impacto na migracao para RGBA8888: + +- facilita trocar backend sem afetar VM; +- reduz disputas entre VM e blit CPU no mesmo core quando houver multicore; +- exige disciplina de snapshots e ownership; +- pode aumentar latencia se a publicacao nao for bem desenhada; +- cria uma mudanca arquitetural grande demais para misturar com color format. + +Portanto, render thread deve ficar fora desta frente. A migracao deve focar em +substituir RGB565 por RGBA8888 no renderer existente. + +## Opcoes + +### Opcao A - Manter RGB565 como framebuffer principal + +**Abordagem:** preservar `Color(pub u16)`, `Vec`, asset palettes RGB565 e +host convertendo para RGBA8. + +**Pros:** + +- menor memoria e banda; +- baixo risco; +- preserva compatibilidade com VM/HAL/testes; +- bom para bare-metal e DIY; +- alinhado com a decisao historica de performance. + +**Contras:** + +- alpha real continua ruim; +- Hub moderno fica limitado ou cheio de hacks; +- host moderno paga conversao RGB565 -> RGBA8; +- formato fisico continua confundido com identidade artistica; +- backends GPU/RGBA ficam menos naturais. + +**Manutenibilidade:** simples no curto prazo, mas tende a acumular excecoes +para UI e backend moderno. + +### Opcao B - Migrar tudo para RGBA8888 + +**Abordagem:** trocar `Color` para RGBA8888, `Gfx` para `Vec`, HAL para +`&[u32]`/RGBA, host sem conversao RGB565, paletas resolvidas em RGBA. RGB565 +deixa de existir como contrato runtime, formato de framebuffer, formato normal +de paleta ou backend de compatibilidade. + +**Pros:** + +- modelo moderno e direto; +- alpha real; +- host desktop mais natural; +- UI/HUB mais expressivo; +- caminho mais direto para GPU. +- remove a ambiguidade entre cor logica, pixel fisico e formato de host; +- reduz superficie de manutencao ao evitar suporte duplo RGB565/RGBA8888. + +**Contras:** + +- quebra grande de HAL/VM/testes/assets; +- dobra memoria dos framebuffers; +- pode piorar portateis baratos se tudo for CPU; +- remove RGB565 como caminho barato; +- exige migracao coordenada de fixtures, geradores de asset e syscalls. + +**Manutenibilidade:** direcao aceita nesta agenda. A migracao e agressiva, mas +o resultado final e mais simples porque ha um unico formato fisico e logico. + +### Opcao C - Suportar ambos via backend/pixel format desde ja + +**Abordagem:** introduzir abstracao de backend/pixel format agora, com renderer +capaz de materializar RGB565 ou RGBA8888. + +**Pros:** + +- hardware agnostico desde o inicio; +- desktop e bare-metal podem escolher formatos naturais; +- evita uma aposta unica. + +**Contras:** + +- alto risco de refatoracao ampla; +- pode criar abstracao prematura; +- `Gfx` pode virar god object; +- testes dobram; +- mistura pixel format com backend abstraction antes de consolidar cor logica. + +**Manutenibilidade:** boa se bem delimitada, ruim se virar uma matriz de +formatos espalhada pelo renderer. + +**Status nesta agenda:** rejeitada. Suporte duplo e compatibilidade RGB565 +ficam fora de escopo. + +### Opcao D - RGBA8888 como cor logica, backends RGB565/RGBA8888 como destino + +**Abordagem:** separar primeiro cor logica de formato fisico. Introduzir tipos +explicitos `ColorRgba8888` e `ColorRgb565`; preservar asset v1 e backend atual; +permitir que paletas/assets resolvam para cor logica ou para formato de backend +em caches preparados; migrar `Gfx`/host em etapas. + +**Pros:** + +- separa identidade artistica de formato de memoria; +- preserva RGB565 para targets baratos; +- prepara RGBA8888 para Hub e backends modernos; +- permite migracao incremental; +- evita mexer em render thread/GPU/asset v2 de uma vez; +- reduz confusao entre logical color e physical pixel. + +**Contras:** + +- adiciona tipos e conversoes; +- exige disciplina para nao converter por pixel no hot path; +- precisa planejar compatibilidade VM/HAL; +- pode manter dois mundos por um tempo. + +**Manutenibilidade:** melhor equilibrio se a primeira etapa for pequena e +explícita: tipos, conversoes e fronteiras; nao backend completo imediato. + +**Status nesta agenda:** rejeitada pela direcao atual. Manter RGB565 como +backend valido criaria exatamente a compatibilidade que queremos evitar. + +## Sugestao / Recomendacao + +Recomendacao atual: seguir pela Opcao B. + +Ou seja: + +- tratar RGBA8888 como formato logico e fisico unico do runtime; +- remover RGB565 por completo do contrato normal; +- preservar assets indexados/paletizados e limites artisticos; +- migrar `Gfx` para buffers RGBA8888; +- atualizar HAL, VM/syscalls, host, testes, paletas e asset tooling para + RGBA8888; +- atualizar specs, docs publicos e contratos ABI para remover RGB565, + `Gfx*565`, `u16` como contrato de cor/framebuffer e paletas RGB565; +- nao introduzir render thread, GPU backend ou abstracao multi-backend no mesmo + passo. + +A identidade 16-bit/fantasy console deve ser preservada por resolucao, +paletas, assets, regras de autoria e estilo visual, nao pelo fato de todo +framebuffer fisico ser RGB565. + +O caminho incremental mais seguro parece: + +1. Definir o tipo de cor RGBA8888 canonico: + - `Color` pode mudar para RGBA8888, ou ser substituido por + `ColorRgba8888`; + - a representacao raw deve ser `u32` ou bytes RGBA8 documentados; + - alpha `255` deve ser o default para cores opacas. + +2. Remover o contrato RGB565 do HAL/VM: + - trocar `front_buffer() -> &[u16]`; + - remover APIs de compatibilidade com sufixo de formato, como + `GfxClear565` ou qualquer superficie `Gfx*565`, e substitui-las por nomes + canonicos format-neutral, como `GfxClear`; + - atualizar validacoes de range de cor de `0xFFFF` para RGBA8888; + - atualizar testes que comparam `Color::raw()` como `u16`. + +2b. Atualizar contratos publicados: + - specs canonicas; + - docs publicos; + - contratos ABI/syscall; + - qualquer documento que ainda descreva RGB565, `Gfx*565`, `u16` como cor + ou framebuffer, ou paletas RGB565. + +3. Atualizar constantes e helpers: + - cores passam a ter representacao logica clara; + - `COLOR_KEY` deve virar semantica de transparencia/mascara, nao magenta + em RGB565. + +4. Migrar `Gfx` para RGBA8888: + - `front/back: Vec` ou storage equivalente; + - `RenderTarget` em RGBA8888; + - `blend_rgb565` substituido por blend RGBA8888; + - fade, fill, text, tile draw e sprite draw atualizados. + +5. Migrar paletas e asset tooling: + - payload de paleta deixa de ser RGB565; + - `GlyphBank.palettes` passa para RGBA8888; + - `pbxgen-stress`, fixtures e testes acompanham; + - indices de paleta deixam de carregar semantica especial de transparencia. + +6. Atualizar host/window layer: + - remover `draw_rgb565_to_rgba8` do caminho normal; + - copiar/publicar RGBA8888 para `pixels` com ordem correta; + - manter overlay compativel com frame RGBA8. + +7. Validar visual e performance: + - testes unitarios atualizados; + - testes de render/fade/blend; + - snapshots ou verificacoes visuais quando disponiveis; + - medicao de custo do novo frame RGBA8888. + +8. Deixar explicitamente para depois: + - render thread; + - GPU backend; + - backend RGB565; + - abstracao multi-formato; + - mudancas esteticas nao necessarias para a migracao. + +## Perguntas em Aberto + +- [x] Queremos declarar RGBA8888 como formato logico de cor do runtime, ou + apenas como um backend fisico adicional? RGBA8888 deve ser formato logico e + fisico unico. +- [x] A VM/PBS deve continuar aceitando valores RGB565 brutos como contrato de + compatibilidade? Nao. RGB565 nao deve permanecer como compatibilidade. +- [x] `GfxClear565` deve ganhar uma syscall nova RGBA/logical color antes de + qualquer deprecacao? Nao como API com sufixo de formato. APIs criadas para + compatibilidade RGB565, como `GfxClear565` ou qualquer superficie `Gfx*565`, + devem deixar de existir; o contrato canonico deve usar nomes format-neutral, + como `GfxClear`. +- [x] `Color` deve ser renomeado para `ColorRgb565` primeiro, ou deve mudar de + semantica para RGBA com um tipo RGB565 separado? A direcao aceita e que o + contrato final exponha RGBA8888; detalhes de rename ficam para decisao/plano. +- [x] O asset `.pa` v1 deve permanecer RGB565 ate haver necessidade de `.pa` v2? + Nao como estado final desta frente. Paletas devem migrar para RGBA8888. +- [x] Paletas carregadas devem guardar RGB565, RGBA8888, ou tabelas preparadas + por backend? RGBA8888. +- [x] Alpha real deve ser permitido em paletas, em sprites separados, ou apenas + em comandos/effects/UI por enquanto? Alpha real deve ser permitido em + qualquer paleta, sprite, tile e demais superficies/elementos que precisarem + dele. Comandos dedicados para gerenciar somente alpha serao necessarios, mas + ficam fora desta wave. +- [x] Quais operacoes podem usar alpha no primeiro corte sem comprometer custo? + Todas as operacoes podem usar alpha no primeiro corte. A direcao e tudo ou + nada; otimizacao e especializacao de caminhos ficam para depois. +- [x] O backend RGBA8888 deve ser implementado primeiro no CPU renderer ou no + host desktop? No CPU renderer existente, com host atualizado para consumir + RGBA8888. +- [x] Quais testes visuais/snapshots definem equivalencia aceitavel entre + RGB565 e RGBA8888? Como RGB565 sai, equivalencia deve ser apenas de + intencao visual/composicao, nao igualdade binaria. Todos os testes devem ser + RGBA8888-first. +- [x] A decisao antiga de `AGD-0010` contra RGBA8888 no `back` continua valida + apenas para aquela fase de performance, ou deve ser substituida por uma nova + direcao mais ampla? Deve ser substituida por nova decisao especifica desta + agenda. +- [x] Qual ordem raw deve ser canonica para `u32`/bytes: RGBA, ABGR, ARGB, ou + a ordem esperada pelo `pixels` frame? RGBA. +- [x] Alpha no framebuffer final deve ser sempre `255` apos composicao, ou o + front buffer pode publicar alpha significativo? Por enquanto, o front buffer + pode publicar alpha significativo. A diretriz deve forcar o minimo possivel + e dar liberdade ao desenvolvedor. +- [x] O asset package deve mudar versao/formato explicitamente para paletas + RGBA8888 ou apenas reinterpretar metadata existente? O asset package deve + usar paletas em formato RGBA8888, sem compatibilidade com paletas RGB565, + mesmo que isso quebre assets existentes. + +## Criterio para Encerrar + +Esta agenda pode ser encerrada quando houver acordo sobre: + +- RGBA8888 como cor logica e formato fisico unico; +- RGB565 sem papel de compatibilidade nesta frente; +- como preservar a identidade fantasy console; +- como migrar asset package, VM/HAL, host, testes e renderer; +- quais conversoes temporarias sao aceitaveis apenas durante a migracao; +- qual e a ordem incremental de substituicao; +- o que fica explicitamente fora de escopo, especialmente render thread, GPU + backend e suporte multi-formato. + +Com essas respostas, a agenda deve virar uma decisao normativa antes de +qualquer edicao de spec ou codigo. + +## Discussao + +Entrada inicial: avaliar cuidadosamente a viabilidade de migrar o Prometeu de +RGB565 para RGBA8888, considerando estado atual do codigo, trade-offs, +compatibilidade de assets, hardware agnostico, VM/render thread, plano +incremental, riscos e uma recomendacao arquitetural. + +Analise inicial, agora superada parcialmente: a migracao e viavel, mas nao +deve ser feita como troca mecanica e isolada de `u16` por `u32`. A primeira +versao da agenda considerava separar cor logica, formato fisico de framebuffer, +formato serializado de assets e formato de apresentacao do backend, preservando +RGB565 como compatibilidade. Essa preservacao nao e mais a direcao aceita. + +Atualizacao em 2026-05-23: a direcao da agenda mudou para Opcao B. RGB565 deve +sair por completo, sem compatibilidade. RGBA8888 deve ser o formato unico +fisico e logico. O escopo desta frente deve ser somente migrar RGB565 para +RGBA8888 no runtime/HAL/renderer/host/assets/testes atuais, sem abrir +multi-backend, render thread ou GPU backend. + +Atualizacao em 2026-05-23: as perguntas restantes foram fechadas. Alpha real +e permitido amplamente em paletas, sprites, tiles e demais operacoes; comandos +especificos para gerenciar somente alpha ficam fora desta wave. O primeiro +corte aceita alpha em todas as operacoes, deixando otimizacoes para depois. +Testes devem ser RGBA8888-first. A ordem raw canonica e RGBA. O front buffer +pode publicar alpha significativo por enquanto. O asset package deve usar +paletas RGBA8888 sem compatibilidade com assets RGB565 existentes. + +## Resolucao + +A agenda esta pronta para ser aceita e convertida em decisao normativa. A +direcao atual e migrar tudo para RGBA8888 como formato unico fisico e logico, +removendo RGB565 sem compatibilidade. A decisao deve cristalizar: + +- RGBA8888 como contrato logico e fisico unico; +- ordem raw canonica RGBA; +- alpha significativo permitido no framebuffer publicado; +- alpha permitido em paletas, sprites, tiles e operacoes do renderer; +- comandos dedicados de alpha fora desta wave; +- testes RGBA8888-first; +- asset package com paletas RGBA8888 sem compatibilidade RGB565; +- specs, docs e contratos ABI atualizados como parte obrigatoria da propagacao; +- render thread, GPU backend, backend RGB565 e suporte multi-formato fora de + escopo. diff --git a/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md b/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md new file mode 100644 index 00000000..c5ecd45f --- /dev/null +++ b/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md @@ -0,0 +1,203 @@ +--- +id: DEC-0029 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: RGBA8888 Runtime Pixel Format Contract +status: accepted +created: 2026-05-23 +ref_agenda: AGD-0037 +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Status + +Accepted. Drafted from accepted agenda AGD-0037 and accepted on 2026-05-23. +Execution is split across the linked RGBA8888 migration plan family. + +## Contexto + +AGD-0037 evaluated whether Prometeu should keep RGB565 as the runtime color +and framebuffer contract or migrate to RGBA8888. + +RGB565 is currently coupled into multiple layers: + +- the public `Color(pub u16)` representation; +- HAL and VM-facing GFX APIs such as `front_buffer() -> &[u16]` and + `GfxClear565`; +- renderer front/back buffers and blending helpers; +- host presentation through RGB565-to-RGBA8 conversion; +- serialized asset palettes in `assets.pa`; +- tests and fixtures that assert RGB565 values. + +The accepted agenda resolves that RGB565 should not remain as compatibility +surface in this migration. RGBA8888 becomes both the logical color contract and +the physical framebuffer format. This decision replaces the prior performance +phase direction in AGD-0010 that rejected RGBA8888 for the back buffer. + +## Decisao + +Prometeu SHALL migrate its normal runtime graphics contract from RGB565 to +RGBA8888. + +RGBA8888 MUST be the single canonical logical color representation for the +runtime, HAL, VM-facing color values, renderer buffers, asset palette decode, +tests, and host presentation path. + +RGBA8888 MUST also be the single canonical physical framebuffer format for this +wave. RGB565 MUST NOT remain as a supported runtime framebuffer backend, +compatibility mode, normal palette encoding, VM color ABI, renderer pixel +format, or host presentation contract. + +The canonical raw channel order is RGBA. + +The published front buffer MAY contain meaningful alpha. The runtime MUST NOT +force the final front buffer alpha channel to `255` as a blanket rule in this +wave. + +Alpha is allowed broadly. Palettes, sprites, tiles, primitives, UI/effects, and +renderer operations MAY carry and apply real alpha where the operation needs +it. The first implementation wave SHALL treat alpha as available across all +operations rather than splitting the migration into alpha-capable and +alpha-forbidden paths. + +Dedicated commands for managing only alpha are expected in the broader design, +but they are explicitly out of scope for this wave. + +Asset packages MUST encode palettes as RGBA8888. Existing RGB565 palette assets +MUST NOT be preserved as compatible runtime input. Any old asset or fixture that +is still needed must be regenerated or converted as part of migration work, not +supported through a permanent compatibility path. + +Tests MUST be RGBA8888-first. They MUST assert the new RGBA8888 contract rather +than proving binary equivalence with RGB565 output. + +This decision does not introduce render thread ownership, a GPU backend, an +RGB565 backend, or a generic multi-format backend abstraction. + +## Rationale + +RGB565 currently plays too many roles at once: logical color, physical pixel, +serialized palette encoding, and host presentation source. Keeping it as a +compatibility layer would preserve that coupling and force the new RGBA8888 +direction to coexist with an old contract that the runtime no longer wants to +guarantee. + +RGBA8888 aligns better with modern host APIs, texture upload paths, alpha-based +UI, Hub visuals, and future GPU-oriented work. It also removes the mandatory +RGB565-to-RGBA8 conversion in the desktop host's normal presentation path. + +The migration deliberately accepts the cost of a coordinated breaking change: +HAL, VM/syscalls, renderer buffers, asset decode, tooling, fixtures, and tests +must move together. The result is simpler than maintaining two color formats or +a premature backend matrix. + +The fantasy-console identity is not tied to RGB565 memory layout. It should be +preserved by resolution, indexed assets, palette limits, art direction, +authoring constraints, and composition rules. + +Allowing meaningful framebuffer alpha and broad alpha in operations keeps the +contract flexible while the renderer evolves. Performance specialization remains +important, but it should follow the correctness migration instead of blocking +the pixel-format contract. + +## Invariantes / Contrato + +- `Color` or its replacement MUST represent RGBA8888 semantics in the final + contract. +- Raw color values MUST use RGBA channel order. +- Runtime renderer front/back buffers MUST materialize RGBA8888 pixels. +- Public runtime/HAL/host contracts MUST stop exposing `&[u16]` as the normal + framebuffer output. +- Format-suffixed compatibility APIs such as `GfxClear565` or any other + `Gfx*565` surface MUST cease to exist in the final contract. Canonical GFX API + names MUST be format-neutral, e.g. `GfxClear`, because RGBA8888 is the only + supported runtime color contract. +- RGB565 conversion helpers may exist only as temporary migration utilities or + test-regeneration tools; they MUST NOT sit on the normal runtime hot path. +- Asset palette payloads MUST be RGBA8888. +- Indexed tile/sprite payloads MAY remain indexed/paletized; palette index + limits and 4bpp authored pixels may remain part of the artistic model. +- Palette indices are ordinary indices. Transparency MUST be represented by the + RGBA alpha channel of the resolved palette entry, not by reserving palette + index `0` as a special transparent index. +- Alpha MAY be meaningful in palettes, sprites, tiles, primitives, UI/effects, + composed framebuffer pixels, and published front-buffer pixels. +- The first migration wave MUST allow alpha across all renderer operations. +- Optimization work MAY later add faster opaque/masked/alpha paths, but that + optimization MUST NOT reintroduce RGB565 as a supported contract. +- Tests MUST use RGBA8888 expectations as source of truth. +- Render thread, GPU backend, RGB565 backend, SDL/wgpu backend abstraction, and + multi-format `FrameSurface` design are out of scope for this decision's + first execution wave. + +## Impactos + +### Spec + +Canonical specs for GFX, assets, VM/syscalls, and host presentation need to be +updated to describe RGBA8888 as the normal color and framebuffer contract. +Published specs must be in English. + +Spec updates are mandatory propagation for this decision, not follow-up cleanup. + +### Runtime / HAL + +The HAL color type, raw color APIs, framebuffer accessor, clear operation, +blend/fade helpers, renderer target storage, and tests must migrate away from +RGB565. Compatibility API names that encode RGB565, including any `Gfx*565` +surface, must be removed rather than carried forward as deprecated canonical +surface. + +### Host + +The desktop host must consume RGBA8888 frames directly in the normal path. The +existing RGB565-to-RGBA8 conversion path must be removed from normal +presentation. + +### Firmware / VM / PBS + +VM-facing color values and syscall validation must change from the RGB565 +`0xFFFF` range to the RGBA8888 contract. PBS or syscall declarations that expose +`GfxClear565`, any other `Gfx*565` surface, or raw RGB565 color must be replaced +with format-neutral APIs such as `GfxClear`. + +ABI contracts and syscall declarations are part of the required update surface. +They must not be left describing RGB565 values, `Gfx*565` names, or `u16` +framebuffer/color contracts after this migration. + +### Assets / Tooling + +`assets.pa`, glyph-bank palette decode, generators, fixtures, and validators +must use RGBA8888 palette entries. Compatibility with existing RGB565 palette +assets is intentionally not preserved. + +### Tests + +Tests must be rewritten around RGBA8888 values, RGBA channel order, broad alpha +support, meaningful front-buffer alpha, asset palette RGBA8888 encoding, and +host presentation without RGB565 conversion. + +Visual/snapshot tests should assert intended RGBA8888 composition behavior, not +binary equivalence with legacy RGB565 output. + +## Propagacao Necessaria + +- specs: GFX peripheral, asset package/glyph-bank palette format, VM/syscall + ABI, host presentation where documented. +- plans: a dedicated execution plan must be written before spec or code edits. +- code: `prometeu-hal`, `prometeu-drivers`, `prometeu-system`, + `prometeu-host-desktop-winit`, asset tooling, fixtures. +- tests: HAL color tests, renderer tests, asset decode tests, VM/syscall tests, + host conversion/presentation tests, visual or snapshot tests where available. +- docs: discussion lessons only after execution is complete. +- canonical docs: specs, ABI contracts, and public documentation must be updated + in the same execution plan as the code/spec migration, not deferred as + optional cleanup. + +## Referencias + +- Agenda: AGD-0037 +- Prior agenda superseded for this topic: AGD-0010 + +## Revision Log + +- 2026-05-23: Initial decision draft from AGD-0037. diff --git a/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md b/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md new file mode 100644 index 00000000..820bb732 --- /dev/null +++ b/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md @@ -0,0 +1,106 @@ +--- +id: PLN-0067 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: RGBA8888 Published Contracts and Specs +status: open +created: 2026-05-23 +ref_decisions: [DEC-0029] +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Briefing + +Publish the RGBA8888 contract before touching runtime code. This plan updates +the canonical specs, ABI documentation, and public docs so the repository has a +single written source of truth for the migration required by DEC-0029. + +## Source Decisions + +- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. + +## Target + +Document RGBA8888 as the only supported runtime color and framebuffer contract, +remove RGB565 compatibility language from published contracts, and define +format-neutral GFX API naming rules. + +## Scope + +Included: + +- Update `docs/specs/runtime/04-gfx-peripheral.md` to define logical color, + framebuffer output, alpha behavior, and format-neutral GFX command naming. +- Update `docs/specs/runtime/15-asset-management.md` to define RGBA8888 palette + entries in `assets.pa` and remove RGB565 palette compatibility. +- Update `docs/specs/runtime/16-host-abi-and-syscalls.md` to remove `Gfx*565` + as public ABI and define format-neutral syscall names such as `GfxClear`. +- Update `docs/specs/runtime/02a-vm-values-and-calling-convention.md` only if + it describes raw color value width/range. +- Update `docs/specs/runtime/11-portability-and-cross-platform-execution.md` + only if it describes host framebuffer format or RGB565 presentation. +- Update `docs/specs/runtime/README.md` if the index or spec summaries mention + RGB565 as current contract. + +## Out of Scope + +- Code changes under `crates/`. +- Asset fixture regeneration. +- Host presentation implementation. +- Lessons; they are written after execution, not before. +- New backend abstractions, render thread, GPU backend, RGB565 fallback. + +## Execution Plan + +1. Audit published contract text. + - Search `docs/` for `RGB565`, `rgb565`, `565`, `u16`, `GfxClear565`, + `Gfx*565`, `front_buffer`, `palette`, `assets.pa`, and `RGBA`. + - Classify each hit as historical, obsolete contract, or still-valid + implementation detail. + +2. Update the GFX peripheral spec. + - State that runtime color values are RGBA8888 in RGBA channel order. + - State that front-buffer alpha may be meaningful. + - State that GFX APIs must be format-neutral and must not expose `Gfx*565`. + - State that palette indices are ordinary indices and transparency comes + from resolved RGBA alpha. + +3. Update asset-management specs. + - Define palette entries as RGBA8888. + - Keep indexed tile/sprite payloads and palette limits if already specified. + - Remove compatibility promises for RGB565 palette payloads. + - Call out that existing RGB565 assets must be regenerated or converted by + tooling, not accepted as runtime compatibility input. + +4. Update host and ABI specs. + - Replace RGB565 and `u16` color/framebuffer ABI language with RGBA8888. + - Replace `GfxClear565` and any `Gfx*565` surface with format-neutral names. + - Document expected syscall color range/shape for RGBA8888 values. + +5. Add a short migration note to each touched spec. + - Reference DEC-0029. + - Make clear that RGB565 text is superseded for the active runtime contract. + +## Acceptance Criteria + +- [ ] `docs/` no longer describes RGB565 as the current runtime color, + framebuffer, palette, or host presentation contract. +- [ ] `docs/` no longer describes `Gfx*565` as public canonical ABI. +- [ ] Specs state RGBA8888 raw channel order as RGBA. +- [ ] Specs state that front-buffer alpha may be meaningful. +- [ ] Specs state that palette transparency comes from alpha, not reserved index + `0`. +- [ ] Specs state that RGB565 asset palettes are not compatible runtime input. + +## Tests / Validation + +- Run a repository text audit with `rg -n "RGB565|rgb565|Gfx.*565|u16|565" docs` + and verify every remaining hit is explicitly historical or unrelated. +- Run `discussion validate`. +- No Rust build is required for this docs-only plan. + +## Risks + +- Specs may contain old historical sections that should remain for context. If + retained, they must be marked historical and must not read as active contract. +- Some ABI names may be generated from Rust enums; this plan documents the + target but does not update generated code. diff --git a/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md b/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md new file mode 100644 index 00000000..7ddf5acf --- /dev/null +++ b/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md @@ -0,0 +1,118 @@ +--- +id: PLN-0068 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: RGBA8888 Color Type HAL and ABI Surface +status: open +created: 2026-05-23 +ref_decisions: [DEC-0029] +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Briefing + +Introduce the RGBA8888 logical color contract and format-neutral HAL/ABI +surface while keeping renderer internals as stable as possible for the next +plan. This is the boundary-setting code PR after the specs are updated. + +## Source Decisions + +- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. + +## Dependencies + +- PLN-0067 must be accepted or complete enough that the target spec wording is + stable. + +## Target + +The public runtime color type, syscall registry, ABI metadata, and HAL bridge +must stop exposing RGB565 as the canonical contract. Public names must be +format-neutral. + +## Scope + +Included: + +- Replace `prometeu_hal::color::Color(pub u16)` semantics with RGBA8888 in + `crates/console/prometeu-hal/src/color.rs`. +- Define constructors and raw accessors for RGBA channel order. +- Preserve ergonomic named constants as RGBA8888 values. +- Replace `Syscall::GfxClear565` with format-neutral `Syscall::GfxClear`. +- Update syscall registry/domain metadata in + `crates/console/prometeu-hal/src/syscalls.rs`, + `crates/console/prometeu-hal/src/syscalls/registry.rs`, and + `crates/console/prometeu-hal/src/syscalls/domains/gfx.rs`. +- Update VM dispatch color parsing and validation in + `crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs`. +- Update ABI/opcode documentation surfaces in + `crates/console/prometeu-bytecode/src/abi.rs` and + `crates/console/prometeu-bytecode/src/opcode_spec.rs` if they expose the + syscall name or raw color range. +- Change `GfxBridge::front_buffer` only if needed to compile the public API + shape; full renderer buffer migration belongs to PLN-0069. + +## Out of Scope + +- Migrating renderer front/back storage. +- Migrating asset palette serialization. +- Removing host RGB565 conversion. +- Performance optimization for alpha or RGBA operations. +- Adding alpha-only commands. + +## Execution Plan + +1. Rewrite `Color` as RGBA8888. + - Store raw color as `u32` or an equivalent transparent representation. + - `Color::rgb(r, g, b)` must create opaque alpha `255`. + - Add or update `Color::rgba(r, g, b, a)`. + - `raw()` and `from_raw()` must use RGBA channel order. + - Remove or quarantine RGB565 helpers such as 5/6/5 pack/unpack from the + canonical API. + +2. Remove format-suffixed GFX syscall naming. + - Rename `GfxClear565` to `GfxClear`. + - Rename the domain metadata from `clear_565` to `clear`. + - Keep the numeric syscall id stable only if the ABI policy allows preserving + the opcode while changing the name/semantics; otherwise document the new + id in the spec before changing it. + - Search for any other `Gfx*565` public surface and rename it to + format-neutral form. + +3. Update VM color ABI handling. + - Replace `0xFFFF` validation with the RGBA8888 range/shape. + - Ensure the VM passes RGBA8888 raw values into `Color`. + - Remove comments and test expectations that identify the GFX clear syscall + as RGB565. + +4. Update tests at the boundary. + - HAL color tests must assert RGBA raw order. + - Syscall metadata tests must assert `GfxClear`, not `GfxClear565`. + - VM dispatch tests must use RGBA8888 values and meaningful alpha examples. + +5. Run a targeted residue scan. + - `rg -n "Gfx.*565|RGB565|rgb565|0xFFFF|Color\\(.*u16|front_buffer\\(\\).*u16" crates/console`. + - Remaining hits must be either in lower layers scheduled for later plans or + marked as temporary implementation residue. + +## Acceptance Criteria + +- [ ] `Color` represents RGBA8888 and exposes RGBA-order raw values. +- [ ] `GfxClear565` is no longer a canonical syscall/API name; `GfxClear` is. +- [ ] No public `Gfx*565` surface remains in HAL/syscall metadata. +- [ ] VM color validation accepts RGBA8888 and does not enforce RGB565 range. +- [ ] Boundary tests are RGBA8888-first. + +## Tests / Validation + +- Run the HAL/syscall unit tests touched by this plan. +- Run VM dispatch tests that cover GFX clear/color values. +- Run `cargo test` for the affected crates if compile scope remains contained. +- Run `discussion validate`. + +## Risks + +- Renaming syscall variants may have wide compile fallout. Keep the PR focused + on boundary names and color semantics, leaving renderer internals for the next + plan. +- If opcode ids are part of a stable ABI, changing numeric ids requires a + separate explicit spec change before implementation. diff --git a/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md b/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md new file mode 100644 index 00000000..727994b6 --- /dev/null +++ b/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md @@ -0,0 +1,109 @@ +--- +id: PLN-0069 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: RGBA8888 CPU Renderer and Composition +status: open +created: 2026-05-23 +ref_decisions: [DEC-0029] +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Briefing + +Migrate the existing CPU renderer and frame composition path from RGB565 +storage to RGBA8888 storage. This plan keeps the current destructive renderer +model and does not introduce a render thread or backend abstraction. + +## Source Decisions + +- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. + +## Dependencies + +- PLN-0067 for published contract wording. +- PLN-0068 for `Color`, HAL, and syscall boundary semantics. + +## Target + +The renderer front/back buffers, render target writes, fades, blends, text, +tiles, sprites, and frame composer tests must operate on RGBA8888 pixels. + +## Scope + +Included: + +- `crates/console/prometeu-drivers/src/gfx.rs`. +- `crates/console/prometeu-drivers/src/frame_composer.rs`. +- `crates/console/prometeu-drivers/src/hardware.rs` where framebuffer/color + assumptions are tested or documented. +- HAL bridge implementation in drivers if it still returns `&[u16]`. +- Renderer unit tests and frame-composer tests that assert raw pixel values. + +## Out of Scope + +- Asset package palette serialization changes; covered by PLN-0070. +- Host presentation conversion removal; covered by PLN-0071. +- GPU backend, render thread, dirty-region optimization, span optimization, or + multi-format backend abstraction. +- Alpha-only commands. + +## Execution Plan + +1. Change renderer storage to RGBA8888. + - Replace `front: Vec` and `back: Vec` with RGBA8888 storage. + - Update `RenderTarget` and all buffer accessors to the new pixel type. + - Ensure `present()` keeps its swap semantics. + +2. Update primitive writes. + - `clear`, `draw_pixel`, `fill_rect`, `draw_text`, hardware font drawing, + and overlay primitives must write RGBA8888 values. + - Opaque calls may write direct RGBA8888 pixels. + - Alpha values must be preserved according to the operation semantics. + +3. Replace RGB565 blending/fade. + - Replace `blend_rgb565` with RGBA8888 blend logic. + - Update `apply_fade_to_buffer` to operate on RGBA channels. + - Do not force final alpha to `255`; preserve or compute alpha according to + the operation. + +4. Update tile and sprite composition. + - Resolve palette entries as RGBA8888 colors. + - Do not treat palette index `0` as automatically transparent. + - Skip or blend based on resolved alpha and operation semantics. + - Allow alpha across tile, sprite, primitive, UI/effect, and fade paths. + +5. Update frame composer expectations. + - Tests must assert RGBA8888 raw values. + - Any old RGB565 expected values must be regenerated from RGBA source colors, + not converted as compatibility behavior. + +6. Isolate temporary compile seams. + - If asset decode still supplies RGBA8888 `Color` through old fixture bytes, + keep the fixture problem contained for PLN-0070 and do not add runtime + RGB565 compatibility to the renderer. + +## Acceptance Criteria + +- [ ] Renderer front/back buffers materialize RGBA8888 pixels. +- [ ] `front_buffer()` no longer exposes `&[u16]` in the driver/HAL + implementation path. +- [ ] RGB565 blend/fade helpers are removed from renderer normal paths. +- [ ] Tile/sprite transparency is based on RGBA alpha, not palette index `0`. +- [ ] Renderer and frame-composer tests assert RGBA8888 values. +- [ ] No render thread, GPU backend, RGB565 backend, or multi-format backend is + introduced. + +## Tests / Validation + +- Run renderer unit tests in `prometeu-drivers`. +- Run frame composer tests in `prometeu-drivers`. +- Run targeted scans for `blend_rgb565`, `Vec`, `&[u16]`, and `RGB565` in + renderer files. +- Run `discussion validate`. + +## Risks + +- This plan will likely touch many assertions. Keep each assertion update tied + to a known RGBA value. +- Alpha behavior can expose previously hidden assumptions in tests. Preserve the + decision rule: alpha is allowed broadly and optimization comes later. diff --git a/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md b/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md new file mode 100644 index 00000000..b494a405 --- /dev/null +++ b/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md @@ -0,0 +1,114 @@ +--- +id: PLN-0070 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: RGBA8888 Asset Palettes Tooling and Fixtures +status: open +created: 2026-05-23 +ref_decisions: [DEC-0029] +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Briefing + +Migrate asset palette serialization, decode, generators, and fixtures to +RGBA8888. This plan intentionally breaks RGB565 palette compatibility rather +than preserving it through runtime fallback. + +## Source Decisions + +- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. + +## Dependencies + +- PLN-0067 for asset spec wording. +- PLN-0068 for RGBA8888 `Color`. +- PLN-0069 may run before or alongside this plan, but renderer normal paths must + not require RGB565 palette compatibility. + +## Target + +`assets.pa` glyph-bank palette payloads, runtime decode, generators, and tests +must use RGBA8888 palette entries with RGBA channel order. + +## Scope + +Included: + +- `crates/console/prometeu-hal/src/glyph_bank.rs`. +- `crates/console/prometeu-hal/src/asset.rs`. +- `crates/console/prometeu-hal/src/cartridge_loader.rs`. +- `crates/console/prometeu-drivers/src/asset.rs`. +- `crates/tools/pbxgen-stress/src/lib.rs` and related generator code. +- Runtime and system tests that compute glyph-bank payload sizes. +- Test fixtures and generated `assets.pa` payload builders in the repository. + +## Out of Scope + +- Supporting legacy RGB565 assets at runtime. +- Adding a general asset package v2 negotiation layer unless the existing format + requires an explicit version bump to avoid ambiguous decode. +- Changing tile/sprite index packing beyond what RGBA8888 palettes require. +- Changing palette count or colors-per-palette limits. + +## Execution Plan + +1. Change palette byte accounting. + - Replace palette entry size from `size_of::()` / `2` bytes to `4` + bytes. + - Update decoded-size calculations in asset decode, cartridge loader tests, + VM runtime tests, and pbxgen-stress. + +2. Decode palettes as RGBA8888. + - Read each palette entry as four bytes in RGBA order. + - Construct `Color` through RGBA8888 APIs, not `Color(raw_u16)`. + - Reject payloads whose palette byte size matches old RGB565 layout when the + format can identify the mismatch. + +3. Update glyph-bank semantics. + - Keep `pixel_indices: Vec` and 4bpp authored payloads where currently + specified. + - Keep palette count and colors-per-palette constants unless the spec says + otherwise. + - Remove comments that say runtime palettes are RGB565. + - Ensure palette index `0` is not treated as transparent by decode or data + model. + +4. Update generators and fixtures. + - Make `pbxgen-stress` emit RGBA8888 palette bytes. + - Regenerate inline fixture builders to append four-byte RGBA palette + entries. + - Do not keep RGB565 fixture decode as runtime compatibility. + +5. Update asset tests. + - Assert RGBA channel order. + - Include at least one non-opaque alpha value in a palette entry. + - Assert payload size failures for old two-byte palette layout where + practical. + +## Acceptance Criteria + +- [ ] Glyph-bank palette payloads are RGBA8888 and use four bytes per entry. +- [ ] Asset decode constructs RGBA8888 `Color` values in RGBA order. +- [ ] Existing RGB565 palette payloads are not accepted as compatible runtime + input. +- [ ] `pbxgen-stress` emits RGBA8888 palettes. +- [ ] Tests include meaningful alpha in palette entries. +- [ ] Palette index `0` has no special transparency semantics in asset decode. + +## Tests / Validation + +- Run asset decode tests in `prometeu-drivers`. +- Run cartridge loader tests in `prometeu-hal`. +- Run VM runtime asset tests in `prometeu-system`. +- Run `cargo test -p pbxgen-stress` if available. +- Run scans for `GLYPH_BANK_PALETTE.*u16`, `* 2`, `size_of::()`, and + `RGB565` in asset/glyph-bank/tooling files. +- Run `discussion validate`. + +## Risks + +- Payload-size constants are duplicated in tests. Update all derived size + helpers in the same PR to avoid misleading failures. +- If the existing asset package has no version marker for palette encoding, the + plan must choose an explicit metadata/version discriminator before accepting + ambiguous payloads. diff --git a/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md b/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md new file mode 100644 index 00000000..226d732b --- /dev/null +++ b/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md @@ -0,0 +1,103 @@ +--- +id: PLN-0071 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: RGBA8888 Host Presentation Path +status: open +created: 2026-05-23 +ref_decisions: [DEC-0029] +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Briefing + +Move the desktop host presentation path from RGB565 conversion to direct +RGBA8888 presentation. This plan removes the normal `draw_rgb565_to_rgba8` +path after the runtime publishes RGBA8888 frames. + +## Source Decisions + +- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. + +## Dependencies + +- PLN-0067 for host/spec contract wording. +- PLN-0068 for public framebuffer type and ABI naming. +- PLN-0069 for renderer front-buffer RGBA8888 storage. + +## Target + +The host must consume RGBA8888 frames directly in the normal presentation path +and must not convert RGB565 frames on every redraw. + +## Scope + +Included: + +- `crates/host/prometeu-host-desktop-winit/src/runner.rs`. +- `crates/host/prometeu-host-desktop-winit/src/utilities.rs`. +- Host tests or utility tests for frame copy/channel order. +- Host overlay integration where it assumes RGBA8 frame bytes. + +## Out of Scope + +- Changing the windowing library. +- Introducing wgpu/OpenGL/SDL backend abstractions. +- Changing host frame pacing. +- Changing render thread ownership. +- Performance optimization beyond removing RGB565 conversion from the normal + path. + +## Execution Plan + +1. Replace host frame conversion. + - Remove use of `draw_rgb565_to_rgba8` from `runner.rs`. + - Copy or expose RGBA8888 runtime pixels into the `pixels` frame using the + documented RGBA channel order. + - Preserve meaningful alpha unless the presentation library explicitly + requires conversion; if conversion is required, document it as host + presentation behavior, not runtime framebuffer semantics. + +2. Remove RGB565 utilities from the normal path. + - Delete `draw_rgb565_to_rgba8` and `rgb565_to_rgb888` if no tests or + temporary migration tools need them. + - If temporary conversion helpers remain for fixture regeneration, move them + out of host presentation utilities and mark them non-runtime. + +3. Verify overlay compatibility. + - Ensure host overlay writes still target RGBA8 bytes in the `pixels` frame. + - Ensure overlay composition does not assume the emulated framebuffer itself + is opaque. + +4. Update host tests. + - Add or update tests for RGBA channel order. + - Include a source pixel with non-`255` alpha. + - Remove tests that only prove RGB565 expansion. + +5. Run residue scan. + - Search host crate for `rgb565`, `RGB565`, `draw_rgb565`, and `u16` + framebuffer assumptions. + +## Acceptance Criteria + +- [ ] The desktop host normal redraw path consumes RGBA8888 frames. +- [ ] `draw_rgb565_to_rgba8` is not used by host presentation. +- [ ] Host channel order matches canonical RGBA. +- [ ] Host presentation does not force runtime front-buffer alpha to `255` as a + runtime contract. +- [ ] Host tests are RGBA8888-first. + +## Tests / Validation + +- Run `cargo test -p prometeu-host-desktop-winit`. +- Run a targeted host scan for `rgb565`, `RGB565`, and `draw_rgb565`. +- Run an interactive smoke test only if the repo already has a standard host + smoke command; otherwise record that manual visual validation remains for the + final validation plan. +- Run `discussion validate`. + +## Risks + +- The `pixels` frame is byte-oriented; byte order mistakes are easy. Tests must + use non-symmetric color values and non-opaque alpha. +- If runtime publishes `u32`, host code must explicitly define how the `u32` + maps to RGBA bytes instead of relying on native endian layout. diff --git a/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md b/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md new file mode 100644 index 00000000..7a74f1b8 --- /dev/null +++ b/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md @@ -0,0 +1,109 @@ +--- +id: PLN-0072 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: RGBA8888 Residue Removal and End to End Validation +status: open +created: 2026-05-23 +ref_decisions: [DEC-0029] +tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] +--- + +## Briefing + +Close the RGBA8888 migration by removing residual RGB565 contract text and code +paths, running end-to-end validation, and preparing the discussion thread for +post-execution lessons. + +## Source Decisions + +- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. + +## Dependencies + +- PLN-0067 through PLN-0071 must be complete or merged into the execution branch. + +## Target + +The repository must no longer expose RGB565, `Gfx*565`, `u16` framebuffer/color +contracts, RGB565 palette payloads, or RGB565 host conversion as active runtime +contract. + +## Scope + +Included: + +- Whole-repository residue audit. +- End-to-end build and test validation. +- Documentation consistency checks. +- Final migration notes needed for housekeeping and lessons. +- Any small missed cleanup in code, docs, tests, or fixtures that directly + violates DEC-0029. + +## Out of Scope + +- New alpha-only commands. +- Performance optimization after broad alpha support. +- GPU backend, render thread, RGB565 backend, multi-format backend abstraction. +- New visual design work for the Hub. + +## Execution Plan + +1. Run repository-wide residue scans. + - Search for `RGB565`, `rgb565`, `Gfx.*565`, `clear_565`, `u16` near color + or framebuffer APIs, `GLYPH_BANK_PALETTE.*u16`, `size_of::()` near + palette code, `draw_rgb565`, and `0xFFFF` near color validation. + - Classify every remaining hit as removed, historical-only, unrelated, or a + bug. + +2. Remove active-contract residues. + - Delete or rename any remaining active `Gfx*565` surface. + - Remove RGB565 helpers from runtime and host normal paths. + - Remove comments that still describe RGB565 as current behavior. + - Remove tests that assert RGB565 output. + +3. Verify docs and ABI consistency. + - Ensure `docs/specs/runtime/04-gfx-peripheral.md`, + `docs/specs/runtime/15-asset-management.md`, and + `docs/specs/runtime/16-host-abi-and-syscalls.md` agree on RGBA8888. + - Ensure public syscall declarations and docs use format-neutral names. + - Ensure any historical RGB565 mention is clearly historical and not + normative. + +4. Run full test/build validation. + - Run the repo's standard build command. + - Run the relevant Rust test suites across HAL, drivers, system, VM, tools, + and host. + - Run any visual/snapshot validation available in the repository. + +5. Record final evidence. + - Capture the exact commands and outcomes in the plan or final PR notes. + - List remaining historical RGB565 mentions and why they are acceptable. + - Identify lesson candidates for `discussion-housekeep` after execution. + +## Acceptance Criteria + +- [ ] Repository scan finds no active RGB565 runtime contract. +- [ ] No public `Gfx*565` API, syscall, metadata, or ABI declaration remains. +- [ ] No normal renderer or host path performs RGB565 conversion. +- [ ] No asset decode path accepts RGB565 palettes as compatible runtime input. +- [ ] Specs, docs, ABI contracts, code, fixtures, and tests agree on RGBA8888. +- [ ] Full validation commands pass or any failure is documented as unrelated. +- [ ] The discussion thread has enough evidence for housekeeping and lessons. + +## Tests / Validation + +- Run the standard repository build command. +- Run affected crate tests: `prometeu-hal`, `prometeu-drivers`, + `prometeu-system`, `prometeu-vm`, `prometeu-bytecode`, + `prometeu-host-desktop-winit`, and `pbxgen-stress` where applicable. +- Run all available visual/snapshot tests. +- Run repository-wide `rg` residue scans described above. +- Run `discussion validate`. + +## Risks + +- Some remaining RGB565 references may be legitimate historical notes. They + must be marked clearly enough that readers cannot mistake them for active + contract. +- End-to-end visual validation may not exist yet. If so, record the gap and add + minimal deterministic checks around RGBA channel order and alpha behavior. From 1256d33a72427814271700edebf23718513cf5da Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 19:15:14 +0100 Subject: [PATCH 03/10] implements PLN-0067 --- discussion/index.ndjson | 2 +- ...-rgba8888-published-contracts-and-specs.md | 2 +- .../02a-vm-values-and-calling-convention.md | 5 +- docs/specs/runtime/04-gfx-peripheral.md | 99 +++++++++++-------- ...ortability-and-cross-platform-execution.md | 6 +- docs/specs/runtime/15-asset-management.md | 17 +++- .../specs/runtime/16-host-abi-and-syscalls.md | 24 +++++ 7 files changed, 103 insertions(+), 52 deletions(-) diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 57896bbc..68d5cd88 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -35,4 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} -{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} diff --git a/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md b/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md index 820bb732..910cab10 100644 --- a/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md +++ b/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md @@ -2,7 +2,7 @@ id: PLN-0067 ticket: rgba8888-framebuffer-and-pixel-format-direction title: RGBA8888 Published Contracts and Specs -status: open +status: done created: 2026-05-23 ref_decisions: [DEC-0029] tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] diff --git a/docs/specs/runtime/02a-vm-values-and-calling-convention.md b/docs/specs/runtime/02a-vm-values-and-calling-convention.md index 1be23abd..ae23586e 100644 --- a/docs/specs/runtime/02a-vm-values-and-calling-convention.md +++ b/docs/specs/runtime/02a-vm-values-and-calling-convention.md @@ -35,7 +35,7 @@ These are treated as VM values with stable layout semantics. | Type | Description | | ------- | --------------------------------- | | `vec2` | 2D vector (x, y) | -| `color` | Packed color value | +| `color` | Packed RGBA8888 color value | | `pixel` | Combination of position and color | These values: @@ -44,6 +44,9 @@ These values: - are copied by value; - do not require heap allocation by themselves. +The canonical `color` raw channel order is RGBA. RGB565 is not a public VM +color contract. + ### Heap values Heap-resident entities are referenced indirectly through handles. diff --git a/docs/specs/runtime/04-gfx-peripheral.md b/docs/specs/runtime/04-gfx-peripheral.md index 9e757c1e..9783fa50 100644 --- a/docs/specs/runtime/04-gfx-peripheral.md +++ b/docs/specs/runtime/04-gfx-peripheral.md @@ -29,13 +29,20 @@ It is an explicit 2D graphics device based on: ### Pixel format -- **RGB565** -- 5 bits Red -- 6 bits Green -- 5 bits Blue -- no alpha channel +- **RGBA8888** +- 8 bits Red +- 8 bits Green +- 8 bits Blue +- 8 bits Alpha +- canonical raw channel order: **RGBA** -Transparency is handled via **color key**. +The framebuffer alpha channel may carry meaningful runtime output. The runtime +MUST NOT force the published front buffer alpha channel to `255` as a blanket +contract. + +Color values in the runtime, HAL, host-facing framebuffer, and GFX ABI are +logical RGBA8888 values. RGB565 is not a supported runtime framebuffer, +palette, host presentation, or compatibility contract. --- @@ -232,16 +239,21 @@ Normative boundary: --- -## 12. Transparency (Color Key) +## 12. Transparency -- One RGB565 value is reserved as TRANSPARENT_KEY -- Pixels with this color are not drawn +Transparency is represented by the alpha channel of the resolved RGBA8888 +color. + +Palette indices are ordinary indices. The runtime MUST NOT reserve palette +index `0` as a special transparent index. A palette entry may still be authored +as transparent by setting its alpha channel to `0`, but that is ordinary palette +data rather than a special index rule. ``` -if src == TRANSPARENT_KEY: +if resolved_color.alpha == 0: skip else: - draw + draw_or_blend(resolved_color) ``` @@ -259,8 +271,9 @@ Official modes: - `BLEND_HALF_MINUS` - `BLEND_FULL` -No continuous alpha. -No arbitrary blending. +Alpha is available through RGBA8888 colors. Discrete blend modes remain part of +the classic GFX contract, and later optimization work may specialize opaque, +masked, and alpha paths. Everything is: @@ -283,12 +296,13 @@ Everything is: By design: -- Continuous alpha -- RGBA framebuffer - Shaders - Modern GPU pipeline - HDR - Gamma correction +- RGB565 compatibility framebuffers +- multi-format backend selection +- render-thread ownership as part of this contract --- @@ -314,8 +328,7 @@ controls: In v1, deferred `gfx.*` overlay/debug primitives are drained after both fades and therefore are not themselves part of scene or HUD fade application. -The fade is implemented without continuous per-pixel alpha and without floats. -It uses a **discrete integer level** (0..31), which in practice produces an +The fade uses a **discrete integer level** (0..31), which in practice produces an "almost continuous" visual result in Prometeu's `480x270` pixel-art framebuffer. --- @@ -327,32 +340,32 @@ Each fade is represented by: - `fade_level: u8` in the range **[0..31]** - `0` → fully replaced by the fade color - `31` → fully visible (no fade) -- `fade_color: RGB565` +- `fade_color: RGBA8888` - color the image will be blended into Registers: - `SCENE_FADE_LEVEL` (0..31) -- `SCENE_FADE_COLOR` (RGB565) +- `SCENE_FADE_COLOR` (RGBA8888) - `HUD_FADE_LEVEL` (0..31) -- `HUD_FADE_COLOR` (RGB565) +- `HUD_FADE_COLOR` (RGBA8888) Common cases: - Fade-out: `fade_color = BLACK` - Flash/teleport: `fade_color = WHITE` -- Special effects: any RGB565 color +- Special effects: any RGBA8888 color --- ### 17.2 Fade Operation (Blending with Arbitrary Color) -For each RGB565 pixel `src` and fade color `fc`, the final pixel `dst` is calculated per channel. +For each RGBA8888 pixel `src` and fade color `fc`, the final pixel `dst` is calculated per channel. 1) Extract components: -- `src_r5`, `src_g6`, `src_b5` -- `fc_r5`, `fc_g6`, `fc_b5` +- `src_r8`, `src_g8`, `src_b8`, `src_a8` +- `fc_r8`, `fc_g8`, `fc_b8`, `fc_a8` 2) Apply integer blending: @@ -360,17 +373,18 @@ For each RGB565 pixel `src` and fade color `fc`, the final pixel `dst` is calcul src_weight = fade_level // 0..31 fc_weight = 31 - fade_level -r5 = (src_r5 * src_weight + fc_r5 * fc_weight) / 31 -g6 = (src_g6 * src_weight + fc_g6 * fc_weight) / 31 -b5 = (src_b5 * src_weight + fc_b5 * fc_weight) / 31 +r8 = (src_r8 * src_weight + fc_r8 * fc_weight) / 31 +g8 = (src_g8 * src_weight + fc_g8 * fc_weight) / 31 +b8 = (src_b8 * src_weight + fc_b8 * fc_weight) / 31 +a8 = (src_a8 * src_weight + fc_a8 * fc_weight) / 31 ``` -- `src_r5`, `src_g6`, `src_b5` -- `fc_r5`, `fc_g6`, `fc_b5` +- `src_r8`, `src_g8`, `src_b8`, `src_a8` +- `fc_r8`, `fc_g8`, `fc_b8`, `fc_a8` 3) Repack: ``` -dst = pack_rgb565(r5, g6, b5) +dst = pack_rgba8888_rgba(r8, g8, b8, a8) ``` @@ -425,8 +439,8 @@ Each pixel of a tile or sprite is: Fixed rule: -- Index `0` = TRANSPARENT -- Indices `1..15` = valid palette colors +- Indices `0..15` are ordinary valid palette indices +- Transparency comes from the alpha channel of the resolved palette entry --- @@ -437,13 +451,13 @@ Each **Tile Bank** contains: - **64 palettes** in runtime-facing v1 - Each palette has: - **16 colors** - - each color in **RGB565 (`u16`, little-endian in serialized assets)** + - each color in **RGBA8888** with canonical RGBA channel order Size: -- 1 palette = 16 × 2 bytes = **32 bytes** -- 64 palettes = **2 KB per bank** -- 16 banks = **32 KB maximum palettes** +- 1 palette = 16 × 4 bytes = **64 bytes** +- 64 palettes = **4 KB per bank** +- 16 banks = **64 KB maximum palettes** --- @@ -496,22 +510,22 @@ Runtime-facing validity rule for v1: The pipeline works like this: 1. Read indexed pixel from tile (value 0..15) -2. If index == 0 → transparent pixel -3. Otherwise: +2. Resolve: - real_color = palette[palette_id][index] -4. Apply: +3. Apply: - flip - discrete blend + - alpha/skip behavior from the resolved RGBA8888 color - writing to back buffer In other words: ``` pixel_index = tile_pixel(x,y) -if pixel_index == 0: +color = bank.palettes[palette_id][pixel_index] +if color.alpha == 0: skip else: - color = bank.palettes[palette_id][pixel_index] - draw(color) + draw_or_blend(color) ``` --- @@ -578,7 +592,6 @@ Fault boundary: | `gfx.draw_disc` | `void` | no real operational failure path in v1 | | `gfx.draw_square` | `void` | no real operational failure path in v1 | | `gfx.draw_text` | `void` | no real operational failure path in v1 | -| `gfx.clear_565` | `void` | no real operational failure path in v1 | | `composer.bind_scene` | `status:int` | status-returning API, but missing scene glyph dependencies are fatal runtime errors | | `composer.unbind_scene` | `status:int` | explicit orchestration-domain operational result | | `composer.set_camera` | `void` | no real operational failure path in v1 | diff --git a/docs/specs/runtime/11-portability-and-cross-platform-execution.md b/docs/specs/runtime/11-portability-and-cross-platform-execution.md index 82d6fe1a..46317f0c 100644 --- a/docs/specs/runtime/11-portability-and-cross-platform-execution.md +++ b/docs/specs/runtime/11-portability-and-cross-platform-execution.md @@ -116,7 +116,7 @@ Hardware differences: The graphics system: -- operates on a logical framebuffer +- operates on a logical RGBA8888 framebuffer - uses an indexed palette - does not depend on a specific GPU @@ -127,6 +127,10 @@ The platform layer: - **may overlay technical HUDs without modifying the logical framebuffer** - may transport the logical framebuffer into a host presentation surface where a host-only overlay layer is composed +The host presentation layer MUST treat RGBA8888 as the canonical logical +framebuffer format. RGB565 conversion is not part of the normal host +presentation contract. + Host presentation SHOULD be driven by published logical frames and explicit host-owned invalidation, not by perpetual redraw polling. In particular: diff --git a/docs/specs/runtime/15-asset-management.md b/docs/specs/runtime/15-asset-management.md index cf76e3c3..d2e52306 100644 --- a/docs/specs/runtime/15-asset-management.md +++ b/docs/specs/runtime/15-asset-management.md @@ -114,7 +114,7 @@ For `BankType::GLYPH`, the v1 runtime-facing contract is: - `codec = NONE` - serialized pixels use packed `u4` palette indices -- serialized palettes use `RGB565` (`u16`, little-endian) +- serialized palettes use `RGBA8888` with canonical RGBA channel order - `palette_count = 64` - runtime materialization may expand pixel indices to one `u8` per pixel @@ -152,18 +152,25 @@ Validation rules for `GLYPH` v1: #### 4.1.2 Payload Layout 1. packed indexed pixels for the full sheet, using `ceil(width * height / 2)` bytes; -2. palette table, using `palette_count * 16 * 2` bytes. +2. palette table, using `palette_count * 16 * 4` bytes. The tile-bank payload therefore separates serialized storage form from runtime memory form: - serialized pixel plane: packed `4bpp` - decoded pixel plane: expanded `u8` indices, one entry per pixel -- palette table: `64 * 16` colors in `RGB565` +- palette table: `64 * 16` colors in RGBA8888 channel order For `GLYPH` v1: -- `size` must match `ceil(width * height / 2) + (palette_count * 16 * 2)` -- `decoded_size` must match `(width * height) + (palette_count * 16 * 2)` +- `size` must match `ceil(width * height / 2) + (palette_count * 16 * 4)` +- `decoded_size` must match `(width * height) + (palette_count * 16 * 4)` + +RGB565 palette payloads are not compatible runtime input. Existing assets with +two-byte RGB565 palette entries must be regenerated or converted by tooling +before they are loaded by the runtime. + +Palette indices are ordinary indices. Transparency is represented by the alpha +channel of the resolved RGBA8888 palette entry, not by reserving index `0`. ### 4.2 `SCENE` asset contract in v1 diff --git a/docs/specs/runtime/16-host-abi-and-syscalls.md b/docs/specs/runtime/16-host-abi-and-syscalls.md index 302a8e68..8a0ddb34 100644 --- a/docs/specs/runtime/16-host-abi-and-syscalls.md +++ b/docs/specs/runtime/16-host-abi-and-syscalls.md @@ -220,6 +220,30 @@ For `asset.load`: - JSON-on-the-wire bank inspection payloads are not valid public ABI; - `bank.info` returns stack values, not textual structured payloads. +### GFX surface (`gfx`, v1) + +The public GFX ABI uses format-neutral operation names. API and syscall names +MUST NOT encode RGB565 or any other pixel format suffix. + +Canonical operations in v1 include: + +- `gfx.clear(color) -> void` +- `gfx.fill_rect(x, y, w, h, color) -> void` +- `gfx.draw_line(x0, y0, x1, y1, color) -> void` +- `gfx.draw_circle(x, y, radius, color) -> void` +- `gfx.draw_disc(x, y, radius, color) -> void` +- `gfx.draw_square(x, y, size, color) -> void` +- `gfx.draw_text(x, y, text, color) -> void` + +Rules: + +- `color` arguments are packed RGBA8888 values using RGBA channel order. +- RGB565 raw values are not a public ABI contract. +- `Gfx*565` syscall names and `gfx.*_565` canonical identities are not valid + current ABI. +- The runtime framebuffer exposed across the host boundary is RGBA8888, not + `u16` RGB565. + ### Composition surface (`composer`, v1) The canonical frame-orchestration public ABI uses module `composer`. From 668a061964a49bf5a51ddd41036b3e411cb8d59d Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 19:19:28 +0100 Subject: [PATCH 04/10] implements PLN-0068 --- crates/console/prometeu-drivers/src/asset.rs | 6 +- crates/console/prometeu-drivers/src/gfx.rs | 63 ++++++----- crates/console/prometeu-hal/src/color.rs | 100 ++++++++++-------- crates/console/prometeu-hal/src/glyph_bank.rs | 19 ++-- crates/console/prometeu-hal/src/syscalls.rs | 1 - .../prometeu-hal/src/syscalls/domains/gfx.rs | 4 - .../prometeu-hal/src/syscalls/registry.rs | 2 - .../prometeu-hal/src/syscalls/tests.rs | 4 - .../src/services/vm_runtime/dispatch.rs | 33 +++--- .../prometeu-vm/src/virtual_machine.rs | 6 +- discussion/index.ndjson | 2 +- ...rgba8888-color-type-hal-and-abi-surface.md | 2 +- 12 files changed, 121 insertions(+), 121 deletions(-) diff --git a/crates/console/prometeu-drivers/src/asset.rs b/crates/console/prometeu-drivers/src/asset.rs index 6e67a941..8579038b 100644 --- a/crates/console/prometeu-drivers/src/asset.rs +++ b/crates/console/prometeu-drivers/src/asset.rs @@ -658,7 +658,7 @@ impl AssetManager { let offset = (p * 16 + c) * 2; let color_raw = u16::from_le_bytes([palette_data[offset], palette_data[offset + 1]]); - *slot = Color(color_raw); + *slot = Color::from_rgb565_lossy(color_raw); } } @@ -690,7 +690,7 @@ impl AssetManager { let offset = (p * 16 + c) * 2; let color_raw = u16::from_le_bytes([palette_data[offset], palette_data[offset + 1]]); - *slot = Color(color_raw); + *slot = Color::from_rgb565_lossy(color_raw); } } @@ -1313,7 +1313,7 @@ mod tests { AssetManager::decode_glyph_bank_from_buffer(&entry, &data).expect("glyph decode"); assert_eq!(bank.pixel_indices, vec![1, 0, 2, 3]); - assert_eq!(bank.palettes[0][0], Color(0x1234)); + assert_eq!(bank.palettes[0][0], Color::from_rgb565_lossy(0x1234)); } #[test] diff --git a/crates/console/prometeu-drivers/src/gfx.rs b/crates/console/prometeu-drivers/src/gfx.rs index 6fca0a2f..14313a16 100644 --- a/crates/console/prometeu-drivers/src/gfx.rs +++ b/crates/console/prometeu-drivers/src/gfx.rs @@ -381,7 +381,7 @@ impl Gfx { } pub fn clear(&mut self, color: Color) { - self.back.fill(color.0); + self.back.fill(color.to_rgb565_lossy()); } /// Rectangle with blend mode. @@ -406,7 +406,7 @@ impl Gfx { let x1 = (x + w).clamp(0, fw); let y1 = (y + h).clamp(0, fh); - let src = color.0; + let src = color.to_rgb565_lossy(); for yy in y0..y1 { let row = (yy as usize) * self.w; @@ -429,7 +429,7 @@ impl Gfx { return; } if x >= 0 && x < self.w as i32 && y >= 0 && y < self.h as i32 { - self.back[y as usize * self.w + x as usize] = color.0; + self.back[y as usize * self.w + x as usize] = color.to_rgb565_lossy(); } } @@ -582,7 +582,7 @@ impl Gfx { return; } for x in start..=end { - self.back[y as usize * self.w + x as usize] = color.0; + self.back[y as usize * self.w + x as usize] = color.to_rgb565_lossy(); } } @@ -600,7 +600,7 @@ impl Gfx { return; } for y in start..=end { - self.back[y as usize * self.w + x as usize] = color.0; + self.back[y as usize * self.w + x as usize] = color.to_rgb565_lossy(); } } @@ -657,7 +657,7 @@ impl Gfx { update: &ResolverUpdate, resolved_glyph_slots: &[usize; 4], ) { - self.back.fill(Color::BLACK.raw()); + self.back.fill(Color::BLACK.to_rgb565_lossy()); self.populate_layer_buckets(); for (layer_index, glyph_slot) in @@ -779,7 +779,7 @@ impl Gfx { } let color = tile.bank.resolve_color(tile.entry.palette_id, px_index); - target.back[world_y as usize * target.screen_w + world_x as usize] = color.raw(); + target.back[world_y as usize * target.screen_w + world_x as usize] = color.to_rgb565_lossy(); } } } @@ -834,7 +834,7 @@ impl Gfx { // 3. Resolve color via palette (from the tile inside the sprite) let color = bank.resolve_color(sprite.glyph.palette_id, px_index); - back[world_y as usize * screen_w + world_x as usize] = color.raw(); + back[world_y as usize * screen_w + world_x as usize] = color.to_rgb565_lossy(); } } } @@ -848,17 +848,17 @@ impl Gfx { let weight = level as u16; let inv_weight = 31 - weight; - let (fr, fg, fb) = Color::unpack_to_native(fade_color.0); + let (fr, fg, fb) = unpack_rgb565_native(fade_color.to_rgb565_lossy()); for px in back.iter_mut() { - let (sr, sg, sb) = Color::unpack_to_native(*px); + let (sr, sg, sb) = unpack_rgb565_native(*px); // Formula: (src * weight + fade * inv_weight) / 31 let r = ((sr as u16 * weight + fr as u16 * inv_weight) / 31) as u8; let g = ((sg as u16 * weight + fg as u16 * inv_weight) / 31) as u8; let b = ((sb as u16 * weight + fb as u16 * inv_weight) / 31) as u8; - *px = Color::pack_from_native(r, g, b); + *px = pack_rgb565_native(r, g, b); } } @@ -900,7 +900,7 @@ impl Gfx { } let glyph = glyph_for_char(c); - let raw = color.0; + let raw = color.to_rgb565_lossy(); let row_start = (-y).clamp(0, glyph_h) as usize; let row_end = (screen_h - y).clamp(0, glyph_h) as usize; @@ -932,49 +932,60 @@ fn blend_rgb565(dst: u16, src: u16, mode: BlendMode) -> u16 { BlendMode::None => src, BlendMode::Half => { - let (dr, dg, db) = Color::unpack_to_native(dst); - let (sr, sg, sb) = Color::unpack_to_native(src); + let (dr, dg, db) = unpack_rgb565_native(dst); + let (sr, sg, sb) = unpack_rgb565_native(src); let r = ((dr as u16 + sr as u16) >> 1) as u8; let g = ((dg as u16 + sg as u16) >> 1) as u8; let b = ((db as u16 + sb as u16) >> 1) as u8; - Color::pack_from_native(r, g, b) + pack_rgb565_native(r, g, b) } BlendMode::HalfPlus => { - let (dr, dg, db) = Color::unpack_to_native(dst); - let (sr, sg, sb) = Color::unpack_to_native(src); + let (dr, dg, db) = unpack_rgb565_native(dst); + let (sr, sg, sb) = unpack_rgb565_native(src); let r = (dr as u16 + ((sr as u16) >> 1)).min(31) as u8; let g = (dg as u16 + ((sg as u16) >> 1)).min(63) as u8; let b = (db as u16 + ((sb as u16) >> 1)).min(31) as u8; - Color::pack_from_native(r, g, b) + pack_rgb565_native(r, g, b) } BlendMode::HalfMinus => { - let (dr, dg, db) = Color::unpack_to_native(dst); - let (sr, sg, sb) = Color::unpack_to_native(src); + let (dr, dg, db) = unpack_rgb565_native(dst); + let (sr, sg, sb) = unpack_rgb565_native(src); let r = (dr as i16 - ((sr as i16) >> 1)).max(0) as u8; let g = (dg as i16 - ((sg as i16) >> 1)).max(0) as u8; let b = (db as i16 - ((sb as i16) >> 1)).max(0) as u8; - Color::pack_from_native(r, g, b) + pack_rgb565_native(r, g, b) } BlendMode::Full => { - let (dr, dg, db) = Color::unpack_to_native(dst); - let (sr, sg, sb) = Color::unpack_to_native(src); + let (dr, dg, db) = unpack_rgb565_native(dst); + let (sr, sg, sb) = unpack_rgb565_native(src); let r = (dr as u16 + sr as u16).min(31) as u8; let g = (dg as u16 + sg as u16).min(63) as u8; let b = (db as u16 + sb as u16).min(31) as u8; - Color::pack_from_native(r, g, b) + pack_rgb565_native(r, g, b) } } } +fn unpack_rgb565_native(px: u16) -> (u8, u8, u8) { + let r = ((px >> 11) & 0x1F) as u8; + let g = ((px >> 5) & 0x3F) as u8; + let b = (px & 0x1F) as u8; + (r, g, b) +} + +fn pack_rgb565_native(r: u8, g: u8, b: u8) -> u16 { + ((r as u16 & 0x1F) << 11) | ((g as u16 & 0x3F) << 5) | (b as u16 & 0x1F) +} + #[cfg(test)] mod tests { use super::*; @@ -1133,7 +1144,7 @@ mod tests { gfx.hud_fade_level = 31; gfx.render_scene_from_cache(&cache, &update, &[0, 0, 0, 0]); - assert_eq!(gfx.back[0], Color::RED.raw()); + assert_eq!(gfx.back[0], Color::RED.to_rgb565_lossy()); } #[test] @@ -1184,7 +1195,7 @@ mod tests { gfx.render_scene_from_cache(&cache, &update, &[0, 0, 0, 0]); - assert_eq!(gfx.back[0], Color::BLUE.raw()); + assert_eq!(gfx.back[0], Color::BLUE.to_rgb565_lossy()); } #[test] diff --git a/crates/console/prometeu-hal/src/color.rs b/crates/console/prometeu-hal/src/color.rs index d5b440bc..04f16c9d 100644 --- a/crates/console/prometeu-hal/src/color.rs +++ b/crates/console/prometeu-hal/src/color.rs @@ -1,75 +1,87 @@ -/// Represents a 16-bit color in the RGB565 format. -/// -/// The RGB565 format is a common high-color representation for embedded systems: -/// - **Red**: 5 bits (0..31) -/// - **Green**: 6 bits (0..63) -/// - **Blue**: 5 bits (0..31) -/// -/// Prometeu does not have a hardware alpha channel. Transparency is achieved -/// by using a specific color key (Magenta / 0xF81F) which the GFX engine -/// skips during rendering. +/// Represents a canonical RGBA8888 color in RGBA channel order. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub struct Color(pub u16); +pub struct Color(pub u32); impl Color { - pub const BLACK: Self = Self::rgb(0, 0, 0); // 0x0000 - pub const WHITE: Self = Self::rgb(255, 255, 255); // 0xFFFF - pub const RED: Self = Self::rgb(255, 0, 0); // 0xF800 - pub const GREEN: Self = Self::rgb(0, 255, 0); // 0x07E0 - pub const BLUE: Self = Self::rgb(0, 0, 255); // 0x001F - pub const YELLOW: Self = Self::rgb(255, 255, 0); // 0xFFE0 + pub const BLACK: Self = Self::rgb(0, 0, 0); + pub const WHITE: Self = Self::rgb(255, 255, 255); + pub const RED: Self = Self::rgb(255, 0, 0); + pub const GREEN: Self = Self::rgb(0, 255, 0); + pub const BLUE: Self = Self::rgb(0, 0, 255); + pub const YELLOW: Self = Self::rgb(255, 255, 0); pub const ORANGE: Self = Self::rgb(255, 128, 0); pub const INDIGO: Self = Self::rgb(75, 0, 130); pub const GRAY: Self = Self::rgb(128, 128, 128); - pub const CYAN: Self = Self::rgb(0, 255, 255); // 0x07FF - pub const MAGENTA: Self = Self::rgb(255, 0, 255); // 0xF81F - pub const COLOR_KEY: Self = Self::MAGENTA; - pub const TRANSPARENT: Self = Self::MAGENTA; + pub const CYAN: Self = Self::rgb(0, 255, 255); + pub const MAGENTA: Self = Self::rgb(255, 0, 255); + pub const TRANSPARENT: Self = Self::rgba(0, 0, 0, 0); + #[deprecated(note = "Use RGBA alpha transparency; COLOR_KEY is temporary migration residue.")] + pub const COLOR_KEY: Self = Self::TRANSPARENT; - /// Extracts channels in the native RGB565 range: - /// R: 0..31, G: 0..63, B: 0..31 + /// Extracts RGBA8888 channels from canonical RGBA raw order. #[inline(always)] - pub const fn unpack_to_native(px: u16) -> (u8, u8, u8) { - let r = ((px >> 11) & 0x1F) as u8; - let g = ((px >> 5) & 0x3F) as u8; - let b = (px & 0x1F) as u8; - (r, g, b) + pub const fn unpack_to_native(px: u32) -> (u8, u8, u8, u8) { + let r = ((px >> 24) & 0xFF) as u8; + let g = ((px >> 16) & 0xFF) as u8; + let b = ((px >> 8) & 0xFF) as u8; + let a = (px & 0xFF) as u8; + (r, g, b, a) } - /// Packs channels from the native RGB565 range into a pixel: - /// R: 0..31, G: 0..63, B: 0..31 + /// Packs RGBA8888 channels into canonical RGBA raw order. #[inline(always)] - pub const fn pack_from_native(r: u8, g: u8, b: u8) -> u16 { - ((r as u16 & 0x1F) << 11) | ((g as u16 & 0x3F) << 5) | (b as u16 & 0x1F) + pub const fn pack_from_native(r: u8, g: u8, b: u8, a: u8) -> u32 { + ((r as u32) << 24) | ((g as u32) << 16) | ((b as u32) << 8) | a as u32 } - /// Creates an RGB565 color from 8-bit components (0..255). + /// Creates an opaque RGBA8888 color from 8-bit RGB components. pub const fn rgb(r: u8, g: u8, b: u8) -> Self { - let r5 = (r as u16 >> 3) & 0x1F; - let g6 = (g as u16 >> 2) & 0x3F; - let b5 = (b as u16 >> 3) & 0x1F; + Self::rgba(r, g, b, 255) + } - Self((r5 << 11) | (g6 << 5) | b5) + pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self { + Self(Self::pack_from_native(r, g, b, a)) } pub const fn gray_scale(c: u8) -> Self { Self::rgb(c, c, c) } - pub const fn from_raw(raw: u16) -> Self { + pub const fn from_raw(raw: u32) -> Self { Self(raw) } - pub const fn raw(self) -> u16 { + pub const fn raw(self) -> u32 { self.0 } pub const fn hex(self) -> i32 { - let (r5, g6, b5) = Self::unpack_to_native(self.0); - let r8 = ((r5 as u32) << 3) | ((r5 as u32) >> 2); - let g8 = ((g6 as u32) << 2) | ((g6 as u32) >> 4); - let b8 = ((b5 as u32) << 3) | ((b5 as u32) >> 2); - let hex = r8 << 16 | g8 << 8 | b8; + let (r, g, b, _) = Self::unpack_to_native(self.0); + let hex = (r as u32) << 16 | (g as u32) << 8 | b as u32; hex as i32 } + + pub const fn alpha(self) -> u8 { + (self.0 & 0xFF) as u8 + } + + #[deprecated(note = "Temporary bridge until the renderer buffer migrates to RGBA8888.")] + pub const fn to_rgb565_lossy(self) -> u16 { + let (r, g, b, _) = Self::unpack_to_native(self.0); + let r5 = (r as u16 >> 3) & 0x1F; + let g6 = (g as u16 >> 2) & 0x3F; + let b5 = (b as u16 >> 3) & 0x1F; + (r5 << 11) | (g6 << 5) | b5 + } + + #[deprecated(note = "Temporary bridge until asset palettes migrate to RGBA8888.")] + pub const fn from_rgb565_lossy(raw: u16) -> Self { + let r5 = ((raw >> 11) & 0x1F) as u32; + let g6 = ((raw >> 5) & 0x3F) as u32; + let b5 = (raw & 0x1F) as u32; + let r = ((r5 << 3) | (r5 >> 2)) as u8; + let g = ((g6 << 2) | (g6 >> 4)) as u8; + let b = ((b5 << 3) | (b5 >> 2)) as u8; + Self::rgba(r, g, b, 255) + } } diff --git a/crates/console/prometeu-hal/src/glyph_bank.rs b/crates/console/prometeu-hal/src/glyph_bank.rs index aa38e700..fe92e131 100644 --- a/crates/console/prometeu-hal/src/glyph_bank.rs +++ b/crates/console/prometeu-hal/src/glyph_bank.rs @@ -32,9 +32,10 @@ pub struct GlyphBank { /// Decoded pixel data stored as one palette index per pixel. /// Serialized payloads are packed; runtime memory is expanded. - /// Index 0 is always reserved for transparency. + /// Palette indices are ordinary indices; transparency is resolved through + /// the RGBA alpha channel of the palette entry. pub pixel_indices: Vec, - /// Runtime-facing v1 palette table: 64 palettes of 16 RGB565 colors each. + /// Runtime-facing v1 palette table: 64 palettes of 16 RGBA8888 colors each. pub palettes: [[Color; GLYPH_BANK_COLORS_PER_PALETTE]; GLYPH_BANK_PALETTE_COUNT_V1], } @@ -45,7 +46,7 @@ impl GlyphBank { tile_size, width, height, - pixel_indices: vec![0; width * height], // Index 0 = Transparent + pixel_indices: vec![0; width * height], palettes: [[Color::BLACK; GLYPH_BANK_COLORS_PER_PALETTE]; GLYPH_BANK_PALETTE_COUNT_V1], } } @@ -65,22 +66,16 @@ impl GlyphBank { if pixel_x < self.width && pixel_y < self.height { self.pixel_indices[pixel_y * self.width + pixel_x] } else { - 0 // Default to transparent if out of bounds + 0 } } - /// Maps a 4-bit index to a real RGB565 Color using the specified palette. + /// Maps a 4-bit index to a real RGBA8888 Color using the specified palette. pub fn resolve_color(&self, palette_id: u8, pixel_index: u8) -> Color { - // Hardware Rule: Index 0 is always transparent. - // We use Magenta as the 'transparent' signal color during composition. - if pixel_index == 0 { - return Color::COLOR_KEY; - } - self.palettes .get(palette_id as usize) .and_then(|palette| palette.get(pixel_index as usize)) .copied() - .unwrap_or(Color::COLOR_KEY) + .unwrap_or(Color::TRANSPARENT) } } diff --git a/crates/console/prometeu-hal/src/syscalls.rs b/crates/console/prometeu-hal/src/syscalls.rs index d63173a1..4098ed40 100644 --- a/crates/console/prometeu-hal/src/syscalls.rs +++ b/crates/console/prometeu-hal/src/syscalls.rs @@ -37,7 +37,6 @@ pub enum Syscall { GfxDrawDisc = 0x1005, GfxDrawSquare = 0x1006, GfxDrawText = 0x1008, - GfxClear565 = 0x1010, ComposerBindScene = 0x1101, ComposerUnbindScene = 0x1102, ComposerSetCamera = 0x1103, diff --git a/crates/console/prometeu-hal/src/syscalls/domains/gfx.rs b/crates/console/prometeu-hal/src/syscalls/domains/gfx.rs index f6023957..d45bc619 100644 --- a/crates/console/prometeu-hal/src/syscalls/domains/gfx.rs +++ b/crates/console/prometeu-hal/src/syscalls/domains/gfx.rs @@ -29,8 +29,4 @@ pub(crate) const ENTRIES: &[SyscallRegistryEntry] = &[ .args(4) .caps(caps::GFX) .cost(20), - SyscallRegistryEntry::builder(Syscall::GfxClear565, "gfx", "clear_565") - .args(1) - .caps(caps::GFX) - .cost(20), ]; diff --git a/crates/console/prometeu-hal/src/syscalls/registry.rs b/crates/console/prometeu-hal/src/syscalls/registry.rs index 7b353b1a..5f005083 100644 --- a/crates/console/prometeu-hal/src/syscalls/registry.rs +++ b/crates/console/prometeu-hal/src/syscalls/registry.rs @@ -21,7 +21,6 @@ impl Syscall { 0x1005 => Some(Self::GfxDrawDisc), 0x1006 => Some(Self::GfxDrawSquare), 0x1008 => Some(Self::GfxDrawText), - 0x1010 => Some(Self::GfxClear565), 0x1101 => Some(Self::ComposerBindScene), 0x1102 => Some(Self::ComposerUnbindScene), 0x1103 => Some(Self::ComposerSetCamera), @@ -71,7 +70,6 @@ impl Syscall { Self::GfxDrawDisc => "GfxDrawDisc", Self::GfxDrawSquare => "GfxDrawSquare", Self::GfxDrawText => "GfxDrawText", - Self::GfxClear565 => "GfxClear565", Self::ComposerBindScene => "ComposerBindScene", Self::ComposerUnbindScene => "ComposerUnbindScene", Self::ComposerSetCamera => "ComposerSetCamera", diff --git a/crates/console/prometeu-hal/src/syscalls/tests.rs b/crates/console/prometeu-hal/src/syscalls/tests.rs index 362a6687..97677f16 100644 --- a/crates/console/prometeu-hal/src/syscalls/tests.rs +++ b/crates/console/prometeu-hal/src/syscalls/tests.rs @@ -210,10 +210,6 @@ fn status_first_syscall_signatures_are_pinned() { assert_eq!(draw_text.arg_slots, 4); assert_eq!(draw_text.ret_slots, 0); - let clear_565 = meta_for(Syscall::GfxClear565); - assert_eq!(clear_565.arg_slots, 1); - assert_eq!(clear_565.ret_slots, 0); - let bind_scene = meta_for(Syscall::ComposerBindScene); assert_eq!(bind_scene.arg_slots, 1); assert_eq!(bind_scene.ret_slots, 1); diff --git a/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs b/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs index 6ddf9bb2..7501ced7 100644 --- a/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs +++ b/crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs @@ -95,8 +95,10 @@ impl VmRuntimeHost<'_> { Ok(()) } - pub(crate) fn get_color(&self, value: i64) -> Color { - Color::from_raw(value as u16) + pub(crate) fn get_color(&self, value: i64) -> Result { + let raw = u32::try_from(value) + .map_err(|_| VmFault::Trap(TRAP_OOB, "Color value out of bounds".into()))?; + Ok(Color::from_raw(raw)) } fn int_arg_to_usize_status(value: i64) -> Result { @@ -126,7 +128,6 @@ impl VmRuntimeHost<'_> { | Syscall::GfxDrawDisc | Syscall::GfxDrawSquare | Syscall::GfxDrawText - | Syscall::GfxClear565 | Syscall::ComposerBindScene | Syscall::ComposerUnbindScene | Syscall::ComposerSetCamera @@ -183,7 +184,7 @@ impl NativeInterface for VmRuntimeHost<'_> { Syscall::SystemHasCart => unreachable!(), Syscall::SystemRunCart => unreachable!(), Syscall::GfxClear => { - let color = self.get_color(expect_int(args, 0)?); + let color = self.get_color(expect_int(args, 0)?)?; hw.gfx_mut().clear(color); Ok(()) } @@ -192,7 +193,7 @@ impl NativeInterface for VmRuntimeHost<'_> { 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)?); + let color = self.get_color(expect_int(args, 4)?)?; hw.gfx_mut().fill_rect(x, y, w, h, color); Ok(()) } @@ -201,7 +202,7 @@ impl NativeInterface for VmRuntimeHost<'_> { 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)?); + let color = self.get_color(expect_int(args, 4)?)?; hw.gfx_mut().draw_line(x1, y1, x2, y2, color); Ok(()) } @@ -209,7 +210,7 @@ impl NativeInterface for VmRuntimeHost<'_> { 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)?); + let color = self.get_color(expect_int(args, 3)?)?; hw.gfx_mut().draw_circle(x, y, r, color); Ok(()) } @@ -217,8 +218,8 @@ impl NativeInterface for VmRuntimeHost<'_> { 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)?); + 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(()) } @@ -227,8 +228,8 @@ impl NativeInterface for VmRuntimeHost<'_> { 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)?); + 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(()) } @@ -236,18 +237,10 @@ impl NativeInterface for VmRuntimeHost<'_> { 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)?); + let color = self.get_color(expect_int(args, 3)?)?; hw.gfx_mut().draw_text(x, y, &msg, color); Ok(()) } - Syscall::GfxClear565 => { - let color_val = expect_int(args, 0)? as u32; - if color_val > 0xFFFF { - return Err(VmFault::Trap(TRAP_OOB, "Color value out of bounds".into())); - } - hw.gfx_mut().clear(Color::from_raw(color_val as u16)); - Ok(()) - } Syscall::ComposerBindScene => { let scene_bank_id = match Self::int_arg_to_usize_status(expect_int(args, 0)?) { Ok(id) => id, diff --git a/crates/console/prometeu-vm/src/virtual_machine.rs b/crates/console/prometeu-vm/src/virtual_machine.rs index 5fb65d93..09282fe9 100644 --- a/crates/console/prometeu-vm/src/virtual_machine.rs +++ b/crates/console/prometeu-vm/src/virtual_machine.rs @@ -2545,12 +2545,12 @@ mod tests { #[test] fn test_syscall_results_count_mismatch_panic() { - // GfxClear565 (0x1010) expects 0 results + // GfxClear (0x1001) expects 0 results let rom = vec![ 0x17, 0x00, // PushI32 0x00, 0x00, 0x00, 0x00, // value 0 0x70, 0x00, // Syscall + Reserved - 0x10, 0x10, 0x00, 0x00, // Syscall ID 0x1010 + 0x01, 0x10, 0x00, 0x00, // Syscall ID 0x1001 ]; struct BadNative; @@ -2562,7 +2562,7 @@ mod tests { ret: &mut HostReturn, _ctx: &mut HostContext, ) -> Result<(), VmFault> { - // Wrong: GfxClear565 is void but we push something + // Wrong: GfxClear is void but we push something ret.push_int(42); Ok(()) } diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 68d5cd88..15765a48 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -35,4 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} -{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} diff --git a/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md b/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md index 7ddf5acf..9df110ab 100644 --- a/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md +++ b/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md @@ -2,7 +2,7 @@ id: PLN-0068 ticket: rgba8888-framebuffer-and-pixel-format-direction title: RGBA8888 Color Type HAL and ABI Surface -status: open +status: done created: 2026-05-23 ref_decisions: [DEC-0029] tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] From c4c2dfb017fa5f15f27efe072005e264028b0049 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 19:21:02 +0100 Subject: [PATCH 05/10] implements PLN-0069 --- crates/console/prometeu-drivers/src/gfx.rs | 124 +++++++++--------- crates/console/prometeu-hal/src/gfx_bridge.rs | 2 +- discussion/index.ndjson | 2 +- ...9-rgba8888-cpu-renderer-and-composition.md | 2 +- 4 files changed, 65 insertions(+), 65 deletions(-) diff --git a/crates/console/prometeu-drivers/src/gfx.rs b/crates/console/prometeu-drivers/src/gfx.rs index 14313a16..1c708e3e 100644 --- a/crates/console/prometeu-drivers/src/gfx.rs +++ b/crates/console/prometeu-drivers/src/gfx.rs @@ -40,9 +40,9 @@ pub struct Gfx { /// Height of the internal framebuffer in pixels. h: usize, /// Front buffer: the "VRAM" currently being displayed by the Host window. - front: Vec, + front: Vec, /// Back buffer: the working buffer where canonical game frames are composed - back: Vec, + back: Vec, /// Shared access to graphical memory banks (tiles and palettes). pub glyph_banks: Arc, @@ -67,7 +67,7 @@ pub struct Gfx { // const GLYPH_UNKNOWN: [u8; 5] = [0x7, 0x7, 0x7, 0x7, 0x7]; struct RenderTarget<'a> { - back: &'a mut [u16], + back: &'a mut [u32], screen_w: usize, screen_h: usize, } @@ -206,7 +206,7 @@ impl GfxBridge for Gfx { fn size(&self) -> (usize, usize) { self.size() } - fn front_buffer(&self) -> &[u16] { + fn front_buffer(&self) -> &[u32] { self.front_buffer() } fn clear(&mut self, color: Color) { @@ -375,13 +375,13 @@ impl Gfx { (self.w, self.h) } - /// The buffer that the host should display (RGB565). - pub fn front_buffer(&self) -> &[u16] { + /// The buffer that the host should display (RGBA8888 in RGBA raw order). + pub fn front_buffer(&self) -> &[u32] { &self.front } pub fn clear(&mut self, color: Color) { - self.back.fill(color.to_rgb565_lossy()); + self.back.fill(color.raw()); } /// Rectangle with blend mode. @@ -394,7 +394,7 @@ impl Gfx { color: Color, mode: BlendMode, ) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -406,14 +406,14 @@ impl Gfx { let x1 = (x + w).clamp(0, fw); let y1 = (y + h).clamp(0, fh); - let src = color.to_rgb565_lossy(); + let src = color.raw(); for yy in y0..y1 { let row = (yy as usize) * self.w; for xx in x0..x1 { let idx = row + (xx as usize); let dst = self.back[idx]; - self.back[idx] = blend_rgb565(dst, src, mode); + self.back[idx] = blend_rgba8888(dst, src, mode); } } } @@ -425,17 +425,17 @@ impl Gfx { /// Draws a single pixel. pub fn draw_pixel(&mut self, x: i32, y: i32, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } if x >= 0 && x < self.w as i32 && y >= 0 && y < self.h as i32 { - self.back[y as usize * self.w + x as usize] = color.to_rgb565_lossy(); + self.back[y as usize * self.w + x as usize] = color.raw(); } } /// Draws a line between two points using Bresenham's algorithm. pub fn draw_line(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -467,7 +467,7 @@ impl Gfx { /// Draws a circle outline using Midpoint Circle Algorithm. pub fn draw_circle(&mut self, xc: i32, yc: i32, r: i32, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -503,7 +503,7 @@ impl Gfx { /// Draws a filled circle. pub fn fill_circle(&mut self, xc: i32, yc: i32, r: i32, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -541,7 +541,7 @@ impl Gfx { /// Draws a rectangle outline. pub fn draw_rect(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -569,7 +569,7 @@ impl Gfx { } fn draw_horizontal_line(&mut self, x0: i32, x1: i32, y: i32, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -582,12 +582,12 @@ impl Gfx { return; } for x in start..=end { - self.back[y as usize * self.w + x as usize] = color.to_rgb565_lossy(); + self.back[y as usize * self.w + x as usize] = color.raw(); } } fn draw_vertical_line(&mut self, x: i32, y0: i32, y1: i32, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -600,7 +600,7 @@ impl Gfx { return; } for y in start..=end { - self.back[y as usize * self.w + x as usize] = color.to_rgb565_lossy(); + self.back[y as usize * self.w + x as usize] = color.raw(); } } @@ -657,7 +657,7 @@ impl Gfx { update: &ResolverUpdate, resolved_glyph_slots: &[usize; 4], ) { - self.back.fill(Color::BLACK.to_rgb565_lossy()); + self.back.fill(Color::BLACK.raw()); self.populate_layer_buckets(); for (layer_index, glyph_slot) in @@ -703,7 +703,7 @@ impl Gfx { } fn draw_cache_layer_to_buffer( - back: &mut [u16], + back: &mut [u32], screen_w: usize, screen_h: usize, cache: &SceneViewportCache, @@ -779,13 +779,13 @@ impl Gfx { } let color = tile.bank.resolve_color(tile.entry.palette_id, px_index); - target.back[world_y as usize * target.screen_w + world_x as usize] = color.to_rgb565_lossy(); + target.back[world_y as usize * target.screen_w + world_x as usize] = color.raw(); } } } fn draw_bucket_on_buffer( - back: &mut [u16], + back: &mut [u32], screen_w: usize, screen_h: usize, bucket: &[usize], @@ -802,7 +802,7 @@ impl Gfx { } fn draw_sprite_pixel_by_pixel( - back: &mut [u16], + back: &mut [u32], screen_w: usize, screen_h: usize, sprite: &Sprite, @@ -834,31 +834,32 @@ impl Gfx { // 3. Resolve color via palette (from the tile inside the sprite) let color = bank.resolve_color(sprite.glyph.palette_id, px_index); - back[world_y as usize * screen_w + world_x as usize] = color.to_rgb565_lossy(); + back[world_y as usize * screen_w + world_x as usize] = color.raw(); } } } /// Applies the fade effect to the entire back buffer. /// level: 0 (full color) to 31 (visible) - fn apply_fade_to_buffer(back: &mut [u16], level: u8, fade_color: Color) { + fn apply_fade_to_buffer(back: &mut [u32], level: u8, fade_color: Color) { if level >= 31 { return; } // Fully visible, skip processing let weight = level as u16; let inv_weight = 31 - weight; - let (fr, fg, fb) = unpack_rgb565_native(fade_color.to_rgb565_lossy()); + let (fr, fg, fb, fa) = unpack_rgba8888(fade_color.raw()); for px in back.iter_mut() { - let (sr, sg, sb) = unpack_rgb565_native(*px); + let (sr, sg, sb, sa) = unpack_rgba8888(*px); // Formula: (src * weight + fade * inv_weight) / 31 let r = ((sr as u16 * weight + fr as u16 * inv_weight) / 31) as u8; let g = ((sg as u16 * weight + fg as u16 * inv_weight) / 31) as u8; let b = ((sb as u16 * weight + fb as u16 * inv_weight) / 31) as u8; + let a = ((sa as u16 * weight + fa as u16 * inv_weight) / 31) as u8; - *px = pack_rgb565_native(r, g, b); + *px = pack_rgba8888(r, g, b, a); } } @@ -885,7 +886,7 @@ impl Gfx { } fn draw_char(&mut self, x: i32, y: i32, c: char, color: Color) { - if color == Color::COLOR_KEY { + if color.alpha() == 0 { return; } @@ -900,7 +901,7 @@ impl Gfx { } let glyph = glyph_for_char(c); - let raw = color.to_rgb565_lossy(); + let raw = color.raw(); let row_start = (-y).clamp(0, glyph_h) as usize; let row_end = (screen_h - y).clamp(0, glyph_h) as usize; @@ -925,65 +926,64 @@ impl Gfx { } } -/// Blends in RGB565 per channel with saturation. -/// `dst` and `src` are RGB565 pixels (u16). -fn blend_rgb565(dst: u16, src: u16, mode: BlendMode) -> u16 { +fn blend_rgba8888(dst: u32, src: u32, mode: BlendMode) -> u32 { match mode { BlendMode::None => src, BlendMode::Half => { - let (dr, dg, db) = unpack_rgb565_native(dst); - let (sr, sg, sb) = unpack_rgb565_native(src); + let (dr, dg, db, da) = unpack_rgba8888(dst); + let (sr, sg, sb, sa) = unpack_rgba8888(src); let r = ((dr as u16 + sr as u16) >> 1) as u8; let g = ((dg as u16 + sg as u16) >> 1) as u8; let b = ((db as u16 + sb as u16) >> 1) as u8; - pack_rgb565_native(r, g, b) + let a = ((da as u16 + sa as u16) >> 1) as u8; + pack_rgba8888(r, g, b, a) } BlendMode::HalfPlus => { - let (dr, dg, db) = unpack_rgb565_native(dst); - let (sr, sg, sb) = unpack_rgb565_native(src); + let (dr, dg, db, da) = unpack_rgba8888(dst); + let (sr, sg, sb, sa) = unpack_rgba8888(src); - let r = (dr as u16 + ((sr as u16) >> 1)).min(31) as u8; - let g = (dg as u16 + ((sg as u16) >> 1)).min(63) as u8; - let b = (db as u16 + ((sb as u16) >> 1)).min(31) as u8; + let r = (dr as u16 + ((sr as u16) >> 1)).min(255) as u8; + let g = (dg as u16 + ((sg as u16) >> 1)).min(255) as u8; + let b = (db as u16 + ((sb as u16) >> 1)).min(255) as u8; + let a = (da as u16 + ((sa as u16) >> 1)).min(255) as u8; - pack_rgb565_native(r, g, b) + pack_rgba8888(r, g, b, a) } BlendMode::HalfMinus => { - let (dr, dg, db) = unpack_rgb565_native(dst); - let (sr, sg, sb) = unpack_rgb565_native(src); + let (dr, dg, db, da) = unpack_rgba8888(dst); + let (sr, sg, sb, sa) = unpack_rgba8888(src); let r = (dr as i16 - ((sr as i16) >> 1)).max(0) as u8; let g = (dg as i16 - ((sg as i16) >> 1)).max(0) as u8; let b = (db as i16 - ((sb as i16) >> 1)).max(0) as u8; + let a = (da as i16 - ((sa as i16) >> 1)).max(0) as u8; - pack_rgb565_native(r, g, b) + pack_rgba8888(r, g, b, a) } BlendMode::Full => { - let (dr, dg, db) = unpack_rgb565_native(dst); - let (sr, sg, sb) = unpack_rgb565_native(src); + let (dr, dg, db, da) = unpack_rgba8888(dst); + let (sr, sg, sb, sa) = unpack_rgba8888(src); - let r = (dr as u16 + sr as u16).min(31) as u8; - let g = (dg as u16 + sg as u16).min(63) as u8; - let b = (db as u16 + sb as u16).min(31) as u8; + let r = (dr as u16 + sr as u16).min(255) as u8; + let g = (dg as u16 + sg as u16).min(255) as u8; + let b = (db as u16 + sb as u16).min(255) as u8; + let a = (da as u16 + sa as u16).min(255) as u8; - pack_rgb565_native(r, g, b) + pack_rgba8888(r, g, b, a) } } } -fn unpack_rgb565_native(px: u16) -> (u8, u8, u8) { - let r = ((px >> 11) & 0x1F) as u8; - let g = ((px >> 5) & 0x3F) as u8; - let b = (px & 0x1F) as u8; - (r, g, b) +fn unpack_rgba8888(px: u32) -> (u8, u8, u8, u8) { + Color::unpack_to_native(px) } -fn pack_rgb565_native(r: u8, g: u8, b: u8) -> u16 { - ((r as u16 & 0x1F) << 11) | ((g as u16 & 0x3F) << 5) | (b as u16 & 0x1F) +fn pack_rgba8888(r: u8, g: u8, b: u8, a: u8) -> u32 { + Color::pack_from_native(r, g, b, a) } #[cfg(test)] @@ -1144,7 +1144,7 @@ mod tests { gfx.hud_fade_level = 31; gfx.render_scene_from_cache(&cache, &update, &[0, 0, 0, 0]); - assert_eq!(gfx.back[0], Color::RED.to_rgb565_lossy()); + assert_eq!(gfx.back[0], Color::RED.raw()); } #[test] @@ -1195,7 +1195,7 @@ mod tests { gfx.render_scene_from_cache(&cache, &update, &[0, 0, 0, 0]); - assert_eq!(gfx.back[0], Color::BLUE.to_rgb565_lossy()); + assert_eq!(gfx.back[0], Color::BLUE.raw()); } #[test] diff --git a/crates/console/prometeu-hal/src/gfx_bridge.rs b/crates/console/prometeu-hal/src/gfx_bridge.rs index 34dd1465..ad0b7424 100644 --- a/crates/console/prometeu-hal/src/gfx_bridge.rs +++ b/crates/console/prometeu-hal/src/gfx_bridge.rs @@ -24,7 +24,7 @@ pub enum GfxOpStatus { pub trait GfxBridge { fn size(&self) -> (usize, usize); - fn front_buffer(&self) -> &[u16]; + fn front_buffer(&self) -> &[u32]; fn clear(&mut self, color: Color); fn fill_rect_blend(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color, mode: BlendMode); fn fill_rect(&mut self, x: i32, y: i32, w: i32, h: i32, color: Color); diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 15765a48..411b9717 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -35,4 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} -{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} diff --git a/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md b/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md index 727994b6..85176692 100644 --- a/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md +++ b/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md @@ -2,7 +2,7 @@ id: PLN-0069 ticket: rgba8888-framebuffer-and-pixel-format-direction title: RGBA8888 CPU Renderer and Composition -status: open +status: done created: 2026-05-23 ref_decisions: [DEC-0029] tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] From f273745589cdd0da79087a1f94767c403fd5ba39 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 19:23:07 +0100 Subject: [PATCH 06/10] implements PLN-0070 --- crates/console/prometeu-drivers/src/asset.rs | 29 +++++++++++-------- .../prometeu-hal/src/cartridge_loader.rs | 4 +-- crates/console/prometeu-hal/src/color.rs | 19 ------------ .../src/services/vm_runtime/tests.rs | 8 ++--- crates/tools/pbxgen-stress/src/lib.rs | 6 ++-- discussion/index.ndjson | 2 +- ...888-asset-palettes-tooling-and-fixtures.md | 2 +- 7 files changed, 28 insertions(+), 42 deletions(-) diff --git a/crates/console/prometeu-drivers/src/asset.rs b/crates/console/prometeu-drivers/src/asset.rs index 8579038b..5adb1f12 100644 --- a/crates/console/prometeu-drivers/src/asset.rs +++ b/crates/console/prometeu-drivers/src/asset.rs @@ -64,7 +64,7 @@ impl GlyphAssetSlotIndex { const GLYPH_BANK_PALETTE_COUNT_V1: usize = 64; const GLYPH_BANK_COLORS_PER_PALETTE: usize = 16; const GLYPH_BANK_PALETTE_BYTES_V1: usize = - GLYPH_BANK_PALETTE_COUNT_V1 * GLYPH_BANK_COLORS_PER_PALETTE * size_of::(); + GLYPH_BANK_PALETTE_COUNT_V1 * GLYPH_BANK_COLORS_PER_PALETTE * size_of::(); /// Resident metadata for a decoded/materialized asset inside a BankPolicy. #[derive(Debug)] @@ -655,10 +655,13 @@ impl AssetManager { [[Color::BLACK; GLYPH_BANK_COLORS_PER_PALETTE]; GLYPH_BANK_PALETTE_COUNT_V1]; for (p, pal) in palettes.iter_mut().enumerate() { for (c, slot) in pal.iter_mut().enumerate() { - let offset = (p * 16 + c) * 2; - let color_raw = - u16::from_le_bytes([palette_data[offset], palette_data[offset + 1]]); - *slot = Color::from_rgb565_lossy(color_raw); + let offset = (p * 16 + c) * 4; + *slot = Color::rgba( + palette_data[offset], + palette_data[offset + 1], + palette_data[offset + 2], + palette_data[offset + 3], + ); } } @@ -687,10 +690,13 @@ impl AssetManager { [[Color::BLACK; GLYPH_BANK_COLORS_PER_PALETTE]; GLYPH_BANK_PALETTE_COUNT_V1]; for (p, pal) in palettes.iter_mut().enumerate() { for (c, slot) in pal.iter_mut().enumerate() { - let offset = (p * 16 + c) * 2; - let color_raw = - u16::from_le_bytes([palette_data[offset], palette_data[offset + 1]]); - *slot = Color::from_rgb565_lossy(color_raw); + let offset = (p * 16 + c) * 4; + *slot = Color::rgba( + palette_data[offset], + palette_data[offset + 1], + palette_data[offset + 2], + palette_data[offset + 3], + ); } } @@ -1306,14 +1312,13 @@ mod tests { let entry = test_glyph_asset_entry("glyphs", 2, 2); let mut data = vec![0x10, 0x23]; data.extend_from_slice(&[0u8; GLYPH_BANK_PALETTE_BYTES_V1]); - data[2] = 0x34; - data[3] = 0x12; + data[2..6].copy_from_slice(&[0x12, 0x34, 0x56, 0x78]); let bank = AssetManager::decode_glyph_bank_from_buffer(&entry, &data).expect("glyph decode"); assert_eq!(bank.pixel_indices, vec![1, 0, 2, 3]); - assert_eq!(bank.palettes[0][0], Color::from_rgb565_lossy(0x1234)); + assert_eq!(bank.palettes[0][0], Color::from_raw(0x12345678)); } #[test] diff --git a/crates/console/prometeu-hal/src/cartridge_loader.rs b/crates/console/prometeu-hal/src/cartridge_loader.rs index ed46a15f..2b287f96 100644 --- a/crates/console/prometeu-hal/src/cartridge_loader.rs +++ b/crates/console/prometeu-hal/src/cartridge_loader.rs @@ -366,7 +366,7 @@ mod tests { bank_type: BankType::GLYPH, offset, size, - decoded_size: 16 * 16 + (GLYPH_BANK_PALETTE_COUNT_V1 as u64 * 16 * 2), + decoded_size: 16 * 16 + (GLYPH_BANK_PALETTE_COUNT_V1 as u64 * 16 * 4), codec: AssetCodec::None, metadata: json!({ "tile_size": 16, @@ -449,7 +449,7 @@ mod tests { bank_type: BankType::GLYPH, offset: 4, size: 4, - decoded_size: 16 * 16 + (GLYPH_BANK_PALETTE_COUNT_V1 as u64 * 16 * 2), + decoded_size: 16 * 16 + (GLYPH_BANK_PALETTE_COUNT_V1 as u64 * 16 * 4), codec: AssetCodec::None, metadata: json!({ "tile_size": 16, diff --git a/crates/console/prometeu-hal/src/color.rs b/crates/console/prometeu-hal/src/color.rs index 04f16c9d..a4374859 100644 --- a/crates/console/prometeu-hal/src/color.rs +++ b/crates/console/prometeu-hal/src/color.rs @@ -65,23 +65,4 @@ impl Color { (self.0 & 0xFF) as u8 } - #[deprecated(note = "Temporary bridge until the renderer buffer migrates to RGBA8888.")] - pub const fn to_rgb565_lossy(self) -> u16 { - let (r, g, b, _) = Self::unpack_to_native(self.0); - let r5 = (r as u16 >> 3) & 0x1F; - let g6 = (g as u16 >> 2) & 0x3F; - let b5 = (b as u16 >> 3) & 0x1F; - (r5 << 11) | (g6 << 5) | b5 - } - - #[deprecated(note = "Temporary bridge until asset palettes migrate to RGBA8888.")] - pub const fn from_rgb565_lossy(raw: u16) -> Self { - let r5 = ((raw >> 11) & 0x1F) as u32; - let g6 = ((raw >> 5) & 0x3F) as u32; - let b5 = (raw & 0x1F) as u32; - let r = ((r5 << 3) | (r5 >> 2)) as u8; - let g = ((g6 << 2) | (g6 >> 4)) as u8; - let b = ((b5 << 3) | (b5 >> 2)) as u8; - Self::rgba(r, g, b, 255) - } } diff --git a/crates/console/prometeu-system/src/services/vm_runtime/tests.rs b/crates/console/prometeu-system/src/services/vm_runtime/tests.rs index 84dd8a61..457624fd 100644 --- a/crates/console/prometeu-system/src/services/vm_runtime/tests.rs +++ b/crates/console/prometeu-system/src/services/vm_runtime/tests.rs @@ -113,11 +113,11 @@ fn serialized_single_function_module_with_consts( } fn test_glyph_payload_size(width: usize, height: usize) -> usize { - (width * height).div_ceil(2) + (GLYPH_BANK_PALETTE_COUNT_V1 * 16 * std::mem::size_of::()) + (width * height).div_ceil(2) + (GLYPH_BANK_PALETTE_COUNT_V1 * 16 * std::mem::size_of::()) } fn test_glyph_decoded_size(width: usize, height: usize) -> usize { - width * height + (GLYPH_BANK_PALETTE_COUNT_V1 * 16 * std::mem::size_of::()) + width * height + (GLYPH_BANK_PALETTE_COUNT_V1 * 16 * std::mem::size_of::()) } fn test_glyph_asset_entry(asset_name: &str, data_len: usize) -> AssetEntry { @@ -141,8 +141,8 @@ fn test_glyph_asset_entry(asset_name: &str, data_len: usize) -> AssetEntry { fn test_glyph_asset_data() -> Vec { let mut data = - vec![0x11u8; test_glyph_payload_size(16, 16) - (GLYPH_BANK_PALETTE_COUNT_V1 * 16 * 2)]; - data.extend_from_slice(&[0u8; GLYPH_BANK_PALETTE_COUNT_V1 * 16 * 2]); + vec![0x11u8; test_glyph_payload_size(16, 16) - (GLYPH_BANK_PALETTE_COUNT_V1 * 16 * 4)]; + data.extend_from_slice(&[0u8; GLYPH_BANK_PALETTE_COUNT_V1 * 16 * 4]); data } diff --git a/crates/tools/pbxgen-stress/src/lib.rs b/crates/tools/pbxgen-stress/src/lib.rs index 6af0bde7..bc95c149 100644 --- a/crates/tools/pbxgen-stress/src/lib.rs +++ b/crates/tools/pbxgen-stress/src/lib.rs @@ -284,7 +284,7 @@ fn build_glyph_asset() -> (AssetEntry, Vec) { bank_type: BankType::GLYPH, offset: 0, size: payload.len() as u64, - decoded_size: (8 * 8 + GLYPH_BANK_PALETTE_COUNT_V1 * GLYPH_BANK_COLORS_PER_PALETTE * 2) + decoded_size: (8 * 8 + GLYPH_BANK_PALETTE_COUNT_V1 * GLYPH_BANK_COLORS_PER_PALETTE * 4) as u64, codec: AssetCodec::None, metadata: serde_json::json!({ @@ -301,11 +301,11 @@ fn build_glyph_asset() -> (AssetEntry, Vec) { fn build_palette_bytes() -> Vec { let mut bytes = - Vec::with_capacity(GLYPH_BANK_PALETTE_COUNT_V1 * GLYPH_BANK_COLORS_PER_PALETTE * 2); + Vec::with_capacity(GLYPH_BANK_PALETTE_COUNT_V1 * GLYPH_BANK_COLORS_PER_PALETTE * 4); for palette_id in 0..GLYPH_BANK_PALETTE_COUNT_V1 { for color_index in 0..GLYPH_BANK_COLORS_PER_PALETTE { let color = if color_index == 1 { stress_color(palette_id) } else { Color::BLACK }; - bytes.extend_from_slice(&color.raw().to_le_bytes()); + bytes.extend_from_slice(&color.raw().to_be_bytes()); } } bytes diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 411b9717..06cfa7cb 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -35,4 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} -{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} diff --git a/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md b/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md index b494a405..e46b688b 100644 --- a/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md +++ b/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md @@ -2,7 +2,7 @@ id: PLN-0070 ticket: rgba8888-framebuffer-and-pixel-format-direction title: RGBA8888 Asset Palettes Tooling and Fixtures -status: open +status: done created: 2026-05-23 ref_decisions: [DEC-0029] tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] From 537096057a57504e2f6a7528b4f04d1f12d9ad06 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 19:24:07 +0100 Subject: [PATCH 07/10] implements PLN-0071 --- .../prometeu-host-desktop-winit/src/runner.rs | 4 +-- .../src/utilities.rs | 35 +++++++++---------- discussion/index.ndjson | 2 +- ...LN-0071-rgba8888-host-presentation-path.md | 2 +- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/crates/host/prometeu-host-desktop-winit/src/runner.rs b/crates/host/prometeu-host-desktop-winit/src/runner.rs index 2e6a2f2b..a5044674 100644 --- a/crates/host/prometeu-host-desktop-winit/src/runner.rs +++ b/crates/host/prometeu-host-desktop-winit/src/runner.rs @@ -5,7 +5,7 @@ use crate::input::HostInputHandler; use crate::log_sink::HostConsoleSink; use crate::overlay::{capture_snapshot, draw_overlay}; use crate::stats::HostStats; -use crate::utilities::draw_rgb565_to_rgba8; +use crate::utilities::draw_rgba8888_to_rgba8; use pixels::wgpu::PresentMode; use pixels::{Pixels, PixelsBuilder, SurfaceTexture}; use prometeu_drivers::AudioCommand; @@ -285,7 +285,7 @@ impl ApplicationHandler for HostRunner { // Immutable borrow of prometeu-core (different field, ok) let src = self.hardware.gfx.front_buffer(); - draw_rgb565_to_rgba8(src, frame); + draw_rgba8888_to_rgba8(src, frame); if let Some(snapshot) = overlay_snapshot.as_ref() { draw_overlay(frame, Hardware::W, Hardware::H, snapshot); diff --git a/crates/host/prometeu-host-desktop-winit/src/utilities.rs b/crates/host/prometeu-host-desktop-winit/src/utilities.rs index 1967f089..30eb7933 100644 --- a/crates/host/prometeu-host-desktop-winit/src/utilities.rs +++ b/crates/host/prometeu-host-desktop-winit/src/utilities.rs @@ -1,26 +1,25 @@ -/// Copies RGB565 (u16) -> RGBA8888 (u8[4]) to the pixels frame. -/// Pixels format: RGBA8. -pub fn draw_rgb565_to_rgba8(src: &[u16], dst_rgba: &mut [u8]) { +/// 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() { - let (r8, g8, b8) = rgb565_to_rgb888(px); let o = i * 4; - dst_rgba[o] = r8; - dst_rgba[o + 1] = g8; - dst_rgba[o + 2] = b8; - dst_rgba[o + 3] = 0xFF; + dst_rgba[o] = ((px >> 24) & 0xFF) as u8; + dst_rgba[o + 1] = ((px >> 16) & 0xFF) as u8; + dst_rgba[o + 2] = ((px >> 8) & 0xFF) as u8; + dst_rgba[o + 3] = (px & 0xFF) as u8; } } -/// Expands RGB565 to RGB888 (high bit replication). -#[inline(always)] -pub fn rgb565_to_rgb888(px: u16) -> (u8, u8, u8) { - let r5 = ((px >> 11) & 0x1F) as u8; - let g6 = ((px >> 5) & 0x3F) as u8; - let b5 = (px & 0x1F) as u8; +#[cfg(test)] +mod tests { + use super::draw_rgba8888_to_rgba8; - let r8 = (r5 << 3) | (r5 >> 2); - let g8 = (g6 << 2) | (g6 >> 4); - let b8 = (b5 << 3) | (b5 >> 2); + #[test] + fn draw_rgba8888_to_rgba8_preserves_channel_order_and_alpha() { + let src = [0x12345678, 0xABCDEF01]; + let mut dst = [0; 8]; - (r8, g8, b8) + draw_rgba8888_to_rgba8(&src, &mut dst); + + assert_eq!(dst, [0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0x01]); + } } diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 06cfa7cb..5079ba1e 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -35,4 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} -{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} diff --git a/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md b/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md index 226d732b..2270112e 100644 --- a/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md +++ b/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md @@ -2,7 +2,7 @@ id: PLN-0071 ticket: rgba8888-framebuffer-and-pixel-format-direction title: RGBA8888 Host Presentation Path -status: open +status: done created: 2026-05-23 ref_decisions: [DEC-0029] tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] From f9a86fafb029d0151933a6cacb9b0b786105e5f5 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 19:26:09 +0100 Subject: [PATCH 08/10] implements PLN-0072 --- crates/console/prometeu-drivers/src/hardware.rs | 2 +- .../prometeu-system/src/services/vm_runtime/tests.rs | 4 ++-- crates/tools/pbxgen-stress/src/lib.rs | 2 +- discussion/index.ndjson | 2 +- ...8888-residue-removal-and-end-to-end-validation.md | 12 +++++++++++- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/crates/console/prometeu-drivers/src/hardware.rs b/crates/console/prometeu-drivers/src/hardware.rs index 005a870a..71720ce1 100644 --- a/crates/console/prometeu-drivers/src/hardware.rs +++ b/crates/console/prometeu-drivers/src/hardware.rs @@ -22,7 +22,7 @@ use std::sync::Arc; /// /// ### Console Specifications: /// - **Resolution**: 480x270 (16:9 Aspect Ratio). -/// - **Color Depth**: RGB565 (16-bit). +/// - **Color Format**: RGBA8888. /// - **Audio**: Stereo, Command-based mixing. /// - **Input**: 12-button Digital Gamepad + Absolute Touch/Mouse. pub struct Hardware { diff --git a/crates/console/prometeu-system/src/services/vm_runtime/tests.rs b/crates/console/prometeu-system/src/services/vm_runtime/tests.rs index 457624fd..61ba95ed 100644 --- a/crates/console/prometeu-system/src/services/vm_runtime/tests.rs +++ b/crates/console/prometeu-system/src/services/vm_runtime/tests.rs @@ -648,7 +648,7 @@ fn tick_draw_text_survives_no_scene_frame_path() { let mut vm = VirtualMachine::default(); let signals = InputSignals::default(); let code = assemble( - "PUSH_I32 0\nPUSH_I32 0\nPUSH_CONST 0\nPUSH_I32 65535\nHOSTCALL 0\nFRAME_SYNC\nHALT", + "PUSH_I32 0\nPUSH_I32 0\nPUSH_CONST 0\nPUSH_I32 287454020\nHOSTCALL 0\nFRAME_SYNC\nHALT", ) .expect("assemble"); let program = serialized_single_function_module_with_consts( @@ -682,7 +682,7 @@ fn tick_draw_text_survives_no_scene_frame_path() { assert!(report.is_none(), "no-scene overlay text must not crash"); hardware.gfx.present(); - assert_eq!(hardware.gfx.front_buffer()[0], Color::WHITE.raw()); + assert_eq!(hardware.gfx.front_buffer()[0], Color::from_raw(0x11223344).raw()); } #[test] diff --git a/crates/tools/pbxgen-stress/src/lib.rs b/crates/tools/pbxgen-stress/src/lib.rs index bc95c149..ca304c0c 100644 --- a/crates/tools/pbxgen-stress/src/lib.rs +++ b/crates/tools/pbxgen-stress/src/lib.rs @@ -43,7 +43,7 @@ pub fn generate() -> Result<()> { let syscalls = vec![ SyscallDecl { module: "gfx".into(), - name: "clear_565".into(), + name: "clear".into(), version: 1, arg_slots: 1, ret_slots: 0, diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 5079ba1e..ba7c704f 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -35,4 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} -{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} diff --git a/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md b/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md index 7a74f1b8..541b7ed2 100644 --- a/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md +++ b/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md @@ -2,7 +2,7 @@ id: PLN-0072 ticket: rgba8888-framebuffer-and-pixel-format-direction title: RGBA8888 Residue Removal and End to End Validation -status: open +status: done created: 2026-05-23 ref_decisions: [DEC-0029] tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] @@ -107,3 +107,13 @@ Included: contract. - End-to-end visual validation may not exist yet. If so, record the gap and add minimal deterministic checks around RGBA channel order and alpha behavior. + +## Validation Evidence + +- `cargo check --workspace` passed. +- `cargo test --workspace` passed. +- `discussion validate` passed. +- Residue scan command: + `rg -n "RGB565|rgb565|Gfx.*565|clear_565|_565|draw_rgb565|0x1010|front_buffer\\(\\).*u16|Vec|\\[u16\\]|GLYPH_BANK_PALETTE.*u16|size_of::|from_rgb565|to_rgb565" crates docs -S` +- Remaining scan hits are either negative normative documentation or unrelated + `u16` uses such as VM verifier instruction offsets / glyph ids. From d9c208ad4fccf60d1160e6c78da628350876e1ee Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 22:17:40 +0100 Subject: [PATCH 09/10] housekeep DSC-0037 --- discussion/index.ndjson | 4 +- ...rmat-contracts-must-move-as-one-surface.md | 78 ++ ...-framebuffer-and-pixel-format-direction.md | 763 ------------------ ...-rgba8888-runtime-pixel-format-contract.md | 203 ----- ...-rgba8888-published-contracts-and-specs.md | 106 --- ...rgba8888-color-type-hal-and-abi-surface.md | 118 --- ...9-rgba8888-cpu-renderer-and-composition.md | 109 --- ...888-asset-palettes-tooling-and-fixtures.md | 114 --- ...LN-0071-rgba8888-host-presentation-path.md | 103 --- ...sidue-removal-and-end-to-end-validation.md | 119 --- 10 files changed, 80 insertions(+), 1637 deletions(-) create mode 100644 discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md delete mode 100644 discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md delete mode 100644 discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md delete mode 100644 discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md delete mode 100644 discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md delete mode 100644 discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md delete mode 100644 discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md delete mode 100644 discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md delete mode 100644 discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md diff --git a/discussion/index.ndjson b/discussion/index.ndjson index ba7c704f..41e283dd 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -1,4 +1,4 @@ -{"type":"meta","next_id":{"DSC":38,"AGD":38,"DEC":30,"PLN":73,"LSN":46,"CLSN":1}} +{"type":"meta","next_id":{"DSC":38,"AGD":38,"DEC":30,"PLN":73,"LSN":47,"CLSN":1}} {"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"}]} @@ -35,4 +35,4 @@ {"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} -{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0037","status":"done","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0046","file":"discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23"}]} diff --git a/discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md b/discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md new file mode 100644 index 00000000..2d9abf1d --- /dev/null +++ b/discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md @@ -0,0 +1,78 @@ +--- +id: LSN-0046 +ticket: rgba8888-framebuffer-and-pixel-format-direction +title: Pixel Format Contracts Must Move as One Surface +created: 2026-05-23 +tags: [gfx, framebuffer, rgba8888, abi, assets, host] +decision: DEC-0029 +--- + +## Context + +The runtime migrated its graphics contract from RGB565 to RGBA8888. The +important discovery was that RGB565 was not only a renderer storage detail. It +had become a cross-cutting contract spanning VM values, syscalls, HAL types, +renderer buffers, asset palette bytes, host presentation, tests, and specs. + +Treating the change as a local buffer replacement would have left contradictory +contracts behind. The successful migration split the work into small plans, but +each plan still respected one global rule: a pixel format is a published +surface, not an implementation token. + +## Key Decisions + +### RGBA8888 Runtime Pixel Format Contract + +**What:** RGBA8888 became the single logical color and physical framebuffer +contract. RGB565 compatibility surfaces were removed instead of deprecated as +canonical aliases. + +**Why:** Keeping RGB565 as compatibility would have preserved the old coupling +between logical color, framebuffer storage, asset palette encoding, and host +presentation. A single RGBA8888 contract made the runtime easier to reason +about and aligned with alpha-capable UI and modern host presentation. + +**Trade-offs:** The migration intentionally broke existing RGB565 assets and +tests. It also doubled framebuffer byte width. The payoff was removing support +for two simultaneous color models and making alpha an ordinary property of +color instead of a special case. + +## Patterns and Algorithms + +Move published contracts before code. Specs, ABI docs, and public docs were +updated first so implementation work had a stable target. + +Keep API names format-neutral when the runtime supports only one format. +Names such as `GfxClear565` create permanent compatibility residue. The +canonical surface should be `GfxClear`; RGBA8888 is the contract behind it. + +Use the alpha channel as data, not a magic index. Palette indices are ordinary +indices. Transparency is represented by the RGBA alpha channel of the resolved +palette entry rather than by reserving palette index `0`. + +Validate with residue scans. The final pass searched for RGB565, `Gfx*565`, +RGB565 palette sizing, host conversion helpers, and `u16` framebuffer surfaces. +Remaining hits had to be negative documentation or unrelated `u16` usage. + +## Pitfalls + +Pixel format names leak into places that look unrelated: generator fixtures, +cartridge payload size calculations, syscall metadata, host copy utilities, and +test assembly snippets. + +Endian assumptions are easy to hide when using `u32`. The contract must say +RGBA channel order explicitly, and host presentation code must unpack channels +by shifts instead of relying on native memory layout. + +Compatibility helpers are useful only as short-lived scaffolding. If they are +left in normal paths, they become a second contract. + +## Takeaways + +- A framebuffer format is a runtime-wide contract once it reaches ABI, assets, + host presentation, or tests. +- Format-suffixed public APIs should be removed when the format is no longer a + selectable backend. +- Alpha should be modeled as color data, not as a reserved palette index. +- A staged migration can still enforce one final contract when each plan has a + residue scan and acceptance criteria. diff --git a/discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md b/discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md deleted file mode 100644 index b3aaf731..00000000 --- a/discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md +++ /dev/null @@ -1,763 +0,0 @@ ---- -id: AGD-0037 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: Agenda - RGBA8888 Framebuffer and Pixel Format Direction -status: accepted -created: 2026-05-22 -resolved: 2026-05-23 -decision: DEC-0029 -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Contexto - -Estamos avaliando uma possivel mudanca no Prometeu de framebuffer/cor RGB565 -para RGBA8888. - -O Prometeu hoje usa um modelo grafico baseado em blit destrutivo, framebuffer -proprio, tiles/sprites/layers, scene cache, paletas, fonte de hardware e -primitivas basicas de desenho. Historicamente, RGB565 foi escolhido para -reforcar a identidade de console 16-bit / fantasy handheld, reduzir memoria e -manter uma estetica simples. - -Agora existe pressao legitima por RGBA8888: - -- e o formato natural de muitos hosts modernos, texturas e APIs de janela; -- facilita UI mais polida, alpha real, transicoes e efeitos; -- combina melhor com a direcao do Hub estilo Homebrew Channel; -- pode reduzir conversoes no host desktop; -- abre uma ponte mais direta para backends GPU futuros. - -Ao mesmo tempo, o objetivo do Prometeu continua sendo: - -- hardware agnostico; -- barato/DIY quando possivel, mas sem manter RGB565 como contrato de - compatibilidade nesta mudanca; -- bom em portateis modernos; -- 480x270 a 60 Hz; -- estetica de fantasy console; -- Hub visualmente mais rico sem perder o modelo operacional; -- caminho futuro para pipeline grafico mais avancado. - -Direcao atual da discussao: seguir pela Opcao B. RGB565 deve sair por completo -do contrato runtime/HAL/renderer/host/asset decode desta frente. RGBA8888 deve -ser o formato unico fisico do framebuffer e tambem a representacao normal de -cor do runtime. Esta mudanca nao deve abrir compatibilidade dupla, backend -RGB565, render thread, GPU backend ou abstracao generica de pixel format. - -Esta agenda e somente analise arquitetural. Nenhum codigo deve ser alterado -como parte desta discussao. - -## Estado Atual do Codigo - -### Acoplamento direto a RGB565 - -O acoplamento central esta em `crates/console/prometeu-hal/src/color.rs`: - -- `Color(pub u16)` representa explicitamente RGB565. -- `Color::rgb(r, g, b)` quantiza componentes 8-bit para 5/6/5. -- `Color::from_raw(raw: u16)` e `Color::raw() -> u16` expõem o formato fisico. -- `Color::COLOR_KEY` e `Color::TRANSPARENT` usam magenta RGB565 como chave de - transparencia. -- `unpack_to_native` e `pack_from_native` operam nos canais 5/6/5. - -Isso significa que `Color` hoje nao e uma cor logica independente; ele e o -proprio pixel RGB565. - -### HAL e API publica de GFX - -`crates/console/prometeu-hal/src/gfx_bridge.rs` fixa RGB565 no contrato: - -- `front_buffer(&self) -> &[u16]`; -- todos os draws recebem `Color`; -- fades expõem `Color`; -- o nome de syscall `GfxClear565` reforca RGB565 no contrato VM/HAL. - -Impacto: qualquer migracao direta para `Vec` quebra a API do HAL, testes, -VM dispatch e host. - -### Buffers do renderer - -`crates/console/prometeu-drivers/src/gfx.rs` fixa o formato fisico: - -- `front: Vec`; -- `back: Vec`; -- `RenderTarget.back: &mut [u16]`; -- `front_buffer() -> &[u16]`; -- `clear`, `draw_pixel`, `draw_char`, tile draw e sprite draw escrevem `u16`; -- `present()` faz swap dos dois buffers, sem copia; -- `render_scene_from_cache()` limpa o back com `Color::BLACK.raw()`; -- tiles/sprites resolvem `Color` e gravam `color.raw()`; -- fades percorrem `&mut [u16]` e fazem blend em canais RGB565. - -O modelo destrutivo em si nao depende conceitualmente de RGB565, mas a -implementacao atual depende. - -### Host/window layer - -`crates/host/prometeu-host-desktop-winit/src/runner.rs` assume que o runtime -publica RGB565: - -- le `self.hardware.gfx.front_buffer()`; -- chama `draw_rgb565_to_rgba8(src, frame)`. - -`crates/host/prometeu-host-desktop-winit/src/utilities.rs` contem: - -- `draw_rgb565_to_rgba8(src: &[u16], dst_rgba: &mut [u8])`; -- `rgb565_to_rgb888(px: u16)`. - -Ou seja, o host `pixels` ja apresenta RGBA8, mas o runtime entrega RGB565 e o -host converte a cada redraw necessario. - -### GlyphBank, paletas, sprites e scene cache - -`crates/console/prometeu-hal/src/glyph_bank.rs` preserva uma separacao util: - -- pixels de glyph/tile sao indices `u8`; -- payload serializado usa indices 4bpp; -- runtime expande para um `u8` por pixel; -- indice 0 e reservado para transparencia; -- a tabela de paletas e `[[Color; 16]; 64]`. - -Isso acopla a resolucao final de cor a RGB565, mas nao obriga os tiles/sprites -a deixarem de ser indexados. A estrutura mais importante para preservar a -estetica fantasy console ja existe: indices + paletas limitadas. - -`crates/console/prometeu-drivers/src/asset.rs` fixa o formato serializado de -paleta: - -- `GLYPH_BANK_PALETTE_BYTES_V1 = 64 * 16 * size_of::()`; -- decode le cada cor como `u16::from_le_bytes`; -- escreve `Color(color_raw)`; -- testes e `pbxgen-stress` tambem assumem paletas RGB565 little-endian. - -O asset pipeline atual, portanto, e v1/RGB565 para paletas, mas os indices dos -tiles/sprites podem permanecer iguais. - -### Fade, blend e primitivas - -`gfx.rs` implementa blend/fade em RGB565: - -- `blend_rgb565(dst: u16, src: u16, mode: BlendMode) -> u16`; -- `apply_fade_to_buffer(back: &mut [u16], level, fade_color)`; -- `fill_rect_blend` mistura por pixel nos canais 5/6/5; -- `draw_text` e fonte de hardware escrevem cor opaca direta. - -RGBA8888 simplificaria alguns efeitos alpha, mas tambem exigiria disciplina -para nao transformar todos os draws em blend caro por pixel. - -### VM e syscall - -`crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs` usa: - -- `get_color(value: i64) -> Color` via `Color::from_raw(value as u16)`; -- `GfxClear565`, com range `0xFFFF`. - -Essa e uma fronteira importante: o PBS/VM conhece hoje o valor bruto RGB565. -Se a cor logica mudar para RGBA8888, a VM API precisa de compatibilidade ou de -uma transicao clara. - -## Problema - -O problema nao e apenas trocar `Vec` por `Vec`. - -Existem quatro conceitos misturados hoje: - -1. cor logica usada pelo runtime e HAL; -2. formato fisico do framebuffer; -3. formato serializado das paletas em `assets.pa`; -4. formato de apresentacao do host/backend. - -RGB565 hoje ocupa os quatro papeis. A direcao escolhida e remove-lo desses -papeis, aceitando a quebra coordenada de HAL, asset pipeline, testes, VM, host -e renderer como o custo da limpeza arquitetural. - -A pergunta arquitetural restante nao e mais se RGBA8888 deve substituir RGB565. -A resposta operacional e sim. A pergunta agora e como fazer essa substituicao -sem misturar a migracao de pixel format com render thread, GPU backend, -abstracao de backend, asset pipeline v2 amplo ou outras frentes. - -## Pontos Criticos - -### Identidade visual nao precisa ser formato de memoria - -O Prometeu pode continuar sendo uma maquina com estetica 16-bit mesmo usando -RGBA8888 em algum ponto do pipeline. A limitacao artistica pode morar em: - -- assets indexados; -- paletas limitadas; -- regras de composicao; -- resolucao 480x270; -- fontes/pixel art; -- ferramentas de autoria; -- validadores do asset pipeline. - -O formato fisico do framebuffer e uma decisao de implementacao, nao -necessariamente uma promessa estetica. - -### RGBA8888 como cor logica e formato fisico unico - -Um tipo `Color` semanticamente RGBA8888, ou um tipo explicito -`ColorRgba8888`, deve substituir `Color(pub u16)`: - -- representar alpha real; -- evitar quantizacao precoce; -- facilitar UI/HUB; -- alinhar com texturas modernas; -- eliminar a conversao obrigatoria RGB565 -> RGBA8 no host desktop. - -Nesta agenda, RGBA8888 nao e apenas um backend alternativo. Ele e o formato -unico fisico do framebuffer. - -### RGB565 deve sair do contrato - -RGB565 continua sendo historicamente importante, mas nao deve permanecer como -compatibilidade operacional nesta mudanca. A migracao deve remover: - -- `Color(pub u16)` como cor publica; -- `Vec` como front/back buffer; -- `front_buffer() -> &[u16]`; -- APIs `Gfx*565` ou qualquer outra superficie publica com formato RGB565 no - nome como APIs canonicas; -- paletas runtime armazenadas como `Color` RGB565; -- conversao host `draw_rgb565_to_rgba8` no caminho normal; -- helpers `blend_rgb565`, `pack_from_native`, `unpack_to_native` como base do - renderer. - -Se algum alvo futuro precisar RGB565 por hardware, isso deve ser tratado como -uma nova discussao depois, nao como requisito desta migracao. - -### O blit destrutivo pode sobreviver - -RGBA8888 nao exige scene graph, GPU obrigatoria ou renderer retained. O modelo -pode continuar: - -```text -frame state -> compose into back buffer -> present/publish -``` - -O que muda e o tipo do pixel no alvo de materializacao. - -### Evitar abrir backend abstraction nesta mudanca - -A VM nao deveria tocar diretamente no framebuffer. Ela deve produzir estado ou -pacotes imutaveis de frame, e o renderer deve ser dono exclusivo dos buffers. - -Essa direcao continua correta no longo prazo, mas esta agenda agora restringe o -escopo. A migracao RGBA8888 deve mudar o formato atual do renderer existente, -nao introduzir uma matriz de backends. Render thread, `RenderFramePacket` -formal, SDL/GPU backend e bare-metal backend ficam fora deste corte. - -O limite pragmatico: a VM/HAL nao deve expor buffer mutavel direto, mas a -implementacao deste passo pode continuar com o renderer CPU destrutivo atual, -apenas migrado para RGBA8888. - -## Trade-offs Numericos - -Resolucao interna atual: `480x270 = 129600` pixels. - -### Memoria de framebuffer - -RGB565: - -- 2 bytes por pixel; -- 1 buffer: `259200` bytes = `253.125 KiB`; -- front + back: `518400` bytes = `506.25 KiB`. - -RGBA8888: - -- 4 bytes por pixel; -- 1 buffer: `518400` bytes = `506.25 KiB`; -- front + back: `1036800` bytes = `1012.5 KiB`. - -Conclusao: RGBA8888 dobra a memoria dos framebuffers. Em desktop isso e -irrelevante; em alvo DIY/barato pode ser significativo, mas ainda e pequeno em -termos absolutos para muitos portateis modernos. - -### Largura de banda por full-frame touch - -Um passe que toca um buffer inteiro: - -- RGB565: `253.125 KiB/frame`, cerca de `14.8 MiB/s` a 60 Hz; -- RGBA8888: `506.25 KiB/frame`, cerca de `29.7 MiB/s` a 60 Hz. - -O custo real pode multiplicar isso, porque o frame atual pode fazer: - -- clear; -- raster de layers; -- raster de sprites; -- scene fade fullscreen; -- hud fade fullscreen; -- conversao/apresentacao no host. - -No desktop atual, a conversao host RGB565 -> RGBA8 le `253.125 KiB` e escreve -`506.25 KiB` por frame convertido, cerca de `44.5 MiB/s` a 60 Hz so nessa -etapa. Um backend RGBA8888 pode eliminar essa conversao, mas so se evitar uma -copia equivalente para o frame do host. - -### CPU - -Impacto esperado por operacao: - -- opaque blit: RGBA8888 pode ser simples (`dst = src`), mas move o dobro de - bytes; pode ficar mais rapido em CPUs modernas se alinhar melhor a `u32`; -- masked blit: continua barato se entradas com alpha transparente pulam antes - de blendar; -- alpha blit: fica mais expressivo, mas custa multiplicacoes/interpolacoes por - canal se usado indiscriminadamente; -- fade: RGBA8888 usa canais 8-bit e pode ser mais simples conceitualmente, mas - ainda e passe fullscreen caro; -- fill_rect: pode ser rapido com fill de `u32`, desde que seja opaco; -- draw_text: continua opaco e simples, nao deve virar alpha blend por padrao; -- sprites: devem manter fast path indexado opaco/mascarado; alpha por sprite - deve ser opt-in; -- scene composition: deve continuar priorizando writes opacos e masked skips. - -### Bateria - -Em portateis baratos, dobrar bytes movimentados pode afetar bateria se a CPU -fizer toda composicao. Por outro lado, em portateis modernos com GPU, RGBA8888 -pode economizar conversoes e usar caminhos nativos de textura/composicao. - -Conclusao da agenda atual: aceitar o custo de memoria/banda do RGBA8888 como -preco de simplificacao e futuro visual. A arquitetura nao deve exigir GPU, mas -tambem nao deve manter RGB565 como fallback no escopo desta mudanca. - -### Simplicidade - -RGBA8888 simplifica: - -- alpha real; -- integracao com host moderno; -- efeitos UI; -- raciocinio em canais 8-bit; -- possivel upload de textura. - -RGBA8888 complica: - -- contrato atual da VM/HAL; -- asset palette v1; -- testes que comparam `u16`; -- risco de alpha blend virar caminho padrao; -- necessidade de remover RGB565 de forma coordenada, sem camada dupla de - compatibilidade. - -## Blit Destrutivo com RGBA8888 - -O modelo destrutivo continuaria valido: - -```text -clear/fill/raster tiles/raster sprites/fades/overlay -> back buffer -> present -``` - -Os caminhos rapidos precisam ser explicitos: - -1. Opaque blit: - - `dst = src`; - - usado para background, tiles totalmente opacos, fills, texto opaco e UI - sem alpha; - - deve ser o caminho dominante. - -2. Masked blit: - - se a entrada resolvida tiver alpha transparente, pula; - - caso contrario, `dst = resolved_color`; - - deve ser o caminho dominante para sprites e tiles com recorte. - -3. Alpha blit: - - `dst = src-over(dst)`; - - usado apenas quando o asset/comando declarar alpha real ou efeito; - - nao deve ser implicito para todo sprite/tile. - -Para evitar que tudo vire alpha blend caro: - -- manter assets indexados como opacos/mascarados por padrao; -- resolver paletas para RGBA; transparencia deve vir do canal alpha da entrada - resolvida, nao de um indice reservado; -- separar APIs/comandos `draw_opaque`, `draw_masked`, `draw_alpha`; -- manter `BlendMode` classico como efeito opt-in; -- medir alpha paths separadamente; -- nao usar RGBA8888 como desculpa para tratar cada pixel como translucido. - -## Compatibilidade com Asset Pipeline - -Tiles/sprites podem continuar indexados e paletizados. - -Recomendacao conceitual: - -- `pixel_indices: Vec` permanece; -- indices de paleta sao indices comuns; transparencia vem do canal alpha da - entrada RGBA8888 resolvida; -- limites 16 cores por paleta e 64 paletas permanecem como contrato artistico; -- paletas passam a resolver para RGBA8888; -- o payload de paleta deve deixar de ser RGB565; -- `assets.pa` e as ferramentas que geram/validam glyph banks precisam migrar - para paletas RGBA8888 no mesmo contrato desta frente. - -Isso preserva o modelo artistico indexado/paletizado, mas nao preserva -compatibilidade binaria RGB565 de paleta. - -Forma alvo: - -```text -asset palette RGBA8888 -> decode -> [[ColorRgba8888; 16]; 64] -``` - -Forma transitoria aceitavel apenas durante execucao da migracao, nao como -estado final: - -```text -old RGB565 test fixture -> one-time conversion -> RGBA8888 fixture -``` - -A decisao importante e evitar conversao por pixel a cada frame. Depois da -migracao, o renderer deve compor diretamente em RGBA8888. - -## Hardware Agnostico e Backends - -O jogo/PBS/VM nao deve saber detalhes de apresentacao do host, mas nesta agenda -nao criaremos multiplos backends de pixel format. - -Arquitetura alvo restrita desta mudanca: - -```text -VM/game tick - -> estado/comandos atuais - -> renderer CPU destrutivo compoe RGBA8888 - -> host apresenta RGBA8888 -``` - -Fora de escopo desta agenda: - -- CPU RGB565 reference backend; -- suporte simultaneo RGB565/RGBA8888; -- SDL texture backend como abstracao nova; -- OpenGL ES / wgpu GPU backend; -- bare-metal framebuffer backend; -- `FrameSurface` generico com matriz de formatos. - -O contrato publico deve parar de expor `&[u16]`. No alvo desta migracao, a -saida normal deve ser RGBA8888, por exemplo `&[u32]` ou bytes RGBA8 com ordem -explicitamente documentada. - -Se uma abstracao generica de surface for criada, ela deve ter apenas um formato -suportado inicialmente: RGBA8888. Nao deve reintroduzir RGB565 por design. - -## VM e Render Thread - -A separacao VM/render thread ajuda a migracao, mas nao deve ser feita no mesmo -passo da troca de pixel format. - -Modelo desejado: - -- VM thread executa logica, syscalls, `frame()`, estado de sprites/cenas; -- VM nao toca diretamente no framebuffer; -- VM publica pacote imutavel de frame; -- render thread e dona exclusiva do framebuffer; -- host consome frame publicado. - -Impacto na migracao para RGBA8888: - -- facilita trocar backend sem afetar VM; -- reduz disputas entre VM e blit CPU no mesmo core quando houver multicore; -- exige disciplina de snapshots e ownership; -- pode aumentar latencia se a publicacao nao for bem desenhada; -- cria uma mudanca arquitetural grande demais para misturar com color format. - -Portanto, render thread deve ficar fora desta frente. A migracao deve focar em -substituir RGB565 por RGBA8888 no renderer existente. - -## Opcoes - -### Opcao A - Manter RGB565 como framebuffer principal - -**Abordagem:** preservar `Color(pub u16)`, `Vec`, asset palettes RGB565 e -host convertendo para RGBA8. - -**Pros:** - -- menor memoria e banda; -- baixo risco; -- preserva compatibilidade com VM/HAL/testes; -- bom para bare-metal e DIY; -- alinhado com a decisao historica de performance. - -**Contras:** - -- alpha real continua ruim; -- Hub moderno fica limitado ou cheio de hacks; -- host moderno paga conversao RGB565 -> RGBA8; -- formato fisico continua confundido com identidade artistica; -- backends GPU/RGBA ficam menos naturais. - -**Manutenibilidade:** simples no curto prazo, mas tende a acumular excecoes -para UI e backend moderno. - -### Opcao B - Migrar tudo para RGBA8888 - -**Abordagem:** trocar `Color` para RGBA8888, `Gfx` para `Vec`, HAL para -`&[u32]`/RGBA, host sem conversao RGB565, paletas resolvidas em RGBA. RGB565 -deixa de existir como contrato runtime, formato de framebuffer, formato normal -de paleta ou backend de compatibilidade. - -**Pros:** - -- modelo moderno e direto; -- alpha real; -- host desktop mais natural; -- UI/HUB mais expressivo; -- caminho mais direto para GPU. -- remove a ambiguidade entre cor logica, pixel fisico e formato de host; -- reduz superficie de manutencao ao evitar suporte duplo RGB565/RGBA8888. - -**Contras:** - -- quebra grande de HAL/VM/testes/assets; -- dobra memoria dos framebuffers; -- pode piorar portateis baratos se tudo for CPU; -- remove RGB565 como caminho barato; -- exige migracao coordenada de fixtures, geradores de asset e syscalls. - -**Manutenibilidade:** direcao aceita nesta agenda. A migracao e agressiva, mas -o resultado final e mais simples porque ha um unico formato fisico e logico. - -### Opcao C - Suportar ambos via backend/pixel format desde ja - -**Abordagem:** introduzir abstracao de backend/pixel format agora, com renderer -capaz de materializar RGB565 ou RGBA8888. - -**Pros:** - -- hardware agnostico desde o inicio; -- desktop e bare-metal podem escolher formatos naturais; -- evita uma aposta unica. - -**Contras:** - -- alto risco de refatoracao ampla; -- pode criar abstracao prematura; -- `Gfx` pode virar god object; -- testes dobram; -- mistura pixel format com backend abstraction antes de consolidar cor logica. - -**Manutenibilidade:** boa se bem delimitada, ruim se virar uma matriz de -formatos espalhada pelo renderer. - -**Status nesta agenda:** rejeitada. Suporte duplo e compatibilidade RGB565 -ficam fora de escopo. - -### Opcao D - RGBA8888 como cor logica, backends RGB565/RGBA8888 como destino - -**Abordagem:** separar primeiro cor logica de formato fisico. Introduzir tipos -explicitos `ColorRgba8888` e `ColorRgb565`; preservar asset v1 e backend atual; -permitir que paletas/assets resolvam para cor logica ou para formato de backend -em caches preparados; migrar `Gfx`/host em etapas. - -**Pros:** - -- separa identidade artistica de formato de memoria; -- preserva RGB565 para targets baratos; -- prepara RGBA8888 para Hub e backends modernos; -- permite migracao incremental; -- evita mexer em render thread/GPU/asset v2 de uma vez; -- reduz confusao entre logical color e physical pixel. - -**Contras:** - -- adiciona tipos e conversoes; -- exige disciplina para nao converter por pixel no hot path; -- precisa planejar compatibilidade VM/HAL; -- pode manter dois mundos por um tempo. - -**Manutenibilidade:** melhor equilibrio se a primeira etapa for pequena e -explícita: tipos, conversoes e fronteiras; nao backend completo imediato. - -**Status nesta agenda:** rejeitada pela direcao atual. Manter RGB565 como -backend valido criaria exatamente a compatibilidade que queremos evitar. - -## Sugestao / Recomendacao - -Recomendacao atual: seguir pela Opcao B. - -Ou seja: - -- tratar RGBA8888 como formato logico e fisico unico do runtime; -- remover RGB565 por completo do contrato normal; -- preservar assets indexados/paletizados e limites artisticos; -- migrar `Gfx` para buffers RGBA8888; -- atualizar HAL, VM/syscalls, host, testes, paletas e asset tooling para - RGBA8888; -- atualizar specs, docs publicos e contratos ABI para remover RGB565, - `Gfx*565`, `u16` como contrato de cor/framebuffer e paletas RGB565; -- nao introduzir render thread, GPU backend ou abstracao multi-backend no mesmo - passo. - -A identidade 16-bit/fantasy console deve ser preservada por resolucao, -paletas, assets, regras de autoria e estilo visual, nao pelo fato de todo -framebuffer fisico ser RGB565. - -O caminho incremental mais seguro parece: - -1. Definir o tipo de cor RGBA8888 canonico: - - `Color` pode mudar para RGBA8888, ou ser substituido por - `ColorRgba8888`; - - a representacao raw deve ser `u32` ou bytes RGBA8 documentados; - - alpha `255` deve ser o default para cores opacas. - -2. Remover o contrato RGB565 do HAL/VM: - - trocar `front_buffer() -> &[u16]`; - - remover APIs de compatibilidade com sufixo de formato, como - `GfxClear565` ou qualquer superficie `Gfx*565`, e substitui-las por nomes - canonicos format-neutral, como `GfxClear`; - - atualizar validacoes de range de cor de `0xFFFF` para RGBA8888; - - atualizar testes que comparam `Color::raw()` como `u16`. - -2b. Atualizar contratos publicados: - - specs canonicas; - - docs publicos; - - contratos ABI/syscall; - - qualquer documento que ainda descreva RGB565, `Gfx*565`, `u16` como cor - ou framebuffer, ou paletas RGB565. - -3. Atualizar constantes e helpers: - - cores passam a ter representacao logica clara; - - `COLOR_KEY` deve virar semantica de transparencia/mascara, nao magenta - em RGB565. - -4. Migrar `Gfx` para RGBA8888: - - `front/back: Vec` ou storage equivalente; - - `RenderTarget` em RGBA8888; - - `blend_rgb565` substituido por blend RGBA8888; - - fade, fill, text, tile draw e sprite draw atualizados. - -5. Migrar paletas e asset tooling: - - payload de paleta deixa de ser RGB565; - - `GlyphBank.palettes` passa para RGBA8888; - - `pbxgen-stress`, fixtures e testes acompanham; - - indices de paleta deixam de carregar semantica especial de transparencia. - -6. Atualizar host/window layer: - - remover `draw_rgb565_to_rgba8` do caminho normal; - - copiar/publicar RGBA8888 para `pixels` com ordem correta; - - manter overlay compativel com frame RGBA8. - -7. Validar visual e performance: - - testes unitarios atualizados; - - testes de render/fade/blend; - - snapshots ou verificacoes visuais quando disponiveis; - - medicao de custo do novo frame RGBA8888. - -8. Deixar explicitamente para depois: - - render thread; - - GPU backend; - - backend RGB565; - - abstracao multi-formato; - - mudancas esteticas nao necessarias para a migracao. - -## Perguntas em Aberto - -- [x] Queremos declarar RGBA8888 como formato logico de cor do runtime, ou - apenas como um backend fisico adicional? RGBA8888 deve ser formato logico e - fisico unico. -- [x] A VM/PBS deve continuar aceitando valores RGB565 brutos como contrato de - compatibilidade? Nao. RGB565 nao deve permanecer como compatibilidade. -- [x] `GfxClear565` deve ganhar uma syscall nova RGBA/logical color antes de - qualquer deprecacao? Nao como API com sufixo de formato. APIs criadas para - compatibilidade RGB565, como `GfxClear565` ou qualquer superficie `Gfx*565`, - devem deixar de existir; o contrato canonico deve usar nomes format-neutral, - como `GfxClear`. -- [x] `Color` deve ser renomeado para `ColorRgb565` primeiro, ou deve mudar de - semantica para RGBA com um tipo RGB565 separado? A direcao aceita e que o - contrato final exponha RGBA8888; detalhes de rename ficam para decisao/plano. -- [x] O asset `.pa` v1 deve permanecer RGB565 ate haver necessidade de `.pa` v2? - Nao como estado final desta frente. Paletas devem migrar para RGBA8888. -- [x] Paletas carregadas devem guardar RGB565, RGBA8888, ou tabelas preparadas - por backend? RGBA8888. -- [x] Alpha real deve ser permitido em paletas, em sprites separados, ou apenas - em comandos/effects/UI por enquanto? Alpha real deve ser permitido em - qualquer paleta, sprite, tile e demais superficies/elementos que precisarem - dele. Comandos dedicados para gerenciar somente alpha serao necessarios, mas - ficam fora desta wave. -- [x] Quais operacoes podem usar alpha no primeiro corte sem comprometer custo? - Todas as operacoes podem usar alpha no primeiro corte. A direcao e tudo ou - nada; otimizacao e especializacao de caminhos ficam para depois. -- [x] O backend RGBA8888 deve ser implementado primeiro no CPU renderer ou no - host desktop? No CPU renderer existente, com host atualizado para consumir - RGBA8888. -- [x] Quais testes visuais/snapshots definem equivalencia aceitavel entre - RGB565 e RGBA8888? Como RGB565 sai, equivalencia deve ser apenas de - intencao visual/composicao, nao igualdade binaria. Todos os testes devem ser - RGBA8888-first. -- [x] A decisao antiga de `AGD-0010` contra RGBA8888 no `back` continua valida - apenas para aquela fase de performance, ou deve ser substituida por uma nova - direcao mais ampla? Deve ser substituida por nova decisao especifica desta - agenda. -- [x] Qual ordem raw deve ser canonica para `u32`/bytes: RGBA, ABGR, ARGB, ou - a ordem esperada pelo `pixels` frame? RGBA. -- [x] Alpha no framebuffer final deve ser sempre `255` apos composicao, ou o - front buffer pode publicar alpha significativo? Por enquanto, o front buffer - pode publicar alpha significativo. A diretriz deve forcar o minimo possivel - e dar liberdade ao desenvolvedor. -- [x] O asset package deve mudar versao/formato explicitamente para paletas - RGBA8888 ou apenas reinterpretar metadata existente? O asset package deve - usar paletas em formato RGBA8888, sem compatibilidade com paletas RGB565, - mesmo que isso quebre assets existentes. - -## Criterio para Encerrar - -Esta agenda pode ser encerrada quando houver acordo sobre: - -- RGBA8888 como cor logica e formato fisico unico; -- RGB565 sem papel de compatibilidade nesta frente; -- como preservar a identidade fantasy console; -- como migrar asset package, VM/HAL, host, testes e renderer; -- quais conversoes temporarias sao aceitaveis apenas durante a migracao; -- qual e a ordem incremental de substituicao; -- o que fica explicitamente fora de escopo, especialmente render thread, GPU - backend e suporte multi-formato. - -Com essas respostas, a agenda deve virar uma decisao normativa antes de -qualquer edicao de spec ou codigo. - -## Discussao - -Entrada inicial: avaliar cuidadosamente a viabilidade de migrar o Prometeu de -RGB565 para RGBA8888, considerando estado atual do codigo, trade-offs, -compatibilidade de assets, hardware agnostico, VM/render thread, plano -incremental, riscos e uma recomendacao arquitetural. - -Analise inicial, agora superada parcialmente: a migracao e viavel, mas nao -deve ser feita como troca mecanica e isolada de `u16` por `u32`. A primeira -versao da agenda considerava separar cor logica, formato fisico de framebuffer, -formato serializado de assets e formato de apresentacao do backend, preservando -RGB565 como compatibilidade. Essa preservacao nao e mais a direcao aceita. - -Atualizacao em 2026-05-23: a direcao da agenda mudou para Opcao B. RGB565 deve -sair por completo, sem compatibilidade. RGBA8888 deve ser o formato unico -fisico e logico. O escopo desta frente deve ser somente migrar RGB565 para -RGBA8888 no runtime/HAL/renderer/host/assets/testes atuais, sem abrir -multi-backend, render thread ou GPU backend. - -Atualizacao em 2026-05-23: as perguntas restantes foram fechadas. Alpha real -e permitido amplamente em paletas, sprites, tiles e demais operacoes; comandos -especificos para gerenciar somente alpha ficam fora desta wave. O primeiro -corte aceita alpha em todas as operacoes, deixando otimizacoes para depois. -Testes devem ser RGBA8888-first. A ordem raw canonica e RGBA. O front buffer -pode publicar alpha significativo por enquanto. O asset package deve usar -paletas RGBA8888 sem compatibilidade com assets RGB565 existentes. - -## Resolucao - -A agenda esta pronta para ser aceita e convertida em decisao normativa. A -direcao atual e migrar tudo para RGBA8888 como formato unico fisico e logico, -removendo RGB565 sem compatibilidade. A decisao deve cristalizar: - -- RGBA8888 como contrato logico e fisico unico; -- ordem raw canonica RGBA; -- alpha significativo permitido no framebuffer publicado; -- alpha permitido em paletas, sprites, tiles e operacoes do renderer; -- comandos dedicados de alpha fora desta wave; -- testes RGBA8888-first; -- asset package com paletas RGBA8888 sem compatibilidade RGB565; -- specs, docs e contratos ABI atualizados como parte obrigatoria da propagacao; -- render thread, GPU backend, backend RGB565 e suporte multi-formato fora de - escopo. diff --git a/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md b/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md deleted file mode 100644 index c5ecd45f..00000000 --- a/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -id: DEC-0029 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: RGBA8888 Runtime Pixel Format Contract -status: accepted -created: 2026-05-23 -ref_agenda: AGD-0037 -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Status - -Accepted. Drafted from accepted agenda AGD-0037 and accepted on 2026-05-23. -Execution is split across the linked RGBA8888 migration plan family. - -## Contexto - -AGD-0037 evaluated whether Prometeu should keep RGB565 as the runtime color -and framebuffer contract or migrate to RGBA8888. - -RGB565 is currently coupled into multiple layers: - -- the public `Color(pub u16)` representation; -- HAL and VM-facing GFX APIs such as `front_buffer() -> &[u16]` and - `GfxClear565`; -- renderer front/back buffers and blending helpers; -- host presentation through RGB565-to-RGBA8 conversion; -- serialized asset palettes in `assets.pa`; -- tests and fixtures that assert RGB565 values. - -The accepted agenda resolves that RGB565 should not remain as compatibility -surface in this migration. RGBA8888 becomes both the logical color contract and -the physical framebuffer format. This decision replaces the prior performance -phase direction in AGD-0010 that rejected RGBA8888 for the back buffer. - -## Decisao - -Prometeu SHALL migrate its normal runtime graphics contract from RGB565 to -RGBA8888. - -RGBA8888 MUST be the single canonical logical color representation for the -runtime, HAL, VM-facing color values, renderer buffers, asset palette decode, -tests, and host presentation path. - -RGBA8888 MUST also be the single canonical physical framebuffer format for this -wave. RGB565 MUST NOT remain as a supported runtime framebuffer backend, -compatibility mode, normal palette encoding, VM color ABI, renderer pixel -format, or host presentation contract. - -The canonical raw channel order is RGBA. - -The published front buffer MAY contain meaningful alpha. The runtime MUST NOT -force the final front buffer alpha channel to `255` as a blanket rule in this -wave. - -Alpha is allowed broadly. Palettes, sprites, tiles, primitives, UI/effects, and -renderer operations MAY carry and apply real alpha where the operation needs -it. The first implementation wave SHALL treat alpha as available across all -operations rather than splitting the migration into alpha-capable and -alpha-forbidden paths. - -Dedicated commands for managing only alpha are expected in the broader design, -but they are explicitly out of scope for this wave. - -Asset packages MUST encode palettes as RGBA8888. Existing RGB565 palette assets -MUST NOT be preserved as compatible runtime input. Any old asset or fixture that -is still needed must be regenerated or converted as part of migration work, not -supported through a permanent compatibility path. - -Tests MUST be RGBA8888-first. They MUST assert the new RGBA8888 contract rather -than proving binary equivalence with RGB565 output. - -This decision does not introduce render thread ownership, a GPU backend, an -RGB565 backend, or a generic multi-format backend abstraction. - -## Rationale - -RGB565 currently plays too many roles at once: logical color, physical pixel, -serialized palette encoding, and host presentation source. Keeping it as a -compatibility layer would preserve that coupling and force the new RGBA8888 -direction to coexist with an old contract that the runtime no longer wants to -guarantee. - -RGBA8888 aligns better with modern host APIs, texture upload paths, alpha-based -UI, Hub visuals, and future GPU-oriented work. It also removes the mandatory -RGB565-to-RGBA8 conversion in the desktop host's normal presentation path. - -The migration deliberately accepts the cost of a coordinated breaking change: -HAL, VM/syscalls, renderer buffers, asset decode, tooling, fixtures, and tests -must move together. The result is simpler than maintaining two color formats or -a premature backend matrix. - -The fantasy-console identity is not tied to RGB565 memory layout. It should be -preserved by resolution, indexed assets, palette limits, art direction, -authoring constraints, and composition rules. - -Allowing meaningful framebuffer alpha and broad alpha in operations keeps the -contract flexible while the renderer evolves. Performance specialization remains -important, but it should follow the correctness migration instead of blocking -the pixel-format contract. - -## Invariantes / Contrato - -- `Color` or its replacement MUST represent RGBA8888 semantics in the final - contract. -- Raw color values MUST use RGBA channel order. -- Runtime renderer front/back buffers MUST materialize RGBA8888 pixels. -- Public runtime/HAL/host contracts MUST stop exposing `&[u16]` as the normal - framebuffer output. -- Format-suffixed compatibility APIs such as `GfxClear565` or any other - `Gfx*565` surface MUST cease to exist in the final contract. Canonical GFX API - names MUST be format-neutral, e.g. `GfxClear`, because RGBA8888 is the only - supported runtime color contract. -- RGB565 conversion helpers may exist only as temporary migration utilities or - test-regeneration tools; they MUST NOT sit on the normal runtime hot path. -- Asset palette payloads MUST be RGBA8888. -- Indexed tile/sprite payloads MAY remain indexed/paletized; palette index - limits and 4bpp authored pixels may remain part of the artistic model. -- Palette indices are ordinary indices. Transparency MUST be represented by the - RGBA alpha channel of the resolved palette entry, not by reserving palette - index `0` as a special transparent index. -- Alpha MAY be meaningful in palettes, sprites, tiles, primitives, UI/effects, - composed framebuffer pixels, and published front-buffer pixels. -- The first migration wave MUST allow alpha across all renderer operations. -- Optimization work MAY later add faster opaque/masked/alpha paths, but that - optimization MUST NOT reintroduce RGB565 as a supported contract. -- Tests MUST use RGBA8888 expectations as source of truth. -- Render thread, GPU backend, RGB565 backend, SDL/wgpu backend abstraction, and - multi-format `FrameSurface` design are out of scope for this decision's - first execution wave. - -## Impactos - -### Spec - -Canonical specs for GFX, assets, VM/syscalls, and host presentation need to be -updated to describe RGBA8888 as the normal color and framebuffer contract. -Published specs must be in English. - -Spec updates are mandatory propagation for this decision, not follow-up cleanup. - -### Runtime / HAL - -The HAL color type, raw color APIs, framebuffer accessor, clear operation, -blend/fade helpers, renderer target storage, and tests must migrate away from -RGB565. Compatibility API names that encode RGB565, including any `Gfx*565` -surface, must be removed rather than carried forward as deprecated canonical -surface. - -### Host - -The desktop host must consume RGBA8888 frames directly in the normal path. The -existing RGB565-to-RGBA8 conversion path must be removed from normal -presentation. - -### Firmware / VM / PBS - -VM-facing color values and syscall validation must change from the RGB565 -`0xFFFF` range to the RGBA8888 contract. PBS or syscall declarations that expose -`GfxClear565`, any other `Gfx*565` surface, or raw RGB565 color must be replaced -with format-neutral APIs such as `GfxClear`. - -ABI contracts and syscall declarations are part of the required update surface. -They must not be left describing RGB565 values, `Gfx*565` names, or `u16` -framebuffer/color contracts after this migration. - -### Assets / Tooling - -`assets.pa`, glyph-bank palette decode, generators, fixtures, and validators -must use RGBA8888 palette entries. Compatibility with existing RGB565 palette -assets is intentionally not preserved. - -### Tests - -Tests must be rewritten around RGBA8888 values, RGBA channel order, broad alpha -support, meaningful front-buffer alpha, asset palette RGBA8888 encoding, and -host presentation without RGB565 conversion. - -Visual/snapshot tests should assert intended RGBA8888 composition behavior, not -binary equivalence with legacy RGB565 output. - -## Propagacao Necessaria - -- specs: GFX peripheral, asset package/glyph-bank palette format, VM/syscall - ABI, host presentation where documented. -- plans: a dedicated execution plan must be written before spec or code edits. -- code: `prometeu-hal`, `prometeu-drivers`, `prometeu-system`, - `prometeu-host-desktop-winit`, asset tooling, fixtures. -- tests: HAL color tests, renderer tests, asset decode tests, VM/syscall tests, - host conversion/presentation tests, visual or snapshot tests where available. -- docs: discussion lessons only after execution is complete. -- canonical docs: specs, ABI contracts, and public documentation must be updated - in the same execution plan as the code/spec migration, not deferred as - optional cleanup. - -## Referencias - -- Agenda: AGD-0037 -- Prior agenda superseded for this topic: AGD-0010 - -## Revision Log - -- 2026-05-23: Initial decision draft from AGD-0037. diff --git a/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md b/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md deleted file mode 100644 index 910cab10..00000000 --- a/discussion/workflow/plans/PLN-0067-rgba8888-published-contracts-and-specs.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -id: PLN-0067 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: RGBA8888 Published Contracts and Specs -status: done -created: 2026-05-23 -ref_decisions: [DEC-0029] -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Briefing - -Publish the RGBA8888 contract before touching runtime code. This plan updates -the canonical specs, ABI documentation, and public docs so the repository has a -single written source of truth for the migration required by DEC-0029. - -## Source Decisions - -- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. - -## Target - -Document RGBA8888 as the only supported runtime color and framebuffer contract, -remove RGB565 compatibility language from published contracts, and define -format-neutral GFX API naming rules. - -## Scope - -Included: - -- Update `docs/specs/runtime/04-gfx-peripheral.md` to define logical color, - framebuffer output, alpha behavior, and format-neutral GFX command naming. -- Update `docs/specs/runtime/15-asset-management.md` to define RGBA8888 palette - entries in `assets.pa` and remove RGB565 palette compatibility. -- Update `docs/specs/runtime/16-host-abi-and-syscalls.md` to remove `Gfx*565` - as public ABI and define format-neutral syscall names such as `GfxClear`. -- Update `docs/specs/runtime/02a-vm-values-and-calling-convention.md` only if - it describes raw color value width/range. -- Update `docs/specs/runtime/11-portability-and-cross-platform-execution.md` - only if it describes host framebuffer format or RGB565 presentation. -- Update `docs/specs/runtime/README.md` if the index or spec summaries mention - RGB565 as current contract. - -## Out of Scope - -- Code changes under `crates/`. -- Asset fixture regeneration. -- Host presentation implementation. -- Lessons; they are written after execution, not before. -- New backend abstractions, render thread, GPU backend, RGB565 fallback. - -## Execution Plan - -1. Audit published contract text. - - Search `docs/` for `RGB565`, `rgb565`, `565`, `u16`, `GfxClear565`, - `Gfx*565`, `front_buffer`, `palette`, `assets.pa`, and `RGBA`. - - Classify each hit as historical, obsolete contract, or still-valid - implementation detail. - -2. Update the GFX peripheral spec. - - State that runtime color values are RGBA8888 in RGBA channel order. - - State that front-buffer alpha may be meaningful. - - State that GFX APIs must be format-neutral and must not expose `Gfx*565`. - - State that palette indices are ordinary indices and transparency comes - from resolved RGBA alpha. - -3. Update asset-management specs. - - Define palette entries as RGBA8888. - - Keep indexed tile/sprite payloads and palette limits if already specified. - - Remove compatibility promises for RGB565 palette payloads. - - Call out that existing RGB565 assets must be regenerated or converted by - tooling, not accepted as runtime compatibility input. - -4. Update host and ABI specs. - - Replace RGB565 and `u16` color/framebuffer ABI language with RGBA8888. - - Replace `GfxClear565` and any `Gfx*565` surface with format-neutral names. - - Document expected syscall color range/shape for RGBA8888 values. - -5. Add a short migration note to each touched spec. - - Reference DEC-0029. - - Make clear that RGB565 text is superseded for the active runtime contract. - -## Acceptance Criteria - -- [ ] `docs/` no longer describes RGB565 as the current runtime color, - framebuffer, palette, or host presentation contract. -- [ ] `docs/` no longer describes `Gfx*565` as public canonical ABI. -- [ ] Specs state RGBA8888 raw channel order as RGBA. -- [ ] Specs state that front-buffer alpha may be meaningful. -- [ ] Specs state that palette transparency comes from alpha, not reserved index - `0`. -- [ ] Specs state that RGB565 asset palettes are not compatible runtime input. - -## Tests / Validation - -- Run a repository text audit with `rg -n "RGB565|rgb565|Gfx.*565|u16|565" docs` - and verify every remaining hit is explicitly historical or unrelated. -- Run `discussion validate`. -- No Rust build is required for this docs-only plan. - -## Risks - -- Specs may contain old historical sections that should remain for context. If - retained, they must be marked historical and must not read as active contract. -- Some ABI names may be generated from Rust enums; this plan documents the - target but does not update generated code. diff --git a/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md b/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md deleted file mode 100644 index 9df110ab..00000000 --- a/discussion/workflow/plans/PLN-0068-rgba8888-color-type-hal-and-abi-surface.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -id: PLN-0068 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: RGBA8888 Color Type HAL and ABI Surface -status: done -created: 2026-05-23 -ref_decisions: [DEC-0029] -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Briefing - -Introduce the RGBA8888 logical color contract and format-neutral HAL/ABI -surface while keeping renderer internals as stable as possible for the next -plan. This is the boundary-setting code PR after the specs are updated. - -## Source Decisions - -- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. - -## Dependencies - -- PLN-0067 must be accepted or complete enough that the target spec wording is - stable. - -## Target - -The public runtime color type, syscall registry, ABI metadata, and HAL bridge -must stop exposing RGB565 as the canonical contract. Public names must be -format-neutral. - -## Scope - -Included: - -- Replace `prometeu_hal::color::Color(pub u16)` semantics with RGBA8888 in - `crates/console/prometeu-hal/src/color.rs`. -- Define constructors and raw accessors for RGBA channel order. -- Preserve ergonomic named constants as RGBA8888 values. -- Replace `Syscall::GfxClear565` with format-neutral `Syscall::GfxClear`. -- Update syscall registry/domain metadata in - `crates/console/prometeu-hal/src/syscalls.rs`, - `crates/console/prometeu-hal/src/syscalls/registry.rs`, and - `crates/console/prometeu-hal/src/syscalls/domains/gfx.rs`. -- Update VM dispatch color parsing and validation in - `crates/console/prometeu-system/src/services/vm_runtime/dispatch.rs`. -- Update ABI/opcode documentation surfaces in - `crates/console/prometeu-bytecode/src/abi.rs` and - `crates/console/prometeu-bytecode/src/opcode_spec.rs` if they expose the - syscall name or raw color range. -- Change `GfxBridge::front_buffer` only if needed to compile the public API - shape; full renderer buffer migration belongs to PLN-0069. - -## Out of Scope - -- Migrating renderer front/back storage. -- Migrating asset palette serialization. -- Removing host RGB565 conversion. -- Performance optimization for alpha or RGBA operations. -- Adding alpha-only commands. - -## Execution Plan - -1. Rewrite `Color` as RGBA8888. - - Store raw color as `u32` or an equivalent transparent representation. - - `Color::rgb(r, g, b)` must create opaque alpha `255`. - - Add or update `Color::rgba(r, g, b, a)`. - - `raw()` and `from_raw()` must use RGBA channel order. - - Remove or quarantine RGB565 helpers such as 5/6/5 pack/unpack from the - canonical API. - -2. Remove format-suffixed GFX syscall naming. - - Rename `GfxClear565` to `GfxClear`. - - Rename the domain metadata from `clear_565` to `clear`. - - Keep the numeric syscall id stable only if the ABI policy allows preserving - the opcode while changing the name/semantics; otherwise document the new - id in the spec before changing it. - - Search for any other `Gfx*565` public surface and rename it to - format-neutral form. - -3. Update VM color ABI handling. - - Replace `0xFFFF` validation with the RGBA8888 range/shape. - - Ensure the VM passes RGBA8888 raw values into `Color`. - - Remove comments and test expectations that identify the GFX clear syscall - as RGB565. - -4. Update tests at the boundary. - - HAL color tests must assert RGBA raw order. - - Syscall metadata tests must assert `GfxClear`, not `GfxClear565`. - - VM dispatch tests must use RGBA8888 values and meaningful alpha examples. - -5. Run a targeted residue scan. - - `rg -n "Gfx.*565|RGB565|rgb565|0xFFFF|Color\\(.*u16|front_buffer\\(\\).*u16" crates/console`. - - Remaining hits must be either in lower layers scheduled for later plans or - marked as temporary implementation residue. - -## Acceptance Criteria - -- [ ] `Color` represents RGBA8888 and exposes RGBA-order raw values. -- [ ] `GfxClear565` is no longer a canonical syscall/API name; `GfxClear` is. -- [ ] No public `Gfx*565` surface remains in HAL/syscall metadata. -- [ ] VM color validation accepts RGBA8888 and does not enforce RGB565 range. -- [ ] Boundary tests are RGBA8888-first. - -## Tests / Validation - -- Run the HAL/syscall unit tests touched by this plan. -- Run VM dispatch tests that cover GFX clear/color values. -- Run `cargo test` for the affected crates if compile scope remains contained. -- Run `discussion validate`. - -## Risks - -- Renaming syscall variants may have wide compile fallout. Keep the PR focused - on boundary names and color semantics, leaving renderer internals for the next - plan. -- If opcode ids are part of a stable ABI, changing numeric ids requires a - separate explicit spec change before implementation. diff --git a/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md b/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md deleted file mode 100644 index 85176692..00000000 --- a/discussion/workflow/plans/PLN-0069-rgba8888-cpu-renderer-and-composition.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -id: PLN-0069 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: RGBA8888 CPU Renderer and Composition -status: done -created: 2026-05-23 -ref_decisions: [DEC-0029] -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Briefing - -Migrate the existing CPU renderer and frame composition path from RGB565 -storage to RGBA8888 storage. This plan keeps the current destructive renderer -model and does not introduce a render thread or backend abstraction. - -## Source Decisions - -- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. - -## Dependencies - -- PLN-0067 for published contract wording. -- PLN-0068 for `Color`, HAL, and syscall boundary semantics. - -## Target - -The renderer front/back buffers, render target writes, fades, blends, text, -tiles, sprites, and frame composer tests must operate on RGBA8888 pixels. - -## Scope - -Included: - -- `crates/console/prometeu-drivers/src/gfx.rs`. -- `crates/console/prometeu-drivers/src/frame_composer.rs`. -- `crates/console/prometeu-drivers/src/hardware.rs` where framebuffer/color - assumptions are tested or documented. -- HAL bridge implementation in drivers if it still returns `&[u16]`. -- Renderer unit tests and frame-composer tests that assert raw pixel values. - -## Out of Scope - -- Asset package palette serialization changes; covered by PLN-0070. -- Host presentation conversion removal; covered by PLN-0071. -- GPU backend, render thread, dirty-region optimization, span optimization, or - multi-format backend abstraction. -- Alpha-only commands. - -## Execution Plan - -1. Change renderer storage to RGBA8888. - - Replace `front: Vec` and `back: Vec` with RGBA8888 storage. - - Update `RenderTarget` and all buffer accessors to the new pixel type. - - Ensure `present()` keeps its swap semantics. - -2. Update primitive writes. - - `clear`, `draw_pixel`, `fill_rect`, `draw_text`, hardware font drawing, - and overlay primitives must write RGBA8888 values. - - Opaque calls may write direct RGBA8888 pixels. - - Alpha values must be preserved according to the operation semantics. - -3. Replace RGB565 blending/fade. - - Replace `blend_rgb565` with RGBA8888 blend logic. - - Update `apply_fade_to_buffer` to operate on RGBA channels. - - Do not force final alpha to `255`; preserve or compute alpha according to - the operation. - -4. Update tile and sprite composition. - - Resolve palette entries as RGBA8888 colors. - - Do not treat palette index `0` as automatically transparent. - - Skip or blend based on resolved alpha and operation semantics. - - Allow alpha across tile, sprite, primitive, UI/effect, and fade paths. - -5. Update frame composer expectations. - - Tests must assert RGBA8888 raw values. - - Any old RGB565 expected values must be regenerated from RGBA source colors, - not converted as compatibility behavior. - -6. Isolate temporary compile seams. - - If asset decode still supplies RGBA8888 `Color` through old fixture bytes, - keep the fixture problem contained for PLN-0070 and do not add runtime - RGB565 compatibility to the renderer. - -## Acceptance Criteria - -- [ ] Renderer front/back buffers materialize RGBA8888 pixels. -- [ ] `front_buffer()` no longer exposes `&[u16]` in the driver/HAL - implementation path. -- [ ] RGB565 blend/fade helpers are removed from renderer normal paths. -- [ ] Tile/sprite transparency is based on RGBA alpha, not palette index `0`. -- [ ] Renderer and frame-composer tests assert RGBA8888 values. -- [ ] No render thread, GPU backend, RGB565 backend, or multi-format backend is - introduced. - -## Tests / Validation - -- Run renderer unit tests in `prometeu-drivers`. -- Run frame composer tests in `prometeu-drivers`. -- Run targeted scans for `blend_rgb565`, `Vec`, `&[u16]`, and `RGB565` in - renderer files. -- Run `discussion validate`. - -## Risks - -- This plan will likely touch many assertions. Keep each assertion update tied - to a known RGBA value. -- Alpha behavior can expose previously hidden assumptions in tests. Preserve the - decision rule: alpha is allowed broadly and optimization comes later. diff --git a/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md b/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md deleted file mode 100644 index e46b688b..00000000 --- a/discussion/workflow/plans/PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -id: PLN-0070 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: RGBA8888 Asset Palettes Tooling and Fixtures -status: done -created: 2026-05-23 -ref_decisions: [DEC-0029] -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Briefing - -Migrate asset palette serialization, decode, generators, and fixtures to -RGBA8888. This plan intentionally breaks RGB565 palette compatibility rather -than preserving it through runtime fallback. - -## Source Decisions - -- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. - -## Dependencies - -- PLN-0067 for asset spec wording. -- PLN-0068 for RGBA8888 `Color`. -- PLN-0069 may run before or alongside this plan, but renderer normal paths must - not require RGB565 palette compatibility. - -## Target - -`assets.pa` glyph-bank palette payloads, runtime decode, generators, and tests -must use RGBA8888 palette entries with RGBA channel order. - -## Scope - -Included: - -- `crates/console/prometeu-hal/src/glyph_bank.rs`. -- `crates/console/prometeu-hal/src/asset.rs`. -- `crates/console/prometeu-hal/src/cartridge_loader.rs`. -- `crates/console/prometeu-drivers/src/asset.rs`. -- `crates/tools/pbxgen-stress/src/lib.rs` and related generator code. -- Runtime and system tests that compute glyph-bank payload sizes. -- Test fixtures and generated `assets.pa` payload builders in the repository. - -## Out of Scope - -- Supporting legacy RGB565 assets at runtime. -- Adding a general asset package v2 negotiation layer unless the existing format - requires an explicit version bump to avoid ambiguous decode. -- Changing tile/sprite index packing beyond what RGBA8888 palettes require. -- Changing palette count or colors-per-palette limits. - -## Execution Plan - -1. Change palette byte accounting. - - Replace palette entry size from `size_of::()` / `2` bytes to `4` - bytes. - - Update decoded-size calculations in asset decode, cartridge loader tests, - VM runtime tests, and pbxgen-stress. - -2. Decode palettes as RGBA8888. - - Read each palette entry as four bytes in RGBA order. - - Construct `Color` through RGBA8888 APIs, not `Color(raw_u16)`. - - Reject payloads whose palette byte size matches old RGB565 layout when the - format can identify the mismatch. - -3. Update glyph-bank semantics. - - Keep `pixel_indices: Vec` and 4bpp authored payloads where currently - specified. - - Keep palette count and colors-per-palette constants unless the spec says - otherwise. - - Remove comments that say runtime palettes are RGB565. - - Ensure palette index `0` is not treated as transparent by decode or data - model. - -4. Update generators and fixtures. - - Make `pbxgen-stress` emit RGBA8888 palette bytes. - - Regenerate inline fixture builders to append four-byte RGBA palette - entries. - - Do not keep RGB565 fixture decode as runtime compatibility. - -5. Update asset tests. - - Assert RGBA channel order. - - Include at least one non-opaque alpha value in a palette entry. - - Assert payload size failures for old two-byte palette layout where - practical. - -## Acceptance Criteria - -- [ ] Glyph-bank palette payloads are RGBA8888 and use four bytes per entry. -- [ ] Asset decode constructs RGBA8888 `Color` values in RGBA order. -- [ ] Existing RGB565 palette payloads are not accepted as compatible runtime - input. -- [ ] `pbxgen-stress` emits RGBA8888 palettes. -- [ ] Tests include meaningful alpha in palette entries. -- [ ] Palette index `0` has no special transparency semantics in asset decode. - -## Tests / Validation - -- Run asset decode tests in `prometeu-drivers`. -- Run cartridge loader tests in `prometeu-hal`. -- Run VM runtime asset tests in `prometeu-system`. -- Run `cargo test -p pbxgen-stress` if available. -- Run scans for `GLYPH_BANK_PALETTE.*u16`, `* 2`, `size_of::()`, and - `RGB565` in asset/glyph-bank/tooling files. -- Run `discussion validate`. - -## Risks - -- Payload-size constants are duplicated in tests. Update all derived size - helpers in the same PR to avoid misleading failures. -- If the existing asset package has no version marker for palette encoding, the - plan must choose an explicit metadata/version discriminator before accepting - ambiguous payloads. diff --git a/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md b/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md deleted file mode 100644 index 2270112e..00000000 --- a/discussion/workflow/plans/PLN-0071-rgba8888-host-presentation-path.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -id: PLN-0071 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: RGBA8888 Host Presentation Path -status: done -created: 2026-05-23 -ref_decisions: [DEC-0029] -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Briefing - -Move the desktop host presentation path from RGB565 conversion to direct -RGBA8888 presentation. This plan removes the normal `draw_rgb565_to_rgba8` -path after the runtime publishes RGBA8888 frames. - -## Source Decisions - -- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. - -## Dependencies - -- PLN-0067 for host/spec contract wording. -- PLN-0068 for public framebuffer type and ABI naming. -- PLN-0069 for renderer front-buffer RGBA8888 storage. - -## Target - -The host must consume RGBA8888 frames directly in the normal presentation path -and must not convert RGB565 frames on every redraw. - -## Scope - -Included: - -- `crates/host/prometeu-host-desktop-winit/src/runner.rs`. -- `crates/host/prometeu-host-desktop-winit/src/utilities.rs`. -- Host tests or utility tests for frame copy/channel order. -- Host overlay integration where it assumes RGBA8 frame bytes. - -## Out of Scope - -- Changing the windowing library. -- Introducing wgpu/OpenGL/SDL backend abstractions. -- Changing host frame pacing. -- Changing render thread ownership. -- Performance optimization beyond removing RGB565 conversion from the normal - path. - -## Execution Plan - -1. Replace host frame conversion. - - Remove use of `draw_rgb565_to_rgba8` from `runner.rs`. - - Copy or expose RGBA8888 runtime pixels into the `pixels` frame using the - documented RGBA channel order. - - Preserve meaningful alpha unless the presentation library explicitly - requires conversion; if conversion is required, document it as host - presentation behavior, not runtime framebuffer semantics. - -2. Remove RGB565 utilities from the normal path. - - Delete `draw_rgb565_to_rgba8` and `rgb565_to_rgb888` if no tests or - temporary migration tools need them. - - If temporary conversion helpers remain for fixture regeneration, move them - out of host presentation utilities and mark them non-runtime. - -3. Verify overlay compatibility. - - Ensure host overlay writes still target RGBA8 bytes in the `pixels` frame. - - Ensure overlay composition does not assume the emulated framebuffer itself - is opaque. - -4. Update host tests. - - Add or update tests for RGBA channel order. - - Include a source pixel with non-`255` alpha. - - Remove tests that only prove RGB565 expansion. - -5. Run residue scan. - - Search host crate for `rgb565`, `RGB565`, `draw_rgb565`, and `u16` - framebuffer assumptions. - -## Acceptance Criteria - -- [ ] The desktop host normal redraw path consumes RGBA8888 frames. -- [ ] `draw_rgb565_to_rgba8` is not used by host presentation. -- [ ] Host channel order matches canonical RGBA. -- [ ] Host presentation does not force runtime front-buffer alpha to `255` as a - runtime contract. -- [ ] Host tests are RGBA8888-first. - -## Tests / Validation - -- Run `cargo test -p prometeu-host-desktop-winit`. -- Run a targeted host scan for `rgb565`, `RGB565`, and `draw_rgb565`. -- Run an interactive smoke test only if the repo already has a standard host - smoke command; otherwise record that manual visual validation remains for the - final validation plan. -- Run `discussion validate`. - -## Risks - -- The `pixels` frame is byte-oriented; byte order mistakes are easy. Tests must - use non-symmetric color values and non-opaque alpha. -- If runtime publishes `u32`, host code must explicitly define how the `u32` - maps to RGBA bytes instead of relying on native endian layout. diff --git a/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md b/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md deleted file mode 100644 index 541b7ed2..00000000 --- a/discussion/workflow/plans/PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -id: PLN-0072 -ticket: rgba8888-framebuffer-and-pixel-format-direction -title: RGBA8888 Residue Removal and End to End Validation -status: done -created: 2026-05-23 -ref_decisions: [DEC-0029] -tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend] ---- - -## Briefing - -Close the RGBA8888 migration by removing residual RGB565 contract text and code -paths, running end-to-end validation, and preparing the discussion thread for -post-execution lessons. - -## Source Decisions - -- DEC-0029 - RGBA8888 Runtime Pixel Format Contract. - -## Dependencies - -- PLN-0067 through PLN-0071 must be complete or merged into the execution branch. - -## Target - -The repository must no longer expose RGB565, `Gfx*565`, `u16` framebuffer/color -contracts, RGB565 palette payloads, or RGB565 host conversion as active runtime -contract. - -## Scope - -Included: - -- Whole-repository residue audit. -- End-to-end build and test validation. -- Documentation consistency checks. -- Final migration notes needed for housekeeping and lessons. -- Any small missed cleanup in code, docs, tests, or fixtures that directly - violates DEC-0029. - -## Out of Scope - -- New alpha-only commands. -- Performance optimization after broad alpha support. -- GPU backend, render thread, RGB565 backend, multi-format backend abstraction. -- New visual design work for the Hub. - -## Execution Plan - -1. Run repository-wide residue scans. - - Search for `RGB565`, `rgb565`, `Gfx.*565`, `clear_565`, `u16` near color - or framebuffer APIs, `GLYPH_BANK_PALETTE.*u16`, `size_of::()` near - palette code, `draw_rgb565`, and `0xFFFF` near color validation. - - Classify every remaining hit as removed, historical-only, unrelated, or a - bug. - -2. Remove active-contract residues. - - Delete or rename any remaining active `Gfx*565` surface. - - Remove RGB565 helpers from runtime and host normal paths. - - Remove comments that still describe RGB565 as current behavior. - - Remove tests that assert RGB565 output. - -3. Verify docs and ABI consistency. - - Ensure `docs/specs/runtime/04-gfx-peripheral.md`, - `docs/specs/runtime/15-asset-management.md`, and - `docs/specs/runtime/16-host-abi-and-syscalls.md` agree on RGBA8888. - - Ensure public syscall declarations and docs use format-neutral names. - - Ensure any historical RGB565 mention is clearly historical and not - normative. - -4. Run full test/build validation. - - Run the repo's standard build command. - - Run the relevant Rust test suites across HAL, drivers, system, VM, tools, - and host. - - Run any visual/snapshot validation available in the repository. - -5. Record final evidence. - - Capture the exact commands and outcomes in the plan or final PR notes. - - List remaining historical RGB565 mentions and why they are acceptable. - - Identify lesson candidates for `discussion-housekeep` after execution. - -## Acceptance Criteria - -- [ ] Repository scan finds no active RGB565 runtime contract. -- [ ] No public `Gfx*565` API, syscall, metadata, or ABI declaration remains. -- [ ] No normal renderer or host path performs RGB565 conversion. -- [ ] No asset decode path accepts RGB565 palettes as compatible runtime input. -- [ ] Specs, docs, ABI contracts, code, fixtures, and tests agree on RGBA8888. -- [ ] Full validation commands pass or any failure is documented as unrelated. -- [ ] The discussion thread has enough evidence for housekeeping and lessons. - -## Tests / Validation - -- Run the standard repository build command. -- Run affected crate tests: `prometeu-hal`, `prometeu-drivers`, - `prometeu-system`, `prometeu-vm`, `prometeu-bytecode`, - `prometeu-host-desktop-winit`, and `pbxgen-stress` where applicable. -- Run all available visual/snapshot tests. -- Run repository-wide `rg` residue scans described above. -- Run `discussion validate`. - -## Risks - -- Some remaining RGB565 references may be legitimate historical notes. They - must be marked clearly enough that readers cannot mistake them for active - contract. -- End-to-end visual validation may not exist yet. If so, record the gap and add - minimal deterministic checks around RGBA channel order and alpha behavior. - -## Validation Evidence - -- `cargo check --workspace` passed. -- `cargo test --workspace` passed. -- `discussion validate` passed. -- Residue scan command: - `rg -n "RGB565|rgb565|Gfx.*565|clear_565|_565|draw_rgb565|0x1010|front_buffer\\(\\).*u16|Vec|\\[u16\\]|GLYPH_BANK_PALETTE.*u16|size_of::|from_rgb565|to_rgb565" crates docs -S` -- Remaining scan hits are either negative normative documentation or unrelated - `u16` uses such as VM verifier instruction offsets / glyph ids. From a07104aad1678d8f93e2e607dc71e0cd25c81dd6 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sat, 23 May 2026 22:18:18 +0100 Subject: [PATCH 10/10] refresh rgba8888 stress cartridge artifacts --- crates/console/prometeu-hal/src/color.rs | 1 - test-cartridges/stress-console/assets.pa | Bin 100989 -> 103037 bytes test-cartridges/stress-console/program.pbx | Bin 1205 -> 1201 bytes 3 files changed, 1 deletion(-) diff --git a/crates/console/prometeu-hal/src/color.rs b/crates/console/prometeu-hal/src/color.rs index a4374859..0066e2e0 100644 --- a/crates/console/prometeu-hal/src/color.rs +++ b/crates/console/prometeu-hal/src/color.rs @@ -64,5 +64,4 @@ impl Color { pub const fn alpha(self) -> u8 { (self.0 & 0xFF) as u8 } - } diff --git a/test-cartridges/stress-console/assets.pa b/test-cartridges/stress-console/assets.pa index aad01aef04d41d430cdb613f37a26d8d556fe01e..2d3c6eb9b90882b9582ea4c749f2963005a2c758 100644 GIT binary patch delta 4181 zcmbW4TS${(7=Zs-STiD8P@!Ql+Kr^8sfl1p5DFEn3!#KC+6J0M(So9kPZ{pQL<^+@ zl4V9EM6fQ56bflKf(4PCz=9z3qCf?uglv7UoBpTof4{@U`2X#FpXWVYZJ{fD;X(Sf z$mYWQf|4EHU?^}V7z);g>o0}8rG@#$yRLV~Rzj@P@9HC3LaS&>Xc~Pgeu{eUD6<-& zMNg&;stYK8H}FZBr}eeOSbSDl0KD6`UX>?{;NEDSs$h`|PaaU@;r?`j$5nNTf+YX7 zzeSBFv^X^2$+)j3Nb!{ouatONKiNRz=(v(#iI3&ZtMJMDgJhz8ql#de$(q`|{Jzu_ z|Czc!B>Me+1wnFqz_-Ls%kw0)eh>_LTIB@>ek%M(ny2;k3AT^Lr3FU*Xwi3BUcWzx z+Hd@m6`1m0|IRXfH#Wz9H{2f*{v0Wh6zJOnKKDhn98V1E2f>NVb8-R;fAeyO6i@4$ zCm0=nA|<1QhUKO|Mv ztris6w+H-{5uX@O80!bYvz&cm0tbHbYON4Y>$4}=@~cru;KUz3bX$aH-yfvWrvoAa z$DE;c?;T@$(+>BCgz2->0s{8-fcL#y%jb#1`aw`rki!=sd`D*`m#6ieCy37mxdM!z zuWsh?&i4m#-arpefW`xxhS0c1|9_zgw=RB0jjh?*hva1A(?@39&u84Owx<69hJM@t delta 2117 zcmeyngzfJXwh7G=Mg|rJI!Y<2$@wX%De=XbRjEo=Muvt)6K8K^0m)4cU|d`;z{G$T z2%F-SW)RQ7FE2G4uY5g&-8H-l7?e2i%d6Vpm)9)ECtuIN;JXT+0tSYFyZGfp1n|p; zJL8cD+Rsp3herWWs(vGW`J^ZK<4*c>{UgMMp+t08= z4W|OI#GXj}^80)6%P&5TOCDlB!|`9Z6hOpJ>Ef3^mw;dX;$$51Q2QCap2ML4D*TfX zzx*E){PGX-vCG5kXJA>3T>(s#oj^9_CXh|}uxC@a{R~EU^C<&^8G&qSNg$irV$G%q z`xzX)VSdFBHPa}?=#FQ>~tf6 zY}!g7n|5GkQxy9d*5J&i5C?4_kWDue$fny9&^?A~Kf`VOwH3oX0@?HsfoysdJ)5H0 q&+rmQK83ma?IIWpJN@A*c5#^K7Y-N;Li3?=n?DL}|0u}V(*OY430hGA diff --git a/test-cartridges/stress-console/program.pbx b/test-cartridges/stress-console/program.pbx index 62767f5952599019e8dcd3101a23bd61de8076e9..aedc5922d613c461d17cbf34fb775a0dcc015793 100644 GIT binary patch delta 24 gcmdnWxsh{13ghIBsfU=^Ss9XZQWJ|N8?iJ40Bk1+I{*Lx delta 28 kcmdnUxs`K53gh&RsfU=kIT@03QWJ~fP0dUv>#;Ng0FPG*LI3~&