export const description = `Validation tests for atomicStoreMin and atomicStoreMax builtins.`;import { makeTestGroup } from '../../../../../../common/framework/test_group.js';import { keysOf } from '../../../../../../common/util/data_tables.js';import { ShaderValidationTest } from '../../../shader_validation_test.js';export const g = makeTestGroup(ShaderValidationTest);const kAtomicOps = {atomicStoreMin: (a: string, v: string) => `atomicStoreMin(${a}, ${v})`,atomicStoreMax: (a: string, v: string) => `atomicStoreMax(${a}, ${v})`,};g.test('requires_extension').desc('Tests that atomicStoreMin and atomicStoreMax require the atomic_vec2u_min_max extension').params(u => u.combine('op', keysOf(kAtomicOps)).combine('enable', [true, false])).fn(t => {const code = `${t.params.enable ? 'enable atomic_vec2u_min_max;' : ''}@group(0) @binding(0) var<storage, read_write> a : atomic<vec2u>;fn foo() {${kAtomicOps[t.params.op]('&a', 'vec2u(1, 1)')};}`;t.expectCompileResult(t.params.enable, code);});g.test('stage').desc('Tests that atomicStoreMin and atomicStoreMax must not be used in vertex shader stage').params(u =>u.combine('op', keysOf(kAtomicOps)).combine('stage', ['fragment', 'vertex', 'compute'] as const)).fn(t => {let code = `enable atomic_vec2u_min_max;@group(0) @binding(0) var<storage, read_write> a : atomic<vec2u>;`;const op = kAtomicOps[t.params.op]('&a', 'vec2u(1, 1)');switch (t.params.stage) {case 'compute':code += `@compute @workgroup_size(1,1,1) fn main() {${op};}`;break;case 'fragment':code += `@fragment fn main() -> @location(0) vec4<f32> {${op};return vec4<f32>();}`;break;case 'vertex':code += `@vertex fn vmain() -> @builtin(position) vec4<f32> {${op};return vec4<f32>();}`;break;}const pass = t.params.stage !== 'vertex';t.expectCompileResult(pass, code);});g.test('atomic_ptr_parameterization').desc('Tests the valid atomic_ptr parameters').params(u =>u.combine('op', keysOf(kAtomicOps)).beginSubcases().combine('aspace', ['storage', 'workgroup', 'private', 'uniform', 'function'] as const).combine('access', ['read', 'read_write'] as const).combine('style', ['param', 'var'] as const).filter(t => {switch (t.aspace) {case 'uniform':return t.style === 'param' && t.access === 'read';case 'workgroup':return t.access === 'read_write';case 'function':case 'private':return t.style === 'param' && t.access === 'read_write';default:return true;}})).fn(t => {let moduleVar = ``;let functionVar = ``;let param = ``;let aParam = ``;if (t.params.style === 'var') {aParam = `&a`;switch (t.params.aspace) {case 'storage':moduleVar = `@group(0) @binding(0) var<storage, ${t.params.access}> a : atomic<vec2u>;`;break;case 'workgroup':moduleVar = `var<workgroup> a : atomic<vec2u>;`;break;case 'uniform':moduleVar = `@group(0) @binding(0) var<uniform> a : atomic<vec2u>;`;break;case 'private':moduleVar = `var<private> a : atomic<vec2u>;`;break;case 'function':functionVar = `var a : atomic<vec2u>;`;break;default:break;}} else {const aspaceParam = t.params.aspace === 'storage' ? `, ${t.params.access}` : ``;param = `p : ptr<${t.params.aspace}, atomic<vec2u>${aspaceParam}>`;aParam = `p`;}const code = `enable atomic_vec2u_min_max;${moduleVar}fn foo(${param}) {${functionVar}${kAtomicOps[t.params.op](aParam, 'vec2u(1, 1)')};}`;const aspaceOK = t.params.aspace === 'storage';const accessOK = t.params.access === 'read_write';t.expectCompileResult(aspaceOK && accessOK, code);});g.test('value_parameter').desc('Validates that the value parameter must be vec2u').params(u =>u.combine('op', keysOf(kAtomicOps)).beginSubcases().combine('valueType', ['vec2u','vec2<u32>','vec2i','vec2<i32>','vec2f','vec2<f32>','u32','i32','vec2<AbstractInt>','vec2<AbstractFloat>',] as const)).fn(t => {let value = '';switch (t.params.valueType) {case 'vec2u':case 'vec2<u32>':value = 'vec2u(1u, 1u)';break;case 'vec2i':case 'vec2<i32>':value = 'vec2i(1i, 1i)';break;case 'vec2f':case 'vec2<f32>':value = 'vec2f(1f, 1f)';break;case 'u32':value = '1u';break;case 'i32':value = '1i';break;case 'vec2<AbstractInt>':value = 'vec2(1, 1)';break;case 'vec2<AbstractFloat>':value = 'vec2(1.0, 1.0)';break;}const code = `enable atomic_vec2u_min_max;@group(0) @binding(0) var<storage, read_write> a : atomic<vec2u>;fn foo() {${kAtomicOps[t.params.op]('&a', value)};}`;const expect =t.params.valueType === 'vec2u' ||t.params.valueType === 'vec2<u32>' ||t.params.valueType === 'vec2<AbstractInt>';t.expectCompileResult(expect, code);});g.test('return_type').desc('Validates that atomicStoreMin and atomicStoreMax return void').params(u => u.combine('op', keysOf(kAtomicOps))).fn(t => {const code = `enable atomic_vec2u_min_max;@group(0) @binding(0) var<storage, read_write> a: atomic<vec2u>;fn foo() {let x = ${kAtomicOps[t.params.op]('&a', 'vec2u(1, 1)')};}`;t.expectCompileResult(false, code);});g.test('atomic_ptr_type').desc('Validates that the atomic_ptr parameter must be atomic<vec2u>').params(u =>u.combine('op', keysOf(kAtomicOps)).beginSubcases().combine('atomicType', ['vec4u', 'vec2u', 'u32', 'i32'] as const)).fn(t => {const code = `enable atomic_vec2u_min_max;@group(0) @binding(0) var<storage, read_write> a : atomic<${t.params.atomicType}>;fn foo() {${kAtomicOps[t.params.op]('&a', `${t.params.atomicType} ( 1) `)};}`;const expect = t.params.atomicType === 'vec2u';t.expectCompileResult(expect, code);});g.test('non_atomic').desc('Test that non-atomic vec2u are rejected').params(u =>u.combine('op', keysOf(kAtomicOps)).combine('addrspace', ['storage', 'workgroup'] as const).combine('atomic', [true, false])).fn(t => {const type = t.params.atomic ? 'atomic<vec2u>' : 'vec2u';let decl = '';if (t.params.addrspace === 'storage') {decl = `@group(0) @binding(0) var<storage, read_write> a : ${type}`;} else if (t.params.addrspace === 'workgroup') {decl = `var<workgroup> a : ${type}`;}const code = `enable atomic_vec2u_min_max;${decl};fn foo() {${kAtomicOps[t.params.op]('&a', 'vec2u(1, 1)')};}`;t.expectCompileResult(t.params.atomic && t.params.addrspace === 'storage', code);});