Skip to content

Commit

Permalink
Use an integer texture instead of a storage buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Jan 21, 2024
1 parent 8e25e16 commit 49ac44e
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 35 deletions.
2 changes: 0 additions & 2 deletions bin/boilerplate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ impl Harness {
Terrain::RayTraced { .. } | Terrain::Sliced { .. } | Terrain::Painted { .. } => {
wgpu::Limits {
max_texture_dimension_2d: adapter_limits.max_texture_dimension_2d,
max_storage_buffers_per_shader_stage: 1,
max_storage_buffer_binding_size: terrain_buffer_size,
..wgpu::Limits::downlevel_webgl2_defaults()
}
}
Expand Down
2 changes: 0 additions & 2 deletions lib/ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,6 @@ pub extern "C" fn rv_init(desc: InitDescriptor) -> Option<ptr::NonNull<Context>>

let limits = wgpu::Limits {
max_texture_dimension_2d: adapter_limits.max_texture_dimension_2d,
max_storage_buffers_per_shader_stage: 1,
max_storage_buffer_binding_size: 1 << 28,
..wgpu::Limits::downlevel_webgl2_defaults()
};

Expand Down
11 changes: 3 additions & 8 deletions res/shader/surface.inc.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ struct SurfaceConstants {
terrain_bits: u32, // low 4 bits = shift, high 4 bits = mask
delta_mode: u32, // low 8 bits = power, higher 16 bits = mask
};
struct TerrainData {
inner: array<u32>,
};

@group(1) @binding(0) var<uniform> u_Surface: SurfaceConstants;
@group(1) @binding(2) var<storage, read> b_Terrain: TerrainData;
@group(1) @binding(2) var t_Terrain: texture_2d<u32>;

const c_DoubleLevelMask: u32 = 64u;
const c_ShadowMask: u32 = 128u;
Expand Down Expand Up @@ -50,9 +47,7 @@ fn get_map_coordinates(pos: vec2<f32>) -> vec2<i32> {
fn get_surface_impl(tci: vec2<i32>) -> Surface {
var suf: Surface;

let tc_index = tci.y * i32(u_Surface.texture_scale.x) + tci.x;
let data_raw = b_Terrain.inner[tc_index / 2];
let data = (vec4<u32>(data_raw) >> vec4<u32>(0u, 8u, 16u, 24u)) & vec4<u32>(0xFFu);
let data = textureLoad(t_Terrain, vec2<i32>(tci.x/2, tci.y), 0);
suf.is_shadowed = (data.y & c_ShadowMask) != 0u;
let scale = u_Surface.texture_scale.z / 256.0;

Expand All @@ -74,7 +69,7 @@ fn get_surface_impl(tci: vec2<i32>) -> Surface {
}
suf.mid_alt = f32(mid) * scale;
} else {
let subdata = select(data.xy, data.zw, (tc_index & 1) != 0);
let subdata = select(data.xy, data.zw, (tci.x & 1) != 0);
let altitude = f32(subdata.x) * scale;
let ty = get_terrain_type(subdata.y);
suf.low_type = ty;
Expand Down
72 changes: 49 additions & 23 deletions src/render/terrain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ pub struct Context {
raytrace_geo: Geometry,
kind: Kind,
shadow_kind: ShadowKind,
terrain_buf: wgpu::Buffer,
terrain_texture: wgpu::Texture,
palette_texture: wgpu::Texture,
pub flood: Flood,
pub dirty_rects: Vec<super::DirtyRect>,
Expand Down Expand Up @@ -698,11 +698,18 @@ impl Context {
})
.collect::<Vec<_>>();

let terrain_buf = gfx.device.create_buffer(&wgpu::BufferDescriptor {
let terrain_texture = gfx.device.create_texture(&wgpu::TextureDescriptor {
label: Some("Terrain data"),
size: (extent.width * extent.height) as wgpu::BufferAddress * 2,
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::STORAGE,
mapped_at_creation: false,
size: wgpu::Extent3d {
width: extent.width / 2,
..extent
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Uint,
view_formats: &[],
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
});

let flood_texture = gfx.device.create_texture(&wgpu::TextureDescriptor {
Expand Down Expand Up @@ -792,15 +799,11 @@ impl Context {
// terrain data
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: if supports_vertex_storage {
wgpu::ShaderStages::all()
} else {
wgpu::ShaderStages::FRAGMENT | wgpu::ShaderStages::COMPUTE
},
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
visibility: wgpu::ShaderStages::all(),
ty: wgpu::BindingType::Texture {
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Uint,
multisampled: false,
},
count: None,
},
Expand Down Expand Up @@ -881,7 +884,9 @@ impl Context {
},
wgpu::BindGroupEntry {
binding: 2,
resource: terrain_buf.as_entire_binding(),
resource: wgpu::BindingResource::TextureView(
&terrain_texture.create_view(&wgpu::TextureViewDescriptor::default()),
),
},
wgpu::BindGroupEntry {
binding: 4,
Expand Down Expand Up @@ -1365,7 +1370,7 @@ impl Context {
raytrace_geo,
kind,
shadow_kind,
terrain_buf,
terrain_texture,
palette_texture: palette.texture,
flood: Flood {
texture: flood_texture,
Expand Down Expand Up @@ -1569,6 +1574,8 @@ impl Context {
if !dr.need_upload {
continue;
}
//Note: we are uploading the whole rows currently. We could instead upload
// only the relevant sub-rectangle, but managing `bytes_per_row` becomes annoying.

let total_size =
dr.rect.h as wgpu::BufferAddress * level.size.0 as wgpu::BufferAddress * 2;
Expand All @@ -1588,15 +1595,34 @@ impl Context {
}
}
}
staging_buf.unmap();
encoder.copy_buffer_to_buffer(
&staging_buf,
0,
&self.terrain_buf,
dr.rect.y as wgpu::BufferAddress * level.size.0 as wgpu::BufferAddress * 2,
total_size,

encoder.copy_buffer_to_texture(
wgpu::ImageCopyBuffer {
buffer: &staging_buf,
layout: wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(level.size.0 as u32 * 2),
rows_per_image: None,
},
},
wgpu::ImageCopyTexture {
texture: &self.terrain_texture,
mip_level: 0,
origin: wgpu::Origin3d {
x: 0,
y: dr.rect.y as u32,
z: 0,
},
aspect: wgpu::TextureAspect::All,
},
wgpu::Extent3d {
width: level.size.0 as u32 / 2,
height: dr.rect.h as u32,
depth_or_array_layers: 1,
},
);

staging_buf.unmap();
dr.need_upload = false;
}

Expand Down

0 comments on commit 49ac44e

Please sign in to comment.