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,
chunk_map_ptr: chunk_map_pointer as *mut c_void,
material_list_ptr: material_list_pointer as _,
runner: Default::default(),
});
});
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;
STATE.with(|state| {
let state = state.borrow_mut();
let pws = state.particle_world_state.as_ref().unwrap();
let mut state = state.borrow_mut();
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) };
unsafe { LUA.lua_pushinteger(lua, runs as isize) };
});

View file

@ -27,7 +27,7 @@ struct PixelRun<Pixel> {
/// Copied from proxy.
/// 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_run_len: u32,
runs: Vec<PixelRun<Pixel>>,
@ -64,14 +64,20 @@ impl<Pixel: Eq + Copy> PixelRunner<Pixel> {
self.current_run_len = 1;
}
}
fn build(mut self) -> Vec<PixelRun<Pixel>> {
fn build(&mut self) -> &[PixelRun<Pixel>] {
if self.current_run_len > 0 {
self.runs.push(PixelRun {
length: self.current_run_len,
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) chunk_map_ptr: *mut c_void,
pub(crate) material_list_ptr: *const c_void,
pub(crate) runner: PixelRunner<RawPixel>,
}
impl ParticleWorldState {
@ -115,14 +123,13 @@ impl ParticleWorldState {
}
pub(crate) unsafe fn encode_area(
&self,
&mut self,
start_x: i32,
start_y: i32,
end_x: i32,
end_y: i32,
pixel_runs: *mut NoitaPixelRun,
) -> usize {
let mut runner = PixelRunner::default();
for y in start_y..end_y {
for x in start_x..end_x {
let mut raw_pixel = RawPixel {
@ -148,12 +155,12 @@ impl ParticleWorldState {
ntypes::CellType::Invalid => {}
}
}
runner.put_pixel(raw_pixel);
self.runner.put_pixel(raw_pixel);
}
}
let mut pixel_runs = pixel_runs;
let built_runner = runner.build();
let built_runner = self.runner.build();
let runs = built_runner.len();
for run in built_runner {
let noita_pixel_run = pixel_runs.as_mut().unwrap();
@ -162,6 +169,7 @@ impl ParticleWorldState {
noita_pixel_run.flags = run.data.flags;
pixel_runs = pixel_runs.offset(1);
}
self.runner.clear();
runs
}
}