export const description = ` Note: render pass 'occlusionQuerySet' validation is tested in queries/general.spec.ts TODO: Check that depth-stencil attachment views must encompass all aspects. TODO: check for duplication (render_pass/, etc.), plan, and implement. Note possibly a lot of this should be operation tests instead. Notes: > - color attachments {zero, one, multiple} > - many different formats (some are non-renderable) > - is a view on a texture with multiple mip levels or array layers > - two attachments use the same view, or views of {intersecting, disjoint} ranges > - {without, with} resolve target > - resolve format compatibility with multisampled format > - {all possible load ops, load color {in range, negative, too large}} > - all possible store ops > - depth/stencil attachment > - {unset, all possible formats} > - {all possible {depth, stencil} load ops, load values {in range, negative, too large}} > - all possible {depth, stencil} store ops > - depthReadOnly {t,f}, stencilReadOnly {t,f} `; import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js'; import * as vtu from '../validation_test_utils.js'; export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest); g.test('color_attachments,device_mismatch') .desc( ` Tests beginRenderPass cannot be called with color attachments whose texture view or resolve target is created from another device The 'view' and 'resolveTarget' are: - created from same device in ColorAttachment0 and ColorAttachment1 - created from different device in ColorAttachment0 and ColorAttachment1 - created from same device in ColorAttachment0, but from different device in ColorAttachment1 ` ) .paramsSubcasesOnly([ { view0Mismatched: false, target0Mismatched: false, view1Mismatched: false, target1Mismatched: false, }, // control case { view0Mismatched: false, target0Mismatched: true, view1Mismatched: false, target1Mismatched: true, }, { view0Mismatched: true, target0Mismatched: false, view1Mismatched: true, target1Mismatched: false, }, { view0Mismatched: false, target0Mismatched: false, view1Mismatched: false, target1Mismatched: true, }, ]) .beforeAllSubcases(t => t.usesMismatchedDevice()) .fn(t => { const { view0Mismatched, target0Mismatched, view1Mismatched, target1Mismatched } = t.params; const mismatched = view0Mismatched || target0Mismatched || view1Mismatched || target1Mismatched; const view0Texture = view0Mismatched ? vtu.getDeviceMismatchedRenderTexture(t, 4) : vtu.getRenderTexture(t, 4); const target0Texture = target0Mismatched ? vtu.getDeviceMismatchedRenderTexture(t) : vtu.getRenderTexture(t); const view1Texture = view1Mismatched ? vtu.getDeviceMismatchedRenderTexture(t, 4) : vtu.getRenderTexture(t, 4); const target1Texture = target1Mismatched ? vtu.getDeviceMismatchedRenderTexture(t) : vtu.getRenderTexture(t); const encoder = t.createEncoder('non-pass'); const pass = encoder.encoder.beginRenderPass({ colorAttachments: [ { view: view0Texture.createView(), clearValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, loadOp: 'clear', storeOp: 'store', resolveTarget: target0Texture.createView(), }, { view: view1Texture.createView(), clearValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }, loadOp: 'clear', storeOp: 'store', resolveTarget: target1Texture.createView(), }, ], }); pass.end(); encoder.validateFinish(!mismatched); }); g.test('depth_stencil_attachment,device_mismatch') .desc( 'Tests beginRenderPass cannot be called with a depth stencil attachment whose texture view is created from another device' ) .paramsSubcasesOnly(u => u.combine('mismatched', [true, false])) .beforeAllSubcases(t => t.usesMismatchedDevice()) .fn(t => { const { mismatched } = t.params; const descriptor: GPUTextureDescriptor = { size: { width: 4, height: 4, depthOrArrayLayers: 1 }, format: 'depth24plus-stencil8', usage: GPUTextureUsage.RENDER_ATTACHMENT, }; const depthStencilTexture = mismatched ? vtu.getDeviceMismatchedTexture(t, descriptor) : t.createTextureTracked(descriptor); const encoder = t.createEncoder('non-pass'); const pass = encoder.encoder.beginRenderPass({ colorAttachments: [], depthStencilAttachment: { view: depthStencilTexture.createView(), depthClearValue: 0, depthLoadOp: 'clear', depthStoreOp: 'store', stencilClearValue: 0, stencilLoadOp: 'clear', stencilStoreOp: 'store', }, }); pass.end(); encoder.validateFinish(!mismatched); }); g.test('occlusion_query_set,device_mismatch') .desc( 'Tests beginRenderPass cannot be called with an occlusion query set created from another device' ) .paramsSubcasesOnly(u => u.combine('mismatched', [true, false])) .beforeAllSubcases(t => t.usesMismatchedDevice()) .fn(t => { const { mismatched } = t.params; const sourceDevice = mismatched ? t.mismatchedDevice : t.device; const occlusionQuerySet = t.trackForCleanup( sourceDevice.createQuerySet({ type: 'occlusion', count: 1, }) ); const encoder = t.createEncoder('render pass', { occlusionQuerySet }); encoder.validateFinish(!mismatched); }); g.test('timestamp_query_set,device_mismatch') .desc( ` Tests beginRenderPass cannot be called with a timestamp query set created from another device. ` ) .paramsSubcasesOnly(u => u.combine('mismatched', [true, false])) .beforeAllSubcases(t => t.usesMismatchedDevice()) .fn(t => { t.skipIfDeviceDoesNotSupportQueryType('timestamp'); const { mismatched } = t.params; const sourceDevice = mismatched ? t.mismatchedDevice : t.device; const timestampQuerySet = t.trackForCleanup( sourceDevice.createQuerySet({ type: 'timestamp', count: 1, }) ); const timestampWrites = { querySet: timestampQuerySet, beginningOfPassWriteIndex: 0, }; const colorTexture = t.createTextureTracked({ format: 'rgba8unorm', size: { width: 4, height: 4, depthOrArrayLayers: 1 }, usage: GPUTextureUsage.RENDER_ATTACHMENT, }); const encoder = t.createEncoder('non-pass'); const pass = encoder.encoder.beginRenderPass({ colorAttachments: [ { view: colorTexture.createView(), loadOp: 'load', storeOp: 'store', }, ], timestampWrites, }); pass.end(); encoder.validateFinish(!mismatched); });