blob: aed28c81cf53abd524f43597fa2b3b7e5df13d34 [file] [log] [blame]
export const description = `
Swizzle assignment execution.
`;
import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { keysOf } from '../../../../common/util/data_tables.js';
import { TypedArrayBufferView } from '../../../../common/util/util.js';
import { Float16Array } from '../../../../external/petamoriken/float16/float16.js';
import { AllFeaturesMaxLimitsGPUTest, GPUTest } from '../../../gpu_test.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
/**
* Builds, runs then checks the output of a shader test with a swizzle assignment.
*
* @param t The test object
* @param elemType The type of the vector elements
* @param vecSize The size of the vector
* @param initial The initial values of the vector
* @param swizzle The swizzle string for the assignment
* @param rhs The WGSL string for the right-hand side of the assignment
* @param expectedValues The expected final values of the vector after the assignment
*/
export function runSwizzleAssignmentTest(
t: GPUTest,
elemType: SwizzleAssignmentCase['elemType'],
vecSize: SwizzleAssignmentCase['vecSize'],
initial: readonly number[],
swizzle: string,
rhs: string,
expectedValues: readonly number[]
) {
t.skipIfLanguageFeatureNotSupported('swizzle_assignment');
if (elemType === 'f16') {
t.skipIfDeviceDoesNotHaveFeature('shader-f16');
}
const vecType = `vec${vecSize}<${elemType}>`;
const initialValues =
elemType === 'bool'
? initial.map(v => (v === 0 ? 'false' : 'true')).join(', ')
: initial.join(', ');
const outputElemType = elemType === 'bool' ? 'u32' : elemType;
const wgsl = `
requires swizzle_assignment;
${elemType === 'f16' ? 'enable f16;' : ''}
struct Outputs {
data : array<${outputElemType}>,
};
@group(0) @binding(1) var<storage, read_write> outputs : Outputs;
@compute @workgroup_size(1)
fn main() {
var v = ${vecType}(${initialValues});
v.${swizzle} = ${rhs};
// Store result to Output
for (var i = 0; i < ${vecSize}; i++) {
${elemType === 'bool' ? 'outputs.data[i] = u32(v[i]);' : 'outputs.data[i] = v[i];'}
}
}
`;
const pipeline = t.device.createComputePipeline({
layout: 'auto',
compute: {
module: t.device.createShaderModule({ code: wgsl }),
entryPoint: 'main',
},
});
const maxOutputValues = 1000;
const outputBuffer = t.createBufferTracked({
size: 4 * (1 + maxOutputValues),
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
});
const bindGroup = t.device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 1, resource: { buffer: outputBuffer } }],
});
const encoder = t.device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(1);
pass.end();
t.queue.submit([encoder.finish()]);
let outputArrayConstructor: { new (values: readonly number[]): TypedArrayBufferView };
switch (elemType) {
case 'u32':
outputArrayConstructor = Uint32Array;
break;
case 'i32':
outputArrayConstructor = Int32Array;
break;
case 'f32':
outputArrayConstructor = Float32Array;
break;
case 'f16':
outputArrayConstructor = Float16Array;
break;
case 'bool':
outputArrayConstructor = Uint32Array;
break;
}
t.expectGPUBufferValuesEqual(outputBuffer, new outputArrayConstructor(expectedValues));
}
interface SwizzleAssignmentCase {
elemType: 'u32' | 'i32' | 'f32' | 'f16' | 'bool';
vecSize: 2 | 3 | 4;
initial: readonly number[];
swizzle: string;
rhs: string;
expected: readonly number[];
}
const kSwizzleAssignmentCases: Record<string, SwizzleAssignmentCase> = {
// v = vec4u(1, 2, 3, 4)
// v.w = 5;
vec4u_w_literal: {
elemType: 'u32',
vecSize: 4,
initial: [1, 2, 3, 4],
swizzle: 'w',
rhs: '5',
expected: [1, 2, 3, 5],
},
// v = vec4u(1, 2, 3, 5)
// v.xy = vec2u(6, 7);
vec4u_xy_vec2u: {
elemType: 'u32',
vecSize: 4,
initial: [1, 2, 3, 5],
swizzle: 'xy',
rhs: 'vec2u(6, 7)',
expected: [6, 7, 3, 5],
},
// v = vec4u(6, 7, 3, 5)
// v.zx = vec2u(8, 9);
vec4u_zx_vec2u: {
elemType: 'u32',
vecSize: 4,
initial: [6, 7, 3, 5],
swizzle: 'zx',
rhs: 'vec2u(8, 9)',
expected: [9, 7, 8, 5],
},
// v = vec4u(1, 1, 1, 1)
// v.xyzw = vec4u(10, 11, 12, 13);
vec4u_xyzw_vec4u: {
elemType: 'u32',
vecSize: 4,
initial: [1, 1, 1, 1],
swizzle: 'xyzw',
rhs: 'vec4u(10, 11, 12, 13)',
expected: [10, 11, 12, 13],
},
// v = vec4u(10, 11, 12, 13)
// v.xy = vec2(v.y, v.x);
vec4u_xy_vec2_yx: {
elemType: 'u32',
vecSize: 4,
initial: [10, 11, 12, 13],
swizzle: 'xy',
rhs: 'vec2(v.y, v.x)',
expected: [11, 10, 12, 13],
},
// v = vec3i(-10, -20, -30)
// v.y = 50;
vec3i_y_literal: {
elemType: 'i32',
vecSize: 3,
initial: [-10, -20, -30],
swizzle: 'y',
rhs: '-50',
expected: [-10, -50, -30],
},
// v = vec3i(10, 20, 30)
// v.zx = vec2i(40, 60);
vec3i_zx_vec2i: {
elemType: 'i32',
vecSize: 3,
initial: [10, 20, 30],
swizzle: 'zx',
rhs: 'vec2i(40, 60)',
expected: [60, 20, 40],
},
// v = vec3f(1.0, 2.0, 3.0)
// v.xy = vec2f(4.0, 5.0);
vec3f_xy_vec2f: {
elemType: 'f32',
vecSize: 3,
initial: [1.0, 2.0, 3.0],
swizzle: 'xy',
rhs: 'vec2f(4.0, 5.0)',
expected: [4.0, 5.0, 3.0],
},
// v = vec2f(1.0, 2.0)
// v.xy = v + v;
vec2f_yx_v_plus_v: {
elemType: 'f32',
vecSize: 2,
initial: [1.0, 2.0],
swizzle: 'yx',
rhs: 'v + v',
expected: [4.0, 2.0],
},
// v = vec4f(10.0, 20.0, 30.0, 100.0)
// v.rgb = vec3f(v.r, v.g, v.b) / 10;
vec4f_rgb_vec3f_div_10: {
elemType: 'f32',
vecSize: 4,
initial: [10.0, 20.0, 30.0, 100.0],
swizzle: 'rgb',
rhs: 'vec3f(v.r, v.g, v.b) / 10',
expected: [1.0, 2.0, 3.0, 100.0],
},
// v = vec2h(1.0, 2.0)
// v.yx = vec2h(4.0, 5.0);
vec2h_yx_vec2h: {
elemType: 'f16',
vecSize: 2,
initial: [1.0, 2.0],
swizzle: 'yx',
rhs: 'vec2h(4.0, 5.0)',
expected: [5.0, 4.0],
},
// v = vec2<bool>(true, false)
// v.y = true;
vec2_bool_y_true: {
elemType: 'bool',
vecSize: 2,
initial: [1, 0],
swizzle: 'y',
rhs: 'true',
expected: [1, 1],
},
// v = vec3<bool>(true, true, true)
// v.xz = vec2<bool>(false, false);
vec3_bool_xz_vec2bool: {
elemType: 'bool',
vecSize: 3,
initial: [1, 1, 1],
swizzle: 'xz',
rhs: 'vec2<bool>(false, false)',
expected: [0, 1, 0],
},
};
g.test('swizzle_assignment_local_var')
.desc('Tests the value of a vector after swizzle assignment on a local function variable.')
.params(u => u.combine('case', keysOf(kSwizzleAssignmentCases)))
.fn(t => {
const { elemType, vecSize, initial, swizzle, rhs, expected } =
kSwizzleAssignmentCases[t.params.case];
runSwizzleAssignmentTest(t, elemType, vecSize, initial, swizzle, rhs, expected);
});
g.test('swizzle_assignment_other_vars')
.desc('Tests the value of a vector after swizzle assignment with other address spaces.')
.unimplemented();
g.test('swizzle_assignment_chained')
.desc('Tests the value of a vector after swizzle assignment on a chained swizzle.')
.unimplemented();
g.test('swizzle_assignment_pointer')
.desc('Tests the value of a vector after swizzle assignment on pointer to a swizzle.')
.unimplemented();
g.test('swizzle_compound_assignment')
.desc('Tests the value of a vector after compound swizzle assignment.')
.unimplemented();