Skip to content

Commit f3cb87b

Browse files
authored
render buffer debug label type prepopulation (#22698)
# Objective - The vast majority of our buffers are unlabelled. This makes debugging wgpu errors really annoying, cus they lack context. ## Solution - We have type information, and buffers predominantly are custom struct types, and the few cases in which they arent they seem to be manually named anyways. Let's exploit the type info to populate the buffer names under a debug gate. ## Testing - ran occlusion_culling example with and without the debug feature, it currently crashes due to a wgpu 28 change. ## Showcase Before: ``` Caused by: In a CommandEncoder In a dispatch command, indirect:true Attempted to use Buffer with '' label with conflicting usages. Current usage BufferUses(STORAGE_READ_WRITE) and new usage BufferUses(INDIRECT). BufferUses(STORAGE_READ_WRITE) is an exclusive usage and cannot be used with any other usages within the usage scope (renderpass or compute dispatch). ``` After: ``` Caused by: In a CommandEncoder In a dispatch command, indirect:true Attempted to use Buffer with 'bevy_render::render_resource::buffer_vec::RawBufferVec<bevy_render::batching::gpu_preprocessing::LatePreprocessWorkItemIndirectParameters>' label with conflicting usages. Current usage BufferUses(STORAGE_READ_WRITE) and new usage BufferUses(INDIRECT). BufferUses(STORAGE_READ_WRITE) is an exclusive usage and cannot be used with any other usages within the usage scope (renderpass or compute dispatch). ``` Note that now we know 1. its a `RawBufferVec`, 2. of `LatePreprocessWorkItemIndirectParameters`. This lets us greatly narrow the scope of the search for an offender. Note: this is the evolution of several different attempts at improving debug info. First attempt was with `#[track_caller]`, but that doesn't work in const contexts because Location isnt allowed there. Second attempt was to prepopulate type name info in constructors, but `std::any::type_name()` returns a `&'static str`, and label is `Option<String>`, and `.into()` and `.to_string()` are both not const because `String` is heap allocated. Finally, i moved it to the buffer creation site, and then extracted it into a generic function to deduplicate.
1 parent 95e80be commit f3cb87b

File tree

7 files changed

+33
-10
lines changed

7 files changed

+33
-10
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ statically-linked-dxc = ["bevy_internal/statically-linked-dxc"]
423423
# Forces the wgpu instance to be initialized using the raw Vulkan HAL, enabling additional configuration
424424
raw_vulkan_init = ["bevy_internal/raw_vulkan_init"]
425425

426+
# Pre-populate buffer labels with buffer types for debugging.
427+
type_label_buffers = ["bevy_internal/type_label_buffers"]
428+
426429
# Tracing support, saving a file in Chrome Tracing format
427430
trace_chrome = ["trace", "bevy_internal/trace_chrome"]
428431

crates/bevy_internal/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ statically-linked-dxc = ["bevy_render/statically-linked-dxc"]
6565
# Forces the wgpu instance to be initialized using the raw Vulkan HAL, enabling additional configuration
6666
raw_vulkan_init = ["bevy_render/raw_vulkan_init"]
6767

68+
# Pre-populate buffer labels with buffer types for debugging.
69+
type_label_buffers = ["bevy_render/type_label_buffers"]
70+
6871
# Include tonemapping LUT KTX2 files.
6972
tonemapping_luts = [
7073
"bevy_core_pipeline?/tonemapping_luts",
@@ -438,7 +441,7 @@ gestures = ["bevy_input/gestures"]
438441

439442
hotpatching = ["bevy_app/hotpatching", "bevy_ecs/hotpatching"]
440443

441-
debug = ["bevy_utils/debug", "bevy_ecs/debug"]
444+
debug = ["bevy_utils/debug", "bevy_ecs/debug", "bevy_render/debug"]
442445

443446
screenrecording = ["bevy_dev_tools/screenrecording"]
444447

crates/bevy_render/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ webgpu = ["wgpu/webgpu"]
4545
vulkan-portability = ["wgpu/vulkan-portability"]
4646
gles = ["wgpu/gles"]
4747
detailed_trace = []
48+
# Pre-populate buffer labels with buffer types for debugging.
49+
type_label_buffers = []
50+
# Enables collecting extra information for debugging.
51+
debug = ["type_label_buffers"]
4852
## Adds serialization support through `serde`.
4953
serialize = ["bevy_mesh/serialize"]
5054

crates/bevy_render/src/render_resource/buffer_vec.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ impl<T: NoUninit> RawBufferVec<T> {
158158
if capacity > self.capacity || (self.changed && size > 0) {
159159
self.capacity = capacity;
160160
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
161-
label: self.label.as_deref(),
161+
label: make_buffer_label::<Self>(&self.label),
162162
size: size as BufferAddress,
163163
usage: BufferUsages::COPY_DST | self.buffer_usage,
164164
mapped_at_creation: false,
@@ -406,7 +406,7 @@ where
406406
self.capacity = capacity;
407407
let size = u64::from(T::min_size()) as usize * capacity;
408408
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
409-
label: self.label.as_deref(),
409+
label: make_buffer_label::<Self>(&self.label),
410410
size: size as BufferAddress,
411411
usage: BufferUsages::COPY_DST | self.buffer_usage,
412412
mapped_at_creation: false,
@@ -590,7 +590,7 @@ where
590590
self.capacity = capacity;
591591
let size = self.item_size * capacity;
592592
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
593-
label: self.label.as_deref(),
593+
label: make_buffer_label::<Self>(&self.label),
594594
size: size as BufferAddress,
595595
usage: BufferUsages::COPY_DST | self.buffer_usage,
596596
mapped_at_creation: false,
@@ -620,3 +620,12 @@ pub enum WriteBufferRangeError {
620620
#[error("there are no values to upload")]
621621
NoValuesToUpload,
622622
}
623+
624+
#[inline]
625+
pub(crate) fn make_buffer_label<'a, T>(label: &'a Option<String>) -> Option<&'a str> {
626+
#[cfg(feature = "type_label_buffers")]
627+
if label.is_none() {
628+
return Some(core::any::type_name::<T>());
629+
}
630+
label.as_deref()
631+
}

crates/bevy_render/src/render_resource/storage_buffer.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use core::marker::PhantomData;
22

33
use super::Buffer;
4-
use crate::renderer::{RenderDevice, RenderQueue};
4+
use crate::{
5+
render_resource::make_buffer_label,
6+
renderer::{RenderDevice, RenderQueue},
7+
};
58
use encase::{
69
internal::WriteInto, DynamicStorageBuffer as DynamicStorageBufferWrapper, ShaderType,
710
StorageBuffer as StorageBufferWrapper,
@@ -133,7 +136,7 @@ impl<T: ShaderType + WriteInto> StorageBuffer<T> {
133136

134137
if capacity < size || self.changed {
135138
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
136-
label: self.label.as_deref(),
139+
label: make_buffer_label::<Self>(&self.label),
137140
usage: self.buffer_usage,
138141
contents: self.scratch.as_ref(),
139142
}));
@@ -258,7 +261,7 @@ impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
258261

259262
if capacity < size || (self.changed && size > 0) {
260263
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
261-
label: self.label.as_deref(),
264+
label: make_buffer_label::<Self>(&self.label),
262265
usage: self.buffer_usage,
263266
contents: self.scratch.as_ref(),
264267
}));

crates/bevy_render/src/render_resource/uniform_buffer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::{marker::PhantomData, num::NonZero};
22

33
use crate::{
4-
render_resource::Buffer,
4+
render_resource::{make_buffer_label, Buffer},
55
renderer::{RenderDevice, RenderQueue},
66
};
77
use encase::{
@@ -131,7 +131,7 @@ impl<T: ShaderType + WriteInto> UniformBuffer<T> {
131131

132132
if self.changed || self.buffer.is_none() {
133133
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
134-
label: self.label.as_deref(),
134+
label: make_buffer_label::<Self>(&self.label),
135135
usage: self.buffer_usage,
136136
contents: self.scratch.as_ref(),
137137
}));
@@ -296,7 +296,7 @@ impl<T: ShaderType + WriteInto> DynamicUniformBuffer<T> {
296296

297297
if capacity < size || (self.changed && size > 0) {
298298
let buffer = device.create_buffer(&BufferDescriptor {
299-
label: self.label.as_deref(),
299+
label: make_buffer_label::<Self>(&self.label),
300300
usage: self.buffer_usage,
301301
size,
302302
mapped_at_creation: false,

docs/cargo_features.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ This is the complete `bevy` cargo feature list, without "profiles" or "collectio
189189
|trace_tracy|Tracing support, exposing a port for Tracy|
190190
|trace_tracy_memory|Tracing support, with memory profiling, exposing a port for Tracy|
191191
|track_location|Enables source location tracking for change detection and spawning/despawning, which can assist with debugging|
192+
|type_label_buffers|Pre-populate buffer labels with buffer types for debugging.|
192193
|ui_picking|Provides an implementation for picking UI|
193194
|vorbis|OGG/VORBIS audio format support|
194195
|wav|WAV audio format support|

0 commit comments

Comments
 (0)