mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
Merge #1
1: Initialize crate r=kvark a=msiglreith The crate is supposed to be a Rust wrapper around D3D12. Motivated by trying to hide the FFI behind a nicer to use layer (part of BAL). It aims at providing a zero-cost abstraction without any overhead at all (no transition costs between Rust structs and D3D12 structs or allocations). The API closely ressambles the d3d12 interfaces and is strucutered accordingly. It currently uses a custom `ComPtr` implementation which does not do any refcounting, therefore requires manual destruction when dropping. Co-authored-by: msiglreith <m.siglreith@gmail.com>
This commit is contained in:
commit
15f6f69725
8
Cargo.toml
Normal file
8
Cargo.toml
Normal 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"] }
|
@ -23,4 +23,4 @@ install:
|
|||||||
|
|
||||||
build: false
|
build: false
|
||||||
test_script:
|
test_script:
|
||||||
- C:\MinGW\bin\mingw32-make.exe all
|
- cargo check
|
||||||
|
98
src/com.rs
Normal file
98
src/com.rs
Normal 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
14
src/command_allocator.rs
Normal 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
218
src/command_list.rs
Normal 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
207
src/descriptor.rs
Normal 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
268
src/device.rs
Normal 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
74
src/lib.rs
Normal 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
164
src/pso.rs
Normal 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
15
src/query.rs
Normal 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
25
src/queue.rs
Normal 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
57
src/resource.rs
Normal 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
21
src/sync.rs
Normal 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) }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user