use concinnity_core::render::error::RenderResult;
use windows::Win32::Graphics::Direct3D12::*;
use super::InitGpu;
use super::bootstrap::DxgiSwapchain;
use super::heap_layout::{DSV_SLOTS, RtvHeapLayout};
use crate::directx::context::{FRAMES, SwapchainState};
use crate::directx::depth::shadow_sample_compare;
use crate::directx::error::map_hresult;
pub(super) const SHADOW_SAMPLER_SLOT: usize = 0;
pub(super) const LINEAR_SAMPLER_SLOT: usize = 1;
pub(super) const TEXT_SAMPLER_SLOT: usize = 3;
pub(super) const RAYMARCH_SAMPLER_BASE_SLOT: usize = 4;
const SAMPLER_SLOTS: u32 = 7;
pub(super) fn cpu_handle(
heap: &ID3D12DescriptorHeap,
stride: usize,
slot: usize,
) -> D3D12_CPU_DESCRIPTOR_HANDLE {
let base = unsafe { heap.GetCPUDescriptorHandleForHeapStart() };
D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: base.ptr + slot * stride,
}
}
pub(super) fn descriptor_size(device: &ID3D12Device, kind: D3D12_DESCRIPTOR_HEAP_TYPE) -> usize {
unsafe { device.GetDescriptorHandleIncrementSize(kind) as usize }
}
impl SwapchainState {
pub(super) fn rtv(&self, slot: usize) -> D3D12_CPU_DESCRIPTOR_HANDLE {
cpu_handle(&self.rtv_heap, self.rtv_descriptor_size, slot)
}
}
pub(super) fn build_swapchain(
gpu: &InitGpu<'_>,
swapchain: DxgiSwapchain,
rtv: &RtvHeapLayout,
vsync: bool,
) -> RenderResult<SwapchainState> {
let device = &gpu.hw.device;
let rtv_heap: ID3D12DescriptorHeap = unsafe {
device.CreateDescriptorHeap(&D3D12_DESCRIPTOR_HEAP_DESC {
Type: D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
NumDescriptors: rtv.rtv_slots as u32,
..Default::default()
})
}
.map_err(|e| map_hresult(e.code(), "RTV heap"))?;
let rtv_descriptor_size = descriptor_size(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
let mut back_buffers = Vec::with_capacity(FRAMES);
for i in 0..FRAMES {
let buf: ID3D12Resource = unsafe { swapchain.handle.GetBuffer(i as u32) }
.map_err(|e| map_hresult(e.code(), &format!("GetBuffer[{i}]")))?;
let rtv_handle = cpu_handle(&rtv_heap, rtv_descriptor_size, i);
unsafe {
device.CreateRenderTargetView(&buf, None, rtv_handle);
}
back_buffers.push(buf);
}
let present_sync_interval: u32 = if vsync { 1 } else { 0 };
Ok(SwapchainState {
handle: swapchain.handle,
back_buffers,
rtv_heap,
rtv_descriptor_size,
format: swapchain.format,
present_sync_interval,
allow_tearing: swapchain.allow_tearing,
last_present_index: None,
})
}
pub(super) fn create_dsv_heap(device: &ID3D12Device) -> RenderResult<ID3D12DescriptorHeap> {
let dsv_heap: ID3D12DescriptorHeap = unsafe {
device.CreateDescriptorHeap(&D3D12_DESCRIPTOR_HEAP_DESC {
Type: D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
NumDescriptors: DSV_SLOTS as u32,
..Default::default()
})
}
.map_err(|e| map_hresult(e.code(), "DSV heap"))?;
Ok(dsv_heap)
}
pub(super) fn create_sampler_heap(
device: &ID3D12Device,
anisotropy: u32,
) -> RenderResult<ID3D12DescriptorHeap> {
let sampler_heap: ID3D12DescriptorHeap = unsafe {
device.CreateDescriptorHeap(&D3D12_DESCRIPTOR_HEAP_DESC {
Type: D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
NumDescriptors: SAMPLER_SLOTS,
Flags: D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
..Default::default()
})
}
.map_err(|e| map_hresult(e.code(), "sampler heap"))?;
let sampler_descriptor_size = descriptor_size(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
create_samplers(
device,
cpu_handle(&sampler_heap, sampler_descriptor_size, 0),
sampler_descriptor_size,
anisotropy,
);
Ok(sampler_heap)
}
fn create_samplers(
device: &ID3D12Device,
base_cpu: D3D12_CPU_DESCRIPTOR_HANDLE,
stride: usize,
anisotropy: u32,
) {
let shadow_samp = D3D12_SAMPLER_DESC {
Filter: D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT,
AddressU: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
AddressV: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
AddressW: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
ComparisonFunc: shadow_sample_compare(),
MinLOD: 0.0,
MaxLOD: f32::MAX,
..Default::default()
};
unsafe {
device.CreateSampler(
&shadow_samp,
D3D12_CPU_DESCRIPTOR_HANDLE { ptr: base_cpu.ptr },
)
};
let linear_samp = D3D12_SAMPLER_DESC {
Filter: D3D12_FILTER_ANISOTROPIC,
AddressU: D3D12_TEXTURE_ADDRESS_MODE_WRAP,
AddressV: D3D12_TEXTURE_ADDRESS_MODE_WRAP,
AddressW: D3D12_TEXTURE_ADDRESS_MODE_WRAP,
MaxAnisotropy: anisotropy.clamp(1, 16),
MinLOD: 0.0,
MaxLOD: f32::MAX,
..Default::default()
};
unsafe {
device.CreateSampler(
&linear_samp,
D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: base_cpu.ptr + stride,
},
)
};
let cube_samp = D3D12_SAMPLER_DESC {
Filter: D3D12_FILTER_MIN_MAG_MIP_LINEAR,
AddressU: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
AddressV: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
AddressW: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
MinLOD: 0.0,
MaxLOD: f32::MAX,
..Default::default()
};
unsafe {
device.CreateSampler(
&cube_samp,
D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: base_cpu.ptr + stride * 2,
},
)
};
let clamp_samp = D3D12_SAMPLER_DESC {
Filter: D3D12_FILTER_MIN_MAG_MIP_LINEAR,
AddressU: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
AddressV: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
AddressW: D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
MinLOD: 0.0,
MaxLOD: 0.0,
..Default::default()
};
unsafe {
device.CreateSampler(
&clamp_samp,
D3D12_CPU_DESCRIPTOR_HANDLE {
ptr: base_cpu.ptr + stride * 3,
},
)
};
}