163 lines
5.4 KiB
Rust
163 lines
5.4 KiB
Rust
use crate::asset::GlyphAssetSlotIndex;
|
|
use crate::frame_composer::FrameComposer;
|
|
use crate::gfx::Gfx;
|
|
use crate::memory_banks::{GlyphBankPoolAccess, MemoryBanks, SceneBankPoolAccess};
|
|
use prometeu_hal::app_mode::AppMode;
|
|
use prometeu_hal::{
|
|
OwnedRgba8888Frame, RenderSubmission, RenderSubmissionPacket, RenderWorkerBackend,
|
|
RenderWorkerError,
|
|
};
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
pub struct LocalFramebufferRenderBackend {
|
|
gfx: Mutex<Gfx>,
|
|
frame_composer: Mutex<FrameComposer>,
|
|
}
|
|
|
|
impl LocalFramebufferRenderBackend {
|
|
pub fn new(width: usize, height: usize, glyph_banks: Arc<dyn GlyphBankPoolAccess>) -> Self {
|
|
Self::new_with_parts(
|
|
width,
|
|
height,
|
|
glyph_banks,
|
|
Arc::new(MemoryBanks::new()),
|
|
GlyphAssetSlotIndex::new(),
|
|
)
|
|
}
|
|
|
|
pub fn new_with_memory_banks(
|
|
width: usize,
|
|
height: usize,
|
|
memory_banks: Arc<MemoryBanks>,
|
|
glyph_slot_index: GlyphAssetSlotIndex,
|
|
) -> Self {
|
|
Self::new_with_parts(
|
|
width,
|
|
height,
|
|
Arc::clone(&memory_banks) as Arc<dyn GlyphBankPoolAccess>,
|
|
memory_banks,
|
|
glyph_slot_index,
|
|
)
|
|
}
|
|
|
|
fn new_with_parts(
|
|
width: usize,
|
|
height: usize,
|
|
glyph_banks: Arc<dyn GlyphBankPoolAccess>,
|
|
scene_banks: Arc<dyn SceneBankPoolAccess>,
|
|
glyph_slot_index: GlyphAssetSlotIndex,
|
|
) -> Self {
|
|
Self {
|
|
gfx: Mutex::new(Gfx::new(width, height, glyph_banks)),
|
|
frame_composer: Mutex::new(FrameComposer::new(
|
|
width,
|
|
height,
|
|
scene_banks,
|
|
glyph_slot_index,
|
|
)),
|
|
}
|
|
}
|
|
|
|
pub fn render_submission(
|
|
&self,
|
|
submission: &RenderSubmission,
|
|
) -> Result<OwnedRgba8888Frame, RenderWorkerError> {
|
|
let mut gfx = self.gfx.lock().map_err(|_| RenderWorkerError::InternalFailure)?;
|
|
match &submission.packet {
|
|
RenderSubmissionPacket::Game2D(packet) if submission.app_mode == AppMode::Game => {
|
|
if packet.composer.bound_scene.is_none() {
|
|
gfx.render_game2d_frame_packet(packet);
|
|
} else {
|
|
let mut frame_composer = self
|
|
.frame_composer
|
|
.lock()
|
|
.map_err(|_| RenderWorkerError::InternalFailure)?;
|
|
frame_composer.render_game2d_frame_packet(packet, &mut *gfx);
|
|
gfx.apply_gfx2d_commands(&packet.gfx2d);
|
|
}
|
|
}
|
|
RenderSubmissionPacket::ShellUi(packet) if submission.app_mode == AppMode::Shell => {
|
|
gfx.render_shell_ui_frame_packet(packet);
|
|
}
|
|
_ => return Err(RenderWorkerError::RenderFailed),
|
|
}
|
|
|
|
gfx.present();
|
|
let (width, height) = gfx.size();
|
|
OwnedRgba8888Frame::packed(
|
|
submission.frame_id,
|
|
submission.ownership,
|
|
width,
|
|
height,
|
|
gfx.front_buffer().to_vec(),
|
|
)
|
|
.map_err(|_| RenderWorkerError::InternalFailure)
|
|
}
|
|
}
|
|
|
|
impl RenderWorkerBackend for LocalFramebufferRenderBackend {
|
|
fn render(
|
|
&self,
|
|
submission: &RenderSubmission,
|
|
) -> Result<OwnedRgba8888Frame, RenderWorkerError> {
|
|
self.render_submission(submission)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::memory_banks::MemoryBanks;
|
|
use prometeu_hal::app_mode::AppMode;
|
|
use prometeu_hal::color::Color;
|
|
use prometeu_hal::primitives::Rect;
|
|
use prometeu_hal::{
|
|
FrameId, Game2DFramePacket, Gfx2dCommand, GfxUiCommand, RenderOwnership, ShellUiFramePacket,
|
|
};
|
|
|
|
fn backend() -> LocalFramebufferRenderBackend {
|
|
let banks = Arc::new(MemoryBanks::new());
|
|
LocalFramebufferRenderBackend::new(4, 4, banks)
|
|
}
|
|
|
|
#[test]
|
|
fn local_backend_renders_game2d_submission_to_owned_frame() {
|
|
let backend = backend();
|
|
let mut packet = Game2DFramePacket::default();
|
|
packet.gfx2d = vec![Gfx2dCommand::FillRect {
|
|
rect: Rect { x: 1, y: 1, w: 2, h: 2 },
|
|
color: Color::RED,
|
|
}];
|
|
let ownership = RenderOwnership::new(3, AppMode::Game, 9);
|
|
let submission =
|
|
RenderSubmission::game2d(FrameId::new(5), packet).with_ownership(ownership);
|
|
|
|
let frame = backend.render(&submission).expect("game frame should render");
|
|
|
|
assert_eq!(frame.frame_id, FrameId::new(5));
|
|
assert_eq!(frame.ownership, ownership);
|
|
assert_eq!(frame.width, 4);
|
|
assert_eq!(frame.height, 4);
|
|
assert_eq!(frame.pixels[1 + 4], Color::RED.raw());
|
|
assert_eq!(frame.pixels[2 + 2 * 4], Color::RED.raw());
|
|
}
|
|
|
|
#[test]
|
|
fn local_backend_renders_shell_ui_submission_to_owned_frame() {
|
|
let backend = backend();
|
|
let packet = ShellUiFramePacket::new(vec![GfxUiCommand::FillRect {
|
|
rect: Rect { x: 0, y: 0, w: 1, h: 1 },
|
|
color: Color::GREEN,
|
|
}]);
|
|
let ownership = RenderOwnership::new(4, AppMode::Shell, 10);
|
|
let submission =
|
|
RenderSubmission::shell_ui(FrameId::new(6), packet).with_ownership(ownership);
|
|
|
|
let frame = backend.render(&submission).expect("shell frame should render");
|
|
|
|
assert_eq!(frame.frame_id, FrameId::new(6));
|
|
assert_eq!(frame.ownership, ownership);
|
|
assert_eq!(frame.pixels[0], Color::GREEN.raw());
|
|
}
|
|
}
|