Don't allocate memory for PixelRunner every time, ~4ns/pixel.

This commit is contained in:
IQuant 2024-09-27 18:06:16 +03:00
parent b9291ba212
commit b24a004d1f
2 changed files with 18 additions and 9 deletions

View file

@ -39,6 +39,7 @@ extern "C" fn init_particle_world_state(lua: *mut lua_State) -> c_int {
_world_ptr: world_pointer as *mut c_void, _world_ptr: world_pointer as *mut c_void,
chunk_map_ptr: chunk_map_pointer as *mut c_void, chunk_map_ptr: chunk_map_pointer as *mut c_void,
material_list_ptr: material_list_pointer as _, material_list_ptr: material_list_pointer as _,
runner: Default::default(),
}); });
}); });
0 0
@ -52,8 +53,8 @@ extern "C" fn encode_area(lua: *mut lua_State) -> c_int {
let encoded_buffer = unsafe { LUA.lua_tointeger(lua, 5) } as *mut NoitaPixelRun; let encoded_buffer = unsafe { LUA.lua_tointeger(lua, 5) } as *mut NoitaPixelRun;
STATE.with(|state| { STATE.with(|state| {
let state = state.borrow_mut(); let mut state = state.borrow_mut();
let pws = state.particle_world_state.as_ref().unwrap(); let pws = state.particle_world_state.as_mut().unwrap();
let runs = unsafe { pws.encode_area(start_x, start_y, end_x, end_y, encoded_buffer) }; let runs = unsafe { pws.encode_area(start_x, start_y, end_x, end_y, encoded_buffer) };
unsafe { LUA.lua_pushinteger(lua, runs as isize) }; unsafe { LUA.lua_pushinteger(lua, runs as isize) };
}); });

View file

@ -27,7 +27,7 @@ struct PixelRun<Pixel> {
/// Copied from proxy. /// Copied from proxy.
/// Converts a normal sequence of pixels to a run-length-encoded one. /// Converts a normal sequence of pixels to a run-length-encoded one.
struct PixelRunner<Pixel> { pub(crate) struct PixelRunner<Pixel> {
current_pixel: Option<Pixel>, current_pixel: Option<Pixel>,
current_run_len: u32, current_run_len: u32,
runs: Vec<PixelRun<Pixel>>, runs: Vec<PixelRun<Pixel>>,
@ -64,14 +64,20 @@ impl<Pixel: Eq + Copy> PixelRunner<Pixel> {
self.current_run_len = 1; self.current_run_len = 1;
} }
} }
fn build(mut self) -> Vec<PixelRun<Pixel>> { fn build(&mut self) -> &[PixelRun<Pixel>] {
if self.current_run_len > 0 { if self.current_run_len > 0 {
self.runs.push(PixelRun { self.runs.push(PixelRun {
length: self.current_run_len, length: self.current_run_len,
data: self.current_pixel.expect("has current pixel"), data: self.current_pixel.expect("has current pixel"),
}); });
} }
self.runs &mut self.runs
}
fn clear(&mut self) {
self.current_pixel = None;
self.current_run_len = 0;
self.runs.clear();
} }
} }
@ -79,6 +85,8 @@ pub(crate) struct ParticleWorldState {
pub(crate) _world_ptr: *mut c_void, pub(crate) _world_ptr: *mut c_void,
pub(crate) chunk_map_ptr: *mut c_void, pub(crate) chunk_map_ptr: *mut c_void,
pub(crate) material_list_ptr: *const c_void, pub(crate) material_list_ptr: *const c_void,
pub(crate) runner: PixelRunner<RawPixel>,
} }
impl ParticleWorldState { impl ParticleWorldState {
@ -115,14 +123,13 @@ impl ParticleWorldState {
} }
pub(crate) unsafe fn encode_area( pub(crate) unsafe fn encode_area(
&self, &mut self,
start_x: i32, start_x: i32,
start_y: i32, start_y: i32,
end_x: i32, end_x: i32,
end_y: i32, end_y: i32,
pixel_runs: *mut NoitaPixelRun, pixel_runs: *mut NoitaPixelRun,
) -> usize { ) -> usize {
let mut runner = PixelRunner::default();
for y in start_y..end_y { for y in start_y..end_y {
for x in start_x..end_x { for x in start_x..end_x {
let mut raw_pixel = RawPixel { let mut raw_pixel = RawPixel {
@ -148,12 +155,12 @@ impl ParticleWorldState {
ntypes::CellType::Invalid => {} ntypes::CellType::Invalid => {}
} }
} }
runner.put_pixel(raw_pixel); self.runner.put_pixel(raw_pixel);
} }
} }
let mut pixel_runs = pixel_runs; let mut pixel_runs = pixel_runs;
let built_runner = runner.build(); let built_runner = self.runner.build();
let runs = built_runner.len(); let runs = built_runner.len();
for run in built_runner { for run in built_runner {
let noita_pixel_run = pixel_runs.as_mut().unwrap(); let noita_pixel_run = pixel_runs.as_mut().unwrap();
@ -162,6 +169,7 @@ impl ParticleWorldState {
noita_pixel_run.flags = run.data.flags; noita_pixel_run.flags = run.data.flags;
pixel_runs = pixel_runs.offset(1); pixel_runs = pixel_runs.offset(1);
} }
self.runner.clear();
runs runs
} }
} }