From 1d35a44edea6eba62385fab58fae0ef6941949f3 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 16 Jul 2022 12:12:42 -0400 Subject: [PATCH 01/10] 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(), ); From d8f3a24f054c5b430e97ddca94bf9c96d56ff2a7 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 16 Jul 2022 18:48:08 -0400 Subject: [PATCH 02/10] Render to the bottom screen in triangle example --- citro3d/examples/triangle.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index 8ec63a0..de28f6b 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -59,12 +59,13 @@ fn main() { let mut top_screen = gfx.top_screen.borrow_mut(); let frame_buffer = top_screen.get_raw_framebuffer(Side::Left); + let (width, height) = (frame_buffer.width, frame_buffer.height); let mut instance = citro3d::Instance::new().expect("failed to initialize Citro3D"); let mut render_target = citro3d::render::Target::new( - frame_buffer.width, - frame_buffer.height, + width, + height, &mut *top_screen, DepthFormat::Depth24Stencil8, ) @@ -72,6 +73,20 @@ fn main() { render_target.set_output(Side::Left); + let mut bottom_screen = gfx.bottom_screen.borrow_mut(); + let frame_buffer = bottom_screen.get_raw_framebuffer(); + let (width, height) = (frame_buffer.width, frame_buffer.height); + + let mut bottom_target = citro3d::render::Target::new( + width, + height, + &mut *bottom_screen, + DepthFormat::Depth24Stencil8, + ) + .expect("failed to create bottom screen render target"); + + bottom_target.set_output(Side::Left); + let shader = shader::Library::from_bytes(SHADER_BYTES).unwrap(); let vertex_shader = shader.get(0).unwrap(); @@ -87,13 +102,22 @@ fn main() { } instance.render_frame_with(|instance| { + instance + .select_render_target(&render_target) + .expect("failed to set render target"); + let clear_color: u32 = 0x7F_7F_7F_FF; render_target.clear(ClearFlags::ALL, clear_color, 0); + scene_render(uloc_projection.into(), &projection); + }); + instance.render_frame_with(|instance| { instance - .select_render_target(&render_target) + .select_render_target(&bottom_target) .expect("failed to set render target"); + let clear_color: u32 = 0x7F_7F_7F_FF; + bottom_target.clear(ClearFlags::ALL, clear_color, 0); scene_render(uloc_projection.into(), &projection); }); } From 5ffde47b8559e37b8297423e95920b84dce47b67 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 6 Aug 2022 23:37:30 -0400 Subject: [PATCH 03/10] Use RefMut and fix some lints --- citro3d/examples/triangle.rs | 25 ++++++++----------------- citro3d/src/render.rs | 12 +++++++----- citro3d/src/shader.rs | 2 +- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index de28f6b..42084c5 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, DepthFormat}; +use citro3d::render::ClearFlags; use std::ffi::CStr; use std::mem::MaybeUninit; @@ -29,7 +29,7 @@ struct Vertex { color: Vec3, } -const VERTICES: &[Vertex] = &[ +static VERTICES: &[Vertex] = &[ Vertex { pos: Vec3::new(0.0, 0.5, 0.5), color: Vec3::new(1.0, 0.0, 0.0), @@ -44,7 +44,7 @@ const VERTICES: &[Vertex] = &[ }, ]; -const SHADER_BYTES: &[u8] = +static SHADER_BYTES: &[u8] = include_aligned_bytes!(concat!(env!("OUT_DIR"), "/examples/assets/vshader.shbin")); fn main() { @@ -63,27 +63,18 @@ fn main() { let mut instance = citro3d::Instance::new().expect("failed to initialize Citro3D"); - let mut render_target = citro3d::render::Target::new( - width, - height, - &mut *top_screen, - DepthFormat::Depth24Stencil8, - ) - .expect("failed to create render target"); + let mut render_target = citro3d::render::Target::new(width, height, top_screen, None) + .expect("failed to create render target"); render_target.set_output(Side::Left); + render_target.set_output(Side::Right); let mut bottom_screen = gfx.bottom_screen.borrow_mut(); let frame_buffer = bottom_screen.get_raw_framebuffer(); let (width, height) = (frame_buffer.width, frame_buffer.height); - let mut bottom_target = citro3d::render::Target::new( - width, - height, - &mut *bottom_screen, - DepthFormat::Depth24Stencil8, - ) - .expect("failed to create bottom screen render target"); + let mut bottom_target = citro3d::render::Target::new(width, height, bottom_screen, None) + .expect("failed to create bottom screen render target"); bottom_target.set_output(Side::Left); diff --git a/citro3d/src/render.rs b/citro3d/src/render.rs index d92f284..a79b45f 100644 --- a/citro3d/src/render.rs +++ b/citro3d/src/render.rs @@ -1,6 +1,8 @@ //! This module provides render target types and options for controlling transfer //! of data to the GPU, including the format of color and depth data to be rendered. +use std::cell::RefMut; + use citro3d_sys::{ C3D_RenderTarget, C3D_RenderTargetCreate, C3D_RenderTargetDelete, C3D_DEPTHTYPE, GPU_COLORBUF, GPU_DEPTHBUF, @@ -17,7 +19,7 @@ mod transfer; pub struct Target<'s, S> { raw: *mut citro3d_sys::C3D_RenderTarget, color_format: ColorFormat, - screen: &'s mut S, + screen: RefMut<'s, S>, } impl<'s, S> Drop for Target<'s, S> { @@ -30,7 +32,7 @@ impl<'s, S> Drop for Target<'s, S> { impl<'s, S> Target<'s, S> where - S: 's + Screen, + S: Screen, { /// Create a new render target with the specified size, color format, /// and depth format. @@ -41,8 +43,8 @@ where pub fn new( width: u16, height: u16, - screen: &'s mut S, - depth_format: DepthFormat, + screen: RefMut<'s, S>, + depth_format: Option, ) -> Result { let color_format = screen.get_framebuffer_format().into(); @@ -51,7 +53,7 @@ where width.into(), height.into(), color_format as GPU_COLORBUF, - depth_format.as_raw(), + depth_format.map_or(C3D_DEPTHTYPE { __i: -1 }, DepthFormat::as_raw), ) }; diff --git a/citro3d/src/shader.rs b/citro3d/src/shader.rs index d66a924..329cf7f 100644 --- a/citro3d/src/shader.rs +++ b/citro3d/src/shader.rs @@ -74,7 +74,7 @@ impl Program { } } -impl<'vert, 'geom> Drop for Program { +impl Drop for Program { fn drop(&mut self) { unsafe { let _ = citro3d_sys::shaderProgramFree(self.as_raw()); From 4648c31467ef51f9c028c7e8f931c54d6a84a082 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 3 Sep 2022 11:26:25 -0400 Subject: [PATCH 04/10] Add inline detach render target fn --- citro3d-sys/src/renderqueue.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/citro3d-sys/src/renderqueue.rs b/citro3d-sys/src/renderqueue.rs index cb7050f..95a239a 100644 --- a/citro3d-sys/src/renderqueue.rs +++ b/citro3d-sys/src/renderqueue.rs @@ -1,11 +1,18 @@ //! Definitions from `` +use crate::*; + +#[inline] +pub unsafe fn C3D_RenderTargetDetachOutput(target: *mut C3D_RenderTarget) { + C3D_RenderTargetSetOutput(core::ptr::null_mut(), (*target).screen, (*target).side, 0); +} + #[inline] pub unsafe fn C3D_RenderTargetClear( - target: *mut crate::C3D_RenderTarget, - clearBits: crate::C3D_ClearBits, + target: *mut C3D_RenderTarget, + clearBits: C3D_ClearBits, clearColor: u32, clearDepth: u32, ) { - crate::C3D_FrameBufClear(&mut (*target).frameBuf, clearBits, clearColor, clearDepth); + C3D_FrameBufClear(&mut (*target).frameBuf, clearBits, clearColor, clearDepth); } From 894eb66806443cc626b1c31fe7d6cfe9dfef031c Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Wed, 23 Nov 2022 20:20:50 -0500 Subject: [PATCH 05/10] Update ctru-rs APIs based on split screen PR --- citro3d-sys/build.rs | 2 +- citro3d/Cargo.toml | 2 +- citro3d/examples/triangle.rs | 14 ++++------ citro3d/src/lib.rs | 6 +---- citro3d/src/render.rs | 51 ++++++++++++++++-------------------- 5 files changed, 30 insertions(+), 45 deletions(-) diff --git a/citro3d-sys/build.rs b/citro3d-sys/build.rs index ff80359..e865214 100644 --- a/citro3d-sys/build.rs +++ b/citro3d-sys/build.rs @@ -6,7 +6,7 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=DEVKITPRO"); - println!("cargo:rustc-link-search=native={}/libctru/lib", dkp_path); + println!("cargo:rustc-link-search=native={dkp_path}/libctru/lib"); println!( "cargo:rustc-link-lib=static={}", match debug_symbols.as_str() { diff --git a/citro3d/Cargo.toml b/citro3d/Cargo.toml index 8bdaf3f..34e418e 100644 --- a/citro3d/Cargo.toml +++ b/citro3d/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" bitflags = "1.3.2" bytemuck = { version = "1.10.0", features = ["extern_crate_std"] } citro3d-sys = { git = "https://github.com/ian-h-chamberlain/citro3d-rs.git" } -ctru-rs = { git = "https://github.com/Meziu/ctru-rs.git" } +ctru-rs = { git = "https://github.com/rust3ds/ctru-rs.git" } libc = "0.2.125" [dev-dependencies] diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index 42084c5..e23424a 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -1,16 +1,16 @@ +use citro3d::render::ClearFlags; use citro3d::{include_aligned_bytes, shader}; use citro3d_sys::C3D_Mtx; -use ctru::gfx::{Gfx, Side}; +use ctru::gfx::{Gfx, Screen}; use ctru::services::apt::Apt; use ctru::services::hid::{Hid, KeyPad}; use ctru::services::soc::Soc; -use citro3d::render::ClearFlags; - use std::ffi::CStr; use std::mem::MaybeUninit; #[repr(C)] +#[derive(Copy, Clone)] struct Vec3 { x: f32, y: f32, @@ -24,6 +24,7 @@ impl Vec3 { } #[repr(C)] +#[derive(Copy, Clone)] struct Vertex { pos: Vec3, color: Vec3, @@ -58,7 +59,7 @@ fn main() { let apt = Apt::init().expect("Couldn't obtain APT controller"); let mut top_screen = gfx.top_screen.borrow_mut(); - let frame_buffer = top_screen.get_raw_framebuffer(Side::Left); + let frame_buffer = top_screen.get_raw_framebuffer(); let (width, height) = (frame_buffer.width, frame_buffer.height); let mut instance = citro3d::Instance::new().expect("failed to initialize Citro3D"); @@ -66,9 +67,6 @@ fn main() { let mut render_target = citro3d::render::Target::new(width, height, top_screen, None) .expect("failed to create render target"); - render_target.set_output(Side::Left); - render_target.set_output(Side::Right); - let mut bottom_screen = gfx.bottom_screen.borrow_mut(); let frame_buffer = bottom_screen.get_raw_framebuffer(); let (width, height) = (frame_buffer.width, frame_buffer.height); @@ -76,8 +74,6 @@ fn main() { let mut bottom_target = citro3d::render::Target::new(width, height, bottom_screen, None) .expect("failed to create bottom screen render target"); - bottom_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 dbd92ce..fa66fc5 100644 --- a/citro3d/src/lib.rs +++ b/citro3d/src/lib.rs @@ -7,7 +7,6 @@ pub mod texture; pub mod vbo; use citro3d_sys::C3D_FrameDrawOn; -use ctru::gfx::Screen; pub use error::{Error, Result}; /// The single instance for using `citro3d`. This is the base type that an application @@ -44,10 +43,7 @@ impl Instance { /// # Errors /// /// Fails if the given target cannot be used for drawing. - pub fn select_render_target<'s, S: Screen>( - &mut self, - target: &render::Target<'s, S>, - ) -> Result<()> { + pub fn select_render_target(&mut self, target: &render::Target<'_>) -> Result<()> { let _ = self; if unsafe { C3D_FrameDrawOn(target.as_raw()) } { Ok(()) diff --git a/citro3d/src/render.rs b/citro3d/src/render.rs index a79b45f..a6fc9c9 100644 --- a/citro3d/src/render.rs +++ b/citro3d/src/render.rs @@ -7,7 +7,7 @@ use citro3d_sys::{ C3D_RenderTarget, C3D_RenderTargetCreate, C3D_RenderTargetDelete, C3D_DEPTHTYPE, GPU_COLORBUF, GPU_DEPTHBUF, }; -use ctru::gfx::{self, Screen}; +use ctru::gfx::Screen; use ctru::services::gspgpu::FramebufferFormat; use crate::{Error, Result}; @@ -16,13 +16,14 @@ 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<'s, S> { +pub struct Target<'screen> { raw: *mut citro3d_sys::C3D_RenderTarget, - color_format: ColorFormat, - screen: RefMut<'s, S>, + // This is unused after construction, but ensures unique access to the + // screen this target writes to during rendering + _screen: RefMut<'screen, dyn Screen>, } -impl<'s, S> Drop for Target<'s, S> { +impl Drop for Target<'_> { fn drop(&mut self) { unsafe { C3D_RenderTargetDelete(self.raw); @@ -30,10 +31,7 @@ impl<'s, S> Drop for Target<'s, S> { } } -impl<'s, S> Target<'s, S> -where - S: Screen, -{ +impl<'screen> Target<'screen> { /// Create a new render target with the specified size, color format, /// and depth format. /// @@ -43,10 +41,11 @@ where pub fn new( width: u16, height: u16, - screen: RefMut<'s, S>, + // TODO: is there a use case for a render target that isn't associated with a Screen? + screen: RefMut<'screen, dyn Screen>, depth_format: Option, ) -> Result { - let color_format = screen.get_framebuffer_format().into(); + let color_format: ColorFormat = screen.get_framebuffer_format().into(); let raw = unsafe { C3D_RenderTargetCreate( @@ -58,33 +57,27 @@ where }; if raw.is_null() { - Err(Error::FailedToInitialize) - } else { - Ok(Self { - raw, - color_format, - screen, - }) + return Err(Error::FailedToInitialize); } - } - - /// 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(); + // Set the render target to actually output to the given screen let flags = transfer::Flags::default() - .in_format(self.color_format.into()) - .out_format(ColorFormat::from(framebuf_format).into()); + .in_format(color_format.into()) + .out_format(color_format.into()); unsafe { citro3d_sys::C3D_RenderTargetSetOutput( - self.raw, - self.screen.as_raw(), - side.into(), + raw, + screen.as_raw(), + screen.side().into(), flags.bits(), ); } + + Ok(Self { + raw, + _screen: screen, + }) } /// Clear the render target with the given 32-bit RGBA color and depth buffer value. From 748e34e5f1df866cc10a18b4c16b43565383e7b1 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 27 Nov 2022 17:11:18 -0700 Subject: [PATCH 06/10] Minor example updates / address comments --- citro3d/examples/triangle.rs | 37 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index e23424a..332dfd4 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -1,4 +1,4 @@ -use citro3d::render::ClearFlags; +use citro3d::render::{ClearFlags, Target}; use citro3d::{include_aligned_bytes, shader}; use citro3d_sys::C3D_Mtx; use ctru::gfx::{Gfx, Screen}; @@ -64,7 +64,7 @@ fn main() { let mut instance = citro3d::Instance::new().expect("failed to initialize Citro3D"); - let mut render_target = citro3d::render::Target::new(width, height, top_screen, None) + let mut top_target = citro3d::render::Target::new(width, height, top_screen, None) .expect("failed to create render target"); let mut bottom_screen = gfx.bottom_screen.borrow_mut(); @@ -88,25 +88,20 @@ fn main() { break; } - instance.render_frame_with(|instance| { - instance - .select_render_target(&render_target) - .expect("failed to set render target"); - - let clear_color: u32 = 0x7F_7F_7F_FF; - render_target.clear(ClearFlags::ALL, clear_color, 0); - scene_render(uloc_projection.into(), &projection); - }); - - instance.render_frame_with(|instance| { - instance - .select_render_target(&bottom_target) - .expect("failed to set render target"); - - let clear_color: u32 = 0x7F_7F_7F_FF; - bottom_target.clear(ClearFlags::ALL, clear_color, 0); - scene_render(uloc_projection.into(), &projection); - }); + let mut render_to = |target: &mut Target| { + instance.render_frame_with(|instance| { + instance + .select_render_target(target) + .expect("failed to set render target"); + + let clear_color: u32 = 0x7F_7F_7F_FF; + target.clear(ClearFlags::ALL, clear_color, 0); + scene_render(uloc_projection.into(), &projection); + }); + }; + + render_to(&mut top_target); + render_to(&mut bottom_target); } scene_exit(vbo_data); From 824f817090c47fb5ab37cccc5d66bd4875835cf0 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 5 Feb 2023 20:21:07 -0500 Subject: [PATCH 07/10] Update old repo references to rust3ds instead --- Cargo.toml | 2 +- citro3d/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e2d84ae..334a0ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] members = ["citro3d-sys", "citro3d"] -[patch."https://github.com/ian-h-chamberlain/citro3d-rs.git"] +[patch."https://github.com/rust3ds/citro3d-rs.git"] citro3d-sys = { path = "citro3d-sys" } diff --git a/citro3d/Cargo.toml b/citro3d/Cargo.toml index 34e418e..c4ab668 100644 --- a/citro3d/Cargo.toml +++ b/citro3d/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitflags = "1.3.2" bytemuck = { version = "1.10.0", features = ["extern_crate_std"] } -citro3d-sys = { git = "https://github.com/ian-h-chamberlain/citro3d-rs.git" } +citro3d-sys = { git = "https://github.com/rust3ds/citro3d-rs.git" } ctru-rs = { git = "https://github.com/rust3ds/ctru-rs.git" } libc = "0.2.125" From f8e8542f922b9b2379224de6fe1c38226612b48f Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 5 Feb 2023 20:34:19 -0500 Subject: [PATCH 08/10] Minor fixes + clippy --- citro3d/examples/triangle.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index 332dfd4..a224b86 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -1,7 +1,7 @@ use citro3d::render::{ClearFlags, Target}; use citro3d::{include_aligned_bytes, shader}; use citro3d_sys::C3D_Mtx; -use ctru::gfx::{Gfx, Screen}; +use ctru::gfx::{Gfx, RawFrameBuffer, Screen}; use ctru::services::apt::Apt; use ctru::services::hid::{Hid, KeyPad}; use ctru::services::soc::Soc; @@ -59,8 +59,7 @@ fn main() { let apt = Apt::init().expect("Couldn't obtain APT controller"); let mut top_screen = gfx.top_screen.borrow_mut(); - let frame_buffer = top_screen.get_raw_framebuffer(); - let (width, height) = (frame_buffer.width, frame_buffer.height); + let RawFrameBuffer { width, height, .. } = top_screen.get_raw_framebuffer(); let mut instance = citro3d::Instance::new().expect("failed to initialize Citro3D"); @@ -68,8 +67,7 @@ fn main() { .expect("failed to create render target"); let mut bottom_screen = gfx.bottom_screen.borrow_mut(); - let frame_buffer = bottom_screen.get_raw_framebuffer(); - let (width, height) = (frame_buffer.width, frame_buffer.height); + let RawFrameBuffer { width, height, .. } = bottom_screen.get_raw_framebuffer(); let mut bottom_target = citro3d::render::Target::new(width, height, bottom_screen, None) .expect("failed to create bottom screen render target"); @@ -144,7 +142,7 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) // Create the vertex buffer object let vbo_data: *mut Vertex = citro3d_sys::linearAlloc( - std::mem::size_of_val(&VERTICES) + std::mem::size_of_val(VERTICES) .try_into() .expect("size fits in u32"), ) From 1f8c5b3bc78c620e11b5a79a2634ad9024fce257 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 5 Feb 2023 20:43:43 -0500 Subject: [PATCH 09/10] Convert VBO data to use `ctru::linear` allocator --- citro3d/examples/triangle.rs | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index 5d4c21c..f9c2522 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -1,3 +1,5 @@ +#![feature(allocator_api)] + use citro3d::render::{ClearFlags, Target}; use citro3d::{include_aligned_bytes, shader}; use citro3d_sys::C3D_Mtx; @@ -77,7 +79,10 @@ fn main() { let mut program = shader::Program::new(vertex_shader).unwrap(); - let (uloc_projection, projection, vbo_data) = scene_init(&mut program); + let mut vbo_data = Vec::with_capacity_in(VERTICES.len(), ctru::linear::LinearAllocator); + vbo_data.extend(VERTICES); + + let (uloc_projection, projection) = scene_init(&mut program, &vbo_data); while apt.main_loop() { hid.scan_input(); @@ -102,10 +107,13 @@ fn main() { render_to(&mut bottom_target); } - scene_exit(vbo_data); + // explicit drop to ensure the vbo_data lives long enough for the render code + // to reference it. This hopefully won't be necessary anymore if we can use + // lifetimes to manage the buffers instead of passing raw ptrs + drop(vbo_data); } -fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) { +fn scene_init(program: &mut shader::Program, vbo_data: &[Vertex]) -> (i8, C3D_Mtx) { // Load the vertex shader, create a shader program and bind it unsafe { citro3d_sys::C3D_BindProgram(program.as_raw()); @@ -140,22 +148,12 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) projection.assume_init() }; - // Create the vertex buffer object - let vbo_data: *mut Vertex = ctru_sys::linearAlloc( - std::mem::size_of_val(VERTICES) - .try_into() - .expect("size fits in u32"), - ) - .cast(); - - vbo_data.copy_from(VERTICES.as_ptr(), VERTICES.len()); - // Configure buffers let buf_info = citro3d_sys::C3D_GetBufInfo(); citro3d_sys::BufInfo_Init(buf_info); citro3d_sys::BufInfo_Add( buf_info, - vbo_data.cast(), + vbo_data.as_ptr().cast(), std::mem::size_of::() .try_into() .expect("size of vec3 fits in u32"), @@ -176,7 +174,7 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) ); citro3d_sys::C3D_TexEnvFunc(env, citro3d_sys::C3D_Both, ctru_sys::GPU_REPLACE); - (uloc_projection, projection, vbo_data.cast()) + (uloc_projection, projection) } } @@ -196,9 +194,3 @@ fn scene_render(uloc_projection: i32, projection: &C3D_Mtx) { ); } } - -fn scene_exit(vbo_data: *mut libc::c_void) { - unsafe { - ctru_sys::linearFree(vbo_data); - } -} From 3a2b3f4ffe04525d1ad73b0e3cf72fd877211c6d Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 11 Feb 2023 20:31:39 -0500 Subject: [PATCH 10/10] Address review comments --- citro3d/examples/triangle.rs | 7 +------ citro3d/src/render.rs | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index f9c2522..50831e0 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -80,7 +80,7 @@ fn main() { let mut program = shader::Program::new(vertex_shader).unwrap(); let mut vbo_data = Vec::with_capacity_in(VERTICES.len(), ctru::linear::LinearAllocator); - vbo_data.extend(VERTICES); + vbo_data.extend_from_slice(VERTICES); let (uloc_projection, projection) = scene_init(&mut program, &vbo_data); @@ -106,11 +106,6 @@ fn main() { render_to(&mut top_target); render_to(&mut bottom_target); } - - // explicit drop to ensure the vbo_data lives long enough for the render code - // to reference it. This hopefully won't be necessary anymore if we can use - // lifetimes to manage the buffers instead of passing raw ptrs - drop(vbo_data); } fn scene_init(program: &mut shader::Program, vbo_data: &[Vertex]) -> (i8, C3D_Mtx) { diff --git a/citro3d/src/render.rs b/citro3d/src/render.rs index 425258e..0a7a563 100644 --- a/citro3d/src/render.rs +++ b/citro3d/src/render.rs @@ -41,7 +41,6 @@ impl<'screen> Target<'screen> { pub fn new( width: u16, height: u16, - // TODO: is there a use case for a render target that isn't associated with a Screen? screen: RefMut<'screen, dyn Screen>, depth_format: Option, ) -> Result {