@@ -51,6 +51,9 @@ g.test('pass_end_invalid_order')
5151 `
5252 Test that beginning a {compute,render} pass before ending the previous {compute,render} pass
5353 causes an error.
54+
55+ TODO(https://github.com/gpuweb/gpuweb/issues/5207): Resolve whether a validation error
56+ should be raised immediately if '!firstPassEnd && endPasses = [1, 0]'.
5457 `
5558 )
5659 . params ( u =>
@@ -95,7 +98,13 @@ g.test('call_after_successful_finish')
9598 . desc ( `Test that encoding command after a successful finish generates a validation error.` )
9699 . params ( u =>
97100 u
98- . combine ( 'callCmd' , [ 'beginComputePass' , 'beginRenderPass' , 'insertDebugMarker' ] )
101+ . combine ( 'callCmd' , [
102+ 'beginComputePass' ,
103+ 'beginRenderPass' ,
104+ 'finishAndSubmitFirst' ,
105+ 'finishAndSubmitSecond' ,
106+ 'insertDebugMarker' ,
107+ ] )
99108 . beginSubcases ( )
100109 . combine ( 'prePassType' , [ 'compute' , 'render' , 'no-op' ] )
101110 . combine ( 'IsEncoderFinished' , [ false , true ] )
@@ -112,8 +121,9 @@ g.test('call_after_successful_finish')
112121 pass . end ( ) ;
113122 }
114123
124+ let buffer ;
115125 if ( IsEncoderFinished ) {
116- encoder . finish ( ) ;
126+ buffer = encoder . finish ( ) ;
117127 }
118128
119129 switch ( callCmd ) {
@@ -126,6 +136,9 @@ g.test('call_after_successful_finish')
126136 t . expectValidationError ( ( ) => {
127137 pass . end ( ) ;
128138 } , IsEncoderFinished ) ;
139+ if ( buffer ) {
140+ t . device . queue . submit ( [ buffer ] ) ;
141+ }
129142 }
130143 break ;
131144 case 'beginRenderPass' :
@@ -137,24 +150,49 @@ g.test('call_after_successful_finish')
137150 t . expectValidationError ( ( ) => {
138151 pass . end ( ) ;
139152 } , IsEncoderFinished ) ;
153+ if ( buffer ) {
154+ t . device . queue . submit ( [ buffer ] ) ;
155+ }
156+ }
157+ break ;
158+ case 'finishAndSubmitFirst' :
159+ t . expectValidationError ( ( ) => {
160+ encoder . finish ( ) ;
161+ } , IsEncoderFinished ) ;
162+ if ( buffer ) {
163+ t . device . queue . submit ( [ buffer ] ) ;
164+ }
165+ break ;
166+ case 'finishAndSubmitSecond' :
167+ {
168+ let secondBuffer : GPUCommandBuffer ;
169+ t . expectValidationError ( ( ) => {
170+ secondBuffer = encoder . finish ( ) ;
171+ } , IsEncoderFinished ) ;
172+ t . expectValidationError ( ( ) => {
173+ t . device . queue . submit ( [ secondBuffer ] ) ;
174+ } , IsEncoderFinished ) ;
140175 }
141176 break ;
142177 case 'insertDebugMarker' :
143178 t . expectValidationError ( ( ) => {
144179 encoder . insertDebugMarker ( '' ) ;
145180 } , IsEncoderFinished ) ;
181+ if ( buffer ) {
182+ t . device . queue . submit ( [ buffer ] ) ;
183+ }
146184 break ;
147185 }
148186
149- if ( ! IsEncoderFinished ) {
187+ if ( ! IsEncoderFinished && ! callCmd . startsWith ( 'finish' ) ) {
150188 encoder . finish ( ) ;
151189 }
152190 } ) ;
153191
154192g . test ( 'pass_end_none' )
155193 . desc (
156194 `
157- Test that ending a {compute,render} pass without ending the passes generates a validation error.
195+ Test that finishing an encoder without ending a child {compute,render} pass generates a validation error.
158196 `
159197 )
160198 . paramsSubcasesOnly ( u => u . combine ( 'passType' , [ 'compute' , 'render' ] ) . combine ( 'endCount' , [ 0 , 1 ] ) )
@@ -247,3 +285,49 @@ g.test('pass_end_twice,render_pass_invalid')
247285 encoder . finish ( ) ;
248286 } ) ;
249287 } ) ;
288+
289+ g . test ( 'pass_begin_invalid_encoder' )
290+ . desc (
291+ `
292+ Test that {compute,render} passes can still be opened on an invalid encoder.
293+ `
294+ )
295+ . params ( u =>
296+ u
297+ . combine ( 'pass0Type' , [ 'compute' , 'render' ] )
298+ . combine ( 'pass1Type' , [ 'compute' , 'render' ] )
299+ . beginSubcases ( )
300+ . combine ( 'firstPassInvalid' , [ false , true ] )
301+ )
302+ . fn ( t => {
303+ const { pass0Type, pass1Type, firstPassInvalid } = t . params ;
304+
305+ const view = t . createAttachmentTextureView ( ) ;
306+
307+ const encoder = t . device . createCommandEncoder ( ) ;
308+
309+ let firstPass ;
310+ if ( pass0Type === 'compute' ) {
311+ firstPass = encoder . beginComputePass ( ) ;
312+ } else {
313+ firstPass = t . beginRenderPass ( encoder , view ) ;
314+ }
315+
316+ if ( firstPassInvalid ) {
317+ // Popping an empty debug group stack invalidates the pass.
318+ firstPass . popDebugGroup ( ) ;
319+ }
320+
321+ // Ending an invalid pass invalidates the encoder
322+ firstPass . end ( ) ;
323+
324+ // Passes can still be opened on an invalid encoder
325+ const secondPass =
326+ pass1Type === 'compute' ? encoder . beginComputePass ( ) : t . beginRenderPass ( encoder , view ) ;
327+
328+ secondPass . end ( ) ;
329+
330+ t . expectValidationError ( ( ) => {
331+ encoder . finish ( ) ;
332+ } , firstPassInvalid ) ;
333+ } ) ;
0 commit comments