[WHLSL] Vertex shader and fragment shader need to be able to come from two different...
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Aug 2019 02:50:21 +0000 (02:50 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Aug 2019 02:50:21 +0000 (02:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195446

Reviewed by Saam Barati.

Source/WebCore:

When an author configures WebGPU to render things, the author provides a vertex shader and a fragment
shader, and they both execute within the same draw call. It's common for authors coming from WebGL to
put the two shaders in distinct files. Until this patch, WHLSL was unable to process two shaders from
different sources which were meant to be hooked together.

The first thing this patch does is add the notion of a "shader module" to the WHLSL compiler. This
represents the source code containing one or more shaders. When the author wants to actually compile
their source, they supply one or more shader modules to the compiler. The compiler then looks in the
first module for the vertex shader and the second module for the fragment shader. The two modules are
passed by reference, so they may refer to the same underlying object, which is supported.

Shader modules have this interesting behavior where, within a shader module, funtion / type names may
refer to each other, but may not refer to any other name within any other shader module. They behave
as if all the names inside the module are not exported. So, it would seem that the most natural way to
support this would be to run the WHLSL compiler and the MSL compiler twice independently, once for each
module. However, this means that our compile times would double, which would be unfortunate. Instead,
a more performant option would be to make the WHLSL compiler smart enough to handle multiple shader
modules at once, and to produce a single merged output program that contains everything. It does this
by parsing all the shader modules into a single Program object, but remembering which items in the
Program came from which places.

This is implemented by teaching the WHLSL compiler about "namespaces." There are three namespaces: one
for each shader module, and an additional one for the standard library. Every global object (e.g.
named types and functions) knows which namespace it lives inside. The NameResolver has been educated
to understand namespaces, so when you ask it for a name in a particular namespace, it will look up
all the names both in that namespace and in the standard library's namespace, and it will union the
results together.

Function overload resolution doesn't actually go through the name resolver; instead, it's handled by
sorting all functions into buckets such that any CallExpression only has to look in a single bucket
to find all its potential overloads. These buckets can't be educated about namespaces (consider a
function which has overloads in all 3 namespaces that is called from both shader modules - all the
overloads must end up in the same bucket). Therefore, this logic is moved into
resolveFunctionOverload(), which will now disregard candidate functions if they are in an inaccessible
namespace.

Tests: webgpu/whlsl/separate-shader-modules/separate-shader-modules-10.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-11.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-12.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-13.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-14.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-15.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-16.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-17.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-18.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-19.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-2.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-20.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-21.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-22.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-23.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-24.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-25.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-26.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-27.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-3.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-4.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-5.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-6.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-7.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-8.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules-9.html
       webgpu/whlsl/separate-shader-modules/separate-shader-modules.html

* Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h:
(WebCore::WHLSL::AST::FunctionDeclaration::nameSpace const):
(WebCore::WHLSL::AST::FunctionDeclaration::setNameSpace):
* Modules/webgpu/WHLSL/AST/WHLSLNameSpace.h: Copied from Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.h.
* Modules/webgpu/WHLSL/AST/WHLSLNamedType.h:
(WebCore::WHLSL::AST::NamedType::nameSpace const):
(WebCore::WHLSL::AST::NamedType::setNameSpace):
* Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
(WebCore::WHLSL::Metal::emitMetalFunctions):
* Modules/webgpu/WHLSL/WHLSLCheckDuplicateFunctions.cpp:
(WebCore::WHLSL::DuplicateFunctionKey::operator== const):
* Modules/webgpu/WHLSL/WHLSLChecker.cpp:
(WebCore::WHLSL::FunctionKey::operator== const):
(WebCore::WHLSL::checkOperatorOverload):
(WebCore::WHLSL::Checker::checkShaderType):
(WebCore::WHLSL::Checker::visit):
(WebCore::WHLSL::Checker::resolveFunction):
* Modules/webgpu/WHLSL/WHLSLLexer.cpp:
* Modules/webgpu/WHLSL/WHLSLNameContext.cpp:
(WebCore::WHLSL::NameContext::add):
(WebCore::WHLSL::NameContext::getTypes):
(WebCore::WHLSL::NameContext::getFunctions):
(WebCore::WHLSL::NameContext::searchTypes const):
(WebCore::WHLSL::NameContext::searchFunctions const):
(WebCore::WHLSL::NameContext::globalExists const):
(WebCore::WHLSL::NameContext::localExists const):
(WebCore::WHLSL::NameContext::exists): Deleted.
* Modules/webgpu/WHLSL/WHLSLNameContext.h:
(WebCore::WHLSL::NameContext::setCurrentNameSpace):
* Modules/webgpu/WHLSL/WHLSLNameResolver.cpp:
(WebCore::WHLSL::NameResolver::NameResolver):
(WebCore::WHLSL::NameResolver::visit):
(WebCore::WHLSL::resolveNamesInTypes):
(WebCore::WHLSL::resolveTypeNamesInFunctions):
* Modules/webgpu/WHLSL/WHLSLNameResolver.h:
(WebCore::WHLSL::NameResolver::setCurrentNameSpace):
* Modules/webgpu/WHLSL/WHLSLParser.cpp:
(WebCore::WHLSL::Parser::parse):
(WebCore::WHLSL::Parser::fail):
(WebCore::WHLSL::Parser::consumeIntegralLiteral):
(WebCore::WHLSL::Parser::consumeNonNegativeIntegralLiteral):
(WebCore::WHLSL::Parser::parseConstantExpression):
(WebCore::WHLSL::Parser::parseTypeSuffixAbbreviated):
(WebCore::WHLSL::Parser::parseTypeSuffixNonAbbreviated):
(WebCore::WHLSL::Parser::parseBuiltInSemantic):
(WebCore::WHLSL::Parser::parseResourceSemantic):
(WebCore::WHLSL::Parser::parseStageInOutSemantic):
(WebCore::WHLSL::Parser::parseEnumerationDefinition):
(WebCore::WHLSL::Parser::parseEnumerationMember):
(WebCore::WHLSL::Parser::parseNumThreadsFunctionAttribute):
(WebCore::WHLSL::Parser::parseVertexOrFragmentFunctionDeclaration):
(WebCore::WHLSL::Parser::parseRegularFunctionDeclaration):
(WebCore::WHLSL::Parser::parseSwitchCase):
(WebCore::WHLSL::Parser::parseForLoop):
(WebCore::WHLSL::Parser::parseVariableDeclarations):
(WebCore::WHLSL::Parser::completeAssignment):
(WebCore::WHLSL::Parser::parsePossibleTernaryConditional):
(WebCore::WHLSL::Parser::parseTerm):
* Modules/webgpu/WHLSL/WHLSLPrepare.cpp:
(WebCore::WHLSL::ShaderModule::ShaderModule):
(WebCore::WHLSL::createShaderModule):
(WebCore::WHLSL::ShaderModuleDeleter::operator()):
(WebCore::WHLSL::prepareShared):
(WebCore::WHLSL::prepare):
* Modules/webgpu/WHLSL/WHLSLPrepare.h:
* Modules/webgpu/WHLSL/WHLSLProgram.h:
(WebCore::WHLSL::Program::append):
* Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp:
(WebCore::WHLSL::resolveFunctionOverloadImpl):
(WebCore::WHLSL::resolveFunctionOverload):
* Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.h:
* Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp:
(WebCore::WHLSL::matchSemantics):
(WebCore::WHLSL::findEntryPoint): Deleted.
* Modules/webgpu/WHLSL/WHLSLSemanticMatcher.h:
* Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.cpp:
(WebCore::WHLSL::includeStandardLibrary):
* Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.h:
* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/gpu/GPUShaderModule.h:
(WebCore::GPUShaderModule::platformShaderModule const):
(WebCore::GPUShaderModule::whlslModule const):
(WebCore::GPUShaderModule::whlslSource const): Deleted.
* platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
(WebCore::trySetFunctions):
(WebCore::convertComputePipelineDescriptor):
* platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
(WebCore::trySetMetalFunctions):
(WebCore::trySetFunctions):
(WebCore::convertRenderPipelineDescriptor):
* platform/graphics/gpu/cocoa/GPUShaderModuleMetal.mm:
(WebCore::GPUShaderModule::tryCreate):
(WebCore::GPUShaderModule::GPUShaderModule):

LayoutTests:

* webgpu/whlsl/separate-shader-modules/separate-shader-modules-10-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-10.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-11-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-11.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-12-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-12.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-13-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-13.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-14-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-14.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-15-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-15.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-16-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-16.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-17-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-17.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-18-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-18.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-19-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-19.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-2-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-2.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-20-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-20.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-21-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-21.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-22-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-22.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-23-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-23.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-24-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-24.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-25-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-25.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-26-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-26.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-27-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-27.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-3-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-3.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-4-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-4.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-5-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-5.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-6-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-6.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-7-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-7.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-8-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-8.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-9-expected.txt: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-9.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules-expected.html: Added.
* webgpu/whlsl/separate-shader-modules/separate-shader-modules.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@248993 268f45cc-cd09-0410-ab3c-d52691b4dbfc

85 files changed:
LayoutTests/ChangeLog
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-10-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-10.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-11-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-11.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-12-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-12.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-13-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-13.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-14-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-14.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-15-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-15.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-16-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-16.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-17-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-17.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-18-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-18.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-19-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-19.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-2-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-2.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-20-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-20.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-21-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-21.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-22-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-22.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-23-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-23.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-24-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-24.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-25-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-25.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-26-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-26.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-27-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-27.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-3-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-3.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-4-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-4.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-5-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-5.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-6-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-6.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-7-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-7.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-8-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-8.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-9-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-9.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-expected.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLNameSpace.h [new file with mode: 0644]
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLNamedType.h
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLCheckDuplicateFunctions.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLCodeLocation.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLLexer.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLLexer.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameContext.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameContext.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLProgram.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLSemanticMatcher.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/gpu/GPUShaderModule.h
Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPUShaderModuleMetal.mm

index 7a424b7..b8ad462 100644 (file)
@@ -1,3 +1,65 @@
+2019-08-21  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [WHLSL] Vertex shader and fragment shader need to be able to come from two different programs
+        https://bugs.webkit.org/show_bug.cgi?id=195446
+
+        Reviewed by Saam Barati.
+
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-10-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-10.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-11-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-11.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-12-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-12.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-13-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-13.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-14-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-14.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-15-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-15.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-16-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-16.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-17-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-17.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-18-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-18.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-19-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-19.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-2-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-2.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-20-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-20.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-21-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-21.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-22-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-22.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-23-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-23.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-24-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-24.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-25-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-25.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-26-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-26.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-27-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-27.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-3-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-3.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-4-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-4.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-5-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-5.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-6-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-6.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-7-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-7.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-8-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-8.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-9-expected.txt: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-9.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules-expected.html: Added.
+        * webgpu/whlsl/separate-shader-modules/separate-shader-modules.html: Added.
+
 2019-08-21  Ryosuke Niwa  <rniwa@webkit.org>
 
         SVG element should become focusable when focus and key event listeners are added
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-10-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-10-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-10.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-10.html
new file mode 100644 (file)
index 0000000..7b94956
--- /dev/null
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+typedef Foo = int;
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo x;
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-11-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-11-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-11.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-11.html
new file mode 100644 (file)
index 0000000..d1da159
--- /dev/null
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+struct Foo {
+    int x;
+}
+
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo f;
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-12-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-12-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-12.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-12.html
new file mode 100644 (file)
index 0000000..53a2f48
--- /dev/null
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+enum Foo {
+    v
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo f = Foo.v;
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-13-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-13-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-13.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-13.html
new file mode 100644 (file)
index 0000000..74b2d91
--- /dev/null
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+typedef Foo = int;
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+typedef Foo = int;
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-14-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-14-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-14.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-14.html
new file mode 100644 (file)
index 0000000..db5e1ab
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+struct Foo {
+    int x;
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+struct Foo {
+    int x;
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-15-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-15-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-15.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-15.html
new file mode 100644 (file)
index 0000000..957c964
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+enum Foo {
+    x
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+enum Foo {
+    x
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-16-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-16-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-16.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-16.html
new file mode 100644 (file)
index 0000000..29a4f4a
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+float4 helper() {
+    return float4(0, 0, 0, 0);
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+float4 helper() {
+    return float4(1, 1, 1, 1);
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-17-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-17-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-17.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-17.html
new file mode 100644 (file)
index 0000000..3c9bf47
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+typedef Foo = float;
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+typedef Foo = float;
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo x = 1;
+    return float4(x, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-18-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-18-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-18.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-18.html
new file mode 100644 (file)
index 0000000..8137e65
--- /dev/null
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+struct Foo {
+    float x;
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+struct Foo {
+    float x;
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo f;
+    f.x = 1;
+    return float4(f.x, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-19-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-19-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-19.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-19.html
new file mode 100644 (file)
index 0000000..d2332a5
--- /dev/null
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+enum Foo {
+    x
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+enum Foo {
+    x = 0,
+    y = 1
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    int y = int(Foo.y);
+    return float4(float(y), 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-2-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-2-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-2.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-2.html
new file mode 100644 (file)
index 0000000..e5d26b3
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+float4 helper() {
+    return float4(1, 1, 1, 1);
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return helper();
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-20-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-20-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-20.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-20.html
new file mode 100644 (file)
index 0000000..d9c8ab6
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+float4 helper() {
+    return float4(1, 1, 1, 1);
+}
+float4 helper() {
+    return float4(1, 1, 1, 1);
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return helper();
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-21-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-21-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-21.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-21.html
new file mode 100644 (file)
index 0000000..1032fe8
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+typedef Foo = int;
+typedef Foo = int;
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-22-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-22-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-22.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-22.html
new file mode 100644 (file)
index 0000000..af4fc9c
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+struct Foo {
+    int x;
+}
+struct Foo {
+    int x;
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-23-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-23-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-23.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-23.html
new file mode 100644 (file)
index 0000000..3ddc1f0
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+enum Foo {
+    x
+}
+enum Foo {
+    x
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-24-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-24-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-24.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-24.html
new file mode 100644 (file)
index 0000000..14a2d07
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+float saturate(float x, float y) {
+    return 1;
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(saturate(3, 4), saturate(2), 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-25-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-25-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-25.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-25.html
new file mode 100644 (file)
index 0000000..934234d
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader2(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-26-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-26-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-26.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-26.html
new file mode 100644 (file)
index 0000000..4f80a75
--- /dev/null
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-27-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-27-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-27.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-27.html
new file mode 100644 (file)
index 0000000..391c154
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}
+`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+fragment float4 fragmentShader(float4 position : SV_Position, bool isFontFace : SV_IsFrontFace) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-3-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-3-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-3.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-3.html
new file mode 100644 (file)
index 0000000..fe4f244
--- /dev/null
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+float4 helper() {
+    return float4(1, 1, 1, 1);
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return helper();
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-4-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-4-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-4.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-4.html
new file mode 100644 (file)
index 0000000..54ec8bb
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+typedef Foo = int;
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo x;
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-5-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-5-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-5.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-5.html
new file mode 100644 (file)
index 0000000..fdc18fe
--- /dev/null
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+struct Foo {
+    int x;
+}
+
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo x;
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-6-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-6-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-6.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-6.html
new file mode 100644 (file)
index 0000000..e05e468
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+enum Foo {
+    v
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    Foo x = Foo.v;
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-7-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-7-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-7.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-7.html
new file mode 100644 (file)
index 0000000..6cd1b4f
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+float4 helper() {
+    return float4(0, 0, 0, 0);
+}
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+float4 helper() {
+    return float4(1, 1, 1, 1);
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return helper();
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-8-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-8-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-8.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-8.html
new file mode 100644 (file)
index 0000000..012a4fd
--- /dev/null
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+float saturate(float x) {
+    return 0;
+}
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-9-expected.txt b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-9-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-9.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-9.html
new file mode 100644 (file)
index 0000000..da6c095
--- /dev/null
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+typedef bool2 = int;
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    device.pushErrorScope("validation");
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+    return device.popErrorScope();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function(x) {
+        if (x)
+            testPassed("");
+        else
+            testFailed("");
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed();
+    finishJSTest();
+});
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-expected.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules-expected.html
new file mode 100644 (file)
index 0000000..6dd184d
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const canvas = document.getElementById("canvas");
+drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules.html b/LayoutTests/webgpu/whlsl/separate-shader-modules/separate-shader-modules.html
new file mode 100644 (file)
index 0000000..d420a82
--- /dev/null
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/webgpu-functions.js"></script>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const vertexShaderSource = `
+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position {
+    return position;
+}`;
+
+const fragmentShaderSource = `
+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 {
+    return float4(1, 1, 1, 1);
+}
+`;
+
+const canvas = document.getElementById("canvas");
+
+async function start(device) {
+    const vertexShaderModule = device.createShaderModule({code: vertexShaderSource, isWHLSL: true});
+    const fragmentShaderModule = device.createShaderModule({code: fragmentShaderSource, isWHLSL: true});
+    const vertexStage = {module: vertexShaderModule, entryPoint: "vertexShader"};
+    const fragmentStage = {module: fragmentShaderModule, entryPoint: "fragmentShader"};
+    const primitiveTopology = "triangle-strip";
+    const rasterizationState = {frontFace: "cw", cullMode: "none"};
+    const alphaBlend = {};
+    const colorBlend = {};
+    const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+    const depthStencilState = null;
+    
+    const attribute = {shaderLocation: 0, format: "float4"};
+    const input = {stride: 16, attributeSet: [attribute]};
+    const inputs = [input];
+    const vertexInput = {vertexBuffers: inputs};
+
+    const pipelineLayoutDescriptor = {bindGroupLayouts: []};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+    const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+    const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+    const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
+    const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync();
+    const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer);
+    vertexBufferFloat32Array[0] = -0.5;
+    vertexBufferFloat32Array[1] = -0.5;
+    vertexBufferFloat32Array[2] = 1.0;
+    vertexBufferFloat32Array[3] = 1;
+    vertexBufferFloat32Array[4] = -0.5;
+    vertexBufferFloat32Array[5] = 0.5;
+    vertexBufferFloat32Array[6] = 1.0;
+    vertexBufferFloat32Array[7] = 1;
+    vertexBufferFloat32Array[8] = 0.5;
+    vertexBufferFloat32Array[9] = -0.5;
+    vertexBufferFloat32Array[10] = 1.0;
+    vertexBufferFloat32Array[11] = 1;
+    vertexBufferFloat32Array[12] = 0.5;
+    vertexBufferFloat32Array[13] = 0.5;
+    vertexBufferFloat32Array[14] = 1.0;
+    vertexBufferFloat32Array[15] = 1;
+    vertexBuffer.unmap();
+
+    const context = canvas.getContext("gpu");
+    const swapChainDescriptor = {device, format: "bgra8unorm"};
+    const swapChain = context.configureSwapChain(swapChainDescriptor);
+    const outputTexture = swapChain.getCurrentTexture();
+    const outputTextureView = outputTexture.createDefaultView();
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const red = {r: 0, g: 0, b: 1, a: 1};
+    const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+    const depthStencilAttachment = null;
+    const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+    const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+    renderPassEncoder.setPipeline(renderPipeline);
+    renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    renderPassEncoder.draw(4, 1, 0, 0);
+    renderPassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+}, function() {
+    drawWhiteSquareOnBlueBackgroundInSoftware(canvas);
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</body>
+</html>
index 2641cc4..d75a845 100644 (file)
@@ -1,3 +1,168 @@
+2019-08-21  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [WHLSL] Vertex shader and fragment shader need to be able to come from two different programs
+        https://bugs.webkit.org/show_bug.cgi?id=195446
+
+        Reviewed by Saam Barati.
+
+        When an author configures WebGPU to render things, the author provides a vertex shader and a fragment
+        shader, and they both execute within the same draw call. It's common for authors coming from WebGL to
+        put the two shaders in distinct files. Until this patch, WHLSL was unable to process two shaders from
+        different sources which were meant to be hooked together.
+
+        The first thing this patch does is add the notion of a "shader module" to the WHLSL compiler. This
+        represents the source code containing one or more shaders. When the author wants to actually compile
+        their source, they supply one or more shader modules to the compiler. The compiler then looks in the
+        first module for the vertex shader and the second module for the fragment shader. The two modules are
+        passed by reference, so they may refer to the same underlying object, which is supported.
+
+        Shader modules have this interesting behavior where, within a shader module, funtion / type names may
+        refer to each other, but may not refer to any other name within any other shader module. They behave
+        as if all the names inside the module are not exported. So, it would seem that the most natural way to
+        support this would be to run the WHLSL compiler and the MSL compiler twice independently, once for each
+        module. However, this means that our compile times would double, which would be unfortunate. Instead,
+        a more performant option would be to make the WHLSL compiler smart enough to handle multiple shader
+        modules at once, and to produce a single merged output program that contains everything. It does this
+        by parsing all the shader modules into a single Program object, but remembering which items in the 
+        Program came from which places.
+
+        This is implemented by teaching the WHLSL compiler about "namespaces." There are three namespaces: one
+        for each shader module, and an additional one for the standard library. Every global object (e.g.
+        named types and functions) knows which namespace it lives inside. The NameResolver has been educated
+        to understand namespaces, so when you ask it for a name in a particular namespace, it will look up
+        all the names both in that namespace and in the standard library's namespace, and it will union the
+        results together.
+
+        Function overload resolution doesn't actually go through the name resolver; instead, it's handled by
+        sorting all functions into buckets such that any CallExpression only has to look in a single bucket
+        to find all its potential overloads. These buckets can't be educated about namespaces (consider a
+        function which has overloads in all 3 namespaces that is called from both shader modules - all the
+        overloads must end up in the same bucket). Therefore, this logic is moved into
+        resolveFunctionOverload(), which will now disregard candidate functions if they are in an inaccessible 
+        namespace.
+
+        Tests: webgpu/whlsl/separate-shader-modules/separate-shader-modules-10.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-11.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-12.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-13.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-14.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-15.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-16.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-17.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-18.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-19.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-2.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-20.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-21.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-22.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-23.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-24.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-25.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-26.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-27.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-3.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-4.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-5.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-6.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-7.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-8.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules-9.html
+               webgpu/whlsl/separate-shader-modules/separate-shader-modules.html
+
+        * Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h:
+        (WebCore::WHLSL::AST::FunctionDeclaration::nameSpace const):
+        (WebCore::WHLSL::AST::FunctionDeclaration::setNameSpace):
+        * Modules/webgpu/WHLSL/AST/WHLSLNameSpace.h: Copied from Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.h.
+        * Modules/webgpu/WHLSL/AST/WHLSLNamedType.h:
+        (WebCore::WHLSL::AST::NamedType::nameSpace const):
+        (WebCore::WHLSL::AST::NamedType::setNameSpace):
+        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::emitMetalFunctions):
+        * Modules/webgpu/WHLSL/WHLSLCheckDuplicateFunctions.cpp:
+        (WebCore::WHLSL::DuplicateFunctionKey::operator== const):
+        * Modules/webgpu/WHLSL/WHLSLChecker.cpp:
+        (WebCore::WHLSL::FunctionKey::operator== const):
+        (WebCore::WHLSL::checkOperatorOverload):
+        (WebCore::WHLSL::Checker::checkShaderType):
+        (WebCore::WHLSL::Checker::visit):
+        (WebCore::WHLSL::Checker::resolveFunction):
+        * Modules/webgpu/WHLSL/WHLSLLexer.cpp:
+        * Modules/webgpu/WHLSL/WHLSLNameContext.cpp:
+        (WebCore::WHLSL::NameContext::add):
+        (WebCore::WHLSL::NameContext::getTypes):
+        (WebCore::WHLSL::NameContext::getFunctions):
+        (WebCore::WHLSL::NameContext::searchTypes const):
+        (WebCore::WHLSL::NameContext::searchFunctions const):
+        (WebCore::WHLSL::NameContext::globalExists const):
+        (WebCore::WHLSL::NameContext::localExists const):
+        (WebCore::WHLSL::NameContext::exists): Deleted.
+        * Modules/webgpu/WHLSL/WHLSLNameContext.h:
+        (WebCore::WHLSL::NameContext::setCurrentNameSpace):
+        * Modules/webgpu/WHLSL/WHLSLNameResolver.cpp:
+        (WebCore::WHLSL::NameResolver::NameResolver):
+        (WebCore::WHLSL::NameResolver::visit):
+        (WebCore::WHLSL::resolveNamesInTypes):
+        (WebCore::WHLSL::resolveTypeNamesInFunctions):
+        * Modules/webgpu/WHLSL/WHLSLNameResolver.h:
+        (WebCore::WHLSL::NameResolver::setCurrentNameSpace):
+        * Modules/webgpu/WHLSL/WHLSLParser.cpp:
+        (WebCore::WHLSL::Parser::parse):
+        (WebCore::WHLSL::Parser::fail):
+        (WebCore::WHLSL::Parser::consumeIntegralLiteral):
+        (WebCore::WHLSL::Parser::consumeNonNegativeIntegralLiteral):
+        (WebCore::WHLSL::Parser::parseConstantExpression):
+        (WebCore::WHLSL::Parser::parseTypeSuffixAbbreviated):
+        (WebCore::WHLSL::Parser::parseTypeSuffixNonAbbreviated):
+        (WebCore::WHLSL::Parser::parseBuiltInSemantic):
+        (WebCore::WHLSL::Parser::parseResourceSemantic):
+        (WebCore::WHLSL::Parser::parseStageInOutSemantic):
+        (WebCore::WHLSL::Parser::parseEnumerationDefinition):
+        (WebCore::WHLSL::Parser::parseEnumerationMember):
+        (WebCore::WHLSL::Parser::parseNumThreadsFunctionAttribute):
+        (WebCore::WHLSL::Parser::parseVertexOrFragmentFunctionDeclaration):
+        (WebCore::WHLSL::Parser::parseRegularFunctionDeclaration):
+        (WebCore::WHLSL::Parser::parseSwitchCase):
+        (WebCore::WHLSL::Parser::parseForLoop):
+        (WebCore::WHLSL::Parser::parseVariableDeclarations):
+        (WebCore::WHLSL::Parser::completeAssignment):
+        (WebCore::WHLSL::Parser::parsePossibleTernaryConditional):
+        (WebCore::WHLSL::Parser::parseTerm):
+        * Modules/webgpu/WHLSL/WHLSLPrepare.cpp:
+        (WebCore::WHLSL::ShaderModule::ShaderModule):
+        (WebCore::WHLSL::createShaderModule):
+        (WebCore::WHLSL::ShaderModuleDeleter::operator()):
+        (WebCore::WHLSL::prepareShared):
+        (WebCore::WHLSL::prepare):
+        * Modules/webgpu/WHLSL/WHLSLPrepare.h:
+        * Modules/webgpu/WHLSL/WHLSLProgram.h:
+        (WebCore::WHLSL::Program::append):
+        * Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp:
+        (WebCore::WHLSL::resolveFunctionOverloadImpl):
+        (WebCore::WHLSL::resolveFunctionOverload):
+        * Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.h:
+        * Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp:
+        (WebCore::WHLSL::matchSemantics):
+        (WebCore::WHLSL::findEntryPoint): Deleted.
+        * Modules/webgpu/WHLSL/WHLSLSemanticMatcher.h:
+        * Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.cpp:
+        (WebCore::WHLSL::includeStandardLibrary):
+        * Modules/webgpu/WHLSL/WHLSLStandardLibraryUtilities.h:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/gpu/GPUShaderModule.h:
+        (WebCore::GPUShaderModule::platformShaderModule const):
+        (WebCore::GPUShaderModule::whlslModule const):
+        (WebCore::GPUShaderModule::whlslSource const): Deleted.
+        * platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
+        (WebCore::trySetFunctions):
+        (WebCore::convertComputePipelineDescriptor):
+        * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
+        (WebCore::trySetMetalFunctions):
+        (WebCore::trySetFunctions):
+        (WebCore::convertRenderPipelineDescriptor):
+        * platform/graphics/gpu/cocoa/GPUShaderModuleMetal.mm:
+        (WebCore::GPUShaderModule::tryCreate):
+        (WebCore::GPUShaderModule::GPUShaderModule):
+
 2019-08-21  Ryosuke Niwa  <rniwa@webkit.org>
 
         SVG element should become focusable when focus and key event listeners are added
index 6805d66..b7256d5 100644 (file)
@@ -30,6 +30,7 @@
 #include "WHLSLCodeLocation.h"
 #include "WHLSLEntryPointType.h"
 #include "WHLSLFunctionAttribute.h"
+#include "WHLSLNameSpace.h"
 #include "WHLSLParsingMode.h"
 #include "WHLSLSemantic.h"
 #include "WHLSLUnnamedType.h"
@@ -83,6 +84,9 @@ public:
 
     ParsingMode parsingMode() const { return m_parsingMode; }
 
+    NameSpace nameSpace() const { return m_nameSpace; }
+    void setNameSpace(NameSpace nameSpace) { m_nameSpace = nameSpace; }
+
 private:
     CodeLocation m_codeLocation;
     AttributeBlock m_attributeBlock;
@@ -93,6 +97,7 @@ private:
     String m_name;
     VariableDeclarations m_parameters;
     std::unique_ptr<Semantic> m_semantic;
+    NameSpace m_nameSpace { NameSpace::StandardLibrary };
 };
 
 } // namespace AST
diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLNameSpace.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLNameSpace.h
new file mode 100644 (file)
index 0000000..5bf9e3f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#pragma once
+
+#if ENABLE(WEBGPU)
+
+namespace WebCore {
+
+namespace WHLSL {
+
+namespace AST {
+
+// Different shader modules operate in different namespaces.
+// This means it's possible to have two functions with the same signatures, as long as they are in different modules.
+enum class NameSpace : uint8_t {
+    StandardLibrary = 0,
+    NameSpace1 = 1,
+    NameSpace2 = 2
+};
+
+constexpr unsigned nameSpaceCount = 3;
+
+}
+
+}
+
+}
+
+#endif // ENABLE(WEBGPU)
index 45b8010..599c46c 100644 (file)
@@ -28,6 +28,7 @@
 #if ENABLE(WEBGPU)
 
 #include "WHLSLCodeLocation.h"
+#include "WHLSLNameSpace.h"
 #include "WHLSLType.h"
 #include <wtf/FastMalloc.h>
 #include <wtf/text/WTFString.h>
@@ -60,12 +61,15 @@ public:
 
     String& name() { return m_name; }
 
+    NameSpace nameSpace() const { return m_nameSpace; }
+    void setNameSpace(NameSpace nameSpace) { m_nameSpace = nameSpace; }
 
 private:
     friend class Type;
     Type& unifyNodeImpl() { return *this; }
     CodeLocation m_codeLocation;
     String m_name;
+    NameSpace m_nameSpace { NameSpace::StandardLibrary };
 };
 
 } // namespace AST
index 7087d8b..94b934f 100644 (file)
@@ -902,11 +902,12 @@ private:
 RenderMetalFunctionEntryPoints emitMetalFunctions(StringBuilder& stringBuilder, Program& program, TypeNamer& typeNamer, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
 {
     auto& vertexShaderEntryPoint = *matchedSemantics.vertexShader;
-    auto& fragmentShaderEntryPoint = *matchedSemantics.fragmentShader;
+    auto* fragmentShaderEntryPoint = matchedSemantics.fragmentShader;
 
     ReachableFunctionsGatherer reachableFunctionsGatherer;
     reachableFunctionsGatherer.Visitor::visit(vertexShaderEntryPoint);
-    reachableFunctionsGatherer.Visitor::visit(fragmentShaderEntryPoint);
+    if (fragmentShaderEntryPoint)
+        reachableFunctionsGatherer.Visitor::visit(*fragmentShaderEntryPoint);
     auto reachableFunctions = reachableFunctionsGatherer.takeReachableFunctions();
 
     auto functionMapping = generateMetalFunctionsMapping(program);
@@ -919,7 +920,7 @@ RenderMetalFunctionEntryPoints emitMetalFunctions(StringBuilder& stringBuilder,
             functionDefinitionWriter.visit(functionDefinition);
     }
 
-    return { functionMapping.get(&vertexShaderEntryPoint), functionMapping.get(&fragmentShaderEntryPoint) };
+    return { functionMapping.get(&vertexShaderEntryPoint), fragmentShaderEntryPoint ? functionMapping.get(fragmentShaderEntryPoint) : MangledFunctionName { 0 } };
 }
 
 ComputeMetalFunctionEntryPoints emitMetalFunctions(StringBuilder& stringBuilder, Program& program, TypeNamer& typeNamer, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
index f8a7a3e..9fef3a1 100644 (file)
@@ -75,6 +75,11 @@ public:
         if (m_function->name() != other.m_function->name())
             return false;
 
+        if (m_function->nameSpace() != AST::NameSpace::StandardLibrary
+            && other.m_function->nameSpace() != AST::NameSpace::StandardLibrary
+            && m_function->nameSpace() != other.m_function->nameSpace())
+            return false;
+
         ASSERT(m_function->isCast() == other.m_function->isCast());
 
         for (size_t i = 0; i < m_function->parameters().size(); ++i) {
index bb9c601..5aea3c5 100644 (file)
@@ -161,7 +161,7 @@ public:
                 return false;
         }
 
-        if (!!m_castReturnType != !!other.m_castReturnType)
+        if (static_cast<bool>(m_castReturnType) != static_cast<bool>(other.m_castReturnType))
             return false;
 
         if (!m_castReturnType)
@@ -427,7 +427,7 @@ static bool checkSemantics(Vector<EntryPointItem>& inputItems, Vector<EntryPoint
     return true;
 }
 
-static bool checkOperatorOverload(const AST::FunctionDefinition& functionDefinition, NameContext& nameContext)
+static bool checkOperatorOverload(const AST::FunctionDefinition& functionDefinition, NameContext& nameContext, AST::NameSpace currentNameSpace)
 {
     enum class CheckKind {
         Index,
@@ -483,16 +483,14 @@ static bool checkOperatorOverload(const AST::FunctionDefinition& functionDefinit
             return false;
         auto& valueType = *functionDefinition.parameters()[numExpectedParameters - 1]->type();
         auto getterName = functionDefinition.name().substring(0, functionDefinition.name().length() - 1);
-        auto* getterFuncs = nameContext.getFunctions(getterName);
-        if (!getterFuncs)
-            return false;
+        auto getterFuncs = nameContext.getFunctions(getterName, currentNameSpace);
         Vector<ResolvingType> argumentTypes;
         Vector<std::reference_wrapper<ResolvingType>> argumentTypeReferences;
         for (size_t i = 0; i < numExpectedParameters - 1; ++i)
             argumentTypes.append(*functionDefinition.parameters()[i]->type());
         for (auto& argumentType : argumentTypes)
             argumentTypeReferences.append(argumentType);
-        auto* overload = resolveFunctionOverload(*getterFuncs, argumentTypeReferences);
+        auto* overload = resolveFunctionOverload(getterFuncs, argumentTypeReferences, currentNameSpace);
         if (!overload)
             return false;
         auto& resultType = overload->type();
@@ -672,14 +670,15 @@ private:
     RefPtr<AST::TypeReference> m_wrappedFloatType;
     RefPtr<AST::UnnamedType> m_genericPointerType;
     HashMap<AST::Expression*, std::unique_ptr<ResolvingType>> m_typeMap;
-    HashSet<String> m_vertexEntryPoints;
-    HashSet<String> m_fragmentEntryPoints;
-    HashSet<String> m_computeEntryPoints;
+    HashSet<String> m_vertexEntryPoints[AST::nameSpaceCount];
+    HashSet<String> m_fragmentEntryPoints[AST::nameSpaceCount];
+    HashSet<String> m_computeEntryPoints[AST::nameSpaceCount];
     const Intrinsics& m_intrinsics;
     Program& m_program;
     AST::FunctionDefinition* m_currentFunction { nullptr };
     HashMap<FunctionKey, Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>, FunctionKey::Hash, FunctionKey::Traits> m_functions;
     HashMap<AndOverloadTypeKey, RefPtr<AST::UnnamedType>, AndOverloadTypeKey::Hash, AndOverloadTypeKey::Traits> m_andOverloadTypeMap;
+    AST::NameSpace m_currentNameSpace { AST::NameSpace::StandardLibrary };
 };
 
 void Checker::visit(Program& program)
@@ -723,18 +722,20 @@ Expected<void, Error> Checker::assignTypes()
 
 bool Checker::checkShaderType(const AST::FunctionDefinition& functionDefinition)
 {
+    auto index = static_cast<unsigned>(m_currentNameSpace);
     switch (*functionDefinition.entryPointType()) {
     case AST::EntryPointType::Vertex:
-        return static_cast<bool>(m_vertexEntryPoints.add(functionDefinition.name()));
+        return static_cast<bool>(m_vertexEntryPoints[index].add(functionDefinition.name()));
     case AST::EntryPointType::Fragment:
-        return static_cast<bool>(m_fragmentEntryPoints.add(functionDefinition.name()));
+        return static_cast<bool>(m_fragmentEntryPoints[index].add(functionDefinition.name()));
     case AST::EntryPointType::Compute:
-        return static_cast<bool>(m_computeEntryPoints.add(functionDefinition.name()));
+        return static_cast<bool>(m_computeEntryPoints[index].add(functionDefinition.name()));
     }
 }
 
 void Checker::visit(AST::FunctionDefinition& functionDefinition)
 {
+    m_currentNameSpace = functionDefinition.nameSpace();
     m_currentFunction = &functionDefinition;
     if (functionDefinition.entryPointType()) {
         if (!checkShaderType(functionDefinition)) {
@@ -751,7 +752,7 @@ void Checker::visit(AST::FunctionDefinition& functionDefinition)
             return;
         }
     }
-    if (!checkOperatorOverload(functionDefinition, m_program.nameContext())) {
+    if (!checkOperatorOverload(functionDefinition, m_program.nameContext(), m_currentNameSpace)) {
         setError(Error("Operator does not match expected signature.", functionDefinition.codeLocation()));
         return;
     }
@@ -834,7 +835,7 @@ AST::FunctionDeclaration* Checker::resolveFunction(Vector<std::reference_wrapper
     {
         auto iter = m_functions.find(FunctionKey { name, WTFMove(unnamedTypes), castReturnType });
         if (iter != m_functions.end()) {
-            if (AST::FunctionDeclaration* function = resolveFunctionOverload(iter->value, types, castReturnType))
+            if (AST::FunctionDeclaration* function = resolveFunctionOverload(iter->value, types, castReturnType, m_currentNameSpace))
                 return function;
         }
     }
@@ -1652,15 +1653,14 @@ void Checker::visit(AST::CallExpression& callExpression)
 
     if (!function) {
         NameContext& nameContext = m_program.nameContext();
-        if (auto* castTypes = nameContext.getTypes(callExpression.name())) {
-            if (castTypes->size() == 1) {
-                AST::NamedType& castType = (*castTypes)[0].get();
-                function = resolveFunction(types, "operator cast"_str, callExpression.codeLocation(), &castType);
-                if (hasError())
-                    return;
-                if (function)
-                    callExpression.setCastData(castType);
-            }
+        auto castTypes = nameContext.getTypes(callExpression.name(), m_currentNameSpace);
+        if (castTypes.size() == 1) {
+            AST::NamedType& castType = castTypes[0].get();
+            function = resolveFunction(types, "operator cast"_str, callExpression.codeLocation(), &castType);
+            if (hasError())
+                return;
+            if (function)
+                callExpression.setCastData(castType);
         }
     }
 
index 9e3173b..83e56f9 100644 (file)
@@ -27,6 +27,8 @@
 
 #if ENABLE(WEBGPU)
 
+#include "WHLSLNameSpace.h"
+
 namespace WebCore {
 
 namespace WHLSL {
@@ -35,31 +37,60 @@ struct Token;
 
 class CodeLocation {
 public:
-    CodeLocation() = default;
-    CodeLocation(unsigned startOffset, unsigned endOffset)
+    CodeLocation()
+        : m_startOffset(0x7FFFFFFF)
+        , m_endOffset(0x7FFFFFFF)
+        , m_nameSpace(static_cast<unsigned>(AST::NameSpace::StandardLibrary))
+    {
+    }
+
+    CodeLocation(unsigned startOffset, unsigned endOffset, AST::NameSpace nameSpace)
         : m_startOffset(startOffset)
         , m_endOffset(endOffset)
-    { }
+        , m_nameSpace(static_cast<unsigned>(nameSpace))
+    {
+    }
+
     CodeLocation(const Token&);
+
     CodeLocation(const CodeLocation& location1, const CodeLocation& location2)
         : m_startOffset(location1.startOffset())
         , m_endOffset(location2.endOffset())
-    { }
+        , m_nameSpace(static_cast<unsigned>(location1.nameSpace()))
+    {
+        ASSERT(location1.nameSpace() == location2.nameSpace());
+    }
 
-    unsigned startOffset() const { return m_startOffset; }
-    unsigned endOffset() const { return m_endOffset; }
+    unsigned startOffset() const
+    {
+        return m_startOffset;
+    }
+
+    unsigned endOffset() const
+    {
+        return m_endOffset;
+    }
+
+    AST::NameSpace nameSpace() const
+    {
+        return static_cast<AST::NameSpace>(m_nameSpace);
+    }
 
     bool operator==(const CodeLocation& other) const 
     {
         return m_startOffset == other.m_startOffset
-            && m_endOffset == other.m_endOffset;
+            && m_endOffset == other.m_endOffset
+            && m_nameSpace == other.m_nameSpace;
     }
+
     bool operator!=(const CodeLocation& other) const { return !(*this == other); }
+
     explicit operator bool() const { return *this != CodeLocation(); }
 
 private:
-    unsigned m_startOffset { std::numeric_limits<unsigned>::max() };
-    unsigned m_endOffset { std::numeric_limits<unsigned>::max() };
+    unsigned m_startOffset : 31;
+    unsigned m_endOffset : 31;
+    unsigned m_nameSpace : 2;
 };
 
 } // namespace WHLSL
index 1aa5dfa..ae5f5e2 100644 (file)
@@ -316,7 +316,7 @@ auto Lexer::consumeTokenFromStream() -> Token
         auto oldOffset = m_offset;
         m_offset = offset;
         skipWhitespaceAndComments();
-        return { { oldOffset, offset }, type };
+        return { { oldOffset, offset, m_nameSpace }, type };
     };
 
     switch (shift()) {
@@ -1702,7 +1702,6 @@ static inline bool isNewline(UChar codeUnit)
     }
 }
 
-
 auto Lexer::lineAndColumnNumberFromOffset(const StringView& stringView, unsigned targetOffset) -> LineAndColumn
 {
     // Counting from 1 to match most text editors.
@@ -1718,11 +1717,26 @@ auto Lexer::lineAndColumnNumberFromOffset(const StringView& stringView, unsigned
     return { lineNumber, columnNumber };
 }
 
-String Lexer::errorString(const StringView& source, Error error)
+static Optional<StringView> sourceFromNameSpace(AST::NameSpace nameSpace, const String& source1, const String* source2)
+{
+    switch (nameSpace) {
+    case AST::NameSpace::StandardLibrary:
+        return WTF::nullopt;
+    case AST::NameSpace::NameSpace1:
+        return StringView(source1);
+    case AST::NameSpace::NameSpace2:
+        ASSERT(source2);
+        return StringView(*source2);
+    }
+}
+
+String Lexer::errorString(Error error, const String& source1, const String* source2)
 {
-    if (error.codeLocation()) {
-        auto lineAndColumn = lineAndColumnNumberFromOffset(source, error.codeLocation().startOffset());
-        return makeString(lineAndColumn.line, ':', lineAndColumn.column, ": ", error.message());
+    if (auto codeLocation = error.codeLocation()) {
+        if (auto source = sourceFromNameSpace(codeLocation.nameSpace(), source1, source2)) {
+            auto lineAndColumn = lineAndColumnNumberFromOffset(*source, error.codeLocation().startOffset());
+            return makeString(lineAndColumn.line, ':', lineAndColumn.column, ": ", error.message());
+        }
     }
     return error.message();
 }
index de2e761..ac023dd 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "WHLSLCodeLocation.h"
 #include "WHLSLError.h"
+#include "WHLSLNameSpace.h"
 #include <wtf/Optional.h>
 #include <wtf/Vector.h>
 #include <wtf/text/StringConcatenate.h>
@@ -165,16 +166,17 @@ struct Token {
 };
 
 inline CodeLocation::CodeLocation(const Token& token)
-    : m_startOffset(token.codeLocation.startOffset())
-    , m_endOffset(token.codeLocation.endOffset())
-}
+    : CodeLocation(token.codeLocation)
+{
+}
 
 class Lexer {
 public:
     Lexer() = default;
 
-    Lexer(StringView stringView)
+    Lexer(StringView stringView, AST::NameSpace nameSpace)
         : m_stringView(stringView)
+        , m_nameSpace(nameSpace)
     {
         skipWhitespaceAndComments();
         m_ringBuffer[0] = consumeTokenFromStream();
@@ -251,7 +253,9 @@ public:
         return makeString("Parse error at line ", lineAndColumnNumberFromOffset(m_stringView, token.startOffset()).line, ": ", message);
     }
 
-    static String errorString(const StringView& source, Error);
+    static String errorString(Error, const String& source1, const String* source2 = nullptr);
+
+    AST::NameSpace nameSpace() const { return m_nameSpace; }
 
 private:
     friend struct Token;
@@ -269,6 +273,7 @@ private:
     Token m_ringBuffer[2];
     unsigned m_ringBufferIndex { 0 };
     unsigned m_offset { 0 };
+    AST::NameSpace m_nameSpace { AST::NameSpace::StandardLibrary };
 };
 
 StringView Token::stringView(const Lexer& lexer) const
index 1990213..56041fb 100644 (file)
@@ -45,99 +45,138 @@ NameContext::NameContext(NameContext* parent)
 {
 }
 
-bool NameContext::add(AST::TypeDefinition& typeDefinition)
+Expected<void, Error> NameContext::add(AST::TypeDefinition& typeDefinition)
 {
-    if (exists(typeDefinition.name()))
-        return false;
-    auto result = m_types.add(typeDefinition.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
-    if (!result.isNewEntry)
-        return false;
+    if (auto existing = topLevelExists(typeDefinition.name()))
+        return makeUnexpected(Error("Duplicate name in program", *existing));
+    typeDefinition.setNameSpace(m_currentNameSpace);
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    auto result = m_types[index].add(typeDefinition.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
+    ASSERT(result.isNewEntry);
     result.iterator->value.append(typeDefinition);
-    return true;
+    return { };
 }
 
-bool NameContext::add(AST::StructureDefinition& structureDefinition)
+Expected<void, Error> NameContext::add(AST::StructureDefinition& structureDefinition)
 {
-    if (exists(structureDefinition.name()))
-        return false;
-    auto result = m_types.add(structureDefinition.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
-    if (!result.isNewEntry)
-        return false;
+    if (auto existing = topLevelExists(structureDefinition.name()))
+        return makeUnexpected(Error("Duplicate name in program.", *existing));
+    structureDefinition.setNameSpace(m_currentNameSpace);
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    auto result = m_types[index].add(structureDefinition.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
+    ASSERT(result.isNewEntry);
     result.iterator->value.append(structureDefinition);
-    return true;
+    return { };
 }
 
-bool NameContext::add(AST::EnumerationDefinition& enumerationDefinition)
+Expected<void, Error> NameContext::add(AST::EnumerationDefinition& enumerationDefinition)
 {
-    if (exists(enumerationDefinition.name()))
-        return false;
-    auto result = m_types.add(enumerationDefinition.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
-    if (!result.isNewEntry)
-        return false;
+    if (auto existing = topLevelExists(enumerationDefinition.name()))
+        return makeUnexpected(Error("Duplicate name in program.", *existing));
+    enumerationDefinition.setNameSpace(m_currentNameSpace);
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    auto result = m_types[index].add(enumerationDefinition.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
+    ASSERT(result.isNewEntry);
     result.iterator->value.append(enumerationDefinition);
-    return true;
+    return { };
 }
 
-bool NameContext::add(AST::FunctionDefinition& functionDefinition)
+Expected<void, Error> NameContext::add(AST::FunctionDefinition& functionDefinition)
 {
-    if (m_types.find(functionDefinition.name()) != m_types.end()
-        || m_variables.find(functionDefinition.name()) != m_variables.end())
-        return false;
-    auto result = m_functions.add(functionDefinition.name(), Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>());
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    if (auto* type = searchTypes(functionDefinition.name()))
+        return makeUnexpected(Error("Duplicate name in program.", type->codeLocation()));
+    functionDefinition.setNameSpace(m_currentNameSpace);
+    auto result = m_functions[index].add(functionDefinition.name(), Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>());
     result.iterator->value.append(functionDefinition);
-    return true;
+    return { };
 }
 
-bool NameContext::add(AST::NativeFunctionDeclaration& nativeFunctionDeclaration)
+Expected<void, Error> NameContext::add(AST::NativeFunctionDeclaration& nativeFunctionDeclaration)
 {
-    if (m_types.find(nativeFunctionDeclaration.name()) != m_types.end()
-        || m_variables.find(nativeFunctionDeclaration.name()) != m_variables.end())
-        return false;
-    auto result = m_functions.add(nativeFunctionDeclaration.name(), Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>());
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    if (auto* type = searchTypes(nativeFunctionDeclaration.name()))
+        return makeUnexpected(Error("Duplicate name in program.", type->codeLocation()));
+    nativeFunctionDeclaration.setNameSpace(m_currentNameSpace);
+    auto result = m_functions[index].add(nativeFunctionDeclaration.name(), Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>());
     result.iterator->value.append(nativeFunctionDeclaration);
-    return true;
+    return { };
 }
 
-bool NameContext::add(AST::NativeTypeDeclaration& nativeTypeDeclaration)
+Expected<void, Error> NameContext::add(AST::NativeTypeDeclaration& nativeTypeDeclaration)
 {
-    if (m_functions.find(nativeTypeDeclaration.name()) != m_functions.end()
-        || m_variables.find(nativeTypeDeclaration.name()) != m_variables.end())
-        return false;
-    auto result = m_types.add(nativeTypeDeclaration.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    if (auto* function = searchFunctions(nativeTypeDeclaration.name()))
+        return makeUnexpected(Error("Duplicate name in program.", function->codeLocation()));
+    nativeTypeDeclaration.setNameSpace(m_currentNameSpace);
+    auto result = m_types[index].add(nativeTypeDeclaration.name(), Vector<std::reference_wrapper<AST::NamedType>, 1>());
     result.iterator->value.append(nativeTypeDeclaration);
-    return true;
+    return { };
 }
 
-bool NameContext::add(AST::VariableDeclaration& variableDeclaration)
+Expected<void, Error> NameContext::add(AST::VariableDeclaration& variableDeclaration)
 {
     if (variableDeclaration.name().isNull())
-        return true;
-    if (exists(variableDeclaration.name()))
-        return false;
+        return { };
+    if (auto* declaration = localExists(variableDeclaration.name()))
+        return makeUnexpected(Error("Duplicate name in program.", declaration->codeLocation()));
     auto result = m_variables.add(String(variableDeclaration.name()), &variableDeclaration);
-    return result.isNewEntry;
+    ASSERT_UNUSED(result, result.isNewEntry);
+    return { };
 }
 
-Vector<std::reference_wrapper<AST::NamedType>, 1>* NameContext::getTypes(const String& name)
+Vector<std::reference_wrapper<AST::NamedType>, 1> NameContext::getTypes(const String& name, AST::NameSpace fromNamespace)
 {
-    auto iterator = m_types.find(name);
-    if (iterator == m_types.end()) {
-        if (m_parent)
-            return m_parent->getTypes(name);
-        return nullptr;
+    // Named types can only be declared in the global name context.
+    if (m_parent)
+        return m_parent->getTypes(name, fromNamespace);
+
+    Vector<std::reference_wrapper<AST::NamedType>, 1> result;
+
+    unsigned index = static_cast<unsigned>(fromNamespace);
+    auto iterator = m_types[index].find(name);
+    if (iterator != m_types[index].end()) {
+        for (auto type : iterator->value)
+            result.append(type);
     }
-    return &iterator->value;
+
+    if (fromNamespace != AST::NameSpace::StandardLibrary) {
+        index = static_cast<unsigned>(AST::NameSpace::StandardLibrary);
+        iterator = m_types[index].find(name);
+        if (iterator != m_types[index].end()) {
+            for (auto type : iterator->value)
+                result.append(type);
+        }
+    }
+
+    return result;
 }
 
-Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>* NameContext::getFunctions(const String& name)
+Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1> NameContext::getFunctions(const String& name, AST::NameSpace fromNamespace)
 {
-    auto iterator = m_functions.find(name);
-    if (iterator == m_functions.end()) {
-        if (m_parent)
-            return m_parent->getFunctions(name);
-        return nullptr;
+    // Functions can only be declared in the global name context.
+    if (m_parent)
+        return m_parent->getFunctions(name, fromNamespace);
+
+    Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1> result;
+
+    unsigned index = static_cast<unsigned>(fromNamespace);
+    auto iterator = m_functions[index].find(name);
+    if (iterator != m_functions[index].end()) {
+        for (auto type : iterator->value)
+            result.append(type);
+    }
+
+    if (fromNamespace != AST::NameSpace::StandardLibrary) {
+        index = static_cast<unsigned>(AST::NameSpace::StandardLibrary);
+        iterator = m_functions[index].find(name);
+        if (iterator != m_functions[index].end()) {
+            for (auto type : iterator->value)
+                result.append(type);
+        }
     }
-    return &iterator->value;
+
+    return result;
 }
 
 AST::VariableDeclaration* NameContext::getVariable(const String& name)
@@ -151,11 +190,72 @@ AST::VariableDeclaration* NameContext::getVariable(const String& name)
     return iterator->value;
 }
 
-bool NameContext::exists(String& name)
+AST::NamedType* NameContext::searchTypes(String& name) const
+{
+    ASSERT(!m_parent);
+    if (m_currentNameSpace == AST::NameSpace::StandardLibrary) {
+        for (auto& types : m_types) {
+            auto iter = types.find(name);
+            if (iter != types.end())
+                return &iter->value[0].get();
+        }
+        return nullptr;
+    }
+
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    auto iter = m_types[index].find(name);
+    if (iter != m_types[index].end())
+        return &iter->value[0].get();
+
+    index = static_cast<unsigned>(AST::NameSpace::StandardLibrary);
+    iter = m_types[index].find(name);
+    if (iter != m_types[index].end())
+        return &iter->value[0].get();
+
+    return nullptr;
+}
+
+AST::FunctionDeclaration* NameContext::searchFunctions(String& name) const
+{
+    ASSERT(!m_parent);
+    if (m_currentNameSpace == AST::NameSpace::StandardLibrary) {
+        for (auto& functions : m_functions) {
+            auto iter = functions.find(name);
+            if (iter != functions.end())
+                return &iter->value[0].get();
+        }
+        return nullptr;
+    }
+
+    auto index = static_cast<unsigned>(m_currentNameSpace);
+    auto iter = m_functions[index].find(name);
+    if (iter != m_functions[index].end())
+        return &iter->value[0].get();
+
+    index = static_cast<unsigned>(AST::NameSpace::StandardLibrary);
+    iter = m_functions[index].find(name);
+    if (iter != m_functions[index].end())
+        return &iter->value[0].get();
+
+    return nullptr;
+}
+
+Optional<CodeLocation> NameContext::topLevelExists(String& name) const
+{
+    if (auto* type = searchTypes(name))
+        return type->codeLocation();
+    if (auto* function = searchFunctions(name))
+        return function->codeLocation();
+    return WTF::nullopt;
+}
+
+AST::VariableDeclaration* NameContext::localExists(String& name) const
 {
-    return m_types.find(name) != m_types.end()
-        || m_functions.find(name) != m_functions.end()
-        || m_variables.find(name) != m_variables.end();
+    ASSERT(m_parent);
+    auto iter = m_variables.find(name);
+    if (iter != m_variables.end())
+        return iter->value;
+    return nullptr;
 }
 
 } // namespace WHLSL
index a04878a..f0de222 100644 (file)
@@ -27,6 +27,9 @@
 
 #if ENABLE(WEBGPU)
 
+#include "WHLSLError.h"
+#include "WHLSLNameSpace.h"
+
 #include <functional>
 #include <wtf/HashMap.h>
 #include <wtf/Vector.h>
@@ -54,25 +57,35 @@ class NameContext {
 public:
     NameContext(NameContext* parent = nullptr);
 
-    bool add(AST::TypeDefinition&);
-    bool add(AST::StructureDefinition&);
-    bool add(AST::EnumerationDefinition&);
-    bool add(AST::FunctionDefinition&);
-    bool add(AST::NativeFunctionDeclaration&);
-    bool add(AST::NativeTypeDeclaration&);
-    bool add(AST::VariableDeclaration&);
-
-    Vector<std::reference_wrapper<AST::NamedType>, 1>* getTypes(const String&);
-    Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>* getFunctions(const String&);
+    void setCurrentNameSpace(AST::NameSpace currentNameSpace)
+    {
+        ASSERT(!m_parent);
+        m_currentNameSpace = currentNameSpace;
+    }
+
+    Expected<void, Error> add(AST::TypeDefinition&);
+    Expected<void, Error> add(AST::StructureDefinition&);
+    Expected<void, Error> add(AST::EnumerationDefinition&);
+    Expected<void, Error> add(AST::FunctionDefinition&);
+    Expected<void, Error> add(AST::NativeFunctionDeclaration&);
+    Expected<void, Error> add(AST::NativeTypeDeclaration&);
+    Expected<void, Error> add(AST::VariableDeclaration&);
+
+    Vector<std::reference_wrapper<AST::NamedType>, 1> getTypes(const String&, AST::NameSpace fromNamespace);
+    Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1> getFunctions(const String&, AST::NameSpace fromNamespace);
     AST::VariableDeclaration* getVariable(const String&);
 
 private:
-    bool exists(String&);
+    AST::NamedType* searchTypes(String& name) const;
+    AST::FunctionDeclaration* searchFunctions(String& name) const;
+    Optional<CodeLocation> topLevelExists(String& name) const;
+    AST::VariableDeclaration* localExists(String& name) const;
 
-    HashMap<String, Vector<std::reference_wrapper<AST::NamedType>, 1>> m_types;
-    HashMap<String, Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>> m_functions;
+    HashMap<String, Vector<std::reference_wrapper<AST::NamedType>, 1>> m_types[AST::nameSpaceCount];
+    HashMap<String, Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>> m_functions[AST::nameSpaceCount];
     HashMap<String, AST::VariableDeclaration*> m_variables;
     NameContext* m_parent;
+    AST::NameSpace m_currentNameSpace { AST::NameSpace::StandardLibrary };
 };
 
 }
index 67b1c9b..271ebd1 100644 (file)
@@ -57,6 +57,7 @@ NameResolver::NameResolver(NameContext& nameContext)
 NameResolver::NameResolver(NameResolver& parentResolver, NameContext& nameContext)
     : m_nameContext(nameContext)
     , m_parentNameResolver(&parentResolver)
+    , m_currentNameSpace(parentResolver.m_currentNameSpace)
 {
 }
 
@@ -80,14 +81,10 @@ void NameResolver::visit(AST::TypeReference& typeReference)
     if (typeReference.maybeResolvedType()) // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198161 Shouldn't we know by now whether the type has been resolved or not?
         return;
 
-    auto* candidates = m_nameContext.getTypes(typeReference.name());
-    if (candidates == nullptr) {
-        setError(Error("Cannot find type reference.", typeReference.codeLocation()));
-        return;
-    }
-    for (auto& candidate : *candidates)
+    auto candidates = m_nameContext.getTypes(typeReference.name(), m_currentNameSpace);
+    for (auto& candidate : candidates)
         Visitor::visit(candidate);
-    if (auto result = resolveTypeOverloadImpl(*candidates, typeReference.typeArguments()))
+    if (auto result = resolveTypeOverloadImpl(candidates, typeReference.typeArguments()))
         typeReference.setResolvedType(*result);
     else {
         setError(Error("Cannot resolve type arguments.", typeReference.codeLocation()));
@@ -192,9 +189,9 @@ void NameResolver::visit(AST::DotExpression& dotExpression)
         auto& variableReference = downcast<AST::VariableReference>(dotExpression.base());
         if (!m_nameContext.getVariable(variableReference.name())) {
             auto baseName = variableReference.name();
-            if (auto enumerationTypes = m_nameContext.getTypes(baseName)) {
-                ASSERT(enumerationTypes->size() == 1);
-                AST::NamedType& type = (*enumerationTypes)[0];
+            auto enumerationTypes = m_nameContext.getTypes(baseName, m_currentNameSpace);
+            if (enumerationTypes.size() == 1) {
+                AST::NamedType& type = enumerationTypes[0];
                 if (is<AST::EnumerationDefinition>(type)) {
                     AST::EnumerationDefinition& enumerationDefinition = downcast<AST::EnumerationDefinition>(type);
                     auto memberName = dotExpression.fieldName();
@@ -206,7 +203,8 @@ void NameResolver::visit(AST::DotExpression& dotExpression)
                     setError(Error("No enum member matches the used name.", dotExpression.codeLocation()));
                     return;
                 }
-            }
+            } else
+                ASSERT(enumerationTypes.isEmpty());
         }
     }
 
@@ -218,9 +216,10 @@ void NameResolver::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral
     if (enumerationMemberLiteral.enumerationMember())
         return;
 
-    if (auto enumerationTypes = m_nameContext.getTypes(enumerationMemberLiteral.left())) {
-        ASSERT(enumerationTypes->size() == 1);
-        AST::NamedType& type = (*enumerationTypes)[0];
+    auto enumerationTypes = m_nameContext.getTypes(enumerationMemberLiteral.left(), m_currentNameSpace);
+    if (enumerationTypes.size() == 1) {
+        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=199335 This needs to work with typedef'ed enums.
+        AST::NamedType& type = enumerationTypes[0];
         if (is<AST::EnumerationDefinition>(type)) {
             AST::EnumerationDefinition& enumerationDefinition = downcast<AST::EnumerationDefinition>(type);
             if (auto* member = enumerationDefinition.memberByName(enumerationMemberLiteral.right())) {
@@ -229,7 +228,7 @@ void NameResolver::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral
             }
         }
     }
-    
+
     setError(Error("Cannot resolve enumeration member literal.", enumerationMemberLiteral.codeLocation()));
 }
 
@@ -245,21 +244,25 @@ void NameResolver::visit(AST::NativeFunctionDeclaration& nativeFunctionDeclarati
 Expected<void, Error> resolveNamesInTypes(Program& program, NameResolver& nameResolver)
 {
     for (auto& typeDefinition : program.typeDefinitions()) {
+        nameResolver.setCurrentNameSpace(typeDefinition.get().nameSpace());
         nameResolver.checkErrorAndVisit(typeDefinition);
         if (nameResolver.hasError())
             return nameResolver.result();
     }
     for (auto& structureDefinition : program.structureDefinitions()) {
+        nameResolver.setCurrentNameSpace(structureDefinition.get().nameSpace());
         nameResolver.checkErrorAndVisit(structureDefinition);
         if (nameResolver.hasError())
             return nameResolver.result();
     }
     for (auto& enumerationDefinition : program.enumerationDefinitions()) {
+        nameResolver.setCurrentNameSpace(enumerationDefinition.get().nameSpace());
         nameResolver.checkErrorAndVisit(enumerationDefinition);
         if (nameResolver.hasError())
             return nameResolver.result();
     }
     for (auto& nativeTypeDeclaration : program.nativeTypeDeclarations()) {
+        nameResolver.setCurrentNameSpace(nativeTypeDeclaration.get().nameSpace());
         nameResolver.checkErrorAndVisit(nativeTypeDeclaration);
         if (nameResolver.hasError())
             return nameResolver.result();
@@ -270,11 +273,13 @@ Expected<void, Error> resolveNamesInTypes(Program& program, NameResolver& nameRe
 Expected<void, Error> resolveTypeNamesInFunctions(Program& program, NameResolver& nameResolver)
 {
     for (auto& functionDefinition : program.functionDefinitions()) {
+        nameResolver.setCurrentNameSpace(functionDefinition.get().nameSpace());
         nameResolver.checkErrorAndVisit(functionDefinition);
         if (nameResolver.hasError())
             return nameResolver.result();
     }
     for (auto& nativeFunctionDeclaration : program.nativeFunctionDeclarations()) {
+        nameResolver.setCurrentNameSpace(nativeFunctionDeclaration.get().nameSpace());
         nameResolver.checkErrorAndVisit(nativeFunctionDeclaration);
         if (nameResolver.hasError())
             return nameResolver.result();
index 658c35f..a7924e0 100644 (file)
@@ -46,6 +46,8 @@ public:
 
     virtual ~NameResolver();
 
+    void setCurrentNameSpace(AST::NameSpace nameSpace) { m_currentNameSpace = nameSpace; }
+
 private:
     void visit(AST::FunctionDefinition&) override;
     void visit(AST::NativeFunctionDeclaration&) override;
@@ -63,6 +65,7 @@ private:
     NameContext& m_nameContext;
     HashSet<AST::TypeReference*> m_typeReferences;
     NameResolver* m_parentNameResolver { nullptr };
+    AST::NameSpace m_currentNameSpace { AST::NameSpace::StandardLibrary };
 };
 
 Expected<void, Error> resolveNamesInTypes(Program&, NameResolver&);
index d84e749..ed095d4 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "WHLSLAddressSpace.h"
 #include "WHLSLEntryPointType.h"
+#include "WHLSLProgram.h"
 #include <wtf/dtoa.h>
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/StringConcatenate.h>
@@ -41,27 +42,26 @@ namespace WHLSL {
 #define PARSE(name, element, ...) \
     auto name = parse##element(__VA_ARGS__); \
     if (!name) \
-        return Unexpected<Error>(name.error()); \
+        return makeUnexpected(name.error()); \
 
 #define CONSUME_TYPE(name, type) \
     auto name = consumeType(Token::Type::type); \
     if (!name) \
-        return Unexpected<Error>(name.error());
+        return makeUnexpected(name.error());
 
 #define PEEK(name) \
     auto name = peek(); \
     if (!name) \
-        return Unexpected<Error>(name.error());
+        return makeUnexpected(name.error());
 
 #define PEEK_FURTHER(name) \
     auto name = peekFurther(); \
     if (!name) \
-        return Unexpected<Error>(name.error());
+        return makeUnexpected(name.error());
 
-// FIXME: https://bugs.webkit.org/show_bug.cgi?id=195682 Return a better error code from this, and report it to JavaScript.
-auto Parser::parse(Program& program, StringView stringView, ParsingMode mode) -> Expected<void, Error>
+auto Parser::parse(Program& program, StringView stringView, ParsingMode mode, AST::NameSpace nameSpace) -> Expected<void, Error>
 {
-    m_lexer = Lexer(stringView);
+    m_lexer = Lexer(stringView, nameSpace);
     m_mode = mode;
 
     while (!m_lexer.isFullyConsumed()) {
@@ -76,25 +76,32 @@ auto Parser::parse(Program& program, StringView stringView, ParsingMode mode) ->
             auto typeDefinition = parseTypeDefinition();
             if (!typeDefinition)
                 return makeUnexpected(typeDefinition.error());
-            program.append(WTFMove(*typeDefinition));
+            auto appendResult = program.append(WTFMove(*typeDefinition));
+            if (!appendResult)
+                return makeUnexpected(appendResult.error());
             continue;
         }
         case Token::Type::Struct: {
             auto structureDefinition = parseStructureDefinition();
             if (!structureDefinition)
                 return makeUnexpected(structureDefinition.error());
-            program.append(WTFMove(*structureDefinition));
+            auto appendResult = program.append(WTFMove(*structureDefinition));
+            if (!appendResult)
+                return makeUnexpected(appendResult.error());
             continue;
         }
         case Token::Type::Enum: {
             auto enumerationDefinition = parseEnumerationDefinition();
             if (!enumerationDefinition)
                 return makeUnexpected(enumerationDefinition.error());
-            program.append(WTFMove(*enumerationDefinition));
+            auto appendResult = program.append(WTFMove(*enumerationDefinition));
+            if (!appendResult)
+                return makeUnexpected(appendResult.error());
             continue;
         }
         case Token::Type::Native: {
-            ASSERT(m_mode == ParsingMode::StandardLibrary);
+            if (m_mode != ParsingMode::StandardLibrary)
+                return fail(makeString("'native' can't exist outside of the standard library."));
             auto furtherToken = peekFurther();
             if (!furtherToken)
                 return { };
@@ -102,20 +109,26 @@ auto Parser::parse(Program& program, StringView stringView, ParsingMode mode) ->
                 auto nativeTypeDeclaration = parseNativeTypeDeclaration();
                 if (!nativeTypeDeclaration)
                     return makeUnexpected(nativeTypeDeclaration.error());
-                program.append(WTFMove(*nativeTypeDeclaration));
+                auto appendResult = program.append(WTFMove(*nativeTypeDeclaration));
+                if (!appendResult)
+                    return makeUnexpected(appendResult.error());
                 continue;
             }
             auto nativeFunctionDeclaration = parseNativeFunctionDeclaration();
             if (!nativeFunctionDeclaration)
                 return makeUnexpected(nativeFunctionDeclaration.error());
-            program.append(WTFMove(*nativeFunctionDeclaration));
+            auto appendResult = program.append(WTFMove(*nativeFunctionDeclaration));
+            if (!appendResult)
+                return makeUnexpected(appendResult.error());
             continue;
         }
         default: {
             auto functionDefinition = parseFunctionDefinition();
             if (!functionDefinition)
                 return makeUnexpected(functionDefinition.error());
-            program.append(WTFMove(*functionDefinition));
+            auto appendResult = program.append(WTFMove(*functionDefinition));
+            if (!appendResult)
+                return makeUnexpected(appendResult.error());
             continue;
         }
         }
@@ -128,9 +141,9 @@ auto Parser::fail(const String& message, TryToPeek tryToPeek) -> Unexpected<Erro
 {
     if (tryToPeek == TryToPeek::Yes) {
         if (auto nextToken = peek())
-            return Unexpected<Error>(Error(m_lexer.errorString(*nextToken, message)));
+            return makeUnexpected(Error(m_lexer.errorString(*nextToken, message)));
     }
-    return Unexpected<Error>(Error(makeString("Cannot lex: ", message)));
+    return makeUnexpected(Error(makeString("Cannot lex: ", message)));
 }
 
 auto Parser::peek() -> Expected<Token, Error>
@@ -306,21 +319,21 @@ auto Parser::consumeIntegralLiteral() -> Expected<Variant<int, unsigned>, Error>
 {
     auto integralLiteralToken = consumeTypes<Token::Type::IntLiteral, Token::Type::UintLiteral>();
     if (!integralLiteralToken)
-        return Unexpected<Error>(integralLiteralToken.error());
+        return makeUnexpected(integralLiteralToken.error());
 
     switch (integralLiteralToken->type) {
     case Token::Type::IntLiteral: {
         auto result = intLiteralToInt(integralLiteralToken->stringView(m_lexer));
         if (result)
             return {{ *result }};
-        return Unexpected<Error>(result.error());
+        return makeUnexpected(result.error());
     }
     default: {
         ASSERT(integralLiteralToken->type == Token::Type::UintLiteral);
         auto result = uintLiteralToUint(integralLiteralToken->stringView(m_lexer));
         if (result)
             return {{ *result }};
-        return Unexpected<Error>(result.error());
+        return makeUnexpected(result.error());
     }
     }
 }
@@ -329,7 +342,7 @@ auto Parser::consumeNonNegativeIntegralLiteral() -> Expected<unsigned, Error>
 {
     auto integralLiteral = consumeIntegralLiteral();
     if (!integralLiteral)
-        return Unexpected<Error>(integralLiteral.error());
+        return makeUnexpected(integralLiteral.error());
     auto result = WTF::visit(WTF::makeVisitor([](int x) -> Optional<unsigned> {
         if (x < 0)
             return WTF::nullopt;
@@ -369,25 +382,25 @@ auto Parser::parseConstantExpression() -> Expected<AST::ConstantExpression, Erro
         Token::Type::False,
         Token::Type::Identifier>();
     if (!type)
-        return Unexpected<Error>(type.error());
+        return makeUnexpected(type.error());
 
     switch (type->type) {
     case Token::Type::IntLiteral: {
         auto value = intLiteralToInt(type->stringView(m_lexer));
         if (!value)
-            return Unexpected<Error>(value.error());
+            return makeUnexpected(value.error());
         return {{ AST::IntegerLiteral({ *type }, *value) }};
     }
     case Token::Type::UintLiteral: {
         auto value = uintLiteralToUint(type->stringView(m_lexer));
         if (!value)
-            return Unexpected<Error>(value.error());
+            return makeUnexpected(value.error());
         return {{ AST::UnsignedIntegerLiteral({ *type }, *value) }};
     }
     case Token::Type::FloatLiteral: {
         auto value = floatLiteralToFloat(type->stringView(m_lexer));
         if (!value)
-            return Unexpected<Error>(value.error());
+            return makeUnexpected(value.error());
         return {{ AST::FloatLiteral({ *type }, *value) }};
     }
     case Token::Type::Null:
@@ -452,11 +465,11 @@ auto Parser::parseTypeSuffixAbbreviated() -> Expected<TypeSuffixAbbreviated, Err
         Token::Type::SquareBracketPair,
         Token::Type::LeftSquareBracket>();
     if (!token)
-        return Unexpected<Error>(token.error());
+        return makeUnexpected(token.error());
     if (token->type == Token::Type::LeftSquareBracket) {
         auto numElements = consumeNonNegativeIntegralLiteral();
         if (!numElements)
-            return Unexpected<Error>(numElements.error());
+            return makeUnexpected(numElements.error());
         CONSUME_TYPE(rightSquareBracket, RightSquareBracket);
         return {{ { *token, *rightSquareBracket }, *token, *numElements }};
     }
@@ -470,11 +483,11 @@ auto Parser::parseTypeSuffixNonAbbreviated() -> Expected<TypeSuffixNonAbbreviate
         Token::Type::SquareBracketPair,
         Token::Type::LeftSquareBracket>();
     if (!token)
-        return Unexpected<Error>(token.error());
+        return makeUnexpected(token.error());
     if (token->type == Token::Type::LeftSquareBracket) {
         auto numElements = consumeNonNegativeIntegralLiteral();
         if (!numElements)
-            return Unexpected<Error>(numElements.error());
+            return makeUnexpected(numElements.error());
         CONSUME_TYPE(rightSquareBracket, RightSquareBracket);
         return {{ { *token, *rightSquareBracket }, *token, WTF::nullopt, *numElements }};
     }
@@ -484,7 +497,7 @@ auto Parser::parseTypeSuffixNonAbbreviated() -> Expected<TypeSuffixNonAbbreviate
         Token::Type::Threadgroup,
         Token::Type::Thread>();
     if (!addressSpaceToken)
-        return Unexpected<Error>(addressSpaceToken.error());
+        return makeUnexpected(addressSpaceToken.error());
     AST::AddressSpace addressSpace;
     switch (addressSpaceToken->type) {
     case Token::Type::Constant:
@@ -619,7 +632,7 @@ auto Parser::parseBuiltInSemantic() -> Expected<AST::BuiltInSemantic, Error>
         Token::Type::SVGroupIndex,
         Token::Type::SVGroupThreadID>();
     if (!origin)
-        return Unexpected<Error>(origin.error());
+        return makeUnexpected(origin.error());
 
     switch (origin->type) {
     case Token::Type::SVInstanceID:
@@ -639,7 +652,7 @@ auto Parser::parseBuiltInSemantic() -> Expected<AST::BuiltInSemantic, Error>
     case Token::Type::SVTarget: {
         auto target = consumeNonNegativeIntegralLiteral(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195807 Make this work with strings like "SV_Target0".
         if (!target)
-            return Unexpected<Error>(target.error());
+            return makeUnexpected(target.error());
         return AST::BuiltInSemantic({ *origin }, AST::BuiltInSemantic::Variable::SVTarget, *target);
     }
     case Token::Type::SVDepth:
@@ -669,7 +682,7 @@ auto Parser::parseResourceSemantic() -> Expected<AST::ResourceSemantic, Error>
         && infoStringView[0] != 't'
         && infoStringView[0] != 'b'
         && infoStringView[0] != 's'))
-        return Unexpected<Error>(Error(makeString(infoStringView.substring(0, 1), " is not a known resource type ('u', 't', 'b', or 's')")));
+        return makeUnexpected(Error(makeString(infoStringView.substring(0, 1), " is not a known resource type ('u', 't', 'b', or 's')")));
 
     AST::ResourceSemantic::Mode mode;
     switch (infoStringView[0]) {
@@ -689,7 +702,7 @@ auto Parser::parseResourceSemantic() -> Expected<AST::ResourceSemantic, Error>
 
     auto index = recognizeSimpleUnsignedInteger(infoStringView.substring(1));
     if (!index)
-        return Unexpected<Error>(index.error());
+        return makeUnexpected(index.error());
 
     unsigned space = 0;
     if (tryType(Token::Type::Comma)) {
@@ -697,12 +710,12 @@ auto Parser::parseResourceSemantic() -> Expected<AST::ResourceSemantic, Error>
         auto spaceTokenStringView = spaceToken->stringView(m_lexer);
         StringView prefix { "space" };
         if (!spaceTokenStringView.startsWith(prefix))
-            return Unexpected<Error>(Error(makeString("Second argument to resource semantic ", spaceTokenStringView, " needs be of the form 'space0'")));
+            return makeUnexpected(Error(makeString("Second argument to resource semantic ", spaceTokenStringView, " needs be of the form 'space0'")));
         if (spaceTokenStringView.length() <= prefix.length())
-            return Unexpected<Error>(Error(makeString("Second argument to resource semantic ", spaceTokenStringView, " needs be of the form 'space0'")));
+            return makeUnexpected(Error(makeString("Second argument to resource semantic ", spaceTokenStringView, " needs be of the form 'space0'")));
         auto spaceValue = recognizeSimpleUnsignedInteger(spaceTokenStringView.substring(prefix.length()));
         if (!spaceValue)
-            return Unexpected<Error>(spaceValue.error());
+            return makeUnexpected(spaceValue.error());
         space = *spaceValue;
     }
 
@@ -724,7 +737,7 @@ auto Parser::parseStageInOutSemantic() -> Expected<AST::StageInOutSemantic, Erro
 
     auto index = consumeNonNegativeIntegralLiteral();
     if (!index)
-        return Unexpected<Error>(index.error());
+        return makeUnexpected(index.error());
 
     CONSUME_TYPE(rightParenthesis, RightParenthesis);
 
@@ -821,7 +834,7 @@ auto Parser::parseEnumerationDefinition() -> Expected<AST::EnumerationDefinition
         return { AST::TypeReference::create(*origin, "int"_str, AST::TypeArguments()) };
     })();
     if (!type)
-        return Unexpected<Error>(type.error());
+        return makeUnexpected(type.error());
 
     CONSUME_TYPE(leftCurlyBracket, LeftCurlyBracket);
 
@@ -868,7 +881,7 @@ auto Parser::parseEnumerationMember(int64_t defaultValue) -> Expected<AST::Enume
         }));
 
         if (!value)
-            return Unexpected<Error>("enum initialization values can only be an int or uint constant.");
+            return makeUnexpected(Error("enum initialization values can only be an int or uint constant."));
         return AST::EnumerationMember(*identifier, WTFMove(name), *value);
     }
     return AST::EnumerationMember(*identifier, WTFMove(name), defaultValue);
@@ -892,19 +905,19 @@ auto Parser::parseNumThreadsFunctionAttribute() -> Expected<AST::NumThreadsFunct
 
     auto width = consumeNonNegativeIntegralLiteral();
     if (!width)
-        return Unexpected<Error>(width.error());
+        return makeUnexpected(width.error());
 
     CONSUME_TYPE(comma, Comma);
 
     auto height = consumeNonNegativeIntegralLiteral();
     if (!height)
-        return Unexpected<Error>(height.error());
+        return makeUnexpected(height.error());
 
     CONSUME_TYPE(secondComma, Comma);
 
     auto depth = consumeNonNegativeIntegralLiteral();
     if (!depth)
-        return Unexpected<Error>(depth.error());
+        return makeUnexpected(depth.error());
 
     CONSUME_TYPE(rightParenthesis, RightParenthesis);
 
@@ -940,7 +953,7 @@ auto Parser::parseParameter() -> Expected<AST::VariableDeclaration, Error>
 
     auto endOffset = m_lexer.peek().startOffset();
 
-    return AST::VariableDeclaration({ startOffset, endOffset }, WTFMove(qualifiers), { WTFMove(*type) }, WTFMove(name), WTFMove(*semantic), nullptr);
+    return AST::VariableDeclaration({ startOffset, endOffset, m_lexer.nameSpace() }, WTFMove(qualifiers), { WTFMove(*type) }, WTFMove(name), WTFMove(*semantic), nullptr);
 }
 
 auto Parser::parseParameters() -> Expected<AST::VariableDeclarations, Error>
@@ -986,14 +999,14 @@ auto Parser::parseComputeFunctionDeclaration() -> Expected<AST::FunctionDeclarat
     auto endOffset = m_lexer.peek().startOffset();
 
     bool isOperator = false;
-    return AST::FunctionDeclaration({ origin->startOffset(), endOffset }, WTFMove(*attributeBlock), AST::EntryPointType::Compute, WTFMove(*type), name->stringView(m_lexer).toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
+    return AST::FunctionDeclaration({ origin->startOffset(), endOffset, m_lexer.nameSpace() }, WTFMove(*attributeBlock), AST::EntryPointType::Compute, WTFMove(*type), name->stringView(m_lexer).toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
 }
 
 auto Parser::parseVertexOrFragmentFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error>
 {
     auto entryPoint = consumeTypes<Token::Type::Vertex, Token::Type::Fragment>();
     if (!entryPoint)
-        return Unexpected<Error>(entryPoint.error());
+        return makeUnexpected(entryPoint.error());
     auto entryPointType = (entryPoint->type == Token::Type::Vertex) ? AST::EntryPointType::Vertex : AST::EntryPointType::Fragment;
 
     PARSE(type, Type);
@@ -1004,7 +1017,7 @@ auto Parser::parseVertexOrFragmentFunctionDeclaration() -> Expected<AST::Functio
     auto endOffset = m_lexer.peek().startOffset();
 
     bool isOperator = false;
-    return AST::FunctionDeclaration({ entryPoint->startOffset(), endOffset }, { }, entryPointType, WTFMove(*type), name->stringView(m_lexer).toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
+    return AST::FunctionDeclaration({ entryPoint->startOffset(), endOffset, m_lexer.nameSpace() }, { }, entryPointType, WTFMove(*type), name->stringView(m_lexer).toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
 }
 
 auto Parser::parseRegularFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error>
@@ -1015,7 +1028,7 @@ auto Parser::parseRegularFunctionDeclaration() -> Expected<AST::FunctionDeclarat
 
     auto name = consumeTypes<Token::Type::Identifier, Token::Type::OperatorName>();
     if (!name)
-        return Unexpected<Error>(name.error());
+        return makeUnexpected(name.error());
     auto isOperator = name->type == Token::Type::OperatorName;
 
     PARSE(parameters, Parameters);
@@ -1023,7 +1036,7 @@ auto Parser::parseRegularFunctionDeclaration() -> Expected<AST::FunctionDeclarat
 
     auto endOffset = m_lexer.peek().startOffset();
 
-    return AST::FunctionDeclaration({ origin->startOffset(), endOffset }, { }, WTF::nullopt, WTFMove(*type), name->stringView(m_lexer).toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
+    return AST::FunctionDeclaration({ origin->startOffset(), endOffset, m_lexer.nameSpace() }, { }, WTF::nullopt, WTFMove(*type), name->stringView(m_lexer).toString(), WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
 }
 
 auto Parser::parseOperatorFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error>
@@ -1036,7 +1049,7 @@ auto Parser::parseOperatorFunctionDeclaration() -> Expected<AST::FunctionDeclara
     auto endOffset = m_lexer.peek().startOffset();
 
     bool isOperator = true;
-    return AST::FunctionDeclaration({ origin->startOffset(), endOffset }, { }, WTF::nullopt, WTFMove(*type), "operator cast"_str, WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
+    return AST::FunctionDeclaration({ origin->startOffset(), endOffset, m_lexer.nameSpace() }, { }, WTF::nullopt, WTFMove(*type), "operator cast"_str, WTFMove(*parameters), WTFMove(*semantic), isOperator, m_mode);
 }
 
 auto Parser::parseFunctionDeclaration() -> Expected<AST::FunctionDeclaration, Error>
@@ -1085,7 +1098,7 @@ auto Parser::parseBlockBody() -> Expected<AST::Block, Error>
 
     auto endOffset = m_lexer.peek().startOffset();
 
-    return AST::Block({ startOffset, endOffset}, WTFMove(statements));
+    return AST::Block({ startOffset, endOffset, m_lexer.nameSpace() }, WTFMove(statements));
 }
 
 auto Parser::parseIfStatement() -> Expected<AST::IfStatement, Error>
@@ -1107,7 +1120,7 @@ auto Parser::parseIfStatement() -> Expected<AST::IfStatement, Error>
     Vector<UniqueRef<AST::Expression>> castArguments;
     castArguments.append(WTFMove(*conditional));
     auto boolCast = makeUniqueRef<AST::CallExpression>(Token(*origin), "bool"_str, WTFMove(castArguments));
-    return AST::IfStatement({ origin->startOffset(), endOffset }, WTFMove(boolCast), WTFMove(*body), WTFMove(elseBody));
+    return AST::IfStatement({ origin->startOffset(), endOffset, m_lexer.nameSpace() }, WTFMove(boolCast), WTFMove(*body), WTFMove(elseBody));
 }
 
 auto Parser::parseSwitchStatement() -> Expected<AST::SwitchStatement, Error>
@@ -1136,7 +1149,7 @@ auto Parser::parseSwitchCase() -> Expected<AST::SwitchCase, Error>
 {
     auto origin = consumeTypes<Token::Type::Case, Token::Type::Default>();
     if (!origin)
-        return Unexpected<Error>(origin.error());
+        return makeUnexpected(origin.error());
 
     switch (origin->type) {
     case Token::Type::Case: {
@@ -1171,7 +1184,7 @@ auto Parser::parseForLoop() -> Expected<AST::ForLoop, Error>
             if (auto expression = parseExpression())
                 condition = (*expression).moveToUniquePtr();
             else
-                return Unexpected<Error>(expression.error());
+                return makeUnexpected(expression.error());
             CONSUME_TYPE(secondSemicolon, Semicolon);
         }
 
@@ -1180,12 +1193,12 @@ auto Parser::parseForLoop() -> Expected<AST::ForLoop, Error>
             if (auto expression = parseExpression())
                 increment = (*expression).moveToUniquePtr();
             else
-                return Unexpected<Error>(expression.error());
+                return makeUnexpected(expression.error());
             CONSUME_TYPE(rightParenthesis, RightParenthesis);
         }
 
         PARSE(body, Statement);
-        CodeLocation location(origin->codeLocation,  (*body)->codeLocation());
+        CodeLocation location(origin->codeLocation, (*body)->codeLocation());
         return AST::ForLoop(location, WTFMove(initialization), WTFMove(condition), WTFMove(increment), WTFMove(*body));
     };
 
@@ -1243,7 +1256,7 @@ auto Parser::parseVariableDeclaration(Ref<AST::UnnamedType>&& type) -> Expected<
     }
 
     auto endOffset = m_lexer.peek().startOffset();
-    return AST::VariableDeclaration({ origin->startOffset(), endOffset }, WTFMove(qualifiers), { WTFMove(type) }, name->stringView(m_lexer).toString(), WTFMove(*semantic), WTFMove(initializer));
+    return AST::VariableDeclaration({ origin->startOffset(), endOffset, m_lexer.nameSpace() }, WTFMove(qualifiers), { WTFMove(type) }, name->stringView(m_lexer).toString(), WTFMove(*semantic), WTFMove(initializer));
 }
 
 auto Parser::parseVariableDeclarations() -> Expected<AST::VariableDeclarationsStatement, Error>
@@ -1254,7 +1267,7 @@ auto Parser::parseVariableDeclarations() -> Expected<AST::VariableDeclarationsSt
 
     auto firstVariableDeclaration = parseVariableDeclaration(type->copyRef());
     if (!firstVariableDeclaration)
-        return Unexpected<Error>(firstVariableDeclaration.error());
+        return makeUnexpected(firstVariableDeclaration.error());
 
     Vector<UniqueRef<AST::VariableDeclaration>> result;
     result.append(makeUniqueRef<AST::VariableDeclaration>(WTFMove(*firstVariableDeclaration)));
@@ -1262,12 +1275,12 @@ auto Parser::parseVariableDeclarations() -> Expected<AST::VariableDeclarationsSt
     while (tryType(Token::Type::Comma)) {
         auto variableDeclaration = parseVariableDeclaration(type->copyRef());
         if (!variableDeclaration)
-            return Unexpected<Error>(variableDeclaration.error());
+            return makeUnexpected(variableDeclaration.error());
         result.append(makeUniqueRef<AST::VariableDeclaration>(WTFMove(*variableDeclaration)));
     }
 
     auto endOffset = m_lexer.peek().startOffset();
-    return AST::VariableDeclarationsStatement({ origin->startOffset(), endOffset }, WTFMove(result));
+    return AST::VariableDeclarationsStatement({ origin->startOffset(), endOffset, m_lexer.nameSpace() }, WTFMove(result));
 }
 
 auto Parser::parseStatement() -> Expected<UniqueRef<AST::Statement>, Error>
@@ -1388,7 +1401,7 @@ auto Parser::parseEffectfulExpression() -> Expected<UniqueRef<AST::Statement>, E
     if (expressions.size() == 1)
         return { makeUniqueRef<AST::EffectfulExpressionStatement>(WTFMove(expressions[0])) };
     unsigned endOffset = m_lexer.peek().startOffset();
-    CodeLocation location(origin->startOffset(), endOffset);
+    CodeLocation location(origin->startOffset(), endOffset, m_lexer.nameSpace());
     auto commaExpression = makeUniqueRef<AST::CommaExpression>(location, WTFMove(expressions));
     return { makeUniqueRef<AST::EffectfulExpressionStatement>(WTFMove(commaExpression)) };
 }
@@ -1530,7 +1543,7 @@ auto Parser::parseExpression() -> Expected<UniqueRef<AST::Expression>, Error>
     if (expressions.size() == 1)
         return WTFMove(expressions[0]);
     auto endOffset = m_lexer.peek().startOffset();
-    CodeLocation location(startOffset, endOffset);
+    CodeLocation location(startOffset, endOffset, m_lexer.nameSpace());
     return { makeUniqueRef<AST::CommaExpression>(location, WTFMove(expressions)) };
 }
 
@@ -1564,7 +1577,7 @@ auto Parser::completeAssignment(UniqueRef<AST::Expression>&& left) -> Expected<U
         Token::Type::RightShiftEquals,
         Token::Type::LeftShiftEquals>();
     if (!assignmentOperator)
-        return Unexpected<Error>(assignmentOperator.error());
+        return makeUnexpected(assignmentOperator.error());
 
     PARSE(right, PossibleTernaryConditional);
     CodeLocation location = { left->codeLocation(), (*right)->codeLocation() };
@@ -1636,23 +1649,23 @@ auto Parser::parsePossibleTernaryConditional() -> Expected<UniqueRef<AST::Expres
 
     expression = completePossibleShift(WTFMove(*expression));
     if (!expression)
-        return Unexpected<Error>(expression.error());
+        return makeUnexpected(expression.error());
 
     expression = completePossibleMultiply(WTFMove(*expression));
     if (!expression)
-        return Unexpected<Error>(expression.error());
+        return makeUnexpected(expression.error());
 
     expression = completePossibleAdd(WTFMove(*expression));
     if (!expression)
-        return Unexpected<Error>(expression.error());
+        return makeUnexpected(expression.error());
 
     expression = completePossibleRelationalBinaryOperation(WTFMove(*expression));
     if (!expression)
-        return Unexpected<Error>(expression.error());
+        return makeUnexpected(expression.error());
 
     expression = completePossibleLogicalBinaryOperation(WTFMove(*expression));
     if (!expression)
-        return Unexpected<Error>(expression.error());
+        return makeUnexpected(expression.error());
 
     PEEK(nextToken);
     if (nextToken->type == Token::Type::QuestionMark)
@@ -2028,25 +2041,25 @@ auto Parser::parseTerm() -> Expected<UniqueRef<AST::Expression>, Error>
         Token::Type::Identifier,
         Token::Type::LeftParenthesis>();
     if (!type)
-        return Unexpected<Error>(type.error());
+        return makeUnexpected(type.error());
 
     switch (type->type) {
     case Token::Type::IntLiteral: {
         auto value = intLiteralToInt(type->stringView(m_lexer));
         if (!value)
-            return Unexpected<Error>(value.error());
+            return makeUnexpected(value.error());
         return { makeUniqueRef<AST::IntegerLiteral>(*type, *value) };
     }
     case Token::Type::UintLiteral: {
         auto value = uintLiteralToUint(type->stringView(m_lexer));
         if (!value)
-            return Unexpected<Error>(value.error());
+            return makeUnexpected(value.error());
         return { makeUniqueRef<AST::UnsignedIntegerLiteral>(*type, *value) };
     }
     case Token::Type::FloatLiteral: {
         auto value = floatLiteralToFloat(type->stringView(m_lexer));
         if (!value)
-            return Unexpected<Error>(value.error());
+            return makeUnexpected(value.error());
         return { makeUniqueRef<AST::FloatLiteral>(*type, *value) };
     }
     case Token::Type::Null:
index be0532d..6c07c22 100644 (file)
@@ -31,7 +31,6 @@
 #include "WHLSLError.h"
 #include "WHLSLLexer.h"
 #include "WHLSLParsingMode.h"
-#include "WHLSLProgram.h"
 #include <wtf/Expected.h>
 #include <wtf/Optional.h>
 #include <wtf/PrintStream.h>
@@ -40,9 +39,11 @@ namespace WebCore {
 
 namespace WHLSL {
 
+class Program;
+
 class Parser {
 public:
-    Expected<void, Error> parse(Program&, StringView, ParsingMode);
+    Expected<void, Error> parse(Program&, StringView, ParsingMode, AST::NameSpace);
 
 private:
     // FIXME: We should not need this
index 73f4832..1195888 100644 (file)
@@ -38,6 +38,7 @@
 #include "WHLSLLiteralTypeChecker.h"
 #include "WHLSLMetalCodeGenerator.h"
 #include "WHLSLNameResolver.h"
+#include "WHLSLNameSpace.h"
 #include "WHLSLParser.h"
 #include "WHLSLPreserveVariableLifetimes.h"
 #include "WHLSLProgram.h"
@@ -59,6 +60,35 @@ namespace WebCore {
 
 namespace WHLSL {
 
+struct ShaderModule {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+
+    ShaderModule(const String& whlslSource)
+        : whlslSource(whlslSource)
+    {
+    }
+
+    String whlslSource;
+};
+
+}
+
+}
+
+namespace std {
+
+void default_delete<WebCore::WHLSL::ShaderModule>::operator()(WebCore::WHLSL::ShaderModule* shaderModule) const
+{
+    delete shaderModule;
+}
+
+}
+
+namespace WebCore {
+
+namespace WHLSL {
+
 static constexpr bool dumpASTBeforeEachPass = false;
 static constexpr bool dumpASTAfterParsing = false;
 static constexpr bool dumpASTAtEnd = false;
@@ -124,13 +154,18 @@ public:
         }
     }
 
-
 private:
     String m_phaseName;
     PhaseTimes& m_phaseTimes;
     MonotonicTime m_start;
 };
 
+UniqueRef<ShaderModule> createShaderModule(const String& whlslSource)
+{
+    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=200872 We should consider moving as much work from prepare() into here as possible.
+    return makeUniqueRef<ShaderModule>(whlslSource);
+}
+
 #define CHECK_PASS(pass, ...) \
     do { \
         dumpASTBetweenEachPassIfNeeded(program, "AST before " # pass); \
@@ -138,8 +173,8 @@ private:
         auto result = pass(__VA_ARGS__); \
         if (!result) { \
             if (dumpPassFailure) \
-                dataLogLn("failed pass: " # pass, Lexer::errorString(whlslSource, result.error())); \
-            return makeUnexpected(Lexer::errorString(whlslSource, result.error())); \
+                dataLogLn("failed pass: " # pass, Lexer::errorString(result.error(), whlslSource1, whlslSource2)); \
+            return makeUnexpected(Lexer::errorString(result.error(), whlslSource1, whlslSource2)); \
         } \
     } while (0)
 
@@ -150,19 +185,31 @@ private:
         pass(__VA_ARGS__); \
     } while (0)
 
-static Expected<Program, String> prepareShared(PhaseTimes& phaseTimes, String& whlslSource)
+static Expected<Program, String> prepareShared(PhaseTimes& phaseTimes, const String& whlslSource1, const String* whlslSource2 = nullptr)
 {
     Program program;
     Parser parser;
 
     {
+        program.nameContext().setCurrentNameSpace(AST::NameSpace::NameSpace1);
+
         PhaseTimer phaseTimer("parse", phaseTimes);
-        auto parseResult = parser.parse(program, whlslSource, ParsingMode::User);
+        auto parseResult = parser.parse(program, whlslSource1, ParsingMode::User, AST::NameSpace::NameSpace1);
         if (!parseResult) {
             if (dumpPassFailure)
-                dataLogLn("failed to parse the program: ", Lexer::errorString(whlslSource, parseResult.error()));
-            return makeUnexpected(Lexer::errorString(whlslSource, parseResult.error()));
+                dataLogLn("failed to parse the program: ", Lexer::errorString(parseResult.error(), whlslSource1, whlslSource2));
+            return makeUnexpected(Lexer::errorString(parseResult.error(), whlslSource1, whlslSource2));
+        }
+        if (whlslSource2) {
+            program.nameContext().setCurrentNameSpace(AST::NameSpace::NameSpace2);
+            auto parseResult = parser.parse(program, *whlslSource2, ParsingMode::User, AST::NameSpace::NameSpace2);
+            if (!parseResult) {
+                if (dumpPassFailure)
+                    dataLogLn("failed to parse the program: ", Lexer::errorString(parseResult.error(), whlslSource1, whlslSource2));
+                return makeUnexpected(Lexer::errorString(parseResult.error(), whlslSource1, whlslSource2));
+            }
         }
+        program.nameContext().setCurrentNameSpace(AST::NameSpace::StandardLibrary);
     }
 
     {
@@ -200,23 +247,29 @@ static Expected<Program, String> prepareShared(PhaseTimes& phaseTimes, String& w
     return program;
 }
 
-Expected<RenderPrepareResult, String> prepare(String& whlslSource, RenderPipelineDescriptor& renderPipelineDescriptor)
+Expected<RenderPrepareResult, String> prepare(const ShaderModule& vertexShaderModule, const ShaderModule* fragmentShaderModule, RenderPipelineDescriptor& renderPipelineDescriptor)
 {
     PhaseTimes phaseTimes;
     Metal::RenderMetalCode generatedCode;
 
     {
         PhaseTimer phaseTimer("prepare total", phaseTimes);
-        auto program = prepareShared(phaseTimes, whlslSource);
+        const String* secondShader = nullptr;
+        bool distinctFragmentShader = false;
+        if (fragmentShaderModule && fragmentShaderModule != &vertexShaderModule) {
+            secondShader = &fragmentShaderModule->whlslSource;
+            distinctFragmentShader = true;
+        }
+        auto program = prepareShared(phaseTimes, vertexShaderModule.whlslSource, secondShader);
         if (!program)
             return makeUnexpected(program.error());
 
         Optional<MatchedRenderSemantics> matchedSemantics;
         {
             PhaseTimer phaseTimer("matchSemantics", phaseTimes);
-            matchedSemantics = matchSemantics(*program, renderPipelineDescriptor);
+            matchedSemantics = matchSemantics(*program, renderPipelineDescriptor, distinctFragmentShader, fragmentShaderModule);
             if (!matchedSemantics)
-                return makeUnexpected(Lexer::errorString(whlslSource, Error("Could not match semantics"_str)));
+                return makeUnexpected(Lexer::errorString(Error("Could not match semantics"_str), vertexShaderModule.whlslSource, secondShader));
         }
 
         {
@@ -234,7 +287,7 @@ Expected<RenderPrepareResult, String> prepare(String& whlslSource, RenderPipelin
     return result;
 }
 
-Expected<ComputePrepareResult, String> prepare(String& whlslSource, ComputePipelineDescriptor& computePipelineDescriptor)
+Expected<ComputePrepareResult, String> prepare(const ShaderModule& shaderModule, ComputePipelineDescriptor& computePipelineDescriptor)
 {
     PhaseTimes phaseTimes;
     Metal::ComputeMetalCode generatedCode;
@@ -242,7 +295,7 @@ Expected<ComputePrepareResult, String> prepare(String& whlslSource, ComputePipel
 
     {
         PhaseTimer phaseTimer("prepare total", phaseTimes);
-        auto program = prepareShared(phaseTimes, whlslSource);
+        auto program = prepareShared(phaseTimes, shaderModule.whlslSource);
         if (!program)
             return makeUnexpected(program.error());
 
@@ -251,14 +304,14 @@ Expected<ComputePrepareResult, String> prepare(String& whlslSource, ComputePipel
             PhaseTimer phaseTimer("matchSemantics", phaseTimes);
             matchedSemantics = matchSemantics(*program, computePipelineDescriptor);
             if (!matchedSemantics)
-                return makeUnexpected(Lexer::errorString(whlslSource, Error("Could not match semantics"_str)));
+                return makeUnexpected(Lexer::errorString(Error("Could not match semantics"_str), shaderModule.whlslSource));
         }
 
         {
             PhaseTimer phaseTimer("computeDimensions", phaseTimes);
             computeDimensions = WHLSL::computeDimensions(*program, *matchedSemantics->shader);
             if (!computeDimensions)
-                return makeUnexpected(Lexer::errorString(whlslSource, Error("Could not match compute dimensions"_str)));
+                return makeUnexpected(Lexer::errorString(Error("Could not match compute dimensions"_str), shaderModule.whlslSource));
         }
 
         {
index 5da77f5..697f9be 100644 (file)
@@ -30,6 +30,7 @@
 #include "WHLSLError.h"
 #include "WHLSLMangledNames.h"
 #include "WHLSLPipelineDescriptor.h"
+#include <wtf/UniqueRef.h>
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/WTFString.h>
 
@@ -37,14 +38,35 @@ namespace WebCore {
 
 namespace WHLSL {
 
+// Hide the contents of the ShaderModule. Clients of the compiler shouldn't care what's inside it.
+struct ShaderModule;
+
+}
+
+}
+
+namespace std {
+
+template<> struct default_delete<WebCore::WHLSL::ShaderModule> {
+    void operator()(WebCore::WHLSL::ShaderModule*) const;
+};
+
+}
+
+namespace WebCore {
+
+namespace WHLSL {
+
 constexpr bool dumpMetalCompileTimes = false;
 
+UniqueRef<ShaderModule> createShaderModule(const String& whlslSource);
+
 struct RenderPrepareResult {
     StringBuilder metalSource;
     Metal::MangledFunctionName mangledVertexEntryPointName;
     Metal::MangledFunctionName mangledFragmentEntryPointName;
 };
-Expected<RenderPrepareResult, String> prepare(String& whlslSource, RenderPipelineDescriptor&);
+Expected<RenderPrepareResult, String> prepare(const ShaderModule& vertexShaderModule, const ShaderModule* fragmentShaderModule, RenderPipelineDescriptor&);
 
 struct ComputeDimensions {
     unsigned width;
@@ -57,7 +79,7 @@ struct ComputePrepareResult {
     Metal::MangledFunctionName mangledEntryPointName;
     ComputeDimensions computeDimensions;
 };
-Expected<ComputePrepareResult, String> prepare(String& whlslSource, ComputePipelineDescriptor&);
+Expected<ComputePrepareResult, String> prepare(const ShaderModule&, ComputePipelineDescriptor&);
 
 } // namespace WHLSL
 
index 40baf09..90861ec 100644 (file)
@@ -28,6 +28,7 @@
 #if ENABLE(WEBGPU)
 
 #include "WHLSLEnumerationDefinition.h"
+#include "WHLSLError.h"
 #include "WHLSLFunctionDefinition.h"
 #include "WHLSLIntrinsics.h"
 #include "WHLSLNameContext.h"
@@ -46,38 +47,38 @@ public:
     Program() = default;
     Program(Program&&) = default;
 
-    bool append(AST::TypeDefinition&& typeDefinition)
+    Expected<void, Error> append(AST::TypeDefinition&& typeDefinition)
     {
         m_typeDefinitions.append(makeUniqueRef<AST::TypeDefinition>(WTFMove(typeDefinition)));
         return m_nameContext.add(m_typeDefinitions.last());
     }
 
-    bool append(AST::StructureDefinition&& structureDefinition)
+    Expected<void, Error> append(AST::StructureDefinition&& structureDefinition)
     {
         m_structureDefinitions.append(makeUniqueRef<AST::StructureDefinition>(WTFMove(structureDefinition)));
         return m_nameContext.add(m_structureDefinitions.last());
     }
 
-    bool append(AST::EnumerationDefinition&& enumerationDefinition)
+    Expected<void, Error> append(AST::EnumerationDefinition&& enumerationDefinition)
     {
         m_enumerationDefinitions.append(makeUniqueRef<AST::EnumerationDefinition>(WTFMove(enumerationDefinition)));
         return m_nameContext.add(m_enumerationDefinitions.last());
     }
 
-    bool append(AST::FunctionDefinition&& functionDefinition)
+    Expected<void, Error> append(AST::FunctionDefinition&& functionDefinition)
     {
         m_functionDefinitions.append(makeUniqueRef<AST::FunctionDefinition>(WTFMove(functionDefinition)));
         return m_nameContext.add(m_functionDefinitions.last());
     }
 
-    bool append(AST::NativeFunctionDeclaration&& nativeFunctionDeclaration)
+    Expected<void, Error> append(AST::NativeFunctionDeclaration&& nativeFunctionDeclaration)
     {
         m_nativeFunctionDeclarations.append(makeUniqueRef<AST::NativeFunctionDeclaration>(WTFMove(nativeFunctionDeclaration)));
         m_intrinsics.add(m_nativeFunctionDeclarations.last());
         return m_nameContext.add(m_nativeFunctionDeclarations.last());
     }
 
-    bool append(AST::NativeTypeDeclaration&& nativeTypeDeclaration)
+    Expected<void, Error> append(AST::NativeTypeDeclaration&& nativeTypeDeclaration)
     {
         m_nativeTypeDeclarations.append(makeUniqueRef<AST::NativeTypeDeclaration>(WTFMove(nativeTypeDeclaration)));
         m_intrinsics.add(m_nativeTypeDeclarations.last());
index 424e795..7c65697 100644 (file)
@@ -52,12 +52,19 @@ static unsigned conversionCost(AST::FunctionDeclaration& candidate, const Vector
 }
 
 template <typename TypeKind>
-AST::FunctionDeclaration* resolveFunctionOverloadImpl(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, TypeKind* castReturnType)
+static AST::FunctionDeclaration* resolveFunctionOverloadImpl(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, TypeKind* castReturnType, AST::NameSpace nameSpace)
 {
     Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1> candidates;
     for (auto& possibleFunction : possibleFunctions) {
         if (possibleFunction.get().entryPointType())
             continue;
+        if (nameSpace == AST::NameSpace::StandardLibrary) {
+            if (possibleFunction.get().nameSpace() != AST::NameSpace::StandardLibrary)
+                continue;
+        } else {
+            if (possibleFunction.get().nameSpace() != AST::NameSpace::StandardLibrary && possibleFunction.get().nameSpace() != nameSpace)
+                continue;
+        }
         if (inferTypesForCall(possibleFunction.get(), argumentTypes, castReturnType))
             candidates.append(possibleFunction.get());
     }
@@ -77,19 +84,19 @@ AST::FunctionDeclaration* resolveFunctionOverloadImpl(Vector<std::reference_wrap
     return nullptr;
 }
 
-AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes)
+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NameSpace nameSpace)
 {
-    return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, static_cast<AST::NamedType*>(nullptr));
+    return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, static_cast<AST::NamedType*>(nullptr), nameSpace);
 }
 
-AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType)
+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType, AST::NameSpace nameSpace)
 {
-    return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, castReturnType);
+    return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, castReturnType, nameSpace);
 }
 
-AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::UnnamedType* castReturnType)
+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::UnnamedType* castReturnType, AST::NameSpace nameSpace)
 {
-    return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, castReturnType);
+    return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, castReturnType, nameSpace);
 }
 
 AST::NamedType* resolveTypeOverloadImpl(Vector<std::reference_wrapper<AST::NamedType>, 1>& possibleTypes, AST::TypeArguments& typeArguments)
index 3d34ab6..3b195a2 100644 (file)
@@ -43,9 +43,9 @@ class NamedType;
 
 }
 
-AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes);
-AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType);
-AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::UnnamedType* castReturnType);
+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NameSpace);
+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType, AST::NameSpace);
+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::UnnamedType* castReturnType, AST::NameSpace);
 AST::NamedType* resolveTypeOverloadImpl(Vector<std::reference_wrapper<AST::NamedType>, 1>&, AST::TypeArguments&);
 
 }
index 157a4bf..2cc7d7d 100644 (file)
@@ -45,16 +45,6 @@ namespace WebCore {
 
 namespace WHLSL {
 
-static AST::FunctionDefinition* findEntryPoint(Vector<UniqueRef<AST::FunctionDefinition>>& functionDefinitions, String& name)
-{
-    auto iterator = std::find_if(functionDefinitions.begin(), functionDefinitions.end(), [&](AST::FunctionDefinition& functionDefinition) {
-        return functionDefinition.entryPointType() && functionDefinition.name() == name;
-    });
-    if (iterator == functionDefinitions.end())
-        return nullptr;
-    return &*iterator;
-};
-
 static bool matchMode(Binding::BindingDetails bindingType, AST::ResourceSemantic::Mode mode)
 {
     return WTF::visit(WTF::makeVisitor([&](UniformBufferBinding) -> bool {
@@ -290,46 +280,59 @@ static bool matchDepthAttachment(Vector<EntryPointItem>& fragmentOutputs, Option
     return false;
 }
 
-Optional<MatchedRenderSemantics> matchSemantics(Program& program, RenderPipelineDescriptor& renderPipelineDescriptor)
+Optional<MatchedRenderSemantics> matchSemantics(Program& program, RenderPipelineDescriptor& renderPipelineDescriptor, bool distinctFragmentShader, bool fragmentShaderExists)
 {
-    auto vertexShaderEntryPoint = findEntryPoint(program.functionDefinitions(), renderPipelineDescriptor.vertexEntryPointName);
-    auto fragmentShaderEntryPoint = findEntryPoint(program.functionDefinitions(), renderPipelineDescriptor.fragmentEntryPointName);
-    if (!vertexShaderEntryPoint || !fragmentShaderEntryPoint)
+    auto vertexFunctions = program.nameContext().getFunctions(renderPipelineDescriptor.vertexEntryPointName, AST::NameSpace::NameSpace1);
+    if (vertexFunctions.size() != 1 || !vertexFunctions[0].get().entryPointType() || !is<AST::FunctionDefinition>(vertexFunctions[0].get()))
         return WTF::nullopt;
-    auto vertexShaderEntryPointItems = gatherEntryPointItems(program.intrinsics(), *vertexShaderEntryPoint);
-    auto fragmentShaderEntryPointItems = gatherEntryPointItems(program.intrinsics(), *fragmentShaderEntryPoint);
-    if (!vertexShaderEntryPointItems || !fragmentShaderEntryPointItems)
+    auto& vertexShaderEntryPoint = downcast<AST::FunctionDefinition>(vertexFunctions[0].get());
+    auto vertexShaderEntryPointItems = gatherEntryPointItems(program.intrinsics(), vertexShaderEntryPoint);
+    if (!vertexShaderEntryPointItems)
         return WTF::nullopt;
     auto vertexShaderResourceMap = matchResources(vertexShaderEntryPointItems->inputs, renderPipelineDescriptor.layout, ShaderStage::Vertex);
-    auto fragmentShaderResourceMap = matchResources(fragmentShaderEntryPointItems->inputs, renderPipelineDescriptor.layout, ShaderStage::Fragment);
-    if (!vertexShaderResourceMap || !fragmentShaderResourceMap)
-        return WTF::nullopt;
-    if (!matchInputsOutputs(vertexShaderEntryPointItems->outputs, fragmentShaderEntryPointItems->inputs))
+    if (!vertexShaderResourceMap)
         return WTF::nullopt;
     auto matchedVertexAttributes = matchVertexAttributes(vertexShaderEntryPointItems->inputs, renderPipelineDescriptor.vertexAttributes, program.intrinsics());
     if (!matchedVertexAttributes)
         return WTF::nullopt;
+    if (!fragmentShaderExists)
+        return {{ &vertexShaderEntryPoint, nullptr, *vertexShaderEntryPointItems, EntryPointItems(), *vertexShaderResourceMap, HashMap<Binding*, size_t>(), *matchedVertexAttributes, HashMap<AttachmentDescriptor*, size_t>() }};
+
+    auto fragmentNameSpace = distinctFragmentShader ? AST::NameSpace::NameSpace2 : AST::NameSpace::NameSpace1;
+    auto fragmentFunctions = program.nameContext().getFunctions(renderPipelineDescriptor.fragmentEntryPointName, fragmentNameSpace);
+    if (fragmentFunctions.size() != 1 || !fragmentFunctions[0].get().entryPointType() || !is<AST::FunctionDefinition>(fragmentFunctions[0].get()))
+        return WTF::nullopt;
+    auto& fragmentShaderEntryPoint = downcast<AST::FunctionDefinition>(fragmentFunctions[0].get());
+    auto fragmentShaderEntryPointItems = gatherEntryPointItems(program.intrinsics(), fragmentShaderEntryPoint);
+    if (!fragmentShaderEntryPointItems)
+        return WTF::nullopt;
+    auto fragmentShaderResourceMap = matchResources(fragmentShaderEntryPointItems->inputs, renderPipelineDescriptor.layout, ShaderStage::Fragment);
+    if (!fragmentShaderResourceMap)
+        return WTF::nullopt;
+    if (!matchInputsOutputs(vertexShaderEntryPointItems->outputs, fragmentShaderEntryPointItems->inputs))
+        return WTF::nullopt;
     auto matchedColorAttachments = matchColorAttachments(fragmentShaderEntryPointItems->outputs, renderPipelineDescriptor.attachmentsStateDescriptor.attachmentDescriptors, program.intrinsics());
     if (!matchedColorAttachments)
         return WTF::nullopt;
     if (!matchDepthAttachment(fragmentShaderEntryPointItems->outputs, renderPipelineDescriptor.attachmentsStateDescriptor.depthStencilAttachmentDescriptor, program.intrinsics()))
         return WTF::nullopt;
-    return {{ vertexShaderEntryPoint, fragmentShaderEntryPoint, *vertexShaderEntryPointItems, *fragmentShaderEntryPointItems, *vertexShaderResourceMap, *fragmentShaderResourceMap, *matchedVertexAttributes, *matchedColorAttachments }};
+    return {{ &vertexShaderEntryPoint, &fragmentShaderEntryPoint, *vertexShaderEntryPointItems, *fragmentShaderEntryPointItems, *vertexShaderResourceMap, *fragmentShaderResourceMap, *matchedVertexAttributes, *matchedColorAttachments }};
 }
 
 Optional<MatchedComputeSemantics> matchSemantics(Program& program, ComputePipelineDescriptor& computePipelineDescriptor)
 {
-    auto entryPoint = findEntryPoint(program.functionDefinitions(), computePipelineDescriptor.entryPointName);
-    if (!entryPoint)
+    auto functions = program.nameContext().getFunctions(computePipelineDescriptor.entryPointName, AST::NameSpace::NameSpace1);
+    if (functions.size() != 1 || !functions[0].get().entryPointType() || !is<AST::FunctionDefinition>(functions[0].get()))
         return WTF::nullopt;
-    auto entryPointItems = gatherEntryPointItems(program.intrinsics(), *entryPoint);
+    auto& entryPoint = downcast<AST::FunctionDefinition>(functions[0].get());
+    auto entryPointItems = gatherEntryPointItems(program.intrinsics(), entryPoint);
     if (!entryPointItems)
         return WTF::nullopt;
     ASSERT(entryPointItems->outputs.isEmpty());
     auto resourceMap = matchResources(entryPointItems->inputs, computePipelineDescriptor.layout, ShaderStage::Compute);
     if (!resourceMap)
         return WTF::nullopt;
-    return {{ entryPoint, *entryPointItems, *resourceMap }};
+    return {{ &entryPoint, *entryPointItems, *resourceMap }};
 }
 
 } // namespace WHLSL
index bdff4bb..369be4b 100644 (file)
@@ -48,7 +48,7 @@ struct MatchedRenderSemantics {
     HashMap<AttachmentDescriptor*, size_t> matchedColorAttachments;
 };
 
-Optional<MatchedRenderSemantics> matchSemantics(Program&, RenderPipelineDescriptor&);
+Optional<MatchedRenderSemantics> matchSemantics(Program&, RenderPipelineDescriptor&, bool distinctFragmentShader, bool fragmentShaderExists);
 
 struct MatchedComputeSemantics {
     AST::FunctionDefinition* shader;
index 24069ec..331932f 100644 (file)
@@ -77,23 +77,22 @@ private:
     HashSet<String> m_functionNames;
 };
 
-void includeStandardLibrary(Program& program, Parser& parser, bool parseFullStandardLibrary)
+Expected<void, Error> includeStandardLibrary(Program& program, Parser& parser, bool parseFullStandardLibrary)
 {
     static NeverDestroyed<String> standardLibrary(decompressAndDecodeStandardLibrary());
     if (parseFullStandardLibrary) {
-        auto parseResult = parser.parse(program, standardLibrary.get(), ParsingMode::StandardLibrary);
-        if (!parseResult) {
-            dataLogLn("failed to parse the (full) standard library: ", Lexer::errorString(StringView(standardLibrary), parseResult.error()));
-            ASSERT_NOT_REACHED();
-        }
-        return;
+        auto parseResult = parser.parse(program, standardLibrary.get(), ParsingMode::StandardLibrary, AST::NameSpace::StandardLibrary);
+        if (!parseResult)
+            return makeUnexpected(parseResult.error());
+        return { };
     }
 
     static NeverDestroyed<HashMap<String, SubstringLocation>> standardLibraryFunctionMap(computeStandardLibraryFunctionMap());
 
     auto stringView = StringView(standardLibrary.get()).substring(0, firstFunctionOffsetInStandardLibrary());
-    auto parseResult = parser.parse(program, stringView, ParsingMode::StandardLibrary);
-    ASSERT_UNUSED(parseResult, parseResult);
+    auto parseResult = parser.parse(program, stringView, ParsingMode::StandardLibrary, AST::NameSpace::StandardLibrary);
+    if (!parseResult)
+        return makeUnexpected(parseResult.error());
 
     NameFinder nameFinder;
     nameFinder.Visitor::visit(program);
@@ -102,6 +101,10 @@ void includeStandardLibrary(Program& program, Parser& parser, bool parseFullStan
     // The name of a call to a cast operator is the name of the type, so we can't match them up correctly.
     // Instead, just include all casting operators.
     functionNames.add("operator cast"_str);
+    // We need to make sure that an author can't write a function with the same signature as anything in the standard library.
+    // If they do so, we need to make sure it collides, so we include all potential duplicates here, and the "checkDuplicateFunctions" pass enforces it.
+    for (auto& functionDefinition : program.functionDefinitions())
+        functionNames.add(functionDefinition->name());
     while (!functionNames.isEmpty()) {
         auto nativeFunctionDeclarationsCount = program.nativeFunctionDeclarations().size();
         auto functionDefinitionsCount = program.functionDefinitions().size();
@@ -118,12 +121,9 @@ void includeStandardLibrary(Program& program, Parser& parser, bool parseFullStan
                 dataLogLn("---------------------------");
             }
             auto start = program.functionDefinitions().size();
-            auto parseResult = parser.parse(program, stringView, ParsingMode::StandardLibrary);
-            if (!parseResult) {
-                dataLogLn("failed to parse the (partial) standard library: ", Lexer::errorString(stringView, parseResult.error()));
-                ASSERT_NOT_REACHED();
-                return;
-            }
+            auto parseResult = parser.parse(program, stringView, ParsingMode::StandardLibrary, AST::NameSpace::StandardLibrary);
+            if (!parseResult)
+                return makeUnexpected(parseResult.error());
             if (verbose) {
                 if (program.functionDefinitions().size() != start)
                     dataLogLn("non native stdlib function: '", name, "'");
@@ -136,6 +136,7 @@ void includeStandardLibrary(Program& program, Parser& parser, bool parseFullStan
             nameFinder.Visitor::visit(program.functionDefinitions()[functionDefinitionsCount]);
         functionNames = nameFinder.takeFunctionNames();
     }
+    return { };
 }
 
 } // namespace WHLSL
index caf6a41..018ce7c 100644 (file)
@@ -27,6 +27,8 @@
 
 #if ENABLE(WEBGPU)
 
+#include "WHLSLError.h"
+#include <wtf/Expected.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -36,7 +38,7 @@ namespace WHLSL {
 class Parser;
 class Program;
 
-void includeStandardLibrary(Program&, Parser&, bool parseFullStandardLibrary);
+Expected<void, Error> includeStandardLibrary(Program&, Parser&, bool parseFullStandardLibrary);
 
 }
 
index b4ab509..3852d3d 100644 (file)
                C234A9B521E92C23003C984D /* WHLSLSynthesizeStructureAccessors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLSynthesizeStructureAccessors.h; sourceTree = "<group>"; };
                C234A9B621E92CC0003C984D /* WHLSLIntrinsics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLIntrinsics.h; sourceTree = "<group>"; };
                C234A9B721E92CC1003C984D /* WHLSLIntrinsics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLIntrinsics.cpp; sourceTree = "<group>"; };
+               C2398EBD230A1B7600641507 /* WHLSLNameSpace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLNameSpace.h; sourceTree = "<group>"; };
                C2458E611FE8979E00594759 /* FontCacheCoreText.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FontCacheCoreText.h; sourceTree = "<group>"; };
                C24A57AF21FAD53F004C6DD1 /* WHLSLPipelineDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLPipelineDescriptor.h; sourceTree = "<group>"; };
                C24A57B221FB8DDA004C6DD1 /* WHLSLSemanticMatcher.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLSemanticMatcher.cpp; sourceTree = "<group>"; };
                                C21BF72D21CD89E900227979 /* WHLSLMakeArrayReferenceExpression.h */,
                                C21BF72C21CD89E900227979 /* WHLSLMakePointerExpression.h */,
                                1C33277121CF0BE1000DC9F2 /* WHLSLNamedType.h */,
+                               C2398EBD230A1B7600641507 /* WHLSLNameSpace.h */,
                                C21BF72321CD89E100227979 /* WHLSLNativeFunctionDeclaration.h */,
                                C21BF72A21CD89E700227979 /* WHLSLNativeTypeDeclaration.h */,
                                C21BF70721CD89C800227979 /* WHLSLNullLiteral.h */,
index ce3341e..88308d6 100644 (file)
@@ -27,6 +27,7 @@
 
 #if ENABLE(WEBGPU)
 
+#include "WHLSLPrepare.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
@@ -46,15 +47,15 @@ class GPUShaderModule : public RefCounted<GPUShaderModule> {
 public:
     static RefPtr<GPUShaderModule> tryCreate(const GPUDevice&, const GPUShaderModuleDescriptor&);
 
-    PlatformShaderModule* platformShaderModule() const { return m_whlslSource.isNull() ? m_platformShaderModule.get() : nullptr; }
-    const String& whlslSource() const { return m_whlslSource; }
+    PlatformShaderModule* platformShaderModule() const { return m_whlslModule ? nullptr : m_platformShaderModule.get(); }
+    const WHLSL::ShaderModule* whlslModule() const { return m_whlslModule.get(); }
 
 private:
     GPUShaderModule(PlatformShaderModuleSmartPtr&&);
-    GPUShaderModule(String&& whlslSource);
+    GPUShaderModule(UniqueRef<WHLSL::ShaderModule>&& whlslModule);
 
     PlatformShaderModuleSmartPtr m_platformShaderModule;
-    String m_whlslSource;
+    std::unique_ptr<WHLSL::ShaderModule> m_whlslModule;
 };
 
 } // namespace WebCore
index 1cefeed..e01b75a 100644 (file)
@@ -70,13 +70,11 @@ static Optional<WHLSL::ComputeDimensions> trySetFunctions(const GPUPipelineStage
     WHLSL::ComputeDimensions computeDimensions { 1, 1, 1 };
 
     if (whlslDescriptor) {
-        // WHLSL functions are compiled to MSL first.
-        String whlslSource = computeStage.module->whlslSource();
-        ASSERT(!whlslSource.isNull());
+        ASSERT(computeStage.module->whlslModule());
 
         whlslDescriptor->entryPointName = computeStage.entryPoint;
 
-        auto whlslCompileResult = WHLSL::prepare(whlslSource, *whlslDescriptor);
+        auto whlslCompileResult = WHLSL::prepare(*computeStage.module->whlslModule(), *whlslDescriptor);
         if (!whlslCompileResult) {
             errorScopes.generatePrefixedError(makeString("WHLSL compile error: ", whlslCompileResult.error()));
             return WTF::nullopt;
@@ -134,7 +132,7 @@ static Optional<ConvertResult> convertComputePipelineDescriptor(const GPUCompute
 
     const auto& computeStage = descriptor.computeStage;
 
-    bool isWhlsl = !computeStage.module->whlslSource().isNull();
+    bool isWhlsl = computeStage.module->whlslModule();
 
     Optional<WHLSL::ComputePipelineDescriptor> whlslDescriptor;
     if (isWhlsl)
index 86aadd8..f4a0371 100644 (file)
@@ -357,7 +357,7 @@ static bool trySetMetalFunctions(MTLLibrary *vertexMetalLibrary, MTLLibrary *fra
         BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
         // However, fragment shaders are optional.
-        if (!fragmentMetalLibrary)
+        if (!fragmentMetalLibrary || fragmentEntryPointName.isNull())
             return true;
 
         auto function = adoptNS([fragmentMetalLibrary newFunctionWithName:fragmentEntryPointName]);
@@ -382,15 +382,14 @@ static bool trySetFunctions(const GPUPipelineStageDescriptor& vertexStage, const
     String vertexEntryPoint, fragmentEntryPoint;
 
     if (whlslDescriptor) {
-        // WHLSL functions are compiled to MSL first.
-        String whlslSource = vertexStage.module->whlslSource();
-        ASSERT(!whlslSource.isNull());
+        ASSERT(vertexStage.module->whlslModule());
+        ASSERT(!fragmentStage || fragmentStage->module->whlslModule());
 
         whlslDescriptor->vertexEntryPointName = vertexStage.entryPoint;
         if (fragmentStage)
             whlslDescriptor->fragmentEntryPointName = fragmentStage->entryPoint;
 
-        auto whlslCompileResult = WHLSL::prepare(whlslSource, *whlslDescriptor);
+        auto whlslCompileResult = WHLSL::prepare(*vertexStage.module->whlslModule(), fragmentStage ? fragmentStage->module->whlslModule() : nullptr, *whlslDescriptor);
         if (!whlslCompileResult) {
             errorScopes.generatePrefixedError(makeString("WHLSL compile error: ", whlslCompileResult.error()));
             return false;
@@ -420,7 +419,8 @@ static bool trySetFunctions(const GPUPipelineStageDescriptor& vertexStage, const
 
         fragmentLibrary = vertexLibrary;
         vertexEntryPoint = whlslCompileResult->mangledVertexEntryPointName.toString();
-        fragmentEntryPoint = whlslCompileResult->mangledFragmentEntryPointName.toString();
+        if (fragmentStage)
+            fragmentEntryPoint = whlslCompileResult->mangledFragmentEntryPointName.toString();
     } else {
         vertexLibrary = vertexStage.module->platformShaderModule();
         vertexEntryPoint = vertexStage.entryPoint;
@@ -452,8 +452,9 @@ static RetainPtr<MTLRenderPipelineDescriptor> convertRenderPipelineDescriptor(co
     const auto& vertexStage = descriptor.vertexStage;
     const auto& fragmentStage = descriptor.fragmentStage;
 
-    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195446 Allow WHLSL shaders to come from different programs.
-    bool isWhlsl = !vertexStage.module->whlslSource().isNull() && (!fragmentStage || vertexStage.module.ptr() == fragmentStage->module.ptr());
+    if (fragmentStage && static_cast<bool>(vertexStage.module->whlslModule()) != static_cast<bool>(fragmentStage->module->whlslModule()))
+        return nullptr;
+    bool isWhlsl = vertexStage.module->whlslModule();
 
     // Set data for the Metal pipeline descriptor (and WHLSL's, if needed).
     Optional<WHLSL::RenderPipelineDescriptor> whlslDescriptor;
index b7f56c8..b86f051 100644 (file)
@@ -45,7 +45,7 @@ RefPtr<GPUShaderModule> GPUShaderModule::tryCreate(const GPUDevice& device, cons
     }
     
     if (descriptor.isWHLSL)
-        return adoptRef(new GPUShaderModule(String(descriptor.code)));
+        return adoptRef(new GPUShaderModule(WHLSL::createShaderModule(descriptor.code)));
 
     PlatformShaderModuleSmartPtr module;
 
@@ -66,8 +66,8 @@ GPUShaderModule::GPUShaderModule(PlatformShaderModuleSmartPtr&& module)
 {
 }
 
-GPUShaderModule::GPUShaderModule(String&& whlslSource)
-    : m_whlslSource(WTFMove(whlslSource))
+GPUShaderModule::GPUShaderModule(UniqueRef<WHLSL::ShaderModule>&& whlslModule)
+    : m_whlslModule(whlslModule.moveToUniquePtr())
 {
 }