@@ -16,6 +16,7 @@ API operations tests for occlusion queries.
1616- test resolving twice in same pass keeps values
1717- test resolving twice across pass keeps values
1818- test resolveQuerySet destinationOffset
19+ - test using the same query multiple times in different passes without resolving in between
1920` ;
2021
2122import { kUnitCaseParamsBuilder } from '../../../../../common/framework/params_builder.js' ;
@@ -436,38 +437,49 @@ class OcclusionQueryTest extends AllFeaturesMaxLimitsGPUTest {
436437 renderMode,
437438 } ;
438439 }
439- async runQueryTest (
440+
441+ encodeQueries (
440442 resources : ReturnType < OcclusionQueryTest [ 'setup' ] > ,
441- renderPassDescriptor : GPURenderPassDescriptor | null ,
442- encodePassFn : ( helper : RenderPassHelper , queryIndex : number ) => void ,
443- checkQueryIndexResultFn : ( passed : boolean , queryIndex : number ) => void
443+ encoder : GPUCommandEncoder ,
444+ renderPassDescriptor : GPURenderPassDescriptor ,
445+ encodePassFn : ( helper : RenderPassHelper , queryIndex : number ) => void
444446 ) {
445447 const { device } = this ;
448+ const { occlusionQuerySet, querySetOffset, renderMode = 'direct' } = resources ;
449+ const numQueries = occlusionQuerySet . count - querySetOffset ;
450+ const queryIndices = range ( numQueries , ( i : number ) => i + querySetOffset ) ;
451+
452+ const pass = encoder . beginRenderPass ( renderPassDescriptor ) ;
453+ const helper = new RenderPassHelper (
454+ pass ,
455+ renderMode === 'direct'
456+ ? new QueryStarterDirect ( pass )
457+ : new QueryStarterRenderBundle ( device , pass , renderPassDescriptor )
458+ ) ;
459+
460+ for ( const queryIndex of queryIndices ) {
461+ encodePassFn ( helper , queryIndex ) ;
462+ }
463+ pass . end ( ) ;
464+ }
465+
466+ encodeAndResolveQueries (
467+ resources : ReturnType < OcclusionQueryTest [ 'setup' ] > ,
468+ encoder : GPUCommandEncoder ,
469+ renderPassDescriptor : GPURenderPassDescriptor | null ,
470+ encodePassFn : ( helper : RenderPassHelper , queryIndex : number ) => void
471+ ) {
446472 const {
447473 readBuffer,
448474 queryResolveBuffer,
449475 queryResolveBufferOffset,
450476 occlusionQuerySet,
451477 querySetOffset,
452- renderMode = 'direct' ,
453478 } = resources ;
454479 const numQueries = occlusionQuerySet . count - querySetOffset ;
455- const queryIndices = range ( numQueries , ( i : number ) => i + querySetOffset ) ;
456480
457- const encoder = device . createCommandEncoder ( ) ;
458481 if ( renderPassDescriptor ) {
459- const pass = encoder . beginRenderPass ( renderPassDescriptor ) ;
460- const helper = new RenderPassHelper (
461- pass ,
462- renderMode === 'direct'
463- ? new QueryStarterDirect ( pass )
464- : new QueryStarterRenderBundle ( device , pass , renderPassDescriptor )
465- ) ;
466-
467- for ( const queryIndex of queryIndices ) {
468- encodePassFn ( helper , queryIndex ) ;
469- }
470- pass . end ( ) ;
482+ this . encodeQueries ( resources , encoder , renderPassDescriptor , encodePassFn ) ;
471483 }
472484
473485 encoder . resolveQuerySet (
@@ -484,7 +496,15 @@ class OcclusionQueryTest extends AllFeaturesMaxLimitsGPUTest {
484496 0 ,
485497 readBuffer . size
486498 ) ;
487- device . queue . submit ( [ encoder . finish ( ) ] ) ;
499+ }
500+
501+ async checkQueryResults (
502+ resources : ReturnType < OcclusionQueryTest [ 'setup' ] > ,
503+ checkQueryIndexResultFn : ( passed : boolean , queryIndex : number ) => void
504+ ) {
505+ const { readBuffer, occlusionQuerySet, querySetOffset } = resources ;
506+ const numQueries = occlusionQuerySet . count - querySetOffset ;
507+ const queryIndices = range ( numQueries , ( i : number ) => i + querySetOffset ) ;
488508
489509 const result = await this . readBufferAsBigUint64 ( readBuffer ) ;
490510 for ( const queryIndex of queryIndices ) {
@@ -495,6 +515,21 @@ class OcclusionQueryTest extends AllFeaturesMaxLimitsGPUTest {
495515
496516 return result ;
497517 }
518+
519+ async runQueryTest (
520+ resources : ReturnType < OcclusionQueryTest [ 'setup' ] > ,
521+ renderPassDescriptor : GPURenderPassDescriptor | null ,
522+ encodePassFn : ( helper : RenderPassHelper , queryIndex : number ) => void ,
523+ checkQueryIndexResultFn : ( passed : boolean , queryIndex : number ) => void
524+ ) {
525+ const { device } = this ;
526+
527+ const encoder = device . createCommandEncoder ( ) ;
528+ this . encodeAndResolveQueries ( resources , encoder , renderPassDescriptor , encodePassFn ) ;
529+ device . queue . submit ( [ encoder . finish ( ) ] ) ;
530+
531+ return this . checkQueryResults ( resources , checkQueryIndexResultFn ) ;
532+ }
498533}
499534
500535const kQueryTestBaseParams = kUnitCaseParamsBuilder
@@ -598,6 +633,59 @@ g.test('occlusion_query,basic')
598633 ) ;
599634 } ) ;
600635
636+ g . test ( 'occlusion_query,reuse' )
637+ . desc (
638+ `
639+ Test queries can be reused.
640+
641+ This tests that if you write to a query twice in the same command buffer (different passes)
642+ and resolve after, that you get the 2nd result.
643+ `
644+ )
645+ . params ( kQueryTestBaseParams . combine ( 'noop' , [ 'before' , 'after' ] as const ) )
646+ . fn ( async t => {
647+ const { writeMask, renderMode, bufferOffset, querySetOffset, noop } = t . params ;
648+ const kNumQueries = 30 ;
649+ const resources = t . setup ( {
650+ writeMask,
651+ renderMode,
652+ bufferOffset,
653+ querySetOffset,
654+ numQueries : kNumQueries ,
655+ } ) ;
656+ const { renderPassDescriptor, vertexBuffer, pipeline } = resources ;
657+
658+ const opEncodePassFn = ( helper : RenderPassHelper , queryIndex : number ) => {
659+ const queryHelper = helper . beginOcclusionQuery ( queryIndex ) ;
660+ queryHelper . setPipeline ( pipeline ) ;
661+ queryHelper . setVertexBuffer ( vertexBuffer ) ;
662+ queryHelper . draw ( 3 ) ;
663+ queryHelper . end ( ) ;
664+ } ;
665+
666+ const noopEncodePassFn = ( helper : RenderPassHelper , queryIndex : number ) => {
667+ const queryHelper = helper . beginOcclusionQuery ( queryIndex ) ;
668+ queryHelper . end ( ) ;
669+ } ;
670+
671+ const [ firstOp , secondOp ] =
672+ noop === 'before' ? [ noopEncodePassFn , opEncodePassFn ] : [ opEncodePassFn , noopEncodePassFn ] ;
673+
674+ const { device } = t ;
675+ const encoder = device . createCommandEncoder ( ) ;
676+ t . encodeQueries ( resources , encoder , renderPassDescriptor , firstOp ) ;
677+ t . encodeAndResolveQueries ( resources , encoder , renderPassDescriptor , secondOp ) ;
678+ device . queue . submit ( [ encoder . finish ( ) ] ) ;
679+
680+ await t . checkQueryResults ( resources , ( passed , queryIndex ) => {
681+ const expectPassed = noop === 'before' ;
682+ t . expect (
683+ ! ! passed === expectPassed ,
684+ `queryIndex: ${ queryIndex } , was: ${ ! ! passed } , expected: ${ expectPassed } `
685+ ) ;
686+ } ) ;
687+ } ) ;
688+
601689g . test ( 'occlusion_query,empty' )
602690 . desc (
603691 `
0 commit comments