Browse Source

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.
pull/10/head
Ian Chamberlain 2 years ago
parent
commit
02a9d40fdb
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 2
      Cargo.toml
  2. 7
      bindgen-citro3d/Cargo.toml
  3. 80
      bindgen-citro3d/src/main.rs
  4. 31
      citro3d-sys/bindgen.sh
  5. 166
      citro3d-sys/src/bindings.rs
  6. 18
      citro3d/examples/triangle.rs

2
Cargo.toml

@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["citro3d-sys", "citro3d"] members = ["citro3d-sys", "citro3d", "bindgen-citro3d"]
[patch."https://github.com/ian-h-chamberlain/citro3d-rs.git"] [patch."https://github.com/ian-h-chamberlain/citro3d-rs.git"]
citro3d-sys = { path = "citro3d-sys" } citro3d-sys = { path = "citro3d-sys" }

7
bindgen-citro3d/Cargo.toml

@ -0,0 +1,7 @@
[package]
name = "bindgen-citro3d"
version = "0.1.0"
edition = "2021"
[dependencies]
bindgen = "0.62.0"

80
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<ImplementsTrait> {
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
}
}
}

31
citro3d-sys/bindgen.sh

@ -2,33 +2,4 @@
set -euxo pipefail set -euxo pipefail
bindgen "$DEVKITPRO/libctru/include/tex3ds.h" \ cargo run --package bindgen-citro3d > src/bindings.rs
--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

166
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_IsCP_Any: u32 = 66846720;
pub const C3DF_LightEnv_LutDirtyAll: u32 = 4227858432; pub const C3DF_LightEnv_LutDirtyAll: u32 = 4227858432;
pub type __int64_t = ::libc::c_longlong; 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; pub type _LOCK_T = i32;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -105,21 +101,6 @@ pub struct __lock_t {
pub counter: u32, pub counter: u32,
} }
pub type _LOCK_RECURSIVE_T = __lock_t; 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 _off_t = __int64_t;
pub type _fpos_t = __int64_t; pub type _fpos_t = __int64_t;
pub type wint_t = ::libc::c_int; pub type wint_t = ::libc::c_int;
@ -135,14 +116,6 @@ pub union _mbstate_t__bindgen_ty_1 {
pub __wch: wint_t, pub __wch: wint_t,
pub __wchb: [::libc::c_uchar; 4usize], 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 __ULong = ::libc::c_ulong;
pub type _flock_t = _LOCK_RECURSIVE_T; pub type _flock_t = _LOCK_RECURSIVE_T;
#[repr(C)] #[repr(C)]
@ -323,145 +296,6 @@ pub struct _reent__bindgen_ty_1__bindgen_ty_2 {
pub _nextf: [*mut ::libc::c_uchar; 30usize], pub _nextf: [*mut ::libc::c_uchar; 30usize],
pub _nmalloc: [::libc::c_uint; 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_; pub type C3D_IVec = u32_;
#[doc = " @struct C3D_FVec"] #[doc = " @struct C3D_FVec"]
#[doc = " @brief Float vector"] #[doc = " @brief Float vector"]

18
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 // Get the location of the uniforms
let projection_name = CStr::from_bytes_with_nul(b"projection\0").unwrap(); 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, (*program.as_raw()).vertexShader,
projection_name.as_ptr(), 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 // Configure attributes for use with the vertex shader
let attr_info = citro3d_sys::C3D_GetAttrInfo(); let attr_info = citro3d_sys::C3D_GetAttrInfo();
citro3d_sys::AttrInfo_Init(attr_info); 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, 0, ctru_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, 1, ctru_sys::GPU_FLOAT, 3); // v1=color
// Compute the projection matrix // Compute the projection matrix
let projection = { 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 // 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) std::mem::size_of_val(&VERTICES)
.try_into() .try_into()
.expect("size fits in u32"), .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( citro3d_sys::C3D_TexEnvSrc(
env, env,
citro3d_sys::C3D_Both, citro3d_sys::C3D_Both,
citro3d_sys::GPU_PRIMARY_COLOR, ctru_sys::GPU_PRIMARY_COLOR,
0, 0,
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()) (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) { fn scene_render(uloc_projection: i32, projection: &C3D_Mtx) {
unsafe { unsafe {
// Update the uniforms // 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 // Draw the VBO
citro3d_sys::C3D_DrawArrays( citro3d_sys::C3D_DrawArrays(
citro3d_sys::GPU_TRIANGLES, ctru_sys::GPU_TRIANGLES,
0, 0,
VERTICES VERTICES
.len() .len()
@ -195,6 +195,6 @@ fn scene_render(uloc_projection: i32, projection: &C3D_Mtx) {
fn scene_exit(vbo_data: *mut libc::c_void) { fn scene_exit(vbo_data: *mut libc::c_void) {
unsafe { unsafe {
citro3d_sys::linearFree(vbo_data); ctru_sys::linearFree(vbo_data);
} }
} }

Loading…
Cancel
Save