Crates.io | rusty-d3d12 |
lib.rs | rusty-d3d12 |
version | 0.5.2 |
source | src |
created_at | 2021-02-27 17:26:01.63816 |
updated_at | 2022-03-16 16:28:28.962985 |
description | Low-level D3D12 bindings for Rust. |
homepage | |
repository | https://github.com/curldivergence/rusty-d3d12 |
max_upload_size | |
id | 361463 |
size | 2,330,732 |
This project provides low-level bindings for D3D12 API. It utilizes rust-bindgen
for generating raw bindings (unlike d3d12-rs
crate), but aims for providing idiomatic APIs (unlike the raw D3D12 wrappers from winapi
or windows-rs
crates).
ID3D12*
interfaces and POD structs. The latter are marked as #[repr(transparent)]
so that they can be used as a drop-in replacement for the native types, but expose type-safe getters and setters. The setters have two forms: with_*(mut self, ...) -> Self
and set_*(&mut self, ...) -> &mut Self
and are intended for building new structures and modifying the existing ones, respectivelyD3D12
and DXGI
prefixes have been stripped from all types, functions and enum variants (e.g. this library exposes CommandListType::Direct
instead of D3D12_COMMAND_LIST_TYPE_DIRECT
) since it's very likely that people who use it already know the name of the API it wraps (it's mentioned in the crate name after all), and do not need to be constantly reminded about it :) Also all type and function names have been reshaped with respect to the official Rust code style (e.g. get_gpu_descriptor_handle_for_heap_start
instead of GetGPUDescriptorHandleForHeapStart
). Note that most, but not all the enum variant names have been converted yet, so some of them will be changed in future versionsheterogeneous_multiadapter.rs
for an example of exporting required symbols). Current SDK version is 1.600.10
pix
feature which is off by default not to introduce a dependency on WinPixEventRuntime.dll
for people who don't need it)Clone
and Drop
traits implementations with optional logging possibilities (e.g. see impl_com_object_refcount_named
macro)debug_callback
feature needs to be activated explicitly since ID3D12InfoQueue1
interface is only supported on Windows 11), object autonaming and GPU validationdx_call!
and dx_try!
)conversion_assist.py
scriptrusty-d3d12
are not marked as unsafe
since it pollutes client code while giving little in return: obviously, a lot of bad things can happen due to misusing D3D12, but guarding against something like that is a task for a high-level graphics library or engine. So unsafe
is reserved for something unsafe that happens on Rust side, e.g. accessing unions (see ClearValue::color()
)let debug_controller = Debug::new().expect("cannot create debug controller");
debug_controller.enable_debug_layer();
debug_controller.enable_gpu_based_validation();
debug_controller.enable_object_auto_name();
let rtv_heap = device
.create_descriptor_heap(
&DescriptorHeapDesc::default()
.with_heap_type(DescriptorHeapType::Rtv)
.with_num_descriptors(FRAMES_IN_FLIGHT),
)
.expect("Cannot create RTV heap");
rtv_heap
.set_name("RTV heap")
.expect("Cannot set RTV heap name");
let mut feature_data = FeatureDataOptions::default();
device
.check_feature_support(Feature::D3D12Options, &mut feature_data)
.expect("Cannot check feature support");
let cross_adapter_textures_supported = feature_data.cross_adapter_row_major_texture_supported();
let ms_bytecode = ShaderBytecode::new(&mesh_shader);
let ps_bytecode = ShaderBytecode::new(&pixel_shader);
let pso_subobjects_desc = MeshShaderPipelineStateDesc::default()
.with_root_signature(root_signature)
.with_ms_bytecode(&ms_bytecode)
.with_ps_bytecode(&ps_bytecode)
.with_rasterizer_state(
RasterizerDesc::default().with_depth_clip_enable(false),
)
.with_blend_state(BlendDesc::default())
.with_depth_stencil_state(
DepthStencilDesc::default().with_depth_enable(false),
)
.with_primitive_topology_type(PrimitiveTopologyType::Triangle)
.with_rtv_formats(&[Format::R8G8B8A8Unorm]);
let pso_desc = PipelineStateStreamDesc::default()
.with_pipeline_state_subobject_stream(
pso_subobjects_desc.as_byte_stream(),
);
let pso = device
.create_pipeline_state(&pso_desc)
.expect("Cannot create PSO");
Several runnable samples can be found in examples directory. Please note their code can be dirty and contains some (non-critical) bugs, so they should not be treated as sane D3D12 tutorials or high-quality Rust code examples since their purpose is just to showcase the API.
Currently implemented examples include:
The next planned goal for this project is to cover DXR APIs and provide the corresponding samples.
Currently the library is under active development, so breaking changes can happen between minor releases (but should not happen between patch releases). After publishing version 1.0
standard semantic versioning will be applied.
As mentioned above, the library is still a work-in-progress, so all contributions are welcome :)
If the type in question is already present in the pre-generated d3d12.rs
, you can use conversion_assist.py script to generate most (or sometimes all) of the code for you.
to generate a struct wrapper:
python tools/conversion_assist.py struct
pub struct
) and without impl blocks, e.g.:pub struct D3D12_ROOT_DESCRIPTOR1 {
pub ShaderRegister: UINT,
pub RegisterSpace: UINT,
pub Flags: D3D12_ROOT_DESCRIPTOR_FLAGS,
}
Enter
./// Wrapper around D3D12_ROOT_DESCRIPTOR1 structure
#[derive(Default, Debug, Hash, PartialOrd, Ord, PartialEq, Eq, Clone)]
#[repr(transparent)]
pub struct RootDescriptor(pub(crate) D3D12_ROOT_DESCRIPTOR1);
impl RootDescriptor {
pub fn set_shader_register(&mut self, shader_register: u32) -> &mut Self {
self.0.ShaderRegister = shader_register;
self
}
pub fn with_shader_register(mut self, shader_register: u32) -> Self {
self.set_shader_register(shader_register);
self
}
pub fn shader_register(&self) -> u32 {
self.0.ShaderRegister
}
pub fn set_register_space(&mut self, register_space: u32) -> &mut Self {
self.0.RegisterSpace = register_space;
self
}
pub fn with_register_space(mut self, register_space: u32) -> Self {
self.set_register_space(register_space);
self
}
pub fn register_space(&self) -> u32 {
self.0.RegisterSpace
}
pub fn set_flags(&mut self, flags: RootDescriptorFlags) -> &mut Self {
self.0.Flags = flags.bits();
self
}
pub fn with_flags(mut self, flags: RootDescriptorFlags) -> Self {
self.set_flags(flags);
self
}
pub fn flags(&self) -> RootDescriptorFlags {
unsafe { RootDescriptorFlags::from_bits_unchecked(self.0.Flags) }
}
}
D3D12_ROOT_DESCRIPTOR_FLAGS
was automatically changed to the correspondent wrapper RootDescriptorFlags
in the signatures of the getter and setters: this is possible since the script parses enum_wrappers.rs
for the already known types and tries to recognize them.PhantomData
's with lifetime specifiers (please see src/struct_wrappers.rs for examples).struct_wrappers.rs
and open a PR :)to generate enum wrapper:
python tools/conversion_assist.py enum
d3d12.rs
:pub const D3D12_DESCRIPTOR_RANGE_TYPE_D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
D3D12_DESCRIPTOR_RANGE_TYPE = 0;
pub const D3D12_DESCRIPTOR_RANGE_TYPE_D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
D3D12_DESCRIPTOR_RANGE_TYPE = 1;
pub const D3D12_DESCRIPTOR_RANGE_TYPE_D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
D3D12_DESCRIPTOR_RANGE_TYPE = 2;
pub const D3D12_DESCRIPTOR_RANGE_TYPE_D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
D3D12_DESCRIPTOR_RANGE_TYPE = 3;
pub type D3D12_DESCRIPTOR_RANGE_TYPE = ::std::os::raw::c_int;
rust-bindgen
duplicates enum name in each of the variants, so the script will ask you about the part you'd like to strip from the variants; in this case it's D3D12_DESCRIPTOR_RANGE_TYPE_D3D12_DESCRIPTOR_RANGE_TYPE_
if your enum variants are not exclusive (i.e. can be OR'ed together etc.), then follow the same procedure, but use python tools/conversion_assist.py flags
: the script will generate bitflags definition.
Unfortunately conversion_assist.py
doesn't support generating function definitions yet, so it should be done manually :( Please refer to lib.rs for examples.
If the required function or type is not yet present in the shipped d3d12.rs
(i.e. the new Agility SDK has come out but has not been integrated into rusty-d3d12
yet), then running rust-bindgen
on the workspace is required after updating Agility SDK.
When used as a Cargo dependency, rusty-d3d12
does not generate bindings during build process by default (besides increasing build times, running rust-bindgen
requires libclang.dll
, which can be absent on some systems, and cannot be vendored via crates.io
due to its large size). So as a prerequisite, Cargo should be able to find this DLL under the path set in LIBCLANG_PATH
environment variable. After this requirement is met, Cargo feature devel
can be activated, and d3d12_bindings.rs
and pix_bindings.rs
files will be generated from scratch, and included into src/raw_bindings/mod.rs
instead of the shipped ones. Of course, enabling this feature and copying libclang.dll
is not required if one doesn't need to update Agility SDK headers and just wants to wrap some APIs that are already present in the shipped d3d12.rs
but not yet covered by this library.
After generating the new raw bindings file (d3d12_bindings.rs
, please see the build script for details) using rust-bindgen
it should be copied from $OUT_DIR
to src/raw_bindings directory and renamed into d3d12.rs
.