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