Skip to content

Commit

Permalink
fixed a bug where re-staging a texture often copied to the wrong layer
Browse files Browse the repository at this point in the history
  • Loading branch information
schell committed Oct 16, 2024
1 parent 163f721 commit a5312b0
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/renderling-ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ ctor = {workspace = true}
env_logger = {workspace = true}
futures-lite = {workspace = true}
img-diff = {path = "../img-diff"}
pretty_assertions.workspace = true
2 changes: 1 addition & 1 deletion crates/renderling-ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub struct ImageId(usize);
/// A two dimensional transformation.
///
/// Clones of `UiTransform` all point to the same data.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct UiTransform {
transform: NestedTransform,
renderlet_ids: Arc<Vec<Id<Renderlet>>>,
Expand Down
60 changes: 59 additions & 1 deletion crates/renderling-ui/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use renderling::{
use crate::{Ui, UiTransform};

// TODO: make UiText able to be updated without fully destroying it

#[derive(Debug)]
pub struct UiText {
pub cache: GlyphCache,
pub vertices: GpuArray<Vertex>,
Expand Down Expand Up @@ -139,6 +139,15 @@ pub struct Cache {
dirty: bool,
}

impl core::fmt::Debug for Cache {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Cache")
.field("img", &(self.img.width(), self.img.height()))
.field("dirty", &self.dirty)
.finish()
}
}

impl Cache {
pub fn new(width: u32, height: u32) -> Cache {
Cache {
Expand All @@ -163,6 +172,7 @@ impl Cache {
}

/// A cache of glyphs.
#[derive(Debug)]
pub struct GlyphCache {
/// Image on the CPU or GPU used as our texture cache
cache: Option<Cache>,
Expand Down Expand Up @@ -432,4 +442,52 @@ mod test {
let depth_img = ui.stage.get_depth_texture().read_image().unwrap();
img_diff::assert_img_eq("ui/text/overlay_depth.png", depth_img);
}

#[test]
fn recreate_text() {
let ctx = Context::headless(50, 50);
let ui = Ui::new(&ctx).with_antialiasing(true);
let _font_id = futures_lite::future::block_on(
ui.load_font("../../fonts/Recursive Mn Lnr St Med Nerd Font Complete.ttf"),
)
.unwrap();
let mut _text = ui
.new_text()
.with_section(
Section::default()
.add_text(
Text::new("60.0 fps")
.with_scale(24.0)
.with_color([1.0, 0.0, 0.0, 1.0]),
)
.with_bounds((50.0, 50.0)),
)
.build();

let frame = ctx.get_next_frame().unwrap();
ui.render(&frame.view());
let img = frame.read_image().unwrap();
frame.present();
img_diff::assert_img_eq("ui/text/can_recreate_0.png", img);

log::info!("replacing text");
_text = ui
.new_text()
.with_section(
Section::default()
.add_text(
Text::new(":)-|<")
.with_scale(24.0)
.with_color([1.0, 0.0, 0.0, 1.0]),
)
.with_bounds((50.0, 50.0)),
)
.build();

let frame = ctx.get_next_frame().unwrap();
ui.render(&frame.view());
let img = frame.read_image().unwrap();
frame.present();
img_diff::assert_img_eq("ui/text/can_recreate_1.png", img);
}
}
6 changes: 3 additions & 3 deletions crates/renderling/src/atlas/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ impl StagedResources {
let new_texture_array = Atlas::create_texture(device, queue, extent)?;
let mut output = vec![];
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("atlas add images"),
label: Some("atlas staging"),
});
let mut temporary_layers = vec![Layer::default(); extent.depth_or_array_layers as usize];
for (layer_index, packed_items) in newly_packed_layers.into_iter().enumerate() {
Expand Down Expand Up @@ -551,7 +551,7 @@ impl StagedResources {
AnotherPacking::Internal(mut texture) => {
let mut t = texture.cache;
debug_assert_eq!(t.size_px, size_px);
log::trace!(" add_images: copying previous frame {t:?}",);
log::trace!(" copying previous frame {t:?}",);
// copy the frame from the old texture to the new texture
// in a new destination
encoder.copy_texture_to_texture(
Expand All @@ -571,7 +571,7 @@ impl StagedResources {
origin: wgpu::Origin3d {
x: offset_px.x,
y: offset_px.y,
z: t.layer_index,
z: layer_index as u32,
},
aspect: wgpu::TextureAspect::All,
},
Expand Down
4 changes: 3 additions & 1 deletion crates/renderling/src/cull/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,9 @@ impl ComputeCopyDepth {

if sample_count_mismatch {
log::info!(
"sample count changed, updating {} bindgroup layout and pipeline",
"sample count changed from {} to {}, updating {} bindgroup layout and pipeline",
self.sample_count,
sample_count,
Self::LABEL.unwrap()
);
self.sample_count = sample_count;
Expand Down
27 changes: 18 additions & 9 deletions crates/renderling/src/slab/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ impl<Buffer: IsBuffer> SlabAllocator<Buffer> {
}

pub(crate) fn insert_update_source(&self, k: usize, source: WeakGpuRef) {
log::trace!("inserting update source {k}",);
log::trace!("slab insert_update_source {k}",);
let _ = self.notifier.0.try_send(k);
// UNWRAP: panic on purpose
self.update_sources.write().unwrap().insert(k, source);
Expand All @@ -328,7 +328,10 @@ impl<Buffer: IsBuffer> SlabAllocator<Buffer> {
let may_range = self.recycles.write().unwrap().remove(T::SLAB_SIZE as u32);
if let Some(range) = may_range {
let id = Id::<T>::new(range.first_index);
log::trace!("dequeued {range:?} to {id:?}");
log::trace!(
"slab allocate {}: dequeued {range:?} to {id:?}",
std::any::type_name::<T>()
);
debug_assert_eq!(
range.last_index,
range.first_index + T::SLAB_SIZE as u32 - 1
Expand All @@ -354,7 +357,10 @@ impl<Buffer: IsBuffer> SlabAllocator<Buffer> {
.remove((T::SLAB_SIZE * len) as u32);
if let Some(range) = may_range {
let array = Array::<T>::new(range.first_index, len as u32);
log::trace!("dequeued {range:?} to {array:?}");
log::trace!(
"slab allocate_array {len}x{}: dequeued {range:?} to {array:?}",
std::any::type_name::<T>()
);
debug_assert_eq!(
range.last_index,
range.first_index + (T::SLAB_SIZE * len) as u32 - 1
Expand Down Expand Up @@ -489,14 +495,16 @@ impl<Buffer: IsBuffer> SlabAllocator<Buffer> {
let count = gpu_ref.weak.strong_count();
if count == 0 {
// recycle this allocation
log::debug!("recycling {key} {:?}", gpu_ref.u32_array);
if gpu_ref.u32_array.is_null() || gpu_ref.u32_array.is_empty() {
log::debug!(" cannot recycle - empty or null");
true
let array = gpu_ref.u32_array;
log::debug!("slab drain_updated_sources: recycling {key} {array:?}");
if array.is_null() {
log::debug!(" cannot recycle, null");
} else if array.is_empty() {
log::debug!(" cannot recycle, empty");
} else {
recycles_guard.add_range(gpu_ref.u32_array.into());
true
}
true
} else {
gpu_ref
.get_update()
Expand Down Expand Up @@ -619,7 +627,7 @@ impl SlabAllocator<wgpu::Buffer> {
}
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct SlabUpdate {
pub array: Array<u32>,
pub elements: Vec<u32>,
Expand Down Expand Up @@ -934,6 +942,7 @@ impl<T: SlabItem + Clone + Send + Sync + 'static> Gpu<T> {
/// Once created, the array cannot be resized.
///
/// Updates are syncronized to the GPU once per frame.
#[derive(Debug)]
pub struct GpuArray<T> {
array: Array<T>,
notifier_index: usize,
Expand Down
Binary file added test_img/ui/text/can_recreate_0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test_img/ui/text/can_recreate_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit a5312b0

Please sign in to comment.