@@ -126,35 +126,68 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec<ShaderTest>
126126 // - Do `input.member[0].x` (direct)
127127 // - Store `input.member[0]` in a variable; do `var.x` (vector_loaded)
128128 // - Store `input.member` in a variable; do `var[0].x` (fully_loaded)
129- let mut direct = String :: new ( ) ;
130- let mut vector_loaded = String :: new ( ) ;
131- let mut fully_loaded = String :: from ( "let loaded = input.member;" ) ;
132- for column in 0 ..columns {
133- writeln ! ( vector_loaded, "let vec_{column} = input.member[{column}];" ) . unwrap ( ) ;
129+ // For each of these, we can either use a static or dynamic index.
130+ let mut direct_static = String :: new ( ) ;
131+ let mut direct_dynamic = String :: new ( ) ;
132+ let mut vector_loaded_static = String :: new ( ) ;
133+ let mut vector_loaded_dynamic = String :: new ( ) ;
134+ let mut fully_loaded_static = String :: from ( "let loaded = input.member;" ) ;
135+ let mut fully_loaded_dynamic = String :: from ( "let loaded = input.member;" ) ;
136+ let column_index_names = [ "zero" , "one" , "two" , "three" ] ;
137+ for ( column, column_str) in column_index_names. iter ( ) . enumerate ( ) . take ( columns) {
138+ writeln ! ( direct_dynamic, "var {column_str} = {column};" ) . unwrap ( ) ;
139+ writeln ! ( vector_loaded_dynamic, "var {column_str} = {column};" ) . unwrap ( ) ;
140+ writeln ! ( fully_loaded_dynamic, "var {column_str} = {column};" ) . unwrap ( ) ;
141+
142+ writeln ! (
143+ vector_loaded_static,
144+ "let vec_{column} = input.member[{column}];"
145+ )
146+ . unwrap ( ) ;
147+ writeln ! (
148+ vector_loaded_dynamic,
149+ "let vec_{column} = input.member[{column_str}];" ,
150+ )
151+ . unwrap ( ) ;
134152 }
135153
136154 let mut output_values = Vec :: new ( ) ;
137155
138156 let mut current_output_idx = 0 ;
139157 let mut current_input_idx = 0 ;
140- for column in 0 .. columns {
158+ for ( column, column_str ) in column_index_names . iter ( ) . enumerate ( ) . take ( columns) {
141159 let component_accessors = [ "x" , "y" , "z" , "w" ] . into_iter ( ) . take ( rows) ;
142160 for component in component_accessors {
143161 writeln ! (
144- direct ,
162+ direct_static ,
145163 "output[{current_output_idx}] = bitcast<u32>(input.member[{column}].{component});"
146164 )
147165 . unwrap ( ) ;
148166 writeln ! (
149- vector_loaded,
167+ direct_dynamic,
168+ "output[{current_output_idx}] = bitcast<u32>(input.member[{column_str}].{component});"
169+ )
170+ . unwrap ( ) ;
171+ writeln ! (
172+ vector_loaded_static,
173+ "output[{current_output_idx}] = bitcast<u32>(vec_{column}.{component});"
174+ )
175+ . unwrap ( ) ;
176+ writeln ! (
177+ vector_loaded_dynamic,
150178 "output[{current_output_idx}] = bitcast<u32>(vec_{column}.{component});"
151179 )
152180 . unwrap ( ) ;
153181 writeln ! (
154- fully_loaded ,
182+ fully_loaded_static ,
155183 "output[{current_output_idx}] = bitcast<u32>(loaded[{column}].{component});"
156184 )
157185 . unwrap ( ) ;
186+ writeln ! (
187+ fully_loaded_dynamic,
188+ "output[{current_output_idx}] = bitcast<u32>(loaded[{column_str}].{component});"
189+ )
190+ . unwrap ( ) ;
158191
159192 output_values. push ( current_input_idx) ;
160193 current_input_idx += 1 ;
@@ -175,9 +208,202 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec<ShaderTest>
175208
176209 tests. push (
177210 ShaderTest :: new (
178- format ! ( "{ty} - direct" ) ,
211+ format ! ( "{ty} - direct, static index " ) ,
179212 input_members. clone ( ) ,
180- direct,
213+ direct_static,
214+ & input_values,
215+ & output_values,
216+ )
217+ . failures ( failures) ,
218+ ) ;
219+ tests. push (
220+ ShaderTest :: new (
221+ format ! ( "{ty} - direct, dynamic index" ) ,
222+ input_members. clone ( ) ,
223+ direct_dynamic,
224+ & input_values,
225+ & output_values,
226+ )
227+ . failures ( failures) ,
228+ ) ;
229+
230+ tests. push (
231+ ShaderTest :: new (
232+ format ! ( "{ty} - vector loaded, static index" ) ,
233+ input_members. clone ( ) ,
234+ vector_loaded_static,
235+ & input_values,
236+ & output_values,
237+ )
238+ . failures ( failures) ,
239+ ) ;
240+ tests. push (
241+ ShaderTest :: new (
242+ format ! ( "{ty} - vector loaded, dynamic index" ) ,
243+ input_members. clone ( ) ,
244+ vector_loaded_dynamic,
245+ & input_values,
246+ & output_values,
247+ )
248+ . failures ( failures) ,
249+ ) ;
250+
251+ tests. push (
252+ ShaderTest :: new (
253+ format ! ( "{ty} - fully loaded, static index" ) ,
254+ input_members. clone ( ) ,
255+ fully_loaded_static,
256+ & input_values,
257+ & output_values,
258+ )
259+ . failures ( failures) ,
260+ ) ;
261+ tests. push (
262+ ShaderTest :: new (
263+ format ! ( "{ty} - fully loaded, dynamic index" ) ,
264+ input_members. clone ( ) ,
265+ fully_loaded_dynamic,
266+ & input_values,
267+ & output_values,
268+ )
269+ . failures ( failures) ,
270+ ) ;
271+ }
272+ }
273+
274+ // Array of matrix tests
275+ for columns in [ 2 , 4 ] {
276+ for rows in [ 2 , 3 , 4 ] {
277+ let array_size = 2 ;
278+ let ty = format ! ( "mat{columns}x{rows}<f32>" ) ;
279+ let input_members = format ! ( "members: array<{ty}, {array_size}>" ) ;
280+ // There's 4 possible ways to load a component of a matrix in an array:
281+ // - Do `input.members[0][0].x` (direct)
282+ // - Store `input.members[0][0]` in a variable; do `var.x` (vector_loaded)
283+ // - Store `input.members[0]` in a variable; do `var[0].x` (matrix_loaded)
284+ // - Store `input.members` in a variable; do `var[0][0].x` (fully_loaded)
285+ // For each of these, we can either use a static or dynamic index.
286+ let mut direct_static = String :: new ( ) ;
287+ let mut direct_dynamic = String :: new ( ) ;
288+ let mut vector_loaded_static = String :: new ( ) ;
289+ let mut vector_loaded_dynamic = String :: new ( ) ;
290+ let mut matrix_loaded_static = String :: new ( ) ;
291+ let mut matrix_loaded_dynamic = String :: new ( ) ;
292+ let mut fully_loaded_static = String :: from ( "let loaded = input.members;" ) ;
293+ let mut fully_loaded_dynamic = String :: from ( "let loaded = input.members;" ) ;
294+ let column_index_names = [ "zero" , "one" , "two" , "three" ] ;
295+ for ( column, column_str) in column_index_names. iter ( ) . enumerate ( ) . take ( columns) {
296+ writeln ! ( direct_dynamic, "var {column_str} = {column};" ) . unwrap ( ) ;
297+ writeln ! ( vector_loaded_dynamic, "var {column_str} = {column};" ) . unwrap ( ) ;
298+ writeln ! ( matrix_loaded_dynamic, "var {column_str} = {column};" ) . unwrap ( ) ;
299+ }
300+ for element in 0 ..array_size {
301+ writeln ! (
302+ matrix_loaded_static,
303+ "let mat_{element} = input.members[{element}];"
304+ )
305+ . unwrap ( ) ;
306+ writeln ! (
307+ matrix_loaded_dynamic,
308+ "let mat_{element} = input.members[{element}];"
309+ )
310+ . unwrap ( ) ;
311+ for ( column, column_str) in column_index_names. iter ( ) . enumerate ( ) . take ( columns) {
312+ writeln ! (
313+ vector_loaded_static,
314+ "let mat_{element}_vec_{column} = input.members[{element}][{column}];"
315+ )
316+ . unwrap ( ) ;
317+ writeln ! (
318+ vector_loaded_dynamic,
319+ "let mat_{element}_vec_{column} = input.members[{element}][{column_str}];" ,
320+ )
321+ . unwrap ( ) ;
322+ }
323+ }
324+
325+ let mut output_values = Vec :: new ( ) ;
326+
327+ let mut current_output_idx = 0 ;
328+ let mut current_input_idx = 0 ;
329+ for element in 0 ..array_size {
330+ for ( column, column_str) in column_index_names. iter ( ) . enumerate ( ) . take ( columns) {
331+ let component_accessors = [ "x" , "y" , "z" , "w" ] . into_iter ( ) . take ( rows) ;
332+ for component in component_accessors {
333+ writeln ! (
334+ direct_static,
335+ "output[{current_output_idx}] = bitcast<u32>(input.members[{element}][{column}].{component});"
336+ )
337+ . unwrap ( ) ;
338+ writeln ! (
339+ direct_dynamic,
340+ "output[{current_output_idx}] = bitcast<u32>(input.members[{element}][{column_str}].{component});"
341+ )
342+ . unwrap ( ) ;
343+ writeln ! (
344+ vector_loaded_static,
345+ "output[{current_output_idx}] = bitcast<u32>(mat_{element}_vec_{column}.{component});"
346+ )
347+ . unwrap ( ) ;
348+ writeln ! (
349+ vector_loaded_dynamic,
350+ "output[{current_output_idx}] = bitcast<u32>(mat_{element}_vec_{column}.{component});"
351+ )
352+ . unwrap ( ) ;
353+ writeln ! (
354+ matrix_loaded_static,
355+ "output[{current_output_idx}] = bitcast<u32>(mat_{element}[{column}].{component});"
356+ )
357+ . unwrap ( ) ;
358+ writeln ! (
359+ matrix_loaded_dynamic,
360+ "output[{current_output_idx}] = bitcast<u32>(mat_{element}[{column_str}].{component});"
361+ )
362+ . unwrap ( ) ;
363+ writeln ! (
364+ fully_loaded_static,
365+ "output[{current_output_idx}] = bitcast<u32>(loaded[{column}].{component});"
366+ )
367+ . unwrap ( ) ;
368+ writeln ! (
369+ fully_loaded_dynamic,
370+ "output[{current_output_idx}] = bitcast<u32>(loaded[{column_str}].{component});"
371+ )
372+ . unwrap ( ) ;
373+
374+ output_values. push ( current_input_idx) ;
375+ current_input_idx += 1 ;
376+ current_output_idx += 1 ;
377+ }
378+ // Round to next vec4 if we're matrices with vec3 columns
379+ if rows == 3 {
380+ current_input_idx += 1 ;
381+ }
382+ }
383+ }
384+
385+ // https://github.com/gfx-rs/wgpu/issues/4371
386+ let failures = if storage_type == InputStorageType :: Uniform && rows == 2 {
387+ Backends :: GL
388+ } else {
389+ Backends :: empty ( )
390+ } ;
391+
392+ tests. push (
393+ ShaderTest :: new (
394+ format ! ( "{ty} - direct, static index" ) ,
395+ input_members. clone ( ) ,
396+ direct_static,
397+ & input_values,
398+ & output_values,
399+ )
400+ . failures ( failures) ,
401+ ) ;
402+ tests. push (
403+ ShaderTest :: new (
404+ format ! ( "{ty} - direct, dynamic index" ) ,
405+ input_members. clone ( ) ,
406+ direct_dynamic,
181407 & input_values,
182408 & output_values,
183409 )
@@ -186,9 +412,19 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec<ShaderTest>
186412
187413 tests. push (
188414 ShaderTest :: new (
189- format ! ( "{ty} - vector loaded" ) ,
415+ format ! ( "{ty} - vector loaded, static index " ) ,
190416 input_members. clone ( ) ,
191- vector_loaded,
417+ vector_loaded_static,
418+ & input_values,
419+ & output_values,
420+ )
421+ . failures ( failures) ,
422+ ) ;
423+ tests. push (
424+ ShaderTest :: new (
425+ format ! ( "{ty} - vector loaded, dynamic index" ) ,
426+ input_members. clone ( ) ,
427+ vector_loaded_dynamic,
192428 & input_values,
193429 & output_values,
194430 )
@@ -197,9 +433,19 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec<ShaderTest>
197433
198434 tests. push (
199435 ShaderTest :: new (
200- format ! ( "{ty} - fully loaded" ) ,
436+ format ! ( "{ty} - matrix loaded, static index" ) ,
437+ input_members. clone ( ) ,
438+ matrix_loaded_static,
439+ & input_values,
440+ & output_values,
441+ )
442+ . failures ( failures) ,
443+ ) ;
444+ tests. push (
445+ ShaderTest :: new (
446+ format ! ( "{ty} - matrix loaded, dynamic index" ) ,
201447 input_members. clone ( ) ,
202- fully_loaded ,
448+ matrix_loaded_dynamic ,
203449 & input_values,
204450 & output_values,
205451 )
0 commit comments