@@ -495,96 +495,114 @@ impl<'tcx> CodegenCx<'tcx> {
495495 . dcx ( )
496496 . span_fatal ( hir_param. ty_span , "pair type not supported yet" )
497497 }
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+ } ;
498523 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) ;
521543
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+ ) ;
531552 }
553+ }
532554
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 ( ) ;
551561
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+ } ;
556573
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 {
557584 match self . lookup_type ( value_spirv_type) {
558585 SpirvType :: RuntimeArray { .. } => {
559586 if is_unsized_with_len {
560587 self . tcx . dcx ( ) . span_err (
561588 hir_param. ty_span ,
562- "uniform_constant must use &RuntimeArray<T>, not &[T]" ,
589+ "descriptor indexing must use &RuntimeArray<T>, not &[T]" ,
563590 ) ;
564591 }
565592 }
566593 _ => {
567594 if is_unsized {
568595 self . tcx . dcx ( ) . span_err (
569596 hir_param. ty_span ,
570- "only plain slices are supported as unsized types" ,
597+ "only RuntimeArray is supported, not other unsized types" ,
571598 ) ;
572599 }
573600 }
574601 }
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".
588606 if is_unsized {
589607 self . tcx . dcx ( ) . span_fatal (
590608 hir_param. ty_span ,
@@ -597,12 +615,19 @@ impl<'tcx> CodegenCx<'tcx> {
597615 ) ,
598616 ) ;
599617 }
600-
601- (
602- var_id. map ( |var_id| var_id. with_type ( var_ptr_spirv_type) ) ,
603- None ,
604- )
605618 }
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+ )
606631 } ;
607632
608633 // Compute call argument(s) to match what the Rust entry `fn` expects,
0 commit comments