use super::d3d12;
use crate::RafxResult;
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use windows::Win32::Graphics::Direct3D12::ID3D12DescriptorHeap;
fn next_power_of_two(mut v: u32) -> u32 {
v = v.saturating_sub(1);
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v += 1;
return v;
}
struct HeapWithHandles {
heap: ID3D12DescriptorHeap,
cpu_first_handle: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_first_handle: Option<d3d12::D3D12_GPU_DESCRIPTOR_HANDLE>,
}
fn create_heap(
device: &d3d12::ID3D12Device,
heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
descriptor_count: u32,
shader_visible: bool,
) -> RafxResult<HeapWithHandles> {
let mut heap_desc = d3d12::D3D12_DESCRIPTOR_HEAP_DESC {
Type: heap_type,
NumDescriptors: descriptor_count,
Flags: d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
NodeMask: 0,
};
if shader_visible {
heap_desc.Flags |= d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
}
println!("{:?}", heap_desc);
let heap: ID3D12DescriptorHeap;
let cpu_first_handle;
let gpu_first_handle;
unsafe {
heap = device.CreateDescriptorHeap(&heap_desc)?;
cpu_first_handle = heap.GetCPUDescriptorHandleForHeapStart();
println!("start_cpu_handle {}", cpu_first_handle.ptr);
gpu_first_handle = if shader_visible {
Some(heap.GetGPUDescriptorHandleForHeapStart())
} else {
None
};
}
Ok(HeapWithHandles {
heap,
cpu_first_handle,
gpu_first_handle,
})
}
#[derive(Debug, Clone, Copy)]
pub struct Dx12DescriptorId(pub u32);
impl Dx12DescriptorId {
pub fn add_offset(
self,
offset: u32,
) -> Dx12DescriptorId {
Dx12DescriptorId(self.0 + offset)
}
}
pub struct Dx12DescriptorHeapInner {
heap: d3d12::ID3D12DescriptorHeap,
cpu_first_handle: d3d12::D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_first_handle: Option<d3d12::D3D12_GPU_DESCRIPTOR_HANDLE>,
descriptor_count: u32,
heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
allocated_descriptor_count: u32,
allocated_descriptors: Vec<bool>,
}
impl Dx12DescriptorHeapInner {
pub fn new(
device: &d3d12::ID3D12Device,
heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
descriptor_count: u32,
shader_visible: bool,
) -> RafxResult<Self> {
let heap = create_heap(device, heap_type, descriptor_count, shader_visible)?;
let allocated_descriptors = vec![false; descriptor_count as usize];
Ok(Dx12DescriptorHeapInner {
heap: heap.heap,
cpu_first_handle: heap.cpu_first_handle,
gpu_first_handle: heap.gpu_first_handle,
descriptor_count,
heap_type,
allocated_descriptor_count: 0,
allocated_descriptors,
})
}
fn grow(
&mut self,
device: &d3d12::ID3D12Device,
minimum_required_descriptors: u32,
) -> RafxResult<()> {
let old_size = self.descriptor_count;
let new_size = next_power_of_two(old_size + minimum_required_descriptors);
println!("GROWING HEAP {} -> {}", old_size, new_size);
let shader_visible = self.gpu_first_handle.is_some();
let new_heap = create_heap(device, self.heap_type, new_size, shader_visible)?;
unsafe {
device.CopyDescriptorsSimple(
old_size,
new_heap.cpu_first_handle,
self.cpu_first_handle,
self.heap_type,
);
}
self.heap = new_heap.heap;
self.cpu_first_handle = new_heap.cpu_first_handle;
self.gpu_first_handle = new_heap.gpu_first_handle;
self.descriptor_count = new_size;
self.allocated_descriptors.resize(new_size as usize, false);
Ok(())
}
pub fn allocate(
&mut self,
device: &d3d12::ID3D12Device,
count: u32,
) -> RafxResult<Dx12DescriptorId> {
assert!(count > 0);
let mut free_count = 0;
let mut free_range_begin = 0;
for i in 0..self.descriptor_count {
if !self.allocated_descriptors[i as usize] {
free_count += 1;
} else {
free_count = 0;
free_range_begin = i + 1;
}
if free_count >= count {
break;
}
}
if free_count < count {
self.grow(device, count)?;
}
for i in free_range_begin..(free_range_begin + count) {
self.allocated_descriptors[i as usize] = true;
}
self.allocated_descriptor_count += count;
Ok(Dx12DescriptorId(free_range_begin))
}
pub fn free(
&mut self,
first_descriptor: Dx12DescriptorId,
count: u32,
) {
assert!(count > 0);
for i in first_descriptor.0..(first_descriptor.0 + count) {
assert!(self.allocated_descriptors[i as usize]);
self.allocated_descriptors[i as usize] = false;
}
self.allocated_descriptor_count -= count;
}
}
pub struct Dx12DescriptorHeap {
inner: Arc<Mutex<Dx12DescriptorHeapInner>>,
heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
stride: u32,
cpu_first_handle: AtomicUsize,
gpu_first_handle: AtomicU64,
}
impl Dx12DescriptorHeap {
pub fn new(
device: &d3d12::ID3D12Device,
heap_type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE,
descriptor_count: u32,
shader_visible: bool,
) -> RafxResult<Self> {
let heap =
Dx12DescriptorHeapInner::new(device, heap_type, descriptor_count, shader_visible)?;
let cpu_first_handle = AtomicUsize::new(heap.cpu_first_handle.ptr);
let gpu_first_handle = if let Some(gpu_first_handle) = &heap.gpu_first_handle {
AtomicU64::new(gpu_first_handle.ptr)
} else {
AtomicU64::new(0xFFFFFFFFFFFFFFFF)
};
let stride = unsafe { device.GetDescriptorHandleIncrementSize(heap_type) };
Ok(Dx12DescriptorHeap {
inner: Arc::new(Mutex::new(heap)),
heap_type,
stride,
cpu_first_handle,
gpu_first_handle,
})
}
pub fn heap_type(&self) -> d3d12::D3D12_DESCRIPTOR_HEAP_TYPE {
self.heap_type
}
pub fn dx12_heap(&self) -> d3d12::ID3D12DescriptorHeap {
let inner = self.inner.lock().unwrap();
inner.heap.clone()
}
pub fn allocate(
&self,
device: &d3d12::ID3D12Device,
count: u32,
) -> RafxResult<Dx12DescriptorId> {
let mut inner = self.inner.lock().unwrap();
let id = inner.allocate(device, count);
self.cpu_first_handle
.store(inner.cpu_first_handle.ptr, Ordering::Relaxed);
if let Some(gpu_first_handle) = inner.gpu_first_handle {
self.gpu_first_handle
.store(gpu_first_handle.ptr, Ordering::Relaxed);
}
id
}
pub fn free(
&self,
first_descriptor: Dx12DescriptorId,
count: u32,
) {
let mut inner = self.inner.lock().unwrap();
inner.free(first_descriptor, count)
}
pub fn id_to_cpu_handle(
&self,
id: Dx12DescriptorId,
) -> d3d12::D3D12_CPU_DESCRIPTOR_HANDLE {
let start_cpu_handle = self.cpu_first_handle.load(Ordering::Relaxed);
d3d12::D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: start_cpu_handle + (id.0 * self.stride) as usize,
}
}
pub fn id_to_gpu_handle(
&self,
id: Dx12DescriptorId,
) -> d3d12::D3D12_GPU_DESCRIPTOR_HANDLE {
let start_gpu_handle = self.gpu_first_handle.load(Ordering::Relaxed);
assert_ne!(start_gpu_handle, 0xFFFFFFFFFFFFFFFF);
d3d12::D3D12_GPU_DESCRIPTOR_HANDLE {
ptr: start_gpu_handle + (id.0 * self.stride) as u64,
}
}
}
pub struct Dx12DescriptorHeapSet {
pub cbv_srv_uav_heap: Dx12DescriptorHeap,
pub sampler_heap: Dx12DescriptorHeap,
pub rtv_heap: Dx12DescriptorHeap,
pub dsv_heap: Dx12DescriptorHeap,
pub gpu_cbv_srv_uav_heap: Dx12DescriptorHeap,
pub gpu_sampler_heap: Dx12DescriptorHeap,
}
impl Dx12DescriptorHeapSet {
pub fn new(device: &d3d12::ID3D12Device) -> RafxResult<Self> {
let cbv_srv_uav_heap = Dx12DescriptorHeap::new(
device,
d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
256 * 1024,
false,
)?;
let sampler_heap = Dx12DescriptorHeap::new(
device,
d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
2048,
false,
)?;
let rtv_heap =
Dx12DescriptorHeap::new(device, d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 512, false)?;
let dsv_heap =
Dx12DescriptorHeap::new(device, d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 512, false)?;
let gpu_cbv_srv_uav_heap = Dx12DescriptorHeap::new(
device,
d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
256 * 1024,
true,
)?;
let gpu_sampler_heap = Dx12DescriptorHeap::new(
device,
d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
2048,
true,
)?;
Ok(Dx12DescriptorHeapSet {
cbv_srv_uav_heap,
sampler_heap,
rtv_heap,
dsv_heap,
gpu_cbv_srv_uav_heap,
gpu_sampler_heap,
})
}
}