WebKit Bugzilla
Attachment 371555 Details for
Bug 198163
: [WHLSL] Implement array references
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-198163-20190607000043.patch (text/plain), 103.47 KB, created by
Myles C. Maxfield
on 2019-06-06 21:00:44 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2019-06-06 21:00:44 PDT
Size:
103.47 KB
patch
obsolete
>Subversion Revision: 246184 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 5c76422138f907692ffeb72bcb8a3af55f08463e..e7261c35c8d3482911312abf47daf61b87497c5b 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,107 @@ >+2019-06-06 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] Implement array references >+ https://bugs.webkit.org/show_bug.cgi?id=198163 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The compiler automatically generates anders for every array reference. Luckily, the infrastructure >+ to generate those anders and emit Metal code to represent them already exists in the compiler. >+ There are two pieces remaining (which this patch implements): >+ >+ 1. The Javascript compiler has a behavior where anders that are called with an array reference >+ as an argument don't wrap the argument in a MakePointerExpression. This is because the array >+ reference is already a reference type, so it's silly to operate on a pointer to a reference. >+ This patch implements this by teaching the type checker about which types should be passed >+ to the ander call, and by actually constructing those types in the property resolver. >+ The property resolver does this by placing the logic to construct an ander argument in a >+ single function which also has logic to save the argument in a temporary if the thread ander >+ will be called. The semantics about which functions are called in which situations are not >+ changed; instead, we just simply don't wrap array references with MakePointerExpressions. >+ >+ 2. Creating a bind group from the WebGPU API has to retain information about buffer lengths for >+ each buffer so the shader can properly perform bounds checks. This can be broken down into a >+ few pieces: >+ - Creating a bind group layout has to assign extra id indexes for each buffer which will be >+ filled in to represent the buffer's length >+ - Creating the bind group itself needs to fill in the buffer length into the Metal argument >+ buffer >+ - The shader compiler needs to emit code at the beginning of entry point to find the buffer >+ lengths and pack them together into the array reference (array references correspond to >+ a Metal struct with two fields: a pointer and a length). >+ >+ This patch doesn't actually implement bounds checks themselves; it just hooks up the buffer >+ lengths so https://bugs.webkit.org/show_bug.cgi?id=198600 can implement it. >+ >+ The shader compiler's API is modified to allow for this extra buffer length information to be >+ passed in from the WebGPU implementation. >+ >+ Unfortunately, I don't think I could split this patch up into two pieces because both are >+ required to test the compiler with buffers. >+ >+ Tests: webgpu/whlsl-buffer-fragment.html >+ webgpu/whlsl-buffer-vertex.html >+ >+ * Modules/webgpu/WHLSL/AST/WHLSLPropertyAccessExpression.h: >+ (WebCore::WHLSL::AST::PropertyAccessExpression::baseReference): >+ * Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.cpp: >+ (WebCore::WHLSL::AST::ResourceSemantic::isAcceptableType const): Arrays can't be resources >+ because the compiler has no way of guaranteeing if the resource is long enough to hold the >+ array at compile time. >+ * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp: >+ (WebCore::WHLSL::Metal::EntryPointScaffolding::EntryPointScaffolding): Generate an extra >+ variable name to represent the buffer length. Only do it for resources which have lengths. >+ (WebCore::WHLSL::Metal::EntryPointScaffolding::resourceHelperTypes): >+ (WebCore::WHLSL::Metal::EntryPointScaffolding::unpackResourcesAndNamedBuiltIns): Perform >+ the appropriate math to turn byte lengths into element counts and store the element count >+ in the array reference. >+ * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h: >+ * Modules/webgpu/WHLSL/WHLSLChecker.cpp: >+ (WebCore::WHLSL::resolveWithOperatorAnderIndexer): Refactor. >+ (WebCore::WHLSL::resolveWithOperatorLength): Ditto. >+ (WebCore::WHLSL::resolveWithReferenceComparator): Ditto. >+ (WebCore::WHLSL::resolveByInstantiation): Ditto. >+ (WebCore::WHLSL::argumentTypeForAndOverload): Given an ander, what should the type of the >+ argument be? >+ (WebCore::WHLSL::Checker::finishVisiting): Call argumentTypeForAndOverload(). Also, if >+ we couldn't find an ander, try automatically generating it, the same way that function >+ calls do. (This is how array references get their anders.) >+ (WebCore::WHLSL::Checker::visit): >+ * Modules/webgpu/WHLSL/WHLSLPipelineDescriptor.h: New WHLSL API to provide the length >+ information. >+ * Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp: >+ (WebCore::WHLSL::PropertyResolver::visit): SimplifyRightValue() can't fail any more. >+ (WebCore::WHLSL::wrapAnderCallArgument): If the ander argument should be wrapped in a >+ MakePointer or a MakeArrayReference, do that. Also, if the ander is a thread ander, save >+ the argument in a local variable and use that. >+ (WebCore::WHLSL::anderCallArgument): The equivalent of argumentTypeForAndOverload(). >+ (WebCore::WHLSL::setterCall): Call anderCallArgument(). >+ (WebCore::WHLSL::getterCall): Ditto. >+ (WebCore::WHLSL::modify): We used to have special-case code for handling pointer-to-argument >+ values as distinct from just the argument values themselves. However, emitting >+ chains of &* operators is valid and won't even make it through the Metal code generator >+ after https://bugs.webkit.org/show_bug.cgi?id=198600 is fixed. So, in order to simplify >+ wrapAnderCallArgument(), don't special case these values and just create &* chains instead. >+ (WebCore::WHLSL::PropertyResolver::simplifyRightValue): >+ (WebCore::WHLSL::LeftValueSimplifier::finishVisiting): Call anderCallArgument(). >+ * Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp: Update to support the new compiler API. >+ (WebCore::WHLSL::matchMode): >+ (WebCore::WHLSL::matchResources): >+ * Modules/webgpu/WebGPUBindGroupDescriptor.cpp: Ditto. >+ (WebCore::WebGPUBindGroupDescriptor::tryCreateGPUBindGroupDescriptor const): >+ * platform/graphics/gpu/GPUBindGroupLayout.h: Add some internal implementation data inside >+ the bindings object. Use a Variant to differentiate between the various bindings types, and >+ put the extra length field on just those members of the variant that represent buffers. >+ * platform/graphics/gpu/cocoa/GPUBindGroupLayoutMetal.mm: Update to support the new compiler API. >+ (WebCore::argumentDescriptor): >+ (WebCore::GPUBindGroupLayout::tryCreate): >+ * platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm: Ditto. >+ (WebCore::setBufferOnEncoder): >+ (WebCore::GPUBindGroup::tryCreate): >+ * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm: Ditto. >+ (WebCore::convertBindingType): >+ (WebCore::convertLayout): >+ > 2019-06-06 Youenn Fablet <youenn@apple.com> > > Allow WebKitTestRunner to terminate network process after it finishes service worker file operations >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPropertyAccessExpression.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPropertyAccessExpression.h >index 8f4aa0ea119f6ce0da2ef4a783ba71f10dfc896b..bb0c3012eeb203903a430020328c8b94829b684d 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPropertyAccessExpression.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPropertyAccessExpression.h >@@ -99,6 +99,7 @@ public: > } > > Expression& base() { return m_base; } >+ UniqueRef<Expression>& baseReference() { return m_base; } > UniqueRef<Expression> takeBase() { return WTFMove(m_base); } > > private: >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.cpp b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.cpp >index 3b58c3d34ca7162c94c03123195df3077adbb49e..e56287e6388fab346dc2857902823193fb70f0ba 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.cpp >@@ -49,8 +49,6 @@ bool ResourceSemantic::isAcceptableType(const UnnamedType& unnamedType, const In > auto& referenceType = downcast<ReferenceType>(unnamedType); > return referenceType.addressSpace() == AddressSpace::Constant || referenceType.addressSpace() == AddressSpace::Device; > } >- if (is<ArrayType>(unnamedType)) >- return true; > if (is<TypeReference>(unnamedType)) { > auto& typeReference = downcast<TypeReference>(unnamedType); > if (is<NativeTypeDeclaration>(typeReference.resolvedType())) >@@ -71,7 +69,7 @@ bool ResourceSemantic::isAcceptableType(const UnnamedType& unnamedType, const In > case Mode::Buffer: > if (is<ReferenceType>(unnamedType)) > return downcast<ReferenceType>(unnamedType).addressSpace() == AddressSpace::Constant; >- return is<ArrayType>(unnamedType); >+ return false; > case Mode::Sampler: > return matches(unnamedType, intrinsics.samplerType()); > } >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp >index 21974eb87d652ab453adee4c20dbcd1ac14c6870..da8c057857e28d2e1fbfafcdaba512e9e2003f30 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp >@@ -32,6 +32,7 @@ > #include "WHLSLFunctionDefinition.h" > #include "WHLSLGatherEntryPointItems.h" > #include "WHLSLPipelineDescriptor.h" >+#include "WHLSLReferenceType.h" > #include "WHLSLResourceSemantic.h" > #include "WHLSLStageInOutSemantic.h" > #include "WHLSLStructureDefinition.h" >@@ -108,7 +109,16 @@ EntryPointScaffolding::EntryPointScaffolding(AST::FunctionDefinition& functionDe > for (size_t j = 0; j < m_layout[i].bindings.size(); ++j) { > NamedBinding namedBinding; > namedBinding.elementName = m_typeNamer.generateNextStructureElementName(); >- namedBinding.index = m_layout[i].bindings[j].name; // GPUBindGroupLayout::tryCreate() makes sure these don't collide. >+ namedBinding.index = m_layout[i].bindings[j].internalName; >+ WTF::visit(WTF::makeVisitor([&](UniformBufferBinding& uniformBufferBinding) { >+ LengthInformation lengthInformation { m_typeNamer.generateNextStructureElementName(), m_generateNextVariableName(), uniformBufferBinding.lengthName }; >+ namedBinding.lengthInformation = lengthInformation; >+ }, [&](SamplerBinding&) { >+ }, [&](TextureBinding&) { >+ }, [&](StorageBufferBinding& storageBufferBinding) { >+ LengthInformation lengthInformation { m_typeNamer.generateNextStructureElementName(), m_generateNextVariableName(), storageBufferBinding.lengthName }; >+ namedBinding.lengthInformation = lengthInformation; >+ }), m_layout[i].bindings[j].binding); > namedBindGroup.namedBindings.uncheckedAppend(WTFMove(namedBinding)); > } > m_namedBindGroups.uncheckedAppend(WTFMove(namedBindGroup)); >@@ -137,10 +147,16 @@ String EntryPointScaffolding::resourceHelperTypes() > auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]); > if (iterator == m_resourceMap.end()) > continue; >- auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[iterator->value].unnamedType); >+ auto& unnamedType = *m_entryPointItems.inputs[iterator->value].unnamedType; >+ ASSERT(is<AST::ReferenceType>(unnamedType)); >+ auto& referenceType = downcast<AST::ReferenceType>(unnamedType); >+ auto mangledTypeName = m_typeNamer.mangledNameForType(referenceType.elementType()); >+ auto addressSpace = toString(referenceType.addressSpace()); > auto elementName = m_namedBindGroups[i].namedBindings[j].elementName; > auto index = m_namedBindGroups[i].namedBindings[j].index; >- stringBuilder.append(makeString(" ", mangledTypeName, ' ', elementName, " [[id(", index, ")]];\n")); >+ stringBuilder.append(makeString(" ", addressSpace, " ", mangledTypeName, "* ", elementName, " [[id(", index, ")]];\n")); >+ if (auto lengthInformation = m_namedBindGroups[i].namedBindings[j].lengthInformation) >+ stringBuilder.append(makeString(" uint2 ", lengthInformation->elementName, " [[id(", lengthInformation->index, ")]];\n")); > } > stringBuilder.append("};\n\n"); > } >@@ -257,9 +273,28 @@ String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns() > auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]); > if (iterator == m_resourceMap.end()) > continue; >- auto& path = m_entryPointItems.inputs[iterator->value].path; >- auto elementName = m_namedBindGroups[i].namedBindings[j].elementName; >- stringBuilder.append(makeString(mangledInputPath(path), " = ", variableName, '.', elementName, ";\n")); >+ if (m_namedBindGroups[i].namedBindings[j].lengthInformation) { >+ auto& path = m_entryPointItems.inputs[iterator->value].path; >+ auto elementName = m_namedBindGroups[i].namedBindings[j].elementName; >+ auto lengthElementName = m_namedBindGroups[i].namedBindings[j].lengthInformation->elementName; >+ auto lengthTemporaryName = m_namedBindGroups[i].namedBindings[j].lengthInformation->temporaryName; >+ >+ auto& unnamedType = *m_entryPointItems.inputs[iterator->value].unnamedType; >+ ASSERT(is<AST::ReferenceType>(unnamedType)); >+ auto& referenceType = downcast<AST::ReferenceType>(unnamedType); >+ auto mangledTypeName = m_typeNamer.mangledNameForType(referenceType.elementType()); >+ >+ stringBuilder.append(makeString("size_t ", lengthTemporaryName, " = ", variableName, '.', lengthElementName, ".x;\n")); >+ stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " << 32;\n")); >+ stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " | ", variableName, '.', lengthElementName, ".y;\n")); >+ stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " / sizeof(", mangledTypeName, ");\n")); >+ stringBuilder.append(makeString("if (", lengthTemporaryName, " > 0xFFFFFFFF) ", lengthTemporaryName, " = 0xFFFFFFFF;\n")); >+ stringBuilder.append(makeString(mangledInputPath(path), " = { ", variableName, '.', elementName, ", static_cast<uint32_t>(", lengthTemporaryName, ") };\n")); >+ } else { >+ auto& path = m_entryPointItems.inputs[iterator->value].path; >+ auto elementName = m_namedBindGroups[i].namedBindings[j].elementName; >+ stringBuilder.append(makeString(mangledInputPath(path), " = ", variableName, '.', elementName, ";\n")); >+ } > } > } > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h >index 2467e86ff86ad24404826e385ca1a51e0d1a837a..664f7fb4a237619a3c2e50f172edfa0d4a5ee3d2 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h >@@ -77,9 +77,15 @@ protected: > Layout& m_layout; > std::function<String()> m_generateNextVariableName; > >+ struct LengthInformation { >+ String elementName; >+ String temporaryName; >+ unsigned index; >+ }; > struct NamedBinding { > String elementName; > unsigned index; >+ Optional<LengthInformation> lengthInformation; > }; > struct NamedBindGroup { > String structName; >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >index 88e75531c330ba199a3642f68de93a727084eb1c..f14e7d43ba6f147783ed11a222f8c82a379645d1 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >@@ -117,29 +117,29 @@ public: > } > }; > >-static AST::NativeFunctionDeclaration resolveWithOperatorAnderIndexer(AST::CallExpression& callExpression, AST::ArrayReferenceType& firstArgument, const Intrinsics& intrinsics) >+static AST::NativeFunctionDeclaration resolveWithOperatorAnderIndexer(Lexer::Token origin, AST::ArrayReferenceType& firstArgument, const Intrinsics& intrinsics) > { > const bool isOperator = true; >- auto returnType = makeUniqueRef<AST::PointerType>(Lexer::Token(callExpression.origin()), firstArgument.addressSpace(), firstArgument.elementType().clone()); >+ auto returnType = makeUniqueRef<AST::PointerType>(Lexer::Token(origin), firstArgument.addressSpace(), firstArgument.elementType().clone()); > AST::VariableDeclarations parameters; >- parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(callExpression.origin()), AST::Qualifiers(), firstArgument.clone(), String(), WTF::nullopt, WTF::nullopt)); >- parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(callExpression.origin()), AST::Qualifiers(), UniqueRef<AST::UnnamedType>(AST::TypeReference::wrap(Lexer::Token(callExpression.origin()), intrinsics.uintType())), String(), WTF::nullopt, WTF::nullopt)); >- return AST::NativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(callExpression.origin()), AST::AttributeBlock(), WTF::nullopt, WTFMove(returnType), String("operator&[]", String::ConstructFromLiteral), WTFMove(parameters), WTF::nullopt, isOperator)); >+ parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), firstArgument.clone(), String(), WTF::nullopt, WTF::nullopt)); >+ parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), UniqueRef<AST::UnnamedType>(AST::TypeReference::wrap(Lexer::Token(origin), intrinsics.uintType())), String(), WTF::nullopt, WTF::nullopt)); >+ return AST::NativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(origin), AST::AttributeBlock(), WTF::nullopt, WTFMove(returnType), String("operator&[]", String::ConstructFromLiteral), WTFMove(parameters), WTF::nullopt, isOperator)); > } > >-static AST::NativeFunctionDeclaration resolveWithOperatorLength(AST::CallExpression& callExpression, AST::UnnamedType& firstArgument, const Intrinsics& intrinsics) >+static AST::NativeFunctionDeclaration resolveWithOperatorLength(Lexer::Token origin, AST::UnnamedType& firstArgument, const Intrinsics& intrinsics) > { > const bool isOperator = true; >- auto returnType = AST::TypeReference::wrap(Lexer::Token(callExpression.origin()), intrinsics.uintType()); >+ auto returnType = AST::TypeReference::wrap(Lexer::Token(origin), intrinsics.uintType()); > AST::VariableDeclarations parameters; >- parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(callExpression.origin()), AST::Qualifiers(), firstArgument.clone(), String(), WTF::nullopt, WTF::nullopt)); >- return AST::NativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(callExpression.origin()), AST::AttributeBlock(), WTF::nullopt, WTFMove(returnType), String("operator.length", String::ConstructFromLiteral), WTFMove(parameters), WTF::nullopt, isOperator)); >+ parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), firstArgument.clone(), String(), WTF::nullopt, WTF::nullopt)); >+ return AST::NativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(origin), AST::AttributeBlock(), WTF::nullopt, WTFMove(returnType), String("operator.length", String::ConstructFromLiteral), WTFMove(parameters), WTF::nullopt, isOperator)); > } > >-static AST::NativeFunctionDeclaration resolveWithReferenceComparator(AST::CallExpression& callExpression, ResolvingType& firstArgument, ResolvingType& secondArgument, const Intrinsics& intrinsics) >+static AST::NativeFunctionDeclaration resolveWithReferenceComparator(Lexer::Token origin, ResolvingType& firstArgument, ResolvingType& secondArgument, const Intrinsics& intrinsics) > { > const bool isOperator = true; >- auto returnType = AST::TypeReference::wrap(Lexer::Token(callExpression.origin()), intrinsics.boolType()); >+ auto returnType = AST::TypeReference::wrap(Lexer::Token(origin), intrinsics.boolType()); > auto argumentType = firstArgument.visit(WTF::makeVisitor([](UniqueRef<AST::UnnamedType>& unnamedType) -> UniqueRef<AST::UnnamedType> { > return unnamedType->clone(); > }, [&](RefPtr<ResolvableTypeReference>&) -> UniqueRef<AST::UnnamedType> { >@@ -149,13 +149,13 @@ static AST::NativeFunctionDeclaration resolveWithReferenceComparator(AST::CallEx > // We encountered "null == null". > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198162 This can probably be generalized, using the "preferred type" infrastructure used by generic literals > ASSERT_NOT_REACHED(); >- return AST::TypeReference::wrap(Lexer::Token(callExpression.origin()), intrinsics.intType()); >+ return AST::TypeReference::wrap(Lexer::Token(origin), intrinsics.intType()); > })); > })); > AST::VariableDeclarations parameters; >- parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(callExpression.origin()), AST::Qualifiers(), argumentType->clone(), String(), WTF::nullopt, WTF::nullopt)); >- parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(callExpression.origin()), AST::Qualifiers(), UniqueRef<AST::UnnamedType>(WTFMove(argumentType)), String(), WTF::nullopt, WTF::nullopt)); >- return AST::NativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(callExpression.origin()), AST::AttributeBlock(), WTF::nullopt, WTFMove(returnType), String("operator==", String::ConstructFromLiteral), WTFMove(parameters), WTF::nullopt, isOperator)); >+ parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), argumentType->clone(), String(), WTF::nullopt, WTF::nullopt)); >+ parameters.append(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), UniqueRef<AST::UnnamedType>(WTFMove(argumentType)), String(), WTF::nullopt, WTF::nullopt)); >+ return AST::NativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(origin), AST::AttributeBlock(), WTF::nullopt, WTFMove(returnType), String("operator==", String::ConstructFromLiteral), WTFMove(parameters), WTF::nullopt, isOperator)); > } > > enum class Acceptability { >@@ -164,9 +164,9 @@ enum class Acceptability { > No > }; > >-static Optional<AST::NativeFunctionDeclaration> resolveByInstantiation(AST::CallExpression& callExpression, const Vector<std::reference_wrapper<ResolvingType>>& types, const Intrinsics& intrinsics) >+static Optional<AST::NativeFunctionDeclaration> resolveByInstantiation(const String& name, Lexer::Token origin, const Vector<std::reference_wrapper<ResolvingType>>& types, const Intrinsics& intrinsics) > { >- if (callExpression.name() == "operator&[]" && types.size() == 2) { >+ if (name == "operator&[]" && types.size() == 2) { > auto* firstArgumentArrayRef = types[0].get().visit(WTF::makeVisitor([](UniqueRef<AST::UnnamedType>& unnamedType) -> AST::ArrayReferenceType* { > if (is<AST::ArrayReferenceType>(static_cast<AST::UnnamedType&>(unnamedType))) > return &downcast<AST::ArrayReferenceType>(static_cast<AST::UnnamedType&>(unnamedType)); >@@ -180,8 +180,8 @@ static Optional<AST::NativeFunctionDeclaration> resolveByInstantiation(AST::Call > return resolvableTypeReference->resolvableType().canResolve(intrinsics.uintType()); > })); > if (firstArgumentArrayRef && secondArgumentIsUint) >- return resolveWithOperatorAnderIndexer(callExpression, *firstArgumentArrayRef, intrinsics); >- } else if (callExpression.name() == "operator.length" && types.size() == 1) { >+ return resolveWithOperatorAnderIndexer(origin, *firstArgumentArrayRef, intrinsics); >+ } else if (name == "operator.length" && types.size() == 1) { > auto* firstArgumentReference = types[0].get().visit(WTF::makeVisitor([](UniqueRef<AST::UnnamedType>& unnamedType) -> AST::UnnamedType* { > if (is<AST::ArrayReferenceType>(static_cast<AST::UnnamedType&>(unnamedType))) > return &unnamedType; >@@ -190,8 +190,8 @@ static Optional<AST::NativeFunctionDeclaration> resolveByInstantiation(AST::Call > return nullptr; > })); > if (firstArgumentReference) >- return resolveWithOperatorLength(callExpression, *firstArgumentReference, intrinsics); >- } else if (callExpression.name() == "operator==" && types.size() == 2) { >+ return resolveWithOperatorLength(origin, *firstArgumentReference, intrinsics); >+ } else if (name == "operator==" && types.size() == 2) { > auto acceptability = [](ResolvingType& resolvingType) -> Acceptability { > return resolvingType.visit(WTF::makeVisitor([](UniqueRef<AST::UnnamedType>& unnamedType) -> Acceptability { > return is<AST::ReferenceType>(static_cast<AST::UnnamedType&>(unnamedType)) ? Acceptability::Yes : Acceptability::No; >@@ -210,7 +210,7 @@ static Optional<AST::NativeFunctionDeclaration> resolveByInstantiation(AST::Call > || (leftAcceptability == Acceptability::Yes && rightAcceptability == Acceptability::Maybe)) > success = true; > if (success) >- return resolveWithReferenceComparator(callExpression, types[0].get(), types[1].get(), intrinsics); >+ return resolveWithReferenceComparator(origin, types[0].get(), types[1].get(), intrinsics); > } > return WTF::nullopt; > } >@@ -969,6 +969,29 @@ void Checker::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpress > assignType(makeArrayReferenceExpression, makeUniqueRef<AST::ArrayReferenceType>(Lexer::Token(makeArrayReferenceExpression.origin()), *leftAddressSpace, leftValueType->clone())); > } > >+static Optional<UniqueRef<AST::UnnamedType>> argumentTypeForAndOverload(AST::UnnamedType& baseType, AST::AddressSpace addressSpace) >+{ >+ auto& unifyNode = baseType.unifyNode(); >+ if (is<AST::NamedType>(unifyNode)) { >+ auto& namedType = downcast<AST::NamedType>(unifyNode); >+ return { makeUniqueRef<AST::PointerType>(Lexer::Token(namedType.origin()), addressSpace, AST::TypeReference::wrap(Lexer::Token(namedType.origin()), namedType)) }; >+ } >+ >+ ASSERT(is<AST::UnnamedType>(unifyNode)); >+ auto& unnamedType = downcast<AST::UnnamedType>(unifyNode); >+ >+ if (is<AST::ArrayReferenceType>(unnamedType)) >+ return unnamedType.clone(); >+ >+ if (is<AST::ArrayType>(unnamedType)) >+ return { makeUniqueRef<AST::ArrayReferenceType>(Lexer::Token(unnamedType.origin()), addressSpace, downcast<AST::ArrayType>(unnamedType).type().clone()) }; >+ >+ if (is<AST::PointerType>(unnamedType)) >+ return WTF::nullopt; >+ >+ return { makeUniqueRef<AST::PointerType>(Lexer::Token(unnamedType.origin()), addressSpace, unnamedType.clone()) }; >+} >+ > void Checker::finishVisiting(AST::PropertyAccessExpression& propertyAccessExpression, ResolvingType* additionalArgumentType) > { > auto baseInfo = recurseAndGetInfo(propertyAccessExpression.base()); >@@ -992,23 +1015,35 @@ void Checker::finishVisiting(AST::PropertyAccessExpression& propertyAccessExpres > AST::UnnamedType* anderReturnType = nullptr; > auto leftAddressSpace = baseInfo->typeAnnotation.leftAddressSpace(); > if (leftAddressSpace) { >- ResolvingType argumentType = { makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), *leftAddressSpace, baseUnnamedType->get().clone()) }; >- Vector<std::reference_wrapper<ResolvingType>> anderArgumentTypes { argumentType }; >- if (additionalArgumentType) >- anderArgumentTypes.append(*additionalArgumentType); >- if ((anderFunction = resolveFunctionOverloadImpl(propertyAccessExpression.possibleAnderOverloads(), anderArgumentTypes, nullptr))) >- anderReturnType = &downcast<AST::PointerType>(anderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer >+ if (auto argumentTypeForAndOverload = WHLSL::argumentTypeForAndOverload(*baseUnnamedType, *leftAddressSpace)) { >+ ResolvingType argumentType = { WTFMove(*argumentTypeForAndOverload) }; >+ Vector<std::reference_wrapper<ResolvingType>> anderArgumentTypes { argumentType }; >+ if (additionalArgumentType) >+ anderArgumentTypes.append(*additionalArgumentType); >+ if ((anderFunction = resolveFunctionOverloadImpl(propertyAccessExpression.possibleAnderOverloads(), anderArgumentTypes, nullptr))) >+ anderReturnType = &downcast<AST::PointerType>(anderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer >+ else if (auto newFunction = resolveByInstantiation(propertyAccessExpression.anderFunctionName(), propertyAccessExpression.origin(), anderArgumentTypes, m_intrinsics)) { >+ m_program.append(WTFMove(*newFunction)); >+ anderFunction = &m_program.nativeFunctionDeclarations().last(); >+ anderReturnType = &downcast<AST::PointerType>(anderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer >+ } >+ } > } > > AST::FunctionDeclaration* threadAnderFunction = nullptr; > AST::UnnamedType* threadAnderReturnType = nullptr; >- { >+ if (auto argumentTypeForAndOverload = WHLSL::argumentTypeForAndOverload(*baseUnnamedType, AST::AddressSpace::Thread)) { > ResolvingType argumentType = { makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), AST::AddressSpace::Thread, baseUnnamedType->get().clone()) }; > Vector<std::reference_wrapper<ResolvingType>> threadAnderArgumentTypes { argumentType }; > if (additionalArgumentType) > threadAnderArgumentTypes.append(*additionalArgumentType); > if ((threadAnderFunction = resolveFunctionOverloadImpl(propertyAccessExpression.possibleAnderOverloads(), threadAnderArgumentTypes, nullptr))) > threadAnderReturnType = &downcast<AST::PointerType>(threadAnderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer >+ else if (auto newFunction = resolveByInstantiation(propertyAccessExpression.anderFunctionName(), propertyAccessExpression.origin(), threadAnderArgumentTypes, m_intrinsics)) { >+ m_program.append(WTFMove(*newFunction)); >+ threadAnderFunction = &m_program.nativeFunctionDeclarations().last(); >+ threadAnderReturnType = &downcast<AST::PointerType>(anderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer >+ } > } > > if (leftAddressSpace && !anderFunction && !getterFunction) { >@@ -1434,7 +1469,7 @@ void Checker::visit(AST::CallExpression& callExpression) > ASSERT(callExpression.hasOverloads()); > auto* function = resolveFunctionOverloadImpl(*callExpression.overloads(), types, callExpression.castReturnType()); > if (!function) { >- if (auto newFunction = resolveByInstantiation(callExpression, types, m_intrinsics)) { >+ if (auto newFunction = resolveByInstantiation(callExpression.name(), callExpression.origin(), types, m_intrinsics)) { > m_program.append(WTFMove(*newFunction)); > function = &m_program.nativeFunctionDeclarations().last(); > } >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPipelineDescriptor.h b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPipelineDescriptor.h >index f8f1745d3f2279c8a43cfef0b572d6468aef07c3..5b37e3fb35ac4f7ed4c034551d89369f0ae84458 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPipelineDescriptor.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPipelineDescriptor.h >@@ -114,18 +114,28 @@ enum class ShaderStage : uint8_t { > Compute = 1 << 2 > }; > >-enum class BindingType : uint8_t { >- UniformBuffer, >- Sampler, >- Texture, >- StorageBuffer, >- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198168 Add the dynamic types >+struct UniformBufferBinding { >+ unsigned lengthName; > }; > >+struct SamplerBinding { >+}; >+ >+struct TextureBinding { >+}; >+ >+struct StorageBufferBinding { >+ unsigned lengthName; >+}; >+ >+// FIXME: https://bugs.webkit.org/show_bug.cgi?id=198168 Add the dynamic types >+ > struct Binding { >+ using BindingDetails = Variant<UniformBufferBinding, SamplerBinding, TextureBinding, StorageBufferBinding>; > OptionSet<ShaderStage> visibility; >- BindingType bindingType; >- unsigned name; >+ BindingDetails binding; >+ unsigned internalName; >+ unsigned externalName; > }; > > struct BindGroup { >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >index 8a5a8b3a3ceff57023c229664ab486f3fd4e98db..a93e0372566c83052294d0261a166fa6151ab658 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >@@ -35,6 +35,7 @@ > #include "WHLSLDotExpression.h" > #include "WHLSLFunctionDeclaration.h" > #include "WHLSLFunctionDefinition.h" >+#include "WHLSLMakeArrayReferenceExpression.h" > #include "WHLSLMakePointerExpression.h" > #include "WHLSLPointerType.h" > #include "WHLSLReadModifyWriteExpression.h" >@@ -55,7 +56,7 @@ private: > void visit(AST::AssignmentExpression&) override; > void visit(AST::ReadModifyWriteExpression&) override; > >- bool simplifyRightValue(AST::PropertyAccessExpression&); >+ void simplifyRightValue(AST::PropertyAccessExpression&); > bool simplifyAbstractLeftValue(AST::AssignmentExpression&, AST::DotExpression&, UniqueRef<AST::Expression>&& right); > void simplifyLeftValue(AST::Expression&); > >@@ -65,16 +66,14 @@ private: > void PropertyResolver::visit(AST::DotExpression& dotExpression) > { > // Unless we're inside an AssignmentExpression or a ReadModifyWriteExpression, we're a right value. >- if (!simplifyRightValue(dotExpression)) >- setError(); >+ simplifyRightValue(dotExpression); > } > > void PropertyResolver::visit(AST::IndexExpression& indexExpression) > { > checkErrorAndVisit(indexExpression.indexExpression()); > // Unless we're inside an AssignmentExpression or a ReadModifyWriteExpression, we're a right value. >- if (!simplifyRightValue(indexExpression)) >- setError(); >+ simplifyRightValue(indexExpression); > } > > void PropertyResolver::visit(AST::FunctionDefinition& functionDefinition) >@@ -84,7 +83,78 @@ void PropertyResolver::visit(AST::FunctionDefinition& functionDefinition) > functionDefinition.block().statements().insert(0, makeUniqueRef<AST::VariableDeclarationsStatement>(Lexer::Token(m_variableDeclarations[0]->origin()), WTFMove(m_variableDeclarations))); > } > >-static Optional<UniqueRef<AST::Expression>> setterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, UniqueRef<AST::Expression>&& newValue, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, const std::function<UniqueRef<AST::Expression>()>& pointerToLeftValueFactory, AST::VariableDeclaration* indexVariable) >+enum class WhichAnder { >+ ThreadAnder, >+ Ander >+}; >+ >+struct AnderCallArgumentResult { >+ UniqueRef<AST::Expression> expression; >+ Optional<UniqueRef<AST::VariableDeclaration>> variableDeclaration; >+ WhichAnder whichAnder; >+}; >+ >+template <typename ExpressionConstructor, typename TypeConstructor> >+static Optional<AnderCallArgumentResult> wrapAnderCallArgument(UniqueRef<AST::Expression>& expression, bool anderFunction, bool threadAnderFunction) >+{ >+ if (auto addressSpace = expression->typeAnnotation().leftAddressSpace()) { >+ if (!anderFunction) >+ return WTF::nullopt; >+ auto origin = expression->origin(); >+ auto baseType = expression->resolvedType().clone(); >+ auto makeArrayReference = makeUniqueRef<ExpressionConstructor>(Lexer::Token(origin), WTFMove(expression)); >+ makeArrayReference->setType(makeUniqueRef<TypeConstructor>(WTFMove(origin), *addressSpace, WTFMove(baseType))); >+ makeArrayReference->setTypeAnnotation(AST::RightValue()); >+ return {{ WTFMove(makeArrayReference), WTF::nullopt, WhichAnder::Ander }}; >+ } >+ if (threadAnderFunction) { >+ auto origin = expression->origin(); >+ auto baseType = expression->resolvedType().clone(); >+ auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), baseType->clone(), String(), WTF::nullopt, WTF::nullopt); >+ >+ auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >+ variableReference1->setType(baseType->clone()); >+ variableReference1->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ >+ auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(origin), WTFMove(variableReference1), WTFMove(expression)); >+ assignmentExpression->setType(baseType->clone()); >+ assignmentExpression->setTypeAnnotation(AST::RightValue()); >+ >+ auto variableReference2 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >+ variableReference2->setType(baseType->clone()); >+ variableReference2->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ >+ auto expression = makeUniqueRef<ExpressionConstructor>(Lexer::Token(origin), WTFMove(variableReference2)); >+ auto resultType = makeUniqueRef<TypeConstructor>(Lexer::Token(origin), AST::AddressSpace::Thread, WTFMove(baseType)); >+ expression->setType(resultType->clone()); >+ expression->setTypeAnnotation(AST::RightValue()); >+ >+ Vector<UniqueRef<AST::Expression>> expressions; >+ expressions.append(WTFMove(assignmentExpression)); >+ expressions.append(WTFMove(expression)); >+ auto commaExpression = makeUniqueRef<AST::CommaExpression>(WTFMove(origin), WTFMove(expressions)); >+ commaExpression->setType(WTFMove(resultType)); >+ commaExpression->setTypeAnnotation(AST::RightValue()); >+ return {{ WTFMove(commaExpression), { WTFMove(variableDeclaration) }, WhichAnder::ThreadAnder}}; >+ } >+ return WTF::nullopt; >+} >+ >+static Optional<AnderCallArgumentResult> anderCallArgument(UniqueRef<AST::Expression>& expression, bool anderFunction, bool threadAnderFunction) >+{ >+ auto& unifyNode = expression->resolvedType().unifyNode(); >+ if (is<AST::UnnamedType>(unifyNode)) { >+ auto& unnamedType = downcast<AST::UnnamedType>(unifyNode); >+ ASSERT(!is<AST::PointerType>(unnamedType)); >+ if (is<AST::ArrayReferenceType>(unnamedType)) >+ return {{ WTFMove(expression), WTF::nullopt, WhichAnder::Ander }}; >+ if (is<AST::ArrayType>(unnamedType)) >+ return wrapAnderCallArgument<AST::MakeArrayReferenceExpression, AST::ArrayReferenceType>(expression, anderFunction, threadAnderFunction); >+ } >+ return wrapAnderCallArgument<AST::MakePointerExpression, AST::PointerType>(expression, anderFunction, threadAnderFunction); >+} >+ >+static Optional<UniqueRef<AST::Expression>> setterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, UniqueRef<AST::Expression>&& newValue, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, AST::VariableDeclaration* indexVariable) > { > auto maybeAddIndexArgument = [&](Vector<UniqueRef<AST::Expression>>& arguments) { > if (!indexVariable) >@@ -98,8 +168,13 @@ static Optional<UniqueRef<AST::Expression>> setterCall(AST::PropertyAccessExpres > > if (relevantAnder) { > // *operator&.foo(&v) = newValue >+ auto leftValue = leftValueFactory(); >+ auto argument = anderCallArgument(leftValue, true, true); >+ ASSERT(argument); >+ ASSERT(!argument->variableDeclaration); >+ ASSERT(argument->whichAnder == WhichAnder::Ander); > Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(pointerToLeftValueFactory()); >+ arguments.append(WTFMove(argument->expression)); > maybeAddIndexArgument(arguments); > > auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(propertyAccessExpression.origin()), String(relevantAnder->name()), WTFMove(arguments)); >@@ -138,7 +213,7 @@ static Optional<UniqueRef<AST::Expression>> setterCall(AST::PropertyAccessExpres > return UniqueRef<AST::Expression>(WTFMove(assignmentExpression)); > } > >-static Optional<UniqueRef<AST::Expression>> getterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, const std::function<UniqueRef<AST::Expression>()>& pointerToLeftValueFactory, AST::VariableDeclaration* indexVariable) >+static Optional<UniqueRef<AST::Expression>> getterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, AST::VariableDeclaration* indexVariable) > { > auto maybeAddIndexArgument = [&](Vector<UniqueRef<AST::Expression>>& arguments) { > if (!indexVariable) >@@ -152,8 +227,13 @@ static Optional<UniqueRef<AST::Expression>> getterCall(AST::PropertyAccessExpres > > if (relevantAnder) { > // *operator&.foo(&v) >+ auto leftValue = leftValueFactory(); >+ auto argument = anderCallArgument(leftValue, true, true); >+ ASSERT(argument); >+ ASSERT(!argument->variableDeclaration); >+ ASSERT(argument->whichAnder == WhichAnder::Ander); > Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(pointerToLeftValueFactory()); >+ arguments.append(WTFMove(argument->expression)); > maybeAddIndexArgument(arguments); > > auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(propertyAccessExpression.origin()), String(relevantAnder->name()), WTFMove(arguments)); >@@ -170,7 +250,7 @@ static Optional<UniqueRef<AST::Expression>> getterCall(AST::PropertyAccessExpres > > // operator.foo(v) > ASSERT(propertyAccessExpression.getterFunction()); >- >+ > Vector<UniqueRef<AST::Expression>> arguments; > arguments.append(leftValueFactory()); > maybeAddIndexArgument(arguments); >@@ -304,7 +384,7 @@ static Optional<ModifyResult> modify(AST::PropertyAccessExpression& propertyAcce > variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? > return variableReference; > } >- >+ > auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); > ASSERT(pointerVariable->type()); > variableReference->setType(pointerVariable->type()->clone()); >@@ -316,26 +396,6 @@ static Optional<ModifyResult> modify(AST::PropertyAccessExpression& propertyAcce > dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(*pointerVariable->type()).addressSpace() }); > return dereferenceExpression; > }; >- auto pointerToPreviousLeftValue = [&]() -> UniqueRef<AST::Expression> { >- if (previous) { >- auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*previous)); >- ASSERT(previous->type()); >- variableReference->setType(previous->type()->clone()); >- variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? >- >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(variableReference)); >- ASSERT(previous->type()); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), AST::AddressSpace::Thread, previous->type()->clone())); >- makePointerExpression->setTypeAnnotation(AST::RightValue()); >- return makePointerExpression; >- } >- >- auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); >- ASSERT(pointerVariable->type()); >- variableReference->setType(pointerVariable->type()->clone()); >- variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? >- return variableReference; >- }; > auto appendIndexAssignment = [&](AST::PropertyAccessExpression& propertyAccessExpression, Optional<UniqueRef<AST::VariableDeclaration>>& indexVariable) { > if (!indexVariable) > return; >@@ -361,7 +421,7 @@ static Optional<ModifyResult> modify(AST::PropertyAccessExpression& propertyAcce > appendIndexAssignment(propertyAccessExpression, indexVariable); > > AST::FunctionDeclaration* relevantAnder = i == chain.size() - 1 ? propertyAccessExpression.anderFunction() : propertyAccessExpression.threadAnderFunction(); >- auto callExpression = getterCall(propertyAccessExpression, relevantAnder, previousLeftValue, pointerToPreviousLeftValue, indexVariable ? &*indexVariable : nullptr); >+ auto callExpression = getterCall(propertyAccessExpression, relevantAnder, previousLeftValue, indexVariable ? &*indexVariable : nullptr); > > if (!callExpression) > return WTF::nullopt; >@@ -376,12 +436,12 @@ static Optional<ModifyResult> modify(AST::PropertyAccessExpression& propertyAcce > assignmentExpression->setTypeAnnotation(AST::RightValue()); > > expressions.append(WTFMove(assignmentExpression)); >- >+ > previous = &variableDeclaration; > } > appendIndexAssignment(chain[0], indexVariables[0]); > AST::FunctionDeclaration* relevantAnder = chain.size() == 1 ? propertyAccessExpression.anderFunction() : propertyAccessExpression.threadAnderFunction(); >- auto lastGetterCallExpression = getterCall(chain[0], relevantAnder, previousLeftValue, pointerToPreviousLeftValue, indexVariables[0] ? &*(indexVariables[0]) : nullptr); >+ auto lastGetterCallExpression = getterCall(chain[0], relevantAnder, previousLeftValue, indexVariables[0] ? &*(indexVariables[0]) : nullptr); > > // Step 3: > auto modificationResult = modification(WTFMove(lastGetterCallExpression)); >@@ -404,17 +464,6 @@ static Optional<ModifyResult> modify(AST::PropertyAccessExpression& propertyAcce > variableReference->setType(variableDeclaration.type()->clone()); > variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? > return variableReference; >- }, [&]() -> UniqueRef<AST::Expression> { >- auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >- ASSERT(variableDeclaration.type()); >- variableReference->setType(variableDeclaration.type()->clone()); >- variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? >- >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(variableReference)); >- ASSERT(variableDeclaration.type()); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), AST::AddressSpace::Thread, variableDeclaration.type()->clone())); >- makePointerExpression->setTypeAnnotation(AST::RightValue()); >- return makePointerExpression; > }, indexVariable ? &*indexVariable : nullptr); > > if (!assignmentExpression) >@@ -442,12 +491,6 @@ static Optional<ModifyResult> modify(AST::PropertyAccessExpression& propertyAcce > dereferenceExpression->setType(downcast<AST::PointerType>(*pointerVariable->type()).elementType().clone()); > dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(*pointerVariable->type()).addressSpace() }); > return dereferenceExpression; >- }, [&]() -> UniqueRef<AST::Expression> { >- auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); >- ASSERT(pointerVariable->type()); >- variableReference->setType(pointerVariable->type()->clone()); >- variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? >- return variableReference; > }, indexVariables[indexVariables.size() - 1] ? &*(indexVariables[indexVariables.size() - 1]) : nullptr); > > if (!assignmentExpression) >@@ -671,94 +714,50 @@ void PropertyResolver::visit(AST::ReadModifyWriteExpression& readModifyWriteExpr > m_variableDeclarations.append(WTFMove(newVariableDeclaration)); > } > >-bool PropertyResolver::simplifyRightValue(AST::PropertyAccessExpression& propertyAccessExpression) >+static Optional<AnderCallArgumentResult> anderCallArgument(AST::PropertyAccessExpression& propertyAccessExpression) >+{ >+ return anderCallArgument(propertyAccessExpression.baseReference(), propertyAccessExpression.anderFunction(), propertyAccessExpression.threadAnderFunction()); >+} >+ >+void PropertyResolver::simplifyRightValue(AST::PropertyAccessExpression& propertyAccessExpression) > { > Lexer::Token origin = propertyAccessExpression.origin(); > > checkErrorAndVisit(propertyAccessExpression.base()); > >- auto& base = propertyAccessExpression.base(); >- if (auto leftAddressSpace = base.typeAnnotation().leftAddressSpace()) { >- if (auto* anderFunction = propertyAccessExpression.anderFunction()) { >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), propertyAccessExpression.takeBase()); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(origin), *leftAddressSpace, base.resolvedType().clone())); >- makePointerExpression->setTypeAnnotation(AST::RightValue()); >- >- Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(WTFMove(makePointerExpression)); >- if (is<AST::IndexExpression>(propertyAccessExpression)) >- arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); >- auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(anderFunction->name()), WTFMove(arguments)); >- callExpression->setType(anderFunction->type().clone()); >- callExpression->setTypeAnnotation(AST::RightValue()); >- callExpression->setFunction(*anderFunction); >- >- auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(propertyAccessExpression, WTFMove(origin), WTFMove(callExpression)); >- dereferenceExpression->setType(downcast<AST::PointerType>(anderFunction->type()).elementType().clone()); >- dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(anderFunction->type()).addressSpace() }); >- return true; >- } >- } >- >- if (propertyAccessExpression.getterFunction()) { >- auto& getterFunction = *propertyAccessExpression.getterFunction(); >+ if (auto argument = anderCallArgument(propertyAccessExpression)) { >+ auto* anderFunction = argument->whichAnder == WhichAnder::ThreadAnder ? propertyAccessExpression.threadAnderFunction() : propertyAccessExpression.anderFunction(); >+ ASSERT(anderFunction); >+ auto origin = propertyAccessExpression.origin(); > Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(propertyAccessExpression.takeBase()); >+ arguments.append(WTFMove(argument->expression)); > if (is<AST::IndexExpression>(propertyAccessExpression)) > arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); >- auto* callExpression = AST::replaceWith<AST::CallExpression>(propertyAccessExpression, WTFMove(origin), String(getterFunction.name()), WTFMove(arguments)); >- callExpression->setFunction(getterFunction); >- callExpression->setType(getterFunction.type().clone()); >+ auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(anderFunction->name()), WTFMove(arguments)); >+ callExpression->setType(anderFunction->type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); >- return true; >- } >- >- // We have an ander, but no left value to call it on. Let's save the value into a temporary variable to create a left value. >- // This is effectively inlining the functions the spec says are generated. >- ASSERT(propertyAccessExpression.threadAnderFunction()); >- auto* threadAnderFunction = propertyAccessExpression.threadAnderFunction(); >- >- auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), base.resolvedType().clone(), String(), WTF::nullopt, WTF::nullopt); >+ callExpression->setFunction(*anderFunction); > >- auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >- variableReference1->setType(base.resolvedType().clone()); >- variableReference1->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >- >- auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(origin), WTFMove(variableReference1), propertyAccessExpression.takeBase()); >- assignmentExpression->setType(base.resolvedType().clone()); >- assignmentExpression->setTypeAnnotation(AST::RightValue()); >+ auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(propertyAccessExpression, WTFMove(origin), WTFMove(callExpression)); >+ dereferenceExpression->setType(downcast<AST::PointerType>(anderFunction->type()).elementType().clone()); >+ dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(anderFunction->type()).addressSpace() }); > >- auto variableReference2 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >- variableReference2->setType(base.resolvedType().clone()); >- variableReference2->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ if (auto& variableDeclaration = argument->variableDeclaration) >+ m_variableDeclarations.append(WTFMove(*variableDeclaration)); > >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), WTFMove(variableReference2)); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(origin), AST::AddressSpace::Thread, base.resolvedType().clone())); >- makePointerExpression->setTypeAnnotation(AST::RightValue()); >+ return; >+ } > >+ ASSERT(propertyAccessExpression.getterFunction()); >+ auto& getterFunction = *propertyAccessExpression.getterFunction(); > Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(WTFMove(makePointerExpression)); >+ arguments.append(propertyAccessExpression.takeBase()); > if (is<AST::IndexExpression>(propertyAccessExpression)) > arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); >- auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(threadAnderFunction->name()), WTFMove(arguments)); >- callExpression->setType(threadAnderFunction->type().clone()); >+ auto* callExpression = AST::replaceWith<AST::CallExpression>(propertyAccessExpression, WTFMove(origin), String(getterFunction.name()), WTFMove(arguments)); >+ callExpression->setFunction(getterFunction); >+ callExpression->setType(getterFunction.type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); >- callExpression->setFunction(*threadAnderFunction); >- >- auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(WTFMove(origin), WTFMove(callExpression)); >- dereferenceExpression->setType(downcast<AST::PointerType>(threadAnderFunction->type()).elementType().clone()); >- dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >- >- Vector<UniqueRef<AST::Expression>> expressions; >- expressions.append(WTFMove(assignmentExpression)); >- expressions.append(WTFMove(dereferenceExpression)); >- auto* commaExpression = AST::replaceWith<AST::CommaExpression>(propertyAccessExpression, WTFMove(origin), WTFMove(expressions)); >- commaExpression->setType(downcast<AST::PointerType>(threadAnderFunction->type()).elementType().clone()); >- commaExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >- >- m_variableDeclarations.append(WTFMove(variableDeclaration)); >- return true; >- > } > > class LeftValueSimplifier : public Visitor { >@@ -777,14 +776,14 @@ void LeftValueSimplifier::finishVisiting(AST::PropertyAccessExpression& property > > Lexer::Token origin = propertyAccessExpression.origin(); > auto* anderFunction = propertyAccessExpression.anderFunction(); >- auto& base = propertyAccessExpression.base(); >- auto leftAddressSpace = *propertyAccessExpression.base().typeAnnotation().leftAddressSpace(); >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), propertyAccessExpression.takeBase()); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(origin), leftAddressSpace, base.resolvedType().clone())); >- makePointerExpression->setTypeAnnotation(AST::RightValue()); >+ >+ auto argument = anderCallArgument(propertyAccessExpression); >+ ASSERT(argument); >+ ASSERT(!argument->variableDeclaration); >+ ASSERT(argument->whichAnder == WhichAnder::Ander); > > Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(WTFMove(makePointerExpression)); >+ arguments.append(WTFMove(argument->expression)); > if (is<AST::IndexExpression>(propertyAccessExpression)) > arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); > auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(anderFunction->name()), WTFMove(arguments)); >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp >index 7a551bf28028626e0a9fd00e82823518a36fbb8e..5002ee526c55eb8ccd2576861e5ab2083a4707ab 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp >@@ -55,19 +55,17 @@ static AST::FunctionDefinition* findEntryPoint(Vector<UniqueRef<AST::FunctionDef > return &*iterator; > }; > >-static bool matchMode(BindingType bindingType, AST::ResourceSemantic::Mode mode) >+static bool matchMode(Binding::BindingDetails bindingType, AST::ResourceSemantic::Mode mode) > { >- switch (bindingType) { >- case BindingType::UniformBuffer: >+ return WTF::visit(WTF::makeVisitor([&](UniformBufferBinding) -> bool { > return mode == AST::ResourceSemantic::Mode::Buffer; >- case BindingType::Sampler: >+ }, [&](SamplerBinding) -> bool { > return mode == AST::ResourceSemantic::Mode::Sampler; >- case BindingType::Texture: >+ }, [&](TextureBinding) -> bool { > return mode == AST::ResourceSemantic::Mode::Texture; >- default: >- ASSERT(bindingType == BindingType::StorageBuffer); >+ }, [&](StorageBufferBinding) -> bool { > return mode == AST::ResourceSemantic::Mode::UnorderedAccessView; >- } >+ }), bindingType); > } > > static Optional<HashMap<Binding*, size_t>> matchResources(Vector<EntryPointItem>& entryPointItems, Layout& layout, ShaderStage shaderStage) >@@ -87,9 +85,9 @@ static Optional<HashMap<Binding*, size_t>> matchResources(Vector<EntryPointItem> > if (!WTF::holds_alternative<AST::ResourceSemantic>(semantic)) > continue; > auto& resourceSemantic = WTF::get<AST::ResourceSemantic>(semantic); >- if (!matchMode(binding.bindingType, resourceSemantic.mode())) >+ if (!matchMode(binding.binding, resourceSemantic.mode())) > continue; >- if (binding.name != resourceSemantic.index()) >+ if (binding.externalName != resourceSemantic.index()) > continue; > if (space != resourceSemantic.space()) > continue; >diff --git a/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp b/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp >index 9851567e7c1e1e3ea021d7f8f5795718a234e540..3e510c574f3ef863b1a1012f5ef6399134b9c17c 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp >+++ b/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp >@@ -111,7 +111,7 @@ Optional<GPUBindGroupDescriptor> WebGPUBindGroupDescriptor::tryCreateGPUBindGrou > if (!buffer) > return WTF::nullopt; > >- if (!validateBufferBindingType(buffer, layoutBinding, functionName)) >+ if (!validateBufferBindingType(buffer, layoutBinding.externalBinding, functionName)) > return WTF::nullopt; > > return static_cast<GPUBindingResource>(GPUBufferBinding { makeRef(*buffer), bufferBinding.offset, bufferBinding.size }); >@@ -119,7 +119,7 @@ Optional<GPUBindGroupDescriptor> WebGPUBindGroupDescriptor::tryCreateGPUBindGrou > > auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource); > if (!bindingResource) { >- LOG(WebGPU, "%s: Invalid resource for binding %u!", functionName, layoutBinding.binding); >+ LOG(WebGPU, "%s: Invalid resource for binding %u!", functionName, layoutBinding.externalBinding.binding); > return WTF::nullopt; > } > >diff --git a/Source/WebCore/platform/graphics/gpu/GPUBindGroupLayout.h b/Source/WebCore/platform/graphics/gpu/GPUBindGroupLayout.h >index a55b1c91368c48ed9566d77829f1f13495162801..f7762c3c3b1332499149793e8a5b2d24135c56ae 100644 >--- a/Source/WebCore/platform/graphics/gpu/GPUBindGroupLayout.h >+++ b/Source/WebCore/platform/graphics/gpu/GPUBindGroupLayout.h >@@ -33,6 +33,7 @@ > #include <wtf/RefCounted.h> > #include <wtf/RefPtr.h> > #include <wtf/RetainPtr.h> >+#include <wtf/Variant.h> > > #if USE(METAL) > OBJC_PROTOCOL(MTLArgumentEncoder); >@@ -47,7 +48,37 @@ class GPUBindGroupLayout : public RefCounted<GPUBindGroupLayout> { > public: > static RefPtr<GPUBindGroupLayout> tryCreate(const GPUDevice&, const GPUBindGroupLayoutDescriptor&); > >- using BindingsMapType = HashMap<uint64_t, GPUBindGroupLayoutBinding, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>>; >+ struct UniformBuffer { >+ unsigned internalLengthName; >+ }; >+ >+ struct DynamicUniformBuffer { >+ unsigned internalLengthName; >+ }; >+ >+ struct Sampler { >+ }; >+ >+ struct SampledTexture { >+ }; >+ >+ struct StorageBuffer { >+ unsigned internalLengthName; >+ }; >+ >+ struct DynamicStorageBuffer { >+ unsigned internalLengthName; >+ }; >+ >+ using InternalBindingDetails = Variant<UniformBuffer, DynamicUniformBuffer, Sampler, SampledTexture, StorageBuffer, DynamicStorageBuffer>; >+ >+ struct Binding { >+ GPUBindGroupLayoutBinding externalBinding; >+ unsigned internalName; >+ InternalBindingDetails internalBindingDetails; >+ }; >+ >+ using BindingsMapType = HashMap<uint64_t, Binding, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>>; > const BindingsMapType& bindingsMap() const { return m_bindingsMap; } > #if USE(METAL) > MTLArgumentEncoder *vertexEncoder() const { return m_vertexEncoder.get(); } >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupLayoutMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupLayoutMetal.mm >index e2ed11a62883f88d55d3f73e6cac92008205915a..35ae3c96420185102c9368c4c60b55aedb1a4772 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupLayoutMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupLayoutMetal.mm >@@ -77,6 +77,18 @@ static RetainPtr<MTLArgumentEncoder> tryCreateMtlArgumentEncoder(const GPUDevice > return encoder; > }; > >+static RetainPtr<MTLArgumentDescriptor> argumentDescriptor(MTLDataType dataType, NSUInteger index) >+{ >+ RetainPtr<MTLArgumentDescriptor> mtlArgument; >+ BEGIN_BLOCK_OBJC_EXCEPTIONS; >+ mtlArgument = adoptNS([MTLArgumentDescriptor new]); >+ END_BLOCK_OBJC_EXCEPTIONS; >+ >+ [mtlArgument setDataType:dataType]; >+ [mtlArgument setIndex:index]; >+ return mtlArgument; >+} >+ > RefPtr<GPUBindGroupLayout> GPUBindGroupLayout::tryCreate(const GPUDevice& device, const GPUBindGroupLayoutDescriptor& descriptor) > { > if (!device.platformDevice()) { >@@ -87,48 +99,73 @@ RefPtr<GPUBindGroupLayout> GPUBindGroupLayout::tryCreate(const GPUDevice& device > ArgumentArray vertexArgsArray, fragmentArgsArray, computeArgsArray; > BindingsMapType bindingsMap; > >+ unsigned internalName = 0; >+ unsigned internalLengthBase = descriptor.bindings.size(); > for (const auto& binding : descriptor.bindings) { >- if (!bindingsMap.add(binding.binding, binding)) { >+ Optional<unsigned> extraIndex; >+ auto internalDetails = ([&]() -> GPUBindGroupLayout::InternalBindingDetails { >+ switch (binding.type) { >+ case GPUBindingType::UniformBuffer: >+ extraIndex = internalLengthBase++; >+ return GPUBindGroupLayout::UniformBuffer { *extraIndex }; >+ case GPUBindingType::DynamicUniformBuffer: >+ extraIndex = internalLengthBase++; >+ return GPUBindGroupLayout::DynamicUniformBuffer { *extraIndex }; >+ case GPUBindingType::Sampler: >+ return GPUBindGroupLayout::Sampler { }; >+ case GPUBindingType::SampledTexture: >+ return GPUBindGroupLayout::SampledTexture { }; >+ case GPUBindingType::StorageBuffer: >+ extraIndex = internalLengthBase++; >+ return GPUBindGroupLayout::StorageBuffer { *extraIndex }; >+ default: >+ ASSERT(binding.type == GPUBindingType::DynamicStorageBuffer); >+ extraIndex = internalLengthBase++; >+ return GPUBindGroupLayout::DynamicStorageBuffer { *extraIndex }; >+ } >+ })(); >+ Binding bindingDetails = { binding, internalName++, WTFMove(internalDetails) }; >+ if (!bindingsMap.add(binding.binding, bindingDetails)) { > LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Duplicate binding %u found in GPUBindGroupLayoutDescriptor!", binding.binding); > return nullptr; > } > >- RetainPtr<MTLArgumentDescriptor> mtlArgument; >+ RetainPtr<MTLArgumentDescriptor> mtlArgument = argumentDescriptor(MTLDataTypeForBindingType(binding.type), bindingDetails.internalName); > >- BEGIN_BLOCK_OBJC_EXCEPTIONS; >- mtlArgument = adoptNS([MTLArgumentDescriptor new]); >- END_BLOCK_OBJC_EXCEPTIONS; > if (!mtlArgument) { > LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Unable to create MTLArgumentDescriptor for binding %u!", binding.binding); > return nullptr; > } > >- [mtlArgument setDataType:MTLDataTypeForBindingType(binding.type)]; >- [mtlArgument setIndex:binding.binding]; >- >- if (binding.visibility & GPUShaderStageBit::Flags::Vertex) >- appendArgumentToArray(vertexArgsArray, mtlArgument); >- if (binding.visibility & GPUShaderStageBit::Flags::Fragment) >- appendArgumentToArray(fragmentArgsArray, mtlArgument); >- if (binding.visibility & GPUShaderStageBit::Flags::Compute) >- appendArgumentToArray(computeArgsArray, mtlArgument); >- } >- >- RetainPtr<MTLArgumentEncoder> vertex, fragment, compute; >- >- if (vertexArgsArray) { >- if (!(vertex = tryCreateMtlArgumentEncoder(device, vertexArgsArray))) >+ auto addIndices = [&](ArgumentArray& array) -> bool { >+ appendArgumentToArray(array, mtlArgument); >+ if (extraIndex) { >+ RetainPtr<MTLArgumentDescriptor> mtlArgument = argumentDescriptor(MTLDataTypeUInt2, *extraIndex); >+ if (!mtlArgument) { >+ LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Unable to create MTLArgumentDescriptor for binding %u!", binding.binding); >+ return false; >+ } >+ appendArgumentToArray(array, mtlArgument); >+ } >+ return true; >+ }; >+ if ((binding.visibility & GPUShaderStageBit::Flags::Vertex) && !addIndices(vertexArgsArray)) > return nullptr; >- } >- if (fragmentArgsArray) { >- if (!(fragment = tryCreateMtlArgumentEncoder(device, fragmentArgsArray))) >+ if ((binding.visibility & GPUShaderStageBit::Flags::Fragment) && !addIndices(fragmentArgsArray)) > return nullptr; >- } >- if (computeArgsArray) { >- if (!(compute = tryCreateMtlArgumentEncoder(device, computeArgsArray))) >+ if ((binding.visibility & GPUShaderStageBit::Flags::Compute) && !addIndices(computeArgsArray)) > return nullptr; > } > >+ RetainPtr<MTLArgumentEncoder> vertex, fragment, compute; >+ >+ if (vertexArgsArray && !(vertex = tryCreateMtlArgumentEncoder(device, vertexArgsArray))) >+ return nullptr; >+ if (fragmentArgsArray && !(fragment = tryCreateMtlArgumentEncoder(device, fragmentArgsArray))) >+ return nullptr; >+ if (computeArgsArray && !(compute = tryCreateMtlArgumentEncoder(device, computeArgsArray))) >+ return nullptr; >+ > return adoptRef(new GPUBindGroupLayout(WTFMove(bindingsMap), WTFMove(vertex), WTFMove(fragment), WTFMove(compute))); > } > >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm >index da2c20d03ef71cb26d7d6c11712c562fec1dcd45..6262e5f6d4156cd55ec0edabdc5a5c764d42ae48 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupMetal.mm >@@ -72,13 +72,15 @@ static Optional<GPUBufferBinding> tryGetResourceAsBufferBinding(const GPUBinding > return GPUBufferBinding { bufferBinding.buffer.copyRef(), bufferBinding.offset, bufferBinding.size }; > } > >-static void setBufferOnEncoder(MTLArgumentEncoder *argumentEncoder, const GPUBufferBinding& bufferBinding, unsigned index) >+static void setBufferOnEncoder(MTLArgumentEncoder *argumentEncoder, const GPUBufferBinding& bufferBinding, unsigned name, unsigned lengthName) > { > ASSERT(argumentEncoder && bufferBinding.buffer->platformBuffer()); > > BEGIN_BLOCK_OBJC_EXCEPTIONS; > // Bounds check when converting GPUBufferBinding ensures that NSUInteger cast of uint64_t offset is safe. >- [argumentEncoder setBuffer:bufferBinding.buffer->platformBuffer() offset:static_cast<NSUInteger>(bufferBinding.offset) atIndex:index]; >+ [argumentEncoder setBuffer:bufferBinding.buffer->platformBuffer() offset:static_cast<NSUInteger>(bufferBinding.offset) atIndex:name]; >+ void* lengthPointer = [argumentEncoder constantDataAtIndex:lengthName]; >+ memcpy(lengthPointer, &bufferBinding.size, sizeof(uint64_t)); > END_BLOCK_OBJC_EXCEPTIONS; > } > >@@ -171,12 +173,12 @@ RefPtr<GPUBindGroup> GPUBindGroup::tryCreate(const GPUBindGroupDescriptor& descr > return nullptr; > } > auto layoutBinding = layoutIterator->value; >- if (layoutBinding.visibility == GPUShaderStageBit::Flags::None) >+ if (layoutBinding.externalBinding.visibility == GPUShaderStageBit::Flags::None) > continue; > >- bool isForVertex = layoutBinding.visibility & GPUShaderStageBit::Flags::Vertex; >- bool isForFragment = layoutBinding.visibility & GPUShaderStageBit::Flags::Fragment; >- bool isForCompute = layoutBinding.visibility & GPUShaderStageBit::Flags::Compute; >+ bool isForVertex = layoutBinding.externalBinding.visibility & GPUShaderStageBit::Flags::Vertex; >+ bool isForFragment = layoutBinding.externalBinding.visibility & GPUShaderStageBit::Flags::Fragment; >+ bool isForCompute = layoutBinding.externalBinding.visibility & GPUShaderStageBit::Flags::Compute; > > if (isForVertex && !vertexEncoder) { > LOG(WebGPU, "%s: No vertex argument encoder found for binding %u!", functionName, index); >@@ -191,39 +193,39 @@ RefPtr<GPUBindGroup> GPUBindGroup::tryCreate(const GPUBindGroupDescriptor& descr > return nullptr; > } > >- switch (layoutBinding.type) { >- // FIXME: Support more resource types. >- // FIXME: We could avoid this ugly switch-on-type using virtual functions if GPUBindingResource is refactored as a base class rather than a Variant. >- case GPUBindingType::UniformBuffer: >- case GPUBindingType::StorageBuffer: { >+ auto handleBuffer = [&](unsigned internalLengthName) -> bool { > auto bufferResource = tryGetResourceAsBufferBinding(resourceBinding.resource, functionName); > if (!bufferResource) >- return nullptr; >+ return false; > if (isForVertex) >- setBufferOnEncoder(vertexEncoder, *bufferResource, index); >+ setBufferOnEncoder(vertexEncoder, *bufferResource, layoutBinding.internalName, internalLengthName); > if (isForFragment) >- setBufferOnEncoder(fragmentEncoder, *bufferResource, index); >+ setBufferOnEncoder(fragmentEncoder, *bufferResource, layoutBinding.internalName, internalLengthName); > if (isForCompute) >- setBufferOnEncoder(computeEncoder, *bufferResource, index); >+ setBufferOnEncoder(computeEncoder, *bufferResource, layoutBinding.internalName, internalLengthName); > boundBuffers.append(bufferResource->buffer.copyRef()); >- break; >- } >- case GPUBindingType::Sampler: { >+ return true; >+ }; >+ >+ auto success = WTF::visit(WTF::makeVisitor([&](GPUBindGroupLayout::UniformBuffer& uniformBuffer) -> bool { >+ return handleBuffer(uniformBuffer.internalLengthName); >+ }, [&](GPUBindGroupLayout::DynamicUniformBuffer& dynamicUniformBuffer) -> bool { >+ return handleBuffer(dynamicUniformBuffer.internalLengthName); >+ }, [&](GPUBindGroupLayout::Sampler&) -> bool { > auto samplerState = tryGetResourceAsMtlSampler(resourceBinding.resource, functionName); > if (!samplerState) >- return nullptr; >+ return false; > if (isForVertex) > setSamplerOnEncoder(vertexEncoder, samplerState, index); > if (isForFragment) > setSamplerOnEncoder(fragmentEncoder, samplerState, index); > if (isForCompute) > setSamplerOnEncoder(computeEncoder, samplerState, index); >- break; >- } >- case GPUBindingType::SampledTexture: { >+ return true; >+ }, [&](GPUBindGroupLayout::SampledTexture&) -> bool { > auto textureResource = tryGetResourceAsTexture(resourceBinding.resource, functionName); > if (!textureResource) >- return nullptr; >+ return false; > if (isForVertex) > setTextureOnEncoder(vertexEncoder, textureResource->platformTexture(), index); > if (isForFragment) >@@ -231,12 +233,14 @@ RefPtr<GPUBindGroup> GPUBindGroup::tryCreate(const GPUBindGroupDescriptor& descr > if (isForCompute) > setTextureOnEncoder(computeEncoder, textureResource->platformTexture(), index); > boundTextures.append(textureResource.releaseNonNull()); >- break; >- } >- default: >- LOG(WebGPU, "%s: Resource type not yet implemented.", functionName); >+ return true; >+ }, [&](GPUBindGroupLayout::StorageBuffer& storageBuffer) -> bool { >+ return handleBuffer(storageBuffer.internalLengthName); >+ }, [&](GPUBindGroupLayout::DynamicStorageBuffer& dynamicStorageBuffer) -> bool { >+ return handleBuffer(dynamicStorageBuffer.internalLengthName); >+ }), layoutBinding.internalBindingDetails); >+ if (!success) > return nullptr; >- } > } > > return adoptRef(new GPUBindGroup(WTFMove(vertexArgsBuffer), WTFMove(fragmentArgsBuffer), WTFMove(computeArgsBuffer), WTFMove(boundBuffers), WTFMove(boundTextures))); >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >index 2bb620409410deaf659b0ad49223091ceb1f99ba..4a9eebbe1302660f0e9b644b38e5ac83b848a7e9 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >@@ -110,20 +110,21 @@ static OptionSet<WHLSL::ShaderStage> convertShaderStageFlags(GPUShaderStageFlags > return result; > } > >-static Optional<WHLSL::BindingType> convertBindingType(GPUBindingType type) >+static Optional<WHLSL::Binding::BindingDetails> convertBindingType(GPUBindGroupLayout::InternalBindingDetails internalBindingDetails) > { >- switch (type) { >- case GPUBindingType::UniformBuffer: >- return WHLSL::BindingType::UniformBuffer; >- case GPUBindingType::Sampler: >- return WHLSL::BindingType::Sampler; >- case GPUBindingType::SampledTexture: >- return WHLSL::BindingType::Texture; >- case GPUBindingType::StorageBuffer: >- return WHLSL::BindingType::StorageBuffer; >- default: >+ return WTF::visit(WTF::makeVisitor([&](GPUBindGroupLayout::UniformBuffer uniformBuffer) -> Optional<WHLSL::Binding::BindingDetails> { >+ return { WHLSL::UniformBufferBinding { uniformBuffer.internalLengthName } }; >+ }, [&](GPUBindGroupLayout::DynamicUniformBuffer) -> Optional<WHLSL::Binding::BindingDetails> { > return WTF::nullopt; >- } >+ }, [&](GPUBindGroupLayout::Sampler) -> Optional<WHLSL::Binding::BindingDetails> { >+ return { WHLSL::SamplerBinding { } }; >+ }, [&](GPUBindGroupLayout::SampledTexture) -> Optional<WHLSL::Binding::BindingDetails> { >+ return { WHLSL::TextureBinding { } }; >+ }, [&](GPUBindGroupLayout::StorageBuffer storageBuffer) -> Optional<WHLSL::Binding::BindingDetails> { >+ return { WHLSL::StorageBufferBinding { storageBuffer.internalLengthName } }; >+ }, [&](GPUBindGroupLayout::DynamicStorageBuffer) -> Optional<WHLSL::Binding::BindingDetails> { >+ return WTF::nullopt; >+ }), internalBindingDetails); > } > > static Optional<WHLSL::TextureFormat> convertTextureFormat(GPUTextureFormat format) >@@ -377,16 +378,17 @@ static Optional<WHLSL::Layout> convertLayout(const GPUPipelineLayout& layout) > WHLSL::BindGroup bindGroup; > bindGroup.name = static_cast<unsigned>(i); > for (const auto& keyValuePair : bindGroupLayout->bindingsMap()) { >- const auto& gpuBindGroupLayoutBinding = keyValuePair.value; >+ const auto& bindingDetails = keyValuePair.value; > WHLSL::Binding binding; >- binding.visibility = convertShaderStageFlags(gpuBindGroupLayoutBinding.visibility); >- if (auto bindingType = convertBindingType(gpuBindGroupLayoutBinding.type)) >- binding.bindingType = *bindingType; >+ binding.visibility = convertShaderStageFlags(bindingDetails.externalBinding.visibility); >+ if (auto bindingType = convertBindingType(bindingDetails.internalBindingDetails)) >+ binding.binding = *bindingType; > else > return WTF::nullopt; >- if (gpuBindGroupLayoutBinding.binding > std::numeric_limits<unsigned>::max()) >+ if (bindingDetails.externalBinding.binding > std::numeric_limits<unsigned>::max()) > return WTF::nullopt; >- binding.name = static_cast<unsigned>(gpuBindGroupLayoutBinding.binding); >+ binding.externalName = bindingDetails.externalBinding.binding; >+ binding.internalName = bindingDetails.internalName; > bindGroup.bindings.append(WTFMove(binding)); > } > result.append(WTFMove(bindGroup)); >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 861721226ef5d8b0f4d0103c0e78d775d664403f..6c70f2ca0f3c439daeb2e701e10d8e87c7201cd2 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,20 @@ >+2019-06-06 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] Implement array references >+ https://bugs.webkit.org/show_bug.cgi?id=198163 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * webgpu/buffer-resource-triangles-expected.html: Deleted. This test doens't make any sense and triggers >+ Metal to read out-of-bounds of a vertex buffer. >+ * webgpu/buffer-resource-triangles.html: Deleted. >+ * webgpu/whlsl-buffer-fragment-expected.html: Added. >+ * webgpu/whlsl-buffer-fragment.html: Added. >+ * webgpu/whlsl-buffer-vertex-expected.html: Added. >+ * webgpu/whlsl-buffer-vertex.html: Added. >+ * webgpu/whlsl-dont-crash-parsing-enum.html: >+ * webgpu/whlsl.html: >+ > 2019-06-06 Youenn Fablet <youenn@apple.com> > > Allow WebKitTestRunner to terminate network process after it finishes service worker file operations >diff --git a/LayoutTests/webgpu/buffer-resource-triangles-expected.html b/LayoutTests/webgpu/buffer-resource-triangles-expected.html >deleted file mode 100644 >index 886f13e8120397a5cc6336c9e2a485e778ba9932..0000000000000000000000000000000000000000 >--- a/LayoutTests/webgpu/buffer-resource-triangles-expected.html >+++ /dev/null >@@ -1,12 +0,0 @@ >-<!DOCTYPE html> >-<meta charset="utf-8"> >-<title>HTML Reference File</title> >-<p>Pass if square canvas below is completely green.</p> >-<canvas width="400" height="400"></canvas> >-<script> >-const canvas = document.querySelector("canvas"); >-const context = canvas.getContext('2d'); >- >-context.fillStyle = 'rgb(0, 255, 0)'; >-context.fillRect(0, 0, canvas.width, canvas.height); >-</script> >\ No newline at end of file >diff --git a/LayoutTests/webgpu/buffer-resource-triangles.html b/LayoutTests/webgpu/buffer-resource-triangles.html >deleted file mode 100644 >index bd06c457d497e6b38441f79161697b7b08c6824d..0000000000000000000000000000000000000000 >--- a/LayoutTests/webgpu/buffer-resource-triangles.html >+++ /dev/null >@@ -1,210 +0,0 @@ >-<!DOCTYPE html> >-<meta charset="utf-8"> >-<title>WebGPU Hello Triangles</title> >-<meta name="assert" content="WebGPU correctly renders a green canvas."> >-<link rel="match" href="buffer-resource-triangles-expected.html"> >-<p>Pass if square canvas below is completely green.</p> >-<canvas width="400" height="400"></canvas> >-<script src="js/webgpu-functions.js"></script> >-<script> >-if (window.testRunner) >- testRunner.waitUntilDone(); >- >-const shaderCode = ` >-#include <metal_stdlib> >- >-using namespace metal; >- >-struct VertexInput { >- float4 position [[attribute(0)]]; >-}; >- >-struct Vertex { >- float4 position [[position]]; >-}; >- >-struct VertexArguments { >- device Vertex* v0; >- device Vertex* v1; >- device Vertex* v2; >-}; >- >-vertex Vertex vertex_main( >- VertexInput input [[stage_in]], >- const device VertexArguments& args0 [[buffer(0)]], >- const device VertexArguments& args1 [[buffer(1)]], >- uint vid [[vertex_id]]) >-{ >- switch (vid) >- { >- case 0: >- case 1: >- case 2: { >- Vertex out; >- out.position = input.position; >- return out; >- } >- case 3: return *args0.v0; >- case 4: return *args0.v1; >- case 5: return *args0.v2; >- case 6: return *args1.v0; >- case 7: return *args1.v1; >- default: return *args1.v2; >- } >-} >- >-struct FragmentArguments { >- device float4* color; >-}; >- >-fragment float4 fragment_main(const device FragmentArguments& args [[buffer(0)]]) >-{ >- return args.color[0]; >-} >-` >- >-const bindingNums = { >- UL: 0, >- UM: 1, >- UR: 2, >- LL: 3, >- LR: 4, >- G: 5 >-}; >- >-function createUniformBufferBindGroupLayout(bindNum, stage = GPUShaderStageBit.VERTEX) { >- return { >- binding: bindNum, >- visibility: stage, >- type: "uniform-buffer" >- }; >-} >- >-const vertexSize = 4 * 4; >-const verticesBufferSize = vertexSize * 3; >-function createAndUploadVerticesBuffer(device) { >- const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST }); >- const arrayBuffer = new Float32Array([ >- 0, 1, 0, 1, >- -1, -1, 0, 1, >- 1, -1, 0, 1 >- ]).buffer; >- >- buffer.setSubData(0, arrayBuffer); >- return buffer; >-} >- >-function createFloat4Buffer(device, a, b, promises) { >- const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE }); >- >- const promise = buffer.mapWriteAsync().then(mapping => { >- const mappedArray = new Float32Array(mapping); >- mappedArray.set([a, b, 0, 1]); >- buffer.unmap(); >- }); >- >- promises.push(promise); >- return buffer; >-} >- >-function createBufferBinding(buffer) { >- return { buffer: buffer, size: vertexSize }; >-} >- >-async function test() { >- const device = await getBasicDevice(); >- const canvas = document.querySelector("canvas"); >- const swapChain = createBasicSwapChain(canvas, device); >- // FIXME: Replace with non-MSL shaders. >- const shaderModule = device.createShaderModule({ code: shaderCode }); >- >- // Create vertex data GPUBuffers. >- const verticesBuffer = createAndUploadVerticesBuffer(device); >- >- let bufferPromises = []; >- const upperLeft = createFloat4Buffer(device, -1, 1, bufferPromises); >- const upperMiddle = createFloat4Buffer(device, 0, 1, bufferPromises); >- const upperRight = createFloat4Buffer(device, 1, 1, bufferPromises); >- const lowerLeft = createFloat4Buffer(device, -1, -1, bufferPromises); >- const lowerRight = createFloat4Buffer(device, 1, -1, bufferPromises); >- >- // Color data buffer. >- const green = createFloat4Buffer(device, 0, 1, bufferPromises); >- >- // Create vertex input state. >- const vertexInput = { >- indexFormat: "uint32", >- vertexBuffers: [{ >- stride: vertexSize, >- attributeSet: [{ >- format: "float4", >- shaderLocation: 0 >- }] >- }] >- }; >- >- // Create buffer GPUBindGroupLayoutBindings. >- const layoutUL = createUniformBufferBindGroupLayout(bindingNums.UL); >- const layoutUM = createUniformBufferBindGroupLayout(bindingNums.UM); >- const layoutUR = createUniformBufferBindGroupLayout(bindingNums.UR); >- const layoutLL = createUniformBufferBindGroupLayout(bindingNums.LL); >- const layoutLR = createUniformBufferBindGroupLayout(bindingNums.LR); >- const layoutG = createUniformBufferBindGroupLayout(bindingNums.G, GPUShaderStageBit.FRAGMENT); >- >- // GPUBindGroupLayouts >- const leftTriangleBGLayout = device.createBindGroupLayout({ bindings: [layoutUL, layoutUM, layoutLL, layoutG] }); >- const rightTriangleBGLayout = device.createBindGroupLayout({ bindings: [layoutUR, layoutUM, layoutLR] }); >- >- // GPUPipelineLayout and GPURenderPipeline >- const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [leftTriangleBGLayout, rightTriangleBGLayout] }); >- const pipeline = createBasicPipeline(shaderModule, device, null, pipelineLayout, vertexInput, null, "triangle-list"); >- >- // GPUBufferBindings >- const bindingUL = createBufferBinding(upperLeft); >- const bindingUM = createBufferBinding(upperMiddle); >- const bindingUR = createBufferBinding(upperRight); >- const bindingLL = createBufferBinding(lowerLeft); >- const bindingLR = createBufferBinding(lowerRight); >- const bindingG = createBufferBinding(green); >- >- // GPUBindGroupBindings >- const bgBindingUL = { binding: bindingNums.UL, resource: bindingUL }; >- const bgBindingUM = { binding: bindingNums.UM, resource: bindingUM }; >- const bgBindingUR = { binding: bindingNums.UR, resource: bindingUR }; >- const bgBindingLL = { binding: bindingNums.LL, resource: bindingLL }; >- const bgBindingLR = { binding: bindingNums.LR, resource: bindingLR }; >- const bgBindingG = { binding: bindingNums.G, resource: bindingG }; >- >- // GPUBindGroups >- const leftTriangleBG = device.createBindGroup({ >- layout: leftTriangleBGLayout, >- bindings: [bgBindingUL, bgBindingUM, bgBindingLL, bgBindingG] >- }); >- const rightTriangleBG = device.createBindGroup({ >- layout: rightTriangleBGLayout, >- bindings: [bgBindingUR, bgBindingUM, bgBindingLR] >- }); >- >- Promise.all(bufferPromises).then(() => { >- const commandEncoder = device.createCommandEncoder(); >- const passEncoder = beginBasicRenderPass(swapChain, commandEncoder); >- passEncoder.setPipeline(pipeline); >- >- // Vertex data for upper triangles. >- passEncoder.setBindGroup(0, leftTriangleBG); >- passEncoder.setBindGroup(1, rightTriangleBG); >- // Lower triangle. >- passEncoder.setVertexBuffers(0, [verticesBuffer], [0]); >- passEncoder.draw(9, 1, 0, 0); >- >- passEncoder.endPass(); >- const queue = device.getQueue(); >- queue.submit([commandEncoder.finish()]); >- >- if (window.testRunner) >- testRunner.notifyDone(); >- }); >-} >- >-test(); >-</script> >\ No newline at end of file >diff --git a/LayoutTests/webgpu/whlsl-buffer-fragment-expected.html b/LayoutTests/webgpu/whlsl-buffer-fragment-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/whlsl-buffer-fragment-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/whlsl-buffer-fragment.html b/LayoutTests/webgpu/whlsl-buffer-fragment.html >new file mode 100644 >index 0000000000000000000000000000000000000000..34d0378b4cf6698c61eb04041f303d6d248a8adb >--- /dev/null >+++ b/LayoutTests/webgpu/whlsl-buffer-fragment.html >@@ -0,0 +1,119 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0), float i : attribute(1)) : SV_Position { >+ return position; >+} >+ >+fragment float4 fragmentShader(float4 position : SV_Position, constant float[] theBuffer : register(b0)) : SV_Target 0 { >+ return float4(theBuffer[0], theBuffer[0], theBuffer[0], 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, 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 attribute0 = {shaderLocation: 0, format: "float4"}; >+ const attribute1 = {shaderLocation: 1, format: "float"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const input1 = {stride: 4, attributeSet: [attribute1]}; >+ const inputs = [input0, input1]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor); >+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync(); >+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer); >+ vertexBuffer0Float32Array[0] = -0.5; >+ vertexBuffer0Float32Array[1] = -0.5; >+ vertexBuffer0Float32Array[2] = 1.0; >+ vertexBuffer0Float32Array[3] = 1; >+ vertexBuffer0Float32Array[4] = -0.5; >+ vertexBuffer0Float32Array[5] = 0.5; >+ vertexBuffer0Float32Array[6] = 1.0; >+ vertexBuffer0Float32Array[7] = 1; >+ vertexBuffer0Float32Array[8] = 0.5; >+ vertexBuffer0Float32Array[9] = -0.5; >+ vertexBuffer0Float32Array[10] = 1.0; >+ vertexBuffer0Float32Array[11] = 1; >+ vertexBuffer0Float32Array[12] = 0.5; >+ vertexBuffer0Float32Array[13] = 0.5; >+ vertexBuffer0Float32Array[14] = 1.0; >+ vertexBuffer0Float32Array[15] = 1; >+ vertexBuffer0.unmap(); >+ >+ const vertexBuffer1Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer1 = device.createBuffer(vertexBuffer1Descriptor); >+ const vertexBuffer1ArrayBuffer = await vertexBuffer1.mapWriteAsync(); >+ const vertexBuffer1Float32Array = new Float32Array(vertexBuffer1ArrayBuffer); >+ vertexBuffer1Float32Array[0] = 1; >+ vertexBuffer1Float32Array[1] = 1; >+ vertexBuffer1Float32Array[2] = 1; >+ vertexBuffer1Float32Array[3] = 1; >+ vertexBuffer1.unmap(); >+ >+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE}; >+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor); >+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync(); >+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer); >+ resourceBufferFloat32Array[0] = 1; >+ resourceBuffer.unmap(); >+ >+ const bufferBinding = {buffer: resourceBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const canvas = document.getElementById("canvas"); >+ 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.setBindGroup(0, bindGroup); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0, vertexBuffer1], [0, 0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/whlsl-buffer-vertex-expected.html b/LayoutTests/webgpu/whlsl-buffer-vertex-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/whlsl-buffer-vertex-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/whlsl-buffer-vertex.html b/LayoutTests/webgpu/whlsl-buffer-vertex.html >new file mode 100644 >index 0000000000000000000000000000000000000000..3fc37357d27c72680e5404d67e410de877086084 >--- /dev/null >+++ b/LayoutTests/webgpu/whlsl-buffer-vertex.html >@@ -0,0 +1,96 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(constant float4[] buffer : register(b0), uint id : SV_VertexID) : SV_Position { >+ return buffer[id]; >+} >+ >+fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 { >+ return float4(1.0, 1.0, 1.0, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, 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 vertexInput = {vertexBuffers: []}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const resourceBufferDescriptor = {size: 4 * 4 * Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE}; >+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor); >+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync(); >+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer); >+ resourceBufferFloat32Array[0] = -0.5; >+ resourceBufferFloat32Array[1] = -0.5; >+ resourceBufferFloat32Array[2] = 1.0; >+ resourceBufferFloat32Array[3] = 1; >+ resourceBufferFloat32Array[4] = -0.5; >+ resourceBufferFloat32Array[5] = 0.5; >+ resourceBufferFloat32Array[6] = 1.0; >+ resourceBufferFloat32Array[7] = 1; >+ resourceBufferFloat32Array[8] = 0.5; >+ resourceBufferFloat32Array[9] = -0.5; >+ resourceBufferFloat32Array[10] = 1.0; >+ resourceBufferFloat32Array[11] = 1; >+ resourceBufferFloat32Array[12] = 0.5; >+ resourceBufferFloat32Array[13] = 0.5; >+ resourceBufferFloat32Array[14] = 1.0; >+ resourceBufferFloat32Array[15] = 1; >+ resourceBuffer.unmap(); >+ >+ const bufferBinding = {buffer: resourceBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const canvas = document.getElementById("canvas"); >+ 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.setBindGroup(0, bindGroup); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/whlsl-dont-crash-parsing-enum.html b/LayoutTests/webgpu/whlsl-dont-crash-parsing-enum.html >index 2f8edd3bd146d3aecc6603e6907f7cf4d948ac6a..93dc2d11add98a83a390cc7e1b82136d91ad1768 100644 >--- a/LayoutTests/webgpu/whlsl-dont-crash-parsing-enum.html >+++ b/LayoutTests/webgpu/whlsl-dont-crash-parsing-enum.html >@@ -74,10 +74,10 @@ async function start() { > const vertexBuffer1 = device.createBuffer(vertexBuffer1Descriptor); > const vertexBuffer1ArrayBuffer = await vertexBuffer1.mapWriteAsync(); > const vertexBuffer1Float32Array = new Float32Array(vertexBuffer1ArrayBuffer); >- vertexBuffer1Descriptor[0] = 1; >- vertexBuffer1Descriptor[1] = 1; >- vertexBuffer1Descriptor[2] = 1; >- vertexBuffer1Descriptor[3] = 1; >+ vertexBuffer1Float32Array[0] = 1; >+ vertexBuffer1Float32Array[1] = 1; >+ vertexBuffer1Float32Array[2] = 1; >+ vertexBuffer1Float32Array[3] = 1; > vertexBuffer1.unmap(); > > const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE}; >diff --git a/LayoutTests/webgpu/whlsl.html b/LayoutTests/webgpu/whlsl.html >index 13726de8a384bd63ea977fd065273efdbe1eeabb..86681e8c89143031436bbfac083f3cb244b44afc 100644 >--- a/LayoutTests/webgpu/whlsl.html >+++ b/LayoutTests/webgpu/whlsl.html >@@ -69,10 +69,10 @@ async function start() { > const vertexBuffer1 = device.createBuffer(vertexBuffer1Descriptor); > const vertexBuffer1ArrayBuffer = await vertexBuffer1.mapWriteAsync(); > const vertexBuffer1Float32Array = new Float32Array(vertexBuffer1ArrayBuffer); >- vertexBuffer1Descriptor[0] = 1; >- vertexBuffer1Descriptor[1] = 1; >- vertexBuffer1Descriptor[2] = 1; >- vertexBuffer1Descriptor[3] = 1; >+ vertexBuffer1Float32Array[0] = 1; >+ vertexBuffer1Float32Array[1] = 1; >+ vertexBuffer1Float32Array[2] = 1; >+ vertexBuffer1Float32Array[3] = 1; > vertexBuffer1.unmap(); > > const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE};
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
saam
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 198163
:
370830
|
370874
|
370912
|
371158
|
371243
|
371373
|
371374
|
371375
|
371471
|
371475
| 371555 |
371900