@@ -132,6 +132,11 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
132
132
}
133
133
} ;
134
134
135
+ // Count the number of sampler fields needed. We might have to disable
136
+ // bindless if bindless arrays take the GPU over the maximum number of
137
+ // samplers.
138
+ let mut sampler_binding_count = 0 ;
139
+
135
140
// Read field-level attributes
136
141
for field in fields {
137
142
// Search ahead for texture attributes so we can use them with any
@@ -341,6 +346,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
341
346
)
342
347
} ) ;
343
348
349
+ sampler_binding_count += 1 ;
350
+
344
351
binding_layouts. push ( quote ! {
345
352
#render_path:: render_resource:: BindGroupLayoutEntry {
346
353
binding: #binding_index,
@@ -417,6 +424,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
417
424
)
418
425
} ) ;
419
426
427
+ sampler_binding_count += 1 ;
428
+
420
429
binding_layouts. push ( quote ! {
421
430
#render_path:: render_resource:: BindGroupLayoutEntry {
422
431
binding: #binding_index,
@@ -440,11 +449,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
440
449
Some ( _) => {
441
450
quote ! {
442
451
let ( #uniform_binding_type, #uniform_buffer_usages) =
443
- if render_device. features( ) . contains(
444
- #render_path:: settings:: WgpuFeatures :: BUFFER_BINDING_ARRAY |
445
- #render_path:: settings:: WgpuFeatures :: TEXTURE_BINDING_ARRAY
446
- ) && render_device. limits( ) . max_storage_buffers_per_shader_stage > 0 &&
447
- !force_no_bindless {
452
+ if Self :: bindless_supported( render_device) && !force_no_bindless {
448
453
(
449
454
#render_path:: render_resource:: BufferBindingType :: Storage { read_only: true } ,
450
455
#render_path:: render_resource:: BufferUsages :: STORAGE ,
@@ -563,6 +568,17 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
563
568
( prepared_data. clone ( ) , prepared_data)
564
569
} ;
565
570
571
+ // Calculate the number of samplers that we need, so that we don't go over
572
+ // the limit on certain platforms. See
573
+ // https://github.com/bevyengine/bevy/issues/16988.
574
+ let samplers_needed = match attr_bindless_count {
575
+ Some ( Lit :: Int ( ref bindless_count) ) => match bindless_count. base10_parse :: < u32 > ( ) {
576
+ Ok ( bindless_count) => sampler_binding_count * bindless_count,
577
+ Err ( _) => 0 ,
578
+ } ,
579
+ _ => 0 ,
580
+ } ;
581
+
566
582
// Calculate the actual number of bindless slots, taking hardware
567
583
// limitations into account.
568
584
let ( bindless_slot_count, actual_bindless_slot_count_declaration) = match attr_bindless_count {
@@ -571,13 +587,19 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
571
587
fn bindless_slot_count( ) -> Option <u32 > {
572
588
Some ( #bindless_count)
573
589
}
590
+
591
+ fn bindless_supported( render_device: & #render_path:: renderer:: RenderDevice ) -> bool {
592
+ render_device. features( ) . contains(
593
+ #render_path:: settings:: WgpuFeatures :: BUFFER_BINDING_ARRAY |
594
+ #render_path:: settings:: WgpuFeatures :: TEXTURE_BINDING_ARRAY
595
+ ) &&
596
+ render_device. limits( ) . max_storage_buffers_per_shader_stage > 0 &&
597
+ render_device. limits( ) . max_samplers_per_shader_stage >= #samplers_needed
598
+ }
574
599
} ,
575
600
quote ! {
576
- let #actual_bindless_slot_count = if render_device. features( ) . contains(
577
- #render_path:: settings:: WgpuFeatures :: BUFFER_BINDING_ARRAY |
578
- #render_path:: settings:: WgpuFeatures :: TEXTURE_BINDING_ARRAY
579
- ) && render_device. limits( ) . max_storage_buffers_per_shader_stage > 0 &&
580
- !force_no_bindless {
601
+ let #actual_bindless_slot_count = if Self :: bindless_supported( render_device) &&
602
+ !force_no_bindless {
581
603
:: core:: num:: NonZeroU32 :: new( #bindless_count)
582
604
} else {
583
605
None
0 commit comments