Setup crate structure and wrap first interface

This commit is contained in:
msiglreith 2018-08-26 12:53:16 +02:00
parent a0c95c9462
commit 4da4b1e908
12 changed files with 1169 additions and 0 deletions

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "d3d12-rs"
version = "0.1.0"
authors = ["msiglreith <m.siglreith@gmail.com>"]
[dependencies]
bitflags = "1"
winapi = { version = "0.3", features = ["d3d12","d3dcommon","d3dcompiler","dxgiformat","winerror"] }

98
src/com.rs Normal file
View File

@ -0,0 +1,98 @@
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::ptr;
use winapi::ctypes::c_void;
use winapi::um::unknwnbase::IUnknown;
use winapi::Interface;
use D3DResult;
#[repr(transparent)]
pub struct WeakPtr<T>(*mut T);
impl<T> WeakPtr<T> {
pub fn null() -> Self {
WeakPtr(ptr::null_mut())
}
pub fn is_null(&self) -> bool {
self.0.is_null()
}
pub fn as_ptr(&self) -> *const T {
self.0
}
pub fn as_mut_ptr(&self) -> *mut T {
self.0
}
pub unsafe fn mut_void(&mut self) -> *mut *mut c_void {
&mut self.0 as *mut *mut _ as *mut *mut _
}
}
impl<T: Interface> WeakPtr<T> {
pub unsafe fn as_unknown(&self) -> &IUnknown {
debug_assert!(!self.is_null());
&*(self.0 as *mut IUnknown)
}
// Cast creates a new WeakPtr requiring explicit destroy call.
pub unsafe fn cast<U>(&self) -> D3DResult<WeakPtr<U>>
where
U: Interface,
{
let mut obj = WeakPtr::<U>::null();
let hr = self
.as_unknown()
.QueryInterface(&U::uuidof(), obj.mut_void());
(obj, hr)
}
// Destroying one instance of the WeakPtr will invalidate all
// copies and clones.
pub unsafe fn destroy(&self) {
self.as_unknown().Release();
}
}
impl<T> Clone for WeakPtr<T> {
fn clone(&self) -> Self {
WeakPtr(self.0)
}
}
impl<T> Copy for WeakPtr<T> {}
impl<T> Deref for WeakPtr<T> {
type Target = T;
fn deref(&self) -> &T {
debug_assert!(!self.is_null());
unsafe { &*self.0 }
}
}
impl<T> fmt::Debug for WeakPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "WeakPtr( ptr: {:?} )", self.0)
}
}
impl<T> PartialEq<*mut T> for WeakPtr<T> {
fn eq(&self, other: &*mut T) -> bool {
self.0 == *other
}
}
impl<T> PartialEq for WeakPtr<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> Hash for WeakPtr<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}

14
src/command_allocator.rs Normal file
View File

@ -0,0 +1,14 @@
//! Command Allocator
use com::WeakPtr;
use winapi::um::d3d12;
pub type CommandAllocator = WeakPtr<d3d12::ID3D12CommandAllocator>;
impl CommandAllocator {
pub fn reset(&self) {
unsafe {
self.Reset();
}
}
}

218
src/command_list.rs Normal file
View File

@ -0,0 +1,218 @@
//! Graphics command list
use com::WeakPtr;
use resource::DiscardRegion;
use std::mem;
use winapi::um::d3d12;
use {
CommandAllocator, CpuDescriptor, DescriptorHeap, Format, GpuAddress, GpuDescriptor, IndexCount,
InstanceCount, PipelineState, Rect, Resource, RootSignature, VertexCount, VertexOffset,
WorkGroupCount, HRESULT,
};
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum CmdListType {
Direct = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT,
Bundle = d3d12::D3D12_COMMAND_LIST_TYPE_BUNDLE,
Compute = d3d12::D3D12_COMMAND_LIST_TYPE_COMPUTE,
Copy = d3d12::D3D12_COMMAND_LIST_TYPE_COPY,
// VideoDecode = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
// VideoProcess = d3d12::D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
}
bitflags! {
pub struct ClearFlags: u32 {
const DEPTH = d3d12::D3D12_CLEAR_FLAG_DEPTH;
const STENCIL = d3d12::D3D12_CLEAR_FLAG_STENCIL;
}
}
#[repr(transparent)]
pub struct IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC);
impl IndirectArgument {
pub fn draw() -> Self {
IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
..unsafe { mem::zeroed() }
})
}
pub fn draw_indexed() -> Self {
IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
..unsafe { mem::zeroed() }
})
}
pub fn dispatch() -> Self {
IndirectArgument(d3d12::D3D12_INDIRECT_ARGUMENT_DESC {
Type: d3d12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
..unsafe { mem::zeroed() }
})
}
// TODO: missing variants
}
pub type CommandSignature = WeakPtr<d3d12::ID3D12CommandSignature>;
pub type GraphicsCommandList = WeakPtr<d3d12::ID3D12GraphicsCommandList>;
impl GraphicsCommandList {
pub fn close(&self) -> HRESULT {
unsafe { self.Close() }
}
pub fn reset(&self, allocator: CommandAllocator, initial_pso: PipelineState) -> HRESULT {
unsafe { self.Reset(allocator.as_mut_ptr(), initial_pso.as_mut_ptr()) }
}
pub fn discard_resource(&self, resource: Resource, region: DiscardRegion) {
debug_assert!(region.subregions.start < region.subregions.end);
unsafe {
self.DiscardResource(
resource.as_mut_ptr(),
&d3d12::D3D12_DISCARD_REGION {
NumRects: region.rects.len() as _,
pRects: region.rects.as_ptr(),
FirstSubresource: region.subregions.start,
NumSubresources: region.subregions.end - region.subregions.start - 1,
},
);
}
}
pub fn clear_depth_stencil_view(
&self,
dsv: CpuDescriptor,
flags: ClearFlags,
depth: f32,
stencil: u8,
rects: &[Rect],
) {
unsafe {
self.ClearDepthStencilView(
dsv,
flags.bits(),
depth,
stencil,
rects.len() as _,
rects.as_ptr(),
);
}
}
pub fn dispatch(&self, count: WorkGroupCount) {
unsafe {
self.Dispatch(count[0], count[1], count[2]);
}
}
pub fn draw(
&self,
num_vertices: VertexCount,
num_instances: InstanceCount,
start_vertex: VertexCount,
start_instance: InstanceCount,
) {
unsafe {
self.DrawInstanced(num_vertices, num_instances, start_vertex, start_instance);
}
}
pub fn draw_indexed(
&self,
num_indices: IndexCount,
num_instances: InstanceCount,
start_index: IndexCount,
base_vertex: VertexOffset,
start_instance: InstanceCount,
) {
unsafe {
self.DrawIndexedInstanced(
num_indices,
num_instances,
start_index,
base_vertex,
start_instance,
);
}
}
pub fn set_index_buffer(&self, gpu_address: GpuAddress, size: u32, format: Format) {
let mut ibv = d3d12::D3D12_INDEX_BUFFER_VIEW {
BufferLocation: gpu_address,
SizeInBytes: size,
Format: format,
};
unsafe {
self.IASetIndexBuffer(&mut ibv);
}
}
pub fn set_blend_factor(&self, factor: [f32; 4]) {
unsafe {
self.OMSetBlendFactor(&factor);
}
}
pub fn set_stencil_reference(&self, reference: u32) {
unsafe {
self.OMSetStencilRef(reference);
}
}
pub fn set_pipeline_state(&self, pso: PipelineState) {
unsafe {
self.SetPipelineState(pso.as_mut_ptr());
}
}
pub fn execute_bundle(&self, bundle: GraphicsCommandList) {
unsafe {
self.ExecuteBundle(bundle.as_mut_ptr());
}
}
pub fn set_descriptor_heaps(&self, heaps: &[DescriptorHeap]) {
unsafe {
self.SetDescriptorHeaps(
heaps.len() as _,
heaps.as_ptr() as *mut &DescriptorHeap as *mut _,
);
}
}
pub fn set_compute_root_signature(&self, signature: RootSignature) {
unsafe {
self.SetComputeRootSignature(signature.as_mut_ptr());
}
}
pub fn set_graphics_root_signature(&self, signature: RootSignature) {
unsafe {
self.SetGraphicsRootSignature(signature.as_mut_ptr());
}
}
pub fn set_compute_root_descriptor_table(
&self,
root_index: u32,
base_descriptor: GpuDescriptor,
) {
unsafe {
self.SetComputeRootDescriptorTable(root_index, base_descriptor);
}
}
pub fn set_graphics_root_descriptor_table(
&self,
root_index: u32,
base_descriptor: GpuDescriptor,
) {
unsafe {
self.SetGraphicsRootDescriptorTable(root_index, base_descriptor);
}
}
}

207
src/descriptor.rs Normal file
View File

@ -0,0 +1,207 @@
use com::WeakPtr;
use std::mem;
use std::ops::Range;
use winapi::um::d3d12;
use {Blob, D3DResult, Error, TextureAddressMode};
pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE;
pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE;
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum HeapType {
CbvSrvUav = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
Sampler = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
Rtv = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
Dsv = d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
}
bitflags! {
pub struct HeapFlags: u32 {
const SHADER_VISIBLE = d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
}
}
pub type DescriptorHeap = WeakPtr<d3d12::ID3D12DescriptorHeap>;
impl DescriptorHeap {
pub fn start_cpu_descriptor(&self) -> CpuDescriptor {
unsafe { self.GetCPUDescriptorHandleForHeapStart() }
}
pub fn start_gpu_descriptor(&self) -> GpuDescriptor {
unsafe { self.GetGPUDescriptorHandleForHeapStart() }
}
}
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum ShaderVisibility {
All = d3d12::D3D12_SHADER_VISIBILITY_ALL,
VS = d3d12::D3D12_SHADER_VISIBILITY_VERTEX,
HS = d3d12::D3D12_SHADER_VISIBILITY_HULL,
DS = d3d12::D3D12_SHADER_VISIBILITY_DOMAIN,
GS = d3d12::D3D12_SHADER_VISIBILITY_GEOMETRY,
PS = d3d12::D3D12_SHADER_VISIBILITY_PIXEL,
}
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum DescriptorRangeType {
SRV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
UAV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
CBV = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
Sampler = d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
}
#[repr(transparent)]
pub struct DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE);
impl DescriptorRange {
pub fn new(
ty: DescriptorRangeType,
count: u32,
base_register: u32,
register_space: u32,
offset: u32,
) -> Self {
DescriptorRange(d3d12::D3D12_DESCRIPTOR_RANGE {
RangeType: ty as _,
NumDescriptors: count,
BaseShaderRegister: base_register,
RegisterSpace: register_space,
OffsetInDescriptorsFromTableStart: offset,
})
}
}
#[repr(transparent)]
pub struct RootParameter(d3d12::D3D12_ROOT_PARAMETER);
impl RootParameter {
// TODO: DescriptorRange must outlive Self
pub fn descriptor_table(visibility: ShaderVisibility, ranges: &[DescriptorRange]) -> Self {
let mut param = d3d12::D3D12_ROOT_PARAMETER {
ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
ShaderVisibility: visibility as _,
..unsafe { mem::zeroed() }
};
*unsafe { param.u.DescriptorTable_mut() } = d3d12::D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: ranges.len() as _,
pDescriptorRanges: ranges.as_ptr() as *const _,
};
RootParameter(param)
}
pub fn constants(
visibility: ShaderVisibility,
register: u32,
register_space: u32,
num: u32,
) -> Self {
let mut param = d3d12::D3D12_ROOT_PARAMETER {
ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
ShaderVisibility: visibility as _,
..unsafe { mem::zeroed() }
};
*unsafe { param.u.Constants_mut() } = d3d12::D3D12_ROOT_CONSTANTS {
ShaderRegister: register,
RegisterSpace: register_space,
Num32BitValues: num,
};
RootParameter(param)
}
}
#[repr(u32)]
pub enum StaticBorderColor {
TransparentBlack = d3d12::D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK,
OpaqueBlack = d3d12::D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,
OpaqueWhite = d3d12::D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,
}
#[repr(transparent)]
pub struct StaticSampler(d3d12::D3D12_STATIC_SAMPLER_DESC);
impl StaticSampler {
pub fn new(
visibility: ShaderVisibility,
register: u32,
register_space: u32,
filter: d3d12::D3D12_FILTER,
address_mode: TextureAddressMode,
mip_lod_bias: f32,
max_anisotropy: u32,
comparison_op: d3d12::D3D12_COMPARISON_FUNC,
border_color: StaticBorderColor,
lod: Range<f32>,
) -> Self {
StaticSampler(d3d12::D3D12_STATIC_SAMPLER_DESC {
Filter: filter,
AddressU: address_mode[0],
AddressV: address_mode[1],
AddressW: address_mode[2],
MipLODBias: mip_lod_bias,
MaxAnisotropy: max_anisotropy,
ComparisonFunc: comparison_op,
BorderColor: border_color as _,
MinLOD: lod.start,
MaxLOD: lod.end,
ShaderRegister: register,
RegisterSpace: register_space,
ShaderVisibility: visibility as _,
})
}
}
#[repr(u32)]
pub enum RootSignatureVersion {
V1_0 = d3d12::D3D_ROOT_SIGNATURE_VERSION_1_0,
V1_1 = d3d12::D3D_ROOT_SIGNATURE_VERSION_1_1,
}
bitflags! {
pub struct RootSignatureFlags: u32 {
const ALLOW_IA_INPUT_LAYOUT = d3d12::D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
const DENY_VS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS;
const DENY_HS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;
const DENY_DS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS;
const DENY_GS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
const DENY_PS_ROOT_ACCESS = d3d12::D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
}
}
pub type RootSignature = WeakPtr<d3d12::ID3D12RootSignature>;
impl RootSignature {
pub fn serialize(
version: RootSignatureVersion,
parameters: &[RootParameter],
static_samplers: &[StaticSampler],
flags: RootSignatureFlags,
) -> D3DResult<(Blob, Error)> {
let mut blob = Blob::null();
let mut error = Error::null();
let desc = d3d12::D3D12_ROOT_SIGNATURE_DESC {
NumParameters: parameters.len() as _,
pParameters: parameters.as_ptr() as *const _,
NumStaticSamplers: static_samplers.len() as _,
pStaticSamplers: static_samplers.as_ptr() as _,
Flags: flags.bits(),
};
let hr = unsafe {
d3d12::D3D12SerializeRootSignature(
&desc,
version as _,
blob.mut_void() as *mut *mut _,
error.mut_void() as *mut *mut _,
)
};
((blob, error), hr)
}
}

268
src/device.rs Normal file
View File

@ -0,0 +1,268 @@
//! Device
use com::WeakPtr;
use command_list::{CmdListType, CommandSignature, IndirectArgument};
use descriptor::{CpuDescriptor, HeapFlags, HeapType};
use std::ops::Range;
use winapi::um::d3d12;
use winapi::Interface;
use {pso, query, queue};
use {
Blob, CachedPSO, CommandAllocator, CommandQueue, D3DResult, DescriptorHeap, FeatureLevel,
GraphicsCommandList, NodeMask, PipelineState, QueryHeap, RootSignature, Shader,
TextureAddressMode,
};
pub type Device = WeakPtr<d3d12::ID3D12Device>;
impl Device {
pub fn create<I: Interface>(
adapter: WeakPtr<I>,
feature_level: FeatureLevel,
) -> D3DResult<Self> {
let mut device = Device::null();
let hr = unsafe {
d3d12::D3D12CreateDevice(
adapter.as_unknown() as *const _ as *mut _,
feature_level as _,
&d3d12::ID3D12Device::uuidof(),
device.mut_void(),
)
};
(device, hr)
}
pub fn create_command_allocator(&self, list_type: CmdListType) -> D3DResult<CommandAllocator> {
let mut allocator = CommandAllocator::null();
let hr = unsafe {
self.CreateCommandAllocator(
list_type as _,
&d3d12::ID3D12CommandAllocator::uuidof(),
allocator.mut_void(),
)
};
(allocator, hr)
}
pub fn create_command_queue(
&self,
list_type: CmdListType,
priority: queue::Priority,
flags: queue::CommandQueueFlags,
node_mask: NodeMask,
) -> D3DResult<CommandQueue> {
let desc = d3d12::D3D12_COMMAND_QUEUE_DESC {
Type: list_type as _,
Priority: priority as _,
Flags: flags.bits(),
NodeMask: node_mask,
};
let mut queue = CommandQueue::null();
let hr = unsafe {
self.CreateCommandQueue(
&desc,
&d3d12::ID3D12CommandQueue::uuidof(),
queue.mut_void(),
)
};
(queue, hr)
}
pub fn create_descriptor_heap(
&self,
num_descriptors: u32,
heap_type: HeapType,
flags: HeapFlags,
node_mask: NodeMask,
) -> D3DResult<DescriptorHeap> {
let desc = d3d12::D3D12_DESCRIPTOR_HEAP_DESC {
Type: heap_type as _,
NumDescriptors: num_descriptors,
Flags: flags.bits(),
NodeMask: node_mask,
};
let mut heap = DescriptorHeap::null();
let hr = unsafe {
self.CreateDescriptorHeap(
&desc,
&d3d12::ID3D12DescriptorHeap::uuidof(),
heap.mut_void(),
)
};
(heap, hr)
}
pub fn get_descriptor_increment_size(&self, heap_type: HeapType) -> u32 {
unsafe { self.GetDescriptorHandleIncrementSize(heap_type as _) }
}
pub fn create_graphics_command_list(
&self,
list_type: CmdListType,
allocator: CommandAllocator,
initial: PipelineState,
node_mask: NodeMask,
) -> D3DResult<GraphicsCommandList> {
let mut command_list = GraphicsCommandList::null();
let hr = unsafe {
self.CreateCommandList(
node_mask,
list_type as _,
allocator.as_mut_ptr(),
initial.as_mut_ptr(),
&d3d12::ID3D12GraphicsCommandList::uuidof(),
command_list.mut_void(),
)
};
(command_list, hr)
}
pub fn create_query_heap(
&self,
heap_ty: query::HeapType,
count: u32,
node_mask: NodeMask,
) -> D3DResult<QueryHeap> {
let desc = d3d12::D3D12_QUERY_HEAP_DESC {
Type: heap_ty as _,
Count: count,
NodeMask: node_mask,
};
let mut query_heap = QueryHeap::null();
let hr = unsafe {
self.CreateQueryHeap(
&desc,
&d3d12::ID3D12QueryHeap::uuidof(),
query_heap.mut_void(),
)
};
(query_heap, hr)
}
pub fn create_graphics_pipeline_state(
&self,
_root_signature: RootSignature,
_vs: Shader,
_ps: Shader,
_gs: Shader,
_hs: Shader,
_ds: Shader,
_node_mask: NodeMask,
_cached_pso: CachedPSO,
_flags: pso::PipelineStateFlags,
) -> D3DResult<PipelineState> {
unimplemented!()
}
pub fn create_compute_pipeline_state(
&self,
root_signature: RootSignature,
cs: Shader,
node_mask: NodeMask,
cached_pso: CachedPSO,
flags: pso::PipelineStateFlags,
) -> D3DResult<PipelineState> {
let mut pipeline = PipelineState::null();
let desc = d3d12::D3D12_COMPUTE_PIPELINE_STATE_DESC {
pRootSignature: root_signature.as_mut_ptr(),
CS: *cs,
NodeMask: node_mask,
CachedPSO: *cached_pso,
Flags: flags.bits(),
};
let hr = unsafe {
self.CreateComputePipelineState(
&desc,
&d3d12::ID3D12PipelineState::uuidof(),
pipeline.mut_void(),
)
};
(pipeline, hr)
}
pub fn create_sampler(
&self,
sampler: CpuDescriptor,
filter: d3d12::D3D12_FILTER,
address_mode: TextureAddressMode,
mip_lod_bias: f32,
max_anisotropy: u32,
comparison_op: d3d12::D3D12_COMPARISON_FUNC,
border_color: [f32; 4],
lod: Range<f32>,
) {
let desc = d3d12::D3D12_SAMPLER_DESC {
Filter: filter,
AddressU: address_mode[0],
AddressV: address_mode[1],
AddressW: address_mode[2],
MipLODBias: mip_lod_bias,
MaxAnisotropy: max_anisotropy,
ComparisonFunc: comparison_op,
BorderColor: border_color,
MinLOD: lod.start,
MaxLOD: lod.end,
};
unsafe {
self.CreateSampler(&desc, sampler);
}
}
pub fn create_root_signature(
&self,
blob: Blob,
node_mask: NodeMask,
) -> D3DResult<RootSignature> {
let mut signature = RootSignature::null();
let hr = unsafe {
self.CreateRootSignature(
node_mask,
blob.GetBufferPointer(),
blob.GetBufferSize(),
&d3d12::ID3D12RootSignature::uuidof(),
signature.mut_void(),
)
};
(signature, hr)
}
pub fn create_command_signature(
&self,
root_signature: RootSignature,
arguments: &[IndirectArgument],
stride: u32,
node_mask: NodeMask,
) -> D3DResult<CommandSignature> {
let mut signature = CommandSignature::null();
let desc = d3d12::D3D12_COMMAND_SIGNATURE_DESC {
ByteStride: stride,
NumArgumentDescs: arguments.len() as _,
pArgumentDescs: arguments.as_ptr() as *const _,
NodeMask: node_mask,
};
let hr = unsafe {
self.CreateCommandSignature(
&desc,
root_signature.as_mut_ptr(),
&d3d12::ID3D12RootSignature::uuidof(),
signature.mut_void(),
)
};
(signature, hr)
}
}

74
src/lib.rs Normal file
View File

@ -0,0 +1,74 @@
extern crate winapi;
#[macro_use]
extern crate bitflags;
use std::ffi::CStr;
use winapi::shared::dxgiformat;
use winapi::um::{d3d12, d3dcommon};
mod com;
pub mod command_allocator;
pub mod command_list;
pub mod descriptor;
pub mod device;
pub mod pso;
pub mod query;
pub mod queue;
pub mod resource;
pub mod sync;
pub use self::com::WeakPtr;
pub use self::command_allocator::CommandAllocator;
pub use self::command_list::{CommandSignature, GraphicsCommandList};
pub use self::descriptor::{CpuDescriptor, DescriptorHeap, GpuDescriptor, RootSignature};
pub use self::device::Device;
pub use self::pso::{CachedPSO, PipelineState, Shader};
pub use self::query::QueryHeap;
pub use self::queue::CommandQueue;
pub use self::resource::{Heap, Resource};
pub use self::sync::Fence;
pub use winapi::shared::winerror::HRESULT;
pub type D3DResult<T> = (T, HRESULT);
pub type GpuAddress = d3d12::D3D12_GPU_VIRTUAL_ADDRESS;
pub type Format = dxgiformat::DXGI_FORMAT;
pub type Rect = d3d12::D3D12_RECT;
pub type NodeMask = u32;
/// Draw vertex count.
pub type VertexCount = u32;
/// Draw vertex base offset.
pub type VertexOffset = i32;
/// Draw number of indices.
pub type IndexCount = u32;
/// Draw number of instances.
pub type InstanceCount = u32;
/// Number of work groups.
pub type WorkGroupCount = [u32; 3];
pub type TextureAddressMode = [d3d12::D3D12_TEXTURE_ADDRESS_MODE; 3];
#[repr(u32)]
pub enum FeatureLevel {
L9_1 = d3dcommon::D3D_FEATURE_LEVEL_9_1,
L9_2 = d3dcommon::D3D_FEATURE_LEVEL_9_2,
L9_3 = d3dcommon::D3D_FEATURE_LEVEL_9_3,
L10_0 = d3dcommon::D3D_FEATURE_LEVEL_10_0,
L10_1 = d3dcommon::D3D_FEATURE_LEVEL_10_1,
L11_0 = d3dcommon::D3D_FEATURE_LEVEL_11_0,
L11_1 = d3dcommon::D3D_FEATURE_LEVEL_11_1,
L12_0 = d3dcommon::D3D_FEATURE_LEVEL_12_0,
L12_1 = d3dcommon::D3D_FEATURE_LEVEL_12_1,
}
pub type Blob = self::com::WeakPtr<d3dcommon::ID3DBlob>;
pub type Error = self::com::WeakPtr<d3dcommon::ID3DBlob>;
impl Error {
pub unsafe fn as_c_str(&self) -> &CStr {
debug_assert!(!self.is_null());
let data = self.GetBufferPointer();
CStr::from_ptr(data as *const _ as *const _)
}
}

164
src/pso.rs Normal file
View File

@ -0,0 +1,164 @@
//! Pipeline state
use com::WeakPtr;
use std::ops::Deref;
use std::{ffi, ptr};
use winapi::um::{d3d12, d3dcompiler};
use {Blob, D3DResult, Error};
bitflags! {
pub struct PipelineStateFlags: u32 {
const TOOL_DEBUG = d3d12::D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG;
}
}
bitflags! {
pub struct ShaderCompileFlags: u32 {
const DEBUG = d3dcompiler::D3DCOMPILE_DEBUG;
const SKIP_VALIDATION = d3dcompiler::D3DCOMPILE_SKIP_VALIDATION;
const SKIP_OPTIMIZATION = d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION;
const PACK_MATRIX_ROW_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
const PACK_MATRIX_COLUMN_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR;
const PARTIAL_PRECISION = d3dcompiler::D3DCOMPILE_PARTIAL_PRECISION;
// TODO: add missing flags
}
}
#[derive(Copy, Clone)]
pub struct Shader(d3d12::D3D12_SHADER_BYTECODE);
impl Shader {
pub fn null() -> Self {
Shader(d3d12::D3D12_SHADER_BYTECODE {
BytecodeLength: 0,
pShaderBytecode: ptr::null(),
})
}
// `blob` may not be null.
pub fn from_blob(blob: Blob) -> Self {
Shader(d3d12::D3D12_SHADER_BYTECODE {
BytecodeLength: unsafe { blob.GetBufferSize() },
pShaderBytecode: unsafe { blob.GetBufferPointer() },
})
}
/// Compile a shader from raw HLSL.
///
/// * `target`: example format: `ps_5_1`.
pub fn compile(
code: &[u8],
target: &ffi::CStr,
entry: &ffi::CStr,
flags: ShaderCompileFlags,
) -> D3DResult<(Blob, Error)> {
let mut shader = Blob::null();
let mut error = Error::null();
let hr = unsafe {
d3dcompiler::D3DCompile(
code.as_ptr() as *const _,
code.len(),
ptr::null(), // defines
ptr::null(), // include
ptr::null_mut(),
entry.as_ptr() as *const _,
target.as_ptr() as *const _,
flags.bits(),
0,
shader.mut_void() as *mut *mut _,
error.mut_void() as *mut *mut _,
)
};
((shader, error), hr)
}
}
impl Deref for Shader {
type Target = d3d12::D3D12_SHADER_BYTECODE;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Option<Blob>> for Shader {
fn from(blob: Option<Blob>) -> Self {
match blob {
Some(b) => Shader::from_blob(b),
None => Shader::null(),
}
}
}
#[derive(Copy, Clone)]
pub struct CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE);
impl CachedPSO {
pub fn null() -> Self {
CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE {
CachedBlobSizeInBytes: 0,
pCachedBlob: ptr::null(),
})
}
// `blob` may not be null.
pub fn from_blob(blob: Blob) -> Self {
CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE {
CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() },
pCachedBlob: unsafe { blob.GetBufferPointer() },
})
}
}
impl Deref for CachedPSO {
type Target = d3d12::D3D12_CACHED_PIPELINE_STATE;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub type PipelineState = WeakPtr<d3d12::ID3D12PipelineState>;
#[repr(u32)]
pub enum Subobject {
RootSignature = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE,
VS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS,
PS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS,
DS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS,
HS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS,
GS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS,
CS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS,
StreamOutput = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT,
Blend = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND,
SampleMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK,
Rasterizer = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER,
DepthStencil = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL,
InputLayout = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT,
IBStripCut = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE,
PrimitiveTopology = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY,
RTFormats = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS,
DSFormat = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT,
SampleDesc = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC,
NodeMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK,
CachedPSO = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO,
Flags = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS,
DepthStencil1 = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1,
// ViewInstancing = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING,
}
/// Subobject of a pipeline stream description
#[repr(C)]
pub struct PipelineStateSubobject<T> {
subobject_align: [usize; 0], // Subobjects must have the same alignment as pointers.
subobject_type: d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE,
subobject: T,
}
impl<T> PipelineStateSubobject<T> {
pub fn new(subobject_type: Subobject, subobject: T) -> Self {
PipelineStateSubobject {
subobject_align: [],
subobject_type: subobject_type as _,
subobject,
}
}
}

15
src/query.rs Normal file
View File

@ -0,0 +1,15 @@
use com::WeakPtr;
use winapi::um::d3d12;
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum HeapType {
Occlusion = d3d12::D3D12_QUERY_HEAP_TYPE_OCCLUSION,
Timestamp = d3d12::D3D12_QUERY_HEAP_TYPE_TIMESTAMP,
PipelineStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS,
SOStatistics = d3d12::D3D12_QUERY_HEAP_TYPE_SO_STATISTICS,
// VideoDecodeStatistcs = d3d12::D3D12_QUERY_HEAP_TYPE_VIDEO_DECODE_STATISTICS,
// CopyQueueTimestamp = d3d12::D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP,
}
pub type QueryHeap = WeakPtr<d3d12::ID3D12QueryHeap>;

25
src/queue.rs Normal file
View File

@ -0,0 +1,25 @@
use com::WeakPtr;
use sync::Fence;
use winapi::um::d3d12;
use HRESULT;
#[repr(u32)]
pub enum Priority {
Normal = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
High = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_HIGH,
GlobalRealtime = d3d12::D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME,
}
bitflags! {
pub struct CommandQueueFlags: u32 {
const DISABLE_GPU_TIMEOUT = d3d12::D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT;
}
}
pub type CommandQueue = WeakPtr<d3d12::ID3D12CommandQueue>;
impl CommandQueue {
pub fn signal(&self, fence: Fence, value: u64) -> HRESULT {
unsafe { self.Signal(fence.as_mut_ptr(), value) }
}
}

57
src/resource.rs Normal file
View File

@ -0,0 +1,57 @@
//! GPU Resource
use com::WeakPtr;
use std::ops::Range;
use std::ptr;
use winapi::um::d3d12;
use {D3DResult, Rect};
pub type Subresource = u32;
pub struct DiscardRegion<'a> {
pub rects: &'a [Rect],
pub subregions: Range<Subresource>,
}
pub type Heap = WeakPtr<d3d12::ID3D12Heap>;
pub type Resource = WeakPtr<d3d12::ID3D12Resource>;
impl Resource {
///
pub fn map(
&self,
subresource: Subresource,
read_range: Option<Range<usize>>,
) -> D3DResult<*mut ()> {
let mut ptr = ptr::null_mut();
let read_range = read_range.map(|r| d3d12::D3D12_RANGE {
Begin: r.start,
End: r.end,
});
let read = match read_range {
Some(ref r) => r as *const _,
None => ptr::null(),
};
let hr = unsafe { self.Map(subresource, read, &mut ptr) };
(ptr as _, hr)
}
pub fn unmap(&self, subresource: Subresource, write_range: Option<Range<usize>>) {
let write_range = write_range.map(|r| d3d12::D3D12_RANGE {
Begin: r.start,
End: r.end,
});
let write = match write_range {
Some(ref r) => r as *const _,
None => ptr::null(),
};
unsafe { self.Unmap(subresource, write) };
}
pub fn gpu_virtual_address(&self) -> u64 {
unsafe { self.GetGPUVirtualAddress() }
}
}

21
src/sync.rs Normal file
View File

@ -0,0 +1,21 @@
use com::WeakPtr;
use winapi::um::d3d12;
use winapi::um::winnt;
use HRESULT;
pub type Event = winnt::HANDLE;
pub type Fence = WeakPtr<d3d12::ID3D12Fence>;
impl Fence {
pub fn set_event_on_completion(&self, event: Event, value: u64) -> HRESULT {
unsafe { self.SetEventOnCompletion(value, event) }
}
pub fn get_value(&self) -> u64 {
unsafe { self.GetCompletedValue() }
}
pub fn signal(&self, value: u64) -> HRESULT {
unsafe { self.Signal(value) }
}
}