[Web GPU] Vertex Buffers/Input State API updates
authorjustin_fan@apple.com <justin_fan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 May 2019 21:05:16 +0000 (21:05 +0000)
committerjustin_fan@apple.com <justin_fan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 May 2019 21:05:16 +0000 (21:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194258
<rdar://problem/47806127>

Reviewed by Myles C. Maxfield.

Source/WebCore:

The vertex buffer attributes model for GPURenderPipelines in the WebGPU API has been updated.
Update our implementation to match.

No new tests. Existing tests updated to match new behavior.

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* Modules/webgpu/GPUVertexAttributeDescriptor.idl:
* Modules/webgpu/GPUVertexBufferDescriptor.idl: Renamed from Source/WebCore/Modules/webgpu/GPUInputStateDescriptor.idl.
* Modules/webgpu/GPUVertexInputDescriptor.idl:
* Modules/webgpu/WebGPURenderPipelineDescriptor.idl:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/gpu/GPURenderPipelineDescriptor.h:
* platform/graphics/gpu/GPUVertexAttributeDescriptor.h:
* platform/graphics/gpu/GPUVertexBufferDescriptor.h: Renamed from Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h.
* platform/graphics/gpu/GPUVertexInputDescriptor.h:
* platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
(WebCore::trySetVertexInput): Added. Populate Metal and WHLSL pipeline descriptors with vertex attribute metadata.
(WebCore::trySetColorStates): Added. Populate Metal and WHLSL pipeline descriptors with color attachment metadata.
(WebCore::convertLayout): Moved.
(WebCore::trySetMetalFunctions): Moved.
(WebCore::trySetFunctions): Added. WHLSL compilation to Metal SL happens here, then MSL functions are set on pipeline descriptor.
(WebCore::convertRenderPipelineDescriptor): Repurposed. Convert a GPURenderPipelineDescriptor to Metal and WHLSL versions.
(WebCore::tryCreateMtlRenderPipelineState):
(WebCore::GPURenderPipeline::tryCreate):
(WebCore::trySetMetalFunctionsForPipelineDescriptor): Deleted.
(WebCore::trySetWHLSLFunctionsForPipelineDescriptor): Deleted.
(WebCore::trySetFunctionsForPipelineDescriptor): Deleted.
(WebCore::trySetInputStateForPipelineDescriptor): Deleted.
(WebCore::setColorStatesForColorAttachmentArray): Deleted.

LayoutTests:

Update WebGPU tests for the new vertex buffer attributes model.

* webgpu/blend-triangle-strip.html:
* webgpu/buffer-command-buffer-races.html:
* webgpu/buffer-resource-triangles.html:
* webgpu/depth-enabled-triangle-strip.html:
* webgpu/draw-indexed-triangles.html:
* webgpu/js/webgpu-functions.js:
* webgpu/texture-triangle-strip.html:
* webgpu/vertex-buffer-triangle-strip.html:
* webgpu/whlsl-arbitrary-vertex-attribute-locations.html:
* webgpu/whlsl-dereference-pointer-should-type-check.html:
* webgpu/whlsl-dont-crash-parsing-enum.html:
* webgpu/whlsl-dot-expressions.html:
* webgpu/whlsl-nested-dot-expression-rvalue.html:
* webgpu/whlsl.html:

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

31 files changed:
LayoutTests/ChangeLog
LayoutTests/webgpu/blend-triangle-strip.html
LayoutTests/webgpu/buffer-command-buffer-races.html
LayoutTests/webgpu/buffer-resource-triangles.html
LayoutTests/webgpu/depth-enabled-triangle-strip.html
LayoutTests/webgpu/draw-indexed-triangles.html
LayoutTests/webgpu/js/webgpu-functions.js
LayoutTests/webgpu/texture-triangle-strip.html
LayoutTests/webgpu/vertex-buffer-triangle-strip.html
LayoutTests/webgpu/whlsl-arbitrary-vertex-attribute-locations.html
LayoutTests/webgpu/whlsl-dereference-pointer-should-type-check.html
LayoutTests/webgpu/whlsl-dont-crash-parsing-enum.html
LayoutTests/webgpu/whlsl-dot-expressions.html
LayoutTests/webgpu/whlsl-nested-dot-expression-rvalue.html
LayoutTests/webgpu/whlsl.html
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources-input.xcfilelist
Source/WebCore/DerivedSources-output.xcfilelist
Source/WebCore/DerivedSources.make
Source/WebCore/Modules/webgpu/GPUVertexAttributeDescriptor.idl
Source/WebCore/Modules/webgpu/GPUVertexBufferDescriptor.idl [moved from Source/WebCore/Modules/webgpu/GPUInputStateDescriptor.idl with 81% similarity]
Source/WebCore/Modules/webgpu/GPUVertexInputDescriptor.idl
Source/WebCore/Modules/webgpu/WebGPURenderPipelineDescriptor.idl
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/gpu/GPURenderPipelineDescriptor.h
Source/WebCore/platform/graphics/gpu/GPUVertexAttributeDescriptor.h
Source/WebCore/platform/graphics/gpu/GPUVertexBufferDescriptor.h [moved from Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h with 82% similarity]
Source/WebCore/platform/graphics/gpu/GPUVertexInputDescriptor.h
Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm

index c927bda..78485df 100644 (file)
@@ -1,3 +1,28 @@
+2019-05-30  Justin Fan  <justin_fan@apple.com>
+
+        [Web GPU] Vertex Buffers/Input State API updates
+        https://bugs.webkit.org/show_bug.cgi?id=194258
+        <rdar://problem/47806127>
+
+        Reviewed by Myles C. Maxfield.
+
+        Update WebGPU tests for the new vertex buffer attributes model.
+
+        * webgpu/blend-triangle-strip.html:
+        * webgpu/buffer-command-buffer-races.html:
+        * webgpu/buffer-resource-triangles.html:
+        * webgpu/depth-enabled-triangle-strip.html:
+        * webgpu/draw-indexed-triangles.html:
+        * webgpu/js/webgpu-functions.js:
+        * webgpu/texture-triangle-strip.html:
+        * webgpu/vertex-buffer-triangle-strip.html:
+        * webgpu/whlsl-arbitrary-vertex-attribute-locations.html:
+        * webgpu/whlsl-dereference-pointer-should-type-check.html:
+        * webgpu/whlsl-dont-crash-parsing-enum.html:
+        * webgpu/whlsl-dot-expressions.html:
+        * webgpu/whlsl-nested-dot-expression-rvalue.html:
+        * webgpu/whlsl.html:
+
 2019-05-30  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Missing caret when focusing an editable field if the selection was set when WKWebView wasn't first responder
index 7932d30..dd7fda6 100644 (file)
@@ -56,20 +56,18 @@ async function test() {
         colorBlend: { dstFactor: "one" }
     }];
 
-    const inputStateDescriptor = {
+    const vertexInputDescriptor = {
         indexFormat: "uint32",
-        attributes: [{
-            shaderLocation: positionAttributeNum,
-            inputSlot: 0,
-            format: "float4"
-        }],
-        inputs: [{
-            inputSlot: 0,
-            stride: 4 * 4
+        vertexBuffers: [{
+            stride: 4 * 4,
+            attributeSet: [{
+                format: "float4",
+                shaderLocation: positionAttributeNum
+            }]
         }]
     };
 
-    const pipeline = createBasicPipeline(shaderModule, device, colorStates, null, inputStateDescriptor);
+    const pipeline = createBasicPipeline(shaderModule, device, colorStates, null, vertexInputDescriptor);
 
     const vertexData = new Float32Array([
         -1, 1, 0, 1,
index 3f04aec..2aecda4 100644 (file)
@@ -42,25 +42,22 @@ fragment float4 fragment_main(VertexOut v [[stage_in]])
 }
 `
 
-function createInputStateDescriptor() {
+function createVertexInputDescriptor() {
     return {
         indexFormat: "uint32",
-        attributes: [{
-            shaderLocation: 0,
-            inputSlot: 0,
-            format: "float2"
+        vertexBuffers: [{
+            stride: 4 * 2,
+            attributeSet: [{
+                format: "float2",
+                shaderLocation: 0
+            }]
         }, {
-            shaderLocation: 1,
-            inputSlot: 1,
-            format: "float3"
-        }],
-        inputs: [{
-            inputSlot: 0,
-            stride: 4 * 2
-        }, {
-            inputSlot: 1,
             stride: 4 * 3,
-            stepMode: "instance"
+            stepMode: "instance",
+            attributeSet: [{
+                format: "float3",
+                shaderLocation: 1
+            }]
         }]
     }
 }
@@ -88,8 +85,8 @@ async function test() {
     const swapChain = createBasicSwapChain(canvas, device);
     // FIXME: Replace with non-MSL shaders.
     const shaderModule = device.createShaderModule({ code: shaderCode });
-    const inputStateDescriptor = createInputStateDescriptor();
-    const pipeline = createBasicPipeline(shaderModule, device, null, null, inputStateDescriptor);
+    const vertexInputDescriptor = createVertexInputDescriptor();
+    const pipeline = createBasicPipeline(shaderModule, device, null, null, vertexInputDescriptor);
 
     const upperLeftBuffer = createAndSetVertexBuffer(device, [-1, 1, -1, -1, 0, 1]);
     const middleBuffer = createAndSetVertexBuffer(device, [0, 1, -1, -1, 1, -1]);
index 2bff4a9..bd06c45 100644 (file)
@@ -132,16 +132,14 @@ async function test() {
     const green = createFloat4Buffer(device, 0, 1, bufferPromises);
 
     // Create vertex input state.
-    const inputState = {
+    const vertexInput = {
         indexFormat: "uint32",
-        attributes: [{
-            shaderLocation: 0,
-            inputSlot: 0,
-            format: "float4"
-        }],
-        inputs: [{
-            inputSlot: 0,
-            stride: vertexSize
+        vertexBuffers: [{
+            stride: vertexSize,
+            attributeSet: [{
+                format: "float4",
+                shaderLocation: 0
+            }]
         }]
     };
 
@@ -159,7 +157,7 @@ async function test() {
 
     // GPUPipelineLayout and GPURenderPipeline
     const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [leftTriangleBGLayout, rightTriangleBGLayout] });
-    const pipeline = createBasicPipeline(shaderModule, device, null, pipelineLayout, inputState, null, "triangle-list");
+    const pipeline = createBasicPipeline(shaderModule, device, null, pipelineLayout, vertexInput, null, "triangle-list");
 
     // GPUBufferBindings
     const bindingUL = createBufferBinding(upperLeft);
index e017e9b..925c4c8 100644 (file)
@@ -62,17 +62,15 @@ function createVertexBuffer(device) {
     return buffer;
 }
 
-function createInputStateDescriptor() {
+function createVertexInputDescriptor() {
     return {
         indexFormat: "uint32",
-        attributes: [{
-            shaderLocation: 0,
-            inputSlot: 0,
-            format: "float4"
-        }],
-        inputs: [{
-            inputSlot: 0,
-            stride: 4 * 4
+        vertexBuffers: [{
+            stride: 4 * 4,
+            attributeSet: [{
+                format: "float4",
+                shaderLocation: 0
+            }]
         }]
     }
 }
@@ -84,9 +82,9 @@ async function test() {
     // FIXME: Replace with non-MSL shaders.
     const shaderModule = device.createShaderModule({ code: shaderCode });
     const vertexBuffer = createVertexBuffer(device);
-    const inputStateDescriptor = createInputStateDescriptor();
+    const vertexInputDescriptor = createVertexInputDescriptor();
     const depthStateDescriptor = createBasicDepthStateDescriptor();
-    const pipeline = createBasicPipeline(shaderModule, device, null, null, inputStateDescriptor, depthStateDescriptor);
+    const pipeline = createBasicPipeline(shaderModule, device, null, null, vertexInputDescriptor, depthStateDescriptor);
     const commandEncoder = device.createCommandEncoder();
 
     const basicAttachment = {
index 0d644cf..289e3bf 100644 (file)
@@ -71,22 +71,19 @@ function createIndexBuffer(device) {
     return buffer;
 }
 
-function createInputStateDescriptor() {
+function createVertexInputDescriptor() {
     return {
         indexFormat: "uint32",
-        attributes: [{
-            shaderLocation: 0,
-            inputSlot: 0,
-            format: "float4"
-        }, {
-            shaderLocation: 1,
-            inputSlot: 0,
-            offset: 4 * 4,
-            format: "float"
-        }],
-        inputs: [{
-            inputSlot: 0,
-            stride: 4 * 5
+        vertexBuffers: [{
+            stride: 4 * 5,
+            attributeSet: [{
+                format: "float4",
+                shaderLocation: 0
+            }, {
+                offset: 4 * 4,
+                format: "float",
+                shaderLocation: 1
+            }]
         }]
     };
 }
@@ -99,7 +96,7 @@ async function test() {
     const shaderModule = device.createShaderModule({ code: shaderCode });
     const vertexBuffer = createVertexBuffer(device);
     const indexBuffer = createIndexBuffer(device);
-    const pipeline = createBasicPipeline(shaderModule, device, null, null, createInputStateDescriptor(), null, "triangle-list");
+    const pipeline = createBasicPipeline(shaderModule, device, null, null, createVertexInputDescriptor(), null, "triangle-list");
     const commandEncoder = device.createCommandEncoder();
     const passEncoder = beginBasicRenderPass(swapChain, commandEncoder);
 
index 5409714..1cc6d6e 100644 (file)
@@ -30,7 +30,7 @@ function createBasicDepthTexture(canvas, device) {
     });
 }
 
-function createBasicPipeline(shaderModule, device, colorStates, pipelineLayout, inputStateDescriptor, depthStateDescriptor, primitiveTopology = "triangle-strip") {
+function createBasicPipeline(shaderModule, device, colorStates, pipelineLayout, vertexInputDescriptor, depthStateDescriptor, primitiveTopology = "triangle-strip") {
     const vertexStageDescriptor = {
         module: shaderModule,
         entryPoint: "vertex_main" 
@@ -49,15 +49,15 @@ function createBasicPipeline(shaderModule, device, colorStates, pipelineLayout,
         }];
     }
 
-    if (!inputStateDescriptor)
-        inputStateDescriptor = { attributes: [], inputs: [] };
+    if (!vertexInputDescriptor)
+        vertexInputDescriptor = { vertexBuffers: [] };
 
     const pipelineDescriptor = {
         vertexStage: vertexStageDescriptor,
         fragmentStage: fragmentStageDescriptor,
         primitiveTopology: primitiveTopology,
         colorStates: colorStates,
-        inputState: inputStateDescriptor
+        vertexInput: vertexInputDescriptor
     };
 
     if (pipelineLayout)
index d34f3c1..33a0e65 100644 (file)
@@ -55,26 +55,24 @@ fragment float4 fragment_main(VertexOut v [[stage_in]], const device TextureSamp
 }
 `
 
-function createInputStateDescriptor() {
-    return {
-        indexFormat: "uint32",
-        attributes: [{
-            shaderLocation: positionAttributeNum,
-            inputSlot: positionBufferIndex,
-            format: "float4"
-        }, {
-            shaderLocation: texCoordsAttributeNum,
-            inputSlot: texCoordsBufferIndex,
-            format: "float2"
-        }],
-        inputs: [{
-            inputSlot: positionBufferIndex,
-            stride: 4 * 4
-        }, {
-            inputSlot: texCoordsBufferIndex,
-            stride: 4 * 2
+function createVertexInputDescriptor() {
+    var bufferDescriptors = [];
+    bufferDescriptors[positionBufferIndex] = {
+        stride: 4 * 4,
+        attributeSet: [{
+            format: "float4",
+            shaderLocation: positionAttributeNum
         }]
-    }
+    };
+    bufferDescriptors[texCoordsBufferIndex] = {
+        stride: 4 * 2,
+        attributeSet: [{
+            format: "float2",
+            shaderLocation: texCoordsAttributeNum
+        }]
+    };
+
+    return { vertexBuffers: bufferDescriptors };
 }
 
 async function test() {
@@ -104,7 +102,7 @@ async function test() {
     const textureCoordBuffer = device.createBuffer({ size: texCoordsArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
     textureCoordBuffer.setSubData(0, texCoordsArray.buffer);
 
-    const inputStateDescriptor = createInputStateDescriptor();
+    const vertexInputDescriptor = createVertexInputDescriptor();
 
     // Load texture image
     const image = new Image();
@@ -177,7 +175,7 @@ async function test() {
     const bindGroup = device.createBindGroup(bindGroupDescriptor);
 
     // Pipeline and render
-    const pipeline = createBasicPipeline(shaderModule, device, null, pipelineLayout, inputStateDescriptor);
+    const pipeline = createBasicPipeline(shaderModule, device, null, pipelineLayout, vertexInputDescriptor);
     const commandEncoder = device.createCommandEncoder();
 
     const bufferCopyView = {
index bd7843c..acd4cee 100644 (file)
@@ -60,22 +60,18 @@ function createVertexBuffer(device) {
     return buffer;
 }
 
-function createInputStateDescriptor() {
+function createVertexInputDescriptor() {
     return {
-        indexFormat: "uint32",
-        attributes: [{
-            shaderLocation: 0,
-            inputSlot: 0,
-            format: "float4"
-        }, {
-            shaderLocation: 1,
-            inputSlot: 0,
-            offset: 4 * 4,
-            format: "float"
-        }],
-        inputs: [{
-            inputSlot: 0,
-            stride: 4 * 5
+        vertexBuffers: [{
+            stride: 4 * 5,
+            attributeSet: [{
+                format: "float4",
+                shaderLocation: 0
+            }, {
+                offset: 4 * 4,
+                format: "float",
+                shaderLocation: 1
+            }]
         }]
     }
 }
@@ -87,8 +83,8 @@ async function test() {
     // FIXME: Replace with non-MSL shaders.
     const shaderModule = device.createShaderModule({ code: shaderCode });
     const vertexBuffer = createVertexBuffer(device);
-    const inputStateDescriptor = createInputStateDescriptor();
-    const pipeline = createBasicPipeline(shaderModule, device, null, null, inputStateDescriptor);
+    const vertexInputDescriptor = createVertexInputDescriptor();
+    const pipeline = createBasicPipeline(shaderModule, device, null, null, vertexInputDescriptor);
     const commandEncoder = device.createCommandEncoder();
     const passEncoder = beginBasicRenderPass(swapChain, commandEncoder);
     encodeBasicCommands(passEncoder, pipeline, vertexBuffer);
index 40a1404..b35e6c2 100644 (file)
@@ -36,19 +36,18 @@ async function start() {
     const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
     const depthStencilState = null;
 
-    const attribute0 = {shaderLocation: 173, inputSlot: 0, format: "float4", offset: 0};
-    const attribute1 = {shaderLocation: 498, inputSlot: 0, format: "float", offset: 16};
-    const attributes = [attribute0, attribute1];
-    const input0 = {inputSlot: 0, stride: 20 };
+    const attribute0 = {shaderLocation: 173, format: "float4"};
+    const attribute1 = {shaderLocation: 498, format: "float", offset: 16};
+    const input0 = {stride: 20, attributeSet: [attribute0, attribute1]};
     const inputs = [input0];
-    const inputState = {indexFormat: "uint32", attributes, inputs};
+    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, inputState, sampleCount: 1, layout: pipelineLayout};
+    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 * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
index be8fc1f..9507d6b 100644 (file)
@@ -41,19 +41,19 @@ async function start() {
     const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
     const depthStencilState = null;
 
-    const attribute0 = {shaderLocation: 0, inputSlot: 0, format: "float4", offset: 0};
-    const attribute1 = {shaderLocation: 1, inputSlot: 0, format: "float", offset: 16};
+    const attribute0 = {shaderLocation: 0, format: "float4", offset: 0};
+    const attribute1 = {shaderLocation: 1, format: "float", offset: 16};
     const attributes = [attribute0, attribute1];
-    const input0 = {inputSlot: 0, stride: 20 };
+    const input0 = {stride: 20, attributeSet: attributes};
     const inputs = [input0];
-    const inputState = {indexFormat: "uint32", attributes, inputs};
+    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, inputState, sampleCount: 1, layout: pipelineLayout};
+    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 * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
index cb6f55e..2f8edd3 100644 (file)
@@ -33,20 +33,19 @@ async function start() {
     const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
     const depthStencilState = null;
     
-    const attribute0 = {shaderLocation: 0, inputSlot: 0, format: "float4"};
-    const attribute1 = {shaderLocation: 1, inputSlot: 1, format: "float"};
-    const attributes = [attribute0, attribute1];
-    const input0 = {inputSlot: 0, stride: 16 };
-    const input1 = {inputSlot: 1, stride: 4 };
+    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 inputState = {indexFormat: "uint32", attributes, inputs};
+    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, inputState, sampleCount: 1, layout: pipelineLayout};
+    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};
index 18ac9e6..0056322 100644 (file)
@@ -36,19 +36,19 @@ async function start() {
     const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
     const depthStencilState = null;
 
-    const attribute0 = {shaderLocation: 0, inputSlot: 0, format: "float4", offset: 0};
-    const attribute1 = {shaderLocation: 1, inputSlot: 0, format: "float", offset: 16};
+    const attribute0 = {shaderLocation: 0, format: "float4"};
+    const attribute1 = {shaderLocation: 1, format: "float", offset: 16};
     const attributes = [attribute0, attribute1];
-    const input0 = {inputSlot: 0, stride: 20 };
+    const input0 = {stride: 20, attributeSet: attributes};
     const inputs = [input0];
-    const inputState = {indexFormat: "uint32", attributes, inputs};
+    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, inputState, sampleCount: 1, layout: pipelineLayout};
+    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 * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
index 3d548df..f72ad54 100644 (file)
@@ -50,19 +50,19 @@ async function start() {
     const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
     const depthStencilState = null;
 
-    const attribute0 = {shaderLocation: 0, inputSlot: 0, format: "float4", offset: 0};
-    const attribute1 = {shaderLocation: 1, inputSlot: 0, format: "float", offset: 16};
+    const attribute0 = {shaderLocation: 0, format: "float4"};
+    const attribute1 = {shaderLocation: 1, format: "float", offset: 16};
     const attributes = [attribute0, attribute1];
-    const input0 = {inputSlot: 0, stride: 20 };
+    const input0 = {stride: 20, attributeSet: attributes};
     const inputs = [input0];
-    const inputState = {indexFormat: "uint32", attributes, inputs};
+    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, inputState, sampleCount: 1, layout: pipelineLayout};
+    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 * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
index 7c7d79e..13726de 100644 (file)
@@ -28,20 +28,19 @@ async function start() {
     const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
     const depthStencilState = null;
     
-    const attribute0 = {shaderLocation: 0, inputSlot: 0, format: "float4"};
-    const attribute1 = {shaderLocation: 1, inputSlot: 1, format: "float"};
-    const attributes = [attribute0, attribute1];
-    const input0 = {inputSlot: 0, stride: 16 };
-    const input1 = {inputSlot: 1, stride: 4 };
+    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 inputState = {indexFormat: "uint32", attributes, inputs};
+    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, inputState, sampleCount: 1, layout: pipelineLayout};
+    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};
index 840d0f5..0b0fdf8 100644 (file)
@@ -480,7 +480,6 @@ set(WebCore_NON_SVG_IDL_FILES
     Modules/webgpu/GPUCompareFunction.idl
     Modules/webgpu/GPUDepthStencilStateDescriptor.idl
     Modules/webgpu/GPUExtent3D.idl
-    Modules/webgpu/GPUInputStateDescriptor.idl
     Modules/webgpu/GPULoadOp.idl
     Modules/webgpu/GPUOrigin3D.idl
     Modules/webgpu/GPURequestAdapterOptions.idl
@@ -491,6 +490,7 @@ set(WebCore_NON_SVG_IDL_FILES
     Modules/webgpu/GPUTextureFormat.idl
     Modules/webgpu/GPUTextureUsage.idl
     Modules/webgpu/GPUVertexAttributeDescriptor.idl
+    Modules/webgpu/GPUVertexBufferDescriptor.idl
     Modules/webgpu/GPUVertexInputDescriptor.idl
     Modules/webgpu/NavigatorGPU.idl
     Modules/webgpu/WebGPU.idl
index 80f83bd..25f9187 100644 (file)
@@ -1,3 +1,45 @@
+2019-05-30  Justin Fan  <justin_fan@apple.com>
+
+        [Web GPU] Vertex Buffers/Input State API updates
+        https://bugs.webkit.org/show_bug.cgi?id=194258
+        <rdar://problem/47806127>
+
+        Reviewed by Myles C. Maxfield.
+
+        The vertex buffer attributes model for GPURenderPipelines in the WebGPU API has been updated.
+        Update our implementation to match.
+
+        No new tests. Existing tests updated to match new behavior.
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * Modules/webgpu/GPUVertexAttributeDescriptor.idl:
+        * Modules/webgpu/GPUVertexBufferDescriptor.idl: Renamed from Source/WebCore/Modules/webgpu/GPUInputStateDescriptor.idl.
+        * Modules/webgpu/GPUVertexInputDescriptor.idl:
+        * Modules/webgpu/WebGPURenderPipelineDescriptor.idl:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/gpu/GPURenderPipelineDescriptor.h:
+        * platform/graphics/gpu/GPUVertexAttributeDescriptor.h:
+        * platform/graphics/gpu/GPUVertexBufferDescriptor.h: Renamed from Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h.
+        * platform/graphics/gpu/GPUVertexInputDescriptor.h:
+        * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
+        (WebCore::trySetVertexInput): Added. Populate Metal and WHLSL pipeline descriptors with vertex attribute metadata.
+        (WebCore::trySetColorStates): Added. Populate Metal and WHLSL pipeline descriptors with color attachment metadata.
+        (WebCore::convertLayout): Moved.
+        (WebCore::trySetMetalFunctions): Moved.
+        (WebCore::trySetFunctions): Added. WHLSL compilation to Metal SL happens here, then MSL functions are set on pipeline descriptor.
+        (WebCore::convertRenderPipelineDescriptor): Repurposed. Convert a GPURenderPipelineDescriptor to Metal and WHLSL versions.
+        (WebCore::tryCreateMtlRenderPipelineState):
+        (WebCore::GPURenderPipeline::tryCreate):
+        (WebCore::trySetMetalFunctionsForPipelineDescriptor): Deleted.
+        (WebCore::trySetWHLSLFunctionsForPipelineDescriptor): Deleted.
+        (WebCore::trySetFunctionsForPipelineDescriptor): Deleted.
+        (WebCore::trySetInputStateForPipelineDescriptor): Deleted.
+        (WebCore::setColorStatesForColorAttachmentArray): Deleted.
+
 2019-05-30  Zalan Bujtas  <zalan@apple.com>
 
         [iOS] Do not linkify telephone numbers inside <a> elements.
index ac56c7a..21b5ee7 100644 (file)
@@ -342,6 +342,7 @@ $(PROJECT_DIR)/Modules/webgpu/GPUTextureDescriptor.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUTextureFormat.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUTextureUsage.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUVertexAttributeDescriptor.idl
+$(PROJECT_DIR)/Modules/webgpu/GPUVertexBufferDescriptor.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUVertexInputDescriptor.idl
 $(PROJECT_DIR)/Modules/webgpu/NavigatorGPU.idl
 $(PROJECT_DIR)/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt
index 3dd908e..04acd20 100644 (file)
@@ -633,6 +633,8 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUTextureUsage.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUTextureUsage.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUVertexAttributeDescriptor.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUVertexAttributeDescriptor.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUVertexBufferDescriptor.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUVertexBufferDescriptor.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUVertexInputDescriptor.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUVertexInputDescriptor.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGainNode.cpp
index b988da2..57ae114 100644 (file)
@@ -388,7 +388,6 @@ JS_BINDING_IDLS = \
     $(WebCore)/Modules/webgpu/GPUDepthStencilStateDescriptor.idl \
     $(WebCore)/Modules/webgpu/GPUExtent3D.idl \
     $(WebCore)/Modules/webgpu/GPULoadOp.idl \
-    $(WebCore)/Modules/webgpu/GPUInputStateDescriptor.idl \
     $(WebCore)/Modules/webgpu/GPUOrigin3D.idl \
     $(WebCore)/Modules/webgpu/GPURequestAdapterOptions.idl \
     $(WebCore)/Modules/webgpu/GPUSamplerDescriptor.idl \
@@ -398,6 +397,7 @@ JS_BINDING_IDLS = \
     $(WebCore)/Modules/webgpu/GPUTextureFormat.idl \
     $(WebCore)/Modules/webgpu/GPUTextureUsage.idl \
     $(WebCore)/Modules/webgpu/GPUVertexAttributeDescriptor.idl \
+    $(WebCore)/Modules/webgpu/GPUVertexBufferDescriptor.idl \
        $(WebCore)/Modules/webgpu/GPUVertexInputDescriptor.idl \
     $(WebCore)/Modules/webgpu/NavigatorGPU.idl \
     $(WebCore)/Modules/webgpu/WebGPU.idl \
index a83e964..49ecf24 100644 (file)
@@ -40,8 +40,7 @@ typedef unsigned long long u64;
     Conditional=WEBGPU,
     EnabledAtRuntime=WebGPU
 ] dictionary GPUVertexAttributeDescriptor {
-    required u32 shaderLocation;
-    required u32 inputSlot;
     u64 offset = 0;
     required GPUVertexFormat format;
+    required u32 shaderLocation;
 };
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * 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
 // https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
 
 typedef unsigned long u32;
+typedef unsigned long long u64;
 
 [
-    ImplementedAs=GPUIndexFormat
-] enum GPUIndexFormat {
-    "uint16",
-    "uint32"
+    ImplementedAs=GPUInputStepMode
+] enum GPUInputStepMode {
+    "vertex",
+    "instance"
 };
 
 [
     Conditional=WEBGPU,
     EnabledAtRuntime=WebGPU
-] dictionary GPUInputStateDescriptor {
-    GPUIndexFormat? indexFormat;
-
-    required sequence<GPUVertexAttributeDescriptor> attributes;
-    required sequence<GPUVertexInputDescriptor> inputs;
+] dictionary GPUVertexBufferDescriptor {
+    required u64 stride;
+    GPUInputStepMode stepMode = "vertex";
+    sequence<GPUVertexAttributeDescriptor> attributeSet;
 };
index 22a0c9e..9a8b6bf 100644 (file)
 // https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
 
 typedef unsigned long u32;
-typedef unsigned long long u64;
 
 [
-    ImplementedAs=GPUInputStepMode
-] enum GPUInputStepMode {
-    "vertex",
-    "instance"
+    ImplementedAs=GPUIndexFormat
+] enum GPUIndexFormat {
+    "uint16",
+    "uint32"
 };
 
 [
     Conditional=WEBGPU,
     EnabledAtRuntime=WebGPU
 ] dictionary GPUVertexInputDescriptor {
-    required u32 inputSlot;
-    required u64 stride;
-    GPUInputStepMode stepMode = "vertex";
+    GPUIndexFormat indexFormat = "uint32";
+    required sequence<GPUVertexBufferDescriptor?> vertexBuffers;
 };
index 8748db8..32a94b1 100644 (file)
@@ -44,5 +44,5 @@
     required GPUPrimitiveTopology primitiveTopology;
     required sequence<GPUColorStateDescriptor> colorStates;
     GPUDepthStencilStateDescriptor? depthStencilState = null;
-    required GPUInputStateDescriptor inputState;
+    required GPUVertexInputDescriptor vertexInput;
 };
index 0317125..4024236 100644 (file)
@@ -2747,7 +2747,6 @@ JSGPUBufferUsage.cpp
 JSGPUCompareFunction.cpp
 JSGPUDepthStencilStateDescriptor.cpp
 JSGPUExtent3D.cpp
-JSGPUInputStateDescriptor.cpp
 JSGPULoadOp.cpp
 JSGPUOrigin3D.cpp
 JSGPURequestAdapterOptions.cpp
@@ -2758,6 +2757,7 @@ JSGPUTextureDescriptor.cpp
 JSGPUTextureFormat.cpp
 JSGPUTextureUsage.cpp
 JSGPUVertexAttributeDescriptor.cpp
+JSGPUVertexBufferDescriptor.cpp
 JSGPUVertexInputDescriptor.cpp
 JSGainNode.cpp
 JSGeolocation.cpp
index c001863..52db78f 100644 (file)
                D0D8648E21B70676003C983C /* WebGPUBuffer.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebGPUBuffer.idl; sourceTree = "<group>"; };
                D0D8649121B760C4003C983C /* GPUBufferMetal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = GPUBufferMetal.mm; sourceTree = "<group>"; };
                D0D8649221B760F2003C983C /* GPUBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUBuffer.h; sourceTree = "<group>"; };
-               D0D8649421BA173D003C983C /* GPUInputStateDescriptor.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = GPUInputStateDescriptor.idl; sourceTree = "<group>"; };
+               D0D8649421BA173D003C983C /* GPUVertexInputDescriptor.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = GPUVertexInputDescriptor.idl; sourceTree = "<group>"; };
                D0D8649621BA18F4003C983C /* GPUVertexAttributeDescriptor.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = GPUVertexAttributeDescriptor.idl; sourceTree = "<group>"; };
-               D0D8649821BA19A7003C983C /* GPUVertexInputDescriptor.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = GPUVertexInputDescriptor.idl; sourceTree = "<group>"; };
-               D0D8649921BA1B1F003C983C /* GPUInputStateDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUInputStateDescriptor.h; sourceTree = "<group>"; };
+               D0D8649821BA19A7003C983C /* GPUVertexBufferDescriptor.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = GPUVertexBufferDescriptor.idl; sourceTree = "<group>"; };
+               D0D8649921BA1B1F003C983C /* GPUVertexInputDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUVertexInputDescriptor.h; sourceTree = "<group>"; };
                D0D8649B21BA1C2D003C983C /* GPUVertexAttributeDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUVertexAttributeDescriptor.h; sourceTree = "<group>"; };
-               D0D8649C21BA1CE8003C983C /* GPUVertexInputDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUVertexInputDescriptor.h; sourceTree = "<group>"; };
+               D0D8649C21BA1CE8003C983C /* GPUVertexBufferDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUVertexBufferDescriptor.h; sourceTree = "<group>"; };
                D0DA0BE4217930E2007FE2AC /* WebGPUSwapChain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebGPUSwapChain.h; sourceTree = "<group>"; };
                D0DA0BE5217930E2007FE2AC /* WebGPUSwapChain.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebGPUSwapChain.cpp; sourceTree = "<group>"; };
                D0DA0BE6217930E2007FE2AC /* WebGPUSwapChain.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebGPUSwapChain.idl; sourceTree = "<group>"; };
                                312FF8BF21A4C2F100EB199D /* GPUDevice.cpp */,
                                312FF8BE21A4C2F100EB199D /* GPUDevice.h */,
                                D026F47D220A2AC600AC5F49 /* GPUExtent3D.h */,
-                               D0D8649921BA1B1F003C983C /* GPUInputStateDescriptor.h */,
                                D0F7559F2203BA1400118058 /* GPULimits.h */,
                                D08AA02F220D0BD50058C502 /* GPULoadOp.h */,
                                312FF8C421A4C2F400EB199D /* GPUPipelineDescriptorBase.h */,
                                D026F485220A477200AC5F49 /* GPUTextureUsage.h */,
                                D06EF552220BA26A0018724E /* GPUUtils.h */,
                                D0D8649B21BA1C2D003C983C /* GPUVertexAttributeDescriptor.h */,
-                               D0D8649C21BA1CE8003C983C /* GPUVertexInputDescriptor.h */,
+                               D0D8649C21BA1CE8003C983C /* GPUVertexBufferDescriptor.h */,
+                               D0D8649921BA1B1F003C983C /* GPUVertexInputDescriptor.h */,
                                498770D71242C535002226BA /* Texture.cpp */,
                                498770D81242C535002226BA /* Texture.h */,
                                498770D91242C535002226BA /* TilingData.cpp */,
                                D03C849E21FFCF000002227F /* GPUCompareFunction.idl */,
                                D03C84A221FFD7230002227F /* GPUDepthStencilStateDescriptor.idl */,
                                D026F480220A2B7000AC5F49 /* GPUExtent3D.idl */,
-                               D0D8649421BA173D003C983C /* GPUInputStateDescriptor.idl */,
                                D08AA02D220D0B9C0058C502 /* GPULoadOp.idl */,
                                D0CCA94922299F97006979B6 /* GPUOrigin3D.h */,
                                D0CCA94A22299F97006979B6 /* GPUOrigin3D.idl */,
                                D0EACFAE219E30FD000FA75C /* GPUTextureFormat.idl */,
                                D026F483220A472F00AC5F49 /* GPUTextureUsage.idl */,
                                D0D8649621BA18F4003C983C /* GPUVertexAttributeDescriptor.idl */,
-                               D0D8649821BA19A7003C983C /* GPUVertexInputDescriptor.idl */,
+                               D0D8649821BA19A7003C983C /* GPUVertexBufferDescriptor.idl */,
+                               D0D8649421BA173D003C983C /* GPUVertexInputDescriptor.idl */,
                                D00487ED2274281300EED7D9 /* NavigatorGPU.cpp */,
                                D00487EE2274281400EED7D9 /* NavigatorGPU.h */,
                                D00487EB2274281200EED7D9 /* NavigatorGPU.idl */,
index 03fa0e0..8c3f37e 100644 (file)
@@ -29,9 +29,9 @@
 
 #include "GPUColorStateDescriptor.h"
 #include "GPUDepthStencilStateDescriptor.h"
-#include "GPUInputStateDescriptor.h"
 #include "GPUPipelineDescriptorBase.h"
 #include "GPUPipelineStageDescriptor.h"
+#include "GPUVertexInputDescriptor.h"
 #include <wtf/Optional.h>
 #include <wtf/Vector.h>
 
@@ -49,7 +49,7 @@ struct GPURenderPipelineDescriptorBase {
     GPUPrimitiveTopology primitiveTopology;
     Vector<GPUColorStateDescriptor> colorStates;
     Optional<GPUDepthStencilStateDescriptor> depthStencilState;
-    GPUInputStateDescriptor inputState;
+    GPUVertexInputDescriptor vertexInput;
 };
 
 struct GPURenderPipelineDescriptor : GPUPipelineDescriptorBase, GPURenderPipelineDescriptorBase {
index a7bc782..43ac635 100644 (file)
@@ -39,10 +39,9 @@ enum class GPUVertexFormat {
 };
 
 struct GPUVertexAttributeDescriptor {
-    unsigned shaderLocation;
-    unsigned inputSlot;
     uint64_t offset;
     GPUVertexFormat format;
+    unsigned shaderLocation;
 };
 
 } // namespace WebCore
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * 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
 #if ENABLE(WEBGPU)
 
 #include "GPUVertexAttributeDescriptor.h"
-#include "GPUVertexInputDescriptor.h"
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
-enum class GPUIndexFormat {
-    Uint16,
-    Uint32,
+enum class GPUInputStepMode {
+    Vertex,
+    Instance,
 };
 
-struct GPUInputStateDescriptor {
-    Optional<GPUIndexFormat> indexFormat;
-
-    Vector<GPUVertexAttributeDescriptor> attributes;
-    Vector<GPUVertexInputDescriptor> inputs;
+struct GPUVertexBufferDescriptor {
+    uint64_t stride;
+    GPUInputStepMode stepMode;
+    Vector<GPUVertexAttributeDescriptor> attributeSet;
 };
 
 } // namespace WebCore
index 2c7091e..6bf96c4 100644 (file)
 
 #if ENABLE(WEBGPU)
 
+#include "GPUVertexBufferDescriptor.h"
+#include <wtf/Vector.h>
+
 namespace WebCore {
 
-enum class GPUInputStepMode {
-    Vertex,
-    Instance,
+enum class GPUIndexFormat {
+    Uint16,
+    Uint32,
 };
 
 struct GPUVertexInputDescriptor {
-    unsigned inputSlot;
-    uint64_t stride;
-    GPUInputStepMode stepMode;
+    GPUIndexFormat indexFormat;
+    Vector<Optional<GPUVertexBufferDescriptor>> vertexBuffers;
 };
 
 } // namespace WebCore
index 9c4b2a0..2bb6204 100644 (file)
@@ -37,6 +37,7 @@
 #import <Metal/Metal.h>
 #import <wtf/BlockObjCExceptions.h>
 #import <wtf/CheckedArithmetic.h>
+#import <wtf/HashSet.h>
 #import <wtf/OptionSet.h>
 #import <wtf/Optional.h>
 
@@ -145,158 +146,6 @@ static Optional<WHLSL::TextureFormat> convertTextureFormat(GPUTextureFormat form
     }
 }
 
-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 Optional<WHLSL::RenderPipelineDescriptor> convertRenderPipelineDescriptor(const GPURenderPipelineDescriptor& descriptor)
-{
-    WHLSL::RenderPipelineDescriptor whlslDescriptor;
-    if (descriptor.inputState.attributes.size() > std::numeric_limits<unsigned>::max())
-        return WTF::nullopt;
-    if (descriptor.colorStates.size() > std::numeric_limits<unsigned>::max())
-        return WTF::nullopt;
-
-    for (size_t i = 0; i < descriptor.inputState.attributes.size(); ++i)
-        whlslDescriptor.vertexAttributes.append({ convertVertexFormat(descriptor.inputState.attributes[i].format), descriptor.inputState.attributes[i].shaderLocation, static_cast<unsigned>(i) });
-
-    for (size_t i = 0; i < descriptor.colorStates.size(); ++i) {
-        if (auto format = convertTextureFormat(descriptor.colorStates[i].format))
-            whlslDescriptor.attachmentsStateDescriptor.attachmentDescriptors.append({*format, static_cast<unsigned>(i)});
-        else
-            return WTF::nullopt;
-    }
-
-    // FIXME: depthStencilAttachmentDescriptor isn't implemented yet.
-
-    if (descriptor.layout) {
-        if (auto layout = convertLayout(*descriptor.layout))
-            whlslDescriptor.layout = WTFMove(*layout);
-        else
-            return WTF::nullopt;
-    }
-    whlslDescriptor.vertexEntryPointName = descriptor.vertexStage.entryPoint;
-    if (descriptor.fragmentStage)
-        whlslDescriptor.fragmentEntryPointName = descriptor.fragmentStage->entryPoint;
-    return whlslDescriptor;
-}
-
-static bool trySetMetalFunctionsForPipelineDescriptor(const char* const functionName, MTLLibrary *vertexMetalLibrary, MTLLibrary *fragmentMetalLibrary, MTLRenderPipelineDescriptor *mtlDescriptor, const String& vertexEntryPointName, const String& fragmentEntryPointName)
-{
-#if LOG_DISABLED
-    UNUSED_PARAM(functionName);
-#endif
-
-    {
-        BEGIN_BLOCK_OBJC_EXCEPTIONS;
-
-        // Metal requires a vertex shader in all render pipelines.
-        if (!vertexMetalLibrary) {
-            LOG(WebGPU, "%s: MTLLibrary for vertex stage does not exist!", functionName);
-            return false;
-        }
-
-        auto function = adoptNS([vertexMetalLibrary newFunctionWithName:vertexEntryPointName]);
-        if (!function) {
-            LOG(WebGPU, "%s: Cannot create vertex MTLFunction \"%s\"!", functionName, vertexEntryPointName.utf8().data());
-            return false;
-        }
-
-        [mtlDescriptor setVertexFunction:function.get()];
-
-        END_BLOCK_OBJC_EXCEPTIONS;
-    }
-
-    {
-        BEGIN_BLOCK_OBJC_EXCEPTIONS;
-
-        // However, fragment shaders are optional.
-        if (!fragmentMetalLibrary)
-            return true;
-
-        auto function = adoptNS([fragmentMetalLibrary newFunctionWithName:fragmentEntryPointName]);
-
-        if (!function) {
-            LOG(WebGPU, "%s: Cannot create fragment MTLFunction \"%s\"!", functionName, fragmentEntryPointName.utf8().data());
-            return false;
-        }
-
-        [mtlDescriptor setFragmentFunction:function.get()];
-        return true;
-
-        END_BLOCK_OBJC_EXCEPTIONS;
-    }
-
-    return false;
-}
-
-static bool trySetWHLSLFunctionsForPipelineDescriptor(const char* const functionName, MTLRenderPipelineDescriptor *mtlDescriptor, const GPURenderPipelineDescriptor& descriptor, String whlslSource, const GPUDevice& device)
-{
-    auto whlslDescriptor = convertRenderPipelineDescriptor(descriptor);
-    if (!whlslDescriptor)
-        return false;
-
-    auto result = WHLSL::prepare(whlslSource, *whlslDescriptor);
-    if (!result)
-        return false;
-
-    WTFLogAlways("Metal Source: %s", result->metalSource.utf8().data());
-
-    NSError *error = nil;
-    auto library = adoptNS([device.platformDevice() newLibraryWithSource:result->metalSource options:nil error:&error]);
-    ASSERT(library);
-    // 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.
-
-    return trySetMetalFunctionsForPipelineDescriptor(functionName, library.get(), library.get(), mtlDescriptor, result->mangledVertexEntryPointName, result->mangledFragmentEntryPointName);
-}
-
-static bool trySetFunctionsForPipelineDescriptor(const char* const functionName, MTLRenderPipelineDescriptor *mtlDescriptor, const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device)
-{
-    const auto& vertexStage = descriptor.vertexStage;
-    const auto& fragmentStage = descriptor.fragmentStage;
-
-    const auto& whlslSource = vertexStage.module->whlslSource();
-    if (!whlslSource.isNull()) {
-        if (!fragmentStage || vertexStage.module.ptr() == fragmentStage->module.ptr()) {
-            // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195446 Allow WHLSL shaders to come from different programs.
-            return trySetWHLSLFunctionsForPipelineDescriptor(functionName, mtlDescriptor, descriptor, whlslSource, device);
-        }
-    }
-
-    auto vertexLibrary = vertexStage.module->platformShaderModule();
-    MTLLibrary *fragmentLibrary = nil;
-    String fragmentEntryPoint;
-    if (fragmentStage) {
-        fragmentLibrary = fragmentStage->module->platformShaderModule();
-        fragmentEntryPoint = fragmentStage->entryPoint;
-    }
-
-    return trySetMetalFunctionsForPipelineDescriptor(functionName, vertexLibrary, fragmentLibrary, mtlDescriptor, vertexStage.entryPoint, fragmentEntryPoint);
-}
-
 static MTLVertexFormat mtlVertexFormatForGPUVertexFormat(GPUVertexFormat format)
 {
     switch (format) {
@@ -325,62 +174,79 @@ static MTLVertexStepFunction mtlStepFunctionForGPUInputStepMode(GPUInputStepMode
     ASSERT_NOT_REACHED();
 }
 
-static bool trySetInputStateForPipelineDescriptor(const char* const functionName, MTLRenderPipelineDescriptor *mtlDescriptor, const GPUInputStateDescriptor& descriptor)
+// FIXME: Move this into GPULimits when that is implemented properly.
+constexpr unsigned maxVertexAttributes = 16;
+
+static bool trySetVertexInput(const char* const functionName, const GPUVertexInputDescriptor& descriptor, MTLRenderPipelineDescriptor *mtlDescriptor, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor)
 {
 #if LOG_DISABLED
     UNUSED_PARAM(functionName);
 #endif
-    auto mtlVertexDescriptor = adoptNS([MTLVertexDescriptor new]);
+    const auto& buffers = descriptor.vertexBuffers;
 
-    const auto& attributes = descriptor.attributes;
+    if (buffers.size() > maxVertexBuffers) {
+        LOG(WebGPU, "%s: Too many vertex input buffers!", functionName);
+        return false;
+    }
 
-    auto attributeArray = retainPtr(mtlVertexDescriptor.get().attributes);
+    auto mtlVertexDescriptor = adoptNS([MTLVertexDescriptor new]);
 
-    for (size_t i = 0; i < attributes.size(); ++i) {
-        auto location = static_cast<unsigned>(i);
-        // Maximum number of vertex attributes to be supported by Web GPU.
-        if (location >= 16) {
-            LOG(WebGPU, "%s: Invalid shaderLocation %u for vertex attribute!", functionName, location);
-            return false;
-        }
-        if (attributes[i].inputSlot >= maxVertexBuffers) {
-            LOG(WebGPU, "%s: Invalid inputSlot %u for vertex attribute %u!", functionName, attributes[i].inputSlot, location);
-            return false;
-        }
-        // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
-        // FIXME: Ensure offset < buffer's stride + format's data size.
-        NSUInteger attributeOffset = 0;
-        if (!WTF::convertSafely(attributes[i].offset, attributeOffset)) {
-            LOG(WebGPU, "%s: Buffer offset for vertex attribute %u is too large!", functionName, location);
-            return false;
-        }
+    auto layoutArray = retainPtr(mtlVertexDescriptor.get().layouts);
+    auto attributeArray = retainPtr(mtlVertexDescriptor.get().attributes);
 
-        auto mtlAttributeDesc = retainPtr([attributeArray objectAtIndexedSubscript:location]);
-        [mtlAttributeDesc setFormat:mtlVertexFormatForGPUVertexFormat(attributes[i].format)];
-        [mtlAttributeDesc setOffset:attributeOffset];
-        [mtlAttributeDesc setBufferIndex:WHLSL::Metal::calculateVertexBufferIndex(attributes[i].inputSlot)];
-    }
+    // Attribute shaderLocations must be uniquely flat-mapped to [0, {max number of vertex attributes}].
+    unsigned attributeIndex = 0;
+    HashSet<unsigned, IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> locations;
 
-    const auto& inputs = descriptor.inputs;
+    for (size_t index = 0; index < buffers.size(); ++index) {
+        if (!buffers[index])
+            continue;
 
-    auto layoutArray = retainPtr(mtlVertexDescriptor.get().layouts);
+        const auto& attributes = buffers[index]->attributeSet;
 
-    for (size_t j = 0; j < inputs.size(); ++j) {
-        auto slot = inputs[j].inputSlot;
-        if (slot >= maxVertexBuffers) {
-            LOG(WebGPU, "%s: Invalid inputSlot %d for vertex buffer!", functionName, slot);
+        if (attributes.size() + attributeIndex > maxVertexAttributes) {
+            LOG(WebGPU, "%s: Too many vertex attributes!", functionName);
             return false;
         }
+
         NSUInteger inputStride = 0;
-        if (!WTF::convertSafely(inputs[j].stride, inputStride)) {
-            LOG(WebGPU, "%s: Stride for vertex buffer slot %d is too large!", functionName, slot);
+        if (!WTF::convertSafely(buffers[index]->stride, inputStride)) {
+            LOG(WebGPU, "%s: Stride for vertex input buffer %u is too large!", functionName, index);
             return false;
         }
 
-        auto convertedSlot = WHLSL::Metal::calculateVertexBufferIndex(slot);
-        auto mtlLayoutDesc = retainPtr([layoutArray objectAtIndexedSubscript:convertedSlot]);
-        [mtlLayoutDesc setStepFunction:mtlStepFunctionForGPUInputStepMode(inputs[j].stepMode)];
+        auto convertedBufferIndex = WHLSL::Metal::calculateVertexBufferIndex(index);
+
+        BEGIN_BLOCK_OBJC_EXCEPTIONS;
+        auto mtlLayoutDesc = retainPtr([layoutArray objectAtIndexedSubscript:convertedBufferIndex]);
+        [mtlLayoutDesc setStepFunction:mtlStepFunctionForGPUInputStepMode(buffers[index]->stepMode)];
         [mtlLayoutDesc setStride:inputStride];
+        END_BLOCK_OBJC_EXCEPTIONS;
+
+        for (const auto& attribute : attributes) {
+            if (!locations.add(attribute.shaderLocation).isNewEntry) {
+                LOG(WebGPU, "%s: Duplicate shaderLocation %u for vertex attribute!", functionName, attribute.shaderLocation);
+                return false;
+            }
+
+            NSUInteger offset = 0;
+            if (!WTF::convertSafely(attribute.offset, offset)) {
+                LOG(WebGPU, "%s: Buffer offset for vertex attribute %u is too large!", functionName, attribute.shaderLocation);
+                return false;
+            }
+
+            BEGIN_BLOCK_OBJC_EXCEPTIONS;
+            auto mtlAttributeDesc = retainPtr([attributeArray objectAtIndexedSubscript:attributeIndex]);
+            [mtlAttributeDesc setFormat:mtlVertexFormatForGPUVertexFormat(attribute.format)];
+            [mtlAttributeDesc setOffset:offset];
+            [mtlAttributeDesc setBufferIndex:convertedBufferIndex];
+            END_BLOCK_OBJC_EXCEPTIONS;
+
+            if (whlslDescriptor)
+                whlslDescriptor->vertexAttributes.append({ convertVertexFormat(attribute.format), attribute.shaderLocation, attributeIndex });
+
+            ++attributeIndex;
+        }
     }
 
     [mtlDescriptor setVertexDescriptor:mtlVertexDescriptor.get()];
@@ -460,8 +326,19 @@ static MTLBlendFactor mtlBlendFactorForGPUBlendFactor(GPUBlendFactor factor)
     ASSERT_NOT_REACHED();
 }
 
-static void setColorStatesForColorAttachmentArray(MTLRenderPipelineColorAttachmentDescriptorArray* array, const Vector<GPUColorStateDescriptor>& colorStates)
+static bool trySetColorStates(const char* const functionName, const Vector<GPUColorStateDescriptor>& colorStates, MTLRenderPipelineColorAttachmentDescriptorArray* array, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor)
 {
+#if LOG_DISABLED
+    UNUSED_PARAM(functionName);
+#endif
+    // FIXME: Replace with maximum number of color attachments per render pass from GPULimits.
+    if (colorStates.size() > 4) {
+        LOG(WebGPU, "%s: Invalid number of GPUColorStateDescriptors!", functionName);
+        return false;
+    }
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
     for (unsigned i = 0; i < colorStates.size(); ++i) {
         auto& state = colorStates[i];
         auto descriptor = retainPtr([array objectAtIndexedSubscript:i]);
@@ -474,10 +351,146 @@ static void setColorStatesForColorAttachmentArray(MTLRenderPipelineColorAttachme
         [descriptor setDestinationRGBBlendFactor:mtlBlendFactorForGPUBlendFactor(state.colorBlend.dstFactor)];
         [descriptor setSourceAlphaBlendFactor:mtlBlendFactorForGPUBlendFactor(state.alphaBlend.srcFactor)];
         [descriptor setSourceRGBBlendFactor:mtlBlendFactorForGPUBlendFactor(state.colorBlend.srcFactor)];
+
+        if (whlslDescriptor) {
+            if (auto format = convertTextureFormat(state.format))
+                whlslDescriptor->attachmentsStateDescriptor.attachmentDescriptors.append({*format, i});
+            else {
+                LOG(WebGPU, "%s: Invalid texture format for color attachment %u!", functionName, i);
+                return false;
+            }
+        }
     }
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    return true;
 }
 
-static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const char* const functionName, const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device)
+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
+    UNUSED_PARAM(functionName);
+#endif
+
+    {
+        BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+        // Metal requires a vertex shader in all render pipelines.
+        if (!vertexMetalLibrary) {
+            LOG(WebGPU, "%s: MTLLibrary for vertex stage does not exist!", functionName);
+            return false;
+        }
+
+        auto function = adoptNS([vertexMetalLibrary newFunctionWithName:vertexEntryPointName]);
+        if (!function) {
+            LOG(WebGPU, "%s: Cannot create vertex MTLFunction \"%s\"!", functionName, vertexEntryPointName.utf8().data());
+            return false;
+        }
+
+        [mtlDescriptor setVertexFunction:function.get()];
+
+        END_BLOCK_OBJC_EXCEPTIONS;
+    }
+
+    {
+        BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+        // However, fragment shaders are optional.
+        if (!fragmentMetalLibrary)
+            return true;
+
+        auto function = adoptNS([fragmentMetalLibrary newFunctionWithName:fragmentEntryPointName]);
+
+        if (!function) {
+            LOG(WebGPU, "%s: Cannot create fragment MTLFunction \"%s\"!", functionName, fragmentEntryPointName.utf8().data());
+            return false;
+        }
+
+        [mtlDescriptor setFragmentFunction:function.get()];
+        return true;
+
+        END_BLOCK_OBJC_EXCEPTIONS;
+    }
+
+    return false;
+}
+
+static bool trySetFunctions(const char* const functionName, const GPUPipelineStageDescriptor& vertexStage, const Optional<GPUPipelineStageDescriptor>& fragmentStage, const GPUDevice& device, MTLRenderPipelineDescriptor* mtlDescriptor, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor)
+{
+#if LOG_DISABLED
+    UNUSED_PARAM(functionName);
+#endif
+    RetainPtr<MTLLibrary> vertexLibrary, fragmentLibrary;
+    String vertexEntryPoint, fragmentEntryPoint;
+
+    if (whlslDescriptor) {
+        // WHLSL functions are compiled to MSL first.
+        String whlslSource = vertexStage.module->whlslSource();
+        ASSERT(!whlslSource.isNull());
+
+        whlslDescriptor->vertexEntryPointName = vertexStage.entryPoint;
+        if (fragmentStage)
+            whlslDescriptor->fragmentEntryPointName = fragmentStage->entryPoint;
+
+        auto whlslCompileResult = WHLSL::prepare(whlslSource, *whlslDescriptor);
+        if (!whlslCompileResult)
+            return false;
+
+        WTFLogAlways("Metal Source: %s", whlslCompileResult->metalSource.utf8().data());
+
+        NSError *error = nil;
+
+        BEGIN_BLOCK_OBJC_EXCEPTIONS;
+        vertexLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]);
+        END_BLOCK_OBJC_EXCEPTIONS;
+
+        ASSERT(vertexLibrary);
+        // 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.
+
+        fragmentLibrary = vertexLibrary;
+        vertexEntryPoint = whlslCompileResult->mangledVertexEntryPointName;
+        fragmentEntryPoint = whlslCompileResult->mangledFragmentEntryPointName;
+    } else {
+        vertexLibrary = vertexStage.module->platformShaderModule();
+        vertexEntryPoint = vertexStage.entryPoint;
+        if (fragmentStage) {
+            fragmentLibrary = fragmentStage->module->platformShaderModule();
+            fragmentEntryPoint = fragmentStage->entryPoint;
+        }
+    }
+
+    return trySetMetalFunctions(functionName, vertexLibrary.get(), fragmentLibrary.get(), mtlDescriptor, vertexEntryPoint, fragmentEntryPoint);
+}
+
+static RetainPtr<MTLRenderPipelineDescriptor> convertRenderPipelineDescriptor(const char* const functionName, const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device)
 {
     RetainPtr<MTLRenderPipelineDescriptor> mtlDescriptor;
 
@@ -492,17 +505,43 @@ static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const c
         return nullptr;
     }
 
-    bool didSetFunctions = false, didSetInputState = false;
+    // Determine if shader source is in WHLSL or MSL.
+    const auto& vertexStage = descriptor.vertexStage;
+    const auto& fragmentStage = descriptor.fragmentStage;
+
+    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195446 Allow WHLSL shaders to come from different programs.
+    bool isWhlsl = !vertexStage.module->whlslSource().isNull() && (!fragmentStage || vertexStage.module.ptr() == fragmentStage->module.ptr());
 
-    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    // Set data for the Metal pipeline descriptor (and WHLSL's, if needed).
+    Optional<WHLSL::RenderPipelineDescriptor> whlslDescriptor;
+    if (isWhlsl)
+        whlslDescriptor = WHLSL::RenderPipelineDescriptor();
 
-    didSetFunctions = trySetFunctionsForPipelineDescriptor(functionName, mtlDescriptor.get(), descriptor, device);
-    didSetInputState = trySetInputStateForPipelineDescriptor(functionName, mtlDescriptor.get(), descriptor.inputState);
-    setColorStatesForColorAttachmentArray(mtlDescriptor.get().colorAttachments, descriptor.colorStates);
+    if (!trySetVertexInput(functionName, descriptor.vertexInput, mtlDescriptor.get(), whlslDescriptor))
+        return nullptr;
 
-    END_BLOCK_OBJC_EXCEPTIONS;
+    if (!trySetColorStates(functionName, descriptor.colorStates, mtlDescriptor.get().colorAttachments, whlslDescriptor))
+        return nullptr;
+
+    if (descriptor.layout && whlslDescriptor) {
+        if (auto layout = convertLayout(*descriptor.layout))
+            whlslDescriptor->layout = WTFMove(*layout);
+        else {
+            LOG(WebGPU, "%s: Error converting GPUPipelineLayout!", functionName);
+            return nullptr;
+        }
+    }
+
+    if (!trySetFunctions(functionName, vertexStage, fragmentStage, device, mtlDescriptor.get(), whlslDescriptor))
+        return nullptr;
+
+    return mtlDescriptor;
+}
 
-    if (!didSetFunctions || !didSetInputState)
+static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const char* const functionName, const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device)
+{
+    auto mtlDescriptor = convertRenderPipelineDescriptor(functionName, descriptor, device);
+    if (!mtlDescriptor)
         return nullptr;
 
     RetainPtr<MTLRenderPipelineState> pipeline;
@@ -533,11 +572,13 @@ RefPtr<GPURenderPipeline> GPURenderPipeline::tryCreate(const GPUDevice& device,
     if (descriptor.depthStencilState && !(depthStencil = tryCreateMtlDepthStencilState(functionName, *descriptor.depthStencilState, device)))
         return nullptr;
 
+    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198387 depthStencilAttachmentDescriptor isn't implemented yet for WHLSL compiler.
+
     auto pipeline = tryCreateMtlRenderPipelineState(functionName, descriptor, device);
     if (!pipeline)
         return nullptr;
 
-    return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.inputState.indexFormat));
+    return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.vertexInput.indexFormat));
 }
 
 GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology, Optional<GPUIndexFormat> format)