Diff
Modified: trunk/Tools/ChangeLog (222279 => 222280)
--- trunk/Tools/ChangeLog 2017-09-20 20:03:22 UTC (rev 222279)
+++ trunk/Tools/ChangeLog 2017-09-20 20:07:07 UTC (rev 222280)
@@ -1,5 +1,46 @@
2017-09-20 Myles C. Maxfield <[email protected]>
+ Make a playground where people can try WSL
+ https://bugs.webkit.org/show_bug.cgi?id=177125
+
+ Reviewed by Filip Pizlo.
+
+ This patch creates a webpage, index.html, which lets users type in a WSL program and
+ run it, and see the results.
+
+ * WebGPUShadingLanguageRI/All.js:
+ * WebGPUShadingLanguageRI/CallFunction.js:
+ (callFunction):
+ * WebGPUShadingLanguageRI/Checker.js:
+ (Checker):
+ (Checker.prototype._checkShaderType.NonNumericSearcher):
+ (Checker.prototype._checkShaderType.NonNumericSearcher.prototype.visitArrayRefType):
+ (Checker.prototype._checkShaderType.NonNumericSearcher.prototype.visitPtrType):
+ (Checker.prototype._checkShaderType):
+ (Checker.prototype.visitFuncDef):
+ (Checker.prototype._requireBool):
+ * WebGPUShadingLanguageRI/FlattenedStructOffsetGatherer.js: Copied from Tools/WebGPUShadingLanguageRI/CallFunction.js.
+ (FlattenedStructOffsetGatherer):
+ (FlattenedStructOffsetGatherer.prototype.get result):
+ (FlattenedStructOffsetGatherer.prototype.visitReferenceType):
+ (FlattenedStructOffsetGatherer.prototype.visitField):
+ (FlattenedStructOffsetGatherer.prototype.visitNativeType):
+ * WebGPUShadingLanguageRI/Func.js:
+ (Func.prototype.toDeclString):
+ * WebGPUShadingLanguageRI/Inline.js:
+ (resolveInlinedFunction):
+ * WebGPUShadingLanguageRI/NameContext.js:
+ (NameContext.prototype.get let):
+ * WebGPUShadingLanguageRI/ResolveOverloadImpl.js:
+ (resolveOverloadImpl):
+ * WebGPUShadingLanguageRI/StandardLibrary.js:
+ * WebGPUShadingLanguageRI/Test.html:
+ * WebGPUShadingLanguageRI/Test.js:
+ (TEST_shaderTypes):
+ * WebGPUShadingLanguageRI/index.html: Added.
+
+2017-09-20 Myles C. Maxfield <[email protected]>
+
[WSL] Restrict vertex and fragment entry points according to WSL.md
https://bugs.webkit.org/show_bug.cgi?id=177253
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (222279 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-20 20:03:22 UTC (rev 222279)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-20 20:07:07 UTC (rev 222280)
@@ -78,6 +78,7 @@
load("Field.js");
load("FindHighZombies.js");
load("FlattenProtocolExtends.js");
+load("FlattenedStructOffsetGatherer.js");
load("FloatLiteral.js");
load("FloatLiteralType.js");
load("FoldConstexprs.js");
Modified: trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js (222279 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js 2017-09-20 20:03:22 UTC (rev 222279)
+++ trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js 2017-09-20 20:07:07 UTC (rev 222280)
@@ -28,7 +28,7 @@
function callFunction(program, name, typeArguments, argumentList)
{
let argumentTypes = argumentList.map(argument => argument.type);
- let funcOrFailures = resolveInlinedFunction(program, name, typeArguments, argumentTypes);
+ let funcOrFailures = resolveInlinedFunction(program, name, typeArguments, argumentTypes, true);
if (!(funcOrFailures instanceof Func)) {
let failures = funcOrFailures;
throw new WTypeError("<callFunction>", "Cannot resolve function call " + name + "<" + typeArguments + ">(" + argumentList + ")" + (failures.length ? "; tried:\n" + failures.join("\n") : ""));
Copied: trunk/Tools/WebGPUShadingLanguageRI/FlattenedStructOffsetGatherer.js (from rev 222279, trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js) (0 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/FlattenedStructOffsetGatherer.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/FlattenedStructOffsetGatherer.js 2017-09-20 20:07:07 UTC (rev 222280)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+"use strict";
+
+class FlattenedStructOffsetGatherer extends Visitor {
+ constructor(initial)
+ {
+ super();
+ this._offset = 0;
+ this._name = [initial];
+ this._result = [];
+ }
+
+ get result()
+ {
+ return this._result;
+ }
+
+ visitReferenceType(node)
+ {
+ }
+
+ visitField(node)
+ {
+ this._offset += node.offset;
+ this._name.push(node.name);
+ super.visitField(node);
+ this._name.pop();
+ this._offset -= node.offset;
+ }
+
+ visitNativeType(node)
+ {
+ this._result.push({name: this._name.join("."), offset: this._offset, type: node.name});
+ super.visitNativeType(node);
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/Inline.js (222279 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/Inline.js 2017-09-20 20:03:22 UTC (rev 222279)
+++ trunk/Tools/WebGPUShadingLanguageRI/Inline.js 2017-09-20 20:07:07 UTC (rev 222280)
@@ -53,9 +53,9 @@
func.inlined = true;
}
-function resolveInlinedFunction(program, name, typeArguments, argumentTypes)
+function resolveInlinedFunction(program, name, typeArguments, argumentTypes, allowEntryPoint = false)
{
- let overload = program.globalNameContext.resolveFuncOverload(name, typeArguments, argumentTypes);
+ let overload = program.globalNameContext.resolveFuncOverload(name, typeArguments, argumentTypes, undefined, allowEntryPoint);
if (!overload.func)
return overload.failures;
if (!overload.func.typeParameters)
Modified: trunk/Tools/WebGPUShadingLanguageRI/NameContext.js (222279 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/NameContext.js 2017-09-20 20:03:22 UTC (rev 222279)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameContext.js 2017-09-20 20:07:07 UTC (rev 222280)
@@ -96,13 +96,13 @@
return result;
}
- resolveFuncOverload(name, typeArguments, argumentTypes, returnType)
+ resolveFuncOverload(name, typeArguments, argumentTypes, returnType, allowEntryPoint = false)
{
let functions = this.get(Func, name);
if (!functions)
return {failures: []};
- return resolveOverloadImpl(functions, typeArguments, argumentTypes, returnType);
+ return resolveOverloadImpl(functions, typeArguments, argumentTypes, returnType, allowEntryPoint);
}
get currentStatement()
Modified: trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js (222279 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js 2017-09-20 20:03:22 UTC (rev 222279)
+++ trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js 2017-09-20 20:07:07 UTC (rev 222280)
@@ -24,7 +24,7 @@
*/
"use strict";
-function resolveOverloadImpl(functions, typeArguments, argumentTypes, returnType)
+function resolveOverloadImpl(functions, typeArguments, argumentTypes, returnType, allowEntryPoint = false)
{
if (!functions)
throw new Error("Null functions; that should have been caught by the caller.");
@@ -32,7 +32,7 @@
let failures = [];
let successes = [];
for (let func of functions) {
- if (func.shaderType) {
+ if (!allowEntryPoint && func.shaderType) {
failures.push(new OverloadResolutionFailure(func, "Function is a " + func.shaderType + " shader, so it cannot be called from within an existing shader."))
continue;
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (222279 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-20 20:03:22 UTC (rev 222279)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-20 20:07:07 UTC (rev 222280)
@@ -55,6 +55,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
Added: trunk/Tools/WebGPUShadingLanguageRI/index.html (0 => 222280)
--- trunk/Tools/WebGPUShadingLanguageRI/index.html (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/index.html 2017-09-20 20:07:07 UTC (rev 222280)
@@ -0,0 +1,469 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+<style>
+#ShaderSource {
+ font-family: monospace;
+ width: 700px;
+ height: 400px;
+}
+
+td {
+ border: 1px solid black;
+}
+</style>
+<script>
+let defaultShaderSource = `struct VertexInput {
+ float2 position;
+ float3 color;
+}
+
+struct VertexOutput {
+ float4 wsl_Position;
+ float3 color;
+}
+
+struct FragmentOutput {
+ float4 wsl_Color;
+}
+
+vertex VertexOutput vertexShader(VertexInput vertexInput) {
+ VertexOutput result;
+ result.wsl_Position = float4(vertexInput.position, 0., 1.);
+ result.color = vertexInput.color;
+ return result;
+}
+
+fragment FragmentOutput fragmentShader(VertexOutput stageIn) {
+ FragmentOutput result;
+ result.wsl_Color = float4(stageIn.color, 1.);
+ return result;
+}`;
+
+let shaderSourceTextarea;
+let localStorage;
+let compileLogElement;
+let vertexShaderSelect;
+let fragmentShaderSelect;
+let dataTable;
+let resultTable;
+
+let program;
+let availableVertexShaders;
+let availableFragmentShaders;
+let currentVertexShader;
+let currentFragmentShader;
+let inlinedVertexShader;
+let inlinedFragmentShader;
+let allArgumentInfos;
+let argumentEPtrs;
+let stageInArgumentIndex;
+
+window.addEventListener("load", function() {
+ shaderSourceTextarea = document.getElementById("ShaderSource");
+ document.getElementById("CompileButton").addEventListener("click", compilePresentShaderSource);
+ compileLogElement = document.getElementById("CompileLog");
+ vertexShaderSelect = document.getElementById("VertexShaderSelect");
+ fragmentShaderSelect = document.getElementById("FragmentShaderSelect");
+ vertexShaderSelect.addEventListener("change", selectedShadersChanged);
+ fragmentShaderSelect.addEventListener("change", selectedShadersChanged);
+ dataTable = document.getElementById("DataTable");
+ document.getElementById("RunButton").addEventListener("click", runShaders);
+ resultTable = document.getElementById("ResultTable");
+ shaderSourceTextarea.addEventListener("input", sourceCodeChanged);
+
+ let shaderSource;
+ try {
+ localStorage = window.localStorage;
+ shaderSource = localStorage.getItem("ShaderSource");
+ } catch (e) {
+ }
+
+ if (!shaderSource)
+ shaderSource = defaultShaderSource;
+ shaderSourceTextarea.value = shaderSource;
+ compilePresentShaderSource();
+});
+
+function clearDataTable()
+{
+ while (dataTable.lastChild instanceof HTMLTableRowElement)
+ dataTable.removeChild(dataTable.lastChild);
+}
+
+function clearResultTable()
+{
+ while (resultTable.lastChild instanceof HTMLTableRowElement)
+ resultTable.removeChild(resultTable.lastChild);
+}
+
+function clearShaderSelect()
+{
+ while (vertexShaderSelect.firstChild)
+ vertexShaderSelect.removeChild(vertexShaderSelect.firstChild);
+ while (fragmentShaderSelect.firstChild)
+ fragmentShaderSelect.removeChild(fragmentShaderSelect.firstChild);
+}
+
+function sourceCodeChanged() {
+ compileLogElement.textContent = "";
+ clearShaderSelect();
+ clearDataTable();
+ clearResultTable();
+}
+
+function presentError(message) {
+ compileLogElement.textContent = message;
+ clearShaderSelect();
+ clearDataTable();
+ clearResultTable();
+ throw new Error(message);
+}
+
+function compilePresentShaderSource() {
+ compileLogElement.textContent = "";
+ let start = new Date().getTime();
+ let result;
+ try {
+ result = prepare("/internal/test", 0, shaderSourceTextarea.value);
+ } catch (e) {
+ result = e;
+ }
+ let end = new Date().getTime();
+ if (!(result instanceof Program)) {
+ compileLogElement.textContent = result.toString();
+ return;
+ } else
+ compileLogElement.textContent = "Compile successful!";
+
+ try {
+ shaderSource = localStorage.setItem("ShaderSource", shaderSourceTextarea.value);
+ } catch (e) {
+ }
+
+ program = result;
+ availableVertexShaders = [];
+ availableFragmentShaders = [];
+ for (functionNames of program.functions.values()) {
+ for (func of functionNames) {
+ if (func.shaderType == "vertex")
+ availableVertexShaders.push(func);
+ if (func.shaderType == "fragment")
+ availableFragmentShaders.push(func);
+ }
+ }
+ clearShaderSelect();
+ function createOption(textContent) {
+ let option = document.createElement("option");
+ option.textContent = textContent;
+ return option;
+ }
+ for (let i = 0; i < availableVertexShaders.length; ++i)
+ vertexShaderSelect.appendChild(createOption(availableVertexShaders[i].name));
+ for (let i = 0; i < availableFragmentShaders.length; ++i)
+ fragmentShaderSelect.appendChild(createOption(availableFragmentShaders[i].name));
+ selectedShadersChanged(true);
+}
+
+function createTableRow(name, elementCallback) {
+ let row = document.createElement("tr");
+ let variableCell = document.createElement("td");
+ let valueCell = document.createElement("td");
+ variableCell.textContent = name;
+ valueCell.appendChild(elementCallback());
+ row.appendChild(variableCell);
+ row.appendChild(valueCell);
+ return row;
+ dataTable.appendChild(row);
+}
+
+function linkError(message) {
+ compileLogElement.textContent = message + " Fix this by selecting a different pair of shaders below.";
+ clearDataTable();
+ clearResultTable();
+}
+
+function selectedShadersChanged(fromCompilation = false) {
+ if (!fromCompilation)
+ compileLogElement.textContent = "";
+ currentVertexShader = availableVertexShaders[vertexShaderSelect.selectedIndex];
+ currentFragmentShader = availableFragmentShaders[fragmentShaderSelect.selectedIndex];
+
+ inlinedVertexShader = program.funcInstantiator.getUnique(currentVertexShader, []);
+ _inlineFunction(program, inlinedVertexShader, new VisitingSet(currentVertexShader));
+
+ allArgumentInfos = [];
+ argumentEPtrs = [];
+ for (let parameter of inlinedVertexShader.parameters) {
+ let ePtr = new EPtr(new EBuffer(parameter.type.size), 0);
+ argumentEPtrs.push({ePtr: ePtr, size: parameter.type.size});
+ let gatherer = new FlattenedStructOffsetGatherer(parameter.name);
+ parameter.visit(gatherer);
+ for (argumentInfo of gatherer.result) {
+ argumentInfo.ePtr = ePtr;
+ allArgumentInfos.push(argumentInfo);
+ }
+ }
+ clearDataTable();
+ clearResultTable();
+ for (let info of allArgumentInfos) {
+ dataTable.appendChild(createTableRow(info.name, function() {
+ let input = document.createElement("input");
+ input.addEventListener("input", clearResultTable);
+ input.type = "text";
+ return input;
+ }));
+ }
+
+ let found = false;
+ let index = 0;
+ for (let parameter of currentFragmentShader.parameters) {
+ if (parameter.name == "stageIn") {
+ found = true;
+ if (!parameter.type.equals(currentVertexShader.returnType))
+ linkError("Vertex shader's return type needs to match the stageIn parameter of the fragment shader!");
+ stageInArgumentIndex = index;
+ break;
+ }
+ ++index;
+ }
+ if (!found)
+ linkError("Could not find the stageIn argument in the fragment shader!");
+ if (func.parameters.length > 1)
+ linkError("Fragment shaders currently don't know how to have any other arguments other than stageIn.");
+}
+
+function runShaders() {
+ let func = inlinedVertexShader;
+
+ let index = 0;
+ for (let childElement of dataTable.children) {
+ if (!(childElement instanceof HTMLTableRowElement))
+ continue;
+ let value = childElement.children[1].firstChild.value;
+ let argumentInfo = allArgumentInfos[index];
+ let type = argumentInfo.type;
+ switch (type) {
+ case "float":
+ value = Math.fround(parseFloat(value));
+ argumentInfo.ePtr.set(argumentInfo.offset, value);
+ break;
+ case "double":
+ value = parseFloat(value);
+ break;
+ case "int32":
+ value = parseInt(value) | 0;
+ break;
+ case "uint32":
+ value = parseInt(value) >>> 0;
+ break;
+ default:
+ presentError("I don't know how to parse values of type " + type);
+ }
+ if (isNaN(value))
+ presentError("Could not parse input data " + index);
+ argumentInfo.ePtr.set(argumentInfo.offset, value);
+ ++index;
+ }
+
+ for (let i = 0; i < func.parameters.length; ++i)
+ func.parameters[i].ePtr.copyFrom(argumentEPtrs[i].ePtr, argumentEPtrs[i].size);
+ let result = new Evaluator(program).runFunc(func);
+
+ inlinedFragmentShader = program.funcInstantiator.getUnique(currentFragmentShader, []);
+ _inlineFunction(program, inlinedFragmentShader, new VisitingSet(currentFragmentShader));
+ func = inlinedFragmentShader;
+
+ func.parameters[stageInArgumentIndex].ePtr.copyFrom(result, func.parameters[stageInArgumentIndex].type.size);
+
+ result = new Evaluator(program).runFunc(func);
+
+ clearResultTable();
+ let gatherer = new FlattenedStructOffsetGatherer(func.returnType.type.name);
+ func.returnType.type.visit(gatherer);
+ for (let info of gatherer.result) {
+ resultTable.appendChild(createTableRow(info.name, function() {
+ return document.createTextNode(result.get(info.offset));
+ }));
+ }
+}
+</script>
+</head>
+<body>
+<h1>WebGPU Shading Language</h1>
+<ol>
+<li>
+ Write a shader!
+ <div><textarea id="ShaderSource"></textarea></div>
+ <div id="CompileLog"></div>
+ <div><input type="button" value="Compile" id="CompileButton"></div>
+</li>
+<li>
+ Select your shaders
+ <div><label>Vertex Shader <select id="VertexShaderSelect"></select></label></div>
+ <div><label>Fragment Shader <select id="FragmentShaderSelect"></select></label></div>
+</li>
+<li>
+ Specify input data
+ <table id="DataTable">
+ <thead>
+ <tr>
+ <td>Variable</td>
+ <td>Value</td>
+ </tr>
+ </thead>
+ </table>
+</li>
+<li>
+ <div><input type="button" value="Run" id="RunButton"></div>
+ <table id="ResultTable">
+ <thead>
+ <tr>
+ <td>Variable</td>
+ <td>Value</td>
+ </tr>
+ </thead>
+ </table>
+</li>
+</ol>
+</body>
+</html>