@@ -12,6 +12,7 @@ import { ValidationTest } from '../validation_test.js';
1212class F extends ValidationTest {
1313 async testMapAsyncCall (
1414 success : boolean ,
15+ earlyRejection : boolean ,
1516 rejectName : string | null ,
1617 buffer : GPUBuffer ,
1718 mode : GPUMapModeFlags ,
@@ -26,12 +27,26 @@ class F extends ValidationTest {
2627 this . expectValidationError ( ( ) => {
2728 p = buffer . mapAsync ( mode , offset , size ) ;
2829 } ) ;
30+ let caught = false ;
31+ let rejectedEarly = false ;
32+ // If mapAsync rejected early, microtask A will run before B.
33+ // If not, B will run before A.
34+ p ! . catch ( ( ) => {
35+ // Microtask A
36+ caught = true ;
37+ } ) ;
38+ queueMicrotask ( ( ) => {
39+ // Microtask B
40+ rejectedEarly = caught ;
41+ } ) ;
2942 try {
43+ // This await will always complete after microtasks A and B are both done.
3044 await p ! ;
3145 assert ( rejectName === null , 'mapAsync unexpectedly passed' ) ;
3246 } catch ( ex ) {
3347 assert ( ex instanceof Error , 'mapAsync rejected with non-error' ) ;
3448 assert ( rejectName === ex . name , `mapAsync rejected unexpectedly with: ${ ex } ` ) ;
49+ assert ( earlyRejection === rejectedEarly , 'mapAsync rejected at an unexpected timing' ) ;
3550 }
3651 }
3752 }
@@ -102,7 +117,7 @@ g.test('mapAsync,usage')
102117 } ) ;
103118
104119 const success = usage === validUsage ;
105- await t . testMapAsyncCall ( success , 'OperationError' , buffer , mapMode ) ;
120+ await t . testMapAsyncCall ( success , false , 'OperationError' , buffer , mapMode ) ;
106121 } ) ;
107122
108123g . test ( 'mapAsync,invalidBuffer' )
@@ -111,7 +126,7 @@ g.test('mapAsync,invalidBuffer')
111126 . fn ( async t => {
112127 const { mapMode } = t . params ;
113128 const buffer = t . getErrorBuffer ( ) ;
114- await t . testMapAsyncCall ( false , 'OperationError' , buffer , mapMode ) ;
129+ await t . testMapAsyncCall ( false , false , 'OperationError' , buffer , mapMode ) ;
115130 } ) ;
116131
117132g . test ( 'mapAsync,state,destroyed' )
@@ -126,7 +141,7 @@ g.test('mapAsync,state,destroyed')
126141 t . shouldReject ( 'AbortError' , buffer . mapAsync ( mapMode ) ) ;
127142
128143 buffer . destroy ( ) ;
129- await t . testMapAsyncCall ( false , 'OperationError' , buffer , mapMode ) ;
144+ await t . testMapAsyncCall ( false , false , 'OperationError' , buffer , mapMode ) ;
130145 } ) ;
131146
132147g . test ( 'mapAsync,state,mappedAtCreation' )
@@ -146,10 +161,10 @@ g.test('mapAsync,state,mappedAtCreation')
146161 usage : validUsage ,
147162 mappedAtCreation : true ,
148163 } ) ;
149- await t . testMapAsyncCall ( false , 'OperationError' , buffer , mapMode ) ;
164+ await t . testMapAsyncCall ( false , false , 'OperationError' , buffer , mapMode ) ;
150165
151166 buffer . unmap ( ) ;
152- await t . testMapAsyncCall ( true , null , buffer , mapMode ) ;
167+ await t . testMapAsyncCall ( true , false , null , buffer , mapMode ) ;
153168 } ) ;
154169
155170g . test ( 'mapAsync,state,mapped' )
@@ -162,11 +177,11 @@ g.test('mapAsync,state,mapped')
162177 const { mapMode } = t . params ;
163178
164179 const buffer = t . createMappableBuffer ( mapMode , 16 ) ;
165- await t . testMapAsyncCall ( true , null , buffer , mapMode ) ;
166- await t . testMapAsyncCall ( false , 'OperationError' , buffer , mapMode ) ;
180+ await t . testMapAsyncCall ( true , false , null , buffer , mapMode ) ;
181+ await t . testMapAsyncCall ( false , false , 'OperationError' , buffer , mapMode ) ;
167182
168183 buffer . unmap ( ) ;
169- await t . testMapAsyncCall ( true , null , buffer , mapMode ) ;
184+ await t . testMapAsyncCall ( true , false , null , buffer , mapMode ) ;
170185 } ) ;
171186
172187g . test ( 'mapAsync,state,mappingPending' )
@@ -193,7 +208,7 @@ g.test('mapAsync,state,mappingPending')
193208
194209 // Unmap the first mapping. It should now be possible to successfully call mapAsync
195210 buffer . unmap ( ) ;
196- await t . testMapAsyncCall ( true , null , buffer , mapMode ) ;
211+ await t . testMapAsyncCall ( true , false , null , buffer , mapMode ) ;
197212 } ) ;
198213
199214g . test ( 'mapAsync,sizeUnspecifiedOOB' )
@@ -224,7 +239,7 @@ g.test('mapAsync,sizeUnspecifiedOOB')
224239 const buffer = t . createMappableBuffer ( mapMode , bufferSize ) ;
225240
226241 const success = offset <= bufferSize ;
227- await t . testMapAsyncCall ( success , 'OperationError' , buffer , mapMode , offset ) ;
242+ await t . testMapAsyncCall ( success , false , 'OperationError' , buffer , mapMode , offset ) ;
228243 } ) ;
229244
230245g . test ( 'mapAsync,offsetAndSizeAlignment' )
@@ -240,7 +255,7 @@ g.test('mapAsync,offsetAndSizeAlignment')
240255 const buffer = t . createMappableBuffer ( mapMode , 16 ) ;
241256
242257 const success = offset % kOffsetAlignment === 0 && size % kSizeAlignment === 0 ;
243- await t . testMapAsyncCall ( success , 'OperationError' , buffer , mapMode , offset , size ) ;
258+ await t . testMapAsyncCall ( success , false , 'OperationError' , buffer , mapMode , offset , size ) ;
244259 } ) ;
245260
246261g . test ( 'mapAsync,offsetAndSizeOOB' )
@@ -282,7 +297,7 @@ g.test('mapAsync,offsetAndSizeOOB')
282297 const buffer = t . createMappableBuffer ( mapMode , bufferSize ) ;
283298
284299 const success = offset + size <= bufferSize ;
285- await t . testMapAsyncCall ( success , 'OperationError' , buffer , mapMode , offset , size ) ;
300+ await t . testMapAsyncCall ( success , false , 'OperationError' , buffer , mapMode , offset , size ) ;
286301 } ) ;
287302
288303g . test ( 'mapAsync,earlyRejection' )
@@ -296,26 +311,9 @@ g.test('mapAsync,earlyRejection')
296311 const offset1 = 0 ;
297312
298313 const buffer = t . createMappableBuffer ( mapMode , bufferSize ) ;
299-
300314 const p1 = buffer . mapAsync ( mapMode , offset1 , mapSize ) ; // succeeds
301- let success = false ;
302- {
303- let caught = false ;
304- // should be already rejected
305- const p2 = buffer . mapAsync ( mapMode , offset2 , mapSize ) ;
306- // queues a microtask catching the rejection
307- p2 . catch ( ( ) => {
308- caught = true ;
309- } ) ;
310- // queues a second microtask to capture the state immediately after the catch.
311- // Test fails if p2 isn't rejected before the second microtask is fired or
312- // p1 is resolved.
313- queueMicrotask ( ( ) => {
314- success = caught ;
315- } ) ;
316- }
315+ await t . testMapAsyncCall ( false , true , 'OperationError' , buffer , mapMode , offset2 , mapSize ) ;
317316 await p1 ; // ensure the original map still succeeds
318- assert ( success ) ;
319317 } ) ;
320318
321319g . test ( 'getMappedRange,state,mapped' )
@@ -410,7 +408,7 @@ g.test('getMappedRange,state,mappedAgain')
410408 await buffer . mapAsync ( mapMode ) ;
411409
412410 // call mapAsync again on already mapped buffer should fail
413- await t . testMapAsyncCall ( false , 'OperationError' , buffer , mapMode ) ;
411+ await t . testMapAsyncCall ( false , false , 'OperationError' , buffer , mapMode ) ;
414412
415413 // getMapppedRange should still success
416414 t . testGetMappedRangeCall ( true , buffer ) ;
0 commit comments