Changeset 246824 in webkit


Ignore:
Timestamp:
Jun 25, 2019 6:40:52 PM (5 years ago)
Author:
Justin Fan
Message:

[WHLSL] Make whlsl-test-harness actually generate WHLSL shaders by default
https://bugs.webkit.org/show_bug.cgi?id=199028

Reviewed by Saam Barati.

whlsl-test-harness.js now generates WHLSL shaders and invokes WebKit's WHLSL compiler.
MSL mode remains to facilitate further harness tesing.
In addition, if WebGPU is not supported, synchronous Harness methods do nothing.
Asynchronous methods will throw a WebGPUUnsupportedError that "rejects" the returned Promise.

  • TestExpectations:
  • platform/mac/TestExpectations:
  • webgpu/js/whlsl-test-harness.js:

(WebGPUUnsupportedError): Layout tests should catch these to fail gracefully if WebGPU is not supported.
(Data):
(Data.prototype.async.getArrayBuffer):
(Data.prototype.get isBuffer): Renamed from isPointer.
(Harness):
(Harness.prototype.async.requestDevice): Can be used to re-acquire a GPUDevice.
(Harness.prototype.set isWHLSL): Determines whether harness will generate WHLSL or MSL shaders.
(Harness.prototype.async.callTypedFunction):
(Harness.prototype.callVoidFunction):
(Harness.prototype.get device):
(Harness.prototype._clearResults):
(Harness.prototype._setUpArguments):
(Harness.prototype._callFunction):
(Data.prototype.get isPointer): Deleted.
(Harness.prototype._initialize): Deleted.
(Harness.prototype.async.callVoidFunction): Deleted.
(harness._initialize.async): Deleted.

  • webgpu/msl-harness-test-expected.txt: Renamed from LayoutTests/webgpu/whlsl-harness-test-expected.txt.
  • webgpu/msl-harness-test.html: Copied from LayoutTests/webgpu/whlsl-harness-test.html.
  • webgpu/whlsl-test-harness-test-expected.html: Added.
  • webgpu/whlsl-test-harness-test.html: Renamed from LayoutTests/webgpu/whlsl-harness-test.html.
Location:
trunk/LayoutTests
Files:
4 edited
2 copied
2 moved

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r246817 r246824  
     12019-06-25  Justin Fan  <justin_fan@apple.com>
     2
     3        [WHLSL] Make whlsl-test-harness actually generate WHLSL shaders by default
     4        https://bugs.webkit.org/show_bug.cgi?id=199028
     5
     6        Reviewed by Saam Barati.
     7
     8        whlsl-test-harness.js now generates WHLSL shaders and invokes WebKit's WHLSL compiler.
     9        MSL mode remains to facilitate further harness tesing.
     10        In addition, if WebGPU is not supported, synchronous Harness methods do nothing.
     11        Asynchronous methods will throw a WebGPUUnsupportedError that "rejects" the returned Promise.
     12
     13        * TestExpectations:
     14        * platform/mac/TestExpectations:
     15        * webgpu/js/whlsl-test-harness.js:
     16        (WebGPUUnsupportedError): Layout tests should catch these to fail gracefully if WebGPU is not supported.
     17        (Data):
     18        (Data.prototype.async.getArrayBuffer):
     19        (Data.prototype.get isBuffer): Renamed from isPointer.
     20        (Harness):
     21        (Harness.prototype.async.requestDevice): Can be used to re-acquire a GPUDevice.
     22        (Harness.prototype.set isWHLSL): Determines whether harness will generate WHLSL or MSL shaders.
     23        (Harness.prototype.async.callTypedFunction):
     24        (Harness.prototype.callVoidFunction):
     25        (Harness.prototype.get device):
     26        (Harness.prototype._clearResults):
     27        (Harness.prototype._setUpArguments):
     28        (Harness.prototype._callFunction):
     29        (Data.prototype.get isPointer): Deleted.
     30        (Harness.prototype._initialize): Deleted.
     31        (Harness.prototype.async.callVoidFunction): Deleted.
     32        (harness._initialize.async): Deleted.
     33        * webgpu/msl-harness-test-expected.txt: Renamed from LayoutTests/webgpu/whlsl-harness-test-expected.txt.
     34        * webgpu/msl-harness-test.html: Copied from LayoutTests/webgpu/whlsl-harness-test.html.
     35        * webgpu/whlsl-test-harness-test-expected.html: Added.
     36        * webgpu/whlsl-test-harness-test.html: Renamed from LayoutTests/webgpu/whlsl-harness-test.html.
     37
    1382019-06-25  Daniel Bates  <dabates@apple.com>
    239
  • trunk/LayoutTests/TestExpectations

    r246788 r246824  
    34413441
    34423442webkit.org/b/199039 editing/deleting/smart-delete-paragraph-003.html [ Skip ]
     3443
     3444webkit.org/b/199028 webgpu/whlsl-test-harness-test.html [ Slow ]
  • trunk/LayoutTests/platform/mac/TestExpectations

    r246806 r246824  
    17871787webkit.org/b/192956 [ Sierra ] inspector/canvas/resolveCanvasContext-webgpu.html [ Skip ]
    17881788
    1789 webkit.org/b/199076 [ HighSierra ] webgpu/whlsl-harness-test.html [ Skip ]
     1789webkit.org/b/199076 [ HighSierra ] webgpu/whlsl-test-harness-test.html [ Skip ]
     1790webkit.org/b/199028 [ HighSierra ] webgpu/msl-harness-test.html [ Skip ]
    17901791
    17911792webkit.org/b/189680 platform/mac/media/audio-session-category-video-paused.html [ Pass Timeout ]
  • trunk/LayoutTests/webgpu/js/whlsl-test-harness.js

    r246628 r246824  
    6464/* Harness Classes */
    6565
     66class WebGPUUnsupportedError extends Error {
     67    constructor()
     68    {
     69        super("No GPUDevice detected!");
     70    }
     71};
     72
    6673class Data {
    6774    /**
     
    7077     * @param {Number or Array[Number]} values - The raw data to be uploaded.
    7178     */
    72     constructor(harness, type, values, isPointer = false)
    73     {
    74         // One or more scalars in an array can be accessed through a pointer to buffer.
     79    constructor(harness, type, values, isBuffer = false)
     80    {
     81        if (harness.device === undefined)
     82            return;
     83        // One or more scalars in an array can be accessed through an array reference.
    7584        // However, vector types are also created via an array of scalars.
    7685        // This ensures that buffers of just one vector are usable in a test function.
    7786        if (Array.isArray(values))
    78             this._isPointer = isVectorType(type) ? isPointer : true;
     87            this._isBuffer = isVectorType(type) ? isBuffer : true;
    7988        else {
    80             this._isPointer = false;
     89            this._isBuffer = false;
    8190            values = [values];
    8291        }
     
    8594        this._byteLength = (convertTypeToArrayType(type)).BYTES_PER_ELEMENT * values.length;
    8695
    87         const [buffer, arrayBuffer] = harness._device.createBufferMapped({
     96        const [buffer, arrayBuffer] = harness.device.createBufferMapped({
    8897            size: this._byteLength,
    8998            usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ
     
    102111    async getArrayBuffer()
    103112    {
     113        if (harness.device === undefined)
     114            throw new WebGPUUnsupportedError();
     115
    104116        let result;
    105117        try {
     
    113125
    114126    get type() { return this._type; }
    115     get isPointer() { return this._isPointer; }
     127    get isBuffer() { return this._isBuffer; }
    116128    get buffer() { return this._buffer; }
    117129    get byteLength() { return this._byteLength; }
     
    119131
    120132class Harness {
    121     constructor()
    122     {
    123         this._shaderHeader = `#include <metal_stdlib>
    124         using namespace metal;
     133    constructor ()
     134    {
     135        this.isWHLSL = true;
     136    }
     137
     138    async requestDevice()
     139    {
     140        try {
     141            const adapter = await navigator.gpu.requestAdapter();
     142            this._device = await adapter.requestDevice();
     143        } catch {
     144            // WebGPU is not supported.
     145            // FIXME: Add support for GPUAdapterRequestOptions and GPUDeviceDescriptor,
     146            // and differentiate between descriptor validation errors and no WebGPU support.
     147        }
     148    }
     149
     150    // Sets whether Harness generates WHLSL or MSL shaders.
     151    set isWHLSL(value)
     152    {
     153        this._isWHLSL = value;
     154        this._shaderHeader = value ? "" : `
     155#include <metal_stdlib>
     156using namespace metal;
    125157        `;
    126     }
    127 
    128     _initialize(callback)
    129     {
    130         callback.bind(this)();
    131158    }
    132159
     
    141168    async callTypedFunction(type, functions, name, args)
    142169    {   
    143         const [argsLayouts, argsResourceBindings, argsStructCode, functionCallArgs] = this._setUpArguments(args);
    144 
    145         if (!this._resultBuffer) {
    146             this._resultBuffer = this._device.createBuffer({
     170        if (this._device === undefined)
     171            throw new WebGPUUnsupportedError();
     172
     173        const [argsLayouts, argsResourceBindings, argsDeclarations, functionCallArgs] = this._setUpArguments(args);
     174
     175        if (this._resultBuffer) {
     176            this._clearResults()
     177        } else {
     178            this._resultBuffer = this.device.createBuffer({
    147179                size: Types.MAX_SIZE,
    148                 usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ
     180                usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ | GPUBufferUsage.TRANSFER_DST
    149181            });
    150182        }
     
    163195        });
    164196
    165         const code = this._shaderHeader + functions + `
    166         struct _compute_args {
    167             device ${convertTypeToWHLSLType(type)}* result [[id(0)]];
    168             ${argsStructCode}};
    169    
    170         kernel void _compute_main(device _compute_args& args [[buffer(0)]])
    171         {
    172             *args.result = ${name}(${functionCallArgs.join(", ")});
    173         }
    174         `;
    175    
     197        let entryPointCode;
     198        if (this._isWHLSL) {
     199            argsDeclarations.unshift(`device ${convertTypeToWHLSLType(type)}[] result : register(u0)`);
     200            entryPointCode = `
     201[numthreads(1, 1, 1)]
     202compute void _compute_main(${argsDeclarations.join(", ")})
     203{
     204    result[0] = ${name}(${functionCallArgs.join(", ")});
     205}
     206`;
     207        } else {
     208            argsDeclarations.unshift(`device ${convertTypeToWHLSLType(type)}* result [[id(0)]];`);
     209            entryPointCode = `
     210struct _compute_args {
     211    ${argsDeclarations.join("\n")}
     212};
     213
     214kernel void _compute_main(device _compute_args& args [[buffer(0)]])
     215{
     216    *args.result = ${name}(${functionCallArgs.join(", ")});
     217}
     218`;
     219        }
     220        const code = this._shaderHeader + functions + entryPointCode;
    176221        this._callFunction(code, argsLayouts, argsResourceBindings);
    177222   
     
    193238     * @param {Data or Array[Data]} args - Data arguments to be passed to the call of 'name'.
    194239     */
    195     async callVoidFunction(functions, name, args)
    196     {
    197         const [argsLayouts, argsResourceBindings, argsStructCode, functionCallArgs] = this._setUpArguments(args);
    198 
    199         const code = this._shaderHeader + functions + `
    200         struct _compute_args {
    201             ${argsStructCode}};
    202 
    203         kernel void _compute_main(device _compute_args& args [[buffer(0)]])
    204         {
    205             ${name}(${functionCallArgs.join(", ")});
    206         }
    207         `;
    208 
     240    callVoidFunction(functions, name, args)
     241    {
     242        if (this._device === undefined)
     243            return;
     244
     245        const [argsLayouts, argsResourceBindings, argsDeclarations, functionCallArgs] = this._setUpArguments(args);
     246
     247        let entryPointCode;
     248        if (this._isWHLSL) {
     249            entryPointCode = `
     250[numthreads(1, 1, 1)]
     251compute void _compute_main(${argsDeclarations.join(", ")})
     252{
     253    ${name}(${functionCallArgs.join(", ")});
     254}`;
     255        } else {
     256            entryPointCode = `
     257struct _compute_args {
     258    ${argsDeclarations.join("\n")}
     259};
     260
     261kernel void _compute_main(device _compute_args& args [[buffer(0)]])
     262{
     263    ${name}(${functionCallArgs.join(", ")});
     264}
     265`;
     266        }
     267        const code = this._shaderHeader + functions + entryPointCode;
    209268        this._callFunction(code, argsLayouts, argsResourceBindings);
     269    }
     270
     271    get device() { return this._device; }
     272
     273    _clearResults()
     274    {
     275        if (!this._clearBuffer) {
     276            this._clearBuffer = this._device.createBuffer({
     277                size: Types.MAX_SIZE,
     278                usage: GPUBufferUsage.TRANSFER_SRC
     279            });
     280        }
     281        const commandEncoder = this._device.createCommandEncoder();
     282        commandEncoder.copyBufferToBuffer(this._clearBuffer, 0, this._resultBuffer, 0, Types.MAX_SIZE);
     283        this._device.getQueue().submit([commandEncoder.finish()]);
    210284    }
    211285
     
    219293        }
    220294
    221         // FIXME: Replace with WHLSL.
    222295        // Expand bind group structure to represent any arguments.
    223         let argsStructCode = "";
     296        let argsDeclarations = [];
    224297        let functionCallArgs = [];
    225298        let argsLayouts = [];
     
    228301        for (let i = 1; i <= args.length; ++i) {
    229302            const arg = args[i - 1];
    230             argsStructCode += `device ${convertTypeToWHLSLType(arg.type)}* arg${i} [[id(${i})]];
    231             `;
    232             const optionalDeref = (!arg.isPointer) ? "*" : "";
    233             functionCallArgs.push(optionalDeref + `args.arg${i}`);
     303            if (this._isWHLSL) {
     304                argsDeclarations.push(`device ${convertTypeToWHLSLType(arg.type)}[] arg${i} : register(u${i})`);
     305                functionCallArgs.push(`arg${i}` + (arg.isBuffer ? "" : "[0]"));
     306            } else {
     307                argsDeclarations.push(`device ${convertTypeToWHLSLType(arg.type)}* arg${i} [[id(${i})]];`);
     308                functionCallArgs.push((arg.isBuffer ? "" : "*") + `args.arg${i}`);
     309            }
    234310            argsLayouts.push({
    235311                binding: i,
     
    246322        }
    247323
    248         return [argsLayouts, argsResourceBindings, argsStructCode, functionCallArgs];
     324        return [argsLayouts, argsResourceBindings, argsDeclarations, functionCallArgs];
    249325    }
    250326
    251327    _callFunction(code, argsLayouts, argsResourceBindings)
    252328    {
    253         const shaders = this._device.createShaderModule({ code: code });
     329        const shaders = this._device.createShaderModule({ code: code, isWHLSL: this._isWHLSL });
     330
     331        const bindGroupLayout = this._device.createBindGroupLayout({
     332            bindings: argsLayouts
     333        });
     334
     335        const pipelineLayout = this._device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] });
     336
     337        const bindGroup = this._device.createBindGroup({
     338            layout: bindGroupLayout,
     339            bindings: argsResourceBindings
     340        });
     341
    254342        // FIXME: Compile errors should be caught and reported here.
    255343        const pipeline = this._device.createComputePipeline({
     344            layout: pipelineLayout,
    256345            computeStage: {
    257346                module: shaders,
     
    260349        });
    261350
    262         const layout = this._device.createBindGroupLayout({
    263             bindings: argsLayouts
    264         });
    265    
    266         const bindGroup = this._device.createBindGroup({
    267             layout: layout,
    268             bindings: argsResourceBindings
    269         });
    270        
    271351        const commandEncoder = this._device.createCommandEncoder();
    272352        const passEncoder = commandEncoder.beginComputePass();
     
    283363
    284364const harness = new Harness();
    285 harness._initialize(async () => {
    286     try {
    287         const adapter = await navigator.gpu.requestAdapter();
    288         harness._device = await adapter.requestDevice();
    289     } catch (e) {
    290         throw new Error("Harness error: Unable to acquire GPUDevice!");
    291     }
    292 });
     365harness.requestDevice();
    293366
    294367/* Global Helper Functions */
  • trunk/LayoutTests/webgpu/msl-harness-test.html

    r246823 r246824  
    2525};
    2626
    27 let tests = {};
    28 
    29 tests.literals = () => {
     27let mslTests = {};
     28
     29mslTests.literals = () => {
    3030    checkBools("Return a literal of type bool.", "return true;");
    3131    checkFloat4s("return float4(0, 1, 2, 3);");
     
    3333};
    3434
    35 tests.singleArgument = () => {
     35mslTests.singleArgument = () => {
    3636    checkBools("Upload and return a bool value.", "return in0;", [true]);
    3737    checkFloat4s("return in0.wzyx;", [[3, 2, 1, 0]]);
     
    3939};
    4040
    41 tests.manyArguments = () => {
     41mslTests.manyArguments = () => {
    4242    checkBools("Upload many bool values and return a calculated result.",
    4343        "return in0 & in1 & in2 & in3 & in4 & in5 & in6 & in7;", 
     
    5252};
    5353
    54 tests.buffersWithOneValue = () => {
     54mslTests.buffersWithOneValue = () => {
    5555    const body = `return in0[0];`
    5656    checkBools("Access and return a single bool through a bool*.", body, [[true]]);
     
    5959};
    6060
    61 tests.multipleBufferArguments = () => {
     61mslTests.multipleBufferArguments = () => {
    6262    checkBools("Access multiple bools through various buffers and return a bool.",
    6363        "return in0[0] & in0[1] & in0[2] & in1 & in2[0];",
     
    7070};
    7171
    72 tests.multipleArgumentTypes = () => {
     72mslTests.multipleArgumentTypes = () => {
    7373    const src = `float test(int i, uchar c, device uint* u, bool b, device bool* bs, float4 f4, device float* fs)
    7474    {
     
    8585    const f4 = makeFloat4([4, 5, 6, 7]);
    8686    const fs = makeFloat([8, 9]);
    87     promise_test(() => {
     87    webGPUPromiseTest(() => {
    8888        return callFloatFunction(src, "test", [i, c, u, b, bs, f4, fs]).then(result => {
    8989            assert_approx_equals(result, 45, epsilon, "Test returned expected value.");
     
    9292};
    9393
    94 tests.bufferStores = () => {
     94mslTests.bufferStores = () => {
    9595    let src = `void test(device float4* out) {
    9696        *out = float4(0, 1, 2, 3);
     
    9999    callVoidFunction(src, "test", float4Out);
    100100
    101     promise_test(() => {
     101    webGPUPromiseTest(() => {
    102102        return float4Out.getArrayBuffer().then(arrayBuffer => {
    103103            const result = new Float32Array(arrayBuffer);
     
    117117    callVoidFunction(src, "test", [input, output]);
    118118
    119     promise_test(() => {
     119    webGPUPromiseTest(() => {
    120120        return output.getArrayBuffer().then(arrayBuffer => {
    121121            const result = new Uint8Array(arrayBuffer);
     
    126126
    127127window.addEventListener("load", () => {
    128     for (const name in tests) {
    129         tests[name]();
     128    harness.isWHLSL = false;
     129    for (const name in mslTests) {
     130        mslTests[name]();
    130131    }
    131132});
     
    154155    for (const f of functions) {
    155156        const callFunc = numericScalarFuncs[f.type];
    156         promise_test(async () => {
     157        webGPUPromiseTest(async () => {
    157158            return callFunc(src, f.name, f.args).then(result => {
    158159                assert_approx_equals(result, f.expected, epsilon, "Test returned expected value.");
     
    175176    `;
    176177
    177     promise_test(async () => {
     178    webGPUPromiseTest(async () => {
    178179        return callBoolFunction(src, "boolTest", values).then(result => {
    179180            assert_equals(result, expected, "Test returned expected value.");
     
    198199    `;
    199200
    200     promise_test(async () => {
     201    webGPUPromiseTest(async () => {
    201202        return callFloat4Function(src, "float4Test", values).then(result => {
    202203            for (let i = 0; i < 4; ++i)
     
    205206    }, "Return an expected float4 value.");
    206207}
     208
     209const webGPUPromiseTest = (testFunc, msg) => {
     210    promise_test(async () => {
     211        return testFunc().catch(e => {
     212        if (!(e instanceof WebGPUUnsupportedError))
     213            throw e;
     214        });
     215    }, msg);
     216}
    207217</script>
    208218</html>
  • trunk/LayoutTests/webgpu/whlsl-test-harness-test-expected.txt

    r246823 r246824  
    11
    2 PASS Return a literal of type bool.
    32PASS Return an expected float4 value.
    43PASS Return an expected int value.
    5 PASS Return an expected uchar value.
    64PASS Return an expected uint value.
    75PASS Return an expected float value.
    8 PASS Upload and return a bool value.
    96PASS Return an expected float4 value.
    107PASS Return an expected int value.
    11 PASS Return an expected uchar value.
    128PASS Return an expected uint value.
    139PASS Return an expected float value.
    14 PASS Upload many bool values and return a calculated result.
    1510PASS Return an expected float4 value.
    1611PASS Return an expected int value.
    17 PASS Return an expected uchar value.
    1812PASS Return an expected uint value.
    1913PASS Return an expected float value.
    20 PASS Access and return a single bool through a bool*.
    2114PASS Return an expected float4 value.
    2215PASS Return an expected int value.
    23 PASS Return an expected uchar value.
    2416PASS Return an expected uint value.
    2517PASS Return an expected float value.
    26 PASS Access multiple bools through various buffers and return a bool.
    2718PASS Return an expected float4 value.
    2819PASS Return an expected int value.
    29 PASS Return an expected uchar value.
    3020PASS Return an expected uint value.
    3121PASS Return an expected float value.
    3222PASS Upload and calculate a result from varied argument types.
    33 PASS Store into a float4*.
    34 PASS Upload a uchar* and store into a uchar*.
     23PASS Store into a float4[].
     24PASS Upload a int[] and store into a int[].
    3525
  • trunk/LayoutTests/webgpu/whlsl-test-harness-test.html

    r246823 r246824  
    22<html>
    33<meta charset=utf-8>
     4<meta name="timeout" content="long">
    45<title>Test the WHLSL test harness.</title>
    56<script src="js/whlsl-test-harness.js"></script>
     
    910const epsilon = 0.0001;
    1011
    11 const numericScalarTypes = ["int", "uchar", "uint", "float"];
     12// FIXME: Add "uchar" back in when operator+(uchar, uchar) is available.
     13const numericScalarTypes = ["int", "uint", "float"];
    1214
    1315const numericScalarFuncs = {
     
    1921
    2022const scalarArgMakers = {
     23    "bool": makeBool,
    2124    "int": makeInt,
    2225    "uchar": makeUchar,
     
    2528};
    2629
    27 let tests = {};
    28 
    29 tests.literals = () => {
     30let whlslTests = {};
     31
     32whlslTests.literals = () => {
    3033    checkBools("Return a literal of type bool.", "return true;");
    3134    checkFloat4s("return float4(0, 1, 2, 3);");
     
    3336};
    3437
    35 tests.singleArgument = () => {
     38whlslTests.singleArgument = () => {
    3639    checkBools("Upload and return a bool value.", "return in0;", [true]);
    37     checkFloat4s("return in0.wzyx;", [[3, 2, 1, 0]]);
     40    checkFloat4s("return in0;", [[0, 1, 2, 3]]);
    3841    checkNumericScalars("return in0;", [42], 42);
    3942};
    4043
    41 tests.manyArguments = () => {
     44whlslTests.manyArguments = () => {
    4245    checkBools("Upload many bool values and return a calculated result.",
    43         "return in0 & in1 & in2 & in3 & in4 & in5 & in6 & in7;", 
     46        "return in0 & in1 & in2 & in3 & in4 & in5 & in6 & in7;",
    4447        [true, true, true, true, true, true, true, true]);
    4548
    46     const body = `return in0 + in1 + in2 + in3 + in4 + in5 + in6 + in7;`;
     49    let body = "return float4(in0.x, in1.y, in2.z, in3.w);"
    4750    let args = [];
    48     for (let i = 0; i < 8; ++i)
     51    for (let i = 0; i < 4; ++i)
    4952        args.push([0, 1, 2, 3]);
    50     checkFloat4s(body, args, [0, 8, 16, 24]);
     53    checkFloat4s(body, args, [0, 1, 2, 3]);
     54
     55    body = `return in0 + in1 + in2 + in3 + in4 + in5 + in6 + in7;`;
    5156    checkNumericScalars(body, [0, 1, 2, 3, 4, 5, 6, 7], 28);
    5257};
    5358
    54 tests.buffersWithOneValue = () => {
     59whlslTests.buffersWithOneValue = () => {
    5560    const body = `return in0[0];`
    56     checkBools("Access and return a single bool through a bool*.", body, [[true]]);
     61    checkBools("Access and return a single bool through a bool[].", body, [[true]]);
    5762    checkFloat4s(body, [[[0, 1, 2, 3]]]);
    5863    checkNumericScalars(body, [[42]], 42);
    5964};
    6065
    61 tests.multipleBufferArguments = () => {
     66whlslTests.multipleBufferArguments = () => {
    6267    checkBools("Access multiple bools through various buffers and return a bool.",
    6368        "return in0[0] & in0[1] & in0[2] & in1 & in2[0];",
    6469        [[true, true, true], true, [true]]);
    65    
    66     const body = `return in0[0] + in0[1] + in0[2] + in1 + in2[0];`;
     70
     71    let body = `
     72    float x = in0[0].x + in0[1].x + in0[2].x + in1.x + in2[0].x;
     73    float y = in0[0].y + in0[1].y + in0[2].y + in1.y + in2[0].y;
     74    float z = in0[0].z + in0[1].z + in0[2].z + in1.z + in2[0].z;
     75    float w = in0[0].w + in0[1].w + in0[2].w + in1.w + in2[0].w;
     76
     77    return float4(x, y, z, w);`;
    6778    const vector = [0, 1, 2, 3];
    6879    checkFloat4s(body, [[vector, vector, vector], vector, [vector]], [0, 5, 10, 15]);
     80
     81    body = `return in0[0] + in0[1] + in0[2] + in1 + in2[0];`;
    6982    checkNumericScalars(body, [[0, 1, 2], 3, [4]], 10);
    7083};
    7184
    72 tests.multipleArgumentTypes = () => {
    73     const src = `float test(int i, uchar c, device uint* u, bool b, device bool* bs, float4 f4, device float* fs)
     85whlslTests.multipleArgumentTypes = () => {
     86    const src = `float test(int i, uchar c, float4 f4, device uint[] u, device float[] fs)
    7487    {
    75         if (b && bs[0] && bs[1])
    76             return i + c + u[0] + f4.x + f4.y + f4.z + f4.w + fs[0] + fs[1];
    77        
    78         return 0;
     88        return float(i) + float(c) + f4.x + f4.y + f4.z + f4.w + float(u[0]) + fs[0] + fs[1];
    7989    }`;
    8090    const i = makeInt(1);
    8191    const c = makeUchar(2);
     92    const f4 = makeFloat4([4, 5, 6, 7]);
    8293    const u = makeUint([3]);
    83     const b = makeBool(true);
    84     const bs = makeBool([true, true]);
    85     const f4 = makeFloat4([4, 5, 6, 7]);
    8694    const fs = makeFloat([8, 9]);
    87     promise_test(() => {
    88         return callFloatFunction(src, "test", [i, c, u, b, bs, f4, fs]).then(result => {
     95    webGPUPromiseTest(() => {
     96        return callFloatFunction(src, "test", [i, c, f4, u, fs]).then(result => {
    8997            assert_approx_equals(result, 45, epsilon, "Test returned expected value.");
    9098        });
     
    92100};
    93101
    94 tests.bufferStores = () => {
    95     let src = `void test(device float4* out) {
    96         *out = float4(0, 1, 2, 3);
     102whlslTests.bufferStores = () => {
     103    let src = `void test(device float4[] out) {
     104        out[0] = float4(0, 1, 2, 3);
    97105    }`;
    98106    const float4Out = makeFloat4([[0, 0, 0, 0]]);
    99107    callVoidFunction(src, "test", float4Out);
    100108
    101     promise_test(() => {
     109    webGPUPromiseTest(() => {
    102110        return float4Out.getArrayBuffer().then(arrayBuffer => {
    103111            const result = new Float32Array(arrayBuffer);
     
    106114            }
    107115        });
    108     }, "Store into a float4*.");
    109 
    110     src = `void test(device uchar* in, device uchar* out) {
    111         for (uint i = 0; i < 5; ++i)
     116    }, "Store into a float4[].");
     117
     118    src = `void test(device int[] in, device int[] out) {
     119        for (uint i = 0; i < 5; i = i + 1)
    112120            out[i] = in[i];
    113121    }`;
    114122    const array = [0, 1, 2, 3, 4];
    115     const input = makeUchar(array);
    116     const output = makeUchar([0, 0, 0, 0, 0]);
     123    const input = makeInt(array);
     124    const output = makeInt([0, 0, 0, 0, 0]);
    117125    callVoidFunction(src, "test", [input, output]);
    118126
    119     promise_test(() => {
     127    webGPUPromiseTest(() => {
    120128        return output.getArrayBuffer().then(arrayBuffer => {
    121             const result = new Uint8Array(arrayBuffer);
     129            const result = new Uint32Array(arrayBuffer);
    122130            assert_array_equals(array, result, "Test stored expected values.");
    123131        });
    124     }, "Upload a uchar* and store into a uchar*.");
     132    }, "Upload a int[] and store into a int[].");
    125133};
    126134
    127135window.addEventListener("load", () => {
    128     for (const name in tests) {
    129         tests[name]();
     136    try {
     137        for (const name in whlslTests) {
     138            if (!name.startsWith("_"))
     139                whlslTests[name]();
     140        }
     141    } catch (e) {
     142        if (window.testRunner)
     143            testRunner.notifyDone();
     144       
     145        throw e;
    130146    }
    131147});
     
    137153    let src = "";
    138154    for (let type of numericScalarTypes) {
    139         const name = `${type}Test`;
    140 
    141         let inputArgs = [];
    142         let values = [];
    143         for (let i = 0; i < argValues.length; ++i) {
    144             const isPointer = Array.isArray(argValues[i]);
    145             inputArgs.push(`${isPointer ? "device " : ""}${type}${isPointer ? "*" : ""} in${i}`);
    146             values.push(scalarArgMakers[type](argValues[i]));
    147         }
    148        
    149         src += `${type} ${name}(${inputArgs.join(", ")}) { ${body} }
    150         `;
     155        let name, values;
     156        [src, name, values] = appendScalarFunctionToSource(src, type, body, argValues);
    151157        functions.push({ type: type, name: name, args: values, expected: expected });
    152158    }
     
    154160    for (const f of functions) {
    155161        const callFunc = numericScalarFuncs[f.type];
    156         promise_test(async () => {
     162        webGPUPromiseTest(async () => {
    157163            return callFunc(src, f.name, f.args).then(result => {
    158164                assert_approx_equals(result, f.expected, epsilon, "Test returned expected value.");
     
    163169
    164170const checkBools = (msg = "Return an expected bool value.", body, argValues = [], expected = true) => {
    165     let src = "";
     171    // FIXME (https://webkit.org/b/199093): Bool[] functions don't compile, so no-op for now.
     172    return;
     173
     174    const [src, name, values] = appendScalarFunctionToSource("", "bool", body, argValues);
     175
     176    webGPUPromiseTest(async () => {
     177        return callBoolFunction(src, name, values).then(result => {
     178            assert_equals(result, expected, "Test returned expected value.");
     179        }, e => {
     180            if (!(e instanceof WebGPUUnsupportedError))
     181                throw e;
     182        });
     183    }, msg);
     184};
     185
     186const checkFloat4s = (body, argValues = [], expected = [0, 1, 2, 3]) => {
    166187    let inputArgs = [];
    167188    let values = [];
    168189    for (let i = 0; i < argValues.length; ++i) {
    169         const isPointer = Array.isArray(argValues[i]);
    170         inputArgs.push(`${isPointer ? "device " : ""}bool${isPointer ? "*" : ""} in${i}`);
    171         values.push(makeBool(argValues[i]));
    172     }
    173 
    174     src += `bool boolTest(${inputArgs.join(", ")}) { ${body} }
    175     `;
    176 
    177     promise_test(async () => {
    178         return callBoolFunction(src, "boolTest", values).then(result => {
    179             assert_equals(result, expected, "Test returned expected value.");
    180         });
    181     }, msg);
    182 };
    183 
    184 const checkFloat4s = (body, argValues = [], expected = [0, 1, 2, 3]) => {
    185     let src = "";
    186     let inputArgs = [];
    187     let values = [];
    188 
    189     for (let i = 0; i < argValues.length; ++i) {
    190190        // Support arrays of float4, including one with a single float4.
    191191        const totalLength = argValues[i].flat().length;
    192         const isPointer = argValues[i].length === 1 || totalLength > 4;
    193         inputArgs.push(`${isPointer ? "device " : ""}float4${isPointer ? "*" : ""} in${i}`);
     192        const isBuffer = argValues[i].length === 1 || totalLength > 4;
     193        inputArgs.push(`${isBuffer ? "device " : ""}float4${isBuffer ? "[]" : ""} in${i}`);
    194194        values.push(makeFloat4(argValues[i]));
    195195    }
    196196
    197     src += `float4 float4Test(${inputArgs.join(", ")}) { ${body} }
     197    const src = `float4 float4Test(${inputArgs.join(", ")}) { ${body} }
    198198    `;
    199199
    200     promise_test(async () => {
     200    webGPUPromiseTest(async () => {
    201201        return callFloat4Function(src, "float4Test", values).then(result => {
    202202            for (let i = 0; i < 4; ++i)
     
    205205    }, "Return an expected float4 value.");
    206206}
     207
     208const appendScalarFunctionToSource = (src, type, body, argValues) => {
     209    const name = `${type}Test`;
     210
     211    let inputArgs = [];
     212    let values = [];
     213    for (let i = 0; i < argValues.length; ++i) {
     214        const isBuffer = Array.isArray(argValues[i]);
     215        inputArgs.push(`${isBuffer ? "device " : ""}${type}${isBuffer ? "[]" : ""} in${i}`);
     216        values.push(scalarArgMakers[type](argValues[i]));
     217    }
     218
     219    src += `${type} ${name}(${inputArgs.join(", ")}) { ${body} }
     220    `;
     221   
     222    return [src, name, values];
     223};
     224
     225const webGPUPromiseTest = (testFunc, msg) => {
     226    promise_test(async () => {
     227        return testFunc().catch(e => {
     228        if (!(e instanceof WebGPUUnsupportedError))
     229            throw e;
     230        });
     231    }, msg);
     232}
    207233</script>
    208234</html>
Note: See TracChangeset for help on using the changeset viewer.