Browse Source

Fixed Screen unsafety on VRAM

pull/137/head
Andrea Ciliberti 1 year ago
parent
commit
a84d2045f2
  1. 7
      ctru-rs/src/console.rs
  2. 81
      ctru-rs/src/services/gfx.rs
  3. 2
      ctru-rs/src/services/romfs.rs

7
ctru-rs/src/console.rs

@ -75,6 +75,11 @@ impl<'screen> Console<'screen> { @@ -75,6 +75,11 @@ impl<'screen> Console<'screen> {
///
/// [`Console`] automatically takes care of flushing and swapping buffers for its screen when printing.
///
/// # Panics
///
/// If the [`Gfx`](crate::services::gfx::Gfx) service was initialised via [`Gfx::with_formats_vram()`](crate::services::gfx::Gfx::with_formats_vram)
/// this function will crash the program with an ARM exception.
///
/// # Example
///
/// ```no_run
@ -84,7 +89,7 @@ impl<'screen> Console<'screen> { @@ -84,7 +89,7 @@ impl<'screen> Console<'screen> {
/// use ctru::services::gfx::Gfx;
/// use ctru::console::Console;
///
/// // Initialize graphics.
/// // Initialize graphics (using framebuffers allocated on the HEAP).
/// let gfx = Gfx::new()?;
///
/// // Create a `Console` that takes control of the upper LCD screen.

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

@ -37,10 +37,16 @@ pub trait Screen: private::Sealed { @@ -37,10 +37,16 @@ pub trait Screen: private::Sealed {
/// Returns the Screen side (left or right).
fn side(&self) -> Side;
/// Returns a [`RawFrameBuffer`] for the screen.
/// Returns a [`RawFrameBuffer`] for the screen (if the framebuffer was allocated on the HEAP).
///
/// Note that the pointer of the framebuffer returned by this function can
/// change after each call to this function if double buffering is enabled.
/// # Notes
///
/// The pointer of the framebuffer returned by this function can change after each call
/// to this function if double buffering is enabled, so it's suggested to NOT save it for later use.
///
/// # Panics
///
/// If the [`Gfx`] service was initialised via [`Gfx::with_formats_vram()`] this function will crash the program with an ARM exception.
#[doc(alias = "gfxGetFramebuffer")]
fn raw_framebuffer(&mut self) -> RawFrameBuffer {
let mut width: u16 = 0;
@ -251,7 +257,8 @@ impl Gfx { @@ -251,7 +257,8 @@ impl Gfx {
///
/// # Notes
///
/// It's the same as calling:
/// The new `Gfx` instance will allocate the needed framebuffers in the CPU-GPU shared memory region (to ensure compatibiltiy with all possible uses of the `Gfx` service).
/// As such, it's the same as calling:
///
/// ```no_run
/// # use std::error::Error;
@ -260,12 +267,14 @@ impl Gfx { @@ -260,12 +267,14 @@ impl Gfx {
/// # use ctru::services::gfx::Gfx;
/// # use ctru::services::gspgpu::FramebufferFormat;
/// #
/// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)?;
/// Gfx::with_formats_shared(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8)?;
/// #
/// # Ok(())
/// # }
/// ```
///
/// Have a look at [`Gfx::with_formats_vram()`] if you aren't interested in manipulating the framebuffers using the CPU.
///
/// # Example
///
/// ```no_run
@ -281,10 +290,10 @@ impl Gfx { @@ -281,10 +290,10 @@ impl Gfx {
/// ```
#[doc(alias = "gfxInit")]
pub fn new() -> Result<Self> {
Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
Gfx::with_formats_shared(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8)
}
/// 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 on the HEAP for the top and bottom screens.
///
/// Use [`Gfx::new()`] instead of this function to initialize the module with default parameters
///
@ -298,21 +307,71 @@ impl Gfx { @@ -298,21 +307,71 @@ impl Gfx {
///
/// // 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)?;
/// let gfx = Gfx::with_formats_shared(FramebufferFormat::Rgba8, FramebufferFormat::Rgb565)?;
/// #
/// # Ok(())
/// # }
/// ```
#[doc(alias = "gfxInit")]
pub fn with_formats_shared(
top_fb_fmt: FramebufferFormat,
bottom_fb_fmt: FramebufferFormat,
) -> Result<Self> {
let handler = ServiceReference::new(
&GFX_ACTIVE,
|| unsafe {
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), false);
Ok(())
},
|| unsafe { ctru_sys::gfxExit() },
)?;
Ok(Self {
top_screen: RefCell::new(TopScreen::new()),
bottom_screen: RefCell::new(BottomScreen),
_service_handler: handler,
})
}
/// Initialize a new service handle with the chosen framebuffer formats on the VRAM for the top and bottom screens.
///
/// # Notes
///
/// Though unsafe to do so, it's suggested to use VRAM buffers when working exclusively with the GPU,
/// since they result in faster performance and less memory waste.
///
/// # Safety
///
/// By initializing the [`Gfx`] service as such, all functionality that relies on CPU manipulation of the framebuffers will
/// be completely unavailable (usually resulting in an ARM panic if wrongly used).
///
/// Things such as [`Console`](crate::console::Console) and [`Screen::raw_framebuffer()`] will result in ARM exceptions.
///
/// # 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 in VRAM, so they will NOT be accessible from the CPU.
/// let gfx = unsafe { Gfx::with_formats_vram(FramebufferFormat::Rgba8, FramebufferFormat::Rgb565)? };
/// #
/// # Ok(())
/// # }
/// ```
#[doc(alias = "gfxInit")]
pub fn with_formats(
pub unsafe fn with_formats_vram(
top_fb_fmt: FramebufferFormat,
bottom_fb_fmt: FramebufferFormat,
use_vram_buffers: bool,
) -> Result<Self> {
let handler = ServiceReference::new(
&GFX_ACTIVE,
|| unsafe {
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers);
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), true);
Ok(())
},

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

@ -87,7 +87,7 @@ mod tests { @@ -87,7 +87,7 @@ mod tests {
fn romfs_lock() {
let romfs = RomFS::new().unwrap();
let _value = *ROMFS_ACTIVE.lock().unwrap();
let _value = *ROMFS_ACTIVE.try_lock().unwrap();
drop(romfs);
}

Loading…
Cancel
Save