Skip to content
Snippets Groups Projects
Verified Commit 9aeec374 authored by João Magalhães's avatar João Magalhães :rocket:
Browse files

chore: initial working version of the display

parent 247fb798
No related branches found
No related tags found
1 merge request!29Support for Libretro
Pipeline #3072 passed
......@@ -4,17 +4,25 @@ use std::os::raw::{c_char, c_float, c_uint, c_void};
use boytacean::{
gb::GameBoy,
ppu::{DISPLAY_HEIGHT, DISPLAY_WIDTH},
ppu::{DISPLAY_HEIGHT, DISPLAY_WIDTH, RGB1555_SIZE},
};
const RETRO_API_VERSION: u32 = 1;
const REGION_NTSC: u32 = 0;
//const RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: u32 = 10;
//const RETRO_PIXEL_FORMAT_0RGB1555: usize = 0;
//const RETRO_PIXEL_FORMAT_XRGB8888: usize = 1;
//const RETRO_PIXEL_FORMAT_RGB565: usize = 2;
//const RETRO_MEMORY_SAVE_RAM: u32 = 0;
//const RETRO_MEMORY_SYSTEM_RAM: u32 = 0;
static mut EMULATOR: Option<GameBoy> = None;
static mut ENVIRONMENT_CALLBACK: Option<extern "C" fn(u32, *const c_void) -> bool> = None;
static mut VIDEO_REFRESH_CALLBACK: Option<extern "C" fn(*const u8)> = None;
static mut VIDEO_REFRESH_CALLBACK: Option<extern "C" fn(*const u8, c_uint, c_uint, usize)> = None;
static mut AUDIO_SAMPLE_CALLBACK: Option<extern "C" fn(i16, i16)> = None;
static mut AUDIO_SAMPLE_BATCH_CALLBACK: Option<extern "C" fn(*const i16, usize)> = None;
static mut INPUT_POLL_CALLBACK: Option<extern "C" fn()> = None;
......@@ -63,6 +71,10 @@ pub struct RetroSystemTiming {
#[no_mangle]
pub extern "C" fn retro_init() {
println!("retro_init()");
unsafe {
EMULATOR = Some(GameBoy::new(None));
EMULATOR.as_mut().unwrap().load(true);
}
}
#[no_mangle]
......@@ -118,7 +130,9 @@ pub extern "C" fn retro_set_environment(
}
#[no_mangle]
pub extern "C" fn retro_set_video_refresh(callback: Option<extern "C" fn(*const u8)>) {
pub extern "C" fn retro_set_video_refresh(
callback: Option<extern "C" fn(*const u8, c_uint, c_uint, usize)>,
) {
println!("retro_set_video_refresh()");
unsafe {
VIDEO_REFRESH_CALLBACK = callback;
......@@ -176,7 +190,35 @@ pub extern "C" fn retro_set_controller_port_device() {
#[no_mangle]
pub extern "C" fn retro_run() {
println!("retro_run()");
let emulator = unsafe { EMULATOR.as_mut().unwrap() };
let mut counter_cycles = 0_u32;
let cycle_limit = 4194304 / 60; //@TODO this is super tricky
loop {
// limits the number of ticks to the typical number
// of cycles expected for the current logic cycle
if counter_cycles >= cycle_limit {
//pending_cycles = counter_cycles - cycle_limit;
break;
}
// runs the Game Boy clock, this operation should
// include the advance of both the CPU, PPU, APU
// and any other frequency based component of the system
counter_cycles += emulator.clock() as u32;
}
let frame_buffer = emulator.frame_buffer_rgb1555();
unsafe {
VIDEO_REFRESH_CALLBACK.unwrap()(
frame_buffer.as_ptr(),
DISPLAY_WIDTH as u32,
DISPLAY_HEIGHT as u32,
DISPLAY_WIDTH * RGB1555_SIZE,
);
}
}
#[no_mangle]
......@@ -186,8 +228,12 @@ pub extern "C" fn retro_get_region() -> u32 {
}
#[no_mangle]
pub extern "C" fn retro_load_game(_game: *const RetroGameInfo) -> bool {
pub extern "C" fn retro_load_game(game: *const RetroGameInfo) -> bool {
println!("retro_load_game()");
unsafe {
let data_buffer = std::slice::from_raw_parts((*game).data as *const u8, (*game).size);
EMULATOR.as_mut().unwrap().load_rom(data_buffer, None);
}
return true;
}
......
......@@ -14,7 +14,10 @@ use crate::{
gen::{COMPILATION_DATE, COMPILATION_TIME, COMPILER, COMPILER_VERSION, VERSION},
mmu::Mmu,
pad::{Pad, PadKey},
ppu::{Ppu, PpuMode, Tile, DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_SIZE},
ppu::{
Ppu, PpuMode, Tile, DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_RGB155_SIZE,
FRAME_BUFFER_SIZE,
},
rom::{Cartridge, RamSize},
serial::{NullDevice, Serial, SerialDevice},
timer::Timer,
......@@ -950,6 +953,10 @@ impl GameBoy {
&(self.ppu().frame_buffer)
}
pub fn frame_buffer_rgb1555(&mut self) -> [u8; FRAME_BUFFER_RGB155_SIZE] {
self.ppu().frame_buffer_rgb1555()
}
pub fn audio_buffer(&mut self) -> &VecDeque<u8> {
self.apu().audio_buffer()
}
......
......@@ -23,6 +23,7 @@ pub const OAM_SIZE: usize = 260;
pub const PALETTE_SIZE: usize = 4;
pub const RGB_SIZE: usize = 3;
pub const RGBA_SIZE: usize = 4;
pub const RGB1555_SIZE: usize = 2;
pub const TILE_WIDTH: usize = 8;
pub const TILE_HEIGHT: usize = 8;
pub const TILE_WIDTH_I: usize = 7;
......@@ -46,13 +47,19 @@ pub const DISPLAY_WIDTH: usize = 160;
/// The height of the Game Boy screen in pixels.
pub const DISPLAY_HEIGHT: usize = 144;
/// The size in pixels of the display.
pub const DISPLAY_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT;
/// The size to be used by the buffer of colors
/// for the Game Boy screen the values there should
/// range from 0 to 3.
pub const COLOR_BUFFER_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT;
pub const COLOR_BUFFER_SIZE: usize = DISPLAY_SIZE;
/// The size of the RGB frame buffer in bytes.
pub const FRAME_BUFFER_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE;
pub const FRAME_BUFFER_SIZE: usize = DISPLAY_SIZE * RGB_SIZE;
/// The size of the RGB1555 frame buffer in bytes.
pub const FRAME_BUFFER_RGB155_SIZE: usize = DISPLAY_SIZE * RGB1555_SIZE;
/// The base colors to be used to populate the
/// custom palettes of the Game Boy.
......@@ -74,6 +81,10 @@ pub type Pixel = [u8; RGB_SIZE];
/// with the size of RGBA (4 bytes).
pub type PixelAlpha = [u8; RGBA_SIZE];
/// Defines a pixel with 5 bits per channel plus a padding
/// bit at the beginning.
pub type PixelRgb1555 = [u8; RGB1555_SIZE];
/// Defines a type that represents a color palette
/// within the Game Boy context.
pub type Palette = [Pixel; PALETTE_SIZE];
......@@ -896,6 +907,21 @@ impl Ppu {
}
}
pub fn frame_buffer_rgb1555(&self) -> [u8; FRAME_BUFFER_RGB155_SIZE] {
let mut buffer = [0u8; FRAME_BUFFER_RGB155_SIZE];
for index in 0..DISPLAY_SIZE {
let (r, g, b) = (
self.frame_buffer[index * 3],
self.frame_buffer[index * 3 + 1],
self.frame_buffer[index * 3 + 2],
);
let rgb1555 = Self::rgb888_to_rgb1555(r, g, b);
buffer[index * 2] = rgb1555[0];
buffer[index * 2 + 1] = rgb1555[1];
}
buffer
}
pub fn vram(&self) -> &[u8; VRAM_SIZE] {
&self.vram
}
......@@ -1709,6 +1735,16 @@ impl Ppu {
let b = ((second & 0x7c) >> 2) << 3;
[r, g, b]
}
fn rgb888_to_rgb1555(first: u8, second: u8, third: u8) -> PixelRgb1555 {
let r = (first as u16 >> 3) & 0x1F;
let g = (second as u16 >> 3) & 0x1F;
let b = (third as u16 >> 3) & 0x1F;
let a = 1;
let pixel = (a << 15) | (b << 10) | (g << 5) | r;
[pixel as u8, (pixel >> 8) as u8]
}
}
impl Default for Ppu {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment