From 683fad4aee346d73c731f0e7ef652f84abeac322 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Wed, 12 Apr 2023 11:06:20 -0400 Subject: [PATCH] Initial pass of Swap/Flush traits for screens --- ctru-rs/Cargo.toml | 4 +- ctru-rs/examples/camera-image.rs | 2 +- ctru-rs/examples/gfx-3d-mode.rs | 14 +++-- ctru-rs/examples/graphics-bitmap.rs | 2 +- ctru-rs/src/lib.rs | 2 +- ctru-rs/src/services/gfx.rs | 97 +++++++++++++++++++++-------- 6 files changed, 84 insertions(+), 37 deletions(-) diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index d8b095a..a79e7ac 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = [ "Rust3DS Org", "Ronald Kinard " ] +authors = ["Rust3DS Org", "Ronald Kinard "] description = "A safe wrapper around smealum's ctrulib." license = "Zlib" name = "ctru-rs" @@ -15,7 +15,7 @@ name = "ctru" cfg-if = "1.0" ctru-sys = { path = "../ctru-sys", version = "21.2" } const-zero = "0.1.0" -linker-fix-3ds = { git = "https://github.com/rust3ds/rust-linker-fix-3ds.git" } +shim-3ds = { git = "https://github.com/rust3ds/shim-3ds.git" } pthread-3ds = { git = "https://github.com/rust3ds/pthread-3ds.git" } libc = "0.2.121" bitflags = "1.0.0" diff --git a/ctru-rs/examples/camera-image.rs b/ctru-rs/examples/camera-image.rs index dcc92ff..010ef95 100644 --- a/ctru-rs/examples/camera-image.rs +++ b/ctru-rs/examples/camera-image.rs @@ -1,6 +1,6 @@ use ctru::prelude::*; use ctru::services::cam::{Cam, Camera, OutputFormat, ShutterSound, ViewSize}; -use ctru::services::gfx::Screen; +use ctru::services::gfx::{Flush, Screen, Swap}; use ctru::services::gspgpu::FramebufferFormat; use std::time::Duration; diff --git a/ctru-rs/examples/gfx-3d-mode.rs b/ctru-rs/examples/gfx-3d-mode.rs index 5bd982f..4108694 100644 --- a/ctru-rs/examples/gfx-3d-mode.rs +++ b/ctru-rs/examples/gfx-3d-mode.rs @@ -1,5 +1,5 @@ use ctru::prelude::*; -use ctru::services::gfx::{Screen, Side, TopScreen3D}; +use ctru::services::gfx::{Screen, Side, Swap, TopScreen3D}; /// See `graphics-bitmap.rs` for details on how the image is generated. /// @@ -21,8 +21,7 @@ fn main() { gfx.top_screen.borrow_mut().set_double_buffering(true); - let top_screen = TopScreen3D::from(&gfx.top_screen); - let (mut left, mut right) = top_screen.split_mut(); + let mut top_screen = TopScreen3D::from(&gfx.top_screen); let mut current_side = Side::Left; @@ -35,6 +34,8 @@ fn main() { break; } + let (mut left, mut right) = top_screen.split_mut(); + let left_buf = left.raw_framebuffer(); let right_buf = right.raw_framebuffer(); @@ -61,8 +62,11 @@ fn main() { buf.copy_from(IMAGE.as_ptr(), IMAGE.len()); } - left.flush_buffer(); - left.swap_buffers(); + drop(left); + drop(right); + + top_screen.flush_buffers(); + top_screen.swap_buffers(); //Wait for VBlank gfx.wait_for_vblank(); diff --git a/ctru-rs/examples/graphics-bitmap.rs b/ctru-rs/examples/graphics-bitmap.rs index 4beacea..01358ac 100644 --- a/ctru-rs/examples/graphics-bitmap.rs +++ b/ctru-rs/examples/graphics-bitmap.rs @@ -1,5 +1,5 @@ use ctru::prelude::*; -use ctru::services::gfx::Screen; +use ctru::services::gfx::{Flush, Screen, Swap}; /// Ferris image taken from and scaled down to 320x240px. /// To regenerate the data, you will need to install `imagemagick` and run this diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 57b61e9..210d37f 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -8,8 +8,8 @@ #![test_runner(test_runner::run)] // Nothing is imported from these crates but their inclusion here assures correct linking of the missing implementations. -extern crate linker_fix_3ds; extern crate pthread_3ds; +extern crate shim_3ds; #[no_mangle] #[cfg(feature = "big-stack")] diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 1412bb7..6bbb02d 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -9,11 +9,12 @@ use crate::services::gspgpu::{self, FramebufferFormat}; use crate::services::ServiceReference; mod private { - use super::{BottomScreen, TopScreen, TopScreenLeft, TopScreenRight}; + use super::{BottomScreen, TopScreen, TopScreen3D, TopScreenLeft, TopScreenRight}; pub trait Sealed {} impl Sealed for TopScreen {} + impl Sealed for TopScreen3D<'_> {} impl Sealed for TopScreenLeft {} impl Sealed for TopScreenRight {} impl Sealed for BottomScreen {} @@ -55,28 +56,6 @@ pub trait Screen: private::Sealed { unsafe { ctru_sys::gfxSetDoubleBuffering(self.as_raw(), enabled) } } - /// Swaps the video buffers. - /// - /// This should be used even if double buffering is disabled. - fn flush_buffer(&mut self) { - let framebuffer = self.raw_framebuffer(); - - // Flush the data array. `self.raw_framebuffer` should get the correct parameters for all kinds of screens - unsafe { - ctru_sys::GSPGPU_FlushDataCache( - framebuffer.ptr.cast(), - (framebuffer.height * framebuffer.width) as u32, - ) - }; - } - - /// Swaps the video buffers. - /// - /// This should be used even if double buffering is disabled. - fn swap_buffers(&mut self) { - unsafe { ctru_sys::gfxScreenSwapBuffers(self.side().into(), true) }; - } - /// Gets the framebuffer format fn framebuffer_format(&self) -> FramebufferFormat { unsafe { ctru_sys::gfxGetScreenFormat(self.as_raw()) }.into() @@ -101,13 +80,77 @@ pub struct TopScreen3D<'top_screen> { screen: &'top_screen RefCell, } -struct TopScreenLeft; +pub trait Swap: private::Sealed { + fn swap_buffers(&mut self); +} + +trait SwappableScreen: Screen {} +impl SwappableScreen for TopScreen {} +impl SwappableScreen for BottomScreen {} + +impl Swap for S { + fn swap_buffers(&mut self) { + unsafe { + ctru_sys::gfxScreenSwapBuffers(self.side().into(), false); + } + } +} + +pub trait Flush: private::Sealed { + fn flush_buffer(&mut self); +} -struct TopScreenRight; +trait FlushableScreen: Screen {} +impl FlushableScreen for TopScreen {} +impl FlushableScreen for BottomScreen {} +impl FlushableScreen for TopScreenLeft {} +impl FlushableScreen for TopScreenRight {} +impl Flush for S { + fn flush_buffer(&mut self) { + let framebuffer = self.raw_framebuffer(); + + // Flush the data array. `self.raw_framebuffer` should get the correct parameters for all kinds of screens + unsafe { + ctru_sys::GSPGPU_FlushDataCache( + framebuffer.ptr.cast(), + (framebuffer.height * framebuffer.width) as u32, + ) + }; + } +} + +impl Swap for TopScreen3D<'_> { + fn swap_buffers(&mut self) { + unsafe { + ctru_sys::gfxScreenSwapBuffers(Side::Left.into(), true); + } + } +} + +impl TopScreen3D<'_> { + /// Flush the buffers for both the left and right sides of the screen. + pub fn flush_buffers(&mut self) { + let (mut left, mut right) = self.split_mut(); + left.flush_buffer(); + right.flush_buffer(); + } +} + +/// The left side of the top screen, when using 3D mode. +#[derive(Debug)] +#[non_exhaustive] +pub struct TopScreenLeft; + +/// The right side of the top screen, when using 3D mode. +#[derive(Debug)] #[non_exhaustive] +pub struct TopScreenRight; + /// The bottom screen. Mutable access to this struct is required to write to the /// bottom screen's frame buffer. +#[derive(Debug)] +#[non_exhaustive] pub struct BottomScreen; /// Representation of a framebuffer for one [`Side`] of the top screen, or the @@ -194,14 +237,14 @@ impl Gfx { impl TopScreen3D<'_> { /// Immutably borrow the two sides of the screen as `(left, right)`. - pub fn split(&self) -> (Ref, Ref) { + pub fn split(&self) -> (Ref, Ref) { Ref::map_split(self.screen.borrow(), |screen| { (&screen.left as _, &screen.right as _) }) } /// Mutably borrow the two sides of the screen as `(left, right)`. - pub fn split_mut(&self) -> (RefMut, RefMut) { + pub fn split_mut(&self) -> (RefMut, RefMut) { RefMut::map_split(self.screen.borrow_mut(), |screen| { (&mut screen.left as _, &mut screen.right as _) })