implements PLN-0110
This commit is contained in:
parent
3916a652b2
commit
12d314a62d
@ -17,6 +17,7 @@ pub mod input_signals;
|
||||
pub mod log;
|
||||
pub mod native_helpers;
|
||||
pub mod native_interface;
|
||||
pub mod owned_frame;
|
||||
pub mod pad_bridge;
|
||||
pub mod platform;
|
||||
pub mod primitives;
|
||||
@ -44,6 +45,7 @@ pub use host_return::HostReturn;
|
||||
pub use input_signals::InputSignals;
|
||||
pub use native_helpers::{expect_bool, expect_int};
|
||||
pub use native_interface::{NativeInterface, SyscallId};
|
||||
pub use owned_frame::{OwnedRgba8888Frame, OwnedRgba8888FrameError};
|
||||
pub use pad_bridge::PadBridge;
|
||||
pub use platform::{
|
||||
AssetStoragePlatform, AudioPlatform, ClockPacingPlatform, Game2DFrameComposer, InputPlatform,
|
||||
|
||||
127
crates/console/prometeu-hal/src/owned_frame.rs
Normal file
127
crates/console/prometeu-hal/src/owned_frame.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use crate::render_submission::{FrameId, RenderOwnership};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct OwnedRgba8888Frame {
|
||||
pub frame_id: FrameId,
|
||||
pub ownership: RenderOwnership,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub stride_pixels: usize,
|
||||
pub pixels: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum OwnedRgba8888FrameError {
|
||||
EmptyDimensions,
|
||||
StrideTooSmall,
|
||||
PixelBufferTooSmall,
|
||||
}
|
||||
|
||||
impl OwnedRgba8888Frame {
|
||||
pub fn new(
|
||||
frame_id: FrameId,
|
||||
ownership: RenderOwnership,
|
||||
width: usize,
|
||||
height: usize,
|
||||
stride_pixels: usize,
|
||||
pixels: Vec<u32>,
|
||||
) -> Result<Self, OwnedRgba8888FrameError> {
|
||||
if width == 0 || height == 0 {
|
||||
return Err(OwnedRgba8888FrameError::EmptyDimensions);
|
||||
}
|
||||
if stride_pixels < width {
|
||||
return Err(OwnedRgba8888FrameError::StrideTooSmall);
|
||||
}
|
||||
let required_len = stride_pixels
|
||||
.checked_mul(height)
|
||||
.ok_or(OwnedRgba8888FrameError::PixelBufferTooSmall)?;
|
||||
if pixels.len() < required_len {
|
||||
return Err(OwnedRgba8888FrameError::PixelBufferTooSmall);
|
||||
}
|
||||
|
||||
Ok(Self { frame_id, ownership, width, height, stride_pixels, pixels })
|
||||
}
|
||||
|
||||
pub fn packed(
|
||||
frame_id: FrameId,
|
||||
ownership: RenderOwnership,
|
||||
width: usize,
|
||||
height: usize,
|
||||
pixels: Vec<u32>,
|
||||
) -> Result<Self, OwnedRgba8888FrameError> {
|
||||
Self::new(frame_id, ownership, width, height, width, pixels)
|
||||
}
|
||||
|
||||
pub fn required_pixel_len(&self) -> usize {
|
||||
self.stride_pixels * self.height
|
||||
}
|
||||
|
||||
pub fn row(&self, y: usize) -> Option<&[u32]> {
|
||||
if y >= self.height {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = y * self.stride_pixels;
|
||||
Some(&self.pixels[start..start + self.width])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::app_mode::AppMode;
|
||||
|
||||
fn ownership() -> RenderOwnership {
|
||||
RenderOwnership::new(11, AppMode::Game, 42)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn owned_rgba8888_frame_preserves_metadata_and_pixels() {
|
||||
let pixels = vec![0x11223344, 0x55667788, 0x99AABBCC, 0xDDEEFF00];
|
||||
let frame = OwnedRgba8888Frame::packed(FrameId::new(7), ownership(), 2, 2, pixels.clone())
|
||||
.expect("valid packed RGBA8888 frame");
|
||||
|
||||
assert_eq!(frame.frame_id, FrameId::new(7));
|
||||
assert_eq!(frame.ownership, ownership());
|
||||
assert_eq!(frame.width, 2);
|
||||
assert_eq!(frame.height, 2);
|
||||
assert_eq!(frame.stride_pixels, 2);
|
||||
assert_eq!(frame.pixels, pixels);
|
||||
assert_eq!(frame.required_pixel_len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_constructor_rejects_empty_dimensions() {
|
||||
let err = OwnedRgba8888Frame::new(FrameId::ZERO, ownership(), 0, 1, 1, vec![0])
|
||||
.expect_err("zero width should be rejected");
|
||||
|
||||
assert_eq!(err, OwnedRgba8888FrameError::EmptyDimensions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_constructor_rejects_stride_smaller_than_width() {
|
||||
let err = OwnedRgba8888Frame::new(FrameId::ZERO, ownership(), 3, 1, 2, vec![0, 0, 0])
|
||||
.expect_err("stride smaller than width should be rejected");
|
||||
|
||||
assert_eq!(err, OwnedRgba8888FrameError::StrideTooSmall);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_constructor_rejects_short_pixel_buffer() {
|
||||
let err = OwnedRgba8888Frame::new(FrameId::ZERO, ownership(), 2, 2, 3, vec![0; 5])
|
||||
.expect_err("buffer shorter than stride * height should be rejected");
|
||||
|
||||
assert_eq!(err, OwnedRgba8888FrameError::PixelBufferTooSmall);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn row_returns_visible_width_without_stride_padding() {
|
||||
let frame =
|
||||
OwnedRgba8888Frame::new(FrameId::ZERO, ownership(), 2, 2, 3, vec![1, 2, 99, 3, 4, 88])
|
||||
.expect("valid padded frame");
|
||||
|
||||
assert_eq!(frame.row(0), Some(&[1, 2][..]));
|
||||
assert_eq!(frame.row(1), Some(&[3, 4][..]));
|
||||
assert_eq!(frame.row(2), None);
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
||||
id: PLN-0110
|
||||
ticket: real-render-worker-establishment
|
||||
title: Define Owned RGBA8888 Frame Contract
|
||||
status: open
|
||||
status: done
|
||||
created: 2026-06-15
|
||||
completed:
|
||||
ref_decisions: [DEC-0033]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user