From 1d35a44edea6eba62385fab58fae0ef6941949f3 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 16 Jul 2022 12:12:42 -0400 Subject: [PATCH] Add a screen member to render::Target This ensures the screen lives longer than the render target, and also makes it a little more convenient to get the color format. --- citro3d/examples/triangle.rs | 18 ++++++++-------- citro3d/src/lib.rs | 29 +++++-------------------- citro3d/src/render.rs | 42 ++++++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 49 deletions(-) diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index e46171c..8ec63a0 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -5,7 +5,7 @@ use ctru::services::apt::Apt; use ctru::services::hid::{Hid, KeyPad}; use ctru::services::soc::Soc; -use citro3d::render::{ClearFlags, ColorFormat, DepthFormat}; +use citro3d::render::{ClearFlags, DepthFormat}; use std::ffi::CStr; use std::mem::MaybeUninit; @@ -62,15 +62,15 @@ fn main() { let mut instance = citro3d::Instance::new().expect("failed to initialize Citro3D"); - let mut render_target = instance - .render_target_for_screen( - &frame_buffer, - ColorFormat::RGBA8, - DepthFormat::Depth24Stencil8, - ) - .expect("failed to create render target"); + let mut render_target = citro3d::render::Target::new( + frame_buffer.width, + frame_buffer.height, + &mut *top_screen, + DepthFormat::Depth24Stencil8, + ) + .expect("failed to create render target"); - render_target.set_output(&*top_screen, Side::Left); + render_target.set_output(Side::Left); let shader = shader::Library::from_bytes(SHADER_BYTES).unwrap(); let vertex_shader = shader.get(0).unwrap(); diff --git a/citro3d/src/lib.rs b/citro3d/src/lib.rs index 7d27f4f..dbd92ce 100644 --- a/citro3d/src/lib.rs +++ b/citro3d/src/lib.rs @@ -7,11 +7,9 @@ pub mod texture; pub mod vbo; use citro3d_sys::C3D_FrameDrawOn; -use ctru::gfx::RawFrameBuffer; +use ctru::gfx::Screen; pub use error::{Error, Result}; -use render::Target; - /// The single instance for using `citro3d`. This is the base type that an application /// should instantiate to use this library. #[non_exhaustive] @@ -41,32 +39,15 @@ impl Instance { } } - /// Create a default render target for the given screen. - /// - /// # Errors - /// - /// Fails if the render target could not be created. - pub fn render_target_for_screen( - &self, - frame_buffer: &RawFrameBuffer, - color_format: render::ColorFormat, - depth_format: render::DepthFormat, - ) -> Result { - let _ = self; - Target::new( - frame_buffer.width.into(), - frame_buffer.height.into(), - color_format, - depth_format, - ) - } - /// Select the given render target for drawing the frame. /// /// # Errors /// /// Fails if the given target cannot be used for drawing. - pub fn select_render_target(&mut self, target: &render::Target) -> Result<()> { + pub fn select_render_target<'s, S: Screen>( + &mut self, + target: &render::Target<'s, S>, + ) -> Result<()> { let _ = self; if unsafe { C3D_FrameDrawOn(target.as_raw()) } { Ok(()) diff --git a/citro3d/src/render.rs b/citro3d/src/render.rs index dcd7fa3..d92f284 100644 --- a/citro3d/src/render.rs +++ b/citro3d/src/render.rs @@ -5,7 +5,7 @@ use citro3d_sys::{ C3D_RenderTarget, C3D_RenderTargetCreate, C3D_RenderTargetDelete, C3D_DEPTHTYPE, GPU_COLORBUF, GPU_DEPTHBUF, }; -use ctru::gfx; +use ctru::gfx::{self, Screen}; use ctru::services::gspgpu::FramebufferFormat; use crate::{Error, Result}; @@ -14,12 +14,13 @@ mod transfer; /// A render target for `citro3d`. Frame data will be written to this target /// to be rendered on the GPU and displayed on the screen. -pub struct Target { +pub struct Target<'s, S> { raw: *mut citro3d_sys::C3D_RenderTarget, color_format: ColorFormat, + screen: &'s mut S, } -impl Drop for Target { +impl<'s, S> Drop for Target<'s, S> { fn drop(&mut self) { unsafe { C3D_RenderTargetDelete(self.raw); @@ -27,24 +28,28 @@ impl Drop for Target { } } -impl Target { +impl<'s, S> Target<'s, S> +where + S: 's + Screen, +{ /// Create a new render target with the specified size, color format, /// and depth format. /// /// # Errors /// - /// Fails if the specified sizes are invalid, or the target could not be - /// created. + /// Fails if the target could not be created. pub fn new( - width: u32, - height: u32, - color_format: ColorFormat, + width: u16, + height: u16, + screen: &'s mut S, depth_format: DepthFormat, ) -> Result { + let color_format = screen.get_framebuffer_format().into(); + let raw = unsafe { C3D_RenderTargetCreate( - width.try_into()?, - height.try_into()?, + width.into(), + height.into(), color_format as GPU_COLORBUF, depth_format.as_raw(), ) @@ -53,13 +58,18 @@ impl Target { if raw.is_null() { Err(Error::FailedToInitialize) } else { - Ok(Self { raw, color_format }) + Ok(Self { + raw, + color_format, + screen, + }) } } - /// Sets the screen to actually display the output of this render target. - pub fn set_output(&mut self, screen: &impl gfx::Screen, side: gfx::Side) { - let framebuf_format = screen.get_framebuffer_format(); + /// Sets the screen to actually display the output of this render target + /// on the given [`Side`](gfx::Side). + pub fn set_output(&mut self, side: gfx::Side) { + let framebuf_format = self.screen.get_framebuffer_format(); let flags = transfer::Flags::default() .in_format(self.color_format.into()) @@ -68,7 +78,7 @@ impl Target { unsafe { citro3d_sys::C3D_RenderTargetSetOutput( self.raw, - screen.as_raw(), + self.screen.as_raw(), side.into(), flags.bits(), );