[WHLSL] Resources don't work when only a subset of a bind group is referenced by...
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Sep 2019 05:23:51 +0000 (05:23 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Sep 2019 05:23:51 +0000 (05:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201383

Reviewed by Dean Jackson.

Source/WebCore:

Bind groups correspond to argument buffers in Metal. Both the Metal API and Metal Shading Language
have to agree on the layout of exactly which resources lie at which byte offsets within an argument
buffer.

Before this patch, we only emitted code for the items in the argument buffer that were actually
referenced by the shader source code. However, because these items are held inside a struct, if
we omit one item from the middle of the struct, the byte offets of all the successive items would
be wrong. This means that the Metal API and the shader would disagree about how to access these
resources, making the resources inaccessible (and causing security problems).

Tests: webgpu/whlsl/sparse-bind-group-2.html
       webgpu/whlsl/sparse-bind-group-3.html
       webgpu/whlsl/sparse-bind-group.html

* Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp:
(WebCore::WHLSL::Metal::EntryPointScaffolding::emitResourceHelperTypes):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitHelperTypes):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitHelperTypes):
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitHelperTypes):
* Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h:
* Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp:
(WebCore::WHLSL::matchResources):
(WebCore::WHLSL::matchVertexAttributes):
(WebCore::WHLSL::matchColorAttachments):

LayoutTests:

* webgpu/whlsl/compute.html:
* webgpu/whlsl/sparse-bind-group-2-expected.txt: Added.
* webgpu/whlsl/sparse-bind-group-2.html: Added.
* webgpu/whlsl/sparse-bind-group-3-expected.txt: Added.
* webgpu/whlsl/sparse-bind-group-3.html: Added.
* webgpu/whlsl/sparse-bind-group-expected.txt: Added.
* webgpu/whlsl/sparse-bind-group.html: Added.

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

13 files changed:
LayoutTests/ChangeLog
LayoutTests/webgpu/whlsl/compute.html
LayoutTests/webgpu/whlsl/sparse-bind-group-2-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/sparse-bind-group-2.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/sparse-bind-group-3-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/sparse-bind-group-3.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl/sparse-bind-group-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl/sparse-bind-group.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp
Source/WebCore/platform/graphics/gpu/cocoa/GPUBindGroupLayoutMetal.mm

index 13a489d..76e49fe 100644 (file)
@@ -1,3 +1,18 @@
+2019-09-01  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [WHLSL] Resources don't work when only a subset of a bind group is referenced by a shader
+        https://bugs.webkit.org/show_bug.cgi?id=201383
+
+        Reviewed by Dean Jackson.
+
+        * webgpu/whlsl/compute.html:
+        * webgpu/whlsl/sparse-bind-group-2-expected.txt: Added.
+        * webgpu/whlsl/sparse-bind-group-2.html: Added.
+        * webgpu/whlsl/sparse-bind-group-3-expected.txt: Added.
+        * webgpu/whlsl/sparse-bind-group-3.html: Added.
+        * webgpu/whlsl/sparse-bind-group-expected.txt: Added.
+        * webgpu/whlsl/sparse-bind-group.html: Added.
+
 2019-09-01  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r249369.
index 1f632e6..1cee6e6 100644 (file)
@@ -74,6 +74,7 @@ async function start(device) {
         testFailed("");
     resultsBuffer.unmap();
 }
+
 window.jsTestIsAsync = true;
 getBasicDevice().then(function(device) {
     start(device).then(function() {
diff --git a/LayoutTests/webgpu/whlsl/sparse-bind-group-2-expected.txt b/LayoutTests/webgpu/whlsl/sparse-bind-group-2-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/sparse-bind-group-2.html b/LayoutTests/webgpu/whlsl/sparse-bind-group-2.html
new file mode 100644 (file)
index 0000000..97c317f
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../js/webgpu-functions.js"></script>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const shaderSource = `
+[numthreads(1, 1, 1)]
+compute void computeShader(device float[] buffer : register(u1)) {
+    buffer[0] = 17;
+}
+`;
+
+async function start(device) {
+    const shaderModule = device.createShaderModule({code: shaderSource});
+    const computeStage = {module: shaderModule, entryPoint: "computeShader"};
+
+    const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}, {binding: 1, 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 size = Float32Array.BYTES_PER_ELEMENT * 1;
+
+    const buffer1 = device.createBuffer({size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ});
+    const buffer2 = device.createBuffer({size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ});
+
+    const bindGroup = device.createBindGroup({layout: bindGroupLayout, bindings: [{binding: 0, resource: {buffer: buffer1, size}}, {binding: 1, resource: {buffer: buffer2, size}}]});
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(1, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await buffer2.mapReadAsync();
+    const resultsFloat32Array = new Float32Array(resultsArrayBuffer);
+    if (resultsFloat32Array[0] == 17)
+        testPassed("");
+    else
+        testFailed("");
+    buffer2.unmap();
+}
+
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed("");
+    finishJSTest();
+});
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/sparse-bind-group-3-expected.txt b/LayoutTests/webgpu/whlsl/sparse-bind-group-3-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/sparse-bind-group-3.html b/LayoutTests/webgpu/whlsl/sparse-bind-group-3.html
new file mode 100644 (file)
index 0000000..9dbf158
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../js/webgpu-functions.js"></script>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const shaderSource = `
+[numthreads(1, 1, 1)]
+compute void computeShader(device float[] buffer : register(u1)) {
+    buffer[0] = 17;
+}
+`;
+
+async function start(device) {
+    const shaderModule = device.createShaderModule({code: shaderSource});
+    const computeStage = {module: shaderModule, entryPoint: "computeShader"};
+
+    const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 0, type: "storage-buffer"}, {binding: 1, 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 size = Float32Array.BYTES_PER_ELEMENT * 1;
+
+    const buffer1 = device.createBuffer({size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ});
+    const buffer2 = device.createBuffer({size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ});
+
+    const bindGroup = device.createBindGroup({layout: bindGroupLayout, bindings: [{binding: 0, resource: {buffer: buffer1, size}}, {binding: 1, resource: {buffer: buffer2, size}}]});
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(1, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await buffer2.mapReadAsync();
+    const resultsFloat32Array = new Float32Array(resultsArrayBuffer);
+    if (resultsFloat32Array[0] == 17)
+        testPassed("");
+    else
+        testFailed("");
+    buffer2.unmap();
+}
+
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed("");
+    finishJSTest();
+});
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl/sparse-bind-group-expected.txt b/LayoutTests/webgpu/whlsl/sparse-bind-group-expected.txt
new file mode 100644 (file)
index 0000000..4882f90
--- /dev/null
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webgpu/whlsl/sparse-bind-group.html b/LayoutTests/webgpu/whlsl/sparse-bind-group.html
new file mode 100644 (file)
index 0000000..a938224
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../js/webgpu-functions.js"></script>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const shaderSource = `
+[numthreads(1, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0, space1)) {
+    buffer[0] = 17;
+}
+`;
+
+async function start(device) {
+    const shaderModule = device.createShaderModule({code: shaderSource});
+    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, bindGroupLayout]};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const computePipelineDescriptor = {computeStage, layout: pipelineLayout};
+    const computePipeline = device.createComputePipeline(computePipelineDescriptor);
+
+    const size = Float32Array.BYTES_PER_ELEMENT * 1;
+
+    const buffer1 = device.createBuffer({size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ});
+    const buffer2 = device.createBuffer({size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ});
+
+    const bindGroup1 = device.createBindGroup({layout: bindGroupLayout, bindings: [{binding: 0, resource: {buffer: buffer1, size}}]});
+    const bindGroup2 = device.createBindGroup({layout: bindGroupLayout, bindings: [{binding: 0, resource: {buffer: buffer2, size}}]});
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup1);
+    computePassEncoder.setBindGroup(1, bindGroup2);
+    computePassEncoder.dispatch(1, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await buffer2.mapReadAsync();
+    const resultsFloat32Array = new Float32Array(resultsArrayBuffer);
+    if (resultsFloat32Array[0] == 17)
+        testPassed("");
+    else
+        testFailed("");
+    buffer2.unmap();
+}
+
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed("");
+    finishJSTest();
+});
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 2bb4896..a9ebd9a 100644 (file)
@@ -1,3 +1,35 @@
+2019-09-01  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [WHLSL] Resources don't work when only a subset of a bind group is referenced by a shader
+        https://bugs.webkit.org/show_bug.cgi?id=201383
+
+        Reviewed by Dean Jackson.
+
+        Bind groups correspond to argument buffers in Metal. Both the Metal API and Metal Shading Language
+        have to agree on the layout of exactly which resources lie at which byte offsets within an argument
+        buffer.
+
+        Before this patch, we only emitted code for the items in the argument buffer that were actually
+        referenced by the shader source code. However, because these items are held inside a struct, if
+        we omit one item from the middle of the struct, the byte offets of all the successive items would
+        be wrong. This means that the Metal API and the shader would disagree about how to access these
+        resources, making the resources inaccessible (and causing security problems).
+
+        Tests: webgpu/whlsl/sparse-bind-group-2.html
+               webgpu/whlsl/sparse-bind-group-3.html
+               webgpu/whlsl/sparse-bind-group.html
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp:
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::emitResourceHelperTypes):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitHelperTypes):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitHelperTypes):
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitHelperTypes):
+        * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h:
+        * Modules/webgpu/WHLSL/WHLSLSemanticMatcher.cpp:
+        (WebCore::WHLSL::matchResources):
+        (WebCore::WHLSL::matchVertexAttributes):
+        (WebCore::WHLSL::matchColorAttachments):
+
 2019-09-01  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r249369.
index 7e75937..8fb8a3b 100644 (file)
@@ -139,7 +139,7 @@ EntryPointScaffolding::EntryPointScaffolding(AST::FunctionDefinition& functionDe
         m_parameterVariables.uncheckedAppend(m_generateNextVariableName());
 }
 
-void EntryPointScaffolding::emitResourceHelperTypes(StringBuilder& stringBuilder, Indentation<4> indent)
+void EntryPointScaffolding::emitResourceHelperTypes(StringBuilder& stringBuilder, Indentation<4> indent, ShaderStage shaderStage)
 {
     for (size_t i = 0; i < m_layout.size(); ++i) {
         stringBuilder.append(indent, "struct ", m_namedBindGroups[i].structName, " {\n");
@@ -147,25 +147,43 @@ void EntryPointScaffolding::emitResourceHelperTypes(StringBuilder& stringBuilder
             IndentationScope scope(indent);
             Vector<std::pair<unsigned, String>> structItems;
             for (size_t j = 0; j < m_layout[i].bindings.size(); ++j) {
-                auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]);
-                if (iterator == m_resourceMap.end())
+                auto& binding = m_layout[i].bindings[j];
+                if (!binding.visibility.contains(shaderStage))
                     continue;
-                auto& type = m_entryPointItems.inputs[iterator->value].unnamedType->unifyNode();
-                if (is<AST::UnnamedType>(type) && is<AST::ReferenceType>(downcast<AST::UnnamedType>(type))) {
-                    auto& referenceType = downcast<AST::ReferenceType>(downcast<AST::UnnamedType>(type));
-                    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;
-                    structItems.append(std::make_pair(index, makeString(addressSpace, " ", mangledTypeName, "* ", elementName, " [[id(", index, ")]];")));
-                    if (auto lengthInformation = m_namedBindGroups[i].namedBindings[j].lengthInformation)
-                        structItems.append(std::make_pair(lengthInformation->index, makeString("uint2 ", lengthInformation->elementName, " [[id(", lengthInformation->index, ")]];")));
-                } else if (is<AST::NamedType>(type) && is<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(type))) {
-                    auto& namedType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(type));
-                    auto mangledTypeName = m_typeNamer.mangledNameForType(namedType);
-                    auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
-                    auto index = m_namedBindGroups[i].namedBindings[j].index;
-                    structItems.append(std::make_pair(index, makeString(mangledTypeName, ' ', elementName, " [[id(", index, ")]];")));
+
+                auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
+                auto index = m_namedBindGroups[i].namedBindings[j].index;
+                if (auto lengthInformation = m_namedBindGroups[i].namedBindings[j].lengthInformation)
+                    structItems.append(std::make_pair(lengthInformation->index, makeString("uint2 ", lengthInformation->elementName, " [[id(", lengthInformation->index, ")]];")));
+
+                auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]);
+                if (iterator != m_resourceMap.end()) {
+                    auto& type = m_entryPointItems.inputs[iterator->value].unnamedType->unifyNode();
+                    if (is<AST::UnnamedType>(type) && is<AST::ReferenceType>(downcast<AST::UnnamedType>(type))) {
+                        auto& referenceType = downcast<AST::ReferenceType>(downcast<AST::UnnamedType>(type));
+                        auto mangledTypeName = m_typeNamer.mangledNameForType(referenceType.elementType());
+                        auto addressSpace = toString(referenceType.addressSpace());
+                        structItems.append(std::make_pair(index, makeString(addressSpace, " ", mangledTypeName, "* ", elementName, " [[id(", index, ")]];")));
+                    } else if (is<AST::NamedType>(type) && is<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(type))) {
+                        auto& namedType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(type));
+                        auto mangledTypeName = m_typeNamer.mangledNameForType(namedType);
+                        structItems.append(std::make_pair(index, makeString(mangledTypeName, ' ', elementName, " [[id(", index, ")]];")));
+                    }
+                } else {
+                    // The binding doesn't appear in the shader source.
+                    // However, we must still emit a placeholder, so successive items in the argument buffer struct have the correct offset.
+                    // Because the binding doesn't appear in the shader source, we don't know which exact type the bind point should have.
+                    // Therefore, we must synthesize a type out of thin air.
+                    WTF::visit(WTF::makeVisitor([&](UniformBufferBinding) {
+                        structItems.append(std::make_pair(index, makeString("constant void* ", elementName, " [[id(", index, ")]];")));
+                    }, [&](SamplerBinding) {
+                        structItems.append(std::make_pair(index, makeString("sampler ", elementName, " [[id(", index, ")]];")));
+                    }, [&](TextureBinding) {
+                        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=201384 We don't know which texture type the binding represents. This is no good very bad.
+                        structItems.append(std::make_pair(index, makeString("texture2d<float> ", elementName, " [[id(", index, ")]];")));
+                    }, [&](StorageBufferBinding) {
+                        structItems.append(std::make_pair(index, makeString("device void* ", elementName, " [[id(", index, ")]];")));
+                    }), binding.binding);
                 }
             }
             std::sort(structItems.begin(), structItems.end(), [](const std::pair<unsigned, String>& left, const std::pair<unsigned, String>& right) {
@@ -425,7 +443,7 @@ void VertexEntryPointScaffolding::emitHelperTypes(StringBuilder& stringBuilder,
     }
     stringBuilder.append(indent, "};\n\n");
     
-    emitResourceHelperTypes(stringBuilder, indent);
+    emitResourceHelperTypes(stringBuilder, indent, ShaderStage::Vertex);
 }
 
 void VertexEntryPointScaffolding::emitSignature(StringBuilder& stringBuilder, MangledFunctionName functionName, Indentation<4> indent)
@@ -530,7 +548,7 @@ void FragmentEntryPointScaffolding::emitHelperTypes(StringBuilder& stringBuilder
     }
     stringBuilder.append(indent, "};\n\n");
 
-    emitResourceHelperTypes(stringBuilder, indent);
+    emitResourceHelperTypes(stringBuilder, indent, ShaderStage::Fragment);
 }
 
 void FragmentEntryPointScaffolding::emitSignature(StringBuilder& stringBuilder, MangledFunctionName functionName, Indentation<4> indent)
@@ -580,7 +598,7 @@ ComputeEntryPointScaffolding::ComputeEntryPointScaffolding(AST::FunctionDefiniti
 
 void ComputeEntryPointScaffolding::emitHelperTypes(StringBuilder& stringBuilder, Indentation<4> indent)
 {
-    emitResourceHelperTypes(stringBuilder, indent);
+    emitResourceHelperTypes(stringBuilder, indent, ShaderStage::Compute);
 }
 
 void ComputeEntryPointScaffolding::emitSignature(StringBuilder& stringBuilder, MangledFunctionName functionName, Indentation<4> indent)
index 48a8c5b..e5b4c6d 100644 (file)
@@ -64,7 +64,7 @@ public:
 protected:
     EntryPointScaffolding(AST::FunctionDefinition&, Intrinsics&, TypeNamer&, EntryPointItems&, HashMap<Binding*, size_t>& resourceMap, Layout&, std::function<MangledVariableName()>&& generateNextVariableName);
 
-    void emitResourceHelperTypes(StringBuilder&, Indentation<4>);
+    void emitResourceHelperTypes(StringBuilder&, Indentation<4>, ShaderStage);
 
     enum class IncludePrecedingComma {
         Yes,
index 2cc7d7d..542fa78 100644 (file)
@@ -61,9 +61,7 @@ static bool matchMode(Binding::BindingDetails bindingType, AST::ResourceSemantic
 static Optional<HashMap<Binding*, size_t>> matchResources(Vector<EntryPointItem>& entryPointItems, Layout& layout, ShaderStage shaderStage)
 {
     HashMap<Binding*, size_t> result;
-    HashSet<size_t> itemIndices;
-    if (entryPointItems.size() == std::numeric_limits<size_t>::max())
-        return WTF::nullopt; // Work around the fact that HashSet's keys are restricted.
+    HashSet<size_t, DefaultHash<size_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<size_t>> itemIndices;
     for (auto& bindGroup : layout) {
         auto space = bindGroup.name;
         for (auto& binding : bindGroup.bindings) {
@@ -82,7 +80,7 @@ static Optional<HashMap<Binding*, size_t>> matchResources(Vector<EntryPointItem>
                 if (space != resourceSemantic.space())
                     continue;
                 result.add(&binding, i);
-                itemIndices.add(i + 1); // Work around the fact that HashSet's keys are restricted.
+                itemIndices.add(i);
             }
         }
     }
@@ -92,7 +90,7 @@ static Optional<HashMap<Binding*, size_t>> matchResources(Vector<EntryPointItem>
         auto& semantic = *item.semantic;
         if (!WTF::holds_alternative<AST::ResourceSemantic>(semantic))
             continue;
-        if (!itemIndices.contains(i + 1))
+        if (!itemIndices.contains(i))
             return WTF::nullopt;
     }
 
@@ -142,9 +140,7 @@ static bool isAcceptableFormat(VertexFormat vertexFormat, AST::UnnamedType& unna
 static Optional<HashMap<VertexAttribute*, size_t>> matchVertexAttributes(Vector<EntryPointItem>& vertexInputs, VertexAttributes& vertexAttributes, Intrinsics& intrinsics)
 {
     HashMap<VertexAttribute*, size_t> result;
-    HashSet<size_t> itemIndices;
-    if (vertexInputs.size() == std::numeric_limits<size_t>::max())
-        return WTF::nullopt; // Work around the fact that HashSet's keys are restricted.
+    HashSet<size_t, DefaultHash<size_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<size_t>> itemIndices;
     for (auto& vertexAttribute : vertexAttributes) {
         for (size_t i = 0; i < vertexInputs.size(); ++i) {
             auto& item = vertexInputs[i];
@@ -157,7 +153,7 @@ static Optional<HashMap<VertexAttribute*, size_t>> matchVertexAttributes(Vector<
             if (!isAcceptableFormat(vertexAttribute.vertexFormat, *item.unnamedType, intrinsics))
                 return WTF::nullopt;
             result.add(&vertexAttribute, i);
-            itemIndices.add(i + 1); // Work around the fact that HashSet's keys are restricted.
+            itemIndices.add(i);
         }
     }
 
@@ -166,7 +162,7 @@ static Optional<HashMap<VertexAttribute*, size_t>> matchVertexAttributes(Vector<
         auto& semantic = *item.semantic;
         if (!WTF::holds_alternative<AST::StageInOutSemantic>(semantic))
             continue;
-        if (!itemIndices.contains(i + 1))
+        if (!itemIndices.contains(i))
             return WTF::nullopt;
     }
 
@@ -230,9 +226,7 @@ static bool isAcceptableFormat(TextureFormat textureFormat, AST::UnnamedType& un
 static Optional<HashMap<AttachmentDescriptor*, size_t>> matchColorAttachments(Vector<EntryPointItem>& fragmentOutputs, Vector<AttachmentDescriptor>& attachmentDescriptors, Intrinsics& intrinsics)
 {
     HashMap<AttachmentDescriptor*, size_t> result;
-    HashSet<size_t> itemIndices;
-    if (attachmentDescriptors.size() == std::numeric_limits<size_t>::max())
-        return WTF::nullopt; // Work around the fact that HashSet's keys are restricted.
+    HashSet<size_t, DefaultHash<size_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<size_t>> itemIndices;
     for (auto& attachmentDescriptor : attachmentDescriptors) {
         for (size_t i = 0; i < fragmentOutputs.size(); ++i) {
             auto& item = fragmentOutputs[i];
@@ -245,7 +239,7 @@ static Optional<HashMap<AttachmentDescriptor*, size_t>> matchColorAttachments(Ve
             if (!isAcceptableFormat(attachmentDescriptor.textureFormat, *item.unnamedType, intrinsics, true))
                 return WTF::nullopt;
             result.add(&attachmentDescriptor, i);
-            itemIndices.add(i + 1); // Work around the fact that HashSet's keys are restricted.
+            itemIndices.add(i);
         }
     }
 
@@ -254,7 +248,7 @@ static Optional<HashMap<AttachmentDescriptor*, size_t>> matchColorAttachments(Ve
         auto& semantic = *item.semantic;
         if (!WTF::holds_alternative<AST::StageInOutSemantic>(semantic))
             continue;
-        if (!itemIndices.contains(i + 1))
+        if (!itemIndices.contains(i))
             return WTF::nullopt;
     }
 
index 8020163..a26badf 100644 (file)
@@ -84,6 +84,7 @@ static RetainPtr<MTLArgumentDescriptor> argumentDescriptor(MTLDataType dataType,
     mtlArgument = adoptNS([MTLArgumentDescriptor new]);
     END_BLOCK_OBJC_EXCEPTIONS;
 
+    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=201384 This needs to set the "textureType" field
     [mtlArgument setDataType:dataType];
     [mtlArgument setIndex:index];
     return mtlArgument;