use concinnity_core::gfx::transform::mat4_inverse;
use windows::Win32::Foundation::RECT;
use windows::Win32::Graphics::Direct3D12::*;
use windows::Win32::Graphics::Dxgi::Common::*;
use super::allocator::{DeviceAllocator, PooledBuffer};
use super::com;
use crate::directx::context::{DxContext, FRAMES, align256, dump_on_err};
use crate::directx::pipeline::serialize_desc_and_create;
use crate::directx::slang_builtins;
use crate::directx::slang_builtins::SlangCompile;
use crate::directx::texture::{HDR_FORMAT, create_buffer};
use crate::gfx::render_graph::{FOG_FROXEL_X, FOG_FROXEL_Y, FOG_FROXEL_Z};
use crate::gfx::render_types::{FogFroxelParams, FogParams};
pub(in crate::directx) fn compile_fog_shaders(
msaa_samples: u32,
hot_reload: bool,
) -> Result<(Vec<u8>, Vec<u8>), String> {
let vs = slang_builtins::FULLSCREEN_VERT.compile(hot_reload)?;
let ps = if msaa_samples > 1 {
slang_builtins::FOG_FRAG_MSAA.compile(hot_reload)?
} else {
slang_builtins::FOG_FRAG.compile(hot_reload)?
};
Ok((vs, ps))
}
pub(in crate::directx) fn compile_fog_froxel_shader(hot_reload: bool) -> Result<Vec<u8>, String> {
slang_builtins::FOG_FROXEL.compile(hot_reload)
}
pub(in crate::directx) fn rebuild_fog_pso(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
msaa_samples: u32,
hot_reload: bool,
info_queue: Option<&ID3D12InfoQueue>,
) -> Result<ID3D12PipelineState, String> {
let (vs, ps) = compile_fog_shaders(msaa_samples, hot_reload)?;
dump_on_err(info_queue, create_fog_pso(device, root_sig, &vs, &ps))
}
pub(in crate::directx) fn rebuild_fog_froxel_pso(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
hot_reload: bool,
info_queue: Option<&ID3D12InfoQueue>,
) -> Result<ID3D12PipelineState, String> {
let cs = compile_fog_froxel_shader(hot_reload)?;
dump_on_err(info_queue, create_fog_froxel_pso(device, root_sig, &cs))
}
fn create_fog_root_signature(device: &ID3D12Device) -> Result<ID3D12RootSignature, String> {
let depth_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 1,
BaseShaderRegister: 0, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let volume_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 1,
BaseShaderRegister: 1, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let params = [
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 0,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 1,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &depth_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &volume_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
},
];
let volume_sampler = D3D12_STATIC_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,
ComparisonFunc: D3D12_COMPARISON_FUNC_ALWAYS,
MaxLOD: f32::MAX,
ShaderRegister: 0,
RegisterSpace: 0,
ShaderVisibility: D3D12_SHADER_VISIBILITY_PIXEL,
..Default::default()
};
let desc = D3D12_ROOT_SIGNATURE_DESC {
NumParameters: params.len() as u32,
pParameters: params.as_ptr(),
NumStaticSamplers: 1,
pStaticSamplers: &volume_sampler,
Flags: D3D12_ROOT_SIGNATURE_FLAG_NONE,
};
serialize_desc_and_create(device, &desc, "fog root sig")
}
fn create_fog_froxel_root_signature(device: &ID3D12Device) -> Result<ID3D12RootSignature, String> {
let shadow_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
NumDescriptors: 1,
BaseShaderRegister: 0, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let volume_range = D3D12_DESCRIPTOR_RANGE {
RangeType: D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
NumDescriptors: 1,
BaseShaderRegister: 0, RegisterSpace: 0,
OffsetInDescriptorsFromTableStart: D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
};
let params = [
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 0,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 1,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_CBV,
Anonymous: D3D12_ROOT_PARAMETER_0 {
Descriptor: D3D12_ROOT_DESCRIPTOR {
ShaderRegister: 2,
RegisterSpace: 0,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &shadow_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
D3D12_ROOT_PARAMETER {
ParameterType: D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
Anonymous: D3D12_ROOT_PARAMETER_0 {
DescriptorTable: D3D12_ROOT_DESCRIPTOR_TABLE {
NumDescriptorRanges: 1,
pDescriptorRanges: &volume_range,
},
},
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
},
];
let shadow_sampler = D3D12_STATIC_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: D3D12_COMPARISON_FUNC_LESS_EQUAL,
MaxLOD: f32::MAX,
ShaderRegister: 0,
RegisterSpace: 0,
ShaderVisibility: D3D12_SHADER_VISIBILITY_ALL,
..Default::default()
};
let desc = D3D12_ROOT_SIGNATURE_DESC {
NumParameters: params.len() as u32,
pParameters: params.as_ptr(),
NumStaticSamplers: 1,
pStaticSamplers: &shadow_sampler,
Flags: D3D12_ROOT_SIGNATURE_FLAG_NONE,
};
serialize_desc_and_create(device, &desc, "fog froxel root sig")
}
fn create_fog_pso(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
vs: &[u8],
ps: &[u8],
) -> Result<ID3D12PipelineState, String> {
let pso_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC {
pRootSignature: com::borrowed(root_sig),
VS: D3D12_SHADER_BYTECODE {
pShaderBytecode: vs.as_ptr() as _,
BytecodeLength: vs.len(),
},
PS: D3D12_SHADER_BYTECODE {
pShaderBytecode: ps.as_ptr() as _,
BytecodeLength: ps.len(),
},
PrimitiveTopologyType: D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
NumRenderTargets: 1,
RTVFormats: {
let mut a = [DXGI_FORMAT_UNKNOWN; 8];
a[0] = HDR_FORMAT;
a
},
DSVFormat: DXGI_FORMAT_UNKNOWN,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
SampleMask: u32::MAX,
RasterizerState: D3D12_RASTERIZER_DESC {
FillMode: D3D12_FILL_MODE_SOLID,
CullMode: D3D12_CULL_MODE_NONE,
FrontCounterClockwise: true.into(),
DepthClipEnable: false.into(),
..Default::default()
},
DepthStencilState: D3D12_DEPTH_STENCIL_DESC {
DepthEnable: false.into(),
DepthWriteMask: D3D12_DEPTH_WRITE_MASK_ZERO,
StencilEnable: false.into(),
..Default::default()
},
BlendState: D3D12_BLEND_DESC {
RenderTarget: {
let mut arr = [D3D12_RENDER_TARGET_BLEND_DESC::default(); 8];
arr[0] = D3D12_RENDER_TARGET_BLEND_DESC {
BlendEnable: true.into(),
SrcBlend: D3D12_BLEND_ONE,
DestBlend: D3D12_BLEND_INV_SRC_ALPHA,
BlendOp: D3D12_BLEND_OP_ADD,
SrcBlendAlpha: D3D12_BLEND_ONE,
DestBlendAlpha: D3D12_BLEND_INV_SRC_ALPHA,
BlendOpAlpha: D3D12_BLEND_OP_ADD,
RenderTargetWriteMask: D3D12_COLOR_WRITE_ENABLE_ALL.0 as u8,
..Default::default()
};
arr
},
..Default::default()
},
..Default::default()
};
unsafe { crate::directx::pso_library::create_graphics(device, &pso_desc) }
.map_err(|e| format!("create fog PSO: {e}"))
}
fn create_fog_froxel_pso(
device: &ID3D12Device,
root_sig: &ID3D12RootSignature,
cs: &[u8],
) -> Result<ID3D12PipelineState, String> {
let desc = D3D12_COMPUTE_PIPELINE_STATE_DESC {
pRootSignature: com::borrowed(root_sig),
CS: D3D12_SHADER_BYTECODE {
pShaderBytecode: cs.as_ptr() as _,
BytecodeLength: cs.len(),
},
..Default::default()
};
unsafe { crate::directx::pso_library::create_compute(device, &desc) }
.map_err(|e| format!("create fog froxel PSO: {e}"))
}
fn create_fog_froxel_volume(
device: &ID3D12Device,
uav_cpu: D3D12_CPU_DESCRIPTOR_HANDLE,
srv_cpu: D3D12_CPU_DESCRIPTOR_HANDLE,
) -> Result<ID3D12Resource, String> {
let heap_props = D3D12_HEAP_PROPERTIES {
Type: D3D12_HEAP_TYPE_DEFAULT,
..Default::default()
};
let desc = D3D12_RESOURCE_DESC {
Dimension: D3D12_RESOURCE_DIMENSION_TEXTURE3D,
Width: FOG_FROXEL_X as u64,
Height: FOG_FROXEL_Y,
DepthOrArraySize: FOG_FROXEL_Z as u16,
MipLevels: 1,
Format: DXGI_FORMAT_R16G16B16A16_FLOAT,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
Flags: D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
..Default::default()
};
let mut tex_opt: Option<ID3D12Resource> = None;
unsafe {
device.CreateCommittedResource(
&heap_props,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
None,
&mut tex_opt,
)
}
.map_err(|e| format!("create fog froxel volume: {e}"))?;
let resource = tex_opt.ok_or_else(|| "create fog froxel volume returned None".to_string())?;
let uav_desc = D3D12_UNORDERED_ACCESS_VIEW_DESC {
Format: DXGI_FORMAT_R16G16B16A16_FLOAT,
ViewDimension: D3D12_UAV_DIMENSION_TEXTURE3D,
Anonymous: D3D12_UNORDERED_ACCESS_VIEW_DESC_0 {
Texture3D: D3D12_TEX3D_UAV {
MipSlice: 0,
FirstWSlice: 0,
WSize: FOG_FROXEL_Z,
},
},
};
unsafe {
device.CreateUnorderedAccessView(&resource, None, Some(&uav_desc), uav_cpu);
}
let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC {
Format: DXGI_FORMAT_R16G16B16A16_FLOAT,
ViewDimension: D3D12_SRV_DIMENSION_TEXTURE3D,
Shader4ComponentMapping: D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
Anonymous: D3D12_SHADER_RESOURCE_VIEW_DESC_0 {
Texture3D: D3D12_TEX3D_SRV {
MostDetailedMip: 0,
MipLevels: 1,
ResourceMinLODClamp: 0.0,
},
},
};
unsafe { device.CreateShaderResourceView(&resource, Some(&srv_desc), srv_cpu) };
Ok(resource)
}
pub(in crate::directx) struct FogResources {
pub(in crate::directx) root_sig: ID3D12RootSignature,
pub(in crate::directx) pso: ID3D12PipelineState,
pub(in crate::directx) froxel_root_sig: ID3D12RootSignature,
pub(in crate::directx) froxel_pso: ID3D12PipelineState,
pub(in crate::directx) params_ubo_resources: Vec<PooledBuffer>,
pub(in crate::directx) params_ubo_ptrs: Vec<*mut u8>,
pub(in crate::directx) froxel_params_ubo_resources: Vec<PooledBuffer>,
pub(in crate::directx) froxel_params_ubo_ptrs: Vec<*mut u8>,
pub(in crate::directx) volume_resource: ID3D12Resource,
pub(in crate::directx) volume_uav_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
pub(in crate::directx) volume_srv_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
pub(in crate::directx) depth_srv_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
pub(in crate::directx) shadow_srv_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
}
#[derive(Clone, Copy)]
pub(in crate::directx) struct FogVolumeDescriptors {
pub uav_cpu: D3D12_CPU_DESCRIPTOR_HANDLE,
pub uav_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
pub srv_cpu: D3D12_CPU_DESCRIPTOR_HANDLE,
pub srv_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
}
#[derive(Clone, Copy)]
pub(in crate::directx) struct FogShaderResourceHandles {
pub depth_srv_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
pub shadow_srv_gpu: D3D12_GPU_DESCRIPTOR_HANDLE,
}
#[derive(Clone, Copy)]
pub(in crate::directx) struct FogDeviceParams {
pub msaa_samples: u32,
pub hot_reload: bool,
}
impl FogResources {
pub(in crate::directx) fn new(
alloc: &DeviceAllocator,
volume: FogVolumeDescriptors,
shader_resources: FogShaderResourceHandles,
params: FogDeviceParams,
info_queue: Option<&ID3D12InfoQueue>,
) -> Result<Self, String> {
let device = alloc.device();
let FogVolumeDescriptors {
uav_cpu: volume_uav_cpu,
uav_gpu: volume_uav_gpu,
srv_cpu: volume_srv_cpu,
srv_gpu: volume_srv_gpu,
} = volume;
let FogShaderResourceHandles {
depth_srv_gpu,
shadow_srv_gpu,
} = shader_resources;
let FogDeviceParams {
msaa_samples,
hot_reload,
} = params;
let (vs, ps) = compile_fog_shaders(msaa_samples, hot_reload)?;
let cs = compile_fog_froxel_shader(hot_reload)?;
let root_sig = dump_on_err(info_queue, create_fog_root_signature(device))?;
let pso = dump_on_err(info_queue, create_fog_pso(device, &root_sig, &vs, &ps))?;
let froxel_root_sig = dump_on_err(info_queue, create_fog_froxel_root_signature(device))?;
let froxel_pso = dump_on_err(
info_queue,
create_fog_froxel_pso(device, &froxel_root_sig, &cs),
)?;
let volume_resource = create_fog_froxel_volume(device, volume_uav_cpu, volume_srv_cpu)?;
let params_ubo_size = align256(std::mem::size_of::<FogParams>() as u64);
let mut params_ubo_resources: Vec<PooledBuffer> = Vec::with_capacity(FRAMES);
let mut params_ubo_ptrs: Vec<*mut u8> = Vec::with_capacity(FRAMES);
for _ in 0..FRAMES {
let buf = create_buffer(
alloc,
params_ubo_size,
D3D12_HEAP_TYPE_UPLOAD,
D3D12_RESOURCE_STATE_GENERIC_READ,
)?;
let mut ptr = std::ptr::null_mut::<std::ffi::c_void>();
unsafe { buf.Map(0, None, Some(&mut ptr)) }
.map_err(|e| format!("map fog params ubo: {e}"))?;
params_ubo_ptrs.push(ptr as *mut u8);
params_ubo_resources.push(buf);
}
let froxel_ubo_size = align256(std::mem::size_of::<FogFroxelParams>() as u64);
let mut froxel_params_ubo_resources: Vec<PooledBuffer> = Vec::with_capacity(FRAMES);
let mut froxel_params_ubo_ptrs: Vec<*mut u8> = Vec::with_capacity(FRAMES);
for _ in 0..FRAMES {
let buf = create_buffer(
alloc,
froxel_ubo_size,
D3D12_HEAP_TYPE_UPLOAD,
D3D12_RESOURCE_STATE_GENERIC_READ,
)?;
let mut ptr = std::ptr::null_mut::<std::ffi::c_void>();
unsafe { buf.Map(0, None, Some(&mut ptr)) }
.map_err(|e| format!("map fog froxel params ubo: {e}"))?;
froxel_params_ubo_ptrs.push(ptr as *mut u8);
froxel_params_ubo_resources.push(buf);
}
Ok(Self {
root_sig,
pso,
froxel_root_sig,
froxel_pso,
params_ubo_resources,
params_ubo_ptrs,
froxel_params_ubo_resources,
froxel_params_ubo_ptrs,
volume_resource,
volume_uav_gpu,
volume_srv_gpu,
depth_srv_gpu,
shadow_srv_gpu,
})
}
}
impl DxContext {
pub(crate) fn update_fog_settings(
&mut self,
settings: Option<crate::gfx::volumetric_fog::FogSettings>,
) {
if settings.is_some() && self.fog.resources.is_none() {
tracing::warn!(
"VolumetricFog hot-reload: world started without fog, so the fog \
pipeline was never built: re-enabling fog mid-run is not \
supported (relaunch required). Ignoring update."
);
return;
}
self.fog.settings = settings;
}
fn fog_froxel_params(&self, near: f32) -> Option<FogFroxelParams> {
let fog = self.fog.settings?;
Some(FogFroxelParams {
view: self.view.matrix,
froxel_dims: [FOG_FROXEL_X, FOG_FROXEL_Y, FOG_FROXEL_Z],
_pad_align: 0,
z_near: near.max(1e-3),
z_far: fog.max_distance,
_pad: [0.0; 2],
})
}
pub(in crate::directx) fn encode_fog_froxel(
&self,
cmd: &ID3D12GraphicsCommandList,
frame_idx: usize,
near: f32,
vp: [[f32; 4]; 4],
cam_pos: [f32; 3],
shadow_ubo_gva: u64,
) {
let fog_settings = match &self.fog.settings {
Some(s) => *s,
None => return,
};
let fog = match &self.fog.resources {
Some(f) => f,
None => return,
};
let froxel_params = match self.fog_froxel_params(near) {
Some(p) => p,
None => return,
};
let inv_vp = mat4_inverse(vp);
let viewport = [
self.extent.render_width as f32,
self.extent.render_height as f32,
];
let params = fog_settings.params(
inv_vp,
cam_pos,
self.fog.sun_dir,
self.fog.sun_color,
viewport,
);
unsafe {
std::ptr::copy_nonoverlapping(
¶ms as *const FogParams as *const u8,
fog.params_ubo_ptrs[frame_idx],
std::mem::size_of::<FogParams>(),
);
std::ptr::copy_nonoverlapping(
&froxel_params as *const FogFroxelParams as *const u8,
fog.froxel_params_ubo_ptrs[frame_idx],
std::mem::size_of::<FogFroxelParams>(),
);
}
let params_gva = com::gpu_va(&fog.params_ubo_resources[frame_idx]);
let froxel_params_gva = com::gpu_va(&fog.froxel_params_ubo_resources[frame_idx]);
unsafe {
cmd.SetComputeRootSignature(&fog.froxel_root_sig);
cmd.SetPipelineState(&fog.froxel_pso);
cmd.SetDescriptorHeaps(&[Some(self.descriptors.srv_heap.clone())]);
cmd.SetComputeRootConstantBufferView(0, params_gva);
cmd.SetComputeRootConstantBufferView(1, froxel_params_gva);
cmd.SetComputeRootConstantBufferView(2, shadow_ubo_gva);
cmd.SetComputeRootDescriptorTable(3, fog.shadow_srv_gpu);
cmd.SetComputeRootDescriptorTable(4, fog.volume_uav_gpu);
let groups_x = FOG_FROXEL_X.div_ceil(8);
let groups_y = FOG_FROXEL_Y.div_ceil(8);
cmd.Dispatch(groups_x, groups_y, 1);
}
}
pub(in crate::directx) fn encode_fog(
&self,
cmd: &ID3D12GraphicsCommandList,
frame_idx: usize,
_vp: [[f32; 4]; 4],
_cam_pos: [f32; 3],
) {
let _ = match &self.fog.settings {
Some(s) => *s,
None => return,
};
let fog = match &self.fog.resources {
Some(f) => f,
None => return,
};
let params_gva = com::gpu_va(&fog.params_ubo_resources[frame_idx]);
let froxel_params_gva = com::gpu_va(&fog.froxel_params_ubo_resources[frame_idx]);
let scene_rtv = self.hdr_scene_rtv();
let w = self.extent.render_width;
let h = self.extent.render_height;
unsafe {
cmd.OMSetRenderTargets(1, Some(&scene_rtv), false, None);
let vp_state = D3D12_VIEWPORT {
TopLeftX: 0.0,
TopLeftY: 0.0,
Width: w as f32,
Height: h as f32,
MinDepth: 0.0,
MaxDepth: 1.0,
};
cmd.RSSetViewports(&[vp_state]);
let scissor = RECT {
left: 0,
top: 0,
right: w as i32,
bottom: h as i32,
};
cmd.RSSetScissorRects(&[scissor]);
cmd.IASetPrimitiveTopology(
windows::Win32::Graphics::Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
);
cmd.SetPipelineState(&fog.pso);
cmd.SetGraphicsRootSignature(&fog.root_sig);
cmd.SetDescriptorHeaps(&[Some(self.descriptors.srv_heap.clone())]);
cmd.SetGraphicsRootConstantBufferView(0, params_gva);
cmd.SetGraphicsRootConstantBufferView(1, froxel_params_gva);
cmd.SetGraphicsRootDescriptorTable(2, fog.depth_srv_gpu);
cmd.SetGraphicsRootDescriptorTable(3, fog.volume_srv_gpu);
cmd.DrawInstanced(3, 1, 0, 0);
}
}
}