WebKit Bugzilla
Attachment 349817 Details for
Bug 187735
: [WHLSL] Metal code generation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-187735-20180914151956.patch (text/plain), 152.64 KB, created by
Thomas Denney
on 2018-09-14 15:19:59 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Thomas Denney
Created:
2018-09-14 15:19:59 PDT
Size:
152.64 KB
patch
obsolete
>Subversion Revision: 236001 >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 60dc9bcca816fc13fe430ba3ccf2879b5f8ce42c..caae63442a1f74d34b1c165750cba6dd6a37e7bf 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,61 @@ >+2018-09-14 Thomas Denney <tdenney@apple.com> >+ >+ [WHLSL] Metal code generation >+ https://bugs.webkit.org/show_bug.cgi?id=187735 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adds support for generating Metal Shading Language from WHLSL. Clients >+ should include the file MetalCodegenAll.js and then call whlslToMsl >+ with their program source code to compile to Metal. >+ >+ * WebGPUShadingLanguageRI/ArrayType.js: >+ (ArrayType.prototype.get arrayRefType): Adds the arrayRefType method to >+ all types to find the type of that expression when it is used in a >+ MakeArrayRefExpression. >+ * WebGPUShadingLanguageRI/Casts.js: >+ (castToBool): >+ (castAndCheckValue): >+ (isBitwiseEquivalent): >+ * WebGPUShadingLanguageRI/Intrinsics.js: >+ (Intrinsics.isBitwiseEquivalent): Deleted. >+ * WebGPUShadingLanguageRI/MakeArrayRefExpression.js: >+ (MakeArrayRefExpression): >+ (MakeArrayRefExpression.prototype.get type): Uses the new arrayRefType >+ getter on all types to find the type of the expression. >+ * WebGPUShadingLanguageRI/Metal/MSLBackend.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLCompileResult.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLConstexprEmitter.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLNameMangler.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLNativeFunctionCall.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLTypeAttributes.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLTypeAttributesMap.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLTypeNamer.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLTypeUnifier.js: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLVarDeclaration.js: Added. >+ * WebGPUShadingLanguageRI/Metal/TypeOf.js: Added. >+ * WebGPUShadingLanguageRI/Metal/WhlslToMsl.js: Added. >+ * WebGPUShadingLanguageRI/PropertyResolver.js: >+ (PropertyResolver.visitMakePtrExpression): >+ * WebGPUShadingLanguageRI/SynthesizeStructAccessors.js: >+ (synthesizeStructAccessors.setupImplementationData): Add native >+ function implementation data. >+ * WebGPUShadingLanguageRI/Test.js: Added awkward tests for the compiler >+ to generate code for. >+ (tests.incrementAndDecrement): >+ (tests.returnIntLiteralUint): >+ (tests.returnIntLiteralFloat): >+ (tests.nestedSubscriptWithArraysInStructs): >+ (tests.nestedSubscript): >+ (tests.lotsOfLocalVariables): >+ * WebGPUShadingLanguageRI/Type.js: >+ (Type.prototype.get arrayRefType): See above. >+ > 2018-09-13 Ryan Haddad <ryanhaddad@apple.com> > > Unreviewed, rolling out r235954. >diff --git a/Tools/WebGPUShadingLanguageRI/ArrayType.js b/Tools/WebGPUShadingLanguageRI/ArrayType.js >index 0d56a0b375712c4c14bf731196109dff586bab94..b9d918e80cd210a937f238bde4f4668f10689360 100644 >--- a/Tools/WebGPUShadingLanguageRI/ArrayType.js >+++ b/Tools/WebGPUShadingLanguageRI/ArrayType.js >@@ -48,6 +48,11 @@ class ArrayType extends Type { > return this.numElements.value; > } > >+ get arrayRefType() >+ { >+ return new ArrayRefType(this.origin, "thread", this.elementType); >+ } >+ > toString() > { > return this.elementType + "[" + this.numElements + "]"; >diff --git a/Tools/WebGPUShadingLanguageRI/Casts.js b/Tools/WebGPUShadingLanguageRI/Casts.js >index acbb2ea028535b4670423097f7a5b57caf6b8b1c..c8f08ce69a7f32e8a11a0504352a4052df164d3f 100644 >--- a/Tools/WebGPUShadingLanguageRI/Casts.js >+++ b/Tools/WebGPUShadingLanguageRI/Casts.js >@@ -39,6 +39,11 @@ function bitwiseCast(typedArrayConstructor1, typedArrayConstructor2, value) > return typedArray2[0]; > } > >+function castToBool(value) >+{ >+ return !!value; >+} >+ > function castToUchar(number) > { > return number & 0xFF; >@@ -113,3 +118,25 @@ function castToFloat(number) > { > return Math.fround(number); > } >+ >+function castAndCheckValue(castFunction, value) >+{ >+ const castedValue = castFunction(value); >+ if (!isBitwiseEquivalent(castedValue, value)) >+ throw new Error(`${value} was casted and yielded ${castedValue}, which is not bitwise equivalent.`); >+ return castedValue; >+} >+ >+function isBitwiseEquivalent(left, right) >+{ >+ let doubleArray = new Float64Array(1); >+ let intArray = new Int32Array(doubleArray.buffer); >+ doubleArray[0] = left; >+ let leftInts = Int32Array.from(intArray); >+ doubleArray[0] = right; >+ for (let i = 0; i < 2; ++i) { >+ if (leftInts[i] != intArray[i]) >+ return false; >+ } >+ return true; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Intrinsics.js b/Tools/WebGPUShadingLanguageRI/Intrinsics.js >index 1b0a12af4002a90be635e738f1d5e7d90dcb04d3..68b0dd573fc02ea38517955d8388a646aa90a596 100644 >--- a/Tools/WebGPUShadingLanguageRI/Intrinsics.js >+++ b/Tools/WebGPUShadingLanguageRI/Intrinsics.js >@@ -34,20 +34,6 @@ class Intrinsics { > // For example, if a native function is declared using "int" rather than "int", then we must > // use "int" here, since we don't yet know that they are the same type. > >- function isBitwiseEquivalent(left, right) >- { >- let doubleArray = new Float64Array(1); >- let intArray = new Int32Array(doubleArray.buffer); >- doubleArray[0] = left; >- let leftInts = Int32Array.from(intArray); >- doubleArray[0] = right; >- for (let i = 0; i < 2; ++i) { >- if (leftInts[i] != intArray[i]) >- return false; >- } >- return true; >- } >- > this._map.set( > "native typedef void", > type => { >diff --git a/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js b/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js >index 0cc6f6ecd23bf03f0ae223f192b1a07ad443709e..6eb6f27d26ccd27c86f362f3808c5ec5f1ef8a56 100644 >--- a/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js >+++ b/Tools/WebGPUShadingLanguageRI/MakeArrayRefExpression.js >@@ -29,12 +29,13 @@ class MakeArrayRefExpression extends Expression { > { > super(origin); > this._lValue = lValue; >- if (this.lValue.variable && this.lValue.variable.type && this.lValue.variable.type.isArray && this.lValue.variable.type.elementType) { >- this._type = new ArrayRefType(origin, "thread", this.lValue.variable.type.elementType); >- } > } > >- get type() { return this._type; } >+ get type() >+ { >+ return typeOf(this.lValue).arrayRefType; >+ } >+ > get lValue() { return this._lValue; } > > toString() >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js >new file mode 100644 >index 0000000000000000000000000000000000000000..2d5d39a42352ae7df5e80e84c0aea97fe6cf2143 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js >@@ -0,0 +1,256 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+const DefaultMetalSource = `#include <metal_stdlib> >+using namespace metal; >+ >+`; >+ >+// Handles the compilation of Program AST instances to MSLCompileResult instances, which >+// include the raw MSL. In general clients should call |whlslToMsl|, which parses, >+// typechecks, and inlines the WHLSL before passing it to this compiler. >+class MSLBackend { >+ >+ constructor(program) >+ { >+ this._program = program; >+ this._declarations = []; >+ this._funcNameMangler = new MSLNameMangler("F"); >+ this._typeUnifier = new MSLTypeUnifier(); >+ this._typeNamer = new MSLTypeNamer(this._typeUnifier); >+ this._forwardTypeDecls = []; >+ this._typeDefinitions = []; >+ this._forwardFunctionDecls = []; >+ this._functionDefintions = []; >+ } >+ >+ get program() >+ { >+ return this._program; >+ } >+ >+ get declarations() >+ { >+ return this._declarations; >+ } >+ >+ get functionSources() >+ { >+ return this._functionSources; >+ } >+ >+ compile() >+ { >+ try { >+ const src = this._msl(); >+ const mangledMap = {}; >+ for (let func of this._functionDefintions) { >+ const key = func.func.name; >+ const value = this._funcNameMangler.mangle(func.func); >+ mangledMap[key] = value; >+ } >+ >+ return new MSLCompileResult(src, null, mangledMap, this._functionSources); >+ } catch (e) { >+ return new MSLCompileResult(null, e, null, null); >+ } >+ } >+ >+ _msl() >+ { >+ // Step 1: Find all the functions to compile >+ >+ const functionsToCompile = this._findFunctionsToCompile(); >+ for (let func of functionsToCompile) >+ func.visit(this._typeUnifier); >+ >+ // Step 2: Find properties of the types and create type and function declarations. >+ >+ this._allTypeAttributes = new MSLTypeAttributesMap(functionsToCompile, this._typeUnifier); >+ this._createTypeDecls(); >+ this._createFunctionDecls(functionsToCompile); >+ >+ // Step 3: Generate the actual MSL source code. >+ >+ let outputStr = DefaultMetalSource; >+ >+ const addSection = (title, decls) => { >+ outputStr += `#pragma mark - ${title}\n\n${decls.join("\n\n")}\n\n`; >+ }; >+ >+ addSection("Forward type declarations", this._forwardTypeDecls); >+ addSection("Type definitions", this._typeDefinitions); >+ addSection("Forward function declarations", this._forwardFunctionDecls); >+ addSection("Function definitions", this._functionDefintions); >+ >+ if (!this._allowComments) >+ outputStr = this._removeCommentsAndEmptyLines(outputStr); >+ >+ return outputStr; >+ } >+ >+ _findFunctionsToCompile() >+ { >+ const entryPointFunctions = []; >+ for (let [name, instances] of this._program.functions) { >+ for (let instance of instances) { >+ if (instance.isEntryPoint) >+ entryPointFunctions.push(instance); >+ } >+ } >+ const functions = new Set(entryPointFunctions); >+ >+ class FindFunctionsThatGetCalled extends Visitor { >+ visitCallExpression(node) >+ { >+ super.visitCallExpression(node); >+ if (node.func instanceof FuncDef) { >+ functions.add(node.func); >+ node.func.visit(this); >+ } >+ } >+ } >+ const findFunctionsThatGetCalledVisitor = new FindFunctionsThatGetCalled(); >+ for (let entryPoint of entryPointFunctions) >+ entryPoint.visit(findFunctionsThatGetCalledVisitor); >+ return Array.from(functions); >+ } >+ >+ _createTypeDecls() >+ { >+ const typesThatNeedDeclaration = this._typeUnifier.typesThatNeedDeclaration(); >+ const typeDeclsInOrder = this._sortTypeDeclarationsInTopologicalOrder(typesThatNeedDeclaration); >+ >+ for (let type of typeDeclsInOrder) { >+ if (type instanceof StructType) { >+ this._forwardTypeDecls.push(this._metalSourceForStructForwardDeclaration(type, this._typeNamer)); >+ this._typeDefinitions.push(this._metalSourceForStructDefinition(type, this._typeNamer, this._allTypeAttributes.attributesForType(type))); >+ } else if (type instanceof ArrayRefType) { >+ this._forwardTypeDecls.push(this._metalSourceForArrayRefForwardDeclaration(type, this._typeNamer)); >+ this._typeDefinitions.push(this._metalSourceForArrayRefDefinition(type, this._typeNamer)); >+ } else >+ throw new Error(`${type} cannot be declared in Metal`); >+ } >+ } >+ >+ _createFunctionDecls(unifiedFunctionDefs) >+ { >+ for (let func of unifiedFunctionDefs) { >+ this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this._funcNameMangler, func, this._typeNamer, this._allTypeAttributes)); >+ this._functionDefintions.push(new MSLFunctionDefinition(this._funcNameMangler, func, this._typeNamer, this._allTypeAttributes)); >+ } >+ } >+ >+ _sortTypeDeclarationsInTopologicalOrder(typesToDeclare) >+ { >+ const declarations = new Array(); >+ for (let type of typesToDeclare) >+ declarations.push(type); >+ >+ let typeOrder = []; >+ let visitedSet = new Set(); >+ const typeUnifier = this._typeUnifier; >+ class TypeOrderer extends Visitor { >+ visitStructType(node) >+ { >+ const id = typeUnifier.uniqueTypeId(node); >+ if (!visitedSet.has(id)) { >+ typeOrder.push(node); >+ super.visitStructType(node); >+ } >+ visitedSet.add(id); >+ } >+ >+ // An empty implementation ensures that we don't recurse into the element type and needlessly create dependencies. >+ visitReferenceType(node) {} >+ } >+ const typeOrderer = new TypeOrderer(); >+ for (let type of typesToDeclare) >+ type.visit(typeOrderer); >+ typeOrder = typeOrder.reverse(); >+ >+ const typeOrderMap = new Map(); >+ for (let i = 0; i < typeOrder.length; i++) >+ typeOrderMap.set(typeOrder[i], i); >+ >+ return declarations.sort((a, b) => typeOrderMap.get(a) - typeOrderMap.get(b)); >+ } >+ >+ // Also removes #pragma marks. >+ _removeCommentsAndEmptyLines(src) >+ { >+ const singleLineCommentRegex = /(\/\/|\#pragma)(.*?)($|\n)/; >+ const lines = src.split('\n') >+ .map(line => line.replace(singleLineCommentRegex, '').trimEnd()) >+ .filter(line => line.length > 0); >+ return lines.join('\n'); >+ } >+ >+ _metalSourceForArrayRefDefinition(arrayRefType, typeNamer) >+ { >+ let src = `struct ${typeNamer.uniqueTypeId(arrayRefType)} {\n`; >+ const fakePtrType = new PtrType(arrayRefType.origin, arrayRefType.addressSpace, arrayRefType.elementType); >+ src += ` ${mslVarDeclaration(typeNamer, fakePtrType, "ptr")};\n`; >+ src += " uint32_t length;\n"; >+ src += "};"; >+ return src; >+ } >+ >+ _metalSourceForArrayRefForwardDeclaration(arrayRefType, typeNamer) >+ { >+ return `struct ${typeNamer.uniqueTypeId(arrayRefType)};`; >+ } >+ >+ _metalSourceForStructForwardDeclaration(structType, typeNamer) >+ { >+ return `struct ${typeNamer.uniqueTypeId(structType)};`; >+ } >+ >+ _metalSourceForStructDefinition(structType, typeNamer, structTypeAttributes) >+ { >+ let src = `struct ${typeNamer.uniqueTypeId(structType)} {\n`; >+ >+ let index = 0; >+ for (let [fieldName, field] of structType.fieldMap) { >+ const mangledFieldName = structTypeAttributes.mangledFieldName(fieldName); >+ src += ` ${mslVarDeclaration(typeNamer, field.type, mangledFieldName)}`; >+ >+ const annotations = []; >+ if (structTypeAttributes.isVertexAttribute) >+ annotations.push(`attribute(${index++})`); >+ if (structTypeAttributes.isVertexOutputOrFragmentInput && fieldName === "wsl_Position") >+ annotations.push("position"); >+ if (structTypeAttributes.isFragmentOutput && fieldName === "wsl_Color") >+ annotations.push("color(0)"); >+ if (annotations.length) >+ src += ` [[${annotations.join(", ")}]]`; >+ src += ";\n"; >+ } >+ >+ src += "};"; >+ >+ return src; >+ } >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js >new file mode 100644 >index 0000000000000000000000000000000000000000..94677b9f11ec5958aefc917fcfcf1a4ca86365ae >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+load("MSLBackend.js"); >+load("MSLCompileResult.js"); >+load("MSLConstexprEmitter.js"); >+load("MSLFunctionDeclaration.js"); >+load("MSLFunctionDefinition.js"); >+load("MSLFunctionForwardDeclaration.js"); >+load("MSLNameMangler.js"); >+load("MSLNativeFunctionCall.js"); >+load("MSLStatementEmitter.js"); >+load("MSLTypeAttributesMap.js"); >+load("MSLTypeAttributes.js"); >+load("MSLTypeNamer.js"); >+load("MSLTypeUnifier.js"); >+load("MSLVarDeclaration.js"); >+load("TypeOf.js"); >+load("WhlslToMsl.js"); >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLCompileResult.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLCompileResult.js >new file mode 100644 >index 0000000000000000000000000000000000000000..2fd0bb892b669e79b730c790f453ae5a29346d0c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLCompileResult.js >@@ -0,0 +1,60 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLCompileResult { >+ >+ constructor(src, err, mangledNameMap, functionSources) >+ { >+ this._metalShaderLanguageSource = src; >+ this._error = err; >+ this._originalFunctionNameToMangledNames = mangledNameMap; >+ this._functionSources = functionSources; >+ } >+ >+ get metalShaderLanguageSource() >+ { >+ return this._metalShaderLanguageSource; >+ } >+ >+ get error() >+ { >+ return this._error; >+ } >+ >+ get originalFunctionNameToMangledNames() >+ { >+ return this._originalFunctionNameToMangledNames; >+ } >+ >+ get functionSources() >+ { >+ return this._functionSources; >+ } >+ >+ get didSucceed() >+ { >+ return !this.error; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLConstexprEmitter.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLConstexprEmitter.js >new file mode 100644 >index 0000000000000000000000000000000000000000..5d343286cfd2f38a43e83c49059804478bbfe9d1 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLConstexprEmitter.js >@@ -0,0 +1,54 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Used in scenarios where having an auxiliary variable is not possible (e.g. switch cases). >+class MSLConstexprEmitter extends Visitor >+{ >+ visitIdentityExpression(node) >+ { >+ return node.target.visit(this); >+ } >+ >+ visitBoolLiteral(node) >+ { >+ return node.value.toString(); >+ } >+ >+ visitEnumLiteral(node) >+ { >+ return node.member.value.visit(this); >+ } >+ >+ visitGenericLiteral(node) >+ { >+ // FIXME: What happens in the case of halfs/floats/etc >+ return node.value.toString(); >+ } >+ >+ visitNullLiteral(node) >+ { >+ return "nullptr"; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js >new file mode 100644 >index 0000000000000000000000000000000000000000..de39a49fb8436ea5bab642b1a22e07688e9f706e >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js >@@ -0,0 +1,124 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Emits code for for the first line of a function declaration or definition. >+class MSLFunctionDeclaration { >+ >+ constructor(funcMangler, funcDef, typeNamer, typeAttributes) >+ { >+ this._funcMangler = funcMangler; >+ this._func = funcDef; >+ this._typeNamer = typeNamer; >+ this._typeAttributes = typeAttributes; >+ } >+ >+ get funcMangler() >+ { >+ return this._funcMangler; >+ } >+ >+ get func() >+ { >+ return this._func; >+ } >+ >+ get typeNamer() >+ { >+ return this._typeNamer; >+ } >+ >+ get typeAttributes() >+ { >+ return this._typeAttributes; >+ } >+ >+ get isVertexShader() >+ { >+ return this._func.shaderType == "vertex"; >+ } >+ >+ get paramMap() >+ { >+ const map = new Map(); >+ let counter = 0; >+ for (let param of this._func.parameters) >+ map.set(param, `P${counter++}`); >+ return map; >+ } >+ >+ commentLine() >+ { >+ const params = []; >+ for (let param of this.paramMap.keys()) >+ params.push(param.name); >+ return `// ${this._func.name}(${params.join(", ")}) @ ${this._func.origin.originString}\n`; >+ } >+ >+ toString() >+ { >+ let declLine = this.commentLine(); >+ >+ if (this.isShader) >+ declLine += `${this._func.shaderType} `; >+ declLine += `${this._typeNamer.mslTypeName(this._func.returnType)} `; >+ declLine += this._funcMangler.mangle(this.func); >+ declLine += "(" >+ >+ let params = []; >+ const paramMap = this.paramMap; >+ for (let param of this._func.parameters) { >+ let pStr = mslVarDeclaration(this._typeNamer, param.type, paramMap.get(param), true); >+ // FIXME: The parser doesn't currently support vertex shaders having uint parameters, so this doesn't work. >+ if (this.parameterIsVertexId(param) && this.isVertexShader) >+ pStr += " [[vertex_id]]"; >+ else if (this.parameterIsAttribute(param)) >+ pStr += " [[stage_in]]"; >+ params.push(pStr); >+ } >+ >+ declLine += params.join(", ") + ")"; >+ >+ return declLine; >+ } >+ >+ get isShader() >+ { >+ // FIXME: Support WHLSL "compute" shaders (MSL calls these kernel shaders) >+ return this.func.shaderType === "vertex" || this.func.shaderType === "fragment"; >+ } >+ >+ parameterIsAttribute(node) >+ { >+ // We currently assuming that all parameters to entry points are attributes. >+ // TODO: Better logic for this, i.e. support samplers. >+ return this.isShader; >+ } >+ >+ parameterIsVertexId(node) >+ { >+ // FIXME: This isn't final, and isn't formally specified yet. >+ return this.isVertexShader && node.name == "wsl_vertexID" && node.type.name == "uint32"; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js >new file mode 100644 >index 0000000000000000000000000000000000000000..0d2878a94a619096c2846280f78d22b83a98251a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js >@@ -0,0 +1,37 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLFunctionDefinition extends MSLFunctionDeclaration >+{ >+ toString() >+ { >+ let src = super.toString(); >+ src += "\n{\n"; >+ let emitter = new MSLStatementEmitter(this.funcMangler, this.typeNamer, this.func, this.paramMap, this.func.name, this.typeAttributes); >+ src += emitter.indentedSource(); >+ src += "}"; >+ return src; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.js >new file mode 100644 >index 0000000000000000000000000000000000000000..57c6f81353c1f381f967345f8987f3cfb91da518 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.js >@@ -0,0 +1,32 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLFunctionForwardDeclaration extends MSLFunctionDeclaration >+{ >+ toString() >+ { >+ return super.toString() + ";" >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLNameMangler.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLNameMangler.js >new file mode 100644 >index 0000000000000000000000000000000000000000..49a30df91f821748132329629e5b55a520206bb1 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLNameMangler.js >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLNameMangler { >+ >+ constructor(prefix) >+ { >+ this._prefix = prefix; >+ this._counter = 0; >+ this._mangledNameMap = new Map(); >+ } >+ >+ mangle(key) >+ { >+ if (!this._mangledNameMap.has(key)) >+ this._mangledNameMap.set(key, `${this._prefix}${this._counter++}`); >+ return this._mangledNameMap.get(key); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLNativeFunctionCall.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLNativeFunctionCall.js >new file mode 100644 >index 0000000000000000000000000000000000000000..2ab8717fcd1ad70757fbf0a879cec91225813ccd >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLNativeFunctionCall.js >@@ -0,0 +1,82 @@ >+/* >+ * Copyright (C) 2018 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"; >+ >+function mslNativeFunctionCall(node, resultVariable, args) >+{ >+ const key = node.toString(); >+ >+ // FIXME: Implement the sampling functions. >+ // FIXME: Implement functions like f16tof32, asfloat, etc. >+ // FIXME: Implement tests for all native functions https://bugs.webkit.org/show_bug.cgi?id=189535. >+ const functionsWithTheSameCallingConvention = { >+ "native bool isfinite(float)" : "isfinite", >+ "native bool isinf(float)" : "isinf", >+ "native bool isnormal(float)" : "isnormal", >+ "native bool isnormal(half)" : "isnormal", >+ "native float acos(float)" : "acos", >+ "native float asfloat(int)" : "static_cast<float>", >+ "native float asfloat(uint)" : "static_cast<float>", >+ "native int asint(float)" : "static_cast<int>", >+ "native uint asuint(float)" : "static_cast<uint>", >+ "native float asin(float)" : "asin", >+ "native float atan(float)" : "atan", >+ "native float atan2(float,float)" : "atan2", >+ "native float ceil(float)" : "ceil", >+ "native float cos(float)" : "cos", >+ "native float cosh(float)" : "cosh", >+ "native float ddx(float)" : "dfdx", >+ "native float ddy(float)" : "dfdy", >+ "native float exp(float)" : "exp", >+ "native float floor(float)" : "floor", >+ "native float log(float)" : "log", >+ "native float pow(float,float)" : "pow", >+ "native float round(float)" : "round", >+ "native float sin(float)" : "sin", >+ "native float sinh(float)" : "sinh", >+ "native float sqrt(float)" : "sqrt", >+ "native float tan(float)" : "tan", >+ "native float tanh(float)" : "tanh", >+ "native float trunc(float)" : "trunc", >+ }; >+ >+ if (key in functionsWithTheSameCallingConvention) { >+ const callString = `${functionsWithTheSameCallingConvention[key]}(${args.join(", ")})`; >+ if (resultVariable) >+ return `${resultVariable} = ${callString};`; >+ else >+ return `${callString};`; >+ } >+ >+ const functionsWithDifferentCallingConventions = { >+ "native uint f32tof16(float)" : () => `${resultVariable} = uint(static_cast<ushort>(half(${args[0]})));`, >+ "native float f16tof32(uint)" : () => `${resultVariable} = float(static_cast<half>(ushort(${args[0]})));` >+ }; >+ if (key in functionsWithDifferentCallingConventions) >+ return functionsWithDifferentCallingConventions[key](); >+ >+ throw new Error(`${node} doesn't have mapping to a native Metal function.`); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js >new file mode 100644 >index 0000000000000000000000000000000000000000..f14ad367e9309ed2f609aa98719c864b5a12423c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js >@@ -0,0 +1,749 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLStatementEmitter extends Visitor { >+ >+ constructor(funcMangler, typeNamer, func, paramMap, debugName, typeAttributes) >+ { >+ super(); >+ this._funcMangler = funcMangler; >+ this._typeNamer = typeNamer; >+ this._func = func; >+ this._nameMap = paramMap; >+ this._debugName = debugName; >+ this._typeAttributes = typeAttributes; >+ this._counter = 0; >+ this._indentLevel = 0; >+ this._lines = []; >+ >+ this._loopConditionVariableStack = []; >+ this._loopConditionNodeStack = []; >+ this._loopIncrementNodeStack = []; >+ >+ this._actualResult = this._func.visit(this); >+ } >+ >+ _emitTrap() >+ { >+ // FIXME: Handle traps. >+ } >+ >+ _zeroInitialize(type, variableName, allowComment = true) >+ { >+ const emitter = this; >+ >+ class ZeroInitializer extends Visitor { >+ visitNativeType(node) >+ { >+ if (node.name == "bool") >+ emitter._add(`${variableName} = false;`); >+ else >+ emitter._add(`${variableName} = 0;`); >+ } >+ >+ visitPtrType(node) >+ { >+ emitter._add(`${variableName} = nullptr;`); >+ } >+ >+ visitArrayType(node) >+ { >+ for (let i = 0; i < node.numElements.value; i++) >+ emitter._zeroInitialize(node.elementType, `${variableName}[${i}]`, false); >+ } >+ >+ visitArrayRefType(node) >+ { >+ emitter._add(`${variableName}.ptr = nullptr;`); >+ emitter._add(`${variableName}.length = 0;`); >+ } >+ >+ visitEnumType(node) >+ { >+ emitter._zeroInitialize(node.baseType, variableName, false); >+ } >+ >+ visitStructType(node) >+ { >+ const typeAttributes = emitter._typeAttributes.attributesForType(node); >+ >+ for (let field of node.fields) { >+ const fieldName = typeAttributes.mangledFieldName(field.name); >+ emitter._zeroInitialize(field.type, `${variableName}.${fieldName}`, false); >+ } >+ } >+ >+ visitVectorType(node) >+ { >+ const elementNames = [ "x", "y", "z", "w" ]; >+ for (let i = 0; i < node.numElementsValue; i++) >+ emitter._add(`${variableName}.${elementNames[i]} = 0;`); >+ } >+ >+ visitMatrixType(node) >+ { >+ for (let i = 0; i < node.numRowsValue; i++) { >+ for (let j = 0; j < node.numRowsValue; j++) >+ emitter._zeroInitialize(node.elementType, `${variableName}[${i}][${j}]`, false); >+ } >+ } >+ >+ visitTypeRef(node) >+ { >+ node.type.visit(this); >+ } >+ } >+ if (allowComment) >+ this._add(`// Zero initialization of ${variableName}`); >+ Node.visit(type, new ZeroInitializer()); >+ } >+ >+ get actualResult() >+ { >+ return this._actualResult; >+ } >+ >+ get lines() >+ { >+ return this._lines; >+ } >+ >+ indentedSource() >+ { >+ return this._lines.map(line => " " + line + "\n").join(""); >+ } >+ >+ get _loopConditionVariable() >+ { >+ return this._loopConditionVariableStack[this._loopConditionVariableStack.length - 1]; >+ } >+ >+ get _loopCondition() >+ { >+ return this._loopConditionNodeStack[this._loopConditionNodeStack.length - 1]; >+ } >+ >+ get _loopIncrement() >+ { >+ return this._loopIncrementNodeStack[this._loopIncrementNodeStack.length - 1]; >+ } >+ >+ _add(linesString) >+ { >+ for (let line of linesString.split('\n')) { >+ for (let i = 0; i < this._indentLevel; i++) >+ line = " " + line; >+ this._lines.push(line); >+ } >+ } >+ >+ _addLines(lines) >+ { >+ for (let line of lines) >+ this._add(line); >+ } >+ >+ _fresh() >+ { >+ return `V${this._counter++}`; >+ } >+ >+ _indent(closure) >+ { >+ this._indentLevel++; >+ const result = closure(); >+ this._indentLevel--; >+ return result; >+ } >+ >+ // Atomic statements. >+ >+ visitBreak(node) >+ { >+ this._add("break;") >+ } >+ >+ visitContinue(node) >+ { >+ // This is necessary because for loops are compiled as while loops, so we need to do >+ // the loop increment and condition check before returning to the beginning of the loop. >+ this._emitLoopBodyEnd(); >+ this._add("continue;"); >+ } >+ >+ // Basic compound statements. >+ >+ visitBlock(block) >+ { >+ for (let statement of block.statements) { >+ this._add(`// ${this._debugName} @ ${statement.origin.originString}`); >+ statement.visit(this); >+ } >+ } >+ >+ visitReturn(node) >+ { >+ const expr = node.value.visit(this); >+ this._add(`return ${expr};`); >+ } >+ >+ _visitAndIndent(node) >+ { >+ return this._indent(() => node.visit(this)); >+ } >+ >+ visitIfStatement(node) >+ { >+ let condition = node.conditional.visit(this); >+ this._add(`if (${condition}) {`); >+ this._visitAndIndent(node.body); >+ // At the moment the parser emits Block nodes for the if and else bodies, so this allows us >+ // to check whether or not the else body is actually empty, and therefore doesn't need to be emitted. >+ // (This isn't necessary, it just yields shorter, easier to read output). >+ const shouldEmitElseBody = node.elseBody && (!(node.elseBody instanceof Block) || node.elseBody.statements.length); >+ if (shouldEmitElseBody) { >+ this._add(`} else {`); >+ this._visitAndIndent(node.elseBody); >+ this._add('}'); >+ } else >+ this._add('}'); >+ } >+ >+ visitIdentityExpression(node) >+ { >+ return node.target.visit(this); >+ } >+ >+ visitLogicalNot(node) >+ { >+ const type = typeOf(node); >+ let expr = Node.visit(node.operand, this); >+ let id = this._fresh(); >+ this._add(mslVarDeclaration(this._typeNamer, type, id) + ";"); >+ this._add(`${id} = !(${expr});`); >+ return id; >+ } >+ >+ visitDereferenceExpression(node) >+ { >+ return `(*(${node.ptr.visit(this)}))`; >+ } >+ >+ _isOperatorAnder(node) >+ { >+ const anderRegex = /^operator\&\.(.*?)$/; >+ return node instanceof NativeFunc && anderRegex.test(node.name); >+ } >+ >+ _isOperatorGetter(node) >+ { >+ const getterRegex = /^operator\.(.*?)$/; >+ return node instanceof NativeFunc && getterRegex.test(node.name); >+ } >+ >+ _isOperatorIndexer(node) >+ { >+ return node instanceof NativeFunc && node.name == "operator&[]"; >+ } >+ >+ _isOperatorSetter(node) >+ { >+ const setterRegex = /^operator\.(.*?)=$/; >+ return node instanceof NativeFunc && setterRegex.test(node.name) >+ } >+ >+ _isOperatorCast(node) >+ { >+ return node instanceof NativeFunc && node.name == "operator cast"; >+ } >+ >+ _isUnaryOperator(node) >+ { >+ const operatorRegex = /^operator\~$/; >+ return node instanceof NativeFunc && operatorRegex.test(node.name); >+ } >+ >+ _isBinaryOperator(node) >+ { >+ const operatorRegex = /operator(\+|\-|\*|\/|\^|\&|\||\&\&|\|\||\<\<|\>\>|\<|\<\=|\>|\>\=|\=\=|\!\=)$/; >+ return node instanceof NativeFunc && operatorRegex.test(node.name); >+ } >+ >+ _isOperatorValue(node) >+ { >+ return node instanceof NativeFunc && node.name == "operator.value"; >+ } >+ >+ _isOperatorLength(node) >+ { >+ return node instanceof NativeFunc && node.name == "operator.length"; >+ } >+ >+ _extractOperatorName(node) >+ { >+ return node.name.substring("operator".length); >+ } >+ >+ visitVariableDecl(node) >+ { >+ let id = this._fresh(); >+ this._nameMap.set(node, id); >+ >+ this._add(`${mslVarDeclaration(this._typeNamer, node.type, id)}; // ${node.name}`); >+ >+ if (node.initializer) { >+ let expr = node.initializer.visit(this); >+ this._add(`${id} = ${expr};`); >+ } else >+ this._zeroInitialize(node.type, id); >+ } >+ >+ visitVariableRef(node) >+ { >+ if (!this._nameMap.has(node.variable)) >+ throw new Error(`${node.variable} not found in this function's (${this._func.name}) variable map`); >+ return this._nameMap.get(node.variable); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ const elemName = Node.visit(node.lValue, this); >+ const arrayType = typeOf(node.lValue); >+ const id = this._fresh(); >+ this._add(mslVarDeclaration(this._typeNamer, node.type, id) + ";"); >+ this._add(`${id}.length = ${node.numElements.value};`); >+ if (arrayType.isArray) >+ this._add(`${id}.ptr = ${elemName};`); >+ else >+ this._add(`${id}.ptr = &(${elemName});`); >+ return id; >+ } >+ >+ visitConvertPtrToArrayRefExpression(node) >+ { >+ const lValue = node.lValue.visit(this); >+ const type = typeOf(node); >+ const id = this._fresh(); >+ this._add(mslVarDeclaration(this._typeNamer, type, id) + ";"); >+ this._add(`${id}.length = 1;`); >+ this._add(`${id}.ptr = ${lValue};`); >+ return id; >+ } >+ >+ visitAnonymousVariable(node) >+ { >+ let id = this._fresh(); >+ this._nameMap.set(node, id); >+ this._add(mslVarDeclaration(this._typeNamer, node.type, id) + `; // ${node.name}`); >+ this._zeroInitialize(node.type, id); >+ return id; >+ } >+ >+ visitAssignment(node) >+ { >+ const lhs = Node.visit(node.lhs, this); >+ const rhs = Node.visit(node.rhs, this); >+ this._add(`${lhs} = ${rhs};`); >+ return lhs; >+ } >+ >+ visitCommaExpression(node) >+ { >+ let result; >+ for (let expr of node.list) >+ result = Node.visit(expr, this); >+ return result; >+ } >+ >+ visitCallExpression(node) >+ { >+ const args = []; >+ for (let i = node.argumentList.length; i--;) >+ args.unshift(node.argumentList[i].visit(this)); >+ >+ let resultVariable; >+ if (node.func.returnType.name !== "void") { >+ resultVariable = this._fresh(); >+ this._add(`// Result variable for call ${node.func.name}(${args.join(", ")})`); >+ this._add(`${mslVarDeclaration(this._typeNamer, node.resultType, resultVariable)};`); >+ } >+ >+ if (node.func instanceof FuncDef) { >+ const mangledCallName = this._funcMangler.mangle(node.func); >+ const callString = `${mangledCallName}(${args.join(", ")})`; >+ if (resultVariable) >+ this._add(`${resultVariable} = ${callString};`); >+ else >+ this._add(`${callString};`); >+ } else >+ this._makeNativeFunctionCall(node.func, resultVariable, args); >+ >+ return resultVariable; >+ } >+ >+ _makeNativeFunctionCall(node, resultVariable, args) >+ { >+ if (!(node instanceof NativeFunc)) >+ throw new Error(`${node} should be a native function.`); >+ >+ if (this._isOperatorAnder(node)) >+ this._emitOperatorAnder(node, resultVariable, args); >+ else if (node.implementationData instanceof BuiltinVectorGetter) >+ this._emitBuiltinVectorGetter(node, resultVariable, args); >+ else if (node.implementationData instanceof BuiltinVectorSetter) >+ this._emitBuiltinVectorSetter(node, resultVariable, args); >+ else if (node.implementationData instanceof BuiltinMatrixGetter) >+ this._emitBuiltinMatrixGetter(node, resultVariable, args); >+ else if (node.implementationData instanceof BuiltinMatrixSetter) >+ this._emitBuiltinMatrixSetter(node, resultVariable, args); >+ else if (this._isOperatorValue(node)) >+ this._add(`${resultVariable} = ${args[0]};`); >+ else if (this._isOperatorLength(node)) >+ this._emitOperatorLength(node, resultVariable, args); >+ else if (this._isOperatorSetter(node)) >+ this._emitOperatorSetter(node, resultVariable, args); >+ else if (this._isOperatorGetter(node)) >+ this._emitOperatorGetter(node, resultVariable, args); >+ else if (this._isOperatorIndexer(node)) >+ this._emitOperatorIndexer(node, resultVariable, args); >+ else if (this._isOperatorCast(node)) >+ this._emitOperatorCast(node, resultVariable, args); >+ else if (this._isUnaryOperator(node)) >+ this._add(`${resultVariable} = ${this._extractOperatorName(node)}(${args[0]});`); >+ else if (this._isBinaryOperator(node)) >+ this._add(`${resultVariable} = ${args[0]} ${this._extractOperatorName(node)} ${args[1]};`); >+ else >+ this._add(mslNativeFunctionCall(node, resultVariable, args)); >+ >+ return resultVariable; >+ } >+ >+ _emitCallToMetalFunction(name, result, args) >+ { >+ this._add(`${result} = ${name}(${args.join(", ")});`); >+ } >+ >+ _emitBuiltinVectorGetter(node, result, args) >+ { >+ this._add(`${result} = ${args[0]}.${node.implementationData.elementName};`); >+ } >+ >+ _emitBuiltinVectorSetter(node, result, args) >+ { >+ this._add(`${result} = ${args[0]};`); >+ this._add(`${result}.${node.implementationData.elementName} = ${args[1]};`); >+ } >+ >+ _emitBuiltinMatrixGetter(node, result, args) >+ { >+ this._add(`if (${args[1]} >= ${node.implementationData.height}) {`); >+ this._indent(() => this._emitTrap()); >+ this._add('}'); >+ this._add(`${result} = ${args[0]}[${args[1]}];`); >+ } >+ >+ _emitBuiltinMatrixSetter(node, result, args) >+ { >+ this._add(`if (${args[1]} >= ${node.implementationData.height}) {`); >+ this._indent(() => this._emitTrap()); >+ this._add('}'); >+ this._add(`${result} = ${args[0]};`); >+ this._add(`${result}[${args[1]}] = ${args[2]};`); >+ } >+ >+ _emitOperatorLength(node, result, args) >+ { >+ const paramType = typeOf(node.parameters[0]); >+ if (paramType instanceof ArrayRefType) >+ this._add(`${result} = ${args[0]}.length;`); >+ else if (paramType instanceof ArrayType) >+ this._add(`${result} = ${paramType.numElements.visit(this)};`); >+ else >+ throw new Error(`Unhandled paramter type ${paramType} for operator.length`); >+ } >+ >+ _emitOperatorCast(node, result, args) >+ { >+ const retType = this._typeNamer.mslTypeName(node.returnType); >+ this._add(`${result} = ${retType}(${args.join(", ")});`); >+ } >+ >+ _emitOperatorIndexer(node, result, args) >+ { >+ if (!(typeOf(node.parameters[0]) instanceof ArrayRefType)) >+ throw new Error(`Support for operator&[] ${node.parameters[0]} not implemented.`); >+ >+ this._add(`if (${args[1]} >= ${args[0]}.length) {`); >+ this._indent(() => this._emitTrap()); >+ this._add(`}`); >+ this._add(`// Operator indexer`); >+ this._add(`${result} = &(${args[0]}.ptr[${args[1]}]);`); >+ } >+ >+ _emitOperatorAnder(node, result, args) >+ { >+ const type = node.implementationData.type; >+ const field = this._typeAttributes.attributesForType(type).mangledFieldName(node.implementationData.name); >+ this._add(`${result} = &((${args[0]})->${field});`); >+ } >+ >+ _emitOperatorGetter(node, result, args) >+ { >+ const type = node.implementationData.type; >+ const field = this._typeAttributes.attributesForType(type).mangledFieldName(node.implementationData.name); >+ this._add(`${result} = ${args[0]}.${field};`); >+ } >+ >+ _emitOperatorSetter(node, result, args) >+ { >+ // FIXME: Currently no WHLSL source produces structs that only have getters/setters rather than the ander, >+ // and the ander is always preferred over the getter and setter. Therefore this code is untested. >+ const type = node.implementationData.type; >+ const field = this._typeAttributes.attributesForType(type).mangledFieldName(node.implementationData.name); >+ this._add(`${args[0]}.${field} = ${args[1]};`); >+ this._add(`${result} = ${args[0]}`); >+ } >+ >+ visitMakePtrExpression(node) >+ { >+ return `&(${node.lValue.visit(this)})`; >+ } >+ >+ // Loop code generation. Loops all follow the same style where they declare a conditional variable (boolean) >+ // which is checked on each iteration (all loops are compiled to a while loop or do/while loop). The check is >+ // emitted in _emitLoopCondition. For loops additionally have _emitLoopBodyEnd for the increment on each iteration. >+ >+ visitForLoop(node) >+ { >+ this._emitAsLoop(node.condition, node.increment, (conditionVar) => { >+ Node.visit(node.initialization, this); >+ this._emitLoopCondition(); >+ this._add(`while (${conditionVar}) {`); >+ this._indent(() => { >+ node.body.visit(this); >+ this._emitLoopBodyEnd(); >+ }); >+ this._add('}'); >+ }); >+ } >+ >+ visitWhileLoop(node) >+ { >+ this._emitAsLoop(node.conditional, null, (conditionVar) => { >+ this._add(`while (${conditionVar}) {`); >+ this._indent(() => { >+ node.body.visit(this); >+ this._emitLoopCondition(); >+ }); >+ this._add('}'); >+ }); >+ } >+ >+ visitDoWhileLoop(node) >+ { >+ this._emitAsLoop(node.conditional, null, conditionVar => { >+ this._add("do {"); >+ this._indent(() => { >+ node.body.visit(this); >+ this._emitLoopBodyEnd(); >+ }); >+ this._add(`} while (${conditionVar});`); >+ }); >+ } >+ >+ _emitAsLoop(conditional, increment, emitLoopBody) >+ { >+ const conditionVar = this._fresh(); >+ this._loopConditionVariableStack.push(conditionVar); >+ this._loopConditionNodeStack.push(conditional); >+ this._loopIncrementNodeStack.push(increment); >+ this._add(`bool ${conditionVar} = true;`); >+ >+ emitLoopBody(conditionVar); >+ >+ this._loopIncrementNodeStack.pop(); >+ this._loopConditionVariableStack.pop(); >+ this._loopConditionNodeStack.pop(); >+ } >+ >+ _emitLoopBodyEnd() >+ { >+ this._emitLoopIncrement(); >+ this._emitLoopCondition(); >+ } >+ >+ _emitLoopIncrement() >+ { >+ Node.visit(this._loopIncrement, this); >+ } >+ >+ _emitLoopCondition() >+ { >+ if (this._loopCondition) { >+ const conditionResult = this._loopCondition.visit(this); >+ this._add(`${this._loopConditionVariable} = ${conditionResult};`); >+ } >+ } >+ >+ // Switch statements. >+ >+ visitSwitchStatement(node) >+ { >+ const caseValueEmitter = new MSLConstexprEmitter(); >+ >+ let switchValue = Node.visit(node.value, this); >+ this._add(`switch (${switchValue}) {`); >+ this._indent(() => { >+ for (let i = 0; i < node.switchCases.length; i++) { >+ let switchCase = node.switchCases[i]; >+ if (!switchCase.isDefault) >+ this._add(`case ${switchCase.value.visit(caseValueEmitter)}: {`); >+ else >+ this._add("default: {"); >+ this._visitAndIndent(switchCase.body); >+ this._add("}"); >+ } >+ }); >+ this._add("}"); >+ } >+ >+ visitSwitchCase(node) >+ { >+ throw new Error(`MSLStatementEmitter.visitSwitchCase called; switch statements should be fully handled by MSLStatementEmitter.visitSwitchStatement.`); >+ } >+ >+ // Literals >+ >+ visitBoolLiteral(node) >+ { >+ const fresh = this._fresh(); >+ this._add(`bool ${fresh} = ${node.value};`); >+ return fresh; >+ } >+ >+ visitEnumLiteral(node) >+ { >+ return node.member.value.visit(this); >+ } >+ >+ visitGenericLiteral(node) >+ { >+ const fresh = this._fresh(); >+ this._add(mslVarDeclaration(this._typeNamer, node.type, fresh) + ";"); >+ this._add(`${fresh} = ${node.value};`); >+ return fresh; >+ } >+ >+ visitNullLiteral(node) >+ { >+ return `nullptr`; >+ } >+ >+ visitDotExpression(node) >+ { >+ throw new Error(`MSLStatementEmitter.visitDotExpression called; ${node} should have been converted to an operator function call.`); >+ } >+ >+ visitTrapStatement(node) >+ { >+ this._emitTrap(); >+ } >+ >+ visitLogicalExpression(node) >+ { >+ const result = this._fresh(); >+ this._add(`// Result variable for ${node.text}`); >+ this._add(`bool ${result};`); >+ if (node.text == "&&") { >+ const left = node.left.visit(this); >+ this._add(`if (!${left}) {`) >+ this._indent(() => this._add(`${result} = false;`)); >+ this._add('} else {'); >+ this._indent(() => this._add(`${result} = ${node.right.visit(this)};`)); >+ this._add('}'); >+ } else if (node.text == "||") { >+ const left = node.left.visit(this); >+ this._add(`${result} = ${left};`); >+ this._add(`if (!${result}) {`); >+ this._indent(() => this._add(`${result} = ${node.right.visit(this)};`)); >+ this._add("}"); >+ } else >+ throw new Error(`Unrecognized logical expression ${node.text}`); >+ return result; >+ } >+ >+ visitTernaryExpression(node) >+ { >+ // FIXME: If each of the three expressions isn't a compound expression or statement then just use ternary syntax. >+ let resultType = typeOf(node.bodyExpression); >+ if (node.isLValue) >+ resultType = new PtrType(node.origin, "thread", resultType); >+ let resultVar = this._fresh(); >+ this._add(mslVarDeclaration(this._typeNamer, resultType, resultVar) + ";"); >+ const predicate = node.predicate.visit(this); >+ this._add(`if (${predicate}) {`); >+ this._indent(() => { >+ const bodyExpression = node.bodyExpression.visit(this); >+ if (node.isLValue) >+ this._add(`${resultVar} = &(${bodyExpression});`); >+ else >+ this._add(`${resultVar} = ${bodyExpression};`); >+ }); >+ this._add("} else {"); >+ this._indent(() => { >+ const elseExpression = node.elseExpression.visit(this); >+ if (node.isLValue) >+ this._add(`${resultVar} = &(${elseExpression});`); >+ else >+ this._add(`${resultVar} = ${elseExpression};`); >+ }); >+ this._add("}"); >+ >+ if (node.isLValue) >+ resultVar = `*(${resultVar})`; >+ >+ return resultVar; >+ } >+ >+ visitIndexExpression(node) >+ { >+ throw new Error("MSLStatementEmitter.visitIndexExpression is not implemented; IndexExpression should not appear in the AST for Metal codegen."); >+ } >+ >+ visitNativeFunc(node) >+ { >+ throw new Error("MSLStatementEmitter.visitNativeFunc is not implemented; NativeFunction is not compiled by the Metal codegen."); >+ } >+ >+ visitNativeTypeInstance(node) >+ { >+ throw new Error("MSLStatementEmitter.visitNativeTypeInstance is not implemented."); >+ } >+ >+ visitReadModifyWriteExpression(node) >+ { >+ throw new Error("MSLStatementEmitter.visitReadModifyWriteExpression is not implemented; it should have been transformed out the tree in earlier stage."); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeAttributes.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeAttributes.js >new file mode 100644 >index 0000000000000000000000000000000000000000..d6f1676130a8d03fb2f757b9c2b7ed8c41ca1750 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeAttributes.js >@@ -0,0 +1,86 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLTypeAttributes { >+ >+ constructor(type) >+ { >+ this._type = type; >+ this._isVertexAttribute = false; >+ this._isVertexOutputOrFragmentInput = false; >+ this._isFragmentOutput = false; >+ this._fieldMangler = new MSLNameMangler('field'); >+ >+ if (type instanceof StructType) { >+ for (let field of type.fields) >+ this._fieldMangler.mangle(field.name) >+ } >+ } >+ >+ get type() >+ { >+ return this._type; >+ } >+ >+ get isVertexAttribute() >+ { >+ return this._isVertexAttribute; >+ } >+ >+ set isVertexAttribute(va) >+ { >+ this._isVertexAttribute = va; >+ } >+ >+ get isVertexOutputOrFragmentInput() >+ { >+ return this._isVertexOutputOrFragmentInput; >+ } >+ >+ set isVertexOutputOrFragmentInput(vo) >+ { >+ this._isVertexOutputOrFragmentInput = vo; >+ } >+ >+ get isFragmentOutput() >+ { >+ return this._isFragmentOutput; >+ } >+ >+ set isFragmentOutput(fo) >+ { >+ this._isFragmentOutput = fo; >+ } >+ >+ get fieldMangler() >+ { >+ return this._fieldMangler; >+ } >+ >+ mangledFieldName(fieldName) >+ { >+ return this.fieldMangler.mangle(fieldName); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeAttributesMap.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeAttributesMap.js >new file mode 100644 >index 0000000000000000000000000000000000000000..373b0e8c0fe93488988b6f830c7a9c6f703a28f6 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeAttributesMap.js >@@ -0,0 +1,66 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Provides lookup for all the top level types in the program. >+class MSLTypeAttributesMap { >+ >+ constructor(functionDefs, typeUnifier) >+ { >+ this._typeUnifier = typeUnifier; >+ this._typeAttributeMap = new Map(); >+ >+ for (let funcDef of functionDefs) { >+ if (funcDef.shaderType == "vertex") >+ this._visitVertexShader(funcDef); >+ else if (funcDef.shaderType == "fragment") >+ this._visitFragmentShader(funcDef); >+ } >+ } >+ >+ attributesForType(type) >+ { >+ const key = this._typeUnifier.uniqueTypeId(type); >+ let attrs = this._typeAttributeMap.get(key); >+ if (!attrs) >+ this._typeAttributeMap.set(key, attrs = new MSLTypeAttributes(type)); >+ return attrs; >+ } >+ >+ _visitVertexShader(func) >+ { >+ this.attributesForType(func.returnType).isVertexOutputOrFragmentInput = true; >+ for (let param of func.parameters) >+ this.attributesForType(param.type).isVertexAttribute = true; >+ } >+ >+ _visitFragmentShader(func) >+ { >+ this.attributesForType(func.returnType).isFragmentOutput = true; >+ for (let param of func.parameters) >+ this.attributesForType(param.type).isVertexOutputOrFragmentInput = true; >+ } >+ >+ // FIXME: Support compute shaders. >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.js >new file mode 100644 >index 0000000000000000000000000000000000000000..8c4dd61a37216534917cd21ae97bbd608eb9f10a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.js >@@ -0,0 +1,148 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+class MSLTypeNamer { >+ >+ constructor(typeUnifier) >+ { >+ this._typeUnifier = typeUnifier; >+ } >+ >+ get typeUnifier() >+ { >+ return this._typeUnifier; >+ } >+ >+ uniqueTypeId(type) >+ { >+ return this.typeUnifier.uniqueTypeId(type); >+ } >+ >+ // Yields the string that should be used in MSL source for the type. >+ mslTypeName(type) >+ { >+ let name; >+ >+ const typeUnifier = this.typeUnifier; >+ const typeNamer = this; >+ let emittedAddressSpaceForArray = false; >+ >+ class TypeNameVisitor extends Visitor { >+ visitNativeType(node) >+ { >+ // FIXME: Also add samplers and textures here. >+ const nativeTypeNameMap = { >+ "void": "void", >+ "bool": "bool", >+ "uchar": "uint8_t", >+ "ushort": "uint16_t", >+ "uint": "uint32_t", >+ "char": "int8_t", >+ "short": "int16_t", >+ "int": "int32_t", >+ "half": "half", >+ "float": "float", >+ "atomic_int": "atomic_int", >+ "atomic_uint": "atomic_uint" >+ }; >+ >+ name = nativeTypeNameMap[node.name]; >+ } >+ >+ visitStructType(node) >+ { >+ name = typeUnifier.uniqueTypeId(node); >+ } >+ >+ visitEnumType(node) >+ { >+ return Node.visit(node.baseType, this); >+ } >+ >+ visitReferenceType(node) >+ { >+ name = `${node.addressSpace} ${typeNamer.mslTypeName(node.elementType)}*`; >+ } >+ >+ visitArrayType(node) >+ { >+ name = `${node.addressSpace ? node.addressSpace + " " : ""}${typeNamer.mslTypeName(node.elementType)}*`; >+ } >+ >+ visitArrayRefType(node) >+ { >+ name = typeUnifier.uniqueTypeId(node); >+ } >+ >+ visitVectorType(node) >+ { >+ // Vector type names work slightly differently to native type names >+ const elementTypeNameMap = { >+ "bool": "bool", >+ "char": "char", >+ "uchar": "uchar", >+ "short": "short", >+ "ushort": "ushort", >+ "int": "int", >+ "uint": "uint", >+ "half": "half", >+ "float": "float" >+ }; >+ >+ const elementTypeName = elementTypeNameMap[node.elementType.name]; >+ if (!elementTypeName) >+ throw new Error(`${node.elementType.name} is not a supported vector element type`); >+ >+ name = `${elementTypeName}${node.numElementsValue}`; >+ } >+ >+ visitTypeRef(node) >+ { >+ node.type.visit(this); >+ } >+ >+ visitMatrixType(node) >+ { >+ const elementTypeNameMap = { >+ "half": "half", >+ "float": "float" >+ }; >+ >+ const elementTypeName = elementTypeNameMap[node.elementType.name]; >+ if (!elementTypeName) >+ throw new Error(`${node.elementType.name} is not a supported matrix element type`); >+ >+ name = `${elementTypeName}${node.numRowsValue}x${node.numColumnsValue}`; >+ } >+ } >+ >+ type.visit(new TypeNameVisitor()); >+ >+ if (!name) >+ throw new Error(`${type} doesn't have a name`); >+ >+ return name; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeUnifier.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeUnifier.js >new file mode 100644 >index 0000000000000000000000000000000000000000..8b9bbcbb5b0eb837569c88c2fb1ffda8ca7e46bd >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeUnifier.js >@@ -0,0 +1,132 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+ >+class MSLTypeUnifier extends Visitor { >+ >+ constructor() >+ { >+ super(); >+ >+ this._typeNameMangler = new MSLNameMangler('T'); >+ this._allTypes = new Set(); >+ } >+ >+ get allTypes() >+ { >+ return this._allTypes; >+ } >+ >+ uniqueTypeId(type) >+ { >+ return type.visit(this); >+ } >+ >+ visitTypeRef(node) >+ { >+ if ((node.typeArguments && node.typeArguments.length) || !node.name) { >+ return node.type.visit(this); >+ } >+ >+ if (!this._allTypes.has(node.type)) >+ node.type.visit(this); >+ >+ const baseType = typeOf(node); >+ >+ if (baseType instanceof NativeType || baseType instanceof VectorType) >+ return baseType.visit(this); >+ >+ return this._typeNameMangler.mangle(node.name); >+ } >+ >+ visitStructType(node) >+ { >+ this._allTypes.add(node); >+ for (let field of node.fields) >+ field.visit(this); >+ return this._typeNameMangler.mangle(node.name); >+ } >+ >+ visitEnumType(node) >+ { >+ this._allTypes.add(node); >+ node.baseType.visit(this); >+ return this._typeNameMangler.mangle(node.name); >+ } >+ >+ visitNativeType(node) >+ { >+ this._allTypes.add(node); >+ return node.name; >+ } >+ >+ visitPtrType(node) >+ { >+ this._allTypes.add(node); >+ node.elementType.visit(this); >+ return `${node.elementType.visit(this)}* ${node.addressSpace}`; >+ } >+ >+ visitArrayType(node) >+ { >+ this._allTypes.add(node); >+ node.elementType.visit(this); >+ return `${node.elementType.visit(this)}[${node.numElements}]`; >+ } >+ >+ visitArrayRefType(node) >+ { >+ this._allTypes.add(node); >+ // The name mangler is used here because array refs are "user-defined" types in the sense >+ // that they will need to be defined as structs in the Metal output. >+ return this._typeNameMangler.mangle(`${node.elementType.visit(this)}[] ${node.addressSpace}`); >+ } >+ >+ visitVectorType(node) >+ { >+ this._allTypes.add(node); >+ return node.toString(); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ super.visitMakeArrayRefExpression(node); >+ return node.type.visit(this); >+ } >+ >+ typesThatNeedDeclaration() >+ { >+ const declSet = new Set(); >+ const nameSet = new Set(); >+ for (let type of this._allTypes) { >+ const name = type.visit(this); >+ if ((type instanceof StructType || type instanceof ArrayRefType) && !nameSet.has(name)) { >+ declSet.add(type); >+ nameSet.add(name); >+ } >+ } >+ return declSet; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLVarDeclaration.js b/Tools/WebGPUShadingLanguageRI/Metal/MSLVarDeclaration.js >new file mode 100644 >index 0000000000000000000000000000000000000000..355638c87ede6f1baacf8616ab8bf0f0bec76340 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLVarDeclaration.js >@@ -0,0 +1,46 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+function mslVarDeclaration(typeNamer, type, name, treatArrayAsPointer = false) >+{ >+ type = typeOf(type); // Unwrap TypeRef if necessary >+ if (type.isArray) { >+ let arrayType = type; >+ const sizes = [ arrayType.numElementsValue ]; >+ let elementType = typeOf(arrayType.elementType); >+ while (elementType.isArray) { >+ arrayType = elementType; >+ sizes.push(arrayType.numElementsValue); >+ elementType = arrayType.elementType; >+ } >+ if (treatArrayAsPointer) >+ return `${arrayType.addressSpace ? arrayType.addressSpace : "thread"} ${typeNamer.mslTypeName(elementType)} (*${name})${sizes.slice(1).map(size => `[${size}]`).join('')}`; >+ else >+ return `${typeNamer.mslTypeName(elementType)} ${name}${sizes.map(size => `[${size}]`).join('')}`; >+ } else if (type.isPtr) >+ return (type).addressSpace + " " + mslVarDeclaration(typeNamer, (type).elementType, `(*${name})`); >+ else >+ return `${typeNamer.mslTypeName(type)} ${name}`; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeOf.js b/Tools/WebGPUShadingLanguageRI/Metal/TypeOf.js >new file mode 100644 >index 0000000000000000000000000000000000000000..a1be79332a9c28843228fac3c770d905889b4771 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeOf.js >@@ -0,0 +1,325 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// FIXME: Rather than being a separate function this should instead be a separate preparation phase that annotates >+// each Node instance with a "type" property. https://bugs.webkit.org/show_bug.cgi?id=189611 >+function typeOf(node) { >+ class TypeVisitor extends Visitor { >+ visitAnonymousVariable(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitArrayRefType(node) >+ { >+ return node; >+ } >+ >+ visitArrayType(node) >+ { >+ return node; >+ } >+ >+ visitAssignment(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitCallExpression(node) >+ { >+ return node.func.visit(this); >+ } >+ >+ visitCommaExpression(node) >+ { >+ return node.list[node.list.length - 1].visit(this); >+ } >+ >+ visitConvertPtrToArrayRefExpression(node) >+ { >+ const ptrType = typeOf(node.lValue); >+ return new ArrayRefType(node.origin, ptrType.addressSpace, ptrType.elementType); >+ } >+ >+ visitDotExpression(node) >+ { >+ return node.struct.fieldMap.get(node.fieldName).type.visit(this); >+ } >+ >+ visitElementalType(node) >+ { >+ return node; >+ } >+ >+ visitEnumType(node) >+ { >+ return node; >+ } >+ >+ visitField(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitFunc(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitFuncDef(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitFuncParameter(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitFunctionLikeBlock(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitGenericLiteralType(node) >+ { >+ return typeOf(node.type); >+ } >+ >+ visitIdentityExpression(node) >+ { >+ return node.target.visit(this); >+ } >+ >+ visitIndexExpression(node) >+ { >+ return node.array.elementType.visit(this); >+ } >+ >+ visitLogicalExpression(node) >+ { >+ throw new Error("FIXME: Implement TypeVisitor.visitLogicalExpression"); >+ } >+ >+ visitLogicalNot(node) >+ { >+ return node.operand.visit(this); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitMakePtrExpression(node) >+ { >+ throw new Error("FIXME: Implement TypeVisitor.visitMakePtrExpression"); >+ } >+ >+ visitMatrixType(node) >+ { >+ return node; >+ } >+ >+ visitNativeFunc(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitNativeFuncInstance(node) >+ { >+ return node.returnType.visit(this); >+ } >+ >+ visitNativeType(node) >+ { >+ return node; >+ } >+ >+ visitNativeTypeInstance(node) >+ { >+ return node; >+ } >+ >+ visitNullLiteral(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitNullType(node) >+ { >+ return node; >+ } >+ >+ visitPtrType(node) >+ { >+ return node; >+ } >+ >+ visitReadModifyWriteExpression(node) >+ { >+ throw new Error("FIXME: Implement TypeVisitor.visitReadModifyWriteExpression"); >+ } >+ >+ visitReferenceType(node) >+ { >+ return node; >+ } >+ >+ visitStructType(node) >+ { >+ return node; >+ } >+ >+ visitTypeDef(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitTypeRef(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitVariableDecl(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitVariableRef(node) >+ { >+ return node.variable.type.visit(this); >+ } >+ >+ visitVectorType(node) >+ { >+ return node; >+ } >+ >+ visitBlock(node) >+ { >+ throw new Error("Block has no type"); >+ } >+ >+ visitBoolLiteral(node) >+ { >+ throw new Error("BoolLiteral has no type"); >+ } >+ >+ visitBreak(node) >+ { >+ throw new Error("Break has no type"); >+ } >+ >+ visitConstexprTypeParameter(node) >+ { >+ throw new Error("ConstexprTypeParameter has no type"); >+ } >+ >+ visitContinue(node) >+ { >+ throw new Error("Continue has no type"); >+ } >+ >+ visitDereferenceExpression(node) >+ { >+ return node.type.visit(this); >+ } >+ >+ visitDoWhileLoop(node) >+ { >+ throw new Error("DoWhileLoop has no type"); >+ } >+ >+ visitEnumLiteral(node) >+ { >+ throw new Error("EnumLiteral has no type"); >+ } >+ >+ visitEnumMember(node) >+ { >+ throw new Error("EnumMember has no type"); >+ } >+ >+ visitForLoop(node) >+ { >+ throw new Error("ForLoop has no type"); >+ } >+ visitGenericLiteral(node) >+ { >+ return node.type.visit(this); >+ } >+ visitIfStatement(node) >+ { >+ throw new Error("IfStatement has no type"); >+ } >+ >+ visitProgram(node) >+ { >+ throw new Error("Program has no type"); >+ } >+ >+ visitProtocolDecl(node) >+ { >+ throw new Error("ProtocolDecl has no type"); >+ } >+ >+ visitProtocolFuncDecl(node) >+ { >+ throw new Error("ProtocolFuncDecl has no type"); >+ } >+ >+ visitProtocolRef(node) >+ { >+ throw new Error("ProtocolRef has no type"); >+ } >+ >+ visitReturn(node) >+ { >+ throw new Error("Return has no type"); >+ } >+ >+ visitSwitchCase(node) >+ { >+ throw new Error("SwitchCase has no type"); >+ } >+ >+ visitSwitchStatement(node) >+ { >+ throw new Error("SwitchStatement has no type"); >+ } >+ >+ visitTrapStatement(node) >+ { >+ throw new Error("TrapStatement has no type"); >+ } >+ >+ visitWhileLoop(node) >+ { >+ throw new Error("WhileLoop has no type"); >+ } >+ } >+ return node.visit(new TypeVisitor()); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WhlslToMsl.js b/Tools/WebGPUShadingLanguageRI/Metal/WhlslToMsl.js >new file mode 100644 >index 0000000000000000000000000000000000000000..5c85f2b49b2e3920a281f4e7278f21fc1ff4103f >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WhlslToMsl.js >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (C) 2018 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. >+ */ >+ >+// Main wrapper for the compiler. Clients should use this function to compile WHLSL. >+function whlslToMsl(src) >+{ >+ let parsedProgram; >+ try { >+ parsedProgram = prepare("/internal/test", 0, src); >+ } catch (e) { >+ return new MSLCompileResult(null, e, null, null); >+ } >+ >+ if (!(parsedProgram instanceof Program)) >+ return new MSLCompileResult(null, new Error("Compilation failed"), null, null); >+ >+ const compiler = new MSLBackend(parsedProgram); >+ return compiler.compile(); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/PropertyResolver.js b/Tools/WebGPUShadingLanguageRI/PropertyResolver.js >index b5c454ac2dc3d534ca5213ef13c3736cd1700344..23184ca5ad2f3aab46416a56adfcbe084ef39b5c 100644 >--- a/Tools/WebGPUShadingLanguageRI/PropertyResolver.js >+++ b/Tools/WebGPUShadingLanguageRI/PropertyResolver.js >@@ -168,6 +168,8 @@ class PropertyResolver extends Visitor { > super.visitMakePtrExpression(node); > if (!node.lValue.isLValue) > throw new WTypeError(node.origin.originString, "Not an lvalue: " + node.lValue); >+ if (node.lValue.unifyNode instanceof DereferenceExpression) >+ node.become(new IdentityExpression(node.lValue.unifyNode.ptr)); > } > > visitMakeArrayRefExpression(node) >diff --git a/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js b/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js >index a0181468a25ed4c09050d7bf1d61f44ed3a0aa66..24a209433bde0c1bbc2085654a0612c8c65fe9cd 100644 >--- a/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js >+++ b/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js >@@ -42,6 +42,13 @@ function synthesizeStructAccessors(program) > nativeFunc.implementation = (argumentList, node) => { > return implementation(argumentList, field.offset, type.size, field.type.size); > }; >+ >+ nativeFunc.implementationData = { >+ name: field.name, >+ type: type, >+ offset: field.offset, >+ size: field.type.size >+ }; > } > > function createFieldType() >diff --git a/Tools/WebGPUShadingLanguageRI/Test.js b/Tools/WebGPUShadingLanguageRI/Test.js >index 2bcea7d7da3cb382f1aabe2167ef3a7891392333..bec9a530f3e146cb4906b04bea1d0f5ed47166d0 100644 >--- a/Tools/WebGPUShadingLanguageRI/Test.js >+++ b/Tools/WebGPUShadingLanguageRI/Test.js >@@ -55,32 +55,37 @@ function doLex(code) > > function makeInt(program, value) > { >- return TypedValue.box(program.intrinsics.int, value); >+ return TypedValue.box(program.intrinsics.int, castAndCheckValue(castToInt, value)); > } > > function makeUint(program, value) > { >- return TypedValue.box(program.intrinsics.uint, value); >+ return TypedValue.box(program.intrinsics.uint, castAndCheckValue(castToUint, value)); > } > > function makeUchar(program, value) > { >- return TypedValue.box(program.intrinsics.uchar, value); >+ return TypedValue.box(program.intrinsics.uchar, castAndCheckValue(castToUchar, value)); > } > > function makeBool(program, value) > { >- return TypedValue.box(program.intrinsics.bool, value); >+ return TypedValue.box(program.intrinsics.bool, castAndCheckValue(castToBool, value)); > } > > function makeFloat(program, value) > { >- return TypedValue.box(program.intrinsics.float, value); >+ return TypedValue.box(program.intrinsics.float, castAndCheckValue(castToFloat, value)); >+} >+ >+function makeCastedFloat(program, value) >+{ >+ return TypedValue.box(program.intrinsics.float, castToFloat(value)); > } > > function makeHalf(program, value) > { >- return TypedValue.box(program.intrinsics.half, value); >+ return TypedValue.box(program.intrinsics.half, castAndCheckValue(castToHalf, value)); > } > > function makeEnum(program, enumName, value) >@@ -221,19 +226,12 @@ function makeRW2DDepthTextureArray(program, array, elementType) > return TypedValue.box(program.intrinsics[`RWTextureDepth2DArray<${elementType}>`], new TextureDepth2DArrayRW(elementType, array)); > } > >-function checkNumber(program, result, expected) >-{ >- if (!result.type.unifyNode.isNumber) >- throw new Error("Wrong result type; result: " + result); >- if (result.value != expected) >- throw new Error("Wrong result: " + result.value + " (expected " + expected + ")"); >-} >- > function checkInt(program, result, expected) > { > if (!result.type.equals(program.intrinsics.int)) > throw new Error("Wrong result type; result: " + result); >- checkNumber(program, result, expected); >+ if (result.value != expected) >+ throw new Error(`Wrong result: ${result.value} (expected ${expected})`); > } > > function checkEnum(program, result, expected) >@@ -439,6 +437,27 @@ tests.intSimpleMath = function() { > checkInt(program, callFunction(program, "foo", [makeInt(program, 7), makeInt(program, -2)]), -3); > } > >+tests.incrementAndDecrement = function() { >+ let program = doPrep(` >+ test int foo1() { int x = 0; return x++; } >+ test int foo2() { int x = 0; x++; return x; } >+ test int foo3() { int x = 0; return ++x; } >+ test int foo4() { int x = 0; ++x; return x; } >+ test int foo5() { int x = 0; return x--; } >+ test int foo6() { int x = 0; x--; return x; } >+ test int foo7() { int x = 0; return --x; } >+ test int foo8() { int x = 0; --x; return x; } >+ `); >+ checkInt(program, callFunction(program, "foo1", []), 0); >+ checkInt(program, callFunction(program, "foo2", []), 1); >+ checkInt(program, callFunction(program, "foo3", []), 1); >+ checkInt(program, callFunction(program, "foo4", []), 1); >+ checkInt(program, callFunction(program, "foo5", []), 0); >+ checkInt(program, callFunction(program, "foo6", []), -1); >+ checkInt(program, callFunction(program, "foo7", []), -1); >+ checkInt(program, callFunction(program, "foo8", []), -1); >+} >+ > tests.uintSimpleMath = function() { > let program = doPrep("test uint foo(uint x, uint y) { return x + y; }"); > checkUint(program, callFunction(program, "foo", [makeUint(program, 7), makeUint(program, 5)]), 12); >@@ -1039,13 +1058,13 @@ tests.passNullToPtrMonomorphicArrayRef = function() > tests.returnIntLiteralUint = function() > { > let program = doPrep("test uint foo() { return 42; }"); >- checkNumber(program, callFunction(program, "foo", []), 42); >+ checkUint(program, callFunction(program, "foo", []), 42); > } > > tests.returnIntLiteralFloat = function() > { > let program = doPrep("test float foo() { return 42; }"); >- checkNumber(program, callFunction(program, "foo", []), 42); >+ checkFloat(program, callFunction(program, "foo", []), 42); > } > > tests.badIntLiteralForInt = function() >@@ -2355,6 +2374,149 @@ tests.nestedSubscriptLValueEmulationSimple = function() > checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", []), 5565); > } > >+tests.nestedSubscriptWithArraysInStructs = function() >+{ >+ let program = doPrep(` >+ struct Foo { >+ int[7] array; >+ } >+ int sum(Foo foo) >+ { >+ int result = 0; >+ for (uint i = 0; i < foo.array.length; i++) >+ result += foo.array[i]; >+ return result; >+ } >+ struct Bar { >+ Foo[6] array; >+ } >+ int sum(Bar bar) >+ { >+ int result = 0; >+ for (uint i = 0; i < bar.array.length; i++) >+ result += sum(bar.array[i]); >+ return result; >+ } >+ struct Baz { >+ Bar[5] array; >+ } >+ int sum(Baz baz) >+ { >+ int result = 0; >+ for (uint i = 0; i < baz.array.length; i++) >+ result += sum(baz.array[i]); >+ return result; >+ } >+ void setValues(thread Baz* baz) >+ { >+ for (uint i = 0; i < baz->array.length; i++) { >+ for (uint j = 0; j < baz->array[i].array.length; j++) { >+ for (uint k = 0; k < baz->array[i].array[j].array.length; k++) >+ baz->array[i].array[j].array[k] = int(i + j + k); >+ } >+ } >+ } >+ test int testSetValuesAndSum() >+ { >+ Baz baz; >+ setValues(&baz); >+ return sum(baz); >+ } >+ test int testSetValuesMutateValuesAndSum() >+ { >+ Baz baz; >+ setValues(&baz); >+ for (uint i = baz.array.length; i--;) { >+ for (uint j = baz.array[i].array.length; j--;) { >+ for (uint k = baz.array[i].array[j].array.length; k--;) >+ baz.array[i].array[j].array[k] = baz.array[i].array[j].array[k] * int(k); >+ } >+ } >+ return sum(baz); >+ } >+ `); >+ checkInt(program, callFunction(program, "testSetValuesAndSum", []), 1575); >+ checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", []), 5565); >+} >+ >+tests.nestedSubscript = function() >+{ >+ let program = doPrep(` >+ int sum(int[7] array) >+ { >+ int result = 0; >+ for (uint i = array.length; i--;) >+ result += array[i]; >+ return result; >+ } >+ int sum(int[6][7] array) >+ { >+ int result = 0; >+ for (uint i = array.length; i--;) >+ result += sum(array[i]); >+ return result; >+ } >+ int sum(int[5][6][7] array) >+ { >+ int result = 0; >+ for (uint i = array.length; i--;) >+ result += sum(array[i]); >+ return result; >+ } >+ void setValues(thread int[][6][7] array) >+ { >+ for (uint i = array.length; i--;) { >+ for (uint j = array[i].length; j--;) { >+ for (uint k = array[i][j].length; k--;) >+ array[i][j][k] = int(i + j + k); >+ } >+ } >+ } >+ test int testSetValuesAndSum() >+ { >+ int[5][6][7] array; >+ setValues(@array); >+ return sum(array); >+ } >+ test int testSetValuesMutateValuesAndSum() >+ { >+ int[5][6][7] array; >+ setValues(@array); >+ for (uint i = array.length; i--;) { >+ for (uint j = array[i].length; j--;) { >+ for (uint k = array[i][j].length; k--;) >+ array[i][j][k] = array[i][j][k] * int(k); >+ } >+ } >+ return sum(array); >+ } >+ `); >+ checkInt(program, callFunction(program, "testSetValuesAndSum", []), 1575); >+ checkInt(program, callFunction(program, "testSetValuesMutateValuesAndSum", []), 5565); >+} >+ >+tests.lotsOfLocalVariables = function() >+{ >+ let src = "test int sum() {\n"; >+ src += " int i = 0;\n"; >+ let target = 0; >+ const numVars = 1024; >+ for (let i = 0; i < numVars; i++) { >+ const value = i * 3; >+ src += ` i = ${i};\n`; >+ src += ` int V${i} = (i + 3) * (i + 3);\n`; >+ target += (i + 3) * (i + 3); >+ } >+ src += " int result = 0;\n"; >+ for (let i = 0; i < numVars; i++) { >+ src += ` result += V${i};\n`; >+ } >+ src += " return result;\n"; >+ src += "}"; >+ let program = doPrep(src); >+ checkInt(program, callFunction(program, "sum", []), target); >+} >+ > tests.operatorBool = function() > { > let program = doPrep(` >@@ -2552,7 +2714,6 @@ tests.uintBitAnd = function() > `); > checkUint(program, callFunction(program, "foo", [makeUint(program, 1), makeUint(program, 7)]), 1); > checkUint(program, callFunction(program, "foo", [makeUint(program, 65535), makeUint(program, 42)]), 42); >- checkUint(program, callFunction(program, "foo", [makeUint(program, -1), makeUint(program, -7)]), 4294967289); > checkUint(program, callFunction(program, "foo", [makeUint(program, 0), makeUint(program, 85732)]), 0); > } > >@@ -2566,7 +2727,6 @@ tests.uintBitOr = function() > `); > checkUint(program, callFunction(program, "foo", [makeUint(program, 1), makeUint(program, 7)]), 7); > checkUint(program, callFunction(program, "foo", [makeUint(program, 65535), makeUint(program, 42)]), 65535); >- checkUint(program, callFunction(program, "foo", [makeUint(program, -1), makeUint(program, -7)]), 4294967295); > checkUint(program, callFunction(program, "foo", [makeUint(program, 0), makeUint(program, 85732)]), 85732); > } > >@@ -2580,7 +2740,6 @@ tests.uintBitXor = function() > `); > checkUint(program, callFunction(program, "foo", [makeUint(program, 1), makeUint(program, 7)]), 6); > checkUint(program, callFunction(program, "foo", [makeUint(program, 65535), makeUint(program, 42)]), 65493); >- checkUint(program, callFunction(program, "foo", [makeUint(program, -1), makeUint(program, -7)]), 6); > checkUint(program, callFunction(program, "foo", [makeUint(program, 0), makeUint(program, 85732)]), 85732); > } > >@@ -2594,7 +2753,6 @@ tests.uintBitNot = function() > `); > checkUint(program, callFunction(program, "foo", [makeUint(program, 1)]), 4294967294); > checkUint(program, callFunction(program, "foo", [makeUint(program, 65535)]), 4294901760); >- checkUint(program, callFunction(program, "foo", [makeUint(program, -1)]), 0); > checkUint(program, callFunction(program, "foo", [makeUint(program, 0)]), 4294967295); > } > >@@ -2608,7 +2766,6 @@ tests.uintLShift = function() > `); > checkUint(program, callFunction(program, "foo", [makeUint(program, 1), makeUint(program, 7)]), 128); > checkUint(program, callFunction(program, "foo", [makeUint(program, 65535), makeUint(program, 2)]), 262140); >- checkUint(program, callFunction(program, "foo", [makeUint(program, -1), makeUint(program, 5)]), 4294967264); > checkUint(program, callFunction(program, "foo", [makeUint(program, 0), makeUint(program, 3)]), 0); > } > >@@ -2622,7 +2779,6 @@ tests.uintRShift = function() > `); > checkUint(program, callFunction(program, "foo", [makeUint(program, 1), makeUint(program, 7)]), 0); > checkUint(program, callFunction(program, "foo", [makeUint(program, 65535), makeUint(program, 2)]), 16383); >- checkUint(program, callFunction(program, "foo", [makeUint(program, -1), makeUint(program, 5)]), 134217727); > checkUint(program, callFunction(program, "foo", [makeUint(program, 0), makeUint(program, 3)]), 0); > } > >@@ -2635,9 +2791,8 @@ tests.ucharBitAnd = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1), makeUchar(program, 7)]), 1); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535), makeUchar(program, 42)]), 42); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1), makeUchar(program, -7)]), 249); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUchar(program, 85732)]), 0); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 255), makeUchar(program, 42)]), 42); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUchar(program, 255)]), 0); > } > > tests.ucharBitOr = function() >@@ -2649,9 +2804,8 @@ tests.ucharBitOr = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1), makeUchar(program, 7)]), 7); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535), makeUchar(program, 42)]), 255); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1), makeUchar(program, -7)]), 255); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUchar(program, 85732)]), 228); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 255), makeUchar(program, 42)]), 255); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUchar(program, 228)]), 228); > } > > tests.ucharBitXor = function() >@@ -2663,9 +2817,8 @@ tests.ucharBitXor = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1), makeUchar(program, 7)]), 6); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535), makeUchar(program, 42)]), 213); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1), makeUchar(program, -7)]), 6); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUchar(program, 85732)]), 228); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 255), makeUchar(program, 42)]), 213); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUchar(program, 255)]), 255); > } > > tests.ucharBitNot = function() >@@ -2677,8 +2830,7 @@ tests.ucharBitNot = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1)]), 254); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535)]), 0); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1)]), 0); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 255)]), 0); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0)]), 255); > } > >@@ -2691,8 +2843,7 @@ tests.ucharLShift = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1), makeUint(program, 7)]), 128); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535), makeUint(program, 2)]), 252); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1), makeUint(program, 5)]), 224); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 255), makeUint(program, 2)]), 252); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUint(program, 3)]), 0); > } > >@@ -2705,8 +2856,8 @@ tests.ucharRShift = function() > } > `); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 1), makeUint(program, 7)]), 0); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, 65535), makeUint(program, 2)]), 255); >- checkUchar(program, callFunction(program, "foo", [makeUchar(program, -1), makeUint(program, 5)]), 255); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 255), makeUint(program, 2)]), 63); >+ checkUchar(program, callFunction(program, "foo", [makeUchar(program, 255), makeUint(program, 5)]), 7); > checkUchar(program, callFunction(program, "foo", [makeUchar(program, 0), makeUint(program, 3)]), 0); > } > >@@ -7293,14 +7444,14 @@ tests.textureSample = function() { > checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height)]), (34 + 35 + 38 + 39) / 4); >- checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >- checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >+ checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); > checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 0), makeInt(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (35 + 36 + 39 + 40) / 4); >- checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >- checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >+ checkFloat(program, callFunction(program, "foo15", [texture2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); > checkFloat(program, callFunction(program, "foo16", [texture2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo16", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1)]), (34 + 35 + 38 + 39) / 4); > checkFloat(program, callFunction(program, "foo16", [texture2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0.5)]), (12 + 13 + 20 + 21) / 4); >@@ -7326,25 +7477,25 @@ tests.textureSample = function() { > checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height)]), (34 + 35 + 38 + 39) / 4); >- checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >- checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >+ checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); > checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0)]), (54 + 55 + 62 + 63) / 4); > checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height)]), (54 + 55 + 62 + 63) / 4); > checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height)]), (76 + 77 + 80 + 81) / 4); >- checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (54 + 55 + 62 + 63) / 4); >- checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((54 + 55 + 62 + 63) / 4) + ((76 + 77 + 80 + 81) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (54 + 55 + 62 + 63) / 4); >+ checkFloat(program, callFunction(program, "foo20", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((54 + 55 + 62 + 63) / 4) + ((76 + 77 + 80 + 81) / 4)) / 2); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 0), makeInt(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (35 + 36 + 39 + 40) / 4); >- checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >- checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >+ checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 0), makeInt(program, 0)]), (54 + 55 + 62 + 63) / 4); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); > checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (77 + 78 + 81 + 82) / 4); >- checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); >- checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((55 + 56 + 63 + 64) / 4) + ((77 + 78 + 81 + 82) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); >+ checkFloat(program, callFunction(program, "foo21", [texture2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((55 + 56 + 63 + 64) / 4) + ((77 + 78 + 81 + 82) / 4)) / 2); > checkFloat(program, callFunction(program, "foo22", [texture2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo22", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 1)]), (34 + 35 + 38 + 39) / 4); > checkFloat(program, callFunction(program, "foo22", [texture2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0.5)]), (12 + 13 + 20 + 21) / 4); >@@ -7372,7 +7523,7 @@ tests.textureSample = function() { > checkFloat(program, callFunction(program, "foo16", [texture2D, makeSampler(program, {minFilter: "linear", lodMinClamp: 1, lodMaxClamp: 1}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 2)]), (34 + 35 + 38 + 39) / 4); > checkFloat(program, callFunction(program, "foo16", [texture2D, makeSampler(program, {minFilter: "linear", lodMinClamp: 1, lodMaxClamp: 1}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0)]), (34 + 35 + 38 + 39) / 4); > checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height)]), (34 + 35 + 38 + 39) / 4); >- checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear", maxAnisotropy: 2}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 4 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, (4/3) / texture2D.ePtr.loadValue().height)]), (34 + 35 + 38 + 39) / 4); >+ checkFloat(program, callFunction(program, "foo14", [texture2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear", maxAnisotropy: 2}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 4 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, (4/3) / texture2D.ePtr.loadValue().height)]), (34 + 35 + 38 + 39) / 4); > let texture1DInt4 = make1DTexture(program, [[[1, 2, 3, 4], [100, 200, 300, 400], [101, 202, 301, 401], [13, 14, 15, 16]], [[17, 18, 19, 20], [21, 22, 23, 24]], [[25, 26, 27, 28]]], "int4"); > checkInt(program, callFunction(program, "foo24", [texture1DInt4, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5)]), 100); > checkInt(program, callFunction(program, "foo25", [texture1DInt4, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5)]), 201); >@@ -7414,14 +7565,14 @@ tests.textureSample = function() { > checkFloat(program, callFunction(program, "foo35", [textureDepth2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo35", [textureDepth2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo35", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height)]), (34 + 35 + 38 + 39) / 4); >- checkFloat(program, callFunction(program, "foo35", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >- checkFloat(program, callFunction(program, "foo35", [textureDepth2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo35", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >+ checkFloat(program, callFunction(program, "foo35", [textureDepth2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); > checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 0), makeInt(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (35 + 36 + 39 + 40) / 4); >- checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >- checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >+ checkFloat(program, callFunction(program, "foo36", [textureDepth2D, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); > checkFloat(program, callFunction(program, "foo37", [textureDepth2D, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo37", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1)]), (34 + 35 + 38 + 39) / 4); > checkFloat(program, callFunction(program, "foo37", [textureDepth2D, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0.5)]), (12 + 13 + 20 + 21) / 4); >@@ -7447,25 +7598,25 @@ tests.textureSample = function() { > checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height)]), (34 + 35 + 38 + 39) / 4); >- checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >- checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (12 + 13 + 20 + 21) / 4); >+ checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((12 + 13 + 20 + 21) / 4) + ((34 + 35 + 38 + 39) / 4)) / 2); > checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0)]), (54 + 55 + 62 + 63) / 4); > checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height)]), (54 + 55 + 62 + 63) / 4); > checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height)]), (76 + 77 + 80 + 81) / 4); >- checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (54 + 55 + 62 + 63) / 4); >- checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((54 + 55 + 62 + 63) / 4) + ((76 + 77 + 80 + 81) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height)]), (54 + 55 + 62 + 63) / 4); >+ checkFloat(program, callFunction(program, "foo41", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height)]), (((54 + 55 + 62 + 63) / 4) + ((76 + 77 + 80 + 81) / 4)) / 2); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 0), makeInt(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (35 + 36 + 39 + 40) / 4); >- checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >- checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (13 + 14 + 21 + 22) / 4); >+ checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((13 + 14 + 21 + 22) / 4) + ((35 + 36 + 39 + 40) / 4)) / 2); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 0), makeInt(program, 0)]), (54 + 55 + 62 + 63) / 4); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 0), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 1 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 1 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); > checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, 2 / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, 2 / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (77 + 78 + 81 + 82) / 4); >- checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); >- checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((55 + 56 + 63 + 64) / 4) + ((77 + 78 + 81 + 82) / 4)) / 2); >+ checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.25) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (55 + 56 + 63 + 64) / 4); >+ checkFloat(program, callFunction(program, "foo42", [textureDepth2DArray, makeSampler(program, {minFilter: "linear", mipmapFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 1), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().width), makeFloat(program, 0), makeFloat(program, 0), makeCastedFloat(program, Math.pow(2, 0.5) / texture2D.ePtr.loadValue().height), makeInt(program, 1), makeInt(program, 0)]), (((55 + 56 + 63 + 64) / 4) + ((77 + 78 + 81 + 82) / 4)) / 2); > checkFloat(program, callFunction(program, "foo43", [textureDepth2DArray, makeSampler(program, {magFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0)]), (12 + 13 + 20 + 21) / 4); > checkFloat(program, callFunction(program, "foo43", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 1)]), (34 + 35 + 38 + 39) / 4); > checkFloat(program, callFunction(program, "foo43", [textureDepth2DArray, makeSampler(program, {minFilter: "linear"}), makeFloat(program, 0.5), makeFloat(program, 0.5), makeFloat(program, 0), makeFloat(program, 0.5)]), (12 + 13 + 20 + 21) / 4); >@@ -7946,13 +8097,6 @@ function* doTest(testFilter) > throw new Error("Test setup is incomplete."); > let before = preciseTime(); > >- print("Compiling standard library..."); >- const compileBefore = preciseTime(); >- yield; >- prepare(); >- const compileAfter = preciseTime(); >- print(` OK, took ${Math.round((compileAfter - compileBefore) * 1000)} ms`); >- > let names = []; > for (let s in tests) > names.push(s); >diff --git a/Tools/WebGPUShadingLanguageRI/Type.js b/Tools/WebGPUShadingLanguageRI/Type.js >index 2db158d099b326a93e7335e4e696138c5edbefdb..9a5e56e501d8e81e0a85a5f5c2960eb462eccbb3 100644 >--- a/Tools/WebGPUShadingLanguageRI/Type.js >+++ b/Tools/WebGPUShadingLanguageRI/Type.js >@@ -36,6 +36,11 @@ class Type extends Node { > get isEnum() { return false; } > get isPrimitive() { return false; } > >+ get arrayRefType() >+ { >+ return new ArrayRefType(this.origin, "thread", this); >+ } >+ > // Have to call these on the unifyNode. > argumentForAndOverload(origin, value) > {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 187735
:
345174
|
345185
|
345208
|
345219
|
345220
|
348257
|
348407
|
348703
|
348852
|
348869
|
348884
|
349505
|
349524
|
349612
|
349696
|
349733
|
349735
|
349817
|
349826
|
349839
|
349939
|
349957
|
350095
|
350174