chunk_builder: single-threaded on wasm (#458)
Refactor the chunk builder to use multithreading on native, but no threads on wasm, at least until we have web workers or wasm threads. With this change and the shader fix, chunks now render on Chrome (albeit with no textures). Another step towards 🕸️ Web support #446. * Single-threaded chunk builder * shaders: chunk_frag: consistently enable outputs, fixes GL_INVALID_OPERATION on WebGL
This commit is contained in:
parent
8208e3b595
commit
fa2e5e8bdb
|
@ -43,7 +43,7 @@ impl ChunkBuilder {
|
|||
let id = i;
|
||||
threads.push((
|
||||
work_send,
|
||||
thread::spawn(move || build_func(id, models, work_recv, built_send)),
|
||||
thread::spawn(move || build_func_threaded(id, models, work_recv, built_send)),
|
||||
));
|
||||
free.push((i, vec![], vec![]));
|
||||
}
|
||||
|
@ -69,32 +69,36 @@ impl ChunkBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
while let Ok((id, mut val)) = self.built_recv.try_recv() {
|
||||
world.reset_building_flag(val.position);
|
||||
if NUM_WORKERS > 0 {
|
||||
while let Ok((id, mut val)) = self.built_recv.try_recv() {
|
||||
world.reset_building_flag(val.position);
|
||||
|
||||
if let Some(sec) = world.get_section_mut(val.position.0, val.position.1, val.position.2)
|
||||
{
|
||||
sec.cull_info = val.cull_info;
|
||||
renderer.update_chunk_solid(
|
||||
&mut sec.render_buffer,
|
||||
&val.solid_buffer,
|
||||
val.solid_count,
|
||||
);
|
||||
renderer.update_chunk_trans(
|
||||
&mut sec.render_buffer,
|
||||
&val.trans_buffer,
|
||||
val.trans_count,
|
||||
);
|
||||
if let Some(sec) =
|
||||
world.get_section_mut(val.position.0, val.position.1, val.position.2)
|
||||
{
|
||||
sec.cull_info = val.cull_info;
|
||||
renderer.update_chunk_solid(
|
||||
&mut sec.render_buffer,
|
||||
&val.solid_buffer,
|
||||
val.solid_count,
|
||||
);
|
||||
renderer.update_chunk_trans(
|
||||
&mut sec.render_buffer,
|
||||
&val.trans_buffer,
|
||||
val.trans_count,
|
||||
);
|
||||
}
|
||||
|
||||
val.solid_buffer.clear();
|
||||
val.trans_buffer.clear();
|
||||
self.free_builders
|
||||
.push((id, val.solid_buffer, val.trans_buffer));
|
||||
}
|
||||
if self.free_builders.is_empty() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
val.solid_buffer.clear();
|
||||
val.trans_buffer.clear();
|
||||
self.free_builders
|
||||
.push((id, val.solid_buffer, val.trans_buffer));
|
||||
}
|
||||
if self.free_builders.is_empty() {
|
||||
return;
|
||||
}
|
||||
let dirty_sections = world
|
||||
.get_render_list()
|
||||
.iter()
|
||||
|
@ -102,22 +106,60 @@ impl ChunkBuilder {
|
|||
.filter(|v| world.is_section_dirty(*v))
|
||||
.collect::<Vec<_>>();
|
||||
for (x, y, z) in dirty_sections {
|
||||
let t_id = self.free_builders.pop().unwrap();
|
||||
let t_id = if NUM_WORKERS > 0 {
|
||||
self.free_builders.pop().unwrap()
|
||||
} else {
|
||||
(0, vec![], vec![])
|
||||
};
|
||||
world.set_building_flag((x, y, z));
|
||||
let (cx, cy, cz) = (x << 4, y << 4, z << 4);
|
||||
let mut snapshot = world.capture_snapshot(cx - 2, cy - 2, cz - 2, 20, 20, 20);
|
||||
snapshot.make_relative(-2, -2, -2);
|
||||
self.threads[t_id.0]
|
||||
.0
|
||||
.send(BuildReq {
|
||||
snapshot,
|
||||
position: (x, y, z),
|
||||
solid_buffer: t_id.1,
|
||||
trans_buffer: t_id.2,
|
||||
})
|
||||
.unwrap();
|
||||
if self.free_builders.is_empty() {
|
||||
return;
|
||||
|
||||
if NUM_WORKERS > 0 {
|
||||
self.threads[t_id.0]
|
||||
.0
|
||||
.send(BuildReq {
|
||||
snapshot,
|
||||
position: (x, y, z),
|
||||
solid_buffer: t_id.1,
|
||||
trans_buffer: t_id.2,
|
||||
})
|
||||
.unwrap();
|
||||
if self.free_builders.is_empty() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
let mut val = build_func_1(
|
||||
self.models.clone(),
|
||||
BuildReq {
|
||||
snapshot,
|
||||
position: (x, y, z),
|
||||
solid_buffer: t_id.1,
|
||||
trans_buffer: t_id.2,
|
||||
},
|
||||
);
|
||||
|
||||
world.reset_building_flag(val.position);
|
||||
|
||||
if let Some(sec) =
|
||||
world.get_section_mut(val.position.0, val.position.1, val.position.2)
|
||||
{
|
||||
sec.cull_info = val.cull_info;
|
||||
renderer.update_chunk_solid(
|
||||
&mut sec.render_buffer,
|
||||
&val.solid_buffer,
|
||||
val.solid_count,
|
||||
);
|
||||
renderer.update_chunk_trans(
|
||||
&mut sec.render_buffer,
|
||||
&val.trans_buffer,
|
||||
val.trans_count,
|
||||
);
|
||||
}
|
||||
|
||||
val.solid_buffer.clear();
|
||||
val.trans_buffer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,130 +181,133 @@ struct BuildReply {
|
|||
cull_info: CullInfo,
|
||||
}
|
||||
|
||||
fn build_func(
|
||||
fn build_func_threaded(
|
||||
id: usize,
|
||||
models: Arc<RwLock<model::Factory>>,
|
||||
work_recv: mpsc::Receiver<BuildReq>,
|
||||
built_send: mpsc::Sender<(usize, BuildReply)>,
|
||||
) {
|
||||
loop {
|
||||
let BuildReq {
|
||||
snapshot,
|
||||
position,
|
||||
mut solid_buffer,
|
||||
mut trans_buffer,
|
||||
} = match work_recv.recv() {
|
||||
let work: BuildReq = match work_recv.recv() {
|
||||
Ok(val) => val,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let mut rng = rand_pcg::Pcg32::from_seed([
|
||||
((position.0 as u32) & 0xff) as u8,
|
||||
(((position.0 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.0 as u32) >> 16) & 0xff) as u8,
|
||||
((position.0 as u32) >> 24) as u8,
|
||||
((position.1 as u32) & 0xff) as u8,
|
||||
(((position.1 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.1 as u32) >> 16) & 0xff) as u8,
|
||||
((position.1 as u32) >> 24) as u8,
|
||||
((position.2 as u32) & 0xff) as u8,
|
||||
(((position.2 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.2 as u32) >> 16) & 0xff) as u8,
|
||||
((position.2 as u32) >> 24) as u8,
|
||||
(((position.0 as u32 ^ position.2 as u32) | 1) & 0xff) as u8,
|
||||
((((position.0 as u32 ^ position.2 as u32) | 1) >> 8) & 0xff) as u8,
|
||||
((((position.0 as u32 ^ position.2 as u32) | 1) >> 16) & 0xff) as u8,
|
||||
(((position.0 as u32 ^ position.2 as u32) | 1) >> 24) as u8,
|
||||
]);
|
||||
let reply = build_func_1(models.clone(), work);
|
||||
|
||||
let mut solid_count = 0;
|
||||
let mut trans_count = 0;
|
||||
built_send.send((id, reply)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
for y in 0..16 {
|
||||
for x in 0..16 {
|
||||
for z in 0..16 {
|
||||
let block = snapshot.get_block(x, y, z);
|
||||
let mat = block.get_material();
|
||||
if !mat.renderable {
|
||||
// Use one step of the rng so that
|
||||
// if a block is placed in an empty
|
||||
// location is variant doesn't change
|
||||
let _: u32 = rng.gen();
|
||||
continue;
|
||||
}
|
||||
fn build_func_1(models: Arc<RwLock<model::Factory>>, work: BuildReq) -> BuildReply {
|
||||
let BuildReq {
|
||||
snapshot,
|
||||
position,
|
||||
mut solid_buffer,
|
||||
mut trans_buffer,
|
||||
} = work;
|
||||
|
||||
match block {
|
||||
block::Block::Water { .. } | block::Block::FlowingWater { .. } => {
|
||||
let tex = models.read().unwrap().textures.clone();
|
||||
trans_count += model::liquid::render_liquid(
|
||||
tex,
|
||||
false,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut trans_buffer,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
block::Block::Lava { .. } | block::Block::FlowingLava { .. } => {
|
||||
let tex = models.read().unwrap().textures.clone();
|
||||
solid_count += model::liquid::render_liquid(
|
||||
tex,
|
||||
true,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut solid_buffer,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut rng = rand_pcg::Pcg32::from_seed([
|
||||
((position.0 as u32) & 0xff) as u8,
|
||||
(((position.0 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.0 as u32) >> 16) & 0xff) as u8,
|
||||
((position.0 as u32) >> 24) as u8,
|
||||
((position.1 as u32) & 0xff) as u8,
|
||||
(((position.1 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.1 as u32) >> 16) & 0xff) as u8,
|
||||
((position.1 as u32) >> 24) as u8,
|
||||
((position.2 as u32) & 0xff) as u8,
|
||||
(((position.2 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.2 as u32) >> 16) & 0xff) as u8,
|
||||
((position.2 as u32) >> 24) as u8,
|
||||
(((position.0 as u32 ^ position.2 as u32) | 1) & 0xff) as u8,
|
||||
((((position.0 as u32 ^ position.2 as u32) | 1) >> 8) & 0xff) as u8,
|
||||
((((position.0 as u32 ^ position.2 as u32) | 1) >> 16) & 0xff) as u8,
|
||||
(((position.0 as u32 ^ position.2 as u32) | 1) >> 24) as u8,
|
||||
]);
|
||||
|
||||
if mat.transparent {
|
||||
trans_count += model::Factory::get_state_model(
|
||||
&models,
|
||||
block,
|
||||
&mut rng,
|
||||
let mut solid_count = 0;
|
||||
let mut trans_count = 0;
|
||||
|
||||
for y in 0..16 {
|
||||
for x in 0..16 {
|
||||
for z in 0..16 {
|
||||
let block = snapshot.get_block(x, y, z);
|
||||
let mat = block.get_material();
|
||||
if !mat.renderable {
|
||||
// Use one step of the rng so that
|
||||
// if a block is placed in an empty
|
||||
// location is variant doesn't change
|
||||
let _: u32 = rng.gen();
|
||||
continue;
|
||||
}
|
||||
|
||||
match block {
|
||||
block::Block::Water { .. } | block::Block::FlowingWater { .. } => {
|
||||
let tex = models.read().unwrap().textures.clone();
|
||||
trans_count += model::liquid::render_liquid(
|
||||
tex,
|
||||
false,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut trans_buffer,
|
||||
);
|
||||
} else {
|
||||
solid_count += model::Factory::get_state_model(
|
||||
&models,
|
||||
block,
|
||||
&mut rng,
|
||||
continue;
|
||||
}
|
||||
block::Block::Lava { .. } | block::Block::FlowingLava { .. } => {
|
||||
let tex = models.read().unwrap().textures.clone();
|
||||
solid_count += model::liquid::render_liquid(
|
||||
tex,
|
||||
true,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut solid_buffer,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if mat.transparent {
|
||||
trans_count += model::Factory::get_state_model(
|
||||
&models,
|
||||
block,
|
||||
&mut rng,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut trans_buffer,
|
||||
);
|
||||
} else {
|
||||
solid_count += model::Factory::get_state_model(
|
||||
&models,
|
||||
block,
|
||||
&mut rng,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut solid_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let cull_info = build_cull_info(&snapshot);
|
||||
let cull_info = build_cull_info(&snapshot);
|
||||
|
||||
built_send
|
||||
.send((
|
||||
id,
|
||||
BuildReply {
|
||||
position,
|
||||
solid_buffer,
|
||||
solid_count,
|
||||
trans_buffer,
|
||||
trans_count,
|
||||
cull_info,
|
||||
},
|
||||
))
|
||||
.unwrap();
|
||||
BuildReply {
|
||||
position,
|
||||
solid_buffer,
|
||||
solid_count,
|
||||
trans_buffer,
|
||||
trans_count,
|
||||
cull_info,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,11 @@ in vec2 vTextureOffset;
|
|||
in float vAtlas;
|
||||
in vec3 vLighting;
|
||||
|
||||
#ifndef alpha
|
||||
#ifdef ES
|
||||
layout(location = 2) out vec4 fragColor;
|
||||
#else
|
||||
out vec4 fragColor;
|
||||
#endif
|
||||
#else
|
||||
|
||||
#ifdef ES
|
||||
layout(location = 0) out vec4 accum;
|
||||
|
@ -22,8 +20,6 @@ out vec4 accum;
|
|||
out float revealage;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include lookup_texture
|
||||
|
||||
void main() {
|
||||
|
|
Loading…
Reference in New Issue