@@ -495,96 +495,114 @@ impl<'tcx> CodegenCx<'tcx> {
495
495
. dcx ( )
496
496
. span_fatal ( hir_param. ty_span , "pair type not supported yet" )
497
497
}
498
+ // FIXME(eddyb) should this talk about "typed buffers" instead of "interface blocks"?
499
+ // FIXME(eddyb) should we talk about "descriptor indexing" or
500
+ // actually use more reasonable terms like "resource arrays"?
501
+ let needs_interface_block_and_supports_descriptor_indexing = matches ! (
502
+ storage_class,
503
+ Ok ( StorageClass :: Uniform | StorageClass :: StorageBuffer )
504
+ ) ;
505
+ let needs_interface_block = needs_interface_block_and_supports_descriptor_indexing
506
+ || storage_class == Ok ( StorageClass :: PushConstant ) ;
507
+ // NOTE(eddyb) `#[spirv(typed_buffer)]` adds `SpirvType::InterfaceBlock`s
508
+ // which must bypass the automated ones (i.e. the user is taking control).
509
+ let has_explicit_interface_block = needs_interface_block_and_supports_descriptor_indexing
510
+ && {
511
+ // Peel off arrays first (used for "descriptor indexing").
512
+ let outermost_or_array_element = match self . lookup_type ( value_spirv_type) {
513
+ SpirvType :: Array { element, .. } | SpirvType :: RuntimeArray { element } => {
514
+ element
515
+ }
516
+ _ => value_spirv_type,
517
+ } ;
518
+ matches ! (
519
+ self . lookup_type( outermost_or_array_element) ,
520
+ SpirvType :: InterfaceBlock { .. }
521
+ )
522
+ } ;
498
523
let var_ptr_spirv_type;
499
- let ( value_ptr, value_len) = match storage_class {
500
- Ok (
501
- StorageClass :: PushConstant | StorageClass :: Uniform | StorageClass :: StorageBuffer ,
502
- ) => {
503
- let var_spirv_type = SpirvType :: InterfaceBlock {
504
- inner_type : value_spirv_type,
505
- }
506
- . def ( hir_param. span , self ) ;
507
- var_ptr_spirv_type = self . type_ptr_to ( var_spirv_type) ;
508
-
509
- let zero_u32 = self . constant_u32 ( hir_param. span , 0 ) . def_cx ( self ) ;
510
- let value_ptr_spirv_type = self . type_ptr_to ( value_spirv_type) ;
511
- let value_ptr = bx
512
- . emit ( )
513
- . in_bounds_access_chain (
514
- value_ptr_spirv_type,
515
- None ,
516
- var_id. unwrap ( ) ,
517
- [ zero_u32] . iter ( ) . cloned ( ) ,
518
- )
519
- . unwrap ( )
520
- . with_type ( value_ptr_spirv_type) ;
524
+ let ( value_ptr, value_len) = if needs_interface_block && !has_explicit_interface_block {
525
+ let var_spirv_type = SpirvType :: InterfaceBlock {
526
+ inner_type : value_spirv_type,
527
+ }
528
+ . def ( hir_param. span , self ) ;
529
+ var_ptr_spirv_type = self . type_ptr_to ( var_spirv_type) ;
530
+
531
+ let zero_u32 = self . constant_u32 ( hir_param. span , 0 ) . def_cx ( self ) ;
532
+ let value_ptr_spirv_type = self . type_ptr_to ( value_spirv_type) ;
533
+ let value_ptr = bx
534
+ . emit ( )
535
+ . in_bounds_access_chain (
536
+ value_ptr_spirv_type,
537
+ None ,
538
+ var_id. unwrap ( ) ,
539
+ [ zero_u32] . iter ( ) . cloned ( ) ,
540
+ )
541
+ . unwrap ( )
542
+ . with_type ( value_ptr_spirv_type) ;
521
543
522
- let value_len = if is_unsized_with_len {
523
- match self . lookup_type ( value_spirv_type) {
524
- SpirvType :: RuntimeArray { .. } => { }
525
- _ => {
526
- self . tcx . dcx ( ) . span_err (
527
- hir_param. ty_span ,
528
- "only plain slices are supported as unsized types" ,
529
- ) ;
530
- }
544
+ let value_len = if is_unsized_with_len {
545
+ match self . lookup_type ( value_spirv_type) {
546
+ SpirvType :: RuntimeArray { .. } => { }
547
+ _ => {
548
+ self . tcx . dcx ( ) . span_err (
549
+ hir_param. ty_span ,
550
+ "only plain slices are supported as unsized types" ,
551
+ ) ;
531
552
}
553
+ }
532
554
533
- // FIXME(eddyb) shouldn't this be `usize`?
534
- let len_spirv_type = self . type_isize ( ) ;
535
- let len = bx
536
- . emit ( )
537
- . array_length ( len_spirv_type, None , var_id. unwrap ( ) , 0 )
538
- . unwrap ( ) ;
539
-
540
- Some ( len. with_type ( len_spirv_type) )
541
- } else {
542
- if is_unsized {
543
- // It's OK to use a RuntimeArray<u32> and not have a length parameter, but
544
- // it's just nicer ergonomics to use a slice.
545
- self . tcx
546
- . dcx ( )
547
- . span_warn ( hir_param. ty_span , "use &[T] instead of &RuntimeArray<T>" ) ;
548
- }
549
- None
550
- } ;
555
+ // FIXME(eddyb) shouldn't this be `usize`?
556
+ let len_spirv_type = self . type_isize ( ) ;
557
+ let len = bx
558
+ . emit ( )
559
+ . array_length ( len_spirv_type, None , var_id. unwrap ( ) , 0 )
560
+ . unwrap ( ) ;
551
561
552
- ( Ok ( value_ptr) , value_len)
553
- }
554
- Ok ( StorageClass :: UniformConstant ) => {
555
- var_ptr_spirv_type = self . type_ptr_to ( value_spirv_type) ;
562
+ Some ( len. with_type ( len_spirv_type) )
563
+ } else {
564
+ if is_unsized {
565
+ // It's OK to use a RuntimeArray<u32> and not have a length parameter, but
566
+ // it's just nicer ergonomics to use a slice.
567
+ self . tcx
568
+ . dcx ( )
569
+ . span_warn ( hir_param. ty_span , "use &[T] instead of &RuntimeArray<T>" ) ;
570
+ }
571
+ None
572
+ } ;
556
573
574
+ ( Ok ( value_ptr) , value_len)
575
+ } else {
576
+ var_ptr_spirv_type = self . type_ptr_to ( value_spirv_type) ;
577
+
578
+ // FIXME(eddyb) should we talk about "descriptor indexing" or
579
+ // actually use more reasonable terms like "resource arrays"?
580
+ let unsized_is_descriptor_indexing =
581
+ needs_interface_block_and_supports_descriptor_indexing
582
+ || storage_class == Ok ( StorageClass :: UniformConstant ) ;
583
+ if unsized_is_descriptor_indexing {
557
584
match self . lookup_type ( value_spirv_type) {
558
585
SpirvType :: RuntimeArray { .. } => {
559
586
if is_unsized_with_len {
560
587
self . tcx . dcx ( ) . span_err (
561
588
hir_param. ty_span ,
562
- "uniform_constant must use &RuntimeArray<T>, not &[T]" ,
589
+ "descriptor indexing must use &RuntimeArray<T>, not &[T]" ,
563
590
) ;
564
591
}
565
592
}
566
593
_ => {
567
594
if is_unsized {
568
595
self . tcx . dcx ( ) . span_err (
569
596
hir_param. ty_span ,
570
- "only plain slices are supported as unsized types" ,
597
+ "only RuntimeArray is supported, not other unsized types" ,
571
598
) ;
572
599
}
573
600
}
574
601
}
575
-
576
- let value_len = if is_pair {
577
- // We've already emitted an error, fill in a placeholder value
578
- Some ( bx. undef ( self . type_isize ( ) ) )
579
- } else {
580
- None
581
- } ;
582
-
583
- ( Ok ( var_id. unwrap ( ) . with_type ( var_ptr_spirv_type) ) , value_len)
584
- }
585
- _ => {
586
- var_ptr_spirv_type = self . type_ptr_to ( value_spirv_type) ;
587
-
602
+ } else {
603
+ // FIXME(eddyb) determine, based on the type, what kind of type
604
+ // this is, to narrow it further to e.g. "buffer in a non-buffer
605
+ // storage class" or "storage class expects fixed data sizes".
588
606
if is_unsized {
589
607
self . tcx . dcx ( ) . span_fatal (
590
608
hir_param. ty_span ,
@@ -597,12 +615,19 @@ impl<'tcx> CodegenCx<'tcx> {
597
615
) ,
598
616
) ;
599
617
}
600
-
601
- (
602
- var_id. map ( |var_id| var_id. with_type ( var_ptr_spirv_type) ) ,
603
- None ,
604
- )
605
618
}
619
+
620
+ let value_len = if is_pair {
621
+ // We've already emitted an error, fill in a placeholder value
622
+ Some ( bx. undef ( self . type_isize ( ) ) )
623
+ } else {
624
+ None
625
+ } ;
626
+
627
+ (
628
+ var_id. map ( |var_id| var_id. with_type ( var_ptr_spirv_type) ) ,
629
+ value_len,
630
+ )
606
631
} ;
607
632
608
633
// Compute call argument(s) to match what the Rust entry `fn` expects,
0 commit comments