export const description = ` Validation tests for render pass resolve. `; import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { GPUConst } from '../../../constants.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js'; import * as vtu from '../validation_test_utils.js'; const kNumColorAttachments = 4; export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest); g.test('resolve_attachment') .desc( ` Test various validation behaviors when a resolveTarget is provided. - base case (valid). - resolve source is not multisampled. - resolve target is not single sampled. - resolve target missing RENDER_ATTACHMENT usage. - resolve target has TRANSIENT_ATTACHMENT usage. - resolve target must have exactly one subresource: - base mip level {0, >0}, mip level count {1, >1}. - base array layer {0, >0}, array layer count {1, >1}. - resolve target GPUTextureView is invalid - resolve source and target have different formats. - rgba8unorm -> {bgra8unorm, rgba8unorm-srgb} - {bgra8unorm, rgba8unorm-srgb} -> rgba8unorm - test with other color attachments having a different format - resolve source and target have different sizes. ` ) .paramsSimple([ // control cases should be valid { _valid: true }, { bindTextureResource: true, _valid: true }, { resolveTargetUsage: GPUConst.TextureUsage.RENDER_ATTACHMENT, _valid: true }, // a single sampled resolve source should cause a validation error. { colorAttachmentSamples: 1, _valid: false }, // a multisampled resolve target should cause a validation error. { resolveTargetSamples: 4, _valid: false }, // resolveTargetUsage without RENDER_ATTACHMENT usage should cause a validation error. { resolveTargetUsage: GPUConst.TextureUsage.COPY_SRC, _valid: false }, // resolveTargetUsage with TRANSIENT_ATTACHMENT | RENDER_ATTACHMENT usage should cause a // validation error. { resolveTargetUsage: GPUConst.TextureUsage.RENDER_ATTACHMENT | GPUConst.TextureUsage.TRANSIENT_ATTACHMENT, _valid: false, }, // non-zero resolve target base mip level should be valid. { resolveTargetViewBaseMipLevel: 1, resolveTargetHeight: 4, resolveTargetWidth: 4, _valid: true, }, // a validation error should be created when resolveTarget is invalid. { resolveTargetInvalid: true, _valid: false }, // a validation error should be created when mip count > 1 { resolveTargetViewMipCount: 2, _valid: false }, { resolveTargetViewBaseMipLevel: 1, resolveTargetViewMipCount: 2, resolveTargetHeight: 4, resolveTargetWidth: 4, _valid: false, }, // non-zero resolve target base array layer should be valid. { resolveTargetViewBaseArrayLayer: 1, _valid: true }, // a validation error should be created when array layer count > 1 { resolveTargetViewArrayLayerCount: 2, _valid: false }, { resolveTargetViewBaseArrayLayer: 1, resolveTargetViewArrayLayerCount: 2, _valid: false }, // other color attachments resolving with a different format should be valid. { otherAttachmentFormat: 'bgra8unorm', _valid: true }, // mismatched colorAttachment and resolveTarget formats should cause a validation error. { colorAttachmentFormat: 'bgra8unorm', _valid: false }, { colorAttachmentFormat: 'rgba8unorm-srgb', _valid: false }, { resolveTargetFormat: 'bgra8unorm', _valid: false }, { resolveTargetFormat: 'rgba8unorm-srgb', _valid: false }, // mismatched colorAttachment and resolveTarget sizes should cause a validation error. { colorAttachmentHeight: 4, _valid: false }, { colorAttachmentWidth: 4, _valid: false }, { resolveTargetHeight: 4, _valid: false }, { resolveTargetWidth: 4, _valid: false }, ] as const) .fn(t => { const { bindTextureResource = false, colorAttachmentFormat = 'rgba8unorm', resolveTargetFormat = 'rgba8unorm', otherAttachmentFormat = 'rgba8unorm', colorAttachmentSamples = 4, resolveTargetSamples = 1, resolveTargetUsage = GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, resolveTargetInvalid = false, resolveTargetViewMipCount = 1, resolveTargetViewBaseMipLevel = 0, resolveTargetViewArrayLayerCount = 1, resolveTargetViewBaseArrayLayer = 0, colorAttachmentHeight = 2, colorAttachmentWidth = 2, resolveTargetHeight = 2, resolveTargetWidth = 2, _valid, } = t.params; // MAINTENANCE_TODO(#4509): Remove this after all implementations have TRANSIENT_ATTACHMENT. if ((resolveTargetUsage & GPUConst.TextureUsage.TRANSIENT_ATTACHMENT) !== 0) { t.skipIfTransientAttachmentNotSupported(); } // Run the test in a nested loop such that the configured color attachment with resolve target // is tested while occupying each individual colorAttachment slot. for (let resolveSlot = 0; resolveSlot < kNumColorAttachments; resolveSlot++) { const renderPassColorAttachmentDescriptors: GPURenderPassColorAttachment[] = []; for ( let colorAttachmentSlot = 0; colorAttachmentSlot < kNumColorAttachments; colorAttachmentSlot++ ) { // resolveSlot === colorAttachmentSlot denotes the color attachment slot that contains the // color attachment with resolve target. if (resolveSlot === colorAttachmentSlot) { // Create the color attachment with resolve target with the configurable parameters. const resolveSourceColorAttachment = t.createTextureTracked({ format: colorAttachmentFormat, size: { width: colorAttachmentWidth, height: colorAttachmentHeight, depthOrArrayLayers: 1, }, sampleCount: colorAttachmentSamples, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, }); const resolveTarget = t.createTextureTracked({ format: resolveTargetFormat, size: { width: resolveTargetWidth, height: resolveTargetHeight, depthOrArrayLayers: resolveTargetViewBaseArrayLayer + resolveTargetViewArrayLayerCount, }, sampleCount: resolveTargetSamples, mipLevelCount: resolveTargetViewBaseMipLevel + resolveTargetViewMipCount, usage: resolveTargetUsage, }); renderPassColorAttachmentDescriptors.push({ view: resolveSourceColorAttachment.createView(), loadOp: 'load', storeOp: 'discard', resolveTarget: resolveTargetInvalid ? vtu.getErrorTextureView(t) : bindTextureResource ? resolveTarget : resolveTarget.createView({ dimension: resolveTargetViewArrayLayerCount === 1 ? '2d' : '2d-array', mipLevelCount: resolveTargetViewMipCount, arrayLayerCount: resolveTargetViewArrayLayerCount, baseMipLevel: resolveTargetViewBaseMipLevel, baseArrayLayer: resolveTargetViewBaseArrayLayer, }), }); } else { // Create a basic texture to fill other color attachment slots. This texture's dimensions // and sample count must match the resolve source color attachment to be valid. const colorAttachment = t.createTextureTracked({ format: otherAttachmentFormat, size: { width: colorAttachmentWidth, height: colorAttachmentHeight, depthOrArrayLayers: 1, }, sampleCount: colorAttachmentSamples, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, }); const resolveTarget = t.createTextureTracked({ format: otherAttachmentFormat, size: { width: colorAttachmentWidth, height: colorAttachmentHeight, depthOrArrayLayers: 1, }, sampleCount: 1, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, }); renderPassColorAttachmentDescriptors.push({ view: colorAttachment.createView(), loadOp: 'load', storeOp: 'discard', resolveTarget: resolveTarget.createView(), }); } } const encoder = t.device.createCommandEncoder(); const pass = encoder.beginRenderPass({ colorAttachments: renderPassColorAttachmentDescriptors, }); pass.end(); t.expectValidationError(() => { encoder.finish(); }, !_valid); } });