From 5eaab0760a3df9daa29bd11062a944b8bc285ae7 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Fri, 2 Jun 2023 12:47:50 -0400 Subject: [PATCH] Add a ton more docs where missing --- citro3d/src/attrib.rs | 15 ++++++--- citro3d/src/buffer.rs | 65 +++++++++++++++++++++++++++--------- citro3d/src/error.rs | 7 +++- citro3d/src/lib.rs | 5 ++- citro3d/src/render.rs | 3 ++ citro3d/src/shader.rs | 16 ++++++--- citro3d/src/shader/macros.rs | 15 +++++---- citro3d/src/texture.rs | 1 - 8 files changed, 91 insertions(+), 36 deletions(-) delete mode 100644 citro3d/src/texture.rs diff --git a/citro3d/src/attrib.rs b/citro3d/src/attrib.rs index 176e46a..babdbbb 100644 --- a/citro3d/src/attrib.rs +++ b/citro3d/src/attrib.rs @@ -1,7 +1,14 @@ +//! Configure vertex attributes. +//! +//! This module has types and helpers for describing the shape/structure of vertex +//! data to be sent to the GPU. +//! +//! See the [`buffer`](crate::buffer) module to use the vertex data itself. + use std::mem::MaybeUninit; -/// Vertex attribute info. This struct is used to describe how vertex buffers are -/// used (i.e. the shape of the vertex data). +/// Vertex attribute info. This struct describes how vertex buffers are +/// layed out and used (i.e. the shape of the vertex data). #[derive(Debug)] pub struct Info(pub(crate) citro3d_sys::C3D_AttrInfo); @@ -82,14 +89,14 @@ impl Info { /// Add an attribute loader to the attribute info. The resulting attribute index /// indicates the registration order of the attributes. /// - /// ## Parameters + /// # Parameters /// /// * `register`: the shader program input register for this attribute. /// * `format`: the data format of this attribute. /// * `count`: the number of elements in each attribute (up to 4, corresponding /// to `xyzw` / `rgba` / `stpq`). /// - /// ## Errors + /// # Errors /// /// * If `count > 4` /// * If this attribute info already has the maximum number of attributes. diff --git a/citro3d/src/buffer.rs b/citro3d/src/buffer.rs index 0fd294d..8af071d 100644 --- a/citro3d/src/buffer.rs +++ b/citro3d/src/buffer.rs @@ -1,39 +1,64 @@ -use std::marker::PhantomData; +//! Configure vertex buffer objects to be sent to the GPU for rendering. +//! +//! See the [`attrib`] module for details on how to describe the shape and type +//! of the VBO data. + use std::mem::MaybeUninit; use crate::attrib; +/// Vertex buffer info. This struct is used to describe the shape of the buffer +/// data to be sent to the GPU for rendering. #[derive(Debug)] pub struct Info(pub(crate) citro3d_sys::C3D_BufInfo); +/// A slice of buffer data. This borrows the buffer data and can be thought of +/// as similar to `&[T]` obtained by slicing a `Vec`. #[derive(Debug, Clone, Copy)] pub struct Slice<'buf> { index: libc::c_int, size: libc::c_int, - _vbo_data: PhantomData<&'buf ()>, buf_info: &'buf Info, + // TODO: should we encapsulate the primitive here too, and require it when the + // slice is registered? Could there ever be a use case to draw different primitives + // using the same backing data??? } impl Slice<'_> { - pub fn as_raw(&self) -> libc::c_int { + /// Get the index into the buffer for this slice. + pub fn index(&self) -> libc::c_int { self.index } - pub fn size(&self) -> libc::c_int { + /// Get the length of the slice. + #[must_use] + pub fn len(&self) -> libc::c_int { self.size } + /// Return whether or not the slice has any elements. + pub fn is_empty(&self) -> bool { + self.len() <= 0 + } + + /// Get the buffer info this slice is associated with. pub fn info(&self) -> &Info { self.buf_info } } +/// The geometric primitive to draw (i.e. what shapes the buffer data describes). #[repr(u32)] #[derive(Debug, Clone, Copy)] pub enum Primitive { + /// Draw triangles (3 vertices per triangle). Triangles = ctru_sys::GPU_TRIANGLES, + /// Draw a triangle strip (each vertex shared by 1-3 triangles). TriangleStrip = ctru_sys::GPU_TRIANGLE_STRIP, + /// Draw a triangle fan (first vertex shared by all triangles). TriangleFan = ctru_sys::GPU_TRIANGLE_FAN, + /// Geometry primitive. Can be used for more complex use cases like geometry + /// shaders that output custom primitives. GeometryPrim = ctru_sys::GPU_GEOMETRY_PRIM, } @@ -49,6 +74,7 @@ impl Default for Info { } impl Info { + /// Construct buffer info without any registered data. pub fn new() -> Self { Self::default() } @@ -63,6 +89,18 @@ impl Info { } } + /// Register vertex buffer object data. The resulting [`Slice`] will have its + /// lifetime tied to both this [`Info`] and the passed-in VBO. `vbo_data` is + /// assumed to use one `T` per drawn primitive, and its layout is assumed to + /// match the given `attrib_info` + /// + /// # Errors + /// + /// Registering VBO data may fail: + /// + /// * if `vbo_data` is not allocated with the [`ctru::linear`] allocator + /// * if the maximum number (12) of VBOs are already registered + /// pub fn add<'this, 'vbo, 'idx, T>( &'this mut self, vbo_data: &'vbo [T], @@ -87,21 +125,16 @@ impl Info { ) }; - if res < 0 { - // TODO: should we convert to a more specific error if this fails? - // It looks like the common cases are - // - too many buffers already added (max 12) - // - physical memory address in the wrong place (this can be seen by - // using default allocator instead of LinearAllocator) - // - Err(crate::Error::System(res)) - } else { - Ok(Slice { + // Error codes from + match res { + -2 => Err(crate::Error::InvalidMemoryLocation), + -1 => Err(crate::Error::TooManyBuffers), + ..=0 => Err(crate::Error::System(res)), + _ => Ok(Slice { index: res, size: vbo_data.len().try_into()?, - _vbo_data: PhantomData, buf_info: self, - }) + }), } } } diff --git a/citro3d/src/error.rs b/citro3d/src/error.rs index 0f3791f..29acd73 100644 --- a/citro3d/src/error.rs +++ b/citro3d/src/error.rs @@ -24,8 +24,13 @@ pub enum Error { /// Indicates that a reference could not be obtained because a lock is already /// held on the requested object. LockHeld, - /// Indicates that too many vertex attributes were specified (max 12 supported). + /// Indicates that too many vertex attributes were registered (max 12 supported). TooManyAttributes, + /// Indicates that too many vertex buffer objects were registered (max 12 supported). + TooManyBuffers, + /// The given memory could not be converted to a physical address for sharing + /// with the GPU. Data should be allocated with [`ctru::linear`]. + InvalidMemoryLocation, } impl From for Error { diff --git a/citro3d/src/lib.rs b/citro3d/src/lib.rs index 77cc425..f3f79fd 100644 --- a/citro3d/src/lib.rs +++ b/citro3d/src/lib.rs @@ -5,7 +5,6 @@ pub mod buffer; pub mod error; pub mod render; pub mod shader; -pub mod texture; use citro3d_sys::C3D_FrameDrawOn; pub use error::{Error, Result}; @@ -110,8 +109,8 @@ impl Instance { unsafe { citro3d_sys::C3D_DrawArrays( primitive as ctru_sys::GPU_Primitive_t, - index.as_raw(), - index.size(), + index.index(), + index.len(), ); } } diff --git a/citro3d/src/render.rs b/citro3d/src/render.rs index 16bd48b..517f12f 100644 --- a/citro3d/src/render.rs +++ b/citro3d/src/render.rs @@ -96,8 +96,11 @@ impl<'screen> Target<'screen> { bitflags::bitflags! { /// Indicate whether color, depth buffer, or both values should be cleared. pub struct ClearFlags: u32 { + /// Clear the color of the render target. const COLOR = citro3d_sys::C3D_CLEAR_COLOR; + /// Clear the depth buffer value of the render target. const DEPTH = citro3d_sys::C3D_CLEAR_DEPTH; + /// Clear both color and depth buffer values of the render target. const ALL = citro3d_sys::C3D_CLEAR_ALL; } } diff --git a/citro3d/src/shader.rs b/citro3d/src/shader.rs index e962532..a1bd264 100644 --- a/citro3d/src/shader.rs +++ b/citro3d/src/shader.rs @@ -7,6 +7,9 @@ use std::error::Error; use std::mem::MaybeUninit; +// Macros get exported at the crate root, so no reason to document this module. +// It still needs to be `pub` for the helper struct it exports. +#[doc(hidden)] pub mod macros; /// A PICA200 shader program. It may have one or both of: @@ -110,11 +113,19 @@ impl Library { })) } + /// Get the number of [`Entrypoint`]s in this shader library. #[must_use] pub fn len(&self) -> usize { unsafe { (*self.0).numDVLE as usize } } + /// Whether the library has any [`Entrypoint`]s or not. + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get the [`Entrypoint`] at the given index, if present. #[must_use] pub fn get(&self, index: usize) -> Option { if index < self.len() { @@ -127,11 +138,6 @@ impl Library { } } - #[must_use] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - fn as_raw(&mut self) -> *mut ctru_sys::DVLB_s { self.0 } diff --git a/citro3d/src/shader/macros.rs b/citro3d/src/shader/macros.rs index 5a6fc2e..fb61eb5 100644 --- a/citro3d/src/shader/macros.rs +++ b/citro3d/src/shader/macros.rs @@ -1,9 +1,4 @@ -/// Helper struct to [`include_bytes`] aligned as a specific type. -#[repr(C)] // guarantee 'bytes' comes after '_align' -pub struct AlignedAs { - pub _align: [Align; 0], - pub bytes: Bytes, -} +//! Helper macros for working with shader data. /// Helper macro for including a file as bytes that are correctly aligned for /// use as a [`Library`](super::Library). @@ -22,3 +17,11 @@ macro_rules! include_aligned_bytes { &ALIGNED.bytes }}; } + +/// Helper struct to [`include_bytes`] aligned as a specific type. +#[repr(C)] // guarantee 'bytes' comes after '_align' +#[doc(hidden)] +pub struct AlignedAs { + pub _align: [Align; 0], + pub bytes: Bytes, +} diff --git a/citro3d/src/texture.rs b/citro3d/src/texture.rs deleted file mode 100644 index 8b13789..0000000 --- a/citro3d/src/texture.rs +++ /dev/null @@ -1 +0,0 @@ -