WebKit Bugzilla
Attachment 371612 Details for
Bug 198644
: [WHLSL] Hook up compute
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-198644-20190607174849.patch (text/plain), 63.30 KB, created by
Myles C. Maxfield
on 2019-06-07 14:48:50 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2019-06-07 14:48:50 PDT
Size:
63.30 KB
patch
obsolete
>Subversion Revision: 246184 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 5c76422138f907692ffeb72bcb8a3af55f08463e..4e8db84ee454c6b5aeb6e9651e7e80ac85e79192 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,87 @@ >+2019-06-07 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] Hook up compute >+ https://bugs.webkit.org/show_bug.cgi?id=198644 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch hooks up compute shaders in exactly the same way that vertex and fragment shaders >+ are hooked up. I've modified the two patchs (compute and rendering) to be almost exactly the >+ same code. >+ >+ This patch also adds support for the WHLSL compiler to determine what the numthreads() >+ attribute in the shader says so that it can be hooked up to Metal's threads-per-threadgroup >+ argument in the dispatch call. There is some logic to make sure that there aren't two >+ numthreads() attributes on the same compute shader. >+ >+ It also adds a little bit of type renaming. For built-in variables, sometimes Metal's type >+ doesn't always match WHLSL's (and HLSL's type). For example, in WHLSL and HLSL, SV_DispatchThreadID variables have to be a float3, but in Metal, they are a uint3. >+ Therefore, I've added a little bit of code during each entry point's pack and unpack stages >+ to handle this type conversion. >+ >+ Test: webgpu/whlsl-compute.html >+ >+ * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp: >+ (WebCore::WHLSL::Metal::internalTypeForSemantic): Determine which Metal type corresponds to >+ each built-in variable. >+ (WebCore::WHLSL::Metal::EntryPointScaffolding::builtInsSignature): Perform the type >+ conversion. >+ (WebCore::WHLSL::Metal::EntryPointScaffolding::unpackResourcesAndNamedBuiltIns): Ditto. >+ (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::VertexEntryPointScaffolding): Ditto. >+ (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::helperTypes): Ditto. >+ (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::pack): Ditto. >+ (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::FragmentEntryPointScaffolding): Ditto. >+ (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::helperTypes): Ditto. >+ (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::pack): Ditto. >+ (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::signature): Ditto. >+ * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h: >+ * Modules/webgpu/WHLSL/WHLSLComputeDimensions.cpp: Added. Add a pass to determine whether >+ or not any entry point has duplicate numthreads() attribute, and to determine what the >+ appropriate numthreads() values should be for the current entry point. >+ (WebCore::WHLSL::ComputeDimensionsVisitor::ComputeDimensionsVisitor): >+ (WebCore::WHLSL::ComputeDimensionsVisitor::computeDimensions const): >+ (WebCore::WHLSL::computeDimensions): >+ * Modules/webgpu/WHLSL/WHLSLComputeDimensions.h: Copied from Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h. >+ * Modules/webgpu/WHLSL/WHLSLGatherEntryPointItems.cpp: >+ (WebCore::WHLSL::gatherEntryPointItems): Compute shaders don't need to have a semantic for their return type. >+ * Modules/webgpu/WHLSL/WHLSLPrepare.cpp: >+ (WebCore::WHLSL::prepare): Run the computeDimensions() pass. >+ * Modules/webgpu/WHLSL/WHLSLPrepare.h: >+ * Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp: In a left-value propertyAccessExpression, >+ the index expression can be a right-value. Treat it as such. >+ (WebCore::WHLSL::LeftValueSimplifier::finishVisiting): >+ (WebCore::WHLSL::LeftValueSimplifier::visit): >+ * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt: We need support for multiplication (for a >+ test) and float3 for SV_DispatchThreadID. >+ * Sources.txt: >+ * SourcesCocoa.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ * platform/graphics/gpu/GPUComputePipeline.h: Associate a compute dimensions with a particular >+ compute pipeline. This is how Metal knows what values to use for a dispatch. >+ (WebCore::GPUComputePipeline::computeDimensions const): >+ * platform/graphics/gpu/cocoa/GPUComputePassEncoderMetal.mm: Use the saved compute dimensions. >+ (WebCore::GPUComputePassEncoder::dispatch): >+ * platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm: Make the code match GPURenderPipelineMetal. >+ (WebCore::trySetMetalFunctions): >+ (WebCore::trySetFunctions): >+ (WebCore::convertComputePipelineDescriptor): >+ (WebCore::tryCreateMTLComputePipelineState): >+ (WebCore::GPUComputePipeline::tryCreate): >+ (WebCore::GPUComputePipeline::GPUComputePipeline): >+ (WebCore::tryCreateMtlComputeFunction): Deleted. >+ * platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.cpp: Added. Moved shared helper >+ functions to a file where they can be accessed by multiple places. >+ (WebCore::convertShaderStageFlags): >+ (WebCore::convertBindingType): >+ (WebCore::convertLayout): >+ * platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.h: Copied from Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h. >+ * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm: Delete the functions that were moved to GPUPipelineMetalConvertLayout. >+ (WebCore::trySetFunctions): >+ (WebCore::tryCreateMtlRenderPipelineState): >+ (WebCore::convertShaderStageFlags): Deleted. >+ (WebCore::convertBindingType): Deleted. >+ (WebCore::convertLayout): Deleted. >+ > 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/Metal/WHLSLEntryPointScaffolding.cpp b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp >index 21974eb87d652ab453adee4c20dbcd1ac14c6870..0ea893b3ffa6dfbf8b2db678b5b7ffdafe4883e6 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp >@@ -162,6 +162,41 @@ Optional<String> EntryPointScaffolding::resourceSignature() > return stringBuilder.toString(); > } > >+static String internalTypeForSemantic(const AST::BuiltInSemantic& builtInSemantic) >+{ >+ switch (builtInSemantic.variable()) { >+ case AST::BuiltInSemantic::Variable::SVInstanceID: >+ return "uint"_str; >+ case AST::BuiltInSemantic::Variable::SVVertexID: >+ return "uint"_str; >+ case AST::BuiltInSemantic::Variable::PSize: >+ return "float"_str; >+ case AST::BuiltInSemantic::Variable::SVPosition: >+ return "float4"_str; >+ case AST::BuiltInSemantic::Variable::SVIsFrontFace: >+ return "bool"_str; >+ case AST::BuiltInSemantic::Variable::SVSampleIndex: >+ return "uint"_str; >+ case AST::BuiltInSemantic::Variable::SVInnerCoverage: >+ return "uint"_str; >+ case AST::BuiltInSemantic::Variable::SVTarget: >+ return String(); >+ case AST::BuiltInSemantic::Variable::SVDepth: >+ return "float"_str; >+ case AST::BuiltInSemantic::Variable::SVCoverage: >+ return "uint"_str; >+ case AST::BuiltInSemantic::Variable::SVDispatchThreadID: >+ return "uint3"_str; >+ case AST::BuiltInSemantic::Variable::SVGroupID: >+ return "uint3"_str; >+ case AST::BuiltInSemantic::Variable::SVGroupIndex: >+ return "uint"_str; >+ default: >+ ASSERT(builtInSemantic.variable() == AST::BuiltInSemantic::Variable::SVGroupThreadID); >+ return "uint3"_str; >+ } >+} >+ > Optional<String> EntryPointScaffolding::builtInsSignature() > { > if (!m_namedBuiltIns.size()) >@@ -174,9 +209,11 @@ Optional<String> EntryPointScaffolding::builtInsSignature() > auto& namedBuiltIn = m_namedBuiltIns[i]; > auto& item = m_entryPointItems.inputs[namedBuiltIn.indexInEntryPointItems]; > auto& builtInSemantic = WTF::get<AST::BuiltInSemantic>(*item.semantic); >- auto mangledTypeName = m_typeNamer.mangledNameForType(*item.unnamedType); >+ auto internalType = internalTypeForSemantic(builtInSemantic); >+ if (internalType.isNull()) >+ internalType = m_typeNamer.mangledNameForType(*item.unnamedType); > auto variableName = namedBuiltIn.variableName; >- stringBuilder.append(makeString(mangledTypeName, ' ', variableName, ' ', attributeForSemantic(builtInSemantic))); >+ stringBuilder.append(makeString(internalType, ' ', variableName, ' ', attributeForSemantic(builtInSemantic))); > } > return stringBuilder.toString(); > } >@@ -264,9 +301,11 @@ String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns() > } > > for (auto& namedBuiltIn : m_namedBuiltIns) { >- auto& path = m_entryPointItems.inputs[namedBuiltIn.indexInEntryPointItems].path; >+ auto& item = m_entryPointItems.inputs[namedBuiltIn.indexInEntryPointItems]; >+ auto& path = item.path; > auto& variableName = namedBuiltIn.variableName; >- stringBuilder.append(makeString(mangledInputPath(path), " = ", variableName, ";\n")); >+ auto mangledTypeName = m_typeNamer.mangledNameForType(*item.unnamedType); >+ stringBuilder.append(makeString(mangledInputPath(path), " = ", mangledTypeName, '(', variableName, ");\n")); > } > return stringBuilder.toString(); > } >@@ -289,8 +328,13 @@ VertexEntryPointScaffolding::VertexEntryPointScaffolding(AST::FunctionDefinition > > m_namedOutputs.reserveInitialCapacity(m_entryPointItems.outputs.size()); > for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) { >+ auto& outputItem = m_entryPointItems.outputs[i]; > NamedOutput namedOutput; > namedOutput.elementName = m_typeNamer.generateNextStructureElementName(); >+ if (WTF::holds_alternative<AST::BuiltInSemantic>(*outputItem.semantic)) >+ namedOutput.internalTypeName = internalTypeForSemantic(WTF::get<AST::BuiltInSemantic>(*outputItem.semantic)); >+ if (namedOutput.internalTypeName.isNull()) >+ namedOutput.internalTypeName = m_typeNamer.mangledNameForType(*outputItem.unnamedType); > m_namedOutputs.uncheckedAppend(WTFMove(namedOutput)); > } > } >@@ -311,10 +355,10 @@ String VertexEntryPointScaffolding::helperTypes() > stringBuilder.append(makeString("struct ", m_returnStructName, " {\n")); > for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) { > auto& outputItem = m_entryPointItems.outputs[i]; >- auto mangledTypeName = m_typeNamer.mangledNameForType(*outputItem.unnamedType); >+ auto& internalTypeName = m_namedOutputs[i].internalTypeName; > auto elementName = m_namedOutputs[i].elementName; > auto attribute = attributeForSemantic(*outputItem.semantic); >- stringBuilder.append(makeString(" ", mangledTypeName, ' ', elementName, ' ', attribute, ";\n")); >+ stringBuilder.append(makeString(" ", internalTypeName, ' ', elementName, ' ', attribute, ";\n")); > } > stringBuilder.append("};\n\n"); > >@@ -363,8 +407,9 @@ String VertexEntryPointScaffolding::pack(const String& inputVariableName, const > } > for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) { > auto& elementName = m_namedOutputs[i].elementName; >+ auto& internalTypeName = m_namedOutputs[i].internalTypeName; > auto& path = m_entryPointItems.outputs[i].path; >- stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", inputVariableName, mangledOutputPath(path), ";\n")); >+ stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n")); > } > return stringBuilder.toString(); > } >@@ -389,8 +434,13 @@ FragmentEntryPointScaffolding::FragmentEntryPointScaffolding(AST::FunctionDefini > > m_namedOutputs.reserveInitialCapacity(m_entryPointItems.outputs.size()); > for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) { >+ auto& outputItem = m_entryPointItems.outputs[i]; > NamedOutput namedOutput; > namedOutput.elementName = m_typeNamer.generateNextStructureElementName(); >+ if (WTF::holds_alternative<AST::BuiltInSemantic>(*outputItem.semantic)) >+ namedOutput.internalTypeName = internalTypeForSemantic(WTF::get<AST::BuiltInSemantic>(*outputItem.semantic)); >+ if (namedOutput.internalTypeName.isNull()) >+ namedOutput.internalTypeName = m_typeNamer.mangledNameForType(*outputItem.unnamedType); > m_namedOutputs.uncheckedAppend(WTFMove(namedOutput)); > } > } >@@ -411,10 +461,10 @@ String FragmentEntryPointScaffolding::helperTypes() > stringBuilder.append(makeString("struct ", m_returnStructName, " {\n")); > for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) { > auto& outputItem = m_entryPointItems.outputs[i]; >- auto mangledTypeName = m_typeNamer.mangledNameForType(*outputItem.unnamedType); >+ auto& internalTypeName = m_namedOutputs[i].internalTypeName; > auto elementName = m_namedOutputs[i].elementName; > auto attribute = attributeForSemantic(*outputItem.semantic); >- stringBuilder.append(makeString(" ", mangledTypeName, ' ', elementName, ' ', attribute, ";\n")); >+ stringBuilder.append(makeString(" ", internalTypeName, ' ', elementName, ' ', attribute, ";\n")); > } > stringBuilder.append("};\n\n"); > >@@ -463,8 +513,9 @@ String FragmentEntryPointScaffolding::pack(const String& inputVariableName, cons > } > for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) { > auto& elementName = m_namedOutputs[i].elementName; >+ auto& internalTypeName = m_namedOutputs[i].internalTypeName; > auto& path = m_entryPointItems.outputs[i].path; >- stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", inputVariableName, mangledOutputPath(path), ";\n")); >+ stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n")); > } > return stringBuilder.toString(); > } >@@ -483,7 +534,7 @@ String ComputeEntryPointScaffolding::signature(String& functionName) > { > StringBuilder stringBuilder; > >- stringBuilder.append(makeString("compute void ", functionName, '(')); >+ stringBuilder.append(makeString("kernel void ", functionName, '(')); > bool empty = true; > if (auto resourceSignature = this->resourceSignature()) { > empty = false; >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h >index 2467e86ff86ad24404826e385ca1a51e0d1a837a..0714bb919fa030ec610bb1b30edd71edf9f55161 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h >@@ -123,6 +123,7 @@ private: > > struct NamedOutput { > String elementName; >+ String internalTypeName; > }; > Vector<NamedOutput> m_namedOutputs; > }; >@@ -151,6 +152,7 @@ private: > > struct NamedOutput { > String elementName; >+ String internalTypeName; > }; > Vector<NamedOutput> m_namedOutputs; > }; >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLComputeDimensions.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLComputeDimensions.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..e7de4c6532c8a5a5ae825c7d1ef1ed0f48ee80af >--- /dev/null >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLComputeDimensions.cpp >@@ -0,0 +1,91 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "WHLSLComputeDimensions.h" >+ >+#if ENABLE(WEBGPU) >+ >+#include "WHLSLFunctionDeclaration.h" >+#include "WHLSLPrepare.h" >+#include "WHLSLProgram.h" >+#include <wtf/Optional.h> >+ >+namespace WebCore { >+ >+namespace WHLSL { >+ >+class ComputeDimensionsVisitor : public Visitor { >+public: >+ ComputeDimensionsVisitor(AST::FunctionDefinition& entryPoint) >+ : m_entryPoint(entryPoint) >+ { >+ } >+ >+ virtual ~ComputeDimensionsVisitor() = default; >+ >+ Optional<ComputeDimensions> computeDimensions() const { return m_computeDimensions; } >+ >+private: >+ void visit(AST::FunctionDeclaration& functionDeclaration) override >+ { >+ Visitor::visit(functionDeclaration); >+ bool foundNumThreadsFunctionAttribute = false; >+ for (auto& functionAttribute : functionDeclaration.attributeBlock()) { >+ auto success = WTF::visit(WTF::makeVisitor([&](AST::NumThreadsFunctionAttribute& numThreadsFunctionAttribute) { >+ if (foundNumThreadsFunctionAttribute) >+ return false; >+ foundNumThreadsFunctionAttribute = true; >+ if (&functionDeclaration == &m_entryPoint) { >+ ASSERT(!m_computeDimensions); >+ m_computeDimensions = {{ numThreadsFunctionAttribute.width(), numThreadsFunctionAttribute.height(), numThreadsFunctionAttribute.depth() }}; >+ } >+ return true; >+ }), functionAttribute); >+ if (!success) { >+ setError(); >+ return; >+ } >+ } >+ } >+ >+ AST::FunctionDefinition& m_entryPoint; >+ Optional<ComputeDimensions> m_computeDimensions; >+}; >+ >+Optional<ComputeDimensions> computeDimensions(Program& program, AST::FunctionDefinition& entryPoint) >+{ >+ ComputeDimensionsVisitor computeDimensions(entryPoint); >+ computeDimensions.Visitor::visit(program); >+ if (computeDimensions.error()) >+ return WTF::nullopt; >+ return computeDimensions.computeDimensions(); >+} >+ >+} // namespace WHLSL >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEBGPU) >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLComputeDimensions.h b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLComputeDimensions.h >new file mode 100644 >index 0000000000000000000000000000000000000000..de450813a58c9957aafad4f66e23dd31e11b9873 >--- /dev/null >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLComputeDimensions.h >@@ -0,0 +1,44 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBGPU) >+ >+#include "WHLSLPrepare.h" >+ >+namespace WebCore { >+ >+namespace WHLSL { >+ >+class Program; >+ >+Optional<ComputeDimensions> computeDimensions(Program&, AST::FunctionDefinition&); >+ >+} >+ >+} >+ >+#endif >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLGatherEntryPointItems.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLGatherEntryPointItems.cpp >index 996dd84072d529fa08980d2c1a098ba165bfe54b..aa249c02b72686151b7cd9856630d1c31ffce790 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLGatherEntryPointItems.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLGatherEntryPointItems.cpp >@@ -175,7 +175,8 @@ Optional<EntryPointItems> gatherEntryPointItems(const Intrinsics& intrinsics, AS > return WTF::nullopt; > } > Gatherer outputGatherer(intrinsics, functionDefinition.semantic() ? &*functionDefinition.semantic() : nullptr); >- outputGatherer.checkErrorAndVisit(functionDefinition.type()); >+ if (*functionDefinition.entryPointType() != AST::EntryPointType::Compute) >+ outputGatherer.checkErrorAndVisit(functionDefinition.type()); > if (outputGatherer.error()) > return WTF::nullopt; > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp >index 56fb36546acbc57e1a7e9d2684dbbe4fa53939f0..93e022afaee0cd72a302819570db2b2eb2043249 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp >@@ -31,6 +31,7 @@ > #include "WHLSLASTDumper.h" > #include "WHLSLCheckDuplicateFunctions.h" > #include "WHLSLChecker.h" >+#include "WHLSLComputeDimensions.h" > #include "WHLSLFunctionStageChecker.h" > #include "WHLSLHighZombieFinder.h" > #include "WHLSLLiteralTypeChecker.h" >@@ -168,12 +169,16 @@ Optional<ComputePrepareResult> prepare(String& whlslSource, ComputePipelineDescr > auto matchedSemantics = matchSemantics(*program, computePipelineDescriptor); > if (!matchedSemantics) > return WTF::nullopt; >+ auto computeDimensions = WHLSL::computeDimensions(*program, *matchedSemantics->shader); >+ if (!computeDimensions) >+ return WTF::nullopt; > > auto generatedCode = Metal::generateMetalCode(*program, WTFMove(*matchedSemantics), computePipelineDescriptor.layout); > > ComputePrepareResult result; > result.metalSource = WTFMove(generatedCode.metalSource); > result.mangledEntryPointName = WTFMove(generatedCode.mangledEntryPointName); >+ result.computeDimensions = WTFMove(*computeDimensions); > return result; > } > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h >index 5bd6df06dc691a72f1ce24dfc55576ec7f5284ab..eb2021b7ca2ec58fbd4a05494c54708310e50ed6 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h >@@ -42,9 +42,16 @@ struct RenderPrepareResult { > }; > Optional<RenderPrepareResult> prepare(String& whlslSource, RenderPipelineDescriptor&); > >+struct ComputeDimensions { >+ unsigned width; >+ unsigned height; >+ unsigned depth; >+}; >+ > struct ComputePrepareResult { > String metalSource; > String mangledEntryPointName; >+ ComputeDimensions computeDimensions; > }; > Optional<ComputePrepareResult> prepare(String& whlslSource, ComputePipelineDescriptor&); > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >index 8a5a8b3a3ceff57023c229664ab486f3fd4e98db..25474e2047ac90ceb0a506c6f1ce67c505dbb030 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >@@ -775,6 +775,8 @@ void LeftValueSimplifier::finishVisiting(AST::PropertyAccessExpression& property > ASSERT(propertyAccessExpression.base().typeAnnotation().leftAddressSpace()); > ASSERT(propertyAccessExpression.anderFunction()); > >+ Visitor::visit(propertyAccessExpression.base()); >+ > Lexer::Token origin = propertyAccessExpression.origin(); > auto* anderFunction = propertyAccessExpression.anderFunction(); > auto& base = propertyAccessExpression.base(); >@@ -805,7 +807,6 @@ void LeftValueSimplifier::visit(AST::DotExpression& dotExpression) > > void LeftValueSimplifier::visit(AST::IndexExpression& indexExpression) > { >- Visitor::visit(indexExpression); > PropertyResolver().Visitor::visit(indexExpression.indexExpression()); > finishVisiting(indexExpression); > } >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >index 1c4527a6bf146c4df57baa92e5e33f25e397bdc3..0fb48e1de536b75cc3db3ee73a5bb62e9b508168 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >@@ -432,15 +432,6 @@ native operator float(short); > native operator float(int); > native operator float(half); > >-native float operator.x(float4); >-native float operator.y(float4); >-native float operator.z(float4); >-native float operator.w(float4); >-native float4 operator.x=(float4, float); >-native float4 operator.y=(float4, float); >-native float4 operator.z=(float4, float); >-native float4 operator.w=(float4, float); >- > native float operator+(float, float); > native float operator-(float, float); > native int operator+(int, int); >@@ -448,6 +439,170 @@ native uint operator+(uint, uint); > native bool operator<(int, int); > native bool operator<(uint, uint); > native bool operator<(float, float); >+native float operator*(float, float); >+ >+/* native bool operator.x(bool2); >+native bool operator.y(bool2); >+native bool operator.x(bool3); >+native bool operator.y(bool3); >+native bool operator.z(bool3); >+native bool operator.x(bool4); >+native bool operator.y(bool4); >+native bool operator.z(bool4); >+native bool operator.w(bool4); >+native bool2 operator.x=(bool2, bool); >+native bool2 operator.y=(bool2, bool); >+native bool3 operator.x=(bool3, bool); >+native bool3 operator.y=(bool3, bool); >+native bool3 operator.z=(bool3, bool); >+native bool4 operator.x=(bool4, bool); >+native bool4 operator.y=(bool4, bool); >+native bool4 operator.z=(bool4, bool); >+native bool4 operator.w=(bool4, bool); >+native uchar operator.x(uchar2); >+native uchar operator.y(uchar2); >+native uchar operator.x(uchar3); >+native uchar operator.y(uchar3); >+native uchar operator.z(uchar3); >+native uchar operator.x(uchar4); >+native uchar operator.y(uchar4); >+native uchar operator.z(uchar4); >+native uchar operator.w(uchar4); >+native uchar2 operator.x=(uchar2, uchar); >+native uchar2 operator.y=(uchar2, uchar); >+native uchar3 operator.x=(uchar3, uchar); >+native uchar3 operator.y=(uchar3, uchar); >+native uchar3 operator.z=(uchar3, uchar); >+native uchar4 operator.x=(uchar4, uchar); >+native uchar4 operator.y=(uchar4, uchar); >+native uchar4 operator.z=(uchar4, uchar); >+native uchar4 operator.w=(uchar4, uchar); >+native ushort operator.x(ushort2); >+native ushort operator.y(ushort2); >+native ushort operator.x(ushort3); >+native ushort operator.y(ushort3); >+native ushort operator.z(ushort3); >+native ushort operator.x(ushort4); >+native ushort operator.y(ushort4); >+native ushort operator.z(ushort4); >+native ushort operator.w(ushort4); >+native ushort2 operator.x=(ushort2, ushort); >+native ushort2 operator.y=(ushort2, ushort); >+native ushort3 operator.x=(ushort3, ushort); >+native ushort3 operator.y=(ushort3, ushort); >+native ushort3 operator.z=(ushort3, ushort); >+native ushort4 operator.x=(ushort4, ushort); >+native ushort4 operator.y=(ushort4, ushort); >+native ushort4 operator.z=(ushort4, ushort); >+native ushort4 operator.w=(ushort4, ushort); >+native uint operator.x(uint2); >+native uint operator.y(uint2); >+native uint operator.x(uint3); >+native uint operator.y(uint3); >+native uint operator.z(uint3); >+native uint operator.x(uint4); >+native uint operator.y(uint4); >+native uint operator.z(uint4); >+native uint operator.w(uint4); >+native uint2 operator.x=(uint2, uint); >+native uint2 operator.y=(uint2, uint); >+native uint3 operator.x=(uint3, uint); >+native uint3 operator.y=(uint3, uint); >+native uint3 operator.z=(uint3, uint); >+native uint4 operator.x=(uint4, uint); >+native uint4 operator.y=(uint4, uint); >+native uint4 operator.z=(uint4, uint); >+native uint4 operator.w=(uint4, uint); >+native char operator.x(char2); >+native char operator.y(char2); >+native char operator.x(char3); >+native char operator.y(char3); >+native char operator.z(char3); >+native char operator.x(char4); >+native char operator.y(char4); >+native char operator.z(char4); >+native char operator.w(char4); >+native char2 operator.x=(char2, char); >+native char2 operator.y=(char2, char); >+native char3 operator.x=(char3, char); >+native char3 operator.y=(char3, char); >+native char3 operator.z=(char3, char); >+native char4 operator.x=(char4, char); >+native char4 operator.y=(char4, char); >+native char4 operator.z=(char4, char); >+native char4 operator.w=(char4, char); >+native short operator.x(short2); >+native short operator.y(short2); >+native short operator.x(short3); >+native short operator.y(short3); >+native short operator.z(short3); >+native short operator.x(short4); >+native short operator.y(short4); >+native short operator.z(short4); >+native short operator.w(short4); >+native short2 operator.x=(short2, short); >+native short2 operator.y=(short2, short); >+native short3 operator.x=(short3, short); >+native short3 operator.y=(short3, short); >+native short3 operator.z=(short3, short); >+native short4 operator.x=(short4, short); >+native short4 operator.y=(short4, short); >+native short4 operator.z=(short4, short); >+native short4 operator.w=(short4, short); >+native int operator.x(int2); >+native int operator.y(int2); >+native int operator.x(int3); >+native int operator.y(int3); >+native int operator.z(int3); >+native int operator.x(int4); >+native int operator.y(int4); >+native int operator.z(int4); >+native int operator.w(int4); >+native int2 operator.x=(int2, int); >+native int2 operator.y=(int2, int); >+native int3 operator.x=(int3, int); >+native int3 operator.y=(int3, int); >+native int3 operator.z=(int3, int); >+native int4 operator.x=(int4, int); >+native int4 operator.y=(int4, int); >+native int4 operator.z=(int4, int); >+native int4 operator.w=(int4, int); >+native half operator.x(half2); >+native half operator.y(half2); >+native half operator.x(half3); >+native half operator.y(half3); >+native half operator.z(half3); >+native half operator.x(half4); >+native half operator.y(half4); >+native half operator.z(half4); >+native half operator.w(half4); >+native half2 operator.x=(half2, half); >+native half2 operator.y=(half2, half); >+native half3 operator.x=(half3, half); >+native half3 operator.y=(half3, half); >+native half3 operator.z=(half3, half); >+native half4 operator.x=(half4, half); >+native half4 operator.y=(half4, half); >+native half4 operator.z=(half4, half); >+native half4 operator.w=(half4, half); >+native float operator.x(float2); >+native float operator.y(float2);*/ >+native float operator.x(float3); >+native float operator.y(float3); >+native float operator.z(float3); >+native float operator.x(float4); >+native float operator.y(float4); >+native float operator.z(float4); >+native float operator.w(float4);/* >+native float2 operator.x=(float2, float); >+native float2 operator.y=(float2, float);*/ >+native float3 operator.x=(float3, float); >+native float3 operator.y=(float3, float); >+native float3 operator.z=(float3, float); >+native float4 operator.x=(float4, float); >+native float4 operator.y=(float4, float); >+native float4 operator.z=(float4, float); >+native float4 operator.w=(float4, float); > > native float ddx(float); > native float ddy(float); >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index a8bbbf9f795121ba5758c87e67833657a7d11ad7..8d50e63ad40171470790f520e618180c70962410 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -306,6 +306,7 @@ Modules/websockets/WorkerThreadableWebSocketChannel.cpp > > Modules/webgpu/GPUCanvasContext.cpp > Modules/webgpu/NavigatorGPU.cpp >+Modules/webgpu/WHLSL/WHLSLComputeDimensions.cpp > Modules/webgpu/WHLSL/WHLSLASTDumper.cpp > Modules/webgpu/WHLSL/WHLSLInferTypes.cpp > Modules/webgpu/WHLSL/WHLSLLexer.cpp >diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt >index bd29e5b48cbd60a92435f3cab1be1b7c8fafbb81..b3f351a6ed2a2a248ba8cd6ae5d5a68f5d04cf3e 100644 >--- a/Source/WebCore/SourcesCocoa.txt >+++ b/Source/WebCore/SourcesCocoa.txt >@@ -326,6 +326,7 @@ platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm > platform/graphics/gpu/cocoa/GPUComputePassEncoderMetal.mm > platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm > platform/graphics/gpu/cocoa/GPUDeviceMetal.mm >+platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.cpp > platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm > platform/graphics/gpu/cocoa/GPUQueueMetal.mm > platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index f87491eb1082a0def844143ac2dffbb68d9936c4..ef40562604daf1ee05cba8616614676b3ce3ec20 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -6392,6 +6392,10 @@ > 1C840B9921EC400800D0500D /* WHLSLGatherEntryPointItems.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLGatherEntryPointItems.cpp; sourceTree = "<group>"; }; > 1C840B9A21EC400900D0500D /* WHLSLGatherEntryPointItems.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLGatherEntryPointItems.h; sourceTree = "<group>"; }; > 1C840B9B21EC400900D0500D /* WHLSLChecker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLChecker.cpp; sourceTree = "<group>"; }; >+ 1C86CA4B22AA19FF001BF961 /* WHLSLComputeDimensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLComputeDimensions.cpp; sourceTree = "<group>"; }; >+ 1C86CA4C22AA19FF001BF961 /* WHLSLComputeDimensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLComputeDimensions.h; sourceTree = "<group>"; }; >+ 1C86CA4E22AA23C9001BF961 /* GPUPipelineMetalConvertLayout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GPUPipelineMetalConvertLayout.cpp; sourceTree = "<group>"; }; >+ 1C86CA4F22AA23C9001BF961 /* GPUPipelineMetalConvertLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUPipelineMetalConvertLayout.h; sourceTree = "<group>"; }; > 1C904DF90BA9D2C80081E9D0 /* Version.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Version.xcconfig; sourceTree = "<group>"; }; > 1C9AE5CA21ED9DF50069D5F2 /* WHLSLHighZombieFinder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLHighZombieFinder.cpp; sourceTree = "<group>"; }; > 1C9AE5CB21ED9DF50069D5F2 /* WHLSLHighZombieFinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLHighZombieFinder.h; sourceTree = "<group>"; }; >@@ -25441,6 +25445,8 @@ > C234A9AE21E92C1A003C984D /* WHLSLCheckDuplicateFunctions.h */, > 1C840B9B21EC400900D0500D /* WHLSLChecker.cpp */, > 1C840B9721EC400700D0500D /* WHLSLChecker.h */, >+ 1C86CA4B22AA19FF001BF961 /* WHLSLComputeDimensions.cpp */, >+ 1C86CA4C22AA19FF001BF961 /* WHLSLComputeDimensions.h */, > 1CA0C2E421EED12A00A11860 /* WHLSLFunctionStageChecker.cpp */, > 1CA0C2E521EED12A00A11860 /* WHLSLFunctionStageChecker.h */, > 1C840B9921EC400800D0500D /* WHLSLGatherEntryPointItems.cpp */, >@@ -25980,6 +25986,8 @@ > D08903402241CE4600F3F440 /* GPUComputePassEncoderMetal.mm */, > D089033B224179B500F3F440 /* GPUComputePipelineMetal.mm */, > D087CE3C21ACA94200BDE174 /* GPUDeviceMetal.mm */, >+ 1C86CA4E22AA23C9001BF961 /* GPUPipelineMetalConvertLayout.cpp */, >+ 1C86CA4F22AA23C9001BF961 /* GPUPipelineMetalConvertLayout.h */, > D087CE3B21ACA94200BDE174 /* GPUProgrammablePassEncoderMetal.mm */, > D087CE3921ACA94200BDE174 /* GPUQueueMetal.mm */, > D087CE3A21ACA94200BDE174 /* GPURenderPassEncoderMetal.mm */, >diff --git a/Source/WebCore/platform/graphics/gpu/GPUComputePipeline.h b/Source/WebCore/platform/graphics/gpu/GPUComputePipeline.h >index 0359f29bed0601e778eef4fde2853daf0745f06c..65367c9d9343a5c4691878a194c32d84087b1013 100644 >--- a/Source/WebCore/platform/graphics/gpu/GPUComputePipeline.h >+++ b/Source/WebCore/platform/graphics/gpu/GPUComputePipeline.h >@@ -27,6 +27,7 @@ > > #if ENABLE(WEBGPU) > >+#include "WHLSLPrepare.h" > #include <wtf/RefCounted.h> > #include <wtf/RefPtr.h> > #include <wtf/RetainPtr.h> >@@ -48,10 +49,13 @@ public: > > const PlatformComputePipeline* platformComputePipeline() const { return m_platformComputePipeline.get(); } > >+ WHLSL::ComputeDimensions computeDimensions() const { return m_computeDimensions; } >+ > private: >- GPUComputePipeline(PlatformComputePipelineSmartPtr&&); >+ GPUComputePipeline(PlatformComputePipelineSmartPtr&&, WHLSL::ComputeDimensions); > > PlatformComputePipelineSmartPtr m_platformComputePipeline; >+ WHLSL::ComputeDimensions m_computeDimensions { 0, 0, 0 }; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePassEncoderMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePassEncoderMetal.mm >index 713c1b791075a086b90b31309914a405d6afe682..6bd28f7017072e1ccbd5c7106954d4b44af82ffe 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePassEncoderMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePassEncoderMetal.mm >@@ -97,11 +97,7 @@ void GPUComputePassEncoder::dispatch(unsigned x, unsigned y, unsigned z) > > BEGIN_BLOCK_OBJC_EXCEPTIONS; > >- auto w = pipelineState.threadExecutionWidth; >- auto h = pipelineState.maxTotalThreadsPerThreadgroup / w; >- >- // FIXME: This should be gleaned from the shader if not using MSL. For now, use the docs' example calculation. >- auto threadsPerThreadgroup = MTLSizeMake(w, h, 1); >+ auto threadsPerThreadgroup = MTLSizeMake(m_pipeline->computeDimensions().width, m_pipeline->computeDimensions().height, m_pipeline->computeDimensions().depth); > > auto threadgroupsPerGrid = MTLSizeMake(x, y, z); > >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm >index fbe43f441c83a8445c0bc01bd537b081501ac79d..d6eced44f4b5a9130c56552718d4de57d66d59d7 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm >@@ -30,68 +30,172 @@ > > #import "GPUComputePipelineDescriptor.h" > #import "GPUDevice.h" >+#import "GPUPipelineMetalConvertLayout.h" > #import "Logging.h" >+#import "WHLSLPrepare.h" > #import <Metal/Metal.h> > #import <wtf/BlockObjCExceptions.h> > >-OBJC_PROTOCOL(MTLFunction); >- > namespace WebCore { > >-static RetainPtr<MTLFunction> tryCreateMtlComputeFunction(const GPUPipelineStageDescriptor& stage) >+static bool trySetMetalFunctions(const char* const functionName, MTLLibrary *computeMetalLibrary, MTLComputePipelineDescriptor *mtlDescriptor, const String& computeEntryPointName) > { >- if (!stage.module->platformShaderModule() || stage.entryPoint.isNull()) { >- LOG(WebGPU, "GPUComputePipeline::tryCreate(): Invalid GPUShaderModule!"); >- return nullptr; >+#if LOG_DISABLED >+ UNUSED_PARAM(functionName); >+#endif >+ >+ BEGIN_BLOCK_OBJC_EXCEPTIONS; >+ >+ if (!computeMetalLibrary) { >+ LOG(WebGPU, "%s: MTLLibrary for compute stage does not exist!", functionName); >+ return false; >+ } >+ >+ auto function = adoptNS([computeMetalLibrary newFunctionWithName:computeEntryPointName]); >+ if (!function) { >+ LOG(WebGPU, "%s: Cannot create compute MTLFunction \"%s\"!", functionName, computeEntryPointName.utf8().data()); >+ return false; >+ } >+ >+ [mtlDescriptor setComputeFunction:function.get()]; >+ return true; >+ >+ END_BLOCK_OBJC_EXCEPTIONS; >+ >+ return false; >+} >+ >+static Optional<WHLSL::ComputeDimensions> trySetFunctions(const char* const functionName, const GPUPipelineStageDescriptor& computeStage, const GPUDevice& device, MTLComputePipelineDescriptor* mtlDescriptor, Optional<WHLSL::ComputePipelineDescriptor>& whlslDescriptor) >+{ >+#if LOG_DISABLED >+ UNUSED_PARAM(functionName); >+#endif >+ RetainPtr<MTLLibrary> computeLibrary; >+ String computeEntryPoint; >+ >+ WHLSL::ComputeDimensions computeDimensions { 1, 1, 1 }; >+ >+ if (whlslDescriptor) { >+ // WHLSL functions are compiled to MSL first. >+ String whlslSource = computeStage.module->whlslSource(); >+ ASSERT(!whlslSource.isNull()); >+ >+ whlslDescriptor->entryPointName = computeStage.entryPoint; >+ >+ auto whlslCompileResult = WHLSL::prepare(whlslSource, *whlslDescriptor); >+ if (!whlslCompileResult) >+ return WTF::nullopt; >+ computeDimensions = whlslCompileResult->computeDimensions; >+ >+ NSError *error = nil; >+ >+ BEGIN_BLOCK_OBJC_EXCEPTIONS; >+ computeLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]); >+ END_BLOCK_OBJC_EXCEPTIONS; >+ >+ ASSERT(computeLibrary); >+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here. >+ >+ computeEntryPoint = whlslCompileResult->mangledEntryPointName; >+ } else { >+ computeLibrary = computeStage.module->platformShaderModule(); >+ computeEntryPoint = computeStage.entryPoint; > } > >- RetainPtr<MTLFunction> function; >+ if (trySetMetalFunctions(functionName, computeLibrary.get(), mtlDescriptor, computeEntryPoint)) >+ return computeDimensions; >+ return WTF::nullopt; >+} >+ >+struct ConvertResult { >+ RetainPtr<MTLComputePipelineDescriptor> pipelineDescriptor; >+ WHLSL::ComputeDimensions computeDimensions; >+}; >+static Optional<ConvertResult> convertComputePipelineDescriptor(const char* const functionName, const GPUComputePipelineDescriptor& descriptor, const GPUDevice& device) >+{ >+ RetainPtr<MTLComputePipelineDescriptor> mtlDescriptor; > > BEGIN_BLOCK_OBJC_EXCEPTIONS; >- function = adoptNS([stage.module->platformShaderModule() newFunctionWithName:stage.entryPoint]); >+ >+ mtlDescriptor = adoptNS([MTLComputePipelineDescriptor new]); >+ > END_BLOCK_OBJC_EXCEPTIONS; > >- if (!function) >- LOG(WebGPU, "GPUComputePipeline::tryCreate(): Cannot create compute MTLFunction \"%s\"!", stage.entryPoint.utf8().data()); >+ if (!mtlDescriptor) { >+ LOG(WebGPU, "%s: Error creating MTLDescriptor!", functionName); >+ return WTF::nullopt; >+ } >+ >+ const auto& computeStage = descriptor.computeStage; >+ >+ bool isWhlsl = !computeStage.module->whlslSource().isNull(); >+ >+ Optional<WHLSL::ComputePipelineDescriptor> whlslDescriptor; >+ if (isWhlsl) >+ whlslDescriptor = WHLSL::ComputePipelineDescriptor(); >+ >+ if (descriptor.layout && whlslDescriptor) { >+ if (auto layout = convertLayout(*descriptor.layout)) >+ whlslDescriptor->layout = WTFMove(*layout); >+ else { >+ LOG(WebGPU, "%s: Error converting GPUPipelineLayout!", functionName); >+ return WTF::nullopt; >+ } >+ } >+ >+ if (auto computeDimensions = trySetFunctions(functionName, computeStage, device, mtlDescriptor.get(), whlslDescriptor)) >+ return {{ mtlDescriptor, *computeDimensions }}; > >- return function; >+ return WTF::nullopt; > } > >-static RetainPtr<MTLComputePipelineState> tryCreateMTLComputePipelineState(const GPUDevice& device, const GPUComputePipelineDescriptor& descriptor) >+struct CreateResult { >+ RetainPtr<MTLComputePipelineState> pipelineState; >+ WHLSL::ComputeDimensions computeDimensions; >+}; >+static Optional<CreateResult> tryCreateMTLComputePipelineState(const char* const functionName, const GPUDevice& device, const GPUComputePipelineDescriptor& descriptor) > { > if (!device.platformDevice()) { > LOG(WebGPU, "GPUComputePipeline::tryCreate(): Invalid GPUDevice!"); >- return nullptr; >+ return WTF::nullopt; > } > >- auto computeFunction = tryCreateMtlComputeFunction(descriptor.computeStage); >- if (!computeFunction) >- return nullptr; >+ auto convertResult = convertComputePipelineDescriptor(functionName, descriptor, device); >+ if (!convertResult) >+ return WTF::nullopt; >+ ASSERT(convertResult->pipelineDescriptor); >+ auto mtlDescriptor = convertResult->pipelineDescriptor; > >- RetainPtr<MTLComputePipelineState> pipelineState; >- NSError *error = nil; >+ RetainPtr<MTLComputePipelineState> pipeline; > > BEGIN_BLOCK_OBJC_EXCEPTIONS; >- pipelineState = adoptNS([device.platformDevice() newComputePipelineStateWithFunction:computeFunction.get() error:&error]); >- END_BLOCK_OBJC_EXCEPTIONS; > >- if (!pipelineState) >+ NSError *error = nil; >+ pipeline = adoptNS([device.platformDevice() newComputePipelineStateWithDescriptor:mtlDescriptor.get() options:MTLPipelineOptionNone reflection:nil error:&error]); >+ if (!pipeline) { > LOG(WebGPU, "GPUComputePipeline::tryCreate(): %s!", error ? error.localizedDescription.UTF8String : "Unable to create MTLComputePipelineState!"); >+ return WTF::nullopt; >+ } > >- return pipelineState; >+ END_BLOCK_OBJC_EXCEPTIONS; >+ >+ return {{ pipeline, convertResult->computeDimensions }}; > } > > RefPtr<GPUComputePipeline> GPUComputePipeline::tryCreate(const GPUDevice& device, const GPUComputePipelineDescriptor& descriptor) > { >- auto mtlPipeline = tryCreateMTLComputePipelineState(device, descriptor); >- if (!mtlPipeline) >+ const char* const functionName = "GPURenderPipeline::create()"; >+ >+ auto createResult = tryCreateMTLComputePipelineState(functionName, device, descriptor); >+ if (!createResult) > return nullptr; > >- return adoptRef(new GPUComputePipeline(WTFMove(mtlPipeline))); >+ return adoptRef(new GPUComputePipeline(WTFMove(createResult->pipelineState), createResult->computeDimensions)); > } > >-GPUComputePipeline::GPUComputePipeline(RetainPtr<MTLComputePipelineState>&& pipeline) >+GPUComputePipeline::GPUComputePipeline(RetainPtr<MTLComputePipelineState>&& pipeline, WHLSL::ComputeDimensions computeDimensions) > : m_platformComputePipeline(WTFMove(pipeline)) >+ , m_computeDimensions(computeDimensions) > { > } > >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.cpp b/Source/WebCore/platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..bd57688f5be187c664dd138fe24652fd110743ff >--- /dev/null >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.cpp >@@ -0,0 +1,94 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "GPUPipelineMetalConvertLayout.h" >+ >+#include "GPUPipelineLayout.h" >+ >+#if ENABLE(WEBGPU) >+ >+namespace WebCore { >+ >+static OptionSet<WHLSL::ShaderStage> convertShaderStageFlags(GPUShaderStageFlags flags) >+{ >+ OptionSet<WHLSL::ShaderStage> result; >+ if (flags & GPUShaderStageBit::Flags::Vertex) >+ result.add(WHLSL::ShaderStage::Vertex); >+ if (flags & GPUShaderStageBit::Flags::Fragment) >+ result.add(WHLSL::ShaderStage::Fragment); >+ if (flags & GPUShaderStageBit::Flags::Compute) >+ result.add(WHLSL::ShaderStage::Compute); >+ return result; >+} >+ >+static Optional<WHLSL::Binding::BindingDetails> convertBindingType(GPUBindGroupLayout::InternalBindingDetails internalBindingDetails) >+{ >+ 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); >+} >+ >+Optional<WHLSL::Layout> convertLayout(const GPUPipelineLayout& layout) >+{ >+ WHLSL::Layout result; >+ if (layout.bindGroupLayouts().size() > std::numeric_limits<unsigned>::max()) >+ return WTF::nullopt; >+ for (size_t i = 0; i < layout.bindGroupLayouts().size(); ++i) { >+ const auto& bindGroupLayout = layout.bindGroupLayouts()[i]; >+ WHLSL::BindGroup bindGroup; >+ bindGroup.name = static_cast<unsigned>(i); >+ for (const auto& keyValuePair : bindGroupLayout->bindingsMap()) { >+ const auto& bindingDetails = keyValuePair.value; >+ WHLSL::Binding binding; >+ binding.visibility = convertShaderStageFlags(bindingDetails.externalBinding.visibility); >+ if (auto bindingType = convertBindingType(bindingDetails.internalBindingDetails)) >+ binding.binding = *bindingType; >+ else >+ return WTF::nullopt; >+ if (bindingDetails.externalBinding.binding > std::numeric_limits<unsigned>::max()) >+ return WTF::nullopt; >+ binding.externalName = bindingDetails.externalBinding.binding; >+ binding.internalName = bindingDetails.internalName; >+ bindGroup.bindings.append(WTFMove(binding)); >+ } >+ result.append(WTFMove(bindGroup)); >+ } >+ return result; >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEBGPU) >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.h b/Source/WebCore/platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.h >new file mode 100644 >index 0000000000000000000000000000000000000000..8e29d93af025ea2e1a611ccaf392e00cc16bb620 >--- /dev/null >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUPipelineMetalConvertLayout.h >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBGPU) >+ >+#include "WHLSLPipelineDescriptor.h" >+#include <wtf/Optional.h> >+ >+namespace WebCore { >+ >+class GPUPipelineLayout; >+ >+Optional<WHLSL::Layout> convertLayout(const GPUPipelineLayout&); >+ >+} >+ >+#endif >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >index 2bb620409410deaf659b0ad49223091ceb1f99ba..1745df017b67dd4ec8020c40cead40ec3d6765c3 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >@@ -30,6 +30,7 @@ > > #import "GPUDevice.h" > #import "GPULimits.h" >+#import "GPUPipelineMetalConvertLayout.h" > #import "GPUUtils.h" > #import "Logging.h" > #import "WHLSLPrepare.h" >@@ -98,34 +99,6 @@ static WHLSL::VertexFormat convertVertexFormat(GPUVertexFormat vertexFormat) > } > } > >-static OptionSet<WHLSL::ShaderStage> convertShaderStageFlags(GPUShaderStageFlags flags) >-{ >- OptionSet<WHLSL::ShaderStage> result; >- if (flags & GPUShaderStageBit::Flags::Vertex) >- result.add(WHLSL::ShaderStage::Vertex); >- if (flags & GPUShaderStageBit::Flags::Fragment) >- result.add(WHLSL::ShaderStage::Fragment); >- if (flags & GPUShaderStageBit::Flags::Compute) >- result.add(WHLSL::ShaderStage::Compute); >- return result; >-} >- >-static Optional<WHLSL::BindingType> convertBindingType(GPUBindingType type) >-{ >- 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::nullopt; >- } >-} >- > static Optional<WHLSL::TextureFormat> convertTextureFormat(GPUTextureFormat format) > { > switch (format) { >@@ -367,33 +340,6 @@ static bool trySetColorStates(const char* const functionName, const Vector<GPUCo > return true; > } > >-static Optional<WHLSL::Layout> convertLayout(const GPUPipelineLayout& layout) >-{ >- WHLSL::Layout result; >- if (layout.bindGroupLayouts().size() > std::numeric_limits<unsigned>::max()) >- return WTF::nullopt; >- for (size_t i = 0; i < layout.bindGroupLayouts().size(); ++i) { >- const auto& bindGroupLayout = layout.bindGroupLayouts()[i]; >- WHLSL::BindGroup bindGroup; >- bindGroup.name = static_cast<unsigned>(i); >- for (const auto& keyValuePair : bindGroupLayout->bindingsMap()) { >- const auto& gpuBindGroupLayoutBinding = keyValuePair.value; >- WHLSL::Binding binding; >- binding.visibility = convertShaderStageFlags(gpuBindGroupLayoutBinding.visibility); >- if (auto bindingType = convertBindingType(gpuBindGroupLayoutBinding.type)) >- binding.bindingType = *bindingType; >- else >- return WTF::nullopt; >- if (gpuBindGroupLayoutBinding.binding > std::numeric_limits<unsigned>::max()) >- return WTF::nullopt; >- binding.name = static_cast<unsigned>(gpuBindGroupLayoutBinding.binding); >- bindGroup.bindings.append(WTFMove(binding)); >- } >- result.append(WTFMove(bindGroup)); >- } >- return result; >-} >- > static bool trySetMetalFunctions(const char* const functionName, MTLLibrary *vertexMetalLibrary, MTLLibrary *fragmentMetalLibrary, MTLRenderPipelineDescriptor *mtlDescriptor, const String& vertexEntryPointName, const String& fragmentEntryPointName) > { > #if LOG_DISABLED >@@ -464,8 +410,6 @@ static bool trySetFunctions(const char* const functionName, const GPUPipelineSta > if (!whlslCompileResult) > return false; > >- WTFLogAlways("Metal Source: %s", whlslCompileResult->metalSource.utf8().data()); >- > NSError *error = nil; > > BEGIN_BLOCK_OBJC_EXCEPTIONS; >@@ -540,6 +484,11 @@ static RetainPtr<MTLRenderPipelineDescriptor> convertRenderPipelineDescriptor(co > > static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const char* const functionName, const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device) > { >+ if (!device.platformDevice()) { >+ LOG(WebGPU, "GPUComputePipeline::tryCreate(): Invalid GPUDevice!"); >+ return nullptr; >+ } >+ > auto mtlDescriptor = convertRenderPipelineDescriptor(functionName, descriptor, device); > if (!mtlDescriptor) > return nullptr; >@@ -548,7 +497,7 @@ static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const c > > BEGIN_BLOCK_OBJC_EXCEPTIONS; > >- NSError *error = [NSError errorWithDomain:@"com.apple.WebKit.GPU" code:1 userInfo:nil]; >+ NSError *error = nil; > pipeline = adoptNS([device.platformDevice() newRenderPipelineStateWithDescriptor:mtlDescriptor.get() error:&error]); > if (!pipeline) > LOG(WebGPU, "%s: %s!", functionName, error.localizedDescription.UTF8String); >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 861721226ef5d8b0f4d0103c0e78d775d664403f..0b746216035b722d65a20fc4efaecd87240655c8 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,15 @@ >+2019-06-07 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] Hook up compute >+ https://bugs.webkit.org/show_bug.cgi?id=198644 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This doesn't thoroughly test compute, but it's at least enough to unblock the WHLSL testing effort. >+ >+ * webgpu/whlsl-compute-expected.txt: Added. >+ * webgpu/whlsl-compute.html: Added. >+ > 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/whlsl-compute-expected.txt b/LayoutTests/webgpu/whlsl-compute-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..6e1668a103beb92f76ea7e8d7aa7ffb50e89e241 >--- /dev/null >+++ b/LayoutTests/webgpu/whlsl-compute-expected.txt >@@ -0,0 +1,12 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+PASS resultsFloat32Array[0] is 2 >+PASS resultsFloat32Array[1] is 4 >+PASS resultsFloat32Array[2] is 6 >+PASS resultsFloat32Array[3] is 8 >+PASS resultsFloat32Array[4] is 5 >+PASS resultsFloat32Array[5] is 6 >+PASS resultsFloat32Array[6] is 7 >+PASS resultsFloat32Array[7] is 8 >+ >diff --git a/LayoutTests/webgpu/whlsl-compute.html b/LayoutTests/webgpu/whlsl-compute.html >new file mode 100644 >index 0000000000000000000000000000000000000000..df02655dfe5663bdad3ab2b48a4c07638ca044c2 >--- /dev/null >+++ b/LayoutTests/webgpu/whlsl-compute.html >@@ -0,0 +1,83 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script> >+const shaderSource = ` >+[numthreads(2, 1, 1)] >+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0; >+} >+`; >+let resultsFloat32Array; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const computeStage = {module: shaderModule, entryPoint: "computeShader"}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const computePipelineDescriptor = {computeStage, layout: pipelineLayout}; >+ const computePipeline = device.createComputePipeline(computePipelineDescriptor); >+ >+ const bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferFloat32Array = new Float32Array(bufferArrayBuffer); >+ bufferFloat32Array[0] = 1; >+ bufferFloat32Array[1] = 2; >+ bufferFloat32Array[2] = 3; >+ bufferFloat32Array[3] = 4; >+ bufferFloat32Array[4] = 5; >+ bufferFloat32Array[5] = 6; >+ bufferFloat32Array[6] = 7; >+ bufferFloat32Array[7] = 8; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, Float32Array.BYTES_PER_ELEMENT * 8); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(2, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ resultsFloat32Array = new Float32Array(resultsArrayBuffer); >+ shouldBe("resultsFloat32Array[0]", "2"); >+ shouldBe("resultsFloat32Array[1]", "4"); >+ shouldBe("resultsFloat32Array[2]", "6"); >+ shouldBe("resultsFloat32Array[3]", "8"); >+ shouldBe("resultsFloat32Array[4]", "5"); >+ shouldBe("resultsFloat32Array[5]", "6"); >+ shouldBe("resultsFloat32Array[6]", "7"); >+ shouldBe("resultsFloat32Array[7]", "8"); >+ resultsBuffer.unmap(); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+<script src="../resources/js-test-post.js"></script> >+</body> >+</html>
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 198644
:
371561
| 371612