| <!DOCTYPE html> |
| <html> |
| <head> |
| <script src="../../http/tests/inspector/resources/inspector-test.js"></script> |
| <script> |
| if (window.internals) |
| window.internals.settings.setWebGPUEnabled(true); |
| |
| const renderPipelineSource = ` |
| vertex float4 vertexShader(float4 position : attribute(0), float i : attribute(1)) : SV_Position { |
| return position; |
| } |
| |
| fragment float4 fragmentShader(float4 position : SV_Position) : SV_Target 0 { |
| return position; |
| } |
| `; |
| |
| let device = null; |
| let shaderModule = null; |
| |
| async function createRenderPipeline() { |
| if (!device) { |
| let adapter = await navigator.gpu.requestAdapter(); |
| device = await adapter.requestDevice(); |
| } |
| |
| if (!shaderModule) |
| shaderModule = device.createShaderModule({code: renderPipelineSource}); |
| |
| // Copied from webgpu/whlsl/whlsl.html. |
| const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; |
| const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; |
| const primitiveTopology = "triangle-strip"; |
| const rasterizationState = {frontFace: "cw", cullMode: "none"}; |
| const alphaBlend = {}; |
| const colorBlend = {}; |
| const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWrite.ALL |
| const depthStencilState = null; |
| const attribute0 = {shaderLocation: 0, format: "float4"}; |
| const attribute1 = {shaderLocation: 1, format: "float"}; |
| const input0 = {stride: 16, attributeSet: [attribute0]}; |
| const input1 = {stride: 4, attributeSet: [attribute1]}; |
| const inputs = [input0, input1]; |
| const vertexInput = {vertexBuffers: inputs}; |
| const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]}; |
| const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); |
| const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; |
| const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); |
| device.createRenderPipeline({vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}); |
| } |
| |
| function test() { |
| let suite = InspectorTest.createAsyncSuite("Canvas.updateShader.WebGPU.SharedVertexFragment"); |
| |
| async function awaitProgramCreated() { |
| InspectorTest.log("Creating render pipeline..."); |
| let evalutePromise = InspectorTest.evaluateInPage(`createRenderPipeline()`); |
| |
| if (!WI.canvasManager.canvasCollection.size) |
| await WI.canvasManager.canvasCollection.awaitEvent(WI.Collection.Event.ItemAdded); |
| |
| let canvas = Array.from(WI.canvasManager.canvasCollection)[0]; |
| InspectorTest.assert(canvas.contextType === WI.Canvas.ContextType.WebGPU, "Canvas should be WebGPU."); |
| |
| let itemAddedEvent = await canvas.shaderProgramCollection.awaitEvent(WI.Collection.Event.ItemAdded); |
| let shaderProgram = itemAddedEvent.data.item; |
| InspectorTest.assert(shaderProgram.programType === WI.ShaderProgram.ProgramType.Render, "Shader program should be a render pipeline."); |
| InspectorTest.assert(shaderProgram.sharesVertexFragmentShader, "Shader program should have a shared vertex and fragment module."); |
| |
| await evalutePromise; |
| return shaderProgram; |
| } |
| |
| suite.addTestCase({ |
| name: "Canvas.updateShader.WebGPU.SharedVertexFragment.SinglePipeline", |
| description: "Check that updating the vertex/fragment shader will also affect the fragment/vertex shader if they both use the same module.", |
| async test() { |
| let shaderProgram = await awaitProgramCreated(); |
| |
| let [originalVertexSource, originalFragmentSource] = await Promise.all([ |
| CanvasAgent.requestShaderSource(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Vertex), |
| CanvasAgent.requestShaderSource(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Fragment), |
| ]); |
| InspectorTest.expectShallowEqual(originalVertexSource, originalFragmentSource, "Vertex and Fragment shader sources should be the same."); |
| |
| InspectorTest.log("Updating vertex shader source..."); |
| await CanvasAgent.updateShader(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Vertex, "// MODIFIED VERTEX\n\n" + originalVertexSource.source); |
| |
| let [vertexSourceAfterUpdatingVertex, fragmentSourceAfterUpdatingVertex] = await Promise.all([ |
| CanvasAgent.requestShaderSource(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Vertex), |
| CanvasAgent.requestShaderSource(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Fragment), |
| ]); |
| InspectorTest.expectShallowEqual(vertexSourceAfterUpdatingVertex, fragmentSourceAfterUpdatingVertex, "Vertex and Fragment shader sources should be the same."); |
| InspectorTest.expectNotShallowEqual(vertexSourceAfterUpdatingVertex, originalVertexSource, "Vertex source should have changed."); |
| |
| InspectorTest.log("Updating fragment shader source..."); |
| await CanvasAgent.updateShader(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Fragment, "// MODIFIED FRAGMENT\n\n" + originalFragmentSource.source); |
| |
| let [vertexSourceAfterUpdatingFragment, fragmentSourceAfterUpdatingFragment] = await Promise.all([ |
| CanvasAgent.requestShaderSource(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Vertex), |
| CanvasAgent.requestShaderSource(shaderProgram.identifier, WI.ShaderProgram.ShaderType.Fragment), |
| ]); |
| InspectorTest.expectShallowEqual(vertexSourceAfterUpdatingFragment, fragmentSourceAfterUpdatingFragment, "Vertex and Fragment shader sources should be the same."); |
| InspectorTest.expectNotShallowEqual(fragmentSourceAfterUpdatingFragment, originalFragmentSource, "Fragment source should have changed."); |
| } |
| }); |
| |
| suite.addTestCase({ |
| name: "Canvas.updateShader.WebGPU.SharedVertexFragment.MultiplePipelines", |
| description: "Check that updating one pipeline won't affect any other pipelines if they share the same module.", |
| async test() { |
| let shaderProgram1 = await awaitProgramCreated(); |
| let shaderProgram2 = await awaitProgramCreated(); |
| |
| let [originalVertexSource1, originalVertexSource2] = await Promise.all([ |
| CanvasAgent.requestShaderSource(shaderProgram1.identifier, WI.ShaderProgram.ShaderType.Vertex), |
| CanvasAgent.requestShaderSource(shaderProgram2.identifier, WI.ShaderProgram.ShaderType.Vertex), |
| ]); |
| InspectorTest.expectShallowEqual(originalVertexSource1, originalVertexSource2, "Both pipelines should have the same source."); |
| |
| InspectorTest.log("Updating pipeline 1 vertex source..."); |
| await CanvasAgent.updateShader(shaderProgram1.identifier, WI.ShaderProgram.ShaderType.Vertex, "// MODIFIED VERTEX\n\n" + originalVertexSource1.source); |
| |
| let [newVertexSource1, newVertexSource2] = await Promise.all([ |
| CanvasAgent.requestShaderSource(shaderProgram1.identifier, WI.ShaderProgram.ShaderType.Vertex), |
| CanvasAgent.requestShaderSource(shaderProgram2.identifier, WI.ShaderProgram.ShaderType.Vertex), |
| ]); |
| InspectorTest.expectNotShallowEqual(originalVertexSource1, newVertexSource1, "Source of pipeline 1 should have changed."); |
| InspectorTest.expectNotShallowEqual(newVertexSource1, newVertexSource2, "Both pipelines should have different sources."); |
| } |
| }); |
| |
| suite.runTestCasesAndFinish(); |
| } |
| </script> |
| </head> |
| <body onload="runTest()"> |
| <p>WebGPU tests for Canvas.updateShader command when the vertex and fragment shaders of a render pipeline share the same module.</p> |
| </body> |
| </html> |