Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📚Separate main() into its own function in lib.rs #5

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
/target
/Cargo.lock
.DS_Store
.vscode/launch.json
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just add the entire .vscode folder?

*.metallib
6 changes: 1 addition & 5 deletions bindings_generator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ fn main() {

bindgen::Builder::default()
.header(header)
.clang_args(&[
"-I./vendor/",
"-Wno-microsoft-enum-forward-reference"
])
.clang_args(&["-I./vendor/", "-Wno-microsoft-enum-forward-reference"])
.dynamic_link_require_all(true)
.dynamic_library_name("metal_irconverter")
.layout_tests(false)
Expand All @@ -28,7 +25,6 @@ fn main() {
.blocklist_item("__security_cookie")
.blocklist_item("__va_start")
.blocklist_item("__report_gsfailure")

// Not in the DLLs provided by Apple
.blocklist_item("IRMetalLibSynthesizeIntersectionWrapperFunction")
.generate()
Expand Down
154 changes: 148 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![doc = include_str!("../README.md")]

use std::path::Path;

struct IRCompilerOpaque;
struct IRObjectOpaque;
struct IRRootSignatureOpaque;
Expand Down Expand Up @@ -499,8 +501,6 @@ impl<'lib> IRRootSignature<'lib> {

let me = (funcs.create_from_descriptor)(desc, &mut error);

dbg!(error);

Ok(Self { funcs, me })
}
}
Expand Down Expand Up @@ -587,10 +587,6 @@ impl<'lib> IRCompiler<'lib> {
)
};

dbg!(v);

dbg!(error);

if error.is_null() {
Ok(IRObject {
funcs: input.funcs.clone(),
Expand All @@ -601,3 +597,149 @@ impl<'lib> IRCompiler<'lib> {
}
}
}

// Moved from main.rs to lib.rs
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this comment doesn't really add anything.

fn create_static_sampler(
min_mag_mip_mode: IRFilter,
address_mode: IRTextureAddressMode,
index: u32,
anisotropy: Option<u32>,
) -> IRStaticSamplerDescriptor {
let max_anisotropy = anisotropy.unwrap_or(1);

IRStaticSamplerDescriptor {
filter: min_mag_mip_mode,
address_u: address_mode,
address_v: address_mode,
address_w: address_mode,
mip_lod_bias: 0.0,
max_anisotropy: max_anisotropy,
comparison_func: IRComparisonFunction::IRComparisonFunctionNever,
min_lod: 0.0,
max_lod: 100000.0,
shader_register: index,
register_space: 0,
shader_visibility: IRShaderVisibility::IRShaderVisibilityAll,
border_color: IRStaticBorderColor::IRStaticBorderColorTransparentBlack,
}
}

/// Takes a DXIL binary, cross-compiles it to metal and returns a metallib binary
pub fn compile_dxil_to_metallib(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of this code should live in saxaboom, since it's specific to how breda sets up it's bindings.

path_compiler_lib: &Path,
dxil_binary: &Vec<u8>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clippy will probably complain that this should be a slice, instead of a borrow of a forcibly-owned Vec.

) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
unsafe {
// Load the metal shader converter library
let lib = libloading::Library::new(path_compiler_lib)?;

// Set up root signature. This should match up with the root signature as defined in breda
let parameters = {
let push_constants = IRRootParameter1 {
parameter_type: IRRootParameterType::IRRootParameterType32BitConstants,
shader_visibility: IRShaderVisibility::IRShaderVisibilityAll,
u: IRRootParameter1_u {
constants: IRRootConstants {
register_space: 0 as u32,
shader_register: 0,
num32_bit_values: 4, // debug has 6
},
},
};

let indirect_identifier = IRRootParameter1 {
parameter_type: IRRootParameterType::IRRootParameterType32BitConstants,
shader_visibility: IRShaderVisibility::IRShaderVisibilityAll,
u: IRRootParameter1_u {
constants: IRRootConstants {
register_space: 1 as u32,
shader_register: 0,
num32_bit_values: 1,
},
},
};

vec![push_constants, indirect_identifier]
};

let static_samplers = [
create_static_sampler(
IRFilter::IRFilterMinMagMipPoint,
IRTextureAddressMode::IRTextureAddressModeWrap,
0,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipPoint,
IRTextureAddressMode::IRTextureAddressModeClamp,
1,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipLinear,
IRTextureAddressMode::IRTextureAddressModeWrap,
2,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipLinear,
IRTextureAddressMode::IRTextureAddressModeClamp,
3,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipLinear,
IRTextureAddressMode::IRTextureAddressModeBorder,
4,
None,
),
create_static_sampler(
IRFilter::IRFilterAnisotropic,
IRTextureAddressMode::IRTextureAddressModeWrap,
5,
Some(2),
),
create_static_sampler(
IRFilter::IRFilterAnisotropic,
IRTextureAddressMode::IRTextureAddressModeWrap,
6,
Some(4),
),
];

let desc_1_1 = IRRootSignatureDescriptor1 {
flags: IRRootSignatureFlags::IRRootSignatureFlagCBVSRVUAVHeapDirectlyIndexed,
num_parameters: parameters.len() as u32,
p_parameters: parameters.as_ptr(),
num_static_samplers: static_samplers.len() as u32,
p_static_samplers: static_samplers.as_ptr(),
};

let desc = IRVersionedRootSignatureDescriptor {
version: IRRootSignatureVersion::IRRootSignatureVersion_1_1,
u: IRVersionedRootSignatureDescriptor_u { desc_1_1 },
};

let root_sig = IRRootSignature::create_from_descriptor(&lib, &desc)?;

// Cross-compile to Metal
let mut mtl_binary = IRMetalLibBinary::new(&lib)?;
let obj = IRObject::create_from_dxil(&lib, &dxil_binary)?;
let mut c = IRCompiler::new(&lib)?;
c.set_global_root_signature(&root_sig);
let mtllib = c.alloc_compile_and_link(&[b"main\0"], &obj)?;
mtllib.get_metal_lib_binary(IRShaderStage::IRShaderStageCompute, &mut mtl_binary);

Ok(mtl_binary.get_byte_code())
}
}

pub fn compile_dxil_to_metallib_from_path(
path_compiler_lib: &Path,
path_dxil: &Path,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
Comment on lines +737 to +740
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're turning these into public functions, they should have doc-comments.

// Load DXIL binary from path
let dxil_binary = std::fs::read(path_dxil)?;
Copy link
Member

@MarijnS95 MarijnS95 Oct 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're only reading a file into binary, let the user pass a byte slice. This would make it compatible with our asset pipeline that does not give you access to plain files.
I.e. there is no point to provide a "convenience _from_path() variant, only the byte-slice version suffices.

Perhaps the same for the compiler library itself. Even better: how expensive is it to load the compiler and interface for every shader? Perhaps we need to provide an object-based API of this sort:

let compiler = MetalCompiler::new("path/to/libirmetallibbinary.so")?; // TODO: Should there be a function with a sensible default path? Is it available on the system?

let _compiled = compiler.compile(&[0x13, 0x37, ...])?;

let metallib = compile_dxil_to_metallib(path_compiler_lib, &dxil_binary);
return metallib;
}
151 changes: 10 additions & 141 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,146 +1,15 @@
use saxaboom::{
IRComparisonFunction, IRCompiler, IRFilter, IRMetalLibBinary, IRObject, IRRootConstants,
IRRootDescriptor1, IRRootParameter1, IRRootParameter1_u, IRRootParameterType, IRRootSignature,
IRRootSignatureDescriptor1, IRRootSignatureFlags, IRRootSignatureVersion, IRShaderStage,
IRShaderVisibility, IRStaticBorderColor, IRStaticSamplerDescriptor, IRTextureAddressMode,
IRVersionedRootSignatureDescriptor, IRVersionedRootSignatureDescriptor_u,
};
use std::path::Path;

fn create_static_sampler(
min_mag_mip_mode: IRFilter,
address_mode: IRTextureAddressMode,
index: u32,
anisotropy: Option<u32>,
) -> IRStaticSamplerDescriptor {
let max_anisotropy = anisotropy.unwrap_or(1);
use saxaboom::compile_dxil_to_metallib_from_path;

IRStaticSamplerDescriptor {
filter: min_mag_mip_mode,
address_u: address_mode,
address_v: address_mode,
address_w: address_mode,
mip_lod_bias: 0.0,
max_anisotropy: max_anisotropy,
comparison_func: IRComparisonFunction::IRComparisonFunctionNever,
min_lod: 0.0,
max_lod: 100000.0,
shader_register: index,
register_space: 0,
shader_visibility: IRShaderVisibility::IRShaderVisibilityAll,
border_color: IRStaticBorderColor::IRStaticBorderColorTransparentBlack,
}
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
unsafe {
let lib = libloading::Library::new(
"C:/Program Files/Metal Shader Converter/lib/metalirconverter.dll",
)?;

let parameters = {
let push_constants = IRRootParameter1 {
parameter_type: IRRootParameterType::IRRootParameterType32BitConstants,
shader_visibility: IRShaderVisibility::IRShaderVisibilityAll,
u: IRRootParameter1_u {
constants: IRRootConstants {
register_space: 0 as u32,
shader_register: 0,
num32_bit_values: 4, // debug has 6
},
},
};

let indirect_identifier = IRRootParameter1 {
parameter_type: IRRootParameterType::IRRootParameterType32BitConstants,
shader_visibility: IRShaderVisibility::IRShaderVisibilityAll,
u: IRRootParameter1_u {
constants: IRRootConstants {
register_space: 1 as u32,
shader_register: 0,
num32_bit_values: 1,
},
},
};

vec![push_constants, indirect_identifier]
};

let static_samplers = [
create_static_sampler(
IRFilter::IRFilterMinMagMipPoint,
IRTextureAddressMode::IRTextureAddressModeWrap,
0,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipPoint,
IRTextureAddressMode::IRTextureAddressModeClamp,
1,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipLinear,
IRTextureAddressMode::IRTextureAddressModeWrap,
2,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipLinear,
IRTextureAddressMode::IRTextureAddressModeClamp,
3,
None,
),
create_static_sampler(
IRFilter::IRFilterMinMagMipLinear,
IRTextureAddressMode::IRTextureAddressModeBorder,
4,
None,
),
create_static_sampler(
IRFilter::IRFilterAnisotropic,
IRTextureAddressMode::IRTextureAddressModeWrap,
5,
Some(2),
),
create_static_sampler(
IRFilter::IRFilterAnisotropic,
IRTextureAddressMode::IRTextureAddressModeWrap,
6,
Some(4),
),
];

let desc_1_1 = IRRootSignatureDescriptor1 {
flags: IRRootSignatureFlags::IRRootSignatureFlagCBVSRVUAVHeapDirectlyIndexed,
num_parameters: parameters.len() as u32,
p_parameters: parameters.as_ptr(),
num_static_samplers: static_samplers.len() as u32,
p_static_samplers: static_samplers.as_ptr(),
};

let desc = IRVersionedRootSignatureDescriptor {
version: IRRootSignatureVersion::IRRootSignatureVersion_1_1,
u: IRVersionedRootSignatureDescriptor_u { desc_1_1 },
};

let root_sig = IRRootSignature::create_from_descriptor(&lib, &desc)?;

let egui_update = include_bytes!(
"C:/Users/Jasper/traverse/breda/crates/breda-egui/assets/shaders/egui_update.cs.dxil"
);
// let memcpy = include_bytes!("C:/Users/Jasper/traverse/breda/apps/cs-memcpy/assets/shaders/memcpy.cs.dxil");

let mut mtl_binary = IRMetalLibBinary::new(&lib)?;
fn main() {
let shaders_to_test = ["test/output.dxil"];

let obj = IRObject::create_from_dxil(&lib, egui_update)?;
let mut c = IRCompiler::new(&lib)?;
c.set_global_root_signature(&root_sig);
let mtllib = c.alloc_compile_and_link(&[b"main\0"], &obj)?;
dbg!(mtllib.get_type());
dbg!(mtllib.get_metal_ir_shader_stage());
mtllib.get_metal_lib_binary(IRShaderStage::IRShaderStageCompute, &mut mtl_binary);
dbg!(mtl_binary.get_byte_code().len());
std::fs::write("out.bin", mtl_binary.get_byte_code());
for shader_path in shaders_to_test {
print!("Testing shader \"{shader_path}\": ");
match compile_dxil_to_metallib_from_path(&Path::new("/usr/local/lib/libmetalirconverter.dylib"), &Path::new(shader_path)) {
Ok(_) => println!("\tOk."),
Err(e) => println!("Error: {e:?}"),
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's return anyhow::Result from fn main()?

}
Ok(())
}
Binary file added test/output.dxil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intended addition?

Binary file not shown.
Loading