1
1
use crate :: {
2
2
camera:: ExtractedCamera ,
3
3
extract_component:: ExtractComponentPlugin ,
4
- render_resource:: { Buffer , Texture } ,
4
+ render_resource:: { Buffer , BufferSlice , Texture } ,
5
5
renderer:: RenderDevice ,
6
6
texture:: { CachedTexture , TextureFormatPixelInfo } ,
7
7
Render , RenderApp , RenderSet ,
@@ -50,28 +50,21 @@ fn send_buffer_to_main_world(
50
50
return ;
51
51
} ;
52
52
53
- // sync
54
- if false {
55
- let buffer_slice = buffers. entity_buffer . slice ( ..) ;
56
- buffer_slice. map_async ( MapMode :: Read , move |result| {
57
- if let Err ( e) = result {
58
- panic ! ( "MAP ERROR: {e}" ) ;
59
- }
60
- } ) ;
61
-
62
- // WARN This is blocking
63
- render_device. poll ( Maintain :: Wait ) ;
64
-
53
+ // Send the data to the main world
54
+ fn send (
55
+ sender : Sender < GpuPickingData > ,
56
+ padded_bytes_per_row : usize ,
57
+ entity_buffer : & Buffer ,
58
+ buffer_slice : BufferSlice ,
59
+ ) {
65
60
let buffer_view = buffer_slice. get_mapped_range ( ) ;
66
- // we immediately move the data to CPU to avoid holding the mapped view for long
61
+ // immediately copy the data to CPU to avoid holding the mapped view for long
67
62
let entity_data = Vec :: from ( & * buffer_view) ;
68
63
drop ( buffer_view) ;
69
- buffers. entity_buffer . unmap ( ) ;
70
- // drop(entity_buffer);
64
+ entity_buffer. unmap ( ) ;
71
65
72
- // Send the buffer to the main world
73
- if let Err ( err) = gpu_picking_camera. sender . try_send ( GpuPickingData {
74
- padded_bytes_per_row : buffers. buffer_dimensions . padded_bytes_per_row ,
66
+ if let Err ( err) = sender. try_send ( GpuPickingData {
67
+ padded_bytes_per_row,
75
68
entity_data,
76
69
} ) {
77
70
match err {
@@ -81,18 +74,42 @@ fn send_buffer_to_main_world(
81
74
}
82
75
}
83
76
}
77
+
78
+ // This can only fail if the sender is full or closed
79
+ // and we can't do anything if either of those things happen
80
+ // let _ = sender.try_send(GpuPickingData {
81
+ // padded_bytes_per_row,
82
+ // entity_data,
83
+ // });
84
+ }
85
+
86
+ if true {
87
+ // sync
88
+ let buffer_slice = buffers. entity_buffer . slice ( ..) ;
89
+ buffer_slice. map_async ( MapMode :: Read , move |result| match result {
90
+ Ok ( _) => { }
91
+ Err ( err) => bevy_log:: error!( "Failed to map entity buffer: {err}" ) ,
92
+ } ) ;
93
+
94
+ // WARN This is blocking
95
+ render_device. poll ( Maintain :: Wait ) ;
96
+
97
+ // Send the buffer to the main world
98
+ send (
99
+ gpu_picking_camera. sender . clone ( ) ,
100
+ buffers. buffer_dimensions . padded_bytes_per_row ,
101
+ & buffers. entity_buffer ,
102
+ buffer_slice,
103
+ ) ;
84
104
} else {
105
+ // async
85
106
let entity_buffer = buffers. entity_buffer . clone ( ) ;
86
107
let sender = gpu_picking_camera. sender . clone ( ) ;
87
108
let padded_bytes_per_row = buffers. buffer_dimensions . padded_bytes_per_row ;
88
109
89
110
// Mapping the buffer is an asynchronous process.
90
111
// This means we need to wait until the buffer is mapped before sending it to the main world
91
112
let task = async move {
92
- if sender. is_full ( ) {
93
- return ;
94
- }
95
-
96
113
let ( tx, rx) = async_channel:: bounded ( 1 ) ;
97
114
98
115
// map entity buffer
@@ -105,46 +122,35 @@ fn send_buffer_to_main_world(
105
122
// Buffer is mapped and ready to be sent
106
123
rx. recv ( ) . await . unwrap ( ) ;
107
124
108
- let buffer_view = buffer_slice. get_mapped_range ( ) ;
109
- // immediately move the data to CPU to avoid holding the mapped view for long
110
- let entity_data = Vec :: from ( & * buffer_view) ;
111
- drop ( buffer_view) ;
112
- entity_buffer. unmap ( ) ;
113
- drop ( entity_buffer) ;
114
-
115
125
// Send the buffer to the main world
116
- if let Err ( err) = sender. try_send ( GpuPickingData {
117
- padded_bytes_per_row,
118
- entity_data,
119
- } ) {
120
- match err {
121
- TrySendError :: Full ( _) => bevy_log:: error!( "GPU Picking channel is full" ) ,
122
- TrySendError :: Closed ( _) => {
123
- bevy_log:: error!( "GPU Picking channel is closed" ) ;
124
- }
125
- }
126
- }
126
+ send ( sender, padded_bytes_per_row, & entity_buffer, buffer_slice) ;
127
127
} ;
128
128
AsyncComputeTaskPool :: get ( ) . spawn ( task) . detach ( ) ;
129
129
}
130
130
}
131
131
}
132
132
133
+ /// Marker component to indicate that a mesh should be available for gpu picking
133
134
#[ derive( Component , ExtractComponent , Clone ) ]
134
135
pub struct GpuPickingMesh ;
135
136
137
+ /// Data needed in the render world to manage the entity buffer
136
138
#[ derive( Component ) ]
137
139
pub struct ExtractedGpuPickingCamera {
138
140
pub buffers : Option < GpuPickingCameraBuffers > ,
139
141
sender : Sender < GpuPickingData > ,
140
142
}
141
143
144
+ /// Data sent between the render world and main world
142
145
#[ derive( Default ) ]
143
146
struct GpuPickingData {
144
147
padded_bytes_per_row : usize ,
145
148
entity_data : Vec < u8 > ,
146
149
}
147
150
151
+ /// This component is used to indicate if a camera should support gpu picking.
152
+ /// Any mesh with the [`GpuPickingMesh`] component that is visible from this camera
153
+ /// will be pickable.
148
154
#[ derive( Component ) ]
149
155
pub struct GpuPickingCamera {
150
156
channel : ( Sender < GpuPickingData > , Receiver < GpuPickingData > ) ,
@@ -160,7 +166,7 @@ impl Default for GpuPickingCamera {
160
166
impl GpuPickingCamera {
161
167
pub fn new ( ) -> Self {
162
168
Self {
163
- channel : async_channel:: bounded ( 1 ) ,
169
+ channel : async_channel:: unbounded ( ) ,
164
170
data : GpuPickingData :: default ( ) ,
165
171
}
166
172
}
@@ -211,9 +217,10 @@ impl crate::extract_component::ExtractComponent for GpuPickingCamera {
211
217
}
212
218
}
213
219
220
+ /// Contains the buffer and it's dimension required for gpu picking
214
221
pub struct GpuPickingCameraBuffers {
215
222
pub entity_buffer : Buffer ,
216
- pub buffer_dimensions : BufferDimensions ,
223
+ buffer_dimensions : BufferDimensions ,
217
224
}
218
225
219
226
impl GpuPickingCameraBuffers {
@@ -223,6 +230,8 @@ impl GpuPickingCameraBuffers {
223
230
texture : & Texture ,
224
231
buffer : & Buffer ,
225
232
) {
233
+ // This can't be in the Node because it needs access to wgpu but
234
+ // bevy_core_pipeline doesn't depend on wgpu
226
235
encoder. copy_texture_to_buffer (
227
236
texture. as_image_copy ( ) ,
228
237
wgpu:: ImageCopyBuffer {
@@ -275,7 +284,7 @@ pub struct EntityTextures {
275
284
276
285
impl EntityTextures {
277
286
/// This is the color that will represent "no entity" in the entity buffer
278
- pub fn clear_color ( ) -> wgpu:: Color {
287
+ pub fn no_entity_color ( ) -> wgpu:: Color {
279
288
let v = entity_as_uvec2 ( Entity :: PLACEHOLDER ) ;
280
289
// The texture only uses the red and green channel
281
290
Color {
@@ -315,16 +324,13 @@ fn prepare_gpu_picking_buffers(
315
324
for ( entity, camera, mut gpu_picking_camera) in & mut cameras {
316
325
let Some ( size) = camera. physical_target_size else { continue ; } ;
317
326
327
+ // TODO create 2 buffers and altenate between each buffer each frame
328
+
318
329
// Only create a buffer if it doesn't already exist or the size is different
319
- let mut create_buffer = false ;
330
+ let mut create_buffer = true ;
320
331
if let Some ( ( buffer_dimensions, _) ) = buffer_cache. get ( & entity) {
321
- if buffer_dimensions. width != size. x as usize
322
- || buffer_dimensions. height != size. y as usize
323
- {
324
- create_buffer = true ;
325
- }
326
- } else {
327
- create_buffer = true ;
332
+ create_buffer = buffer_dimensions. width != size. x as usize
333
+ || buffer_dimensions. height != size. y as usize ;
328
334
}
329
335
330
336
if create_buffer {
0 commit comments