use concinnity_core::render::error::RenderResult;
use concinnity_core::render::reactive_mask::ReactiveWrite;
use windows::Win32::Graphics::Direct3D12::*;
use windows::Win32::Graphics::Dxgi::Common::*;
use super::descriptor_slot::SrvSlot;
use super::pso::{Blend, GraphicsPso};
use super::texture::{create_rt_target, transition_barrier, write_format_rtv, write_format_srv};
pub(in crate::directx) const REACTIVE_MASK_FORMAT: DXGI_FORMAT = DXGI_FORMAT_R8_UNORM;
pub(in crate::directx) fn mask_target(pso: GraphicsPso<'_>) -> GraphicsPso<'_> {
pso.target(REACTIVE_MASK_FORMAT, Blend::Max)
}
#[derive(Clone, Copy)]
pub(in crate::directx) struct ReactiveMaskSlots {
pub rtv: D3D12_CPU_DESCRIPTOR_HANDLE,
pub null_rtv: D3D12_CPU_DESCRIPTOR_HANDLE,
pub srv_cpu: D3D12_CPU_DESCRIPTOR_HANDLE,
pub srv_gpu: SrvSlot,
}
pub(in crate::directx) struct ReactiveMask {
pub(in crate::directx) resource: ID3D12Resource,
slots: ReactiveMaskSlots,
}
impl ReactiveMask {
pub(in crate::directx) fn new(
device: &ID3D12Device,
(width, height): (u32, u32),
slots: ReactiveMaskSlots,
) -> RenderResult<Self> {
let null_desc = D3D12_RENDER_TARGET_VIEW_DESC {
Format: REACTIVE_MASK_FORMAT,
ViewDimension: D3D12_RTV_DIMENSION_TEXTURE2D,
..Default::default()
};
unsafe { device.CreateRenderTargetView(None, Some(&null_desc), slots.null_rtv) };
let mut mask = Self {
resource: create_rt_target(device, width, height, REACTIVE_MASK_FORMAT)?,
slots,
};
mask.write_views(device);
Ok(mask)
}
pub(in crate::directx) fn resize(
&mut self,
device: &ID3D12Device,
(width, height): (u32, u32),
) -> RenderResult<()> {
self.resource = create_rt_target(device, width, height, REACTIVE_MASK_FORMAT)?;
self.write_views(device);
Ok(())
}
fn write_views(&mut self, device: &ID3D12Device) {
write_format_rtv(device, &self.resource, self.slots.rtv, REACTIVE_MASK_FORMAT);
write_format_srv(
device,
&self.resource,
self.slots.srv_cpu,
REACTIVE_MASK_FORMAT,
);
}
pub(in crate::directx) fn srv_gpu(&self) -> SrvSlot {
self.slots.srv_gpu
}
pub(in crate::directx) fn rtv(&self, write: ReactiveWrite) -> D3D12_CPU_DESCRIPTOR_HANDLE {
if write.stores() {
self.slots.rtv
} else {
self.slots.null_rtv
}
}
pub(in crate::directx) fn clear(&self, cmd: &ID3D12GraphicsCommandList, write: ReactiveWrite) {
if write == ReactiveWrite::Clear {
unsafe { cmd.ClearRenderTargetView(self.slots.rtv, &[0.0_f32; 4], None) };
}
}
pub(in crate::directx) fn clear_outside_graph(&self, cmd: &ID3D12GraphicsCommandList) {
let to_rt = transition_barrier(
&self.resource,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
);
let to_read = transition_barrier(
&self.resource,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
);
unsafe {
cmd.ResourceBarrier(&[to_rt]);
cmd.ClearRenderTargetView(self.slots.rtv, &[0.0_f32; 4], None);
cmd.ResourceBarrier(&[to_read]);
}
}
pub(in crate::directx) fn rest_after_compute_read(&self, cmd: &ID3D12GraphicsCommandList) {
let back = transition_barrier(
&self.resource,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
);
unsafe { cmd.ResourceBarrier(&[back]) };
}
}