@@ -14,7 +14,10 @@ use wgt::{
1414 BindGroupLayoutEntry , BindingType ,
1515} ;
1616
17- use crate :: { device:: bgl, resource:: InvalidResourceError , FastHashMap , FastHashSet } ;
17+ use crate :: {
18+ device:: bgl, resource:: InvalidResourceError ,
19+ validation:: shader_io_deductions:: MaxFragmentShaderInputDeduction , FastHashMap , FastHashSet ,
20+ } ;
1821
1922pub mod shader_io_deductions;
2023
@@ -354,6 +357,32 @@ pub enum StageError {
354357 limit : u32 ,
355358 deductions : Vec < MaxVertexShaderOutputDeduction > ,
356359 } ,
360+ #[ error(
361+ "fragment shader input location Location[{location}] ({var}) exceeds the \
362+ `max_inter_stage_shader_variables` limit ({}, 0-based){}",
363+ // NOTE: Remember: the limit is 0-based for indices.
364+ limit - 1 ,
365+ // NOTE: WebGPU spec. validation for fragment inputs is expressed in terms of variables
366+ // (unlike vertex outputs), so we use `MaxFragmentShaderInputDeduction::for_variables` here
367+ // (and not a non-existent `for_locations`).
368+ display_deductions_as_optional_list( deductions, |d| d. for_variables( ) )
369+ ) ]
370+ FragmentInputLocationTooLarge {
371+ location : u32 ,
372+ var : InterfaceVar ,
373+ limit : u32 ,
374+ deductions : Vec < MaxFragmentShaderInputDeduction > ,
375+ } ,
376+ #[ error(
377+ "found {num_found} user-defined fragment shader input variables, which exceeds the \
378+ `max_inter_stage_shader_variables` limit ({limit}){}",
379+ display_deductions_as_optional_list( deductions, |d| d. for_variables( ) )
380+ ) ]
381+ TooManyUserDefinedFragmentInputs {
382+ num_found : u32 ,
383+ limit : u32 ,
384+ deductions : Vec < MaxFragmentShaderInputDeduction > ,
385+ } ,
357386 #[ error(
358387 "Location[{location}] {var}'s index exceeds the `max_color_attachments` limit ({limit})"
359388 ) ]
@@ -403,6 +432,8 @@ impl WebGpuError for StageError {
403432 | Self :: MultipleEntryPointsFound
404433 | Self :: VertexOutputLocationTooLarge { .. }
405434 | Self :: TooManyUserDefinedVertexOutputs { .. }
435+ | Self :: FragmentInputLocationTooLarge { .. }
436+ | Self :: TooManyUserDefinedFragmentInputs { .. }
406437 | Self :: ColorAttachmentLocationTooLarge { .. }
407438 | Self :: TooManyMeshVertices { .. }
408439 | Self :: TooManyMeshPrimitives { .. }
@@ -1552,6 +1583,62 @@ impl Interface {
15521583 }
15531584 }
15541585 ShaderStageForValidation :: Fragment => {
1586+ let mut max_fragment_shader_input_variables =
1587+ self . limits . max_inter_stage_shader_variables ;
1588+
1589+ let deductions = entry_point. inputs . iter ( ) . filter_map ( |output| match output {
1590+ Varying :: Local { .. } => None ,
1591+ Varying :: BuiltIn ( builtin) => {
1592+ MaxFragmentShaderInputDeduction :: from_inter_stage_builtin ( * builtin) . or_else (
1593+ || {
1594+ unreachable ! (
1595+ concat!(
1596+ "unexpected built-in provided; " ,
1597+ "{:?} is not used for fragment stage input" ,
1598+ ) ,
1599+ builtin
1600+ )
1601+ } ,
1602+ )
1603+ }
1604+ } ) ;
1605+
1606+ for deduction in deductions. clone ( ) {
1607+ // NOTE: Deductions, in the current version of the spec. we implement, do not
1608+ // ever exceed the minimum variables available.
1609+ max_fragment_shader_input_variables = max_fragment_shader_input_variables
1610+ . checked_sub ( deduction. for_variables ( ) )
1611+ . unwrap ( ) ;
1612+ }
1613+
1614+ let mut num_user_defined_inputs = 0 ;
1615+
1616+ for output in entry_point. inputs . iter ( ) {
1617+ match * output {
1618+ Varying :: Local { ref iv, location } => {
1619+ if location >= max_fragment_shader_input_variables {
1620+ return Err ( StageError :: FragmentInputLocationTooLarge {
1621+ location,
1622+ var : iv. clone ( ) ,
1623+ limit : self . limits . max_inter_stage_shader_variables ,
1624+ deductions : deductions. collect ( ) ,
1625+ } ) ;
1626+ }
1627+ num_user_defined_inputs += 1 ;
1628+ inter_stage_components += iv. ty . dim . num_components ( )
1629+ }
1630+ Varying :: BuiltIn ( _) => { }
1631+ } ;
1632+ }
1633+
1634+ if num_user_defined_inputs > max_fragment_shader_input_variables {
1635+ return Err ( StageError :: TooManyUserDefinedFragmentInputs {
1636+ num_found : num_user_defined_inputs,
1637+ limit : self . limits . max_inter_stage_shader_variables ,
1638+ deductions : deductions. collect ( ) ,
1639+ } ) ;
1640+ }
1641+
15551642 for output in & entry_point. outputs {
15561643 let & Varying :: Local { location, ref iv } = output else {
15571644 continue ;
0 commit comments