Diff
Modified: trunk/LayoutTests/ChangeLog (246823 => 246824)
--- trunk/LayoutTests/ChangeLog 2019-06-26 01:01:01 UTC (rev 246823)
+++ trunk/LayoutTests/ChangeLog 2019-06-26 01:40:52 UTC (rev 246824)
@@ -1,3 +1,40 @@
+2019-06-25 Justin Fan <justin_...@apple.com>
+
+ [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.
+
2019-06-25 Daniel Bates <daba...@apple.com>
Non-editable text selections should be modifiable with hardware keyboard
Modified: trunk/LayoutTests/TestExpectations (246823 => 246824)
--- trunk/LayoutTests/TestExpectations 2019-06-26 01:01:01 UTC (rev 246823)
+++ trunk/LayoutTests/TestExpectations 2019-06-26 01:40:52 UTC (rev 246824)
@@ -3440,3 +3440,5 @@
fast/dom/linkify-phone-numbers.html [ ImageOnlyFailure ]
webkit.org/b/199039 editing/deleting/smart-delete-paragraph-003.html [ Skip ]
+
+webkit.org/b/199028 webgpu/whlsl-test-harness-test.html [ Slow ]
Modified: trunk/LayoutTests/platform/mac/TestExpectations (246823 => 246824)
--- trunk/LayoutTests/platform/mac/TestExpectations 2019-06-26 01:01:01 UTC (rev 246823)
+++ trunk/LayoutTests/platform/mac/TestExpectations 2019-06-26 01:40:52 UTC (rev 246824)
@@ -1786,7 +1786,8 @@
webkit.org/b/192956 [ Sierra ] inspector/canvas/create-context-webgpu.html [ Skip ]
webkit.org/b/192956 [ Sierra ] inspector/canvas/resolveCanvasContext-webgpu.html [ Skip ]
-webkit.org/b/199076 [ HighSierra ] webgpu/whlsl-harness-test.html [ Skip ]
+webkit.org/b/199076 [ HighSierra ] webgpu/whlsl-test-harness-test.html [ Skip ]
+webkit.org/b/199028 [ HighSierra ] webgpu/msl-harness-test.html [ Skip ]
webkit.org/b/189680 platform/mac/media/audio-session-category-video-paused.html [ Pass Timeout ]
Modified: trunk/LayoutTests/webgpu/js/whlsl-test-harness.js (246823 => 246824)
--- trunk/LayoutTests/webgpu/js/whlsl-test-harness.js 2019-06-26 01:01:01 UTC (rev 246823)
+++ trunk/LayoutTests/webgpu/js/whlsl-test-harness.js 2019-06-26 01:40:52 UTC (rev 246824)
@@ -63,6 +63,13 @@
/* Harness Classes */
+class WebGPUUnsupportedError extends Error {
+ constructor()
+ {
+ super("No GPUDevice detected!");
+ }
+};
+
class Data {
/**
* Upload typed data to and return a wrapper of a GPUBuffer.
@@ -69,15 +76,17 @@
* @param {Types} type - The WHLSL type to be stored in this Data.
* @param {Number or Array[Number]} values - The raw data to be uploaded.
*/
- constructor(harness, type, values, isPointer = false)
+ constructor(harness, type, values, isBuffer = false)
{
- // One or more scalars in an array can be accessed through a pointer to buffer.
+ if (harness.device === undefined)
+ return;
+ // One or more scalars in an array can be accessed through an array reference.
// However, vector types are also created via an array of scalars.
// This ensures that buffers of just one vector are usable in a test function.
if (Array.isArray(values))
- this._isPointer = isVectorType(type) ? isPointer : true;
+ this._isBuffer = isVectorType(type) ? isBuffer : true;
else {
- this._isPointer = false;
+ this._isBuffer = false;
values = [values];
}
@@ -84,7 +93,7 @@
this._type = type;
this._byteLength = (convertTypeToArrayType(type)).BYTES_PER_ELEMENT * values.length;
- const [buffer, arrayBuffer] = harness._device.createBufferMapped({
+ const [buffer, arrayBuffer] = harness.device.createBufferMapped({
size: this._byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ
});
@@ -101,6 +110,9 @@
*/
async getArrayBuffer()
{
+ if (harness.device === undefined)
+ throw new WebGPUUnsupportedError();
+
let result;
try {
result = await this._buffer.mapReadAsync();
@@ -112,24 +124,39 @@
}
get type() { return this._type; }
- get isPointer() { return this._isPointer; }
+ get isBuffer() { return this._isBuffer; }
get buffer() { return this._buffer; }
get byteLength() { return this._byteLength; }
}
class Harness {
- constructor()
+ constructor ()
{
- this._shaderHeader = `#include <metal_stdlib>
- using namespace metal;
- `;
+ this.isWHLSL = true;
}
- _initialize(callback)
+ async requestDevice()
{
- callback.bind(this)();
+ try {
+ const adapter = await navigator.gpu.requestAdapter();
+ this._device = await adapter.requestDevice();
+ } catch {
+ // WebGPU is not supported.
+ // FIXME: Add support for GPUAdapterRequestOptions and GPUDeviceDescriptor,
+ // and differentiate between descriptor validation errors and no WebGPU support.
+ }
}
+ // Sets whether Harness generates WHLSL or MSL shaders.
+ set isWHLSL(value)
+ {
+ this._isWHLSL = value;
+ this._shaderHeader = value ? "" : `
+#include <metal_stdlib>
+using namespace metal;
+ `;
+ }
+
/**
* Return the return value of a WHLSL function.
* @param {Types} type - The return type of the WHLSL function.
@@ -140,12 +167,17 @@
*/
async callTypedFunction(type, functions, name, args)
{
- const [argsLayouts, argsResourceBindings, argsStructCode, functionCallArgs] = this._setUpArguments(args);
+ if (this._device === undefined)
+ throw new WebGPUUnsupportedError();
- if (!this._resultBuffer) {
- this._resultBuffer = this._device.createBuffer({
+ const [argsLayouts, argsResourceBindings, argsDeclarations, functionCallArgs] = this._setUpArguments(args);
+
+ if (this._resultBuffer) {
+ this._clearResults()
+ } else {
+ this._resultBuffer = this.device.createBuffer({
size: Types.MAX_SIZE,
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ | GPUBufferUsage.TRANSFER_DST
});
}
@@ -162,17 +194,30 @@
}
});
- const code = this._shaderHeader + functions + `
- struct _compute_args {
- device ${convertTypeToWHLSLType(type)}* result [[id(0)]];
- ${argsStructCode}};
-
- kernel void _compute_main(device _compute_args& args [[buffer(0)]])
- {
- *args.result = ${name}(${functionCallArgs.join(", ")});
+ let entryPointCode;
+ if (this._isWHLSL) {
+ argsDeclarations.unshift(`device ${convertTypeToWHLSLType(type)}[] result : register(u0)`);
+ entryPointCode = `
+[numthreads(1, 1, 1)]
+compute void _compute_main(${argsDeclarations.join(", ")})
+{
+ result[0] = ${name}(${functionCallArgs.join(", ")});
+}
+`;
+ } else {
+ argsDeclarations.unshift(`device ${convertTypeToWHLSLType(type)}* result [[id(0)]];`);
+ entryPointCode = `
+struct _compute_args {
+ ${argsDeclarations.join("\n")}
+};
+
+kernel void _compute_main(device _compute_args& args [[buffer(0)]])
+{
+ *args.result = ${name}(${functionCallArgs.join(", ")});
+}
+`;
}
- `;
-
+ const code = this._shaderHeader + functions + entryPointCode;
this._callFunction(code, argsLayouts, argsResourceBindings);
try {
@@ -192,23 +237,52 @@
* @param {String} name - The name of the WHLSL function which must be present in 'functions'.
* @param {Data or Array[Data]} args - Data arguments to be passed to the call of 'name'.
*/
- async callVoidFunction(functions, name, args)
+ callVoidFunction(functions, name, args)
{
- const [argsLayouts, argsResourceBindings, argsStructCode, functionCallArgs] = this._setUpArguments(args);
+ if (this._device === undefined)
+ return;
- const code = this._shaderHeader + functions + `
- struct _compute_args {
- ${argsStructCode}};
+ const [argsLayouts, argsResourceBindings, argsDeclarations, functionCallArgs] = this._setUpArguments(args);
- kernel void _compute_main(device _compute_args& args [[buffer(0)]])
- {
- ${name}(${functionCallArgs.join(", ")});
+ let entryPointCode;
+ if (this._isWHLSL) {
+ entryPointCode = `
+[numthreads(1, 1, 1)]
+compute void _compute_main(${argsDeclarations.join(", ")})
+{
+ ${name}(${functionCallArgs.join(", ")});
+}`;
+ } else {
+ entryPointCode = `
+struct _compute_args {
+ ${argsDeclarations.join("\n")}
+};
+
+kernel void _compute_main(device _compute_args& args [[buffer(0)]])
+{
+ ${name}(${functionCallArgs.join(", ")});
+}
+`;
}
- `;
-
+ const code = this._shaderHeader + functions + entryPointCode;
this._callFunction(code, argsLayouts, argsResourceBindings);
}
+ get device() { return this._device; }
+
+ _clearResults()
+ {
+ if (!this._clearBuffer) {
+ this._clearBuffer = this._device.createBuffer({
+ size: Types.MAX_SIZE,
+ usage: GPUBufferUsage.TRANSFER_SRC
+ });
+ }
+ const commandEncoder = this._device.createCommandEncoder();
+ commandEncoder.copyBufferToBuffer(this._clearBuffer, 0, this._resultBuffer, 0, Types.MAX_SIZE);
+ this._device.getQueue().submit([commandEncoder.finish()]);
+ }
+
_setUpArguments(args)
{
if (!Array.isArray(args)) {
@@ -218,9 +292,8 @@
args = [];
}
- // FIXME: Replace with WHLSL.
// Expand bind group structure to represent any arguments.
- let argsStructCode = "";
+ let argsDeclarations = [];
let functionCallArgs = [];
let argsLayouts = [];
let argsResourceBindings = [];
@@ -227,10 +300,13 @@
for (let i = 1; i <= args.length; ++i) {
const arg = args[i - 1];
- argsStructCode += `device ${convertTypeToWHLSLType(arg.type)}* arg${i} [[id(${i})]];
- `;
- const optionalDeref = (!arg.isPointer) ? "*" : "";
- functionCallArgs.push(optionalDeref + `args.arg${i}`);
+ if (this._isWHLSL) {
+ argsDeclarations.push(`device ${convertTypeToWHLSLType(arg.type)}[] arg${i} : register(u${i})`);
+ functionCallArgs.push(`arg${i}` + (arg.isBuffer ? "" : "[0]"));
+ } else {
+ argsDeclarations.push(`device ${convertTypeToWHLSLType(arg.type)}* arg${i} [[id(${i})]];`);
+ functionCallArgs.push((arg.isBuffer ? "" : "*") + `args.arg${i}`);
+ }
argsLayouts.push({
binding: i,
visibility: GPUShaderStageBit.COMPUTE,
@@ -245,14 +321,27 @@
});
}
- return [argsLayouts, argsResourceBindings, argsStructCode, functionCallArgs];
+ return [argsLayouts, argsResourceBindings, argsDeclarations, functionCallArgs];
}
_callFunction(code, argsLayouts, argsResourceBindings)
{
- const shaders = this._device.createShaderModule({ code: code });
+ const shaders = this._device.createShaderModule({ code: code, isWHLSL: this._isWHLSL });
+
+ const bindGroupLayout = this._device.createBindGroupLayout({
+ bindings: argsLayouts
+ });
+
+ const pipelineLayout = this._device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] });
+
+ const bindGroup = this._device.createBindGroup({
+ layout: bindGroupLayout,
+ bindings: argsResourceBindings
+ });
+
// FIXME: Compile errors should be caught and reported here.
const pipeline = this._device.createComputePipeline({
+ layout: pipelineLayout,
computeStage: {
module: shaders,
entryPoint: "_compute_main"
@@ -259,15 +348,6 @@
}
});
- const layout = this._device.createBindGroupLayout({
- bindings: argsLayouts
- });
-
- const bindGroup = this._device.createBindGroup({
- layout: layout,
- bindings: argsResourceBindings
- });
-
const commandEncoder = this._device.createCommandEncoder();
const passEncoder = commandEncoder.beginComputePass();
passEncoder.setBindGroup(0, bindGroup);
@@ -282,14 +362,7 @@
/* Harness Setup */
const harness = new Harness();
-harness._initialize(async () => {
- try {
- const adapter = await navigator.gpu.requestAdapter();
- harness._device = await adapter.requestDevice();
- } catch (e) {
- throw new Error("Harness error: Unable to acquire GPUDevice!");
- }
-});
+harness.requestDevice();
/* Global Helper Functions */
Copied: trunk/LayoutTests/webgpu/msl-harness-test-expected.txt (from rev 246823, trunk/LayoutTests/webgpu/whlsl-harness-test-expected.txt) (0 => 246824)
--- trunk/LayoutTests/webgpu/msl-harness-test-expected.txt (rev 0)
+++ trunk/LayoutTests/webgpu/msl-harness-test-expected.txt 2019-06-26 01:40:52 UTC (rev 246824)
@@ -0,0 +1,35 @@
+
+PASS Return a literal of type bool.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uchar value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Upload and return a bool value.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uchar value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Upload many bool values and return a calculated result.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uchar value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Access and return a single bool through a bool*.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uchar value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Access multiple bools through various buffers and return a bool.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uchar value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Upload and calculate a result from varied argument types.
+PASS Store into a float4*.
+PASS Upload a uchar* and store into a uchar*.
+
Copied: trunk/LayoutTests/webgpu/msl-harness-test.html (from rev 246823, trunk/LayoutTests/webgpu/whlsl-harness-test.html) (0 => 246824)
--- trunk/LayoutTests/webgpu/msl-harness-test.html (rev 0)
+++ trunk/LayoutTests/webgpu/msl-harness-test.html 2019-06-26 01:40:52 UTC (rev 246824)
@@ -0,0 +1,218 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
+<html>
+<meta charset=utf-8>
+<title>Test the WHLSL test harness.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+const epsilon = 0.0001;
+
+const numericScalarTypes = ["int", "uchar", "uint", "float"];
+
+const numericScalarFuncs = {
+ "int": callIntFunction,
+ "uchar": callUcharFunction,
+ "uint": callUintFunction,
+ "float": callFloatFunction
+};
+
+const scalarArgMakers = {
+ "int": makeInt,
+ "uchar": makeUchar,
+ "uint": makeUint,
+ "float": makeFloat
+};
+
+let mslTests = {};
+
+mslTests.literals = () => {
+ checkBools("Return a literal of type bool.", "return true;");
+ checkFloat4s("return float4(0, 1, 2, 3);");
+ checkNumericScalars("return 42;", [], 42);
+};
+
+mslTests.singleArgument = () => {
+ checkBools("Upload and return a bool value.", "return in0;", [true]);
+ checkFloat4s("return in0.wzyx;", [[3, 2, 1, 0]]);
+ checkNumericScalars("return in0;", [42], 42);
+};
+
+mslTests.manyArguments = () => {
+ checkBools("Upload many bool values and return a calculated result.",
+ "return in0 & in1 & in2 & in3 & in4 & in5 & in6 & in7;",
+ [true, true, true, true, true, true, true, true]);
+
+ const body = `return in0 + in1 + in2 + in3 + in4 + in5 + in6 + in7;`;
+ let args = [];
+ for (let i = 0; i < 8; ++i)
+ args.push([0, 1, 2, 3]);
+ checkFloat4s(body, args, [0, 8, 16, 24]);
+ checkNumericScalars(body, [0, 1, 2, 3, 4, 5, 6, 7], 28);
+};
+
+mslTests.buffersWithOneValue = () => {
+ const body = `return in0[0];`
+ checkBools("Access and return a single bool through a bool*.", body, [[true]]);
+ checkFloat4s(body, [[[0, 1, 2, 3]]]);
+ checkNumericScalars(body, [[42]], 42);
+};
+
+mslTests.multipleBufferArguments = () => {
+ checkBools("Access multiple bools through various buffers and return a bool.",
+ "return in0[0] & in0[1] & in0[2] & in1 & in2[0];",
+ [[true, true, true], true, [true]]);
+
+ const body = `return in0[0] + in0[1] + in0[2] + in1 + in2[0];`;
+ const vector = [0, 1, 2, 3];
+ checkFloat4s(body, [[vector, vector, vector], vector, [vector]], [0, 5, 10, 15]);
+ checkNumericScalars(body, [[0, 1, 2], 3, [4]], 10);
+};
+
+mslTests.multipleArgumentTypes = () => {
+ const src = "" test(int i, uchar c, device uint* u, bool b, device bool* bs, float4 f4, device float* fs)
+ {
+ if (b && bs[0] && bs[1])
+ return i + c + u[0] + f4.x + f4.y + f4.z + f4.w + fs[0] + fs[1];
+
+ return 0;
+ }`;
+ const i = makeInt(1);
+ const c = makeUchar(2);
+ const u = makeUint([3]);
+ const b = makeBool(true);
+ const bs = makeBool([true, true]);
+ const f4 = makeFloat4([4, 5, 6, 7]);
+ const fs = makeFloat([8, 9]);
+ webGPUPromiseTest(() => {
+ return callFloatFunction(src, "test", [i, c, u, b, bs, f4, fs]).then(result => {
+ assert_approx_equals(result, 45, epsilon, "Test returned expected value.");
+ });
+ }, "Upload and calculate a result from varied argument types.");
+};
+
+mslTests.bufferStores = () => {
+ let src = "" test(device float4* out) {
+ *out = float4(0, 1, 2, 3);
+ }`;
+ const float4Out = makeFloat4([[0, 0, 0, 0]]);
+ callVoidFunction(src, "test", float4Out);
+
+ webGPUPromiseTest(() => {
+ return float4Out.getArrayBuffer().then(arrayBuffer => {
+ const result = new Float32Array(arrayBuffer);
+ for (let i; i < 4; ++i) {
+ assert_approx_equals(result[i], i, "Test stored expected values.");
+ }
+ });
+ }, "Store into a float4*.");
+
+ src = "" test(device uchar* in, device uchar* out) {
+ for (uint i = 0; i < 5; ++i)
+ out[i] = in[i];
+ }`;
+ const array = [0, 1, 2, 3, 4];
+ const input = makeUchar(array);
+ const output = makeUchar([0, 0, 0, 0, 0]);
+ callVoidFunction(src, "test", [input, output]);
+
+ webGPUPromiseTest(() => {
+ return output.getArrayBuffer().then(arrayBuffer => {
+ const result = new Uint8Array(arrayBuffer);
+ assert_array_equals(array, result, "Test stored expected values.");
+ });
+ }, "Upload a uchar* and store into a uchar*.");
+};
+
+window.addEventListener("load", () => {
+ harness.isWHLSL = false;
+ for (const name in mslTests) {
+ mslTests[name]();
+ }
+});
+
+/* Helper functions */
+
+const checkNumericScalars = (body, argValues, expected) => {
+ let functions = [];
+ let src = ""
+ for (let type of numericScalarTypes) {
+ const name = `${type}Test`;
+
+ let inputArgs = [];
+ let values = [];
+ for (let i = 0; i < argValues.length; ++i) {
+ const isPointer = Array.isArray(argValues[i]);
+ inputArgs.push(`${isPointer ? "device " : ""}${type}${isPointer ? "*" : ""} in${i}`);
+ values.push(scalarArgMakers[type](argValues[i]));
+ }
+
+ src += `${type} ${name}(${inputArgs.join(", ")}) { ${body} }
+ `;
+ functions.push({ type: type, name: name, args: values, expected: expected });
+ }
+
+ for (const f of functions) {
+ const callFunc = numericScalarFuncs[f.type];
+ webGPUPromiseTest(async () => {
+ return callFunc(src, f.name, f.args).then(result => {
+ assert_approx_equals(result, f.expected, epsilon, "Test returned expected value.");
+ });
+ }, `Return an expected ${f.type} value.`);
+ }
+};
+
+const checkBools = (msg = "Return an expected bool value.", body, argValues = [], expected = true) => {
+ let src = ""
+ let inputArgs = [];
+ let values = [];
+ for (let i = 0; i < argValues.length; ++i) {
+ const isPointer = Array.isArray(argValues[i]);
+ inputArgs.push(`${isPointer ? "device " : ""}bool${isPointer ? "*" : ""} in${i}`);
+ values.push(makeBool(argValues[i]));
+ }
+
+ src += `bool boolTest(${inputArgs.join(", ")}) { ${body} }
+ `;
+
+ webGPUPromiseTest(async () => {
+ return callBoolFunction(src, "boolTest", values).then(result => {
+ assert_equals(result, expected, "Test returned expected value.");
+ });
+ }, msg);
+};
+
+const checkFloat4s = (body, argValues = [], expected = [0, 1, 2, 3]) => {
+ let src = ""
+ let inputArgs = [];
+ let values = [];
+
+ for (let i = 0; i < argValues.length; ++i) {
+ // Support arrays of float4, including one with a single float4.
+ const totalLength = argValues[i].flat().length;
+ const isPointer = argValues[i].length === 1 || totalLength > 4;
+ inputArgs.push(`${isPointer ? "device " : ""}float4${isPointer ? "*" : ""} in${i}`);
+ values.push(makeFloat4(argValues[i]));
+ }
+
+ src += `float4 float4Test(${inputArgs.join(", ")}) { ${body} }
+ `;
+
+ webGPUPromiseTest(async () => {
+ return callFloat4Function(src, "float4Test", values).then(result => {
+ for (let i = 0; i < 4; ++i)
+ assert_approx_equals(result[i], expected[i], epsilon, "Test returned expected value.");
+ });
+ }, "Return an expected float4 value.");
+}
+
+const webGPUPromiseTest = (testFunc, msg) => {
+ promise_test(async () => {
+ return testFunc().catch(e => {
+ if (!(e instanceof WebGPUUnsupportedError))
+ throw e;
+ });
+ }, msg);
+}
+</script>
+</html>
\ No newline at end of file
Deleted: trunk/LayoutTests/webgpu/whlsl-harness-test-expected.txt (246823 => 246824)
--- trunk/LayoutTests/webgpu/whlsl-harness-test-expected.txt 2019-06-26 01:01:01 UTC (rev 246823)
+++ trunk/LayoutTests/webgpu/whlsl-harness-test-expected.txt 2019-06-26 01:40:52 UTC (rev 246824)
@@ -1,35 +0,0 @@
-
-PASS Return a literal of type bool.
-PASS Return an expected float4 value.
-PASS Return an expected int value.
-PASS Return an expected uchar value.
-PASS Return an expected uint value.
-PASS Return an expected float value.
-PASS Upload and return a bool value.
-PASS Return an expected float4 value.
-PASS Return an expected int value.
-PASS Return an expected uchar value.
-PASS Return an expected uint value.
-PASS Return an expected float value.
-PASS Upload many bool values and return a calculated result.
-PASS Return an expected float4 value.
-PASS Return an expected int value.
-PASS Return an expected uchar value.
-PASS Return an expected uint value.
-PASS Return an expected float value.
-PASS Access and return a single bool through a bool*.
-PASS Return an expected float4 value.
-PASS Return an expected int value.
-PASS Return an expected uchar value.
-PASS Return an expected uint value.
-PASS Return an expected float value.
-PASS Access multiple bools through various buffers and return a bool.
-PASS Return an expected float4 value.
-PASS Return an expected int value.
-PASS Return an expected uchar value.
-PASS Return an expected uint value.
-PASS Return an expected float value.
-PASS Upload and calculate a result from varied argument types.
-PASS Store into a float4*.
-PASS Upload a uchar* and store into a uchar*.
-
Deleted: trunk/LayoutTests/webgpu/whlsl-harness-test.html (246823 => 246824)
--- trunk/LayoutTests/webgpu/whlsl-harness-test.html 2019-06-26 01:01:01 UTC (rev 246823)
+++ trunk/LayoutTests/webgpu/whlsl-harness-test.html 2019-06-26 01:40:52 UTC (rev 246824)
@@ -1,208 +0,0 @@
-<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
-<html>
-<meta charset=utf-8>
-<title>Test the WHLSL test harness.</title>
-<script src=""
-<script src=""
-<script src=""
-<script>
-const epsilon = 0.0001;
-
-const numericScalarTypes = ["int", "uchar", "uint", "float"];
-
-const numericScalarFuncs = {
- "int": callIntFunction,
- "uchar": callUcharFunction,
- "uint": callUintFunction,
- "float": callFloatFunction
-};
-
-const scalarArgMakers = {
- "int": makeInt,
- "uchar": makeUchar,
- "uint": makeUint,
- "float": makeFloat
-};
-
-let tests = {};
-
-tests.literals = () => {
- checkBools("Return a literal of type bool.", "return true;");
- checkFloat4s("return float4(0, 1, 2, 3);");
- checkNumericScalars("return 42;", [], 42);
-};
-
-tests.singleArgument = () => {
- checkBools("Upload and return a bool value.", "return in0;", [true]);
- checkFloat4s("return in0.wzyx;", [[3, 2, 1, 0]]);
- checkNumericScalars("return in0;", [42], 42);
-};
-
-tests.manyArguments = () => {
- checkBools("Upload many bool values and return a calculated result.",
- "return in0 & in1 & in2 & in3 & in4 & in5 & in6 & in7;",
- [true, true, true, true, true, true, true, true]);
-
- const body = `return in0 + in1 + in2 + in3 + in4 + in5 + in6 + in7;`;
- let args = [];
- for (let i = 0; i < 8; ++i)
- args.push([0, 1, 2, 3]);
- checkFloat4s(body, args, [0, 8, 16, 24]);
- checkNumericScalars(body, [0, 1, 2, 3, 4, 5, 6, 7], 28);
-};
-
-tests.buffersWithOneValue = () => {
- const body = `return in0[0];`
- checkBools("Access and return a single bool through a bool*.", body, [[true]]);
- checkFloat4s(body, [[[0, 1, 2, 3]]]);
- checkNumericScalars(body, [[42]], 42);
-};
-
-tests.multipleBufferArguments = () => {
- checkBools("Access multiple bools through various buffers and return a bool.",
- "return in0[0] & in0[1] & in0[2] & in1 & in2[0];",
- [[true, true, true], true, [true]]);
-
- const body = `return in0[0] + in0[1] + in0[2] + in1 + in2[0];`;
- const vector = [0, 1, 2, 3];
- checkFloat4s(body, [[vector, vector, vector], vector, [vector]], [0, 5, 10, 15]);
- checkNumericScalars(body, [[0, 1, 2], 3, [4]], 10);
-};
-
-tests.multipleArgumentTypes = () => {
- const src = "" test(int i, uchar c, device uint* u, bool b, device bool* bs, float4 f4, device float* fs)
- {
- if (b && bs[0] && bs[1])
- return i + c + u[0] + f4.x + f4.y + f4.z + f4.w + fs[0] + fs[1];
-
- return 0;
- }`;
- const i = makeInt(1);
- const c = makeUchar(2);
- const u = makeUint([3]);
- const b = makeBool(true);
- const bs = makeBool([true, true]);
- const f4 = makeFloat4([4, 5, 6, 7]);
- const fs = makeFloat([8, 9]);
- promise_test(() => {
- return callFloatFunction(src, "test", [i, c, u, b, bs, f4, fs]).then(result => {
- assert_approx_equals(result, 45, epsilon, "Test returned expected value.");
- });
- }, "Upload and calculate a result from varied argument types.");
-};
-
-tests.bufferStores = () => {
- let src = "" test(device float4* out) {
- *out = float4(0, 1, 2, 3);
- }`;
- const float4Out = makeFloat4([[0, 0, 0, 0]]);
- callVoidFunction(src, "test", float4Out);
-
- promise_test(() => {
- return float4Out.getArrayBuffer().then(arrayBuffer => {
- const result = new Float32Array(arrayBuffer);
- for (let i; i < 4; ++i) {
- assert_approx_equals(result[i], i, "Test stored expected values.");
- }
- });
- }, "Store into a float4*.");
-
- src = "" test(device uchar* in, device uchar* out) {
- for (uint i = 0; i < 5; ++i)
- out[i] = in[i];
- }`;
- const array = [0, 1, 2, 3, 4];
- const input = makeUchar(array);
- const output = makeUchar([0, 0, 0, 0, 0]);
- callVoidFunction(src, "test", [input, output]);
-
- promise_test(() => {
- return output.getArrayBuffer().then(arrayBuffer => {
- const result = new Uint8Array(arrayBuffer);
- assert_array_equals(array, result, "Test stored expected values.");
- });
- }, "Upload a uchar* and store into a uchar*.");
-};
-
-window.addEventListener("load", () => {
- for (const name in tests) {
- tests[name]();
- }
-});
-
-/* Helper functions */
-
-const checkNumericScalars = (body, argValues, expected) => {
- let functions = [];
- let src = ""
- for (let type of numericScalarTypes) {
- const name = `${type}Test`;
-
- let inputArgs = [];
- let values = [];
- for (let i = 0; i < argValues.length; ++i) {
- const isPointer = Array.isArray(argValues[i]);
- inputArgs.push(`${isPointer ? "device " : ""}${type}${isPointer ? "*" : ""} in${i}`);
- values.push(scalarArgMakers[type](argValues[i]));
- }
-
- src += `${type} ${name}(${inputArgs.join(", ")}) { ${body} }
- `;
- functions.push({ type: type, name: name, args: values, expected: expected });
- }
-
- for (const f of functions) {
- const callFunc = numericScalarFuncs[f.type];
- promise_test(async () => {
- return callFunc(src, f.name, f.args).then(result => {
- assert_approx_equals(result, f.expected, epsilon, "Test returned expected value.");
- });
- }, `Return an expected ${f.type} value.`);
- }
-};
-
-const checkBools = (msg = "Return an expected bool value.", body, argValues = [], expected = true) => {
- let src = ""
- let inputArgs = [];
- let values = [];
- for (let i = 0; i < argValues.length; ++i) {
- const isPointer = Array.isArray(argValues[i]);
- inputArgs.push(`${isPointer ? "device " : ""}bool${isPointer ? "*" : ""} in${i}`);
- values.push(makeBool(argValues[i]));
- }
-
- src += `bool boolTest(${inputArgs.join(", ")}) { ${body} }
- `;
-
- promise_test(async () => {
- return callBoolFunction(src, "boolTest", values).then(result => {
- assert_equals(result, expected, "Test returned expected value.");
- });
- }, msg);
-};
-
-const checkFloat4s = (body, argValues = [], expected = [0, 1, 2, 3]) => {
- let src = ""
- let inputArgs = [];
- let values = [];
-
- for (let i = 0; i < argValues.length; ++i) {
- // Support arrays of float4, including one with a single float4.
- const totalLength = argValues[i].flat().length;
- const isPointer = argValues[i].length === 1 || totalLength > 4;
- inputArgs.push(`${isPointer ? "device " : ""}float4${isPointer ? "*" : ""} in${i}`);
- values.push(makeFloat4(argValues[i]));
- }
-
- src += `float4 float4Test(${inputArgs.join(", ")}) { ${body} }
- `;
-
- promise_test(async () => {
- return callFloat4Function(src, "float4Test", values).then(result => {
- for (let i = 0; i < 4; ++i)
- assert_approx_equals(result[i], expected[i], epsilon, "Test returned expected value.");
- });
- }, "Return an expected float4 value.");
-}
-</script>
-</html>
\ No newline at end of file
Copied: trunk/LayoutTests/webgpu/whlsl-test-harness-test-expected.txt (from rev 246823, trunk/LayoutTests/webgpu/whlsl-harness-test-expected.txt) (0 => 246824)
--- trunk/LayoutTests/webgpu/whlsl-test-harness-test-expected.txt (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-test-harness-test-expected.txt 2019-06-26 01:40:52 UTC (rev 246824)
@@ -0,0 +1,25 @@
+
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Return an expected float4 value.
+PASS Return an expected int value.
+PASS Return an expected uint value.
+PASS Return an expected float value.
+PASS Upload and calculate a result from varied argument types.
+PASS Store into a float4[].
+PASS Upload a int[] and store into a int[].
+
Copied: trunk/LayoutTests/webgpu/whlsl-test-harness-test.html (from rev 246823, trunk/LayoutTests/webgpu/whlsl-harness-test.html) (0 => 246824)
--- trunk/LayoutTests/webgpu/whlsl-test-harness-test.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-test-harness-test.html 2019-06-26 01:40:52 UTC (rev 246824)
@@ -0,0 +1,234 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
+<html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>Test the WHLSL test harness.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+const epsilon = 0.0001;
+
+// FIXME: Add "uchar" back in when operator+(uchar, uchar) is available.
+const numericScalarTypes = ["int", "uint", "float"];
+
+const numericScalarFuncs = {
+ "int": callIntFunction,
+ "uchar": callUcharFunction,
+ "uint": callUintFunction,
+ "float": callFloatFunction
+};
+
+const scalarArgMakers = {
+ "bool": makeBool,
+ "int": makeInt,
+ "uchar": makeUchar,
+ "uint": makeUint,
+ "float": makeFloat
+};
+
+let whlslTests = {};
+
+whlslTests.literals = () => {
+ checkBools("Return a literal of type bool.", "return true;");
+ checkFloat4s("return float4(0, 1, 2, 3);");
+ checkNumericScalars("return 42;", [], 42);
+};
+
+whlslTests.singleArgument = () => {
+ checkBools("Upload and return a bool value.", "return in0;", [true]);
+ checkFloat4s("return in0;", [[0, 1, 2, 3]]);
+ checkNumericScalars("return in0;", [42], 42);
+};
+
+whlslTests.manyArguments = () => {
+ checkBools("Upload many bool values and return a calculated result.",
+ "return in0 & in1 & in2 & in3 & in4 & in5 & in6 & in7;",
+ [true, true, true, true, true, true, true, true]);
+
+ let body = "return float4(in0.x, in1.y, in2.z, in3.w);"
+ let args = [];
+ for (let i = 0; i < 4; ++i)
+ args.push([0, 1, 2, 3]);
+ checkFloat4s(body, args, [0, 1, 2, 3]);
+
+ body = `return in0 + in1 + in2 + in3 + in4 + in5 + in6 + in7;`;
+ checkNumericScalars(body, [0, 1, 2, 3, 4, 5, 6, 7], 28);
+};
+
+whlslTests.buffersWithOneValue = () => {
+ const body = `return in0[0];`
+ checkBools("Access and return a single bool through a bool[].", body, [[true]]);
+ checkFloat4s(body, [[[0, 1, 2, 3]]]);
+ checkNumericScalars(body, [[42]], 42);
+};
+
+whlslTests.multipleBufferArguments = () => {
+ checkBools("Access multiple bools through various buffers and return a bool.",
+ "return in0[0] & in0[1] & in0[2] & in1 & in2[0];",
+ [[true, true, true], true, [true]]);
+
+ let body = `
+ float x = in0[0].x + in0[1].x + in0[2].x + in1.x + in2[0].x;
+ float y = in0[0].y + in0[1].y + in0[2].y + in1.y + in2[0].y;
+ float z = in0[0].z + in0[1].z + in0[2].z + in1.z + in2[0].z;
+ float w = in0[0].w + in0[1].w + in0[2].w + in1.w + in2[0].w;
+
+ return float4(x, y, z, w);`;
+ const vector = [0, 1, 2, 3];
+ checkFloat4s(body, [[vector, vector, vector], vector, [vector]], [0, 5, 10, 15]);
+
+ body = `return in0[0] + in0[1] + in0[2] + in1 + in2[0];`;
+ checkNumericScalars(body, [[0, 1, 2], 3, [4]], 10);
+};
+
+whlslTests.multipleArgumentTypes = () => {
+ const src = "" test(int i, uchar c, float4 f4, device uint[] u, device float[] fs)
+ {
+ return float(i) + float(c) + f4.x + f4.y + f4.z + f4.w + float(u[0]) + fs[0] + fs[1];
+ }`;
+ const i = makeInt(1);
+ const c = makeUchar(2);
+ const f4 = makeFloat4([4, 5, 6, 7]);
+ const u = makeUint([3]);
+ const fs = makeFloat([8, 9]);
+ webGPUPromiseTest(() => {
+ return callFloatFunction(src, "test", [i, c, f4, u, fs]).then(result => {
+ assert_approx_equals(result, 45, epsilon, "Test returned expected value.");
+ });
+ }, "Upload and calculate a result from varied argument types.");
+};
+
+whlslTests.bufferStores = () => {
+ let src = "" test(device float4[] out) {
+ out[0] = float4(0, 1, 2, 3);
+ }`;
+ const float4Out = makeFloat4([[0, 0, 0, 0]]);
+ callVoidFunction(src, "test", float4Out);
+
+ webGPUPromiseTest(() => {
+ return float4Out.getArrayBuffer().then(arrayBuffer => {
+ const result = new Float32Array(arrayBuffer);
+ for (let i; i < 4; ++i) {
+ assert_approx_equals(result[i], i, "Test stored expected values.");
+ }
+ });
+ }, "Store into a float4[].");
+
+ src = "" test(device int[] in, device int[] out) {
+ for (uint i = 0; i < 5; i = i + 1)
+ out[i] = in[i];
+ }`;
+ const array = [0, 1, 2, 3, 4];
+ const input = makeInt(array);
+ const output = makeInt([0, 0, 0, 0, 0]);
+ callVoidFunction(src, "test", [input, output]);
+
+ webGPUPromiseTest(() => {
+ return output.getArrayBuffer().then(arrayBuffer => {
+ const result = new Uint32Array(arrayBuffer);
+ assert_array_equals(array, result, "Test stored expected values.");
+ });
+ }, "Upload a int[] and store into a int[].");
+};
+
+window.addEventListener("load", () => {
+ try {
+ for (const name in whlslTests) {
+ if (!name.startsWith("_"))
+ whlslTests[name]();
+ }
+ } catch (e) {
+ if (window.testRunner)
+ testRunner.notifyDone();
+
+ throw e;
+ }
+});
+
+/* Helper functions */
+
+const checkNumericScalars = (body, argValues, expected) => {
+ let functions = [];
+ let src = ""
+ for (let type of numericScalarTypes) {
+ let name, values;
+ [src, name, values] = appendScalarFunctionToSource(src, type, body, argValues);
+ functions.push({ type: type, name: name, args: values, expected: expected });
+ }
+
+ for (const f of functions) {
+ const callFunc = numericScalarFuncs[f.type];
+ webGPUPromiseTest(async () => {
+ return callFunc(src, f.name, f.args).then(result => {
+ assert_approx_equals(result, f.expected, epsilon, "Test returned expected value.");
+ });
+ }, `Return an expected ${f.type} value.`);
+ }
+};
+
+const checkBools = (msg = "Return an expected bool value.", body, argValues = [], expected = true) => {
+ // FIXME (https://webkit.org/b/199093): Bool[] functions don't compile, so no-op for now.
+ return;
+
+ const [src, name, values] = appendScalarFunctionToSource("", "bool", body, argValues);
+
+ webGPUPromiseTest(async () => {
+ return callBoolFunction(src, name, values).then(result => {
+ assert_equals(result, expected, "Test returned expected value.");
+ }, e => {
+ if (!(e instanceof WebGPUUnsupportedError))
+ throw e;
+ });
+ }, msg);
+};
+
+const checkFloat4s = (body, argValues = [], expected = [0, 1, 2, 3]) => {
+ let inputArgs = [];
+ let values = [];
+ for (let i = 0; i < argValues.length; ++i) {
+ // Support arrays of float4, including one with a single float4.
+ const totalLength = argValues[i].flat().length;
+ const isBuffer = argValues[i].length === 1 || totalLength > 4;
+ inputArgs.push(`${isBuffer ? "device " : ""}float4${isBuffer ? "[]" : ""} in${i}`);
+ values.push(makeFloat4(argValues[i]));
+ }
+
+ const src = "" float4Test(${inputArgs.join(", ")}) { ${body} }
+ `;
+
+ webGPUPromiseTest(async () => {
+ return callFloat4Function(src, "float4Test", values).then(result => {
+ for (let i = 0; i < 4; ++i)
+ assert_approx_equals(result[i], expected[i], epsilon, "Test returned expected value.");
+ });
+ }, "Return an expected float4 value.");
+}
+
+const appendScalarFunctionToSource = (src, type, body, argValues) => {
+ const name = `${type}Test`;
+
+ let inputArgs = [];
+ let values = [];
+ for (let i = 0; i < argValues.length; ++i) {
+ const isBuffer = Array.isArray(argValues[i]);
+ inputArgs.push(`${isBuffer ? "device " : ""}${type}${isBuffer ? "[]" : ""} in${i}`);
+ values.push(scalarArgMakers[type](argValues[i]));
+ }
+
+ src += `${type} ${name}(${inputArgs.join(", ")}) { ${body} }
+ `;
+
+ return [src, name, values];
+};
+
+const webGPUPromiseTest = (testFunc, msg) => {
+ promise_test(async () => {
+ return testFunc().catch(e => {
+ if (!(e instanceof WebGPUUnsupportedError))
+ throw e;
+ });
+ }, msg);
+}
+</script>
+</html>
\ No newline at end of file