You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.8 KiB
102 lines
2.8 KiB
2 years ago
|
use std::marker::PhantomData;
|
||
2 years ago
|
use std::mem::MaybeUninit;
|
||
2 years ago
|
use std::ops::{Deref, DerefMut};
|
||
|
use std::sync::{LazyLock, RwLock};
|
||
|
|
||
|
use crate::attrib;
|
||
|
|
||
2 years ago
|
static BUF_INFO: LazyLock<RwLock<Info>> = LazyLock::new(|| {
|
||
2 years ago
|
let raw = unsafe {
|
||
|
let info = citro3d_sys::C3D_GetBufInfo();
|
||
|
citro3d_sys::BufInfo_Init(info);
|
||
|
info
|
||
|
};
|
||
|
|
||
2 years ago
|
RwLock::new(Info { raw })
|
||
2 years ago
|
});
|
||
|
|
||
2 years ago
|
/// Vertex attribute info. This struct can be used to
|
||
|
pub struct Info {
|
||
2 years ago
|
raw: *mut citro3d_sys::C3D_BufInfo,
|
||
|
}
|
||
|
|
||
|
// SAFETY: the RWLock ensures unique access when mutating the global struct, and
|
||
|
// we trust citro3d to Do The Right Thing™ and not mutate it otherwise.
|
||
2 years ago
|
unsafe impl Sync for Info {}
|
||
|
unsafe impl Send for Info {}
|
||
2 years ago
|
|
||
2 years ago
|
// TODO: is this a good name? It's more like a "handle" to the VBO data, or a slice.
|
||
|
#[derive(Debug, Clone, Copy)]
|
||
|
pub struct Index<'vbo> {
|
||
|
index: libc::c_int,
|
||
|
size: libc::c_int,
|
||
|
_data: PhantomData<&'vbo ()>,
|
||
|
}
|
||
|
|
||
|
impl Index<'_> {
|
||
|
pub fn as_raw(&self) -> libc::c_int {
|
||
|
self.index
|
||
|
}
|
||
|
|
||
|
pub fn size(&self) -> libc::c_int {
|
||
|
self.size
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[repr(u32)]
|
||
|
#[derive(Debug, Clone, Copy)]
|
||
|
pub enum Primitive {
|
||
|
Triangles = ctru_sys::GPU_TRIANGLES,
|
||
|
TriangleStrip = ctru_sys::GPU_TRIANGLE_STRIP,
|
||
|
TriangleFan = ctru_sys::GPU_TRIANGLE_FAN,
|
||
|
GeometryPrim = ctru_sys::GPU_GEOMETRY_PRIM,
|
||
|
}
|
||
|
|
||
2 years ago
|
impl Info {
|
||
2 years ago
|
/// Get a reference to the global buffer info.
|
||
|
pub fn get() -> crate::Result<impl Deref<Target = Self>> {
|
||
|
Ok(BUF_INFO.try_read()?)
|
||
|
}
|
||
|
|
||
|
/// Get a mutable reference to the global buffer info.
|
||
|
pub fn get_mut() -> crate::Result<impl DerefMut<Target = Self>> {
|
||
|
Ok(BUF_INFO.try_write()?)
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn add<'vbo, T>(
|
||
|
&mut self,
|
||
|
vbo_data: &'vbo [T],
|
||
2 years ago
|
attrib_info: &attrib::Info,
|
||
2 years ago
|
) -> crate::Result<Index<'vbo>> {
|
||
2 years ago
|
let stride = std::mem::size_of::<T>().try_into()?;
|
||
|
let attrib_count = attrib_info.count();
|
||
|
let permutation = attrib_info.permutation();
|
||
|
|
||
2 years ago
|
let res = unsafe {
|
||
2 years ago
|
citro3d_sys::BufInfo_Add(
|
||
|
self.raw,
|
||
|
vbo_data.as_ptr().cast(),
|
||
|
stride,
|
||
|
attrib_count,
|
||
|
permutation,
|
||
2 years ago
|
)
|
||
|
};
|
||
2 years ago
|
|
||
2 years ago
|
if res < 0 {
|
||
2 years ago
|
// 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)
|
||
|
// <https://github.com/devkitPro/citro3d/blob/master/source/buffers.c#L13-L17>
|
||
2 years ago
|
Err(crate::Error::System(res))
|
||
|
} else {
|
||
|
Ok(Index {
|
||
|
index: res,
|
||
|
size: vbo_data.len().try_into()?,
|
||
|
_data: PhantomData,
|
||
|
})
|
||
|
}
|
||
2 years ago
|
}
|
||
|
}
|