Skip to content

Commit 6dd517d

Browse files
committed
core: Prevent per frame note-label buffer clone for each visible note
1 parent 184e05b commit 6dd517d

2 files changed

Lines changed: 83 additions & 34 deletions

File tree

neothesia-core/src/render/note_labels/mod.rs

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -97,28 +97,28 @@ impl NoteLabels {
9797
let labels = self.labels_cache.get(keyboard);
9898
let animation_speed = animation_speed / scale;
9999

100-
for note in self.notes.inner.iter() {
101-
if !layout.range.contains(note.note) || note.channel == 9 {
102-
continue;
103-
}
104-
105-
let x = layout.keys[note.note as usize - range_start].x();
106-
let label_buffer = &labels[(note.note % 12) as usize];
107-
108-
let y = self.pos.y - (note.start.as_secs_f32() - time) * animation_speed - label_width;
109-
110-
if y < 0.0 {
111-
break;
112-
}
113-
114-
if y > keyboard.pos().y {
115-
continue;
116-
}
117-
118-
self.text_renderer.queue(super::text::TextArea {
119-
buffer: label_buffer.clone(),
120-
left: x,
121-
top: y,
100+
let iter = self
101+
.notes
102+
.inner
103+
.iter()
104+
.filter(|note| layout.range.contains(note.note) && note.channel != 9)
105+
.map(|note| {
106+
let buffer = &labels[(note.note % 12) as usize];
107+
108+
let x = layout.keys[note.note as usize - range_start].x();
109+
let y =
110+
self.pos.y - (note.start.as_secs_f32() - time) * animation_speed - label_width;
111+
112+
(buffer, x, y)
113+
})
114+
// Stop iteration once we reach top of the screen
115+
.take_while(|(_buffer, _x, y)| *y > 0.0)
116+
// TODO: Cache last note idx to skip this NoOp skip iteration
117+
.skip_while(|(_buffer, _x, y)| *y > keyboard.pos().y)
118+
.map(|(buffer, left, top)| glyphon::TextArea {
119+
buffer,
120+
left,
121+
top,
122122
scale: 1.0,
123123
bounds: glyphon::TextBounds {
124124
left: 0,
@@ -127,10 +127,11 @@ impl NoteLabels {
127127
bottom: i32::MAX,
128128
},
129129
default_color: glyphon::Color::rgb(255, 255, 255),
130+
custom_glyphs: &[],
130131
});
131-
}
132132

133-
self.text_renderer.update(physical_size, scale);
133+
self.text_renderer
134+
.update_from_iter(physical_size, scale, iter);
134135
}
135136

136137
pub fn render<'rpass>(&'rpass mut self, render_pass: &mut wgpu_jumpstart::RenderPass<'rpass>) {

neothesia-core/src/render/text/mod.rs

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,61 @@ impl TextRenderer {
183183
self.text_areas.push(area);
184184
}
185185

186+
#[profiling::function]
186187
pub fn update(&mut self, physical_size: dpi::PhysicalSize<u32>, scale: f32) {
187-
let shared = &mut *self.shared.borrow_mut();
188-
189-
let elements = self.text_areas.iter().map(|area| glyphon::TextArea {
188+
let text_areas = self.text_areas.iter().map(|area| glyphon::TextArea {
190189
buffer: &area.buffer,
190+
left: area.left,
191+
top: area.top,
192+
scale: area.scale,
193+
bounds: area.bounds,
194+
default_color: area.default_color,
195+
custom_glyphs: &[],
196+
});
197+
198+
Self::update_from_iter_inner(
199+
&mut self.text_renderer,
200+
&mut self.shared.borrow_mut(),
201+
&self.device,
202+
&self.queue,
203+
physical_size,
204+
scale,
205+
text_areas,
206+
);
207+
208+
self.text_areas.clear();
209+
}
210+
211+
#[profiling::function]
212+
pub fn update_from_iter<'a>(
213+
&mut self,
214+
physical_size: dpi::PhysicalSize<u32>,
215+
scale: f32,
216+
text_areas: impl Iterator<Item = glyphon::TextArea<'a>>,
217+
) {
218+
Self::update_from_iter_inner(
219+
&mut self.text_renderer,
220+
&mut self.shared.borrow_mut(),
221+
&self.device,
222+
&self.queue,
223+
physical_size,
224+
scale,
225+
text_areas,
226+
);
227+
}
228+
229+
#[profiling::function]
230+
fn update_from_iter_inner<'a>(
231+
text_renderer: &mut glyphon::TextRenderer,
232+
shared: &mut TextShared,
233+
device: &wgpu::Device,
234+
queue: &wgpu::Queue,
235+
physical_size: dpi::PhysicalSize<u32>,
236+
scale: f32,
237+
text_areas: impl Iterator<Item = glyphon::TextArea<'a>>,
238+
) {
239+
let elements = text_areas.map(|area| glyphon::TextArea {
240+
buffer: area.buffer,
191241
left: area.left * scale,
192242
top: area.top * scale,
193243
scale: area.scale * scale,
@@ -198,30 +248,28 @@ impl TextRenderer {
198248
bottom: (area.bounds.bottom as f32 * scale) as i32,
199249
},
200250
default_color: area.default_color,
201-
custom_glyphs: &[],
251+
custom_glyphs: area.custom_glyphs,
202252
});
203253

204254
shared.viewport.update(
205-
&self.queue,
255+
queue,
206256
glyphon::Resolution {
207257
width: physical_size.width,
208258
height: physical_size.height,
209259
},
210260
);
211261

212-
self.text_renderer
262+
text_renderer
213263
.prepare(
214-
&self.device,
215-
&self.queue,
264+
device,
265+
queue,
216266
&mut crate::font_system::font_system().borrow_mut(),
217267
&mut shared.atlas,
218268
&shared.viewport,
219269
elements,
220270
&mut shared.swash_cache,
221271
)
222272
.unwrap();
223-
224-
self.text_areas.clear();
225273
}
226274

227275
pub fn render<'rpass>(&'rpass self, render_pass: &mut wgpu_jumpstart::RenderPass<'rpass>) {

0 commit comments

Comments
 (0)