From 02a9d40fdbc55de4969c3bcb5131bf36471a4f16 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Tue, 22 Nov 2022 19:14:36 -0500 Subject: [PATCH] Use bindgen library to generate bindings This allows us to use a custom callback for marking some types as Copy, which bindgen otherwise pessimistically assumes cannot. --- Cargo.toml | 2 +- bindgen-citro3d/Cargo.toml | 7 ++ bindgen-citro3d/src/main.rs | 80 +++++++++++++++++ citro3d-sys/bindgen.sh | 31 +------ citro3d-sys/src/bindings.rs | 166 ----------------------------------- citro3d/examples/triangle.rs | 18 ++-- 6 files changed, 98 insertions(+), 206 deletions(-) create mode 100644 bindgen-citro3d/Cargo.toml create mode 100644 bindgen-citro3d/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index e2d84ae..e22ce63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["citro3d-sys", "citro3d"] +members = ["citro3d-sys", "citro3d", "bindgen-citro3d"] [patch."https://github.com/ian-h-chamberlain/citro3d-rs.git"] citro3d-sys = { path = "citro3d-sys" } diff --git a/bindgen-citro3d/Cargo.toml b/bindgen-citro3d/Cargo.toml new file mode 100644 index 0000000..3231842 --- /dev/null +++ b/bindgen-citro3d/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "bindgen-citro3d" +version = "0.1.0" +edition = "2021" + +[dependencies] +bindgen = "0.62.0" diff --git a/bindgen-citro3d/src/main.rs b/bindgen-citro3d/src/main.rs new file mode 100644 index 0000000..6d1282b --- /dev/null +++ b/bindgen-citro3d/src/main.rs @@ -0,0 +1,80 @@ +use std::iter::FromIterator; +use std::path::PathBuf; + +use bindgen::callbacks::{DeriveTrait, ImplementsTrait, ParseCallbacks}; +use bindgen::{Builder, RustTarget}; + +fn main() { + let devkitpro = std::env::var("DEVKITPRO").expect("DEVKITPRO not set in environment"); + let devkitarm = std::env::var("DEVKITARM").expect("DEVKITARM not set in environment"); + + let include_path = PathBuf::from(devkitpro).join(PathBuf::from_iter(["libctru", "include"])); + let header = include_path.join("tex3ds.h"); + + let sysroot = PathBuf::from(devkitarm).join("arm-none-eabi"); + let system_include = sysroot.join("include"); + + let bindings = Builder::default() + .header(header.to_str().unwrap()) + .rust_target(RustTarget::Nightly) + .use_core() + .trust_clang_mangling(false) + .layout_tests(false) + .ctypes_prefix("::libc") + .prepend_enum_name(false) + .fit_macro_constants(true) + .raw_line("use ctru_sys::*;") + .must_use_type("Result") + // TODO functions,types,vars + .blocklist_type("u(8|16|32|64)") + .opaque_type("(GPU|GFX)_.*") + .opaque_type("float24Uniform_s") + .blocklist_file(".*/3ds/.*[.]h") + .allowlist_file(".*/c3d/.*[.]h") + .allowlist_file(".*/tex3ds[.]h") + .clang_args([ + "--target=arm-none-eabi", + "--sysroot", + sysroot.to_str().unwrap(), + "-isystem", + system_include.to_str().unwrap(), + "-I", + include_path.to_str().unwrap(), + "-mfloat-abi=hard", + "-march=armv6k", + "-mtune=mpcore", + "-mfpu=vfp", + "-DARM11 ", + "-D_3DS ", + "-D__3DS__ ", + ]) + .parse_callbacks(Box::new(CustomCallbacks)) + .generate() + .expect("Unable to generate bindings"); + + bindings + .write(Box::new(std::io::stdout())) + .expect("failed to write bindings"); +} + +#[derive(Debug)] +struct CustomCallbacks; + +impl ParseCallbacks for CustomCallbacks { + fn blocklisted_type_implements_trait( + &self, + name: &str, + derive_trait: DeriveTrait, + ) -> Option { + if let DeriveTrait::Copy | DeriveTrait::Debug = derive_trait { + match name { + "u64_" | "u32_" | "u16_" | "u8_" | "u64" | "u32" | "u16" | "u8" | "gfxScreen_t" + | "gfx3dSide_t" => Some(ImplementsTrait::Yes), + _ if name.starts_with("GPU_") => Some(ImplementsTrait::Yes), + _ => None, + } + } else { + None + } + } +} diff --git a/citro3d-sys/bindgen.sh b/citro3d-sys/bindgen.sh index ebede4c..ebb4ff9 100755 --- a/citro3d-sys/bindgen.sh +++ b/citro3d-sys/bindgen.sh @@ -2,33 +2,4 @@ set -euxo pipefail -bindgen "$DEVKITPRO/libctru/include/tex3ds.h" \ - --rust-target nightly \ - --use-core \ - --distrust-clang-mangling \ - --no-layout-tests \ - --ctypes-prefix "::libc" \ - --no-prepend-enum-name \ - --fit-macro-constant-types \ - --raw-line "use ctru_sys::*;" \ - --must-use-type "Result" \ - --generate "functions,types,vars" \ - --blocklist-type "u(8|16|32|64)" \ - --opaque-type "GPU_.*" \ - --opaque-type "GFX_.*" \ - --opaque-type "float24Uniform_s" \ - --allowlist-file ".*/c3d/.*[.]h" \ - --allowlist-file ".*/tex3ds[.]h" \ - -- \ - --target=arm-none-eabi \ - --sysroot=$DEVKITARM/arm-none-eabi \ - -isystem$DEVKITARM/arm-none-eabi/include \ - -I$DEVKITPRO/libctru/include \ - -mfloat-abi=hard \ - -march=armv6k \ - -mtune=mpcore \ - -mfpu=vfp \ - -DARM11 \ - -D_3DS \ - -D__3DS__ \ -> src/bindings.rs +cargo run --package bindgen-citro3d > src/bindings.rs diff --git a/citro3d-sys/src/bindings.rs b/citro3d-sys/src/bindings.rs index 0f750e1..c6fc58e 100644 --- a/citro3d-sys/src/bindings.rs +++ b/citro3d-sys/src/bindings.rs @@ -92,10 +92,6 @@ pub const C3D_DEFAULT_CMDBUF_SIZE: u32 = 262144; pub const C3DF_LightEnv_IsCP_Any: u32 = 66846720; pub const C3DF_LightEnv_LutDirtyAll: u32 = 4227858432; pub type __int64_t = ::libc::c_longlong; -pub type u8_ = u8; -pub type u16_ = u16; -pub type u32_ = u32; -pub type u64_ = u64; pub type _LOCK_T = i32; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -105,21 +101,6 @@ pub struct __lock_t { pub counter: u32, } pub type _LOCK_RECURSIVE_T = __lock_t; -#[doc = "< Top screen"] -pub const GFX_TOP: gfxScreen_t = 0; -#[doc = "< Bottom screen"] -pub const GFX_BOTTOM: gfxScreen_t = 1; -#[doc = " Screen IDs."] -pub type gfxScreen_t = ::libc::c_uint; -#[doc = "< Left eye framebuffer"] -pub const GFX_LEFT: gfx3dSide_t = 0; -#[doc = "< Right eye framebuffer"] -pub const GFX_RIGHT: gfx3dSide_t = 1; -#[doc = " @brief Top screen framebuffer side."] -#[doc = ""] -#[doc = " This is only meaningful when stereoscopic 3D is enabled on the top screen."] -#[doc = " In any other case, use \\ref GFX_LEFT."] -pub type gfx3dSide_t = ::libc::c_uint; pub type _off_t = __int64_t; pub type _fpos_t = __int64_t; pub type wint_t = ::libc::c_int; @@ -135,14 +116,6 @@ pub union _mbstate_t__bindgen_ty_1 { pub __wch: wint_t, pub __wchb: [::libc::c_uchar; 4usize], } -#[doc = " @brief Data callback"] -pub type decompressCallback = ::core::option::Option< - unsafe extern "C" fn( - userdata: *mut ::libc::c_void, - buffer: *mut ::libc::c_void, - size: usize, - ) -> isize, ->; pub type __ULong = ::libc::c_ulong; pub type _flock_t = _LOCK_RECURSIVE_T; #[repr(C)] @@ -323,145 +296,6 @@ pub struct _reent__bindgen_ty_1__bindgen_ty_2 { pub _nextf: [*mut ::libc::c_uchar; 30usize], pub _nmalloc: [::libc::c_uint; 30usize], } -#[doc = "< Vertex shader."] -pub const VERTEX_SHDR: DVLE_type = 0; -#[doc = "< Geometry shader."] -pub const GEOMETRY_SHDR: DVLE_type = 1; -#[doc = " DVLE type."] -pub type DVLE_type = ::libc::c_uint; -#[doc = "< Point processing mode."] -pub const GSH_POINT: DVLE_geoShaderMode = 0; -#[doc = "< Variable-size primitive processing mode."] -pub const GSH_VARIABLE_PRIM: DVLE_geoShaderMode = 1; -#[doc = "< Fixed-size primitive processing mode."] -pub const GSH_FIXED_PRIM: DVLE_geoShaderMode = 2; -#[doc = " Geometry shader operation modes."] -pub type DVLE_geoShaderMode = ::libc::c_uint; -#[doc = " DVLP data."] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DVLP_s { - #[doc = "< Code size."] - pub codeSize: u32_, - #[doc = "< Code data."] - pub codeData: *mut u32_, - #[doc = "< Operand description size."] - pub opdescSize: u32_, - #[doc = "< Operand description data."] - pub opcdescData: *mut u32_, -} -#[doc = " DVLE constant entry data."] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DVLE_constEntry_s { - #[doc = "< Constant type. See @ref DVLE_constantType"] - pub type_: u16_, - #[doc = "< Constant ID."] - pub id: u16_, - #[doc = "< Constant data."] - pub data: [u32_; 4usize], -} -#[doc = " DVLE output entry data."] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DVLE_outEntry_s { - #[doc = "< Output type. See @ref DVLE_outputAttribute_t"] - pub type_: u16_, - #[doc = "< Output register ID."] - pub regID: u16_, - #[doc = "< Output mask."] - pub mask: u8_, - #[doc = "< Unknown."] - pub unk: [u8_; 3usize], -} -#[doc = " DVLE uniform entry data."] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DVLE_uniformEntry_s { - #[doc = "< Symbol offset."] - pub symbolOffset: u32_, - #[doc = "< Start register."] - pub startReg: u16_, - #[doc = "< End register."] - pub endReg: u16_, -} -#[doc = " DVLE data."] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DVLE_s { - #[doc = "< DVLE type."] - pub type_: DVLE_type, - #[doc = "< true = merge vertex/geometry shader outmaps ('dummy' output attribute is present)."] - pub mergeOutmaps: bool, - #[doc = "< Geometry shader operation mode."] - pub gshMode: DVLE_geoShaderMode, - #[doc = "< Starting float uniform register number for storing the fixed-size primitive vertex array."] - pub gshFixedVtxStart: u8_, - #[doc = "< Number of fully-defined vertices in the variable-size primitive vertex array."] - pub gshVariableVtxNum: u8_, - #[doc = "< Number of vertices in the fixed-size primitive vertex array."] - pub gshFixedVtxNum: u8_, - #[doc = "< Contained DVLPs."] - pub dvlp: *mut DVLP_s, - #[doc = "< Offset of the start of the main function."] - pub mainOffset: u32_, - #[doc = "< Offset of the end of the main function."] - pub endmainOffset: u32_, - #[doc = "< Constant table size."] - pub constTableSize: u32_, - #[doc = "< Constant table data."] - pub constTableData: *mut DVLE_constEntry_s, - #[doc = "< Output table size."] - pub outTableSize: u32_, - #[doc = "< Output table data."] - pub outTableData: *mut DVLE_outEntry_s, - #[doc = "< Uniform table size."] - pub uniformTableSize: u32_, - #[doc = "< Uniform table data."] - pub uniformTableData: *mut DVLE_uniformEntry_s, - #[doc = "< Symbol table data."] - pub symbolTableData: *mut ::libc::c_char, - #[doc = "< Output map mask."] - pub outmapMask: u8_, - #[doc = "< Output map data."] - pub outmapData: [u32_; 8usize], - #[doc = "< Output map mode."] - pub outmapMode: u32_, - #[doc = "< Output map attribute clock."] - pub outmapClock: u32_, -} -#[doc = " Describes an instance of either a vertex or geometry shader."] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct shaderInstance_s { - #[doc = "< Shader DVLE."] - pub dvle: *mut DVLE_s, - #[doc = "< Boolean uniforms."] - pub boolUniforms: u16_, - #[doc = "< Used boolean uniform mask."] - pub boolUniformMask: u16_, - #[doc = "< Integer uniforms."] - pub intUniforms: [u32_; 4usize], - #[doc = "< 24-bit float uniforms."] - pub float24Uniforms: *mut float24Uniform_s, - #[doc = "< Used integer uniform mask."] - pub intUniformMask: u8_, - #[doc = "< Float uniform count."] - pub numFloat24Uniforms: u8_, -} -#[doc = " Describes an instance of a full shader program."] -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct shaderProgram_s { - #[doc = "< Vertex shader."] - pub vertexShader: *mut shaderInstance_s, - #[doc = "< Geometry shader."] - pub geometryShader: *mut shaderInstance_s, - #[doc = "< Geometry shader input permutation."] - pub geoShaderInputPermutation: [u32_; 2usize], - #[doc = "< Geometry shader input stride."] - pub geoShaderInputStride: u8_, -} pub type C3D_IVec = u32_; #[doc = " @struct C3D_FVec"] #[doc = " @brief Float vector"] diff --git a/citro3d/examples/triangle.rs b/citro3d/examples/triangle.rs index e46171c..099ccd7 100644 --- a/citro3d/examples/triangle.rs +++ b/citro3d/examples/triangle.rs @@ -108,7 +108,7 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) // Get the location of the uniforms let projection_name = CStr::from_bytes_with_nul(b"projection\0").unwrap(); - let uloc_projection = citro3d_sys::shaderInstanceGetUniformLocation( + let uloc_projection = ctru_sys::shaderInstanceGetUniformLocation( (*program.as_raw()).vertexShader, projection_name.as_ptr(), ); @@ -116,8 +116,8 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) // Configure attributes for use with the vertex shader let attr_info = citro3d_sys::C3D_GetAttrInfo(); citro3d_sys::AttrInfo_Init(attr_info); - citro3d_sys::AttrInfo_AddLoader(attr_info, 0, citro3d_sys::GPU_FLOAT, 3); // v0=position - citro3d_sys::AttrInfo_AddLoader(attr_info, 1, citro3d_sys::GPU_FLOAT, 3); // v1=color + citro3d_sys::AttrInfo_AddLoader(attr_info, 0, ctru_sys::GPU_FLOAT, 3); // v0=position + citro3d_sys::AttrInfo_AddLoader(attr_info, 1, ctru_sys::GPU_FLOAT, 3); // v1=color // Compute the projection matrix let projection = { @@ -137,7 +137,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( + let vbo_data: *mut Vertex = ctru_sys::linearAlloc( std::mem::size_of_val(&VERTICES) .try_into() .expect("size fits in u32"), @@ -166,11 +166,11 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) citro3d_sys::C3D_TexEnvSrc( env, citro3d_sys::C3D_Both, - citro3d_sys::GPU_PRIMARY_COLOR, + ctru_sys::GPU_PRIMARY_COLOR, 0, 0, ); - citro3d_sys::C3D_TexEnvFunc(env, citro3d_sys::C3D_Both, citro3d_sys::GPU_REPLACE); + citro3d_sys::C3D_TexEnvFunc(env, citro3d_sys::C3D_Both, ctru_sys::GPU_REPLACE); (uloc_projection, projection, vbo_data.cast()) } @@ -179,11 +179,11 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx, *mut libc::c_void) fn scene_render(uloc_projection: i32, projection: &C3D_Mtx) { unsafe { // Update the uniforms - citro3d_sys::C3D_FVUnifMtx4x4(citro3d_sys::GPU_VERTEX_SHADER, uloc_projection, projection); + citro3d_sys::C3D_FVUnifMtx4x4(ctru_sys::GPU_VERTEX_SHADER, uloc_projection, projection); // Draw the VBO citro3d_sys::C3D_DrawArrays( - citro3d_sys::GPU_TRIANGLES, + ctru_sys::GPU_TRIANGLES, 0, VERTICES .len() @@ -195,6 +195,6 @@ fn scene_render(uloc_projection: i32, projection: &C3D_Mtx) { fn scene_exit(vbo_data: *mut libc::c_void) { unsafe { - citro3d_sys::linearFree(vbo_data); + ctru_sys::linearFree(vbo_data); } }