@@ -261,8 +261,8 @@ class F extends TextureTestMixin(GPUTest) {
261261 rasterizationMask : number ,
262262 pipeline : GPURenderPipeline ,
263263 uniformBuffer : GPUBuffer ,
264- colorTargetsCount : number = 1
265- ) : { color : GPUTexture ; depthStencil : GPUTexture } {
264+ colorTargets : Iterable < GPUColorTargetState | null >
265+ ) : { colors : ( GPUTexture | null ) [ ] ; depthStencil : GPUTexture } {
266266 assert ( this . sampleTexture !== undefined ) ;
267267 assert ( this . sampler !== undefined ) ;
268268
@@ -286,37 +286,42 @@ class F extends TextureTestMixin(GPUTest) {
286286 ] ,
287287 } ) ;
288288
289- const renderTargetTextures = [ ] ;
289+ const renderTargetTextures : ( GPUTexture | null ) [ ] = [ ] ;
290290 const resolveTargetTextures : ( GPUTexture | null ) [ ] = [ ] ;
291- for ( let i = 0 ; i < colorTargetsCount ; i ++ ) {
292- const renderTargetTexture = this . device . createTexture ( {
293- format,
294- size : {
295- width : kRenderTargetSize ,
296- height : kRenderTargetSize ,
297- depthOrArrayLayers : 1 ,
298- } ,
299- sampleCount,
300- mipLevelCount : 1 ,
301- usage : GPUTextureUsage . RENDER_ATTACHMENT | GPUTextureUsage . TEXTURE_BINDING ,
302- } ) ;
303- renderTargetTextures . push ( renderTargetTexture ) ;
304-
305- const resolveTargetTexture =
306- sampleCount === 1
307- ? null
308- : this . device . createTexture ( {
309- format,
310- size : {
311- width : kRenderTargetSize ,
312- height : kRenderTargetSize ,
313- depthOrArrayLayers : 1 ,
314- } ,
315- sampleCount : 1 ,
316- mipLevelCount : 1 ,
317- usage : GPUTextureUsage . COPY_SRC | GPUTextureUsage . RENDER_ATTACHMENT ,
318- } ) ;
319- resolveTargetTextures . push ( resolveTargetTexture ) ;
291+ for ( const target of colorTargets ) {
292+ if ( target === null ) {
293+ renderTargetTextures . push ( null ) ;
294+ resolveTargetTextures . push ( null ) ;
295+ } else {
296+ const renderTargetTexture = this . device . createTexture ( {
297+ format,
298+ size : {
299+ width : kRenderTargetSize ,
300+ height : kRenderTargetSize ,
301+ depthOrArrayLayers : 1 ,
302+ } ,
303+ sampleCount,
304+ mipLevelCount : 1 ,
305+ usage : GPUTextureUsage . RENDER_ATTACHMENT | GPUTextureUsage . TEXTURE_BINDING ,
306+ } ) ;
307+ renderTargetTextures . push ( renderTargetTexture ) ;
308+
309+ const resolveTargetTexture =
310+ sampleCount === 1
311+ ? null
312+ : this . device . createTexture ( {
313+ format,
314+ size : {
315+ width : kRenderTargetSize ,
316+ height : kRenderTargetSize ,
317+ depthOrArrayLayers : 1 ,
318+ } ,
319+ sampleCount : 1 ,
320+ mipLevelCount : 1 ,
321+ usage : GPUTextureUsage . COPY_SRC | GPUTextureUsage . RENDER_ATTACHMENT ,
322+ } ) ;
323+ resolveTargetTextures . push ( resolveTargetTexture ) ;
324+ }
320325 }
321326
322327 const depthStencilTexture = this . device . createTexture ( {
@@ -331,6 +336,10 @@ class F extends TextureTestMixin(GPUTest) {
331336
332337 const renderPassDescriptor : GPURenderPassDescriptor = {
333338 colorAttachments : renderTargetTextures . map ( ( renderTargetTexture , index ) => {
339+ if ( renderTargetTexture === null ) {
340+ return null ;
341+ }
342+
334343 return {
335344 view : renderTargetTexture . createView ( ) ,
336345 resolveTarget : resolveTargetTextures [ index ] ?. createView ( ) ,
@@ -383,7 +392,7 @@ class F extends TextureTestMixin(GPUTest) {
383392 this . device . queue . submit ( [ commandEncoder . finish ( ) ] ) ;
384393
385394 return {
386- color : renderTargetTextures [ 0 ] ,
395+ colors : renderTargetTextures ,
387396 depthStencil : depthStencilTexture ,
388397 } ;
389398 }
@@ -514,6 +523,7 @@ textureLoad each sample index from the texture and write to a storage buffer to
514523 new Uint32Array ( [ fragmentShaderOutputMask ] )
515524 ) ;
516525
526+ const colorTargets = [ { format } ] as const ;
517527 const pipeline = t . device . createRenderPipeline ( {
518528 layout : 'auto' ,
519529 vertex : {
@@ -540,7 +550,7 @@ textureLoad each sample index from the texture and write to a storage buffer to
540550 }` ,
541551 } ) ,
542552 entryPoint : 'main' ,
543- targets : [ { format } ] ,
553+ targets : colorTargets ,
544554 } ,
545555 primitive : { topology : 'triangle-list' } ,
546556 multisample : {
@@ -564,12 +574,15 @@ textureLoad each sample index from the texture and write to a storage buffer to
564574 } ,
565575 } ) ;
566576
567- const { color , depthStencil } = t . GetTargetTexture (
577+ const { colors , depthStencil } = t . GetTargetTexture (
568578 sampleCount ,
569579 rasterizationMask ,
570580 pipeline ,
571- fragmentMaskUniformBuffer
581+ fragmentMaskUniformBuffer ,
582+ colorTargets
572583 ) ;
584+ const color = colors [ 0 ] ;
585+ assert ( color !== null ) ;
573586
574587 t . CheckColorAttachmentResult (
575588 color ,
@@ -601,12 +614,13 @@ textureLoad each sample index from the texture and write to a storage buffer to
601614g . test ( 'alpha_to_coverage_mask' )
602615 . desc (
603616 `
604- Test that alpha_to_coverage_mask is working properly with the alpha output of color target[0].
617+ Test that alpha_to_coverage_mask is working properly with the shader alpha output of color target[0].
605618
606619- for sampleCount = 4, alphaToCoverageEnabled = true and various combinations of:
607620 - rasterization masks
608621 - increasing alpha0 values of the color0 output including { < 0, = 0, = 1/16, = 2/16, ..., = 15/16, = 1, > 1 }
609- - alpha1 values of the color1 output = { 0, 0.5, 1.0 }.
622+ - unrelated alpha1 values of the color1 output = { 0, 0.5, 1.0 } (when target[0] is not empty) or = { 1.0 } (when target[0] is empty)
623+ - target[0] is empty or not
610624- test that for a single pixel in { color0, color1 } { color0, depth, stencil } output the final sample mask is applied to it, moreover:
611625 - if alpha0 is 0.0 or less then alpha to coverage mask is 0x0,
612626 - if alpha0 is 1.0 or greater then alpha to coverage mask is 0xFFFFFFFF,
@@ -622,18 +636,31 @@ color' <= color.
622636 )
623637 . params ( u =>
624638 u
639+ . combine ( 'hasSparseColorAttachment' , [ false , true ] as const )
625640 . expand ( 'rasterizationMask' , function * ( p ) {
626641 for ( let i = 0 , len = 0xf ; i <= len ; i ++ ) {
627642 yield i ;
628643 }
629644 } )
630645 . beginSubcases ( )
631- . combine ( 'alpha1' , [ 0.0 , 0.5 , 1.0 ] as const )
646+ . expand ( 'alpha1' , p => {
647+ if ( p . hasSparseColorAttachment ) {
648+ // when hasSparseColorAttachment is true
649+ // target[0] is empty but target[0].a is still used as alphaToCoverage value.
650+ // target[1] is used as the color output, so target[1].a stays at 1.0 to match sample texture values.
651+ return [ 1.0 ] ;
652+ }
653+ return [ 0.0 , 0.5 , 1.0 ] ;
654+ } )
632655 )
633656 . fn ( async t => {
634657 const sampleCount = 4 ;
635658 const sampleMask = 0xffffffff ;
636- const { rasterizationMask, alpha1 } = t . params ;
659+ const { hasSparseColorAttachment, rasterizationMask, alpha1 } = t . params ;
660+ const colorTargets = [
661+ hasSparseColorAttachment ? null : ( { format } as const ) ,
662+ { format } ,
663+ ] as const ;
637664
638665 const alphaValues = new Float32Array ( 4 ) ; // [alpha0, alpha1, 0, 0]
639666 const alphaValueUniformBuffer = t . device . createBuffer ( {
@@ -674,7 +701,7 @@ color' <= color.
674701 }` ,
675702 } ) ,
676703 entryPoint : 'main' ,
677- targets : [ { format } , { format } ] ,
704+ targets : colorTargets ,
678705 } ,
679706 primitive : { topology : 'triangle-list' } ,
680707 multisample : {
@@ -699,25 +726,29 @@ color' <= color.
699726 } ) ;
700727
701728 // { < 0, = 0, = 1/16, = 2/16, ..., = 15/16, = 1, > 1 }
702- const alpha0ParamsArray = [ - 0.1 , ...range ( 16 , i => i / 16 ) , 1.0 , 1.1 ] ;
729+ const alphaParamsArray = [ - 0.1 , ...range ( 16 , i => i / 16 ) , 1.0 , 1.1 ] ;
703730
704731 const colorResultPromises = [ ] ;
705732 const depthResultPromises = [ ] ;
706733 const stencilResultPromises = [ ] ;
707734
708- for ( const alpha0 of alpha0ParamsArray ) {
735+ for ( const alpha0 of alphaParamsArray ) {
709736 alphaValues [ 0 ] = alpha0 ;
710737 alphaValues [ 1 ] = alpha1 ;
738+
711739 t . device . queue . writeBuffer ( alphaValueUniformBuffer , 0 , alphaValues ) ;
712740
713- const { color , depthStencil } = t . GetTargetTexture (
741+ const { colors , depthStencil } = t . GetTargetTexture (
714742 sampleCount ,
715743 rasterizationMask ,
716744 pipeline ,
717745 alphaValueUniformBuffer ,
718- 2
746+ colorTargets
719747 ) ;
720748
749+ const color = hasSparseColorAttachment ? colors [ 1 ] : colors [ 0 ] ;
750+ assert ( color !== null ) ;
751+
721752 const colorBuffer = t . copySinglePixelTextureToBufferUsingComputePass (
722753 TypeF32 , // correspond to 'rgba8unorm' format
723754 4 ,
@@ -776,13 +807,13 @@ color' <= color.
776807 ) => {
777808 for ( let i = 0 ; i < results . length ; i ++ ) {
778809 const result = results [ i ] ;
779- const alpha0 = alpha0ParamsArray [ i ] ;
810+ const alpha = alphaParamsArray [ i ] ;
780811
781- if ( alpha0 <= 0 ) {
812+ if ( alpha <= 0 ) {
782813 const expected = getExpectedDataFn ( sampleCount , rasterizationMask , sampleMask , 0x0 ) ;
783814 const check = checkElementsEqual ( result . data , expected ) ;
784815 t . expectOK ( check ) ;
785- } else if ( alpha0 >= 1 ) {
816+ } else if ( alpha >= 1 ) {
786817 const expected = getExpectedDataFn (
787818 sampleCount ,
788819 rasterizationMask ,
0 commit comments