Skip to content

Commit

Permalink
Remove rayon dependency (unneeded)
Browse files Browse the repository at this point in the history
  • Loading branch information
Speykious committed Jan 1, 2024
1 parent 8139816 commit c52c060
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 54 deletions.
16 changes: 8 additions & 8 deletions inox2d-opengl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ use std::ops::Deref;
use gl_buffer::RenderCtxOpenglExt;
use glam::{uvec2, Mat4, UVec2, Vec2, Vec3};
use glow::HasContext;
use inox2d::texture::{parallel_decode_model_textures, TextureId};
use tracing::{debug, error};

use inox2d::math::camera::Camera;
use inox2d::model::{Model, ModelTexture};
use inox2d::nodes::node_data::{BlendMode, Composite, Part};
use inox2d::puppet::Puppet;
use inox2d::render::{InoxRenderer, InoxRendererCommon, NodeRenderCtx, PartRenderCtx};
use inox2d::texture::decode_model_textures;

use self::shader::ShaderCompileError;
use self::shaders::{CompositeMaskShader, CompositeShader, PartMaskShader, PartShader};
Expand All @@ -37,7 +37,7 @@ pub struct GlCache {
pub blend_mode: Option<BlendMode>,
pub program: Option<glow::Program>,
pub vao: Option<glow::VertexArray>,
pub albedo: Option<usize>,
pub albedo: Option<TextureId>,
}

impl GlCache {
Expand Down Expand Up @@ -97,7 +97,7 @@ impl GlCache {
}
}

pub fn update_albedo(&mut self, albedo: usize) -> bool {
pub fn update_albedo(&mut self, albedo: TextureId) -> bool {
if let Some(prev_texture) = self.albedo.replace(albedo) {
prev_texture != albedo
} else {
Expand Down Expand Up @@ -188,11 +188,11 @@ impl OpenglRenderer {

fn upload_model_textures(&mut self, model_textures: &[ModelTexture]) -> Result<(), TextureError> {
// decode textures in parallel
let shalltexs = decode_model_textures(model_textures);
let shalltexs = parallel_decode_model_textures(model_textures.iter(), None);

// upload textures
for (i, shalltex) in shalltexs.iter().enumerate() {
debug!("Uploading shallow texture {}", i);
debug!("Uploading shallow texture {:?}", i);
let tex = texture::Texture::from_shallow_texture(&self.gl, shalltex)?;
self.textures.push(tex);
}
Expand Down Expand Up @@ -302,9 +302,9 @@ impl OpenglRenderer {
}

let gl = &self.gl;
self.textures[part.tex_albedo].bind_on(gl, 0);
self.textures[part.tex_bumpmap].bind_on(gl, 1);
self.textures[part.tex_emissive].bind_on(gl, 2);
self.textures[part.tex_albedo.raw()].bind_on(gl, 0);
self.textures[part.tex_bumpmap.raw()].bind_on(gl, 1);
self.textures[part.tex_emissive.raw()].bind_on(gl, 2);
}

/// Clear the texture cache
Expand Down
10 changes: 5 additions & 5 deletions inox2d-wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use inox2d::model::Model;
use inox2d::nodes::node_data::{InoxData, MaskMode};
use inox2d::puppet::Puppet;
use inox2d::render::RenderCtxKind;
use inox2d::texture::decode_model_textures;

use encase::ShaderType;
use glam::{vec3, Mat4, UVec2, Vec2, Vec3};
use inox2d::texture::parallel_decode_model_textures;
use tracing::warn;
use wgpu::{util::DeviceExt, *};

Expand Down Expand Up @@ -52,7 +52,7 @@ impl Renderer {
..SamplerDescriptor::default()
});

let shalltexs = decode_model_textures(&model.textures);
let shalltexs = parallel_decode_model_textures(model.textures.iter(), None);
for shalltex in &shalltexs {
let texture_size = wgpu::Extent3d {
width: shalltex.width(),
Expand Down Expand Up @@ -167,9 +167,9 @@ impl Renderer {
todo!()
};

render_pass.set_bind_group(1, &self.model_texture_binds[part.tex_albedo], &[]);
render_pass.set_bind_group(2, &self.model_texture_binds[part.tex_emissive], &[]);
render_pass.set_bind_group(3, &self.model_texture_binds[part.tex_bumpmap], &[]);
render_pass.set_bind_group(1, &self.model_texture_binds[part.tex_albedo.raw()], &[]);
render_pass.set_bind_group(2, &self.model_texture_binds[part.tex_emissive.raw()], &[]);
render_pass.set_bind_group(3, &self.model_texture_binds[part.tex_bumpmap.raw()], &[]);

render_pass.set_bind_group(
0,
Expand Down
6 changes: 3 additions & 3 deletions inox2d-wgpu/src/node_bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ fn part_bundle_for_part(
uniform_group,
&[(setup.uniform_alignment_needed * buffers.uniform_index_map[&uuid]) as u32],
);
encoder.set_bind_group(1, &model_texture_binds[part.tex_albedo], &[]);
encoder.set_bind_group(2, &model_texture_binds[part.tex_emissive], &[]);
encoder.set_bind_group(3, &model_texture_binds[part.tex_bumpmap], &[]);
encoder.set_bind_group(1, &model_texture_binds[part.tex_albedo.raw()], &[]);
encoder.set_bind_group(2, &model_texture_binds[part.tex_emissive.raw()], &[]);
encoder.set_bind_group(3, &model_texture_binds[part.tex_bumpmap.raw()], &[]);

let node_rinf = &puppet.render_ctx.node_render_ctxs[&uuid];
if let RenderCtxKind::Part(pinf) = &node_rinf.kind {
Expand Down
1 change: 0 additions & 1 deletion inox2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ image = "0.24.5"
indextree = "4.6.0"
json = "0.12.4"
owo-colors = { version = "3.5.0", optional = true }
rayon = "1.7.0"
thiserror = "1.0.39"
tracing = "0.1.37"

Expand Down
5 changes: 4 additions & 1 deletion inox2d/src/formats/inp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::io::{self, Read};
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::sync::Arc;

use image::ImageFormat;

Expand Down Expand Up @@ -62,13 +63,15 @@ pub fn parse_inp<R: Read>(mut data: R) -> Result<Model, ParseInpError> {
for _ in 0..tex_count {
let tex_length = read_be_u32(&mut data)? as usize;
let tex_encoding = read_u8(&mut data)?;

let format = match tex_encoding {
0 => ImageFormat::Png, // PNG
1 => ImageFormat::Tga, // TGA
2 => return Err(ParseInpError::Bc7NotSupported),
n => return Err(ParseInpError::InvalidTexEncoding(n)),
};
let data = read_vec(&mut data, tex_length)?;

let data: Arc<[u8]> = read_vec(&mut data, tex_length)?.into();
textures.push(ModelTexture { format, data });
}

Expand Down
13 changes: 7 additions & 6 deletions inox2d/src/formats/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::puppet::{
UnknownPuppetAllowedUsersError,
};
use crate::render::RenderCtx;
use crate::texture::TextureId;

use super::json::{JsonError, JsonObject, SerialExtend};

Expand Down Expand Up @@ -111,22 +112,22 @@ fn deserialize_part(obj: &JsonObject) -> InoxParseResult<Part> {
let (tex_albedo, tex_emissive, tex_bumpmap) = {
let textures = obj.get_list("textures")?;

let tex_albedo = match textures.first().ok_or(InoxParseError::NoAlbedoTexture)?.as_number() {
let tex_albedo: usize = match textures.first().ok_or(InoxParseError::NoAlbedoTexture)?.as_number() {
Some(val) => val
.try_into()
.map_err(|_| InoxParseError::JsonError(JsonError::ParseIntError("0".to_owned()).nested("textures")))?,
None => return Err(InoxParseError::NoAlbedoTexture),
};

let tex_emissive = match textures.get(1).and_then(JsonValue::as_number) {
let tex_emissive: usize = match textures.get(1).and_then(JsonValue::as_number) {
Some(val) => (val.try_into())
// Map u32::MAX to nothing
.map(|val| if val == u32::MAX as usize { 0 } else { val })
.map_err(|_| InoxParseError::JsonError(JsonError::ParseIntError("1".to_owned()).nested("textures")))?,
None => 0,
};

let tex_bumpmap = match textures.get(2).and_then(JsonValue::as_number) {
let tex_bumpmap: usize = match textures.get(2).and_then(JsonValue::as_number) {
Some(val) => (val.try_into())
// Map u32::MAX to nothing
.map(|val| if val == u32::MAX as usize { 0 } else { val })
Expand All @@ -140,9 +141,9 @@ fn deserialize_part(obj: &JsonObject) -> InoxParseResult<Part> {
Ok(Part {
draw_state: deserialize_drawable(obj)?,
mesh: vals("mesh", deserialize_mesh(&obj.get_object("mesh")?))?,
tex_albedo,
tex_emissive,
tex_bumpmap,
tex_albedo: TextureId(tex_albedo),
tex_emissive: TextureId(tex_emissive),
tex_bumpmap: TextureId(tex_bumpmap),
})
}

Expand Down
3 changes: 2 additions & 1 deletion inox2d/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::fmt;
use std::sync::Arc;

use crate::puppet::Puppet;

#[derive(Clone, Debug)]
pub struct ModelTexture {
pub format: image::ImageFormat,
pub data: Vec<u8>,
pub data: Arc<[u8]>,
}

#[derive(Clone, Debug)]
Expand Down
7 changes: 4 additions & 3 deletions inox2d/src/nodes/node_data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use glam::Vec3;

use crate::mesh::Mesh;
use crate::texture::TextureId;

use super::node::InoxNodeUuid;
use super::physics::SimplePhysics;
Expand Down Expand Up @@ -123,9 +124,9 @@ impl Drawable {
pub struct Part {
pub draw_state: Drawable,
pub mesh: Mesh,
pub tex_albedo: usize,
pub tex_emissive: usize,
pub tex_bumpmap: usize,
pub tex_albedo: TextureId,
pub tex_emissive: TextureId,
pub tex_bumpmap: TextureId,
}

#[derive(Debug, Clone)]
Expand Down
122 changes: 96 additions & 26 deletions inox2d/src/texture.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
use std::io;
use std::sync::mpsc;

use image::{ImageBuffer, ImageFormat, Rgba};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use image::{ImageBuffer, ImageError, ImageFormat, Rgba};
use tracing::error;

use crate::model::ModelTexture;

use self::tga::{read_tga, TgaImage};
use self::tga::{read_tga, TgaDecodeError, TgaImage};

pub mod tga;

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TextureId(pub(crate) usize);

impl TextureId {
pub fn raw(&self) -> usize {
self.0
}
}

pub struct ShallowTexture {
pixels: Vec<u8>,
width: u32,
Expand Down Expand Up @@ -50,29 +59,90 @@ impl From<ImageBuffer<Rgba<u8>, Vec<u8>>> for ShallowTexture {
}
}

pub fn decode_model_textures(model_textures: &[ModelTexture]) -> Vec<ShallowTexture> {
model_textures
.par_iter()
.filter_map(|mtex| {
if mtex.format == ImageFormat::Tga {
match read_tga(&mut io::Cursor::new(&mtex.data)) {
Ok(img) => Some(ShallowTexture::from(img)),
Err(e) => {
error!("{}", e);
None
}
}
} else {
let img_buf = image::load_from_memory_with_format(&mtex.data, mtex.format);

match img_buf {
Ok(img_buf) => Some(ShallowTexture::from(img_buf.into_rgba8())),
Err(e) => {
error!("{}", e);
None
#[derive(Debug, thiserror::Error)]
enum DecodeTextureError {
#[error("Could not decode TGA texture")]
TgaDecode(
#[from]
#[source]
TgaDecodeError,
),

#[error("Could not decode texture")]
ImageDecode(
#[from]
#[source]
ImageError,
),
}

fn decode_texture(mtex: ModelTexture) -> Result<ShallowTexture, DecodeTextureError> {
if mtex.format == ImageFormat::Tga {
let tga_texture = read_tga(&mut io::Cursor::new(&mtex.data))?;
Ok(ShallowTexture::from(tga_texture))
} else {
let img_buf = image::load_from_memory_with_format(&mtex.data, mtex.format)?;
Ok(ShallowTexture::from(img_buf.into_rgba8()))
}
}

pub fn parallel_decode_model_textures<'a>(
model_textures: impl ExactSizeIterator<Item = &'a ModelTexture>,
n_threads: Option<usize>,
) -> Vec<ShallowTexture> {
// get number of optimal threads from computer
let mut max_num_threads = std::thread::available_parallelism().unwrap().get();

// remove at least one thread to not torture the computer
if max_num_threads > 1 {
max_num_threads -= 1;
}

let mut num_threads = match n_threads {
Some(n_threads) => n_threads.min(max_num_threads),
None => max_num_threads,
};

// do not use more threads than there are images
if num_threads > model_textures.len() {
num_threads = model_textures.len();
}

// use channels to get Rs back from thread computation
let (tx_all, rx_all) = mpsc::channel();

let mut pipes = Vec::with_capacity(num_threads);
for th in 0..num_threads {
// thread-local channel
let (tx, rx) = mpsc::channel::<(usize, ModelTexture)>();

let tx_all = tx_all.clone();
std::thread::Builder::new()
.name(format!("Image Decoder Thread ({})", th))
.spawn(move || {
// get textures from the thread-local channel, decode them, and send them to the global channel
while let Ok((i, texture)) = rx.recv() {
match decode_texture(texture) {
Ok(decoded) => tx_all.send((i, decoded)).unwrap(),
Err(e) => tracing::error!("{}", e),
}
}
}
})
.collect::<Vec<_>>()
})
.unwrap();

pipes.push(tx);
}

let n_model_textures = model_textures.len();

// distribute texture decoding on all threads we make available
for ((i, texture), tx) in model_textures.enumerate().zip(pipes.iter().cycle()) {
// REMINDER: the texture data is behind an arc, so it's not actually being cloned
tx.send((i, texture.clone())).unwrap();
}

let mut decoded = rx_all.into_iter().take(n_model_textures).collect::<Vec<_>>();
decoded.sort_by_key(|&(i, _)| i);

decoded.into_iter().map(|(_, tex)| tex).collect()
}

0 comments on commit c52c060

Please sign in to comment.