use concinnity_core::render::backend::{GeometryEdit, SceneHost};
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::scene_state::{GeometryBuffer, GeometryWriter, SceneState};
use windows::Win32::Graphics::Direct3D12::*;
use super::super::allocator::DeviceAllocator;
use super::super::context::*;
use super::super::geometry_upload::{GeometryTarget, GeometryUploads};
use super::super::texture::{one_shot_submit, transition_barrier};
use crate::directx::error::map_hresult;
struct StagingWriter<'a> {
alloc: &'a DeviceAllocator,
uploads: &'a mut GeometryUploads,
}
impl GeometryWriter for StagingWriter<'_> {
fn write(&mut self, buffer: GeometryBuffer, offset: usize, bytes: &[u8]) -> RenderResult<()> {
let target = match buffer {
GeometryBuffer::Vertex => GeometryTarget::Vertex,
GeometryBuffer::Index => GeometryTarget::Index,
};
self.uploads.stage(self.alloc, target, offset as u64, bytes)
}
fn reserve(&mut self, bytes: u64) {
if let Err(e) = self.uploads.reserve(self.alloc, bytes) {
tracing::warn!("mesh streaming: geometry staging reserve failed: {e}");
}
}
}
impl SceneHost for DxContext {
fn scene(&self) -> Option<&SceneState> {
Some(&self.state)
}
fn scene_mut(&mut self) -> Option<&mut SceneState> {
debug_assert_main_thread("scene_mut");
Some(&mut self.state)
}
fn edit_geometry(&mut self, edit: GeometryEdit<'_>) -> Option<RenderResult<()>> {
debug_assert_main_thread("edit_geometry");
let mut writer = StagingWriter {
alloc: &self.hw.alloc,
uploads: self.geometry_uploads.get_mut(),
};
Some(edit(&mut self.state, &mut writer))
}
}
impl DxContext {
pub(in crate::directx) fn write_geometry_region(
&self,
dest: &ID3D12Resource,
usage_state: D3D12_RESOURCE_STATES,
offset: u64,
data: &[u8],
) -> RenderResult<()> {
if data.is_empty() {
return Ok(());
}
let upload = self.hw.alloc.alloc_buffer(
data.len() as u64,
D3D12_HEAP_TYPE_UPLOAD,
D3D12_RESOURCE_STATE_GENERIC_READ,
)?;
let mut ptr = std::ptr::null_mut::<std::ffi::c_void>();
unsafe { upload.Map(0, None, Some(&mut ptr)) }
.map_err(|e| map_hresult(e.code(), "mesh region map"))?;
unsafe {
std::ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len());
upload.Unmap(0, None);
}
one_shot_submit(&self.hw.device, &self.hw.command_queue, |cmd| unsafe {
let to_dst = transition_barrier(dest, usage_state, D3D12_RESOURCE_STATE_COPY_DEST);
cmd.ResourceBarrier(&[to_dst]);
cmd.CopyBufferRegion(dest, offset, &*upload, 0, data.len() as u64);
let back = transition_barrier(dest, D3D12_RESOURCE_STATE_COPY_DEST, usage_state);
cmd.ResourceBarrier(&[back]);
})
}
}