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