diff options
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | source/benoit/benoit/application.rs | 3 | ||||
-rw-r--r-- | source/benoit/benoit/application/initialise.rs | 2 | ||||
-rw-r--r-- | source/benoit/benoit/application/render.rs | 64 | ||||
-rw-r--r-- | source/benoit/benoit/application/render_row.rs | 61 |
5 files changed, 108 insertions, 26 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index c4ddd7d..400b288 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 15 + +* Render using multiple threads + # 14 * Update colouring diff --git a/source/benoit/benoit/application.rs b/source/benoit/benoit/application.rs index 144191e..a203d4c 100644 --- a/source/benoit/benoit/application.rs +++ b/source/benoit/benoit/application.rs @@ -29,6 +29,7 @@ use sdl2::render::WindowCanvas; pub mod initialise; pub mod poll_events; pub mod render; +pub mod render_row; pub mod run; pub struct Application { @@ -36,6 +37,8 @@ pub struct Application { sdl_video: VideoSubsystem, canvas: WindowCanvas, + thread_count: u32, + canvas_width: u32, canvas_height: u32, scale: u32, diff --git a/source/benoit/benoit/application/initialise.rs b/source/benoit/benoit/application/initialise.rs index 9c9cec2..dafaf0e 100644 --- a/source/benoit/benoit/application/initialise.rs +++ b/source/benoit/benoit/application/initialise.rs @@ -41,6 +41,8 @@ impl Application { sdl_video: sdl_video, canvas: canvas, + thread_count: 0x10, + canvas_width: canvas_width, canvas_height: canvas_height, scale: scale, diff --git a/source/benoit/benoit/application/render.rs b/source/benoit/benoit/application/render.rs index f612df2..ec6c582 100644 --- a/source/benoit/benoit/application/render.rs +++ b/source/benoit/benoit/application/render.rs @@ -27,7 +27,10 @@ extern crate sdl2; use sdl2::pixels::Color; use sdl2::rect::Rect; +use std::slice; +use std::thread::{JoinHandle, spawn}; use std::time::Instant; +use std::ptr::addr_of_mut; impl Application { pub fn render(&mut self) { @@ -35,47 +38,56 @@ impl Application { let canvas_size = self.canvas_height * self.canvas_width; - let mut data = Vec::<u32>::with_capacity(canvas_size as usize); + let mut data = vec![0x0; canvas_size as usize]; + + let mut threads = Vec::<JoinHandle<()>>::with_capacity(self.thread_count as usize); let time_start = Instant::now(); - for y in 0x0..self.canvas_height { - for x in 0x0..self.canvas_width { - let canvas_width = self.canvas_width as f64; - let canvas_height = self.canvas_height as f64; + 'render_loop: { + let mut y: u32 = 0x0; + + for _thread in 0x0..self.thread_count { + if y == self.canvas_height { break 'render_loop; } - let ca = (x as f64 - canvas_width / 2.0) / canvas_width * 4.0 / self.zoom + self.position_x; - let cb = (y as f64 - canvas_height / 2.0) / canvas_height * 4.0 / self.zoom + self.position_y; + let slice_start = y as usize * self.canvas_width as usize; + let data_slice = unsafe { slice::from_raw_parts_mut(addr_of_mut!(data[slice_start]), self.canvas_width as usize) }; - let mut za: f64 = 0.0; - let mut zb: f64 = 0.0; + let canvas_width = self.canvas_width; + let canvas_height = self.canvas_height; + let position_x = self.position_x; + let position_y = self.position_y; + let zoom = self.zoom; + let maximum_iteration_count = self.maximum_iteration_count; - let mut iteration_count: u32 = 0x0; - while iteration_count < self.maximum_iteration_count { - let square_distance = (za * za + zb * zb).sqrt(); - if square_distance > 2.0 * 2.0 { break } + threads.push(spawn(move || { Application::render_row(data_slice, y, canvas_width, canvas_height, position_x, position_y, zoom, maximum_iteration_count) })); - { - // z = z^2 + c + y += 0x1; + } - // Complex square: - // a = a^2 - b^2 - // b = 2abi + for y in 0x0..self.canvas_height { + threads.remove(0x0).join(); - let za_temporary = za; - za = za * za - zb * zb + ca; - zb = za_temporary * zb * 2.0 + cb; - } + let slice_start = y as usize * self.canvas_width as usize; + let data_slice = unsafe { slice::from_raw_parts_mut(addr_of_mut!(data[slice_start]), self.canvas_width as usize) }; - iteration_count += 0x1; - } + let canvas_width = self.canvas_width; + let canvas_height = self.canvas_height; + let position_x = self.position_x; + let position_y = self.position_y; + let zoom = self.zoom; + let maximum_iteration_count = self.maximum_iteration_count; - data.push(iteration_count); + threads.push(spawn(move || { Application::render_row(data_slice, y, canvas_width, canvas_height, position_x, position_y, zoom, maximum_iteration_count) })); } } let duration = time_start.elapsed(); + for thread in threads { + thread.join().unwrap(); + } + for pixel in 0x0..canvas_size { let y = pixel as u32 / self.canvas_width; let x = pixel as u32 - y * self.canvas_width; @@ -84,7 +96,7 @@ impl Application { let factor = { let factor = iteration_count as f32 / 64.0 % 1.0; - + (if factor >= 1.0 / 2.0 { 1.0 - factor } else { diff --git a/source/benoit/benoit/application/render_row.rs b/source/benoit/benoit/application/render_row.rs new file mode 100644 index 0000000..80e3646 --- /dev/null +++ b/source/benoit/benoit/application/render_row.rs @@ -0,0 +1,61 @@ +/* + Copyright 2021, 2023 Gabriel Bjørnager Jensen. + + This file is part of Benoit. + + Benoit is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Benoit is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Benoit. + If not, see <https://www.gnu.org/licenses/>. +*/ + +use crate::benoit::application::Application; + +impl Application { + pub fn render_row(data: &mut [u32], y: u32, canvas_width: u32, canvas_height: u32, position_x: f64, position_y: f64, zoom: f64, maximum_iteration_count: u32) { + for x in 0x0..canvas_width { + let canvas_width = canvas_width as f64; + let canvas_height = canvas_height as f64; + + let ca = (x as f64 - canvas_width / 2.0) / canvas_width * 4.0 / zoom + position_x; + let cb = (y as f64 - canvas_height / 2.0) / canvas_height * 4.0 / zoom + position_y; + + let mut za: f64 = 0.0; + let mut zb: f64 = 0.0; + + let mut iteration_count: u32 = 0x0; + while iteration_count < maximum_iteration_count { + let square_distance = za * za + zb * zb; + if square_distance > 2.0 * 2.0 { break } + + { + // z = z^2 + c + + // Complex square: + // a = a^2 - b^2 + // b = 2abi + + let za_temporary = za; + za = za * za - zb * zb + ca; + zb = za_temporary * zb * 2.0 + cb; + } + + iteration_count += 0x1; + } + + data[x as usize] = iteration_count; + } + } +} |