Browse Source

Finish up GFX

pull/134/head
Andrea Ciliberti 1 year ago
parent
commit
1245860aba
  1. 18
      ctru-rs/src/services/fs.rs
  2. 138
      ctru-rs/src/services/gfx.rs
  3. 2
      ctru-rs/src/services/gspgpu.rs

18
ctru-rs/src/services/fs.rs

@ -19,23 +19,23 @@ use widestring::{WideCStr, WideCString};
bitflags! { bitflags! {
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
struct FsOpen: u32 { struct FsOpen: u32 {
const FS_OPEN_READ = 1; const FS_OPEN_READ = ctru_sys::FS_OPEN_READ;
const FS_OPEN_WRITE = 2; const FS_OPEN_WRITE = ctru_sys::FS_OPEN_WRITE;
const FS_OPEN_CREATE = 4; const FS_OPEN_CREATE = ctru_sys::FS_OPEN_CREATE;
} }
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
struct FsWrite: u32 { struct FsWrite: u32 {
const FS_WRITE_FLUSH = 1; const FS_WRITE_FLUSH = ctru_sys::FS_WRITE_FLUSH;
const FS_WRITE_UPDATE_TIME = 256; const FS_WRITE_UPDATE_TIME = ctru_sys::FS_WRITE_UPDATE_TIME;
} }
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
struct FsAttribute: u32 { struct FsAttribute: u32 {
const FS_ATTRIBUTE_DIRECTORY = 1; const FS_ATTRIBUTE_DIRECTORY = ctru_sys::FS_ATTRIBUTE_DIRECTORY;
const FS_ATTRIBUTE_HIDDEN = 256; const FS_ATTRIBUTE_HIDDEN = ctru_sys::FS_ATTRIBUTE_HIDDEN;
const FS_ATTRIBUTE_ARCHIVE = 65536; const FS_ATTRIBUTE_ARCHIVE = ctru_sys::FS_ATTRIBUTE_ARCHIVE;
const FS_ATTRIBUTE_READ_ONLY = 16777216; const FS_ATTRIBUTE_READ_ONLY = ctru_sys::FS_ATTRIBUTE_READ_ONLY;
} }
} }

138
ctru-rs/src/services/gfx.rs

@ -1,4 +1,7 @@
//! Graphics service. //! Graphics service.
//!
//! The GFX service controls (in a somewhat high-level way) the console's LCD screens.
//! The screens are subordinate to the GFX service handle and can be used by only one borrower at a time.
use std::cell::{Ref, RefCell, RefMut}; use std::cell::{Ref, RefCell, RefMut};
use std::marker::PhantomData; use std::marker::PhantomData;
@ -20,6 +23,8 @@ mod private {
impl Sealed for BottomScreen {} impl Sealed for BottomScreen {}
} }
/// Trait to handle common functionality for all screens.
///
/// This trait is implemented by the screen structs for working with frame buffers and /// This trait is implemented by the screen structs for working with frame buffers and
/// drawing to the screens. Graphics-related code can be made generic over this /// drawing to the screens. Graphics-related code can be made generic over this
/// trait to work with any of the given screens. /// trait to work with any of the given screens.
@ -75,28 +80,33 @@ pub trait Screen: private::Sealed {
} }
} }
/// The top screen. Mutable access to this struct is required to write to the top /// The top LCD screen.
/// screen's frame buffer. To enable 3D mode, it can be converted into a [`TopScreen3D`]. ///
/// Mutable access to this struct is required to write to the top screen's frame buffer.
///
/// To enable 3D mode, it can be converted into a [`TopScreen3D`].
pub struct TopScreen { pub struct TopScreen {
left: TopScreenLeft, left: TopScreenLeft,
right: TopScreenRight, right: TopScreenRight,
} }
/// The top LCD screen set in stereoscopic 3D mode.
///
/// A helper container for both sides of the top screen. Once the [`TopScreen`] is /// A helper container for both sides of the top screen. Once the [`TopScreen`] is
/// converted into this, 3D mode will be enabled until this struct is dropped. /// converted into this, 3D mode will be enabled until this struct is dropped.
pub struct TopScreen3D<'screen> { pub struct TopScreen3D<'screen> {
screen: &'screen RefCell<TopScreen>, screen: &'screen RefCell<TopScreen>,
} }
/// A screen that can have its frame buffers swapped, if double buffering is enabled. /// Trait for screens that can have its frame buffers swapped, when double buffering is enabled.
/// ///
/// This trait applies to all [`Screen`]s that have swappable frame buffers. /// This trait applies to all [`Screen`]s that have swappable frame buffers.
pub trait Swap: private::Sealed { pub trait Swap: private::Sealed {
/// Swaps the video buffers. /// Swaps the video buffers.
/// ///
/// If double buffering is disabled, "swapping" the buffers has the side effect /// Even if double buffering is disabled, "swapping" the buffers has the side effect
/// of committing any configuration changes to the buffers (e.g. [`TopScreen::set_wide_mode`], /// of committing any configuration changes to the buffers (e.g. [`TopScreen::set_wide_mode()`],
/// [`Screen::set_framebuffer_format`], [`Screen::set_double_buffering`]). /// [`Screen::set_framebuffer_format()`], [`Screen::set_double_buffering()`]), so it should still be used.
/// ///
/// This should be called once per frame at most. /// This should be called once per frame at most.
#[doc(alias = "gfxScreenSwapBuffers")] #[doc(alias = "gfxScreenSwapBuffers")]
@ -127,11 +137,13 @@ impl Swap for BottomScreen {
} }
} }
/// A screen with buffers that can be flushed. This trait applies to any [`Screen`] /// A screen with buffers that can be flushed.
/// that has data written to its frame buffer. ///
/// This trait applies to any [`Screen`] that has data written to its frame buffer.
pub trait Flush: private::Sealed { pub trait Flush: private::Sealed {
/// Flushes the video buffer(s) for this screen. Note that you must still call /// Flushes the video buffer(s) for this screen.
/// [`Swap::swap_buffers`] after this method for the buffer contents to be displayed. ///
/// Note that you must still call [`Swap::swap_buffers`] after this method for the buffer contents to be displayed.
#[doc(alias = "gfxFlushBuffers")] #[doc(alias = "gfxFlushBuffers")]
fn flush_buffers(&mut self); fn flush_buffers(&mut self);
} }
@ -170,14 +182,16 @@ pub struct TopScreenLeft;
#[non_exhaustive] #[non_exhaustive]
pub struct TopScreenRight; pub struct TopScreenRight;
/// The bottom screen. Mutable access to this struct is required to write to the /// The bottom LCD screen.
/// bottom screen's frame buffer. ///
/// Mutable access to this struct is required to write to the bottom screen's frame buffer.
#[derive(Debug)] #[derive(Debug)]
#[non_exhaustive] #[non_exhaustive]
pub struct BottomScreen; pub struct BottomScreen;
/// Representation of a framebuffer for one [`Side`] of the top screen, or the /// Representation of a framebuffer for one [`Side`] of the top screen, or the entire bottom screen.
/// entire bottom screen. The inner pointer is only valid for one frame if double ///
/// The inner pointer is only valid for one frame if double
/// buffering is enabled. Data written to `ptr` will be rendered to the screen. /// buffering is enabled. Data written to `ptr` will be rendered to the screen.
#[derive(Debug)] #[derive(Debug)]
pub struct RawFrameBuffer<'screen> { pub struct RawFrameBuffer<'screen> {
@ -191,7 +205,7 @@ pub struct RawFrameBuffer<'screen> {
screen: PhantomData<&'screen mut dyn Screen>, screen: PhantomData<&'screen mut dyn Screen>,
} }
/// Side of top screen framebuffer /// Side of the [`TopScreen`]'s framebuffer.
/// ///
/// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality /// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality
#[doc(alias = "gfx3dSide_t")] #[doc(alias = "gfx3dSide_t")]
@ -204,10 +218,10 @@ pub enum Side {
Right = ctru_sys::GFX_RIGHT, Right = ctru_sys::GFX_RIGHT,
} }
/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that /// Handle to the GFX service.
/// provides helper functions and utilities for software rendering.
/// ///
/// The service exits when this struct is dropped. /// This service is a wrapper around the lower-level [GSPGPU](crate::services::gspgpu) service that
/// provides helper functions and utilities for software rendering.
pub struct Gfx { pub struct Gfx {
/// Top screen representation. /// Top screen representation.
pub top_screen: RefCell<TopScreen>, pub top_screen: RefCell<TopScreen>,
@ -221,6 +235,8 @@ static GFX_ACTIVE: Mutex<usize> = Mutex::new(0);
impl Gfx { impl Gfx {
/// Initialize a new default service handle. /// Initialize a new default service handle.
/// ///
/// # Notes
///
/// It's the same as calling: /// It's the same as calling:
/// ///
/// ```no_run /// ```no_run
@ -228,9 +244,23 @@ impl Gfx {
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # /// #
/// # use ctru::services::gfx::Gfx; /// # use ctru::services::gfx::Gfx;
/// use ctru::services::gspgpu::FramebufferFormat; /// # use ctru::services::gspgpu::FramebufferFormat;
/// #
/// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)?;
/// #
/// # Ok(())
/// # }
/// ```
///
/// # Example
///
/// ```no_run
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// #
/// use ctru::services::gfx::Gfx;
/// ///
/// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false); /// let gfx = Gfx::new()?;
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -243,6 +273,22 @@ impl Gfx {
/// Initialize a new service handle with the chosen framebuffer formats for the top and bottom screens. /// Initialize a new service handle with the chosen framebuffer formats for the top and bottom screens.
/// ///
/// Use [`Gfx::new()`] instead of this function to initialize the module with default parameters /// Use [`Gfx::new()`] instead of this function to initialize the module with default parameters
///
/// # Example
///
/// ```no_run
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// #
/// use ctru::services::{gfx::Gfx, gspgpu::FramebufferFormat};
///
/// // Top screen uses RGBA8, bottom screen uses RGB565.
/// // The screen buffers are allocated in the standard HEAP memory, and not in VRAM.
/// let gfx = Gfx::with_formats(FramebufferFormat::Rgba8, FramebufferFormat::Rgb565, false)?;
/// #
/// # Ok(())
/// # }
/// ```
#[doc(alias = "gfxInit")] #[doc(alias = "gfxInit")]
pub fn with_formats( pub fn with_formats(
top_fb_fmt: FramebufferFormat, top_fb_fmt: FramebufferFormat,
@ -267,9 +313,32 @@ impl Gfx {
}) })
} }
/// Waits for the vertical blank interrupt /// Waits for the vertical blank event.
/// ///
/// Use this to synchronize your application with the refresh rate of the LCD screens /// Use this to synchronize your application with the refresh rate of the LCD screens
///
/// # Example
///
/// ```no_run
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// #
/// use ctru::services::{apt::Apt, gfx::Gfx};
/// let apt = Apt::new()?;
/// let gfx = Gfx::new()?;
///
/// // Simple main loop.
/// while apt.main_loop() {
/// // Main program logic
///
/// // Wait for the screens to refresh.
/// // This blocks the current thread to make it run at 60Hz.
/// gfx.wait_for_vblank();
/// }
/// #
/// # Ok(())
/// # }
/// ```
pub fn wait_for_vblank(&self) { pub fn wait_for_vblank(&self) {
gspgpu::wait_for_event(gspgpu::Event::VBlank0, true); gspgpu::wait_for_event(gspgpu::Event::VBlank0, true);
} }
@ -289,6 +358,33 @@ impl TopScreen3D<'_> {
} }
} }
/// Convert the [`TopScreen`] into a [`TopScreen3D`] and activate stereoscopic 3D.
///
/// # Example
///
/// ```no_run
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// #
/// use ctru::services::gfx::{Gfx, TopScreen, TopScreen3D};
/// let gfx = Gfx::new()?;
///
/// let mut top_screen = TopScreen3D::from(&gfx.top_screen);
///
/// let (left, right) = top_screen.split_mut();
///
/// // Rendering must be done twice for each side
/// // (with a slight variation in perspective to simulate the eye-to-eye distance).
/// render(left);
/// render(right);
/// #
/// # Ok(())
/// # }
/// #
/// # use ctru::services::gfx::Screen;
/// # use std::cell::RefMut;
/// # fn render(screen: RefMut<'_, dyn Screen>) {}
/// ```
impl<'screen> From<&'screen RefCell<TopScreen>> for TopScreen3D<'screen> { impl<'screen> From<&'screen RefCell<TopScreen>> for TopScreen3D<'screen> {
#[doc(alias = "gfxSet3D")] #[doc(alias = "gfxSet3D")]
fn from(top_screen: &'screen RefCell<TopScreen>) -> Self { fn from(top_screen: &'screen RefCell<TopScreen>) -> Self {

2
ctru-rs/src/services/gspgpu.rs

@ -22,7 +22,7 @@ pub enum Event {
} }
#[doc(alias = "GSPGPU_FramebufferFormat")] #[doc(alias = "GSPGPU_FramebufferFormat")]
/// Framebuffer formats supported by the 3DS. /// Framebuffer formats supported by the 3DS' screens.
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)] #[repr(u32)]
pub enum FramebufferFormat { pub enum FramebufferFormat {

Loading…
Cancel
Save