From d870fd4f07477a63d82cb4b63a1681c5ea27febd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Fri, 4 Aug 2023 01:14:01 +0100
Subject: [PATCH] chore: better endian handling in frame buffer

---
 frontends/libretro/src/lib.rs |  8 ++---
 src/gb.rs                     | 12 ++++++++
 src/ppu.rs                    | 55 +++++++++++++++++++++++++++++++----
 3 files changed, 66 insertions(+), 9 deletions(-)

diff --git a/frontends/libretro/src/lib.rs b/frontends/libretro/src/lib.rs
index 11af42c0..3343e8e5 100644
--- a/frontends/libretro/src/lib.rs
+++ b/frontends/libretro/src/lib.rs
@@ -6,7 +6,7 @@ use boytacean::{
     debugln,
     gb::{AudioProvider, GameBoy},
     pad::PadKey,
-    ppu::{DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_XRGB8888_SIZE, XRGB8888_SIZE},
+    ppu::{DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_SIZE, XRGB8888_SIZE},
     rom::Cartridge,
 };
 use consts::{
@@ -28,7 +28,7 @@ use std::{
 
 static mut EMULATOR: Option<GameBoy> = None;
 static mut KEY_STATES: Option<HashMap<RetroJoypad, bool>> = None;
-static mut FRAME_BUFFER: [u8; FRAME_BUFFER_XRGB8888_SIZE] = [0x00; FRAME_BUFFER_XRGB8888_SIZE];
+static mut FRAME_BUFFER: [u32; FRAME_BUFFER_SIZE] = [0x00; FRAME_BUFFER_SIZE];
 
 static mut PENDING_CYCLES: u32 = 0_u32;
 
@@ -249,11 +249,11 @@ pub extern "C" fn retro_run() {
         // in case a new frame is available in the emulator
         // then the frame must be pushed into display
         if emulator.ppu_frame() != last_frame {
-            let frame_buffer = emulator.frame_buffer_xrgb8888();
+            let frame_buffer = emulator.frame_buffer_xrgb8888_u32();
             unsafe {
                 FRAME_BUFFER.copy_from_slice(&frame_buffer);
                 video_refresh_cb(
-                    FRAME_BUFFER.as_ptr(),
+                    FRAME_BUFFER.as_ptr() as *const u8,
                     DISPLAY_WIDTH as u32,
                     DISPLAY_HEIGHT as u32,
                     DISPLAY_WIDTH * XRGB8888_SIZE,
diff --git a/src/gb.rs b/src/gb.rs
index 16f06677..45ab76ed 100644
--- a/src/gb.rs
+++ b/src/gb.rs
@@ -966,14 +966,26 @@ impl GameBoy {
         self.ppu().frame_buffer_xrgb8888()
     }
 
+    pub fn frame_buffer_xrgb8888_u32(&mut self) -> [u32; FRAME_BUFFER_SIZE] {
+        self.ppu().frame_buffer_xrgb8888_u32()
+    }
+
     pub fn frame_buffer_rgb1555(&mut self) -> [u8; FRAME_BUFFER_RGB1555_SIZE] {
         self.ppu().frame_buffer_rgb1555()
     }
 
+    pub fn frame_buffer_rgb1555_u16(&mut self) -> [u16; FRAME_BUFFER_SIZE] {
+        self.ppu().frame_buffer_rgb1555_u16()
+    }
+
     pub fn frame_buffer_rgb565(&mut self) -> [u8; FRAME_BUFFER_RGB565_SIZE] {
         self.ppu().frame_buffer_rgb565()
     }
 
+    pub fn frame_buffer_rgb565_u16(&mut self) -> [u16; FRAME_BUFFER_SIZE] {
+        self.ppu().frame_buffer_rgb565_u16()
+    }
+
     pub fn audio_buffer(&mut self) -> &VecDeque<u8> {
         self.apu().audio_buffer()
     }
diff --git a/src/ppu.rs b/src/ppu.rs
index b79e97f2..6abf7199 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -939,6 +939,19 @@ impl Ppu {
         buffer
     }
 
+    pub fn frame_buffer_xrgb8888_u32(&self) -> [u32; FRAME_BUFFER_SIZE] {
+        let mut buffer = [0u32; FRAME_BUFFER_SIZE];
+        for index in 0..DISPLAY_SIZE {
+            let (r, g, b) = (
+                self.frame_buffer[index * RGB_SIZE],
+                self.frame_buffer[index * RGB_SIZE + 1],
+                self.frame_buffer[index * RGB_SIZE + 2],
+            );
+            buffer[index] = ((r as u32) << 16) | ((g as u32) << 8) | b as u32;
+        }
+        buffer
+    }
+
     pub fn frame_buffer_rgb1555(&self) -> [u8; FRAME_BUFFER_RGB1555_SIZE] {
         let mut buffer = [0u8; FRAME_BUFFER_RGB1555_SIZE];
         for index in 0..DISPLAY_SIZE {
@@ -954,6 +967,19 @@ impl Ppu {
         buffer
     }
 
+    pub fn frame_buffer_rgb1555_u16(&self) -> [u16; FRAME_BUFFER_SIZE] {
+        let mut buffer = [0u16; FRAME_BUFFER_SIZE];
+        for index in 0..DISPLAY_SIZE {
+            let (r, g, b) = (
+                self.frame_buffer[index * RGB_SIZE],
+                self.frame_buffer[index * RGB_SIZE + 1],
+                self.frame_buffer[index * RGB_SIZE + 2],
+            );
+            buffer[index] = Self::rgb888_to_rgb1555_u16(r, g, b);
+        }
+        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 {
@@ -969,6 +995,19 @@ impl Ppu {
         buffer
     }
 
+    pub fn frame_buffer_rgb565_u16(&self) -> [u16; FRAME_BUFFER_SIZE] {
+        let mut buffer = [0u16; FRAME_BUFFER_SIZE];
+        for index in 0..DISPLAY_SIZE {
+            let (r, g, b) = (
+                self.frame_buffer[index * RGB_SIZE],
+                self.frame_buffer[index * RGB_SIZE + 1],
+                self.frame_buffer[index * RGB_SIZE + 2],
+            );
+            buffer[index] = Self::rgb888_to_rgb565_u16(r, g, b);
+        }
+        buffer
+    }
+
     pub fn vram(&self) -> &[u8; VRAM_SIZE] {
         &self.vram
     }
@@ -1784,22 +1823,28 @@ impl Ppu {
     }
 
     fn rgb888_to_rgb1555(first: u8, second: u8, third: u8) -> PixelRgb1555 {
+        let pixel = Self::rgb888_to_rgb1555_u16(first, second, third);
+        [pixel as u8, (pixel >> 8) as u8]
+    }
+
+    fn rgb888_to_rgb1555_u16(first: u8, second: u8, third: u8) -> u16 {
         let r = (first as u16 >> 3) & 0x1f;
         let g = (second as u16 >> 3) & 0x1f;
         let b = (third as u16 >> 3) & 0x1f;
         let a = 1;
+        (a << 15) | (r << 10) | (g << 5) | b
+    }
 
-        let pixel = (a << 15) | (r << 10) | (g << 5) | b;
+    fn rgb888_to_rgb565(first: u8, second: u8, third: u8) -> PixelRgb565 {
+        let pixel = Self::rgb888_to_rgb565_u16(first, second, third);
         [pixel as u8, (pixel >> 8) as u8]
     }
 
-    fn rgb888_to_rgb565(first: u8, second: u8, third: u8) -> PixelRgb565 {
+    fn rgb888_to_rgb565_u16(first: u8, second: u8, third: u8) -> u16 {
         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]
+        (r << 11) | (g << 5) | b
     }
 }
 
-- 
GitLab