2020-11-20 04:29:57 +11:00
|
|
|
// Copyright © 2019 piet-gpu developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
use crate::dx12::error::{self, error_if_failed_else_unit, explain_error, Error};
|
2021-11-26 08:12:25 +11:00
|
|
|
use crate::MapMode;
|
2021-11-21 02:14:23 +11:00
|
|
|
use smallvec::SmallVec;
|
2021-04-30 15:06:13 +10:00
|
|
|
use std::convert::{TryFrom, TryInto};
|
|
|
|
use std::sync::atomic::{AtomicPtr, Ordering};
|
2021-10-22 10:08:27 +11:00
|
|
|
use std::{ffi, mem, ptr};
|
2021-11-10 15:28:06 +11:00
|
|
|
use winapi::shared::{dxgi, dxgi1_2, dxgi1_3, dxgi1_4, dxgiformat, dxgitype, minwindef, windef};
|
2020-11-20 04:29:57 +11:00
|
|
|
use winapi::um::d3dcommon::ID3DBlob;
|
2021-04-30 15:06:13 +10:00
|
|
|
use winapi::um::{
|
|
|
|
d3d12, d3d12sdklayers, d3dcommon, d3dcompiler, dxgidebug, handleapi, synchapi, winnt,
|
|
|
|
};
|
2020-11-20 04:29:57 +11:00
|
|
|
use winapi::Interface;
|
|
|
|
use wio::com::ComPtr;
|
|
|
|
|
|
|
|
// everything is ripped from d3d12-rs, but wio::com::ComPtr, and winapi are used more directly
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Heap(pub ComPtr<d3d12::ID3D12Heap>);
|
|
|
|
|
|
|
|
pub struct Resource {
|
2021-04-30 15:06:13 +10:00
|
|
|
// Note: the use of AtomicPtr is to support explicit destruction,
|
|
|
|
// similar to Vulkan.
|
|
|
|
ptr: AtomicPtr<d3d12::ID3D12Resource>,
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Adapter1(pub ComPtr<dxgi::IDXGIAdapter1>);
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Factory2(pub ComPtr<dxgi1_2::IDXGIFactory2>);
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Factory4(pub ComPtr<dxgi1_4::IDXGIFactory4>);
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SwapChain3(pub ComPtr<dxgi1_4::IDXGISwapChain3>);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Device(pub ComPtr<d3d12::ID3D12Device>);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct CommandQueue(pub ComPtr<d3d12::ID3D12CommandQueue>);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct CommandAllocator(pub ComPtr<d3d12::ID3D12CommandAllocator>);
|
|
|
|
|
|
|
|
pub type CpuDescriptor = d3d12::D3D12_CPU_DESCRIPTOR_HANDLE;
|
|
|
|
pub type GpuDescriptor = d3d12::D3D12_GPU_DESCRIPTOR_HANDLE;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2021-11-21 02:14:23 +11:00
|
|
|
pub struct DescriptorHeap(ComPtr<d3d12::ID3D12DescriptorHeap>);
|
2020-11-20 04:29:57 +11:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct RootSignature(pub ComPtr<d3d12::ID3D12RootSignature>);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct CommandSignature(pub ComPtr<d3d12::ID3D12CommandSignature>);
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct GraphicsCommandList(pub ComPtr<d3d12::ID3D12GraphicsCommandList>);
|
|
|
|
|
|
|
|
pub struct Event(pub winnt::HANDLE);
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Fence(pub ComPtr<d3d12::ID3D12Fence>);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct PipelineState(pub ComPtr<d3d12::ID3D12PipelineState>);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Blob(pub ComPtr<d3dcommon::ID3DBlob>);
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct ShaderByteCode {
|
|
|
|
pub bytecode: d3d12::D3D12_SHADER_BYTECODE,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct QueryHeap(pub ComPtr<d3d12::ID3D12QueryHeap>);
|
|
|
|
|
|
|
|
impl Resource {
|
2021-04-30 15:06:13 +10:00
|
|
|
pub unsafe fn new(ptr: *mut d3d12::ID3D12Resource) -> Resource {
|
2020-11-20 04:29:57 +11:00
|
|
|
Resource {
|
2021-04-30 15:06:13 +10:00
|
|
|
ptr: AtomicPtr::new(ptr),
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
pub fn get(&self) -> *const d3d12::ID3D12Resource {
|
2021-05-22 06:19:10 +10:00
|
|
|
self.get_mut()
|
2021-04-30 15:06:13 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_mut(&self) -> *mut d3d12::ID3D12Resource {
|
|
|
|
self.ptr.load(Ordering::Relaxed)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Safety: call only single-threaded.
|
|
|
|
pub unsafe fn destroy(&self) {
|
|
|
|
(*self.get()).Release();
|
|
|
|
self.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
|
2021-11-26 08:12:25 +11:00
|
|
|
pub unsafe fn map_buffer(
|
2021-05-25 08:38:31 +10:00
|
|
|
&self,
|
2021-11-26 08:12:25 +11:00
|
|
|
offset: u64,
|
|
|
|
size: u64,
|
|
|
|
mode: MapMode,
|
|
|
|
) -> Result<*mut u8, Error> {
|
2021-05-25 08:38:31 +10:00
|
|
|
let mut mapped_memory: *mut u8 = ptr::null_mut();
|
2021-11-26 08:12:25 +11:00
|
|
|
let (begin, end) = match mode {
|
|
|
|
MapMode::Read => (offset as usize, (offset + size) as usize),
|
|
|
|
MapMode::Write => (0, 0),
|
|
|
|
};
|
2021-05-25 08:38:31 +10:00
|
|
|
let range = d3d12::D3D12_RANGE {
|
2021-11-26 08:12:25 +11:00
|
|
|
Begin: begin,
|
|
|
|
End: end,
|
2021-05-25 08:38:31 +10:00
|
|
|
};
|
2021-04-30 15:06:13 +10:00
|
|
|
explain_error(
|
2021-11-26 08:12:25 +11:00
|
|
|
(*self.get()).Map(0, &range, &mut mapped_memory as *mut _ as *mut _),
|
2021-04-30 15:06:13 +10:00
|
|
|
"could not map GPU mem to CPU mem",
|
|
|
|
)?;
|
2021-11-26 08:12:25 +11:00
|
|
|
Ok(mapped_memory.add(offset as usize))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-11-26 08:12:25 +11:00
|
|
|
pub unsafe fn unmap_buffer(&self, offset: u64, size: u64, mode: MapMode) -> Result<(), Error> {
|
|
|
|
let (begin, end) = match mode {
|
|
|
|
MapMode::Read => (0, 0),
|
|
|
|
MapMode::Write => (offset as usize, (offset + size) as usize),
|
|
|
|
};
|
2021-04-30 15:06:13 +10:00
|
|
|
let range = d3d12::D3D12_RANGE {
|
2021-11-26 08:12:25 +11:00
|
|
|
Begin: begin,
|
|
|
|
End: end,
|
2020-11-20 04:29:57 +11:00
|
|
|
};
|
2021-11-26 08:12:25 +11:00
|
|
|
(*self.get()).Unmap(0, &range);
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
2021-04-30 15:06:13 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Resource {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
let ptr = self.get();
|
|
|
|
if !ptr.is_null() {
|
|
|
|
(*ptr).Release();
|
|
|
|
}
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
impl Clone for Resource {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
unsafe {
|
|
|
|
let ptr = self.get_mut();
|
|
|
|
(*ptr).AddRef();
|
|
|
|
Resource {
|
|
|
|
ptr: AtomicPtr::new(ptr),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
impl Factory4 {
|
|
|
|
pub unsafe fn create(flags: minwindef::UINT) -> Result<Factory4, Error> {
|
|
|
|
let mut factory = ptr::null_mut();
|
|
|
|
|
|
|
|
explain_error(
|
|
|
|
dxgi1_3::CreateDXGIFactory2(
|
|
|
|
flags,
|
|
|
|
&dxgi1_4::IDXGIFactory4::uuidof(),
|
|
|
|
&mut factory as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"error creating DXGI factory",
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(Factory4(ComPtr::from_raw(factory)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn enumerate_adapters(&self, id: u32) -> Result<Adapter1, Error> {
|
|
|
|
let mut adapter = ptr::null_mut();
|
|
|
|
error_if_failed_else_unit(self.0.EnumAdapters1(id, &mut adapter))?;
|
|
|
|
let mut desc = mem::zeroed();
|
|
|
|
(*adapter).GetDesc(&mut desc);
|
2021-11-12 06:48:58 +11:00
|
|
|
//println!("desc: {:?}", desc.Description);
|
2020-11-20 04:29:57 +11:00
|
|
|
Ok(Adapter1(ComPtr::from_raw(adapter)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_swapchain_for_hwnd(
|
|
|
|
&self,
|
2021-05-26 09:57:33 +10:00
|
|
|
command_queue: &CommandQueue,
|
2020-11-20 04:29:57 +11:00
|
|
|
hwnd: windef::HWND,
|
|
|
|
desc: dxgi1_2::DXGI_SWAP_CHAIN_DESC1,
|
2021-05-26 09:57:33 +10:00
|
|
|
) -> Result<SwapChain3, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut swap_chain = ptr::null_mut();
|
2021-05-26 09:57:33 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.CreateSwapChainForHwnd(
|
|
|
|
command_queue.0.as_raw() as *mut _,
|
|
|
|
hwnd,
|
|
|
|
&desc,
|
|
|
|
ptr::null(),
|
|
|
|
ptr::null_mut(),
|
|
|
|
&mut swap_chain as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"could not creation swapchain for hwnd",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-26 09:57:33 +10:00
|
|
|
Ok(SwapChain3(ComPtr::from_raw(swap_chain)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CommandQueue {
|
2021-04-30 15:06:13 +10:00
|
|
|
pub unsafe fn signal(&self, fence: &Fence, value: u64) -> Result<(), Error> {
|
|
|
|
explain_error(
|
|
|
|
self.0.Signal(fence.0.as_raw(), value),
|
|
|
|
"error setting signal",
|
|
|
|
)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
pub unsafe fn execute_command_lists(&self, command_lists: &[*mut d3d12::ID3D12CommandList]) {
|
|
|
|
let num_command_lists = command_lists.len().try_into().unwrap();
|
2020-11-20 04:29:57 +11:00
|
|
|
self.0
|
|
|
|
.ExecuteCommandLists(num_command_lists, command_lists.as_ptr());
|
|
|
|
}
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
pub unsafe fn get_timestamp_frequency(&self) -> Result<u64, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut result: u64 = 0;
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.GetTimestampFrequency(&mut result),
|
|
|
|
"could not get timestamp frequency",
|
2021-05-17 07:51:02 +10:00
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(result)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SwapChain3 {
|
|
|
|
pub unsafe fn get_buffer(&self, id: u32) -> Resource {
|
|
|
|
let mut resource = ptr::null_mut();
|
|
|
|
error::error_if_failed_else_unit(self.0.GetBuffer(
|
|
|
|
id,
|
|
|
|
&d3d12::ID3D12Resource::uuidof(),
|
|
|
|
&mut resource as *mut _ as *mut _,
|
|
|
|
))
|
|
|
|
.expect("SwapChain3 could not get buffer");
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
Resource::new(resource)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn get_current_back_buffer_index(&self) -> u32 {
|
|
|
|
self.0.GetCurrentBackBufferIndex()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn present(&self, interval: u32, flags: u32) -> Result<(), Error> {
|
|
|
|
error::error_if_failed_else_unit(self.0.Present1(
|
|
|
|
interval,
|
|
|
|
flags,
|
|
|
|
&dxgi1_2::DXGI_PRESENT_PARAMETERS { ..mem::zeroed() } as *const _,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Blob {
|
2021-11-12 06:48:58 +11:00
|
|
|
#[allow(unused)]
|
2021-05-17 07:51:02 +10:00
|
|
|
pub unsafe fn print_to_console(blob: &Blob) {
|
2020-11-20 04:29:57 +11:00
|
|
|
println!("==SHADER COMPILE MESSAGES==");
|
|
|
|
let message = {
|
|
|
|
let pointer = blob.0.GetBufferPointer();
|
|
|
|
let size = blob.0.GetBufferSize();
|
|
|
|
let slice = std::slice::from_raw_parts(pointer as *const u8, size as usize);
|
|
|
|
String::from_utf8_lossy(slice).into_owned()
|
|
|
|
};
|
|
|
|
println!("{}", message);
|
|
|
|
println!("===========================");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Device {
|
|
|
|
pub unsafe fn create_device(factory4: &Factory4) -> Result<Device, Error> {
|
|
|
|
let mut id = 0;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
// This always returns DXGI_ERROR_NOT_FOUND if no suitable adapter is found.
|
|
|
|
// Might be slightly more useful to retain the error from the attempt to create.
|
|
|
|
let adapter = factory4.enumerate_adapters(id)?;
|
|
|
|
|
|
|
|
if let Ok(device) =
|
|
|
|
Self::create_using_adapter(&adapter, d3dcommon::D3D_FEATURE_LEVEL_12_0)
|
|
|
|
{
|
|
|
|
return Ok(device);
|
|
|
|
}
|
|
|
|
id += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_using_adapter(
|
|
|
|
adapter: &Adapter1,
|
|
|
|
feature_level: d3dcommon::D3D_FEATURE_LEVEL,
|
|
|
|
) -> Result<Device, Error> {
|
|
|
|
let mut device = ptr::null_mut();
|
|
|
|
error_if_failed_else_unit(d3d12::D3D12CreateDevice(
|
|
|
|
adapter.0.as_raw() as *mut _,
|
|
|
|
feature_level,
|
|
|
|
&d3d12::ID3D12Device::uuidof(),
|
|
|
|
&mut device as *mut _ as *mut _,
|
|
|
|
))?;
|
|
|
|
|
|
|
|
Ok(Device(ComPtr::from_raw(device)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_command_allocator(
|
|
|
|
&self,
|
|
|
|
list_type: d3d12::D3D12_COMMAND_LIST_TYPE,
|
|
|
|
) -> Result<CommandAllocator, Error> {
|
|
|
|
let mut allocator = ptr::null_mut();
|
|
|
|
explain_error(
|
|
|
|
self.0.CreateCommandAllocator(
|
|
|
|
list_type,
|
|
|
|
&d3d12::ID3D12CommandAllocator::uuidof(),
|
|
|
|
&mut allocator as *mut _ as *mut _,
|
|
|
|
),
|
2021-04-30 15:06:13 +10:00
|
|
|
"device could not create command allocator",
|
2020-11-20 04:29:57 +11:00
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(CommandAllocator(ComPtr::from_raw(allocator)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_command_queue(
|
|
|
|
&self,
|
|
|
|
list_type: d3d12::D3D12_COMMAND_LIST_TYPE,
|
|
|
|
priority: minwindef::INT,
|
|
|
|
flags: d3d12::D3D12_COMMAND_QUEUE_FLAGS,
|
|
|
|
node_mask: minwindef::UINT,
|
|
|
|
) -> Result<CommandQueue, Error> {
|
|
|
|
let desc = d3d12::D3D12_COMMAND_QUEUE_DESC {
|
|
|
|
Type: list_type,
|
|
|
|
Priority: priority,
|
|
|
|
Flags: flags,
|
|
|
|
NodeMask: node_mask,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut cmd_q = ptr::null_mut();
|
|
|
|
explain_error(
|
|
|
|
self.0.CreateCommandQueue(
|
|
|
|
&desc,
|
|
|
|
&d3d12::ID3D12CommandQueue::uuidof(),
|
|
|
|
&mut cmd_q as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"device could not create command queue",
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(CommandQueue(ComPtr::from_raw(cmd_q)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_descriptor_heap(
|
|
|
|
&self,
|
|
|
|
heap_description: &d3d12::D3D12_DESCRIPTOR_HEAP_DESC,
|
2021-04-30 15:06:13 +10:00
|
|
|
) -> Result<DescriptorHeap, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut heap = ptr::null_mut();
|
2021-04-30 15:06:13 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.CreateDescriptorHeap(
|
|
|
|
heap_description,
|
|
|
|
&d3d12::ID3D12DescriptorHeap::uuidof(),
|
|
|
|
&mut heap as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"device could not create descriptor heap",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
Ok(DescriptorHeap(ComPtr::from_raw(heap)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn get_descriptor_increment_size(
|
|
|
|
&self,
|
|
|
|
heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
|
|
|
) -> u32 {
|
|
|
|
self.0.GetDescriptorHandleIncrementSize(heap_type)
|
|
|
|
}
|
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
pub unsafe fn copy_descriptors(
|
|
|
|
&self,
|
|
|
|
dst_starts: &[d3d12::D3D12_CPU_DESCRIPTOR_HANDLE],
|
|
|
|
dst_sizes: &[u32],
|
|
|
|
src_starts: &[d3d12::D3D12_CPU_DESCRIPTOR_HANDLE],
|
|
|
|
src_sizes: &[u32],
|
|
|
|
descriptor_heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
|
|
|
) {
|
|
|
|
debug_assert_eq!(dst_starts.len(), dst_sizes.len());
|
|
|
|
debug_assert_eq!(src_starts.len(), src_sizes.len());
|
|
|
|
debug_assert_eq!(
|
|
|
|
src_sizes.iter().copied().sum::<u32>(),
|
|
|
|
dst_sizes.iter().copied().sum()
|
|
|
|
);
|
|
|
|
self.0.CopyDescriptors(
|
|
|
|
dst_starts.len().try_into().unwrap(),
|
|
|
|
dst_starts.as_ptr(),
|
|
|
|
dst_sizes.as_ptr(),
|
|
|
|
src_starts.len().try_into().unwrap(),
|
|
|
|
src_starts.as_ptr(),
|
|
|
|
src_sizes.as_ptr(),
|
|
|
|
descriptor_heap_type,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-06-24 08:44:42 +10:00
|
|
|
pub unsafe fn copy_one_descriptor(
|
|
|
|
&self,
|
|
|
|
dst: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE,
|
|
|
|
src: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE,
|
|
|
|
descriptor_heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
|
|
|
|
) {
|
|
|
|
self.0
|
|
|
|
.CopyDescriptorsSimple(1, dst, src, descriptor_heap_type);
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
pub unsafe fn create_compute_pipeline_state(
|
|
|
|
&self,
|
|
|
|
compute_pipeline_desc: &d3d12::D3D12_COMPUTE_PIPELINE_STATE_DESC,
|
2021-04-30 15:06:13 +10:00
|
|
|
) -> Result<PipelineState, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut pipeline_state = ptr::null_mut();
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.CreateComputePipelineState(
|
|
|
|
compute_pipeline_desc as *const _,
|
|
|
|
&d3d12::ID3D12PipelineState::uuidof(),
|
|
|
|
&mut pipeline_state as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"device could not create compute pipeline state",
|
2021-05-17 07:51:02 +10:00
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(PipelineState(ComPtr::from_raw(pipeline_state)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_root_signature(
|
|
|
|
&self,
|
|
|
|
node_mask: minwindef::UINT,
|
|
|
|
blob: Blob,
|
2021-04-30 15:06:13 +10:00
|
|
|
) -> Result<RootSignature, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut signature = ptr::null_mut();
|
2021-05-17 07:51:02 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.CreateRootSignature(
|
|
|
|
node_mask,
|
|
|
|
blob.0.GetBufferPointer(),
|
|
|
|
blob.0.GetBufferSize(),
|
|
|
|
&d3d12::ID3D12RootSignature::uuidof(),
|
|
|
|
&mut signature as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"device could not create root signature",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(RootSignature(ComPtr::from_raw(signature)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_graphics_command_list(
|
|
|
|
&self,
|
|
|
|
list_type: d3d12::D3D12_COMMAND_LIST_TYPE,
|
2021-04-30 15:06:13 +10:00
|
|
|
allocator: &CommandAllocator,
|
|
|
|
initial_ps: Option<&PipelineState>,
|
2020-11-20 04:29:57 +11:00
|
|
|
node_mask: minwindef::UINT,
|
2021-04-30 15:06:13 +10:00
|
|
|
) -> Result<GraphicsCommandList, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut command_list = ptr::null_mut();
|
2021-04-30 15:06:13 +10:00
|
|
|
let p_initial_state = initial_ps.map(|p| p.0.as_raw()).unwrap_or(ptr::null_mut());
|
|
|
|
explain_error(
|
|
|
|
self.0.CreateCommandList(
|
|
|
|
node_mask,
|
|
|
|
list_type,
|
|
|
|
allocator.0.as_raw(),
|
|
|
|
p_initial_state,
|
|
|
|
&d3d12::ID3D12GraphicsCommandList::uuidof(),
|
|
|
|
&mut command_list as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"device could not create graphics command list",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(GraphicsCommandList(ComPtr::from_raw(command_list)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_byte_addressed_buffer_unordered_access_view(
|
|
|
|
&self,
|
2021-05-17 07:51:02 +10:00
|
|
|
resource: &Resource,
|
2020-11-20 04:29:57 +11:00
|
|
|
descriptor: CpuDescriptor,
|
|
|
|
first_element: u64,
|
|
|
|
num_elements: u32,
|
|
|
|
) {
|
|
|
|
// shouldn't flags be dxgiformat::DXGI_FORMAT_R32_TYPELESS?
|
|
|
|
let mut uav_desc = d3d12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
|
|
|
|
Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
|
|
|
|
ViewDimension: d3d12::D3D12_UAV_DIMENSION_BUFFER,
|
|
|
|
..mem::zeroed()
|
|
|
|
};
|
|
|
|
*uav_desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_UAV {
|
|
|
|
FirstElement: first_element,
|
|
|
|
NumElements: num_elements,
|
|
|
|
// shouldn't StructureByteStride be 0?
|
|
|
|
StructureByteStride: 0,
|
|
|
|
CounterOffsetInBytes: 0,
|
|
|
|
// shouldn't flags be d3d12::D3D12_BUFFER_UAV_FLAG_RAW?
|
|
|
|
Flags: d3d12::D3D12_BUFFER_UAV_FLAG_RAW,
|
|
|
|
};
|
2021-04-30 15:06:13 +10:00
|
|
|
self.0
|
|
|
|
.CreateUnorderedAccessView(resource.get_mut(), ptr::null_mut(), &uav_desc, descriptor)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_unordered_access_view(
|
|
|
|
&self,
|
2021-05-17 07:51:02 +10:00
|
|
|
resource: &Resource,
|
2020-11-20 04:29:57 +11:00
|
|
|
descriptor: CpuDescriptor,
|
|
|
|
) {
|
|
|
|
self.0.CreateUnorderedAccessView(
|
2021-04-30 15:06:13 +10:00
|
|
|
resource.get_mut(),
|
2020-11-20 04:29:57 +11:00
|
|
|
ptr::null_mut(),
|
|
|
|
ptr::null(),
|
|
|
|
descriptor,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_fence(&self, initial: u64) -> Result<Fence, Error> {
|
|
|
|
let mut fence = ptr::null_mut();
|
2021-04-30 15:06:13 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.CreateFence(
|
|
|
|
initial,
|
|
|
|
d3d12::D3D12_FENCE_FLAG_NONE,
|
|
|
|
&d3d12::ID3D12Fence::uuidof(),
|
|
|
|
&mut fence as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"device could not create fence",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
|
|
|
Ok(Fence(ComPtr::from_raw(fence)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_committed_resource(
|
|
|
|
&self,
|
|
|
|
heap_properties: &d3d12::D3D12_HEAP_PROPERTIES,
|
|
|
|
flags: d3d12::D3D12_HEAP_FLAGS,
|
|
|
|
resource_description: &d3d12::D3D12_RESOURCE_DESC,
|
|
|
|
initial_resource_state: d3d12::D3D12_RESOURCE_STATES,
|
|
|
|
optimized_clear_value: *const d3d12::D3D12_CLEAR_VALUE,
|
|
|
|
) -> Result<Resource, Error> {
|
|
|
|
let mut resource = ptr::null_mut();
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.CreateCommittedResource(
|
|
|
|
heap_properties as *const _,
|
|
|
|
flags,
|
|
|
|
resource_description as *const _,
|
|
|
|
initial_resource_state,
|
|
|
|
optimized_clear_value,
|
|
|
|
&d3d12::ID3D12Resource::uuidof(),
|
|
|
|
&mut resource as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"device could not create committed resource",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(Resource::new(resource))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_query_heap(
|
|
|
|
&self,
|
|
|
|
heap_type: d3d12::D3D12_QUERY_HEAP_TYPE,
|
|
|
|
num_expected_queries: u32,
|
2021-05-22 06:19:10 +10:00
|
|
|
) -> Result<QueryHeap, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let query_heap_desc = d3d12::D3D12_QUERY_HEAP_DESC {
|
|
|
|
Type: heap_type,
|
|
|
|
Count: num_expected_queries,
|
|
|
|
NodeMask: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut query_heap = ptr::null_mut();
|
|
|
|
|
2021-05-22 06:19:10 +10:00
|
|
|
explain_error(
|
|
|
|
self.0.CreateQueryHeap(
|
|
|
|
&query_heap_desc as *const _,
|
|
|
|
&d3d12::ID3D12QueryHeap::uuidof(),
|
|
|
|
&mut query_heap as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"could not create query heap",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-22 06:19:10 +10:00
|
|
|
Ok(QueryHeap(ComPtr::from_raw(query_heap)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-22 15:03:42 +10:00
|
|
|
pub unsafe fn create_buffer(
|
2020-11-20 04:29:57 +11:00
|
|
|
&self,
|
2021-11-21 02:14:23 +11:00
|
|
|
buffer_size_in_bytes: u64,
|
2021-05-22 15:03:42 +10:00
|
|
|
heap_type: d3d12::D3D12_HEAP_TYPE,
|
|
|
|
cpu_page: d3d12::D3D12_CPU_PAGE_PROPERTY,
|
|
|
|
memory_pool_preference: d3d12::D3D12_MEMORY_POOL,
|
|
|
|
init_resource_state: d3d12::D3D12_RESOURCE_STATES,
|
|
|
|
resource_flags: d3d12::D3D12_RESOURCE_FLAGS,
|
2020-11-20 04:29:57 +11:00
|
|
|
) -> Result<Resource, Error> {
|
|
|
|
let heap_properties = d3d12::D3D12_HEAP_PROPERTIES {
|
2021-05-22 15:03:42 +10:00
|
|
|
Type: heap_type,
|
|
|
|
CPUPageProperty: cpu_page,
|
|
|
|
MemoryPoolPreference: memory_pool_preference,
|
2020-11-20 04:29:57 +11:00
|
|
|
//we don't care about multi-adapter operation, so these next two will be zero
|
|
|
|
CreationNodeMask: 0,
|
|
|
|
VisibleNodeMask: 0,
|
|
|
|
};
|
|
|
|
let resource_description = d3d12::D3D12_RESOURCE_DESC {
|
|
|
|
Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER,
|
2021-11-21 02:14:23 +11:00
|
|
|
Width: buffer_size_in_bytes,
|
2020-11-20 04:29:57 +11:00
|
|
|
Height: 1,
|
|
|
|
DepthOrArraySize: 1,
|
|
|
|
MipLevels: 1,
|
|
|
|
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
|
|
|
|
Count: 1,
|
|
|
|
Quality: 0,
|
|
|
|
},
|
|
|
|
Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
2021-05-22 15:03:42 +10:00
|
|
|
Flags: resource_flags,
|
2020-11-20 04:29:57 +11:00
|
|
|
..mem::zeroed()
|
|
|
|
};
|
|
|
|
|
|
|
|
let buffer = self.create_committed_resource(
|
|
|
|
&heap_properties,
|
|
|
|
d3d12::D3D12_HEAP_FLAG_NONE,
|
|
|
|
&resource_description,
|
2021-05-22 15:03:42 +10:00
|
|
|
init_resource_state,
|
2020-11-20 04:29:57 +11:00
|
|
|
ptr::null(),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(buffer)
|
|
|
|
}
|
|
|
|
|
2021-05-22 08:46:00 +10:00
|
|
|
pub unsafe fn create_texture2d_buffer(
|
2020-11-20 04:29:57 +11:00
|
|
|
&self,
|
|
|
|
width: u64,
|
|
|
|
height: u32,
|
|
|
|
format: dxgiformat::DXGI_FORMAT,
|
|
|
|
allow_unordered_access: bool,
|
|
|
|
) -> Result<Resource, Error> {
|
2021-05-22 08:46:00 +10:00
|
|
|
// Images are always created device-local.
|
2020-11-20 04:29:57 +11:00
|
|
|
let heap_properties = d3d12::D3D12_HEAP_PROPERTIES {
|
|
|
|
Type: d3d12::D3D12_HEAP_TYPE_DEFAULT,
|
|
|
|
CPUPageProperty: d3d12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
|
|
|
MemoryPoolPreference: d3d12::D3D12_MEMORY_POOL_UNKNOWN,
|
|
|
|
//we don't care about multi-adapter operation, so these next two will be zero
|
|
|
|
CreationNodeMask: 0,
|
|
|
|
VisibleNodeMask: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
let (flags, initial_resource_state) = {
|
|
|
|
if allow_unordered_access {
|
|
|
|
(
|
|
|
|
d3d12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
|
|
|
|
d3d12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(
|
|
|
|
d3d12::D3D12_RESOURCE_FLAG_NONE,
|
|
|
|
d3d12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let resource_description = d3d12::D3D12_RESOURCE_DESC {
|
|
|
|
Dimension: d3d12::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
|
|
|
DepthOrArraySize: 1,
|
|
|
|
MipLevels: 1,
|
|
|
|
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
|
|
|
|
Count: 1,
|
|
|
|
Quality: 0,
|
|
|
|
},
|
|
|
|
Layout: d3d12::D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
|
|
|
Flags: flags,
|
|
|
|
Format: format,
|
|
|
|
..mem::zeroed()
|
|
|
|
};
|
|
|
|
|
|
|
|
let buffer = self.create_committed_resource(
|
|
|
|
&heap_properties,
|
|
|
|
//TODO: is this heap flag ok?
|
|
|
|
d3d12::D3D12_HEAP_FLAG_NONE,
|
|
|
|
&resource_description,
|
|
|
|
initial_resource_state,
|
|
|
|
ptr::null(),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(buffer)
|
|
|
|
}
|
|
|
|
|
2021-05-22 15:03:42 +10:00
|
|
|
pub unsafe fn get_features_architecture(
|
|
|
|
&self,
|
|
|
|
) -> Result<d3d12::D3D12_FEATURE_DATA_ARCHITECTURE, Error> {
|
|
|
|
let mut features_architecture = mem::zeroed();
|
|
|
|
explain_error(
|
|
|
|
self.0.CheckFeatureSupport(
|
|
|
|
d3d12::D3D12_FEATURE_ARCHITECTURE,
|
|
|
|
&mut features_architecture as *mut _ as *mut _,
|
|
|
|
mem::size_of::<d3d12::D3D12_FEATURE_DATA_ARCHITECTURE>() as u32,
|
|
|
|
),
|
|
|
|
"error querying feature architecture",
|
|
|
|
)?;
|
|
|
|
Ok(features_architecture)
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DescriptorHeap {
|
2021-11-21 02:14:23 +11:00
|
|
|
pub unsafe fn get_cpu_descriptor_handle_for_heap_start(&self) -> CpuDescriptor {
|
|
|
|
self.0.GetCPUDescriptorHandleForHeapStart()
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
pub unsafe fn get_gpu_descriptor_handle_for_heap_start(&self) -> GpuDescriptor {
|
|
|
|
self.0.GetGPUDescriptorHandleForHeapStart()
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RootSignature {
|
|
|
|
pub unsafe fn serialize_description(
|
|
|
|
desc: &d3d12::D3D12_ROOT_SIGNATURE_DESC,
|
|
|
|
version: d3d12::D3D_ROOT_SIGNATURE_VERSION,
|
2021-05-17 07:51:02 +10:00
|
|
|
) -> Result<Blob, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut blob = ptr::null_mut();
|
2021-05-17 07:51:02 +10:00
|
|
|
let mut error_blob_ptr = ptr::null_mut();
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
let hresult =
|
|
|
|
d3d12::D3D12SerializeRootSignature(desc, version, &mut blob, &mut error_blob_ptr);
|
|
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
{
|
2021-11-12 06:48:58 +11:00
|
|
|
let error_blob = if error_blob_ptr.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(Blob(ComPtr::from_raw(error_blob_ptr)))
|
|
|
|
};
|
2021-05-17 07:51:02 +10:00
|
|
|
if let Some(error_blob) = &error_blob {
|
|
|
|
Blob::print_to_console(error_blob);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
explain_error(hresult, "could not serialize root signature description")?;
|
|
|
|
|
|
|
|
Ok(Blob(ComPtr::from_raw(blob)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ShaderByteCode {
|
|
|
|
// `blob` may not be null.
|
2021-05-17 07:51:02 +10:00
|
|
|
// TODO: this is not super elegant, maybe want to move the get
|
|
|
|
// operations closer to where they're used.
|
2021-11-12 06:48:58 +11:00
|
|
|
#[allow(unused)]
|
2020-11-20 04:29:57 +11:00
|
|
|
pub unsafe fn from_blob(blob: Blob) -> ShaderByteCode {
|
|
|
|
ShaderByteCode {
|
|
|
|
bytecode: d3d12::D3D12_SHADER_BYTECODE {
|
|
|
|
BytecodeLength: blob.0.GetBufferSize(),
|
|
|
|
pShaderBytecode: blob.0.GetBufferPointer(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compile a shader from raw HLSL.
|
|
|
|
///
|
|
|
|
/// * `target`: example format: `ps_5_1`.
|
2021-11-12 06:48:58 +11:00
|
|
|
#[allow(unused)]
|
2020-11-20 04:29:57 +11:00
|
|
|
pub unsafe fn compile(
|
2021-05-17 07:51:02 +10:00
|
|
|
source: &str,
|
|
|
|
target: &str,
|
|
|
|
entry: &str,
|
2020-11-20 04:29:57 +11:00
|
|
|
flags: minwindef::DWORD,
|
2021-05-17 07:51:02 +10:00
|
|
|
) -> Result<Blob, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut shader_blob_ptr: *mut ID3DBlob = ptr::null_mut();
|
|
|
|
//TODO: use error blob properly
|
|
|
|
let mut error_blob_ptr: *mut ID3DBlob = ptr::null_mut();
|
|
|
|
|
|
|
|
let target = ffi::CString::new(target)
|
|
|
|
.expect("could not convert target format string into ffi::CString");
|
|
|
|
let entry = ffi::CString::new(entry)
|
|
|
|
.expect("could not convert entry name String into ffi::CString");
|
|
|
|
|
|
|
|
let hresult = d3dcompiler::D3DCompile(
|
|
|
|
source.as_ptr() as *const _,
|
|
|
|
source.len(),
|
|
|
|
ptr::null(),
|
|
|
|
ptr::null(),
|
|
|
|
d3dcompiler::D3D_COMPILE_STANDARD_FILE_INCLUDE,
|
2021-05-17 07:51:02 +10:00
|
|
|
entry.as_ptr(),
|
|
|
|
target.as_ptr(),
|
2020-11-20 04:29:57 +11:00
|
|
|
flags,
|
|
|
|
0,
|
2021-05-17 07:51:02 +10:00
|
|
|
&mut shader_blob_ptr,
|
|
|
|
&mut error_blob_ptr,
|
2020-11-20 04:29:57 +11:00
|
|
|
);
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
let error_blob = if error_blob_ptr.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(Blob(ComPtr::from_raw(error_blob_ptr)))
|
|
|
|
};
|
2020-11-20 04:29:57 +11:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
{
|
2021-05-17 07:51:02 +10:00
|
|
|
if let Some(error_blob) = &error_blob {
|
|
|
|
Blob::print_to_console(error_blob);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
// TODO: we can put the shader compilation error into the returned error.
|
|
|
|
explain_error(hresult, "shader compilation failed")?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
Ok(Blob(ComPtr::from_raw(shader_blob_ptr)))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
2021-11-12 06:48:58 +11:00
|
|
|
|
|
|
|
/// Create bytecode from a slice.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// This call elides the lifetime from the slice. The caller is responsible
|
|
|
|
/// for making sure the reference remains valid for the lifetime of this
|
|
|
|
/// object.
|
|
|
|
#[allow(unused)]
|
|
|
|
pub unsafe fn from_slice(bytecode: &[u8]) -> ShaderByteCode {
|
|
|
|
ShaderByteCode {
|
|
|
|
bytecode: d3d12::D3D12_SHADER_BYTECODE {
|
|
|
|
BytecodeLength: bytecode.len(),
|
|
|
|
pShaderBytecode: bytecode.as_ptr() as *const _,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Fence {
|
2021-04-30 15:06:13 +10:00
|
|
|
pub unsafe fn set_event_on_completion(&self, event: &Event, value: u64) -> Result<(), Error> {
|
|
|
|
explain_error(
|
|
|
|
self.0.SetEventOnCompletion(value, event.0),
|
|
|
|
"error setting event completion",
|
|
|
|
)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn get_value(&self) -> u64 {
|
|
|
|
self.0.GetCompletedValue()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Event {
|
2021-04-30 15:06:13 +10:00
|
|
|
pub unsafe fn create(manual_reset: bool, initial_state: bool) -> Result<Self, Error> {
|
|
|
|
let handle = synchapi::CreateEventA(
|
2020-11-20 04:29:57 +11:00
|
|
|
ptr::null_mut(),
|
|
|
|
manual_reset as _,
|
|
|
|
initial_state as _,
|
|
|
|
ptr::null(),
|
2021-04-30 15:06:13 +10:00
|
|
|
);
|
|
|
|
if handle.is_null() {
|
|
|
|
// TODO: should probably call GetLastError here
|
|
|
|
Err(Error::Hresult(-1))
|
|
|
|
} else {
|
|
|
|
Ok(Event(handle))
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
/// Wait for the event, or a timeout.
|
|
|
|
///
|
|
|
|
/// If the timeout is `winapi::um::winbase::INFINITE`, it will wait until the
|
|
|
|
/// event is signaled.
|
|
|
|
///
|
|
|
|
/// The return value is defined here:
|
|
|
|
/// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
|
2020-11-20 04:29:57 +11:00
|
|
|
pub unsafe fn wait(&self, timeout_ms: u32) -> u32 {
|
|
|
|
synchapi::WaitForSingleObject(self.0, timeout_ms)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
impl Drop for Event {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
handleapi::CloseHandle(self.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-22 12:07:46 +11:00
|
|
|
impl CommandAllocator {
|
|
|
|
pub unsafe fn reset(&self) -> Result<(), Error> {
|
|
|
|
error::error_if_failed_else_unit(self.0.Reset())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
impl GraphicsCommandList {
|
2021-05-25 08:38:31 +10:00
|
|
|
pub unsafe fn as_raw_command_list(&self) -> *mut d3d12::ID3D12CommandList {
|
2020-11-20 04:29:57 +11:00
|
|
|
self.0.as_raw() as *mut d3d12::ID3D12CommandList
|
|
|
|
}
|
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
pub unsafe fn close(&self) -> Result<(), Error> {
|
|
|
|
explain_error(self.0.Close(), "error closing command list")
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-11-10 15:28:06 +11:00
|
|
|
pub unsafe fn reset(
|
|
|
|
&self,
|
|
|
|
allocator: &CommandAllocator,
|
|
|
|
initial_pso: Option<&PipelineState>,
|
|
|
|
) -> Result<(), Error> {
|
2021-04-30 15:06:13 +10:00
|
|
|
let p_initial_state = initial_pso.map(|p| p.0.as_raw()).unwrap_or(ptr::null_mut());
|
|
|
|
error::error_if_failed_else_unit(self.0.Reset(allocator.0.as_raw(), p_initial_state))
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
pub unsafe fn set_compute_pipeline_root_signature(&self, signature: &RootSignature) {
|
2020-11-20 04:29:57 +11:00
|
|
|
self.0.SetComputeRootSignature(signature.0.as_raw());
|
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
pub unsafe fn resource_barrier(&self, resource_barriers: &[d3d12::D3D12_RESOURCE_BARRIER]) {
|
2020-11-20 04:29:57 +11:00
|
|
|
self.0.ResourceBarrier(
|
2021-05-17 07:51:02 +10:00
|
|
|
resource_barriers
|
|
|
|
.len()
|
|
|
|
.try_into()
|
|
|
|
.expect("Waaaaaay too many barriers"),
|
|
|
|
resource_barriers.as_ptr(),
|
2020-11-20 04:29:57 +11:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn dispatch(&self, count_x: u32, count_y: u32, count_z: u32) {
|
|
|
|
self.0.Dispatch(count_x, count_y, count_z);
|
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
pub unsafe fn set_pipeline_state(&self, pipeline_state: &PipelineState) {
|
2020-11-20 04:29:57 +11:00
|
|
|
self.0.SetPipelineState(pipeline_state.0.as_raw());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn set_compute_root_descriptor_table(
|
|
|
|
&self,
|
|
|
|
root_parameter_index: u32,
|
|
|
|
base_descriptor: d3d12::D3D12_GPU_DESCRIPTOR_HANDLE,
|
|
|
|
) {
|
|
|
|
self.0
|
|
|
|
.SetComputeRootDescriptorTable(root_parameter_index, base_descriptor);
|
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
pub unsafe fn set_descriptor_heaps(&self, descriptor_heaps: &[&DescriptorHeap]) {
|
2021-11-21 02:14:23 +11:00
|
|
|
let mut descriptor_heap_pointers: SmallVec<[_; 4]> =
|
|
|
|
descriptor_heaps.iter().map(|dh| dh.0.as_raw()).collect();
|
2020-11-20 04:29:57 +11:00
|
|
|
self.0.SetDescriptorHeaps(
|
|
|
|
u32::try_from(descriptor_heap_pointers.len())
|
|
|
|
.expect("could not safely convert descriptor_heap_pointers.len() into u32"),
|
2021-05-17 07:51:02 +10:00
|
|
|
descriptor_heap_pointers.as_mut_ptr(),
|
2020-11-20 04:29:57 +11:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-22 06:19:10 +10:00
|
|
|
pub unsafe fn end_timing_query(&self, query_heap: &QueryHeap, index: u32) {
|
2020-11-20 04:29:57 +11:00
|
|
|
self.0.EndQuery(
|
2021-05-22 06:19:10 +10:00
|
|
|
query_heap.0.as_raw(),
|
2020-11-20 04:29:57 +11:00
|
|
|
d3d12::D3D12_QUERY_TYPE_TIMESTAMP,
|
|
|
|
index,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn resolve_timing_query_data(
|
|
|
|
&self,
|
2021-05-22 06:19:10 +10:00
|
|
|
query_heap: &QueryHeap,
|
2020-11-20 04:29:57 +11:00
|
|
|
start_index: u32,
|
|
|
|
num_queries: u32,
|
2021-05-22 06:19:10 +10:00
|
|
|
destination_buffer: &Resource,
|
2020-11-20 04:29:57 +11:00
|
|
|
aligned_destination_buffer_offset: u64,
|
|
|
|
) {
|
|
|
|
self.0.ResolveQueryData(
|
|
|
|
query_heap.0.as_raw() as *mut _,
|
|
|
|
d3d12::D3D12_QUERY_TYPE_TIMESTAMP,
|
|
|
|
start_index,
|
|
|
|
num_queries,
|
2021-04-30 15:06:13 +10:00
|
|
|
destination_buffer.get_mut(),
|
2020-11-20 04:29:57 +11:00
|
|
|
aligned_destination_buffer_offset,
|
|
|
|
);
|
|
|
|
}
|
2021-05-22 08:46:00 +10:00
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
pub unsafe fn clear_uav(
|
|
|
|
&self,
|
|
|
|
gpu_handle: d3d12::D3D12_GPU_DESCRIPTOR_HANDLE,
|
|
|
|
cpu_handle: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE,
|
|
|
|
resource: &Resource,
|
|
|
|
value: u32,
|
|
|
|
size: Option<u64>,
|
|
|
|
) {
|
|
|
|
// In testing, only the first value seems to be used, but just in case...
|
|
|
|
let values = [value, value, value, value];
|
|
|
|
let mut rect = d3d12::D3D12_RECT {
|
|
|
|
left: 0,
|
|
|
|
right: 0,
|
|
|
|
top: 0,
|
|
|
|
bottom: 1,
|
|
|
|
};
|
|
|
|
let (num_rects, p_rects) = if let Some(size) = size {
|
|
|
|
rect.right = (size / 4).try_into().unwrap();
|
|
|
|
(1, &rect as *const _)
|
|
|
|
} else {
|
|
|
|
(0, std::ptr::null())
|
|
|
|
};
|
|
|
|
self.0.ClearUnorderedAccessViewUint(
|
|
|
|
gpu_handle,
|
|
|
|
cpu_handle,
|
|
|
|
resource.get_mut(),
|
|
|
|
&values,
|
|
|
|
num_rects,
|
|
|
|
p_rects,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-22 08:46:00 +10:00
|
|
|
/// Copy an entire resource (buffer or image)
|
|
|
|
pub unsafe fn copy_resource(&self, src: &Resource, dst: &Resource) {
|
2021-06-01 13:38:36 +10:00
|
|
|
self.0.CopyResource(dst.get_mut(), src.get_mut());
|
2021-05-22 08:46:00 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn copy_buffer(
|
|
|
|
&self,
|
|
|
|
dst_buf: &Resource,
|
|
|
|
dst_offset: u64,
|
|
|
|
src_buf: &Resource,
|
|
|
|
src_offset: u64,
|
|
|
|
size: u64,
|
|
|
|
) {
|
|
|
|
self.0.CopyBufferRegion(
|
|
|
|
dst_buf.get_mut(),
|
|
|
|
dst_offset,
|
|
|
|
src_buf.get_mut(),
|
|
|
|
src_offset,
|
|
|
|
size,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn copy_buffer_to_texture(
|
2020-11-20 04:29:57 +11:00
|
|
|
&self,
|
2021-05-22 08:46:00 +10:00
|
|
|
buffer: &Resource,
|
2021-04-30 15:06:13 +10:00
|
|
|
texture: &Resource,
|
2021-05-22 08:46:00 +10:00
|
|
|
width: u32,
|
|
|
|
height: u32,
|
2020-11-20 04:29:57 +11:00
|
|
|
) {
|
|
|
|
let mut src = d3d12::D3D12_TEXTURE_COPY_LOCATION {
|
2021-05-22 08:46:00 +10:00
|
|
|
pResource: buffer.get_mut(),
|
2020-11-20 04:29:57 +11:00
|
|
|
Type: d3d12::D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
|
|
|
..mem::zeroed()
|
|
|
|
};
|
2021-05-22 08:46:00 +10:00
|
|
|
let row_pitch = width * 4;
|
|
|
|
assert!(
|
|
|
|
row_pitch % d3d12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT == 0,
|
|
|
|
"TODO: handle unaligned row pitch"
|
|
|
|
);
|
|
|
|
let footprint = d3d12::D3D12_PLACED_SUBRESOURCE_FOOTPRINT {
|
|
|
|
Offset: 0,
|
|
|
|
Footprint: d3d12::D3D12_SUBRESOURCE_FOOTPRINT {
|
|
|
|
Format: dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
|
|
|
Depth: 1,
|
|
|
|
RowPitch: row_pitch,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
*src.u.PlacedFootprint_mut() = footprint;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
|
|
|
let mut dst = d3d12::D3D12_TEXTURE_COPY_LOCATION {
|
2021-04-30 15:06:13 +10:00
|
|
|
pResource: texture.get_mut(),
|
2020-11-20 04:29:57 +11:00
|
|
|
Type: d3d12::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
|
|
|
..mem::zeroed()
|
|
|
|
};
|
|
|
|
*dst.u.SubresourceIndex_mut() = 0;
|
|
|
|
|
2021-05-22 08:46:00 +10:00
|
|
|
self.0.CopyTextureRegion(&dst, 0, 0, 0, &src, ptr::null());
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
2021-05-17 07:51:02 +10:00
|
|
|
|
2021-05-22 08:46:00 +10:00
|
|
|
pub unsafe fn copy_texture_to_buffer(
|
2021-05-17 07:51:02 +10:00
|
|
|
&self,
|
2021-05-22 08:46:00 +10:00
|
|
|
texture: &Resource,
|
|
|
|
buffer: &Resource,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
2021-05-17 07:51:02 +10:00
|
|
|
) {
|
2021-05-22 08:46:00 +10:00
|
|
|
let mut src = d3d12::D3D12_TEXTURE_COPY_LOCATION {
|
|
|
|
pResource: texture.get_mut(),
|
|
|
|
Type: d3d12::D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
|
|
|
..mem::zeroed()
|
|
|
|
};
|
|
|
|
*src.u.SubresourceIndex_mut() = 0;
|
|
|
|
|
|
|
|
let mut dst = d3d12::D3D12_TEXTURE_COPY_LOCATION {
|
|
|
|
pResource: buffer.get_mut(),
|
|
|
|
Type: d3d12::D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
|
|
|
..mem::zeroed()
|
|
|
|
};
|
|
|
|
let row_pitch = width * 4;
|
|
|
|
assert!(
|
|
|
|
row_pitch % d3d12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT == 0,
|
|
|
|
"TODO: handle unaligned row pitch"
|
2021-05-17 07:51:02 +10:00
|
|
|
);
|
2021-05-22 08:46:00 +10:00
|
|
|
let footprint = d3d12::D3D12_PLACED_SUBRESOURCE_FOOTPRINT {
|
|
|
|
Offset: 0,
|
|
|
|
Footprint: d3d12::D3D12_SUBRESOURCE_FOOTPRINT {
|
|
|
|
Format: dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
|
|
|
Depth: 1,
|
|
|
|
RowPitch: row_pitch,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
*dst.u.PlacedFootprint_mut() = footprint;
|
|
|
|
|
|
|
|
self.0.CopyTextureRegion(&dst, 0, 0, 0, &src, ptr::null());
|
2021-05-17 07:51:02 +10:00
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_uav_resource_barrier(
|
|
|
|
resource: *mut d3d12::ID3D12Resource,
|
|
|
|
) -> d3d12::D3D12_RESOURCE_BARRIER {
|
|
|
|
let uav = d3d12::D3D12_RESOURCE_UAV_BARRIER {
|
|
|
|
pResource: resource,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut resource_barrier: d3d12::D3D12_RESOURCE_BARRIER = mem::zeroed();
|
|
|
|
resource_barrier.Type = d3d12::D3D12_RESOURCE_BARRIER_TYPE_UAV;
|
|
|
|
resource_barrier.Flags = d3d12::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
|
|
*resource_barrier.u.UAV_mut() = uav;
|
|
|
|
|
|
|
|
resource_barrier
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn create_transition_resource_barrier(
|
|
|
|
resource: *mut d3d12::ID3D12Resource,
|
|
|
|
state_before: d3d12::D3D12_RESOURCE_STATES,
|
|
|
|
state_after: d3d12::D3D12_RESOURCE_STATES,
|
|
|
|
) -> d3d12::D3D12_RESOURCE_BARRIER {
|
|
|
|
let transition = d3d12::D3D12_RESOURCE_TRANSITION_BARRIER {
|
|
|
|
pResource: resource,
|
|
|
|
Subresource: d3d12::D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
|
|
|
|
StateBefore: state_before,
|
|
|
|
StateAfter: state_after,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut resource_barrier: d3d12::D3D12_RESOURCE_BARRIER = mem::zeroed();
|
|
|
|
resource_barrier.Type = d3d12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
|
|
resource_barrier.Flags = d3d12::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
|
|
*resource_barrier.u.Transition_mut() = transition;
|
|
|
|
|
|
|
|
resource_barrier
|
|
|
|
}
|
|
|
|
|
2021-11-12 06:48:58 +11:00
|
|
|
#[allow(unused)]
|
2021-05-17 07:51:02 +10:00
|
|
|
pub unsafe fn enable_debug_layer() -> Result<(), Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
let mut debug_controller: *mut d3d12sdklayers::ID3D12Debug1 = ptr::null_mut();
|
2021-05-17 07:51:02 +10:00
|
|
|
explain_error(
|
|
|
|
d3d12::D3D12GetDebugInterface(
|
|
|
|
&d3d12sdklayers::ID3D12Debug1::uuidof(),
|
|
|
|
&mut debug_controller as *mut _ as *mut _,
|
|
|
|
),
|
|
|
|
"could not create debug controller",
|
|
|
|
)?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
let debug_controller = ComPtr::from_raw(debug_controller);
|
|
|
|
debug_controller.EnableDebugLayer();
|
2020-11-20 04:29:57 +11:00
|
|
|
|
|
|
|
let mut queue = ptr::null_mut();
|
|
|
|
let hr = dxgi1_3::DXGIGetDebugInterface1(
|
|
|
|
0,
|
|
|
|
&dxgidebug::IDXGIInfoQueue::uuidof(),
|
|
|
|
&mut queue as *mut _ as *mut _,
|
|
|
|
);
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
explain_error(hr, "failed to enable debug layer")?;
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
debug_controller.SetEnableGPUBasedValidation(minwindef::TRUE);
|
|
|
|
Ok(())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|