Skip to content

Commit 7341fbe

Browse files
nikarhpheki
andauthored
Added vitasdk example (#4)
Closes #3 --------- Co-authored-by: Aphek <[email protected]>
1 parent 39674ca commit 7341fbe

File tree

12 files changed

+326
-6
lines changed

12 files changed

+326
-6
lines changed

Cargo.lock

Lines changed: 20 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,5 @@ lto = true
88
opt-level = 2
99

1010
[patch.crates-io]
11-
tokio = { git = "https://github.com/vita-rust/tokio", branch = "vita" }
12-
1311
# Required for rustls
1412
ring = { git = "https://github.com/vita-rust/ring", branch = "v0.16.20-vita" }

crates/4-vitasdk/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "vita-example-vitasdk"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
license = "MIT OR Apache-2.0"
7+
repository = "https://github.com/vita-rust/examples"
8+
homepage = "https://github.com/vita-rust/examples/crates/4-vitasdk"
9+
10+
description = "VITASDK example"
11+
12+
[dependencies]
13+
vitasdk-sys = { version = "0.3.3", features = ["SceDisplay_stub", "SceSysmem_stub"] }
14+
rand = "0.8.5"
15+
16+
[package.metadata.vita]
17+
title_id = "RUSTTEST4"
18+
title_name = "VITASDK test"
19+
assets = "./static"

crates/4-vitasdk/src/debug/font.bin

2 KB
Binary file not shown.

crates/4-vitasdk/src/debug/font.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
pub struct DebugFont {
2+
pub glyphs: &'static [u8],
3+
pub width: usize,
4+
pub height: usize,
5+
pub first: u8,
6+
pub last: u8,
7+
pub size_w: usize,
8+
pub size_h: usize,
9+
}
10+
11+
pub const DEBUG_FONT: DebugFont = DebugFont {
12+
glyphs: include_bytes!("font.bin"),
13+
width: 8,
14+
height: 8,
15+
first: 0,
16+
last: 255,
17+
size_w: 8,
18+
size_h: 8,
19+
};

crates/4-vitasdk/src/debug/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod font;
2+
pub mod screen;

crates/4-vitasdk/src/debug/screen.rs

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
use core::ffi::c_void;
2+
use core::fmt::{Result, Write};
3+
use core::mem::size_of;
4+
use core::ptr;
5+
6+
use vitasdk_sys::{
7+
sceDisplaySetFrameBuf, sceKernelAllocMemBlock, sceKernelFreeMemBlock, sceKernelGetMemBlockBase,
8+
SceDisplayFrameBuf, SceUID, SCE_DISPLAY_SETBUF_NEXTFRAME,
9+
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
10+
};
11+
12+
use super::font::DEBUG_FONT;
13+
14+
const SCREEN_WIDTH: usize = 960;
15+
const SCREEN_HEIGHT: usize = 544;
16+
const SCREEN_PIXEL_COUNT: usize = SCREEN_WIDTH * SCREEN_HEIGHT;
17+
const SCREEN_FB_WIDTH: usize = 960;
18+
const SCREEN_FB_SIZE: usize = 2 * 1024 * 1024;
19+
const SCREEN_TAB_SIZE: usize = 4; // Tab size in number of characters
20+
const SCREEN_TAB_W: usize = DEBUG_FONT.size_w * SCREEN_TAB_SIZE;
21+
22+
const DEFAULT_FG: u32 = 0xFFFFFFFF;
23+
const DEFAULT_BG: u32 = 0xFF000000;
24+
25+
pub struct DebugScreen {
26+
framebuffer: Framebuffer,
27+
coord_x: usize,
28+
coord_y: usize,
29+
color_fg: u32,
30+
color_bg: u32,
31+
}
32+
33+
pub struct Framebuffer {
34+
buf: *mut u32,
35+
block_uid: SceUID,
36+
}
37+
38+
impl Framebuffer {
39+
pub fn new() -> Framebuffer {
40+
// Allocate memory to use as display buffer
41+
let mut base: *mut c_void = ::core::ptr::null_mut();
42+
let block_uid = unsafe {
43+
let block_uid: SceUID = sceKernelAllocMemBlock(
44+
b"display\0".as_ptr() as *const i8,
45+
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
46+
SCREEN_FB_SIZE as u32,
47+
::core::ptr::null_mut(),
48+
);
49+
sceKernelGetMemBlockBase(block_uid, &mut base);
50+
block_uid
51+
};
52+
Framebuffer {
53+
buf: base as *mut u32,
54+
block_uid,
55+
}
56+
}
57+
58+
pub fn set_display(&mut self) {
59+
// Sets buffer as current display frame
60+
let frame = SceDisplayFrameBuf {
61+
size: size_of::<SceDisplayFrameBuf>() as u32,
62+
base: self.buf as *mut c_void,
63+
pitch: SCREEN_FB_WIDTH as u32,
64+
pixelformat: 0,
65+
width: SCREEN_WIDTH as u32,
66+
height: SCREEN_HEIGHT as u32,
67+
};
68+
unsafe {
69+
sceDisplaySetFrameBuf(&frame, SCE_DISPLAY_SETBUF_NEXTFRAME);
70+
}
71+
}
72+
73+
#[allow(unused)]
74+
pub fn get(&self, index: usize) -> u32 {
75+
if index > SCREEN_PIXEL_COUNT {
76+
panic!("Invalid framebuffer index");
77+
}
78+
unsafe { ptr::read_volatile(self.buf.offset(index.try_into().unwrap())) }
79+
}
80+
81+
pub fn set(&mut self, index: usize, value: u32) {
82+
if index > SCREEN_PIXEL_COUNT {
83+
panic!("Invalid framebuffer index");
84+
}
85+
unsafe { ptr::write_volatile(self.buf.offset(index.try_into().unwrap()), value) }
86+
}
87+
}
88+
89+
impl Drop for Framebuffer {
90+
fn drop(&mut self) {
91+
let _error_code = unsafe { sceKernelFreeMemBlock(self.block_uid) };
92+
}
93+
}
94+
95+
impl Write for DebugScreen {
96+
fn write_str(&mut self, s: &str) -> Result {
97+
self.puts(s.as_bytes());
98+
Ok(())
99+
}
100+
}
101+
102+
impl DebugScreen {
103+
pub fn new() -> Self {
104+
let mut framebuffer = Framebuffer::new();
105+
framebuffer.set_display();
106+
Self {
107+
framebuffer,
108+
coord_x: 0,
109+
coord_y: 0,
110+
color_fg: DEFAULT_FG,
111+
color_bg: DEFAULT_BG,
112+
}
113+
}
114+
115+
#[allow(unused)]
116+
fn clear(&mut self, from_h: usize, to_h: usize, from_w: usize, to_w: usize) {
117+
for h in from_h..to_h {
118+
for w in from_w..to_w {
119+
self.framebuffer.set(h * SCREEN_FB_WIDTH + w, self.color_bg);
120+
}
121+
}
122+
}
123+
124+
fn puts(&mut self, text: &[u8]) {
125+
let bytes_per_glyph = DEBUG_FONT.width * DEBUG_FONT.height / 8;
126+
127+
for &chr in text.iter() {
128+
if chr == b'\t' {
129+
self.coord_x += SCREEN_TAB_W - (self.coord_x % SCREEN_TAB_W);
130+
continue;
131+
}
132+
133+
// Go to next line at the end of the current line
134+
if self.coord_x + DEBUG_FONT.width > SCREEN_WIDTH {
135+
self.coord_y += DEBUG_FONT.size_h;
136+
self.coord_x = 0;
137+
}
138+
139+
// Go to screen top when at the bottom of the screen
140+
if self.coord_y + DEBUG_FONT.height > SCREEN_HEIGHT {
141+
self.coord_x = 0;
142+
self.coord_y = 0;
143+
}
144+
145+
if chr == b'\n' {
146+
self.coord_x = 0;
147+
self.coord_y += DEBUG_FONT.size_h;
148+
continue;
149+
} else if chr == b'\r' {
150+
self.coord_x = 0;
151+
continue;
152+
}
153+
154+
let current_offset = self.coord_x + self.coord_y * SCREEN_FB_WIDTH;
155+
let mut font =
156+
&DEBUG_FONT.glyphs[(chr - DEBUG_FONT.first) as usize * bytes_per_glyph..];
157+
let mut mask = 1 << 7;
158+
159+
for row in 0..DEBUG_FONT.height {
160+
for col in 0..DEBUG_FONT.width {
161+
if mask == 0 {
162+
font = &font[1..];
163+
mask = 1 << 7;
164+
}
165+
166+
self.framebuffer.set(
167+
current_offset + row * SCREEN_FB_WIDTH + col,
168+
if font[0] & mask == 0 {
169+
self.color_bg
170+
} else {
171+
self.color_fg
172+
},
173+
);
174+
175+
mask >>= 1;
176+
}
177+
178+
#[allow(clippy::reversed_empty_ranges)]
179+
for col in DEBUG_FONT.width..DEBUG_FONT.size_w {
180+
self.framebuffer
181+
.set(current_offset + row * SCREEN_FB_WIDTH + col, self.color_bg)
182+
}
183+
}
184+
185+
#[allow(clippy::reversed_empty_ranges)]
186+
for row in DEBUG_FONT.height..DEBUG_FONT.size_h {
187+
for col in 0..DEBUG_FONT.size_w {
188+
self.framebuffer
189+
.set(current_offset + row * SCREEN_FB_WIDTH + col, self.color_bg)
190+
}
191+
}
192+
193+
self.coord_x += DEBUG_FONT.size_w;
194+
}
195+
}
196+
}

crates/4-vitasdk/src/main.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use std::backtrace::Backtrace;
2+
use std::fmt::Write;
3+
use std::panic::{self, PanicInfo};
4+
use std::thread;
5+
use std::time::Duration;
6+
7+
mod debug;
8+
9+
pub fn main() {
10+
let default_hook = panic::take_hook();
11+
panic::set_hook(Box::new(move |info| {
12+
custom_panic_hook(info);
13+
default_hook(info);
14+
}));
15+
16+
let mut screen = debug::screen::DebugScreen::new();
17+
writeln!(screen, "This not-so-bare-metal is starting to rust!").ok();
18+
thread::sleep(Duration::from_secs(2));
19+
writeln!(screen, "See? Told ya!").ok();
20+
thread::sleep(Duration::from_secs(2));
21+
22+
let random_numbers: Vec<u8> = (0..8).map(|_i| rand::random::<u8>()).collect();
23+
writeln!(screen, "Some random numbers: {:?}", random_numbers).ok();
24+
25+
thread::sleep(Duration::from_secs(5));
26+
}
27+
28+
fn custom_panic_hook(info: &PanicInfo<'_>) {
29+
// The current implementation always returns `Some`.
30+
let location = info.location().unwrap();
31+
32+
let msg = match info.payload().downcast_ref::<&'static str>() {
33+
Some(s) => *s,
34+
None => match info.payload().downcast_ref::<String>() {
35+
Some(s) => &s[..],
36+
None => "Box<Any>",
37+
},
38+
};
39+
let name = "unknown";
40+
41+
let mut screen = debug::screen::DebugScreen::new();
42+
43+
writeln!(
44+
screen,
45+
"thread '{}' panicked at '{}', {}",
46+
name, msg, location
47+
)
48+
.ok();
49+
50+
// Give 2 seconds to see the error in case capturing the stack trace fails
51+
// (capturing the stack trace allocates memory)
52+
thread::sleep(Duration::from_secs(2));
53+
54+
// The backtrace is full of "unknown" as there's no elf to parse on the vita
55+
let backtrace = Backtrace::force_capture();
56+
writeln!(screen, "{}", backtrace).ok();
57+
58+
thread::sleep(Duration::from_secs(10));
59+
}
12.6 KB
Loading
Loading
Loading
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<livearea style="a1" format-ver="01.00" content-rev="1">
4+
<livearea-background>
5+
<image>bg.png</image>
6+
</livearea-background>
7+
8+
<gate>
9+
<startup-image>startup.png</startup-image>
10+
</gate>
11+
</livearea>

0 commit comments

Comments
 (0)