-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
323 additions
and
6 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "vita-example-vitasdk" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
license = "MIT OR Apache-2.0" | ||
repository = "https://github.com/vita-rust/examples" | ||
homepage = "https://github.com/vita-rust/examples/crates/4-vitasdk" | ||
|
||
description = "VITASDK example" | ||
|
||
[dependencies] | ||
vitasdk-sys = { version = "0.3.3", features = ["SceDisplay_stub", "SceSysmem_stub"] } | ||
rand = "0.8.5" | ||
|
||
[package.metadata.vita] | ||
title_id = "RUSTTEST4" | ||
title_name = "VITASDK test" | ||
assets = "./static" |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
pub struct DebugFont { | ||
pub glyphs: &'static [u8], | ||
pub width: usize, | ||
pub height: usize, | ||
pub first: u8, | ||
pub last: u8, | ||
pub size_w: usize, | ||
pub size_h: usize, | ||
} | ||
|
||
pub const DEBUG_FONT: DebugFont = DebugFont { | ||
glyphs: include_bytes!("font.bin"), | ||
width: 8, | ||
height: 8, | ||
first: 0, | ||
last: 255, | ||
size_w: 8, | ||
size_h: 8, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod font; | ||
pub mod screen; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
use core::ffi::c_void; | ||
use core::fmt::{Result, Write}; | ||
use core::mem::size_of; | ||
use core::ptr; | ||
|
||
use vitasdk_sys::{ | ||
sceDisplaySetFrameBuf, sceKernelAllocMemBlock, sceKernelFreeMemBlock, sceKernelGetMemBlockBase, | ||
SceDisplayFrameBuf, SceUID, SCE_DISPLAY_SETBUF_NEXTFRAME, | ||
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, | ||
}; | ||
|
||
use super::font::DEBUG_FONT; | ||
|
||
const SCREEN_WIDTH: usize = 960; | ||
const SCREEN_HEIGHT: usize = 544; | ||
const SCREEN_PIXEL_COUNT: usize = SCREEN_WIDTH * SCREEN_HEIGHT; | ||
const SCREEN_FB_WIDTH: usize = 960; | ||
const SCREEN_FB_SIZE: usize = 2 * 1024 * 1024; | ||
const SCREEN_TAB_SIZE: usize = 4; // Tab size in number of characters | ||
const SCREEN_TAB_W: usize = DEBUG_FONT.size_w * SCREEN_TAB_SIZE; | ||
|
||
const DEFAULT_FG: u32 = 0xFFFFFFFF; | ||
const DEFAULT_BG: u32 = 0xFF000000; | ||
|
||
pub struct DebugScreen { | ||
// TODO: rename to pixel array or something like that | ||
framebuffer: Framebuffer, | ||
coord_x: usize, | ||
coord_y: usize, | ||
color_fg: u32, | ||
color_bg: u32, | ||
} | ||
|
||
pub struct Framebuffer { | ||
buf: *mut u32, | ||
block_uid: SceUID, | ||
} | ||
|
||
impl Framebuffer { | ||
pub fn new() -> Framebuffer { | ||
// Allocate memory to use as display buffer | ||
let mut base: *mut c_void = ::core::ptr::null_mut(); | ||
let block_uid = unsafe { | ||
let block_uid: SceUID = sceKernelAllocMemBlock( | ||
b"display\0".as_ptr() as *const i8, | ||
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, | ||
SCREEN_FB_SIZE as u32, | ||
::core::ptr::null_mut(), | ||
); | ||
sceKernelGetMemBlockBase(block_uid, &mut base); | ||
block_uid | ||
}; | ||
Framebuffer { | ||
buf: base as *mut u32, | ||
block_uid, | ||
} | ||
} | ||
|
||
pub fn set_display(&mut self) { | ||
// Sets buffer as current display frame | ||
let frame = SceDisplayFrameBuf { | ||
size: size_of::<SceDisplayFrameBuf>() as u32, | ||
base: self.buf as *mut c_void, | ||
pitch: SCREEN_FB_WIDTH as u32, | ||
pixelformat: 0, | ||
width: SCREEN_WIDTH as u32, | ||
height: SCREEN_HEIGHT as u32, | ||
}; | ||
unsafe { | ||
sceDisplaySetFrameBuf(&frame, SCE_DISPLAY_SETBUF_NEXTFRAME); | ||
} | ||
} | ||
|
||
#[allow(unused)] | ||
pub fn get(&self, index: usize) -> u32 { | ||
if index > SCREEN_PIXEL_COUNT { | ||
panic!("Invalid framebuffer index"); | ||
} | ||
unsafe { ptr::read_volatile(self.buf.offset(index.try_into().unwrap())) } | ||
} | ||
|
||
pub fn set(&mut self, index: usize, value: u32) { | ||
if index > SCREEN_PIXEL_COUNT { | ||
panic!("Invalid framebuffer index"); | ||
} | ||
unsafe { ptr::write_volatile(self.buf.offset(index.try_into().unwrap()), value) } | ||
} | ||
} | ||
|
||
impl Drop for Framebuffer { | ||
fn drop(&mut self) { | ||
let _error_code = unsafe { sceKernelFreeMemBlock(self.block_uid) }; | ||
} | ||
} | ||
|
||
impl Write for DebugScreen { | ||
fn write_str(&mut self, s: &str) -> Result { | ||
self.puts(s.as_bytes()); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl DebugScreen { | ||
pub fn new() -> Self { | ||
let mut framebuffer = Framebuffer::new(); | ||
framebuffer.set_display(); | ||
Self { | ||
framebuffer, | ||
coord_x: 0, | ||
coord_y: 0, | ||
color_fg: DEFAULT_FG, | ||
color_bg: DEFAULT_BG, | ||
} | ||
} | ||
|
||
#[allow(unused)] | ||
fn clear(&mut self, from_h: usize, to_h: usize, from_w: usize, to_w: usize) { | ||
for h in from_h..to_h { | ||
for w in from_w..to_w { | ||
self.framebuffer.set(h * SCREEN_FB_WIDTH + w, self.color_bg); | ||
} | ||
} | ||
} | ||
|
||
fn puts(&mut self, text: &[u8]) { | ||
let bytes_per_glyph = DEBUG_FONT.width * DEBUG_FONT.height / 8; | ||
|
||
for &chr in text.iter() { | ||
if chr == b'\t' { | ||
self.coord_x += SCREEN_TAB_W - (self.coord_x % SCREEN_TAB_W); | ||
continue; | ||
} | ||
|
||
// Go to next line at the end of the current line | ||
if self.coord_x + DEBUG_FONT.width > SCREEN_WIDTH { | ||
self.coord_y += DEBUG_FONT.size_h; | ||
self.coord_x = 0; | ||
} | ||
|
||
// Go to screen top when at the bottom of the screen | ||
if self.coord_y + DEBUG_FONT.height > SCREEN_HEIGHT { | ||
self.coord_x = 0; | ||
self.coord_y = 0; | ||
} | ||
|
||
if chr == b'\n' { | ||
self.coord_x = 0; | ||
self.coord_y += DEBUG_FONT.size_h; | ||
continue; | ||
} else if chr == b'\r' { | ||
self.coord_x = 0; | ||
continue; | ||
} | ||
|
||
let current_offset = self.coord_x + self.coord_y * SCREEN_FB_WIDTH; | ||
let mut font = | ||
&DEBUG_FONT.glyphs[(chr - DEBUG_FONT.first) as usize * bytes_per_glyph..]; | ||
let mut mask = 1 << 7; | ||
|
||
for row in 0..DEBUG_FONT.height { | ||
for col in 0..DEBUG_FONT.width { | ||
if mask == 0 { | ||
font = &font[1..]; | ||
mask = 1 << 7; | ||
} | ||
|
||
self.framebuffer.set( | ||
current_offset + row * SCREEN_FB_WIDTH + col, | ||
if font[0] & mask == 0 { | ||
self.color_bg | ||
} else { | ||
self.color_fg | ||
}, | ||
); | ||
|
||
mask >>= 1; | ||
} | ||
|
||
#[allow(clippy::reversed_empty_ranges)] | ||
for col in DEBUG_FONT.width..DEBUG_FONT.size_w { | ||
self.framebuffer | ||
.set(current_offset + row * SCREEN_FB_WIDTH + col, self.color_bg) | ||
} | ||
} | ||
|
||
#[allow(clippy::reversed_empty_ranges)] | ||
for row in DEBUG_FONT.height..DEBUG_FONT.size_h { | ||
for col in 0..DEBUG_FONT.size_w { | ||
self.framebuffer | ||
.set(current_offset + row * SCREEN_FB_WIDTH + col, self.color_bg) | ||
} | ||
} | ||
|
||
self.coord_x += DEBUG_FONT.size_w; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
use std::backtrace::Backtrace; | ||
use std::fmt::Write; | ||
use std::panic::PanicInfo; | ||
use std::thread; | ||
use std::time::Duration; | ||
|
||
mod debug; | ||
|
||
pub fn main() { | ||
std::panic::set_hook(Box::new(custom_panic_hook)); | ||
|
||
let mut screen = debug::screen::DebugScreen::new(); | ||
writeln!(screen, "This not-so-bare-metal is starting to rust!").ok(); | ||
thread::sleep(Duration::from_secs(2)); | ||
writeln!(screen, "See? Told ya!").ok(); | ||
thread::sleep(Duration::from_secs(2)); | ||
|
||
let random_numbers: Vec<u8> = (0..8).map(|_i| rand::random::<u8>()).collect(); | ||
writeln!(screen, "Some random numbers: {:?}", random_numbers).ok(); | ||
|
||
thread::sleep(Duration::from_secs(5)); | ||
} | ||
|
||
fn custom_panic_hook(info: &PanicInfo<'_>) { | ||
// The current implementation always returns `Some`. | ||
let location = info.location().unwrap(); | ||
|
||
let msg = match info.payload().downcast_ref::<&'static str>() { | ||
Some(s) => *s, | ||
None => match info.payload().downcast_ref::<String>() { | ||
Some(s) => &s[..], | ||
None => "Box<Any>", | ||
}, | ||
}; | ||
let name = "unknown"; | ||
|
||
let mut screen = debug::screen::DebugScreen::new(); | ||
|
||
writeln!( | ||
screen, | ||
"thread '{}' panicked at '{}', {}", | ||
name, msg, location | ||
) | ||
.ok(); | ||
|
||
// Give 2 seconds to see the error in case capturing the stack trace fails | ||
// (capturing the stack trace allocates memory) | ||
thread::sleep(Duration::from_secs(2)); | ||
|
||
// The backtrace is full of "unknown" for some reason | ||
let backtrace = Backtrace::force_capture(); | ||
writeln!(screen, "{}", backtrace).ok(); | ||
|
||
thread::sleep(Duration::from_secs(10)); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions
11
crates/4-vitasdk/static/sce_sys/livearea/contents/template.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
|
||
<livearea style="a1" format-ver="01.00" content-rev="1"> | ||
<livearea-background> | ||
<image>bg.png</image> | ||
</livearea-background> | ||
|
||
<gate> | ||
<startup-image>startup.png</startup-image> | ||
</gate> | ||
</livearea> |