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

chore: rgb565 support for libretro

parent ee1e04f6
No related branches found
No related tags found
No related merge requests found
Pipeline #3170 passed
...@@ -6,16 +6,17 @@ use boytacean::{ ...@@ -6,16 +6,17 @@ use boytacean::{
debugln, debugln,
gb::{AudioProvider, GameBoy}, gb::{AudioProvider, GameBoy},
pad::PadKey, pad::PadKey,
ppu::{DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_RGB155_SIZE, RGB1555_SIZE}, ppu::{DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_RGB565_SIZE, RGB565_SIZE},
rom::Cartridge, rom::Cartridge,
}; };
use consts::{ use consts::{
RETRO_DEVICE_ID_JOYPAD_A, RETRO_DEVICE_ID_JOYPAD_B, RETRO_DEVICE_ID_JOYPAD_DOWN, REGION_NTSC, RETRO_API_VERSION, RETRO_DEVICE_ID_JOYPAD_A, RETRO_DEVICE_ID_JOYPAD_B,
RETRO_DEVICE_ID_JOYPAD_L, RETRO_DEVICE_ID_JOYPAD_L2, RETRO_DEVICE_ID_JOYPAD_L3, RETRO_DEVICE_ID_JOYPAD_DOWN, RETRO_DEVICE_ID_JOYPAD_L, RETRO_DEVICE_ID_JOYPAD_L2,
RETRO_DEVICE_ID_JOYPAD_LEFT, RETRO_DEVICE_ID_JOYPAD_R, RETRO_DEVICE_ID_JOYPAD_R2, RETRO_DEVICE_ID_JOYPAD_L3, RETRO_DEVICE_ID_JOYPAD_LEFT, RETRO_DEVICE_ID_JOYPAD_R,
RETRO_DEVICE_ID_JOYPAD_R3, RETRO_DEVICE_ID_JOYPAD_RIGHT, RETRO_DEVICE_ID_JOYPAD_SELECT, RETRO_DEVICE_ID_JOYPAD_R2, RETRO_DEVICE_ID_JOYPAD_R3, RETRO_DEVICE_ID_JOYPAD_RIGHT,
RETRO_DEVICE_ID_JOYPAD_START, RETRO_DEVICE_ID_JOYPAD_UP, RETRO_DEVICE_ID_JOYPAD_X, RETRO_DEVICE_ID_JOYPAD_SELECT, RETRO_DEVICE_ID_JOYPAD_START, RETRO_DEVICE_ID_JOYPAD_UP,
RETRO_DEVICE_ID_JOYPAD_Y, RETRO_DEVICE_JOYPAD, RETRO_DEVICE_ID_JOYPAD_X, RETRO_DEVICE_ID_JOYPAD_Y, RETRO_DEVICE_JOYPAD,
RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, RETRO_PIXEL_FORMAT_RGB565,
}; };
use std::{ use std::{
collections::HashMap, collections::HashMap,
...@@ -25,11 +26,9 @@ use std::{ ...@@ -25,11 +26,9 @@ use std::{
slice::from_raw_parts, slice::from_raw_parts,
}; };
use crate::consts::{REGION_NTSC, RETRO_API_VERSION};
static mut EMULATOR: Option<GameBoy> = None; static mut EMULATOR: Option<GameBoy> = None;
static mut KEY_STATES: Option<HashMap<RetroJoypad, bool>> = None; static mut KEY_STATES: Option<HashMap<RetroJoypad, bool>> = None;
static mut FRAME_BUFFER: [u8; FRAME_BUFFER_RGB155_SIZE] = [0x00; FRAME_BUFFER_RGB155_SIZE]; static mut FRAME_BUFFER: [u8; FRAME_BUFFER_RGB565_SIZE] = [0x00; FRAME_BUFFER_RGB565_SIZE];
static mut AUDIO_BUFFER: Option<Vec<i16>> = None; static mut AUDIO_BUFFER: Option<Vec<i16>> = None;
static mut PENDING_CYCLES: u32 = 0_u32; static mut PENDING_CYCLES: u32 = 0_u32;
...@@ -198,6 +197,12 @@ pub unsafe extern "C" fn retro_get_system_av_info(info: *mut RetroSystemAvInfo) ...@@ -198,6 +197,12 @@ pub unsafe extern "C" fn retro_get_system_av_info(info: *mut RetroSystemAvInfo)
(*info).geometry.aspect_ratio = DISPLAY_WIDTH as f32 / DISPLAY_HEIGHT as f32; (*info).geometry.aspect_ratio = DISPLAY_WIDTH as f32 / DISPLAY_HEIGHT as f32;
(*info).timing.fps = GameBoy::VISUAL_FREQ as f64; (*info).timing.fps = GameBoy::VISUAL_FREQ as f64;
(*info).timing.sample_rate = EMULATOR.as_ref().unwrap().audio_sampling_rate() as f64; (*info).timing.sample_rate = EMULATOR.as_ref().unwrap().audio_sampling_rate() as f64;
let environment_cb = unsafe { ENVIRONMENT_CALLBACK.as_ref().unwrap() };
environment_cb(
RETRO_ENVIRONMENT_SET_PIXEL_FORMAT,
&RETRO_PIXEL_FORMAT_RGB565 as *const _ as *const c_void,
);
} }
#[no_mangle] #[no_mangle]
...@@ -249,14 +254,14 @@ pub extern "C" fn retro_run() { ...@@ -249,14 +254,14 @@ pub extern "C" fn retro_run() {
// in case a new frame is available in the emulator // in case a new frame is available in the emulator
// then the frame must be pushed into display // then the frame must be pushed into display
if emulator.ppu_frame() != last_frame { if emulator.ppu_frame() != last_frame {
let frame_buffer = emulator.frame_buffer_rgb1555(); let frame_buffer = emulator.frame_buffer_rgb565();
unsafe { unsafe {
FRAME_BUFFER.copy_from_slice(&frame_buffer); FRAME_BUFFER.copy_from_slice(&frame_buffer);
video_refresh_cb( video_refresh_cb(
FRAME_BUFFER.as_ptr(), FRAME_BUFFER.as_ptr(),
DISPLAY_WIDTH as u32, DISPLAY_WIDTH as u32,
DISPLAY_HEIGHT as u32, DISPLAY_HEIGHT as u32,
DISPLAY_WIDTH * RGB1555_SIZE, DISPLAY_WIDTH * RGB565_SIZE,
); );
} }
......
...@@ -16,8 +16,8 @@ use crate::{ ...@@ -16,8 +16,8 @@ use crate::{
mmu::Mmu, mmu::Mmu,
pad::{Pad, PadKey}, pad::{Pad, PadKey},
ppu::{ ppu::{
Ppu, PpuMode, Tile, DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_RGB155_SIZE, Ppu, PpuMode, Tile, DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_RGB1555_SIZE,
FRAME_BUFFER_SIZE, FRAME_BUFFER_RGB565_SIZE, FRAME_BUFFER_SIZE,
}, },
rom::{Cartridge, RamSize}, rom::{Cartridge, RamSize},
serial::{NullDevice, Serial, SerialDevice}, serial::{NullDevice, Serial, SerialDevice},
...@@ -962,10 +962,14 @@ impl GameBoy { ...@@ -962,10 +962,14 @@ impl GameBoy {
&(self.ppu().frame_buffer) &(self.ppu().frame_buffer)
} }
pub fn frame_buffer_rgb1555(&mut self) -> [u8; FRAME_BUFFER_RGB155_SIZE] { pub fn frame_buffer_rgb1555(&mut self) -> [u8; FRAME_BUFFER_RGB1555_SIZE] {
self.ppu().frame_buffer_rgb1555() self.ppu().frame_buffer_rgb1555()
} }
pub fn frame_buffer_rgb565(&mut self) -> [u8; FRAME_BUFFER_RGB565_SIZE] {
self.ppu().frame_buffer_rgb565()
}
pub fn audio_buffer(&mut self) -> &VecDeque<u8> { pub fn audio_buffer(&mut self) -> &VecDeque<u8> {
self.apu().audio_buffer() self.apu().audio_buffer()
} }
......
...@@ -24,6 +24,7 @@ pub const PALETTE_SIZE: usize = 4; ...@@ -24,6 +24,7 @@ pub const PALETTE_SIZE: usize = 4;
pub const RGB_SIZE: usize = 3; pub const RGB_SIZE: usize = 3;
pub const RGBA_SIZE: usize = 4; pub const RGBA_SIZE: usize = 4;
pub const RGB1555_SIZE: usize = 2; pub const RGB1555_SIZE: usize = 2;
pub const RGB565_SIZE: usize = 2;
pub const TILE_WIDTH: usize = 8; pub const TILE_WIDTH: usize = 8;
pub const TILE_HEIGHT: usize = 8; pub const TILE_HEIGHT: usize = 8;
pub const TILE_WIDTH_I: usize = 7; pub const TILE_WIDTH_I: usize = 7;
...@@ -59,7 +60,10 @@ pub const COLOR_BUFFER_SIZE: usize = DISPLAY_SIZE; ...@@ -59,7 +60,10 @@ pub const COLOR_BUFFER_SIZE: usize = DISPLAY_SIZE;
pub const FRAME_BUFFER_SIZE: usize = DISPLAY_SIZE * RGB_SIZE; pub const FRAME_BUFFER_SIZE: usize = DISPLAY_SIZE * RGB_SIZE;
/// The size of the RGB1555 frame buffer in bytes. /// The size of the RGB1555 frame buffer in bytes.
pub const FRAME_BUFFER_RGB155_SIZE: usize = DISPLAY_SIZE * RGB1555_SIZE; pub const FRAME_BUFFER_RGB1555_SIZE: usize = DISPLAY_SIZE * RGB1555_SIZE;
/// The size of the RGB565 frame buffer in bytes.
pub const FRAME_BUFFER_RGB565_SIZE: usize = DISPLAY_SIZE * RGB565_SIZE;
/// The base colors to be used to populate the /// The base colors to be used to populate the
/// custom palettes of the Game Boy. /// custom palettes of the Game Boy.
...@@ -85,6 +89,10 @@ pub type PixelAlpha = [u8; RGBA_SIZE]; ...@@ -85,6 +89,10 @@ pub type PixelAlpha = [u8; RGBA_SIZE];
/// bit at the beginning. /// bit at the beginning.
pub type PixelRgb1555 = [u8; RGB1555_SIZE]; pub type PixelRgb1555 = [u8; RGB1555_SIZE];
/// Defines a pixel with 5 bits per channel except for the
/// green channel which uses 6 bits.
pub type PixelRgb565 = [u8; RGB565_SIZE];
/// Defines a type that represents a color palette /// Defines a type that represents a color palette
/// within the Game Boy context. /// within the Game Boy context.
pub type Palette = [Pixel; PALETTE_SIZE]; pub type Palette = [Pixel; PALETTE_SIZE];
...@@ -907,8 +915,8 @@ impl Ppu { ...@@ -907,8 +915,8 @@ impl Ppu {
} }
} }
pub fn frame_buffer_rgb1555(&self) -> [u8; FRAME_BUFFER_RGB155_SIZE] { pub fn frame_buffer_rgb1555(&self) -> [u8; FRAME_BUFFER_RGB1555_SIZE] {
let mut buffer = [0u8; FRAME_BUFFER_RGB155_SIZE]; let mut buffer = [0u8; FRAME_BUFFER_RGB1555_SIZE];
for index in 0..DISPLAY_SIZE { for index in 0..DISPLAY_SIZE {
let (r, g, b) = ( let (r, g, b) = (
self.frame_buffer[index * 3], self.frame_buffer[index * 3],
...@@ -922,6 +930,21 @@ impl Ppu { ...@@ -922,6 +930,21 @@ impl Ppu {
buffer buffer
} }
pub fn frame_buffer_rgb565(&self) -> [u8; FRAME_BUFFER_RGB565_SIZE] {
let mut buffer = [0u8; FRAME_BUFFER_RGB565_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 rgb565 = Self::rgb888_to_rgb565(r, g, b);
buffer[index * 2] = rgb565[0];
buffer[index * 2 + 1] = rgb565[1];
}
buffer
}
pub fn vram(&self) -> &[u8; VRAM_SIZE] { pub fn vram(&self) -> &[u8; VRAM_SIZE] {
&self.vram &self.vram
} }
...@@ -1745,6 +1768,15 @@ impl Ppu { ...@@ -1745,6 +1768,15 @@ impl Ppu {
let pixel = (a << 15) | (r << 10) | (g << 5) | b; let pixel = (a << 15) | (r << 10) | (g << 5) | b;
[pixel as u8, (pixel >> 8) as u8] [pixel as u8, (pixel >> 8) as u8]
} }
fn rgb888_to_rgb565(first: u8, second: u8, third: u8) -> PixelRgb565 {
let r = (first as u16 >> 3) & 0x1f;
let g = (second as u16 >> 2) & 0x3f;
let b = (third as u16 >> 3) & 0x1f;
let pixel = (r << 11) | (g << 5) | b;
[pixel as u8, (pixel >> 8) as u8]
}
} }
impl Default for Ppu { 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