Skip to content

Commit 1281395

Browse files
committed
Added vitasdk example
1 parent dfe2140 commit 1281395

File tree

13 files changed

+328
-7
lines changed

13 files changed

+328
-7
lines changed

.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
{
2-
"rust-analyzer.cargo.target": "armv7-sony-vita-newlibeabihf"
2+
"rust-analyzer.cargo.target": "armv7-sony-vita-newlibeabihf",
3+
"rust-analyzer.cargo.extraEnv": {
4+
"PKG_CONFIG_SYSROOT_DIR": "/opt/vitasdk",
5+
"PKG_CONFIG_PATH": "/opt/vitasdk/arm-vita-eabi/lib/pkgconfig",
6+
}
37
}

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

crates/4-vitasdk/src/main.rs

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