Web Inspector: Canvas: show WebGPU shader pipelines
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Sep 2019 22:27:20 +0000 (22:27 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Sep 2019 22:27:20 +0000 (22:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201675
<rdar://problem/55543450>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

* inspector/protocol/Canvas.json:
Add a `ProgramType` enum that conveys the type of shader program/pipeline when notifying the
frontend of a new program

Source/WebCore:

Tests: inspector/canvas/requestShaderSource-webgpu.html
       inspector/canvas/shaderProgram-add-remove-webgpu.html
       inspector/canvas/updateShader-webgpu.html

Create common base classes for `WebGPUPipeline` and `GPUPipeline` so that Web Inspector can
instrument both render and compute shader pipelines.

Refactor `InspectorShaderProgram` to support both `WebGLProgram` and `WebGPUPipeline` so
that the same object can be used for all types of shader "program"s.

Keep a copy of each shader module's source, and allow the shader module to be updated.

* Modules/webgpu/WebGPUDevice.h:
* Modules/webgpu/WebGPUDevice.cpp:
(WebCore::WebGPUDevice::WebGPUDevice):
(WebCore::WebGPUDevice::~WebGPUDevice):
(WebCore::WebGPUDevice::createShaderModule const):
(WebCore::WebGPUDevice::createRenderPipeline): Added.
(WebCore::WebGPUDevice::createComputePipeline): Added.
(WebCore::WebGPUDevice::createRenderPipeline const): Deleted.
(WebCore::WebGPUDevice::createComputePipeline const): Deleted.

* Modules/webgpu/WebGPUPipeline.h: Added.
(WebCore::WebGPUPipeline::isRenderPipeline const):
(WebCore::WebGPUPipeline::isComputePipeline const):
(WebCore::WebGPUPipeline::scriptExecutionContext const):
* Modules/webgpu/WebGPUPipeline.cpp: Added.
(WebCore::WebGPUPipeline::instancesMutex):
(WebCore::WebGPUPipeline::WebGPUPipeline):
(WebCore::WebGPUPipeline::~WebGPUPipeline):
* platform/graphics/gpu/GPUPipeline.cpp: Added.
* platform/graphics/gpu/GPUPipeline.h: Added.
(WebCore::GPUPipeline::isRenderPipeline const):
(WebCore::GPUPipeline::isComputePipeline const):

* Modules/webgpu/WebGPUComputePipeline.idl:
* Modules/webgpu/WebGPUComputePipeline.h:
(WebCore::WebGPUComputePipeline::computePipeline const): Deleted.
* Modules/webgpu/WebGPUComputePipeline.cpp:
(WebCore::WebGPUComputePipeline::create):
(WebCore::WebGPUComputePipeline::WebGPUComputePipeline):
(WebCore::WebGPUComputePipeline::recompile): Added.
* platform/graphics/gpu/GPUComputePipeline.h:
(WebCore::GPUComputePipeline::isComputePipeline): Added.
* platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
(WebCore::GPUComputePipeline::tryCreate):
(WebCore::GPUComputePipeline::GPUComputePipeline):
(WebCore::GPUComputePipeline::recompile): Added.

* Modules/webgpu/WebGPURenderPipeline.idl:
* Modules/webgpu/WebGPURenderPipeline.h:
(WebCore::WebGPURenderPipeline::renderPipeline const): Deleted.
* Modules/webgpu/WebGPURenderPipeline.cpp:
(WebCore::WebGPURenderPipeline::create):
(WebCore::WebGPURenderPipeline::WebGPURenderPipeline):
(WebCore::WebGPURenderPipeline::recompile): Added.
* platform/graphics/gpu/GPURenderPipeline.h:
(WebCore::GPURenderPipeline::isRenderPipeline): Added.
* platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
(WebCore::tryCreateMtlRenderPipelineState):
(WebCore::GPURenderPipeline::tryCreate):
(WebCore::GPURenderPipeline::GPURenderPipeline):
(WebCore::GPURenderPipeline::recompile): Added.

* Modules/webgpu/WebGPUShaderModule.h:
(WebCore::WebGPUShaderModule::source const): Added.
* Modules/webgpu/WebGPUShaderModule.cpp:
(WebCore::WebGPUShaderModule::update): Added.
* Modules/webgpu/WebGPUProgrammableStageDescriptor.h:
* platform/graphics/gpu/GPUProgrammableStageDescriptor.h:
(WebCore::GPUProgrammableStageDescriptor::GPUProgrammableStageDescriptor):

* inspector/InspectorShaderProgram.h:
* inspector/InspectorShaderProgram.cpp:
(WebCore::InspectorShaderProgram::create):
(WebCore::InspectorShaderProgram::InspectorShaderProgram):
(WebCore::InspectorShaderProgram::program const): Added.
(WebCore::InspectorShaderProgram::pipeline const): Added.
(WebCore::shaderForType): Added.
(WebCore::InspectorShaderProgram::requestShaderSource): Added.
(WebCore::InspectorShaderProgram::updateShader): Added.
(WebCore::InspectorShaderProgram::context const): Deleted.
(WebCore::InspectorShaderProgram::shaderForType): Deleted.

* inspector/agents/InspectorCanvasAgent.h:
* inspector/agents/InspectorCanvasAgent.cpp:
(WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
(WebCore::InspectorCanvasAgent::discardAgent):
(WebCore::InspectorCanvasAgent::enable):
(WebCore::InspectorCanvasAgent::disable):
(WebCore::InspectorCanvasAgent::requestShaderSource):
(WebCore::InspectorCanvasAgent::updateShader):
(WebCore::InspectorCanvasAgent::setShaderProgramDisabled):
(WebCore::InspectorCanvasAgent::setShaderProgramHighlighted):
(WebCore::InspectorCanvasAgent::frameNavigated):
(WebCore::InspectorCanvasAgent::didCreateWebGLProgram): Added.
(WebCore::InspectorCanvasAgent::willDestroyWebGLProgram): Added.
(WebCore::InspectorCanvasAgent::isWebGLProgramDisabled): Added.
(WebCore::InspectorCanvasAgent::isWebGLProgramHighlighted): Added.
(WebCore::InspectorCanvasAgent::didCreateWebGPUPipeline): Added.
(WebCore::InspectorCanvasAgent::willDestroyWebGPUPipeline): Added.
(WebCore::InspectorCanvasAgent::programDestroyedTimerFired): Added.
(WebCore::InspectorCanvasAgent::reset): Added.
(WebCore::InspectorCanvasAgent::unbindProgram):
(WebCore::InspectorCanvasAgent::findInspectorProgram):
(WebCore::InspectorCanvasAgent::didCreateProgram): Deleted.
(WebCore::InspectorCanvasAgent::willDeleteProgram): Deleted.
(WebCore::InspectorCanvasAgent::isShaderProgramDisabled): Deleted.
(WebCore::InspectorCanvasAgent::isShaderProgramHighlighted): Deleted.
(WebCore::InspectorCanvasAgent::clearCanvasData): Deleted.
* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::didCreateWebGLProgram): Added.
(WebCore::InspectorInstrumentation::willDestroyWebGLProgram): Added.
(WebCore::InspectorInstrumentation::isWebGLProgramDisabled): Added.
(WebCore::InspectorInstrumentation::isWebGLProgramHighlighted): Added.
(WebCore::InspectorInstrumentation::didCreateWebGPUPipeline): Added.
(WebCore::InspectorInstrumentation::willDestroyWebGPUPipeline): Added.
(WebCore::InspectorInstrumentation::didCreateProgram): Deleted.
(WebCore::InspectorInstrumentation::willDeleteProgram): Deleted.
(WebCore::InspectorInstrumentation::isShaderProgramDisabled): Deleted.
(WebCore::InspectorInstrumentation::isShaderProgramHighlighted): Deleted.
* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::didCreateWebGLProgramImpl): Added.
(WebCore::InspectorInstrumentation::willDestroyWebGLProgramImpl): Added.
(WebCore::InspectorInstrumentation::isWebGLProgramDisabledImpl): Added.
(WebCore::InspectorInstrumentation::isWebGLProgramHighlightedImpl): Added.
(WebCore::InspectorInstrumentation::didCreateWebGPUPipelineImpl): Added.
(WebCore::InspectorInstrumentation::willDestroyWebGPUPipelineImpl): Added.
(WebCore::InspectorInstrumentation::didCreateProgramImpl): Deleted.
(WebCore::InspectorInstrumentation::willDeleteProgramImpl): Deleted.
(WebCore::InspectorInstrumentation::isShaderProgramDisabledImpl): Deleted.
(WebCore::InspectorInstrumentation::isShaderProgramHighlightedImpl): Deleted.

* html/canvas/WebGLProgram.h:
* html/canvas/WebGLProgram.cpp:
(WebCore::WebGLProgram::WebGLProgram):
(WebCore::WebGLProgram::~WebGLProgram):
* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::InspectorScopedShaderProgramHighlight::showHightlight):
(WebCore::WebGLRenderingContextBase::createProgram):
(WebCore::WebGLRenderingContextBase::deleteProgram):
(WebCore::WebGLRenderingContextBase::drawArrays):
(WebCore::WebGLRenderingContextBase::drawElements):
Rename WebGL program instrumentation points to be less ambiguous.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:

Source/WebInspectorUI:

Show WebGPU shader pipelines ("programs") underneath each corresponding WebGPU device.

Allow editing of attached shader modules for each WebGPU shader pipeline, but don't allow
highlighting/disabling, as WebGPU pipelines don't have those capabilities/concepts yet.

* UserInterface/Protocol/CanvasObserver.js:
(WI.CanvasObserver.prototype.programCreated):
* UserInterface/Controllers/CanvasManager.js:
(WI.CanvasManager.prototype.programCreated):

* UserInterface/Models/Canvas.js:
(WI.Canvas.prototype.nextShaderProgramDisplayNumberForProgramType): Added.
(WI.Canvas.prototype.nextShaderProgramDisplayNumber): Deleted.

* UserInterface/Models/ShaderProgram.js:
(WI.ShaderProgram):
(WI.ShaderProgram.contextTypeSupportsProgramType): Added.
(WI.ShaderProgram.programTypeSupportsShaderType): Added.
(WI.ShaderProgram.prototype.get programType): Added.
(WI.ShaderProgram.prototype.get displayName):
(WI.ShaderProgram.prototype.set disabled):
(WI.ShaderProgram.prototype.requestShaderSource):
(WI.ShaderProgram.prototype.updateShader):
(WI.ShaderProgram.prototype.showHighlight):
(WI.ShaderProgram.prototype.hideHighlight):
(WI.ShaderProgram.prototype.requestVertexShaderSource): Deleted.
(WI.ShaderProgram.prototype.requestFragmentShaderSource): Deleted.
(WI.ShaderProgram.prototype.updateVertexShader): Deleted.
(WI.ShaderProgram.prototype.updateFragmentShader): Deleted.
(WI.ShaderProgram.prototype._requestShaderSource): Deleted.
(WI.ShaderProgram.prototype._updateShader): Deleted.

* UserInterface/Views/ShaderProgramContentView.js:
(WI.ShaderProgramContentView):
(WI.ShaderProgramContentView.prototype.get navigationItems): Added.
(WI.ShaderProgramContentView.prototype.shown):
(WI.ShaderProgramContentView.prototype.hidden):
(WI.ShaderProgramContentView.prototype.get saveData):
(WI.ShaderProgramContentView.prototype._refreshContent):
(WI.ShaderProgramContentView.prototype._updateShader):
(WI.ShaderProgramContentView.prototype._contentDidChange):
* UserInterface/Views/ShaderProgramContentView.css:
(.content-view.shader-program > .shader): Added.
(.content-view.shader-program > .shader.compute): Added.
(body[dir=ltr] .content-view.shader-program > .shader.vertex,): Added.
(body[dir=ltr] .content-view.shader-program > .shader.fragment,): Added.
(.content-view.shader-program > .shader + .shader): Added.
(.content-view.shader-program > .shader > header > *): Added.
(.content-view.shader-program > .shader > header > .shader-type): Added.
(@media (prefers-color-scheme: dark) .content-view.shader-program > .shader > header): Added.
(.content-view.shader-program > .text-editor.shader): Deleted.
(body[dir=ltr] .content-view.shader-program > .text-editor.shader.vertex,): Deleted.
(body[dir=ltr] .content-view.shader-program > .text-editor.shader.fragment,): Deleted.
(body[dir=ltr] .content-view.shader-program > .text-editor.shader + .text-editor.shader): Deleted.
(body[dir=rtl] .content-view.shader-program > .text-editor.shader + .text-editor.shader): Deleted.
(.content-view.shader-program > .text-editor.shader > .type-title): Deleted.
(.content-view.shader-program > .text-editor.shader > .CodeMirror): Deleted.
* UserInterface/Views/CodeMirrorAdditions.js:

* UserInterface/Views/ShaderProgramTreeElement.js:
(WI.ShaderProgramTreeElement):
(WI.ShaderProgramTreeElement.prototype.onattach):
(WI.ShaderProgramTreeElement.prototype.ondetach):
(WI.ShaderProgramTreeElement.prototype.canSelectOnMouseDown):
(WI.ShaderProgramTreeElement.prototype.populateContextMenu):

* Localizations/en.lproj/localizedStrings.js:

LayoutTests:

Split existing shader tests into WebGL and WebGPU sub-tests for different platforms.

* inspector/canvas/requestShaderSource.html:
* inspector/canvas/requestShaderSource-expected.txt:
* inspector/canvas/updateShader.html:
* inspector/canvas/updateShader-expected.txt:

* inspector/canvas/resources/shaderProgram-utilities-webgpu.js: Added.
* inspector/canvas/requestShaderSource-webgpu.html: Added.
* inspector/canvas/requestShaderSource-webgpu-expected.txt: Added.
* inspector/canvas/shaderProgram-add-remove-webgpu.html: Added.
* inspector/canvas/shaderProgram-add-remove-webgpu-expected.txt: Added.
* inspector/canvas/updateShader-webgpu-expected.txt: Added.
* inspector/canvas/updateShader-webgpu.html: Added.

* inspector/canvas/resources/shaderProgram-utilities-webgl.js: Renamed from LayoutTests/inspector/canvas/resources/shaderProgram-utilities.js.
* inspector/canvas/console-record-webgl.html:
* inspector/canvas/console-record-webgl2.html:
* inspector/canvas/recording-webgl-frameCount.html:
* inspector/canvas/recording-webgl-full.html:
* inspector/canvas/recording-webgl-memoryLimit.html:
* inspector/canvas/recording-webgl-snapshots.html:
* inspector/canvas/recording-webgl2-frameCount.html:
* inspector/canvas/recording-webgl2-full.html:
* inspector/canvas/recording-webgl2-memoryLimit.html:
* inspector/canvas/recording-webgl2-snapshots.html:
* inspector/canvas/requestShaderSource-webgl.html: Added.
* inspector/canvas/requestShaderSource-webgl-expected.txt: Added.
* inspector/canvas/setShaderProgramDisabled.html:
* inspector/canvas/setShaderProgramHighlighted.html:
* inspector/canvas/shaderProgram-add-remove-webgl.html:
* inspector/canvas/shaderProgram-add-remove-webgl2.html:
* inspector/canvas/updateShader-webgl.html: Added.
* inspector/canvas/updateShader-webgl-expected.txt: Added.

* platform/gtk/TestExpectations:
* platform/ios/TestExpectations:
* platform/mac-wk1/TestExpectations:
* platform/mac/TestExpectations:
* platform/win/TestExpectations:
* platform/wincairo/TestExpectations:
* platform/wpe/TestExpectations:

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

82 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/canvas/console-record-webgl.html
LayoutTests/inspector/canvas/console-record-webgl2.html
LayoutTests/inspector/canvas/recording-webgl-frameCount.html
LayoutTests/inspector/canvas/recording-webgl-full.html
LayoutTests/inspector/canvas/recording-webgl-memoryLimit.html
LayoutTests/inspector/canvas/recording-webgl-snapshots.html
LayoutTests/inspector/canvas/recording-webgl2-frameCount.html
LayoutTests/inspector/canvas/recording-webgl2-full.html
LayoutTests/inspector/canvas/recording-webgl2-memoryLimit.html
LayoutTests/inspector/canvas/recording-webgl2-snapshots.html
LayoutTests/inspector/canvas/requestShaderSource-expected.txt
LayoutTests/inspector/canvas/requestShaderSource-webgl-expected.txt [new file with mode: 0644]
LayoutTests/inspector/canvas/requestShaderSource-webgl.html [new file with mode: 0644]
LayoutTests/inspector/canvas/requestShaderSource-webgpu-expected.txt [new file with mode: 0644]
LayoutTests/inspector/canvas/requestShaderSource-webgpu.html [new file with mode: 0644]
LayoutTests/inspector/canvas/requestShaderSource.html
LayoutTests/inspector/canvas/resources/shaderProgram-utilities-webgl.js [moved from LayoutTests/inspector/canvas/resources/shaderProgram-utilities.js with 100% similarity]
LayoutTests/inspector/canvas/resources/shaderProgram-utilities-webgpu.js [new file with mode: 0644]
LayoutTests/inspector/canvas/setShaderProgramDisabled.html
LayoutTests/inspector/canvas/setShaderProgramHighlighted.html
LayoutTests/inspector/canvas/shaderProgram-add-remove-webgl.html
LayoutTests/inspector/canvas/shaderProgram-add-remove-webgl2.html
LayoutTests/inspector/canvas/shaderProgram-add-remove-webgpu-expected.txt [new file with mode: 0644]
LayoutTests/inspector/canvas/shaderProgram-add-remove-webgpu.html [new file with mode: 0644]
LayoutTests/inspector/canvas/updateShader-expected.txt
LayoutTests/inspector/canvas/updateShader-webgl-expected.txt [new file with mode: 0644]
LayoutTests/inspector/canvas/updateShader-webgl.html [new file with mode: 0644]
LayoutTests/inspector/canvas/updateShader-webgpu-expected.txt [new file with mode: 0644]
LayoutTests/inspector/canvas/updateShader-webgpu.html [new file with mode: 0644]
LayoutTests/inspector/canvas/updateShader.html
LayoutTests/platform/gtk/TestExpectations
LayoutTests/platform/ios/TestExpectations
LayoutTests/platform/mac-wk1/TestExpectations
LayoutTests/platform/mac/TestExpectations
LayoutTests/platform/win/TestExpectations
LayoutTests/platform/wincairo/TestExpectations
LayoutTests/platform/wpe/TestExpectations
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/Canvas.json
Source/WebCore/ChangeLog
Source/WebCore/Modules/webgpu/WebGPUComputePipeline.cpp
Source/WebCore/Modules/webgpu/WebGPUComputePipeline.h
Source/WebCore/Modules/webgpu/WebGPUComputePipeline.idl
Source/WebCore/Modules/webgpu/WebGPUDevice.cpp
Source/WebCore/Modules/webgpu/WebGPUDevice.h
Source/WebCore/Modules/webgpu/WebGPUPipeline.cpp [new file with mode: 0644]
Source/WebCore/Modules/webgpu/WebGPUPipeline.h [new file with mode: 0644]
Source/WebCore/Modules/webgpu/WebGPUProgrammableStageDescriptor.h
Source/WebCore/Modules/webgpu/WebGPURenderPipeline.cpp
Source/WebCore/Modules/webgpu/WebGPURenderPipeline.h
Source/WebCore/Modules/webgpu/WebGPURenderPipeline.idl
Source/WebCore/Modules/webgpu/WebGPUShaderModule.cpp
Source/WebCore/Modules/webgpu/WebGPUShaderModule.h
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/html/canvas/WebGLProgram.cpp
Source/WebCore/html/canvas/WebGLProgram.h
Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebCore/inspector/InspectorInstrumentation.h
Source/WebCore/inspector/InspectorShaderProgram.cpp
Source/WebCore/inspector/InspectorShaderProgram.h
Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp
Source/WebCore/inspector/agents/InspectorCanvasAgent.h
Source/WebCore/platform/graphics/gpu/GPUComputePipeline.h
Source/WebCore/platform/graphics/gpu/GPUPipeline.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/gpu/GPUPipeline.h [new file with mode: 0644]
Source/WebCore/platform/graphics/gpu/GPUProgrammableStageDescriptor.h
Source/WebCore/platform/graphics/gpu/GPURenderPipeline.h
Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js
Source/WebInspectorUI/UserInterface/Models/Canvas.js
Source/WebInspectorUI/UserInterface/Models/ShaderProgram.js
Source/WebInspectorUI/UserInterface/Protocol/CanvasObserver.js
Source/WebInspectorUI/UserInterface/Views/CodeMirrorAdditions.js
Source/WebInspectorUI/UserInterface/Views/ShaderProgramContentView.css
Source/WebInspectorUI/UserInterface/Views/ShaderProgramContentView.js
Source/WebInspectorUI/UserInterface/Views/ShaderProgramTreeElement.js

index aada96c..f8c5154 100644 (file)
@@ -1,3 +1,54 @@
+2019-09-23  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Canvas: show WebGPU shader pipelines
+        https://bugs.webkit.org/show_bug.cgi?id=201675
+        <rdar://problem/55543450>
+
+        Reviewed by Joseph Pecoraro.
+
+        Split existing shader tests into WebGL and WebGPU sub-tests for different platforms.
+
+        * inspector/canvas/requestShaderSource.html:
+        * inspector/canvas/requestShaderSource-expected.txt:
+        * inspector/canvas/updateShader.html:
+        * inspector/canvas/updateShader-expected.txt:
+
+        * inspector/canvas/resources/shaderProgram-utilities-webgpu.js: Added.
+        * inspector/canvas/requestShaderSource-webgpu.html: Added.
+        * inspector/canvas/requestShaderSource-webgpu-expected.txt: Added.
+        * inspector/canvas/shaderProgram-add-remove-webgpu.html: Added.
+        * inspector/canvas/shaderProgram-add-remove-webgpu-expected.txt: Added.
+        * inspector/canvas/updateShader-webgpu-expected.txt: Added.
+        * inspector/canvas/updateShader-webgpu.html: Added.
+
+        * inspector/canvas/resources/shaderProgram-utilities-webgl.js: Renamed from LayoutTests/inspector/canvas/resources/shaderProgram-utilities.js.
+        * inspector/canvas/console-record-webgl.html:
+        * inspector/canvas/console-record-webgl2.html:
+        * inspector/canvas/recording-webgl-frameCount.html:
+        * inspector/canvas/recording-webgl-full.html:
+        * inspector/canvas/recording-webgl-memoryLimit.html:
+        * inspector/canvas/recording-webgl-snapshots.html:
+        * inspector/canvas/recording-webgl2-frameCount.html:
+        * inspector/canvas/recording-webgl2-full.html:
+        * inspector/canvas/recording-webgl2-memoryLimit.html:
+        * inspector/canvas/recording-webgl2-snapshots.html:
+        * inspector/canvas/requestShaderSource-webgl.html: Added.
+        * inspector/canvas/requestShaderSource-webgl-expected.txt: Added.
+        * inspector/canvas/setShaderProgramDisabled.html:
+        * inspector/canvas/setShaderProgramHighlighted.html:
+        * inspector/canvas/shaderProgram-add-remove-webgl.html:
+        * inspector/canvas/shaderProgram-add-remove-webgl2.html:
+        * inspector/canvas/updateShader-webgl.html: Added.
+        * inspector/canvas/updateShader-webgl-expected.txt: Added.
+
+        * platform/gtk/TestExpectations:
+        * platform/ios/TestExpectations:
+        * platform/mac-wk1/TestExpectations:
+        * platform/mac/TestExpectations:
+        * platform/win/TestExpectations:
+        * platform/wincairo/TestExpectations:
+        * platform/wpe/TestExpectations:
+
 2019-09-23  Daniel Bates  <dabates@apple.com>
 
         Improve CSP inheritance semantics
index 32f559b..e983f19 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index 13e1a01..3763709 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index f240276..8d9a6dc 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index c74361b..76133ee 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index 64bff31..8955817 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index b70c7c5..3d5588d 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec3 position;
     void main(void) {
index 4ca7c1d..50fbede 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index ba68e17..1874ea9 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index 0174b0a..8604df6 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec4 test;
     void main(void) {
index 82f27c9..9e9a4a8 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
 <script src="resources/recording-utilities.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec3 position;
     void main(void) {
index 64bcdf3..f92f495 100644 (file)
@@ -1,28 +1,8 @@
-Test compilation of shaders after being attached to a program, with and without syntax errors.
+Common tests for Canvas.requestShaderSource command.
 
 
-== Running test suite: Canvas.getShaderSource
--- Running test case: Canvas.requestShaderSource.vertexShader
-
-    void main(void) {
-        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-    }
-
-
--- Running test case: Canvas.requestShaderSource.fragmentShader
-
-    precision mediump float;
-
-    void main(void) {
-        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
-    }
-
-
--- Running test case: Canvas.requestShaderSource.invalidProgramId
+== Running test suite: Canvas.requestShaderSource
+-- Running test case: Canvas.requestShaderSource.ProgramId.Invalid
 PASS: Should produce an error.
 Error: Missing program for given programId
 
--- Running test case: Canvas.requestShaderSource.invalidShaderType
-PASS: Should produce an error.
-Error: Missing shader for given shaderType
-
diff --git a/LayoutTests/inspector/canvas/requestShaderSource-webgl-expected.txt b/LayoutTests/inspector/canvas/requestShaderSource-webgl-expected.txt
new file mode 100644 (file)
index 0000000..7523af4
--- /dev/null
@@ -0,0 +1,24 @@
+WebGL tests for Canvas.requestShaderSource command.
+
+
+== Running test suite: Canvas.requestShaderSource.WebGL
+-- Running test case: Canvas.requestShaderSource.WebGL.Vertex
+
+    void main(void) {
+        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+    }
+
+
+-- Running test case: Canvas.requestShaderSource.WebGL.Fragment
+
+    precision mediump float;
+
+    void main(void) {
+        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+    }
+
+
+-- Running test case: Canvas.requestShaderSource.WebGL.ShaderType.Invalid
+PASS: Should produce an error.
+Error: Unknown shaderType: INVALID_SHADER_TYPE
+
diff --git a/LayoutTests/inspector/canvas/requestShaderSource-webgl.html b/LayoutTests/inspector/canvas/requestShaderSource-webgl.html
new file mode 100644 (file)
index 0000000..0b2b750
--- /dev/null
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
+<script id="vertex-shader" type="x-shader/x-vertex">
+    void main(void) {
+        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+    }
+</script>
+<script id="fragment-shader" type="x-shader/x-fragment">
+    precision mediump float;
+
+    void main(void) {
+        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+    }
+</script>
+<script>
+function load() {
+    createProgram("webgl");
+    linkProgram("vertex-shader", "fragment-shader");
+
+    runTest();
+}
+
+function test() {
+    let suite = InspectorTest.createAsyncSuite("Canvas.requestShaderSource.WebGL");
+
+    suite.addTestCase({
+        name: "Canvas.requestShaderSource.WebGL.Vertex",
+        description: "Tests requesting the source code of a program's vertex shader.",
+        test(resolve, reject) {
+            let shaderProgram = WI.canvasManager.shaderPrograms[0];
+            if (!shaderProgram) {
+                reject("Missing shader program")
+                return;
+            }
+
+            CanvasAgent.requestShaderSource(shaderProgram.identifier, CanvasAgent.ShaderType.Vertex)
+            .then(({source}) => InspectorTest.log(source))
+            .then(resolve, reject);
+        }
+    });
+
+    suite.addTestCase({
+        name: "Canvas.requestShaderSource.WebGL.Fragment",
+        description: "Tests requesting the source code of a program's fragment shader.",
+        test(resolve, reject) {
+            let shaderProgram = WI.canvasManager.shaderPrograms[0];
+            if (!shaderProgram) {
+                reject("Missing shader program")
+                return;
+            }
+
+            CanvasAgent.requestShaderSource(shaderProgram.identifier, CanvasAgent.ShaderType.Fragment)
+            .then(({source}) => InspectorTest.log(source))
+            .then(resolve, reject);
+        }
+    });
+
+    suite.addTestCase({
+        name: "Canvas.requestShaderSource.WebGL.ShaderType.Invalid",
+        description: "Invalid shader types should cause an error.",
+        test(resolve, reject) {
+            let shaderProgram = WI.canvasManager.shaderPrograms[0];
+            if (!shaderProgram) {
+                reject("Missing shader program")
+                return;
+            }
+
+            const shaderType = "INVALID_SHADER_TYPE";
+            CanvasAgent.requestShaderSource(shaderProgram.identifier, shaderType, (error) => {
+                InspectorTest.expectThat(error, "Should produce an error.");
+                InspectorTest.log("Error: " + error);
+                resolve();
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="load()">
+<p>WebGL tests for Canvas.requestShaderSource command.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/canvas/requestShaderSource-webgpu-expected.txt b/LayoutTests/inspector/canvas/requestShaderSource-webgpu-expected.txt
new file mode 100644 (file)
index 0000000..daa0e4f
--- /dev/null
@@ -0,0 +1,46 @@
+WebGPU tests for Canvas.requestShaderSource command.
+
+
+== Running test suite: Canvas.requestShaderSource.WebGPU
+-- Running test case: Canvas.requestShaderSource.WebGPU.Program.compute.Shader.compute
+
+[numthreads(2, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0;
+}
+
+
+-- Running test case: Canvas.requestShaderSource.WebGPU.Program.compute.Shader.fragment
+PASS: Should produce an exception.
+Error: Missing shader of given shaderType for given programId
+
+-- Running test case: Canvas.requestShaderSource.WebGPU.Program.compute.Shader.vertex
+PASS: Should produce an exception.
+Error: Missing shader of given shaderType for given programId
+
+-- Running test case: Canvas.requestShaderSource.WebGPU.Program.render.Shader.compute
+PASS: Should produce an exception.
+Error: Missing shader of given shaderType for given programId
+
+-- Running test case: Canvas.requestShaderSource.WebGPU.Program.render.Shader.fragment
+
+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;
+}
+
+
+-- Running test case: Canvas.requestShaderSource.WebGPU.Program.render.Shader.vertex
+
+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;
+}
+
+
diff --git a/LayoutTests/inspector/canvas/requestShaderSource-webgpu.html b/LayoutTests/inspector/canvas/requestShaderSource-webgpu.html
new file mode 100644 (file)
index 0000000..32be60e
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="resources/shaderProgram-utilities-webgpu.js"></script>
+<script>
+function test() {
+    let suite = InspectorTest.createAsyncSuite("Canvas.requestShaderSource.WebGPU");
+
+    for (let programType of Object.values(WI.ShaderProgram.ProgramType)) {
+        for (let shaderType of Object.values(WI.ShaderProgram.ShaderType)) {
+            suite.addTestCase({
+                name: `Canvas.requestShaderSource.WebGPU.Program.${programType}.Shader.${shaderType}`,
+                async test() {
+                    let shaderProgram = InspectorTest.ShaderProgram.programForType(programType);
+                    if (!shaderProgram)
+                        throw "Missing shader program";
+
+                    let logShader = async () => {
+                        let {source} = await CanvasAgent.requestShaderSource(shaderProgram.identifier, shaderType);
+                        InspectorTest.log(source);
+                    };
+
+                    let isComputeProgram = programType === WI.ShaderProgram.ProgramType.Compute;
+                    let isComputeShader = shaderType === WI.ShaderProgram.ShaderType.Compute;
+                    if (isComputeProgram !== isComputeShader)
+                        await InspectorTest.expectException(logShader);
+                    else
+                        await logShader()
+                }
+            });
+        }
+    }
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="load()">
+<p>WebGPU tests for Canvas.requestShaderSource command.</p>
+</body>
+</html>
index a689c16..91e60ea 100644 (file)
@@ -2,64 +2,12 @@
 <html>
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
-<script id="vertex-shader" type="x-shader/x-vertex">
-    void main(void) {
-        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-    }
-</script>
-<script id="fragment-shader" type="x-shader/x-fragment">
-    precision mediump float;
-
-    void main(void) {
-        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
-    }
-</script>
 <script>
-function load() {
-    createProgram("webgl");
-    linkProgram("vertex-shader", "fragment-shader");
-
-    runTest();
-}
-
 function test() {
-    let suite = InspectorTest.createAsyncSuite("Canvas.getShaderSource");
+    let suite = InspectorTest.createAsyncSuite("Canvas.requestShaderSource");
 
     suite.addTestCase({
-        name: "Canvas.requestShaderSource.vertexShader",
-        description: "Tests requesting the source code of a program's vertex shader.",
-        test(resolve, reject) {
-            let shaderProgram = WI.canvasManager.shaderPrograms[0];
-            if (!shaderProgram) {
-                reject("Missing shader program")
-                return;
-            }
-
-            CanvasAgent.requestShaderSource(shaderProgram.identifier, CanvasAgent.ShaderType.Vertex)
-            .then(({content}) => InspectorTest.log(content))
-            .then(resolve, reject);
-        }
-    });
-
-    suite.addTestCase({
-        name: "Canvas.requestShaderSource.fragmentShader",
-        description: "Tests requesting the source code of a program's fragment shader.",
-        test(resolve, reject) {
-            let shaderProgram = WI.canvasManager.shaderPrograms[0];
-            if (!shaderProgram) {
-                reject("Missing shader program")
-                return;
-            }
-
-            CanvasAgent.requestShaderSource(shaderProgram.identifier, CanvasAgent.ShaderType.Fragment)
-            .then(({content}) => InspectorTest.log(content))
-            .then(resolve, reject);
-        }
-    });
-
-    suite.addTestCase({
-        name: "Canvas.requestShaderSource.invalidProgramId",
+        name: "Canvas.requestShaderSource.ProgramId.Invalid",
         description: "Invalid program identifiers should cause an error.",
         test(resolve, reject) {
             const programId = "INVALID_PROGRAM_ID";
@@ -72,30 +20,11 @@ function test() {
         }
     });
 
-    suite.addTestCase({
-        name: "Canvas.requestShaderSource.invalidShaderType",
-        description: "Invalid shader types should cause an error.",
-        test(resolve, reject) {
-            let shaderProgram = WI.canvasManager.shaderPrograms[0];
-            if (!shaderProgram) {
-                reject("Missing shader program")
-                return;
-            }
-
-            const shaderType = "INVALID_SHADER_TYPE";
-            CanvasAgent.requestShaderSource(shaderProgram.identifier, shaderType, (error) => {
-                InspectorTest.expectThat(error, "Should produce an error.");
-                InspectorTest.log("Error: " + error);
-                resolve();
-            });
-        }
-    });
-
     suite.runTestCasesAndFinish();
 }
 </script>
 </head>
-<body onload="load()">
-    <p>Test compilation of shaders after being attached to a program, with and without syntax errors.</p>
+<body onload="runTest()">
+<p>Common tests for Canvas.requestShaderSource command.</p>
 </body>
 </html>
diff --git a/LayoutTests/inspector/canvas/resources/shaderProgram-utilities-webgpu.js b/LayoutTests/inspector/canvas/resources/shaderProgram-utilities-webgpu.js
new file mode 100644 (file)
index 0000000..fe48d8f
--- /dev/null
@@ -0,0 +1,100 @@
+if (window.internals)
+    window.internals.settings.setWebGPUEnabled(true);
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+const computePipelineSource = `
+[numthreads(2, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0;
+}
+`;
+
+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;
+
+async function createComputePipeline(code = computePipelineSource) {
+    // Copied from webgpu/whlsl/compute.html.
+    const shaderModule = device.createShaderModule({code});
+    const computeStage = {module: shaderModule, entryPoint: "computeShader"};
+    const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]};
+    const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+    const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+    device.createComputePipeline({computeStage, layout: pipelineLayout});
+}
+
+async function createRenderPipeline(code = renderPipelineSource) {
+    // Copied from webgpu/whlsl/whlsl.html.
+    const shaderModule = device.createShaderModule({code});
+    const vertexStage = {module: shaderModule, entryPoint: "vertexShader"};
+    const fragmentShaderModule = device.createShaderModule({code});
+    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 deleteDevice() {
+    device = null;
+    // Force GC to make sure the device is destroyed, otherwise the frontend
+    // does not receive WI.CanvasManager.Event.CanvasRemoved events.
+    setTimeout(() => { GCController.collect(); }, 0);
+}
+
+async function load() {
+    let adapter = await navigator.gpu.requestAdapter();
+    device = await adapter.requestDevice();
+
+    await Promise.all([
+        createComputePipeline(),
+        createRenderPipeline(),
+    ]);
+
+    if (window.beforeTest)
+        await beforeTest();
+
+    runTest();
+}
+
+TestPage.registerInitializer(() => {
+    if (!InspectorTest.ShaderProgram)
+        InspectorTest.ShaderProgram = {};
+
+    InspectorTest.ShaderProgram.programForType = function(programType) {
+        let result = null;
+        for (let shaderProgram of WI.canvasManager.shaderPrograms) {
+            if (shaderProgram.programType === programType) {
+                InspectorTest.assert(!result);
+                result = shaderProgram;
+            }
+        }
+        return result;
+    };
+});
index 657a3ab..d39ec30 100644 (file)
@@ -2,7 +2,7 @@
 <html>
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec3 position;
     void main(void) {
index d4089c3..8a7943d 100644 (file)
@@ -2,7 +2,7 @@
 <html>
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script id="vertex-shader" type="x-shader/x-vertex">
     attribute vec3 position;
     void main(void) {
index 2ce79f2..3c6311d 100644 (file)
@@ -2,7 +2,7 @@
 <html>
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script>
 function test() {
     let suite = initializeTestSuite("webgl");
index 263ffca..92fa306 100644 (file)
@@ -2,7 +2,7 @@
 <html>
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
 <script>
 if (window.internals)
     internals.settings.setWebGL2Enabled(true);
diff --git a/LayoutTests/inspector/canvas/shaderProgram-add-remove-webgpu-expected.txt b/LayoutTests/inspector/canvas/shaderProgram-add-remove-webgpu-expected.txt
new file mode 100644 (file)
index 0000000..c68d1fb
--- /dev/null
@@ -0,0 +1,28 @@
+CONSOLE MESSAGE: GPUDevice.createComputePipeline(): WHLSL compile error: Cannot lex: Cannot consume token
+CONSOLE MESSAGE: GPUDevice.createRenderPipeline(): WHLSL compile error: Cannot lex: Cannot consume token
+CONSOLE MESSAGE: GPUDevice.createComputePipeline(): WHLSL compile error: Cannot lex: Cannot consume token
+CONSOLE MESSAGE: GPUDevice.createRenderPipeline(): WHLSL compile error: Cannot lex: Cannot consume token
+Test that CanvasManager tracks creation and destruction of WebGPU shader programs.
+
+
+== Running test suite: Canvas.ShaderProgram.WebGPU
+-- Running test case: Canvas.ShaderProgram.WebGPU.Existing
+PASS: Added "compute" ShaderProgram.
+PASS: Added "render" ShaderProgram.
+PASS: There should be two ShaderProgram.
+
+-- Running test case: Canvas.ShaderProgram.WebGPU.Added.Compute.Valid
+PASS: Added "compute" ShaderProgram.
+
+-- Running test case: Canvas.ShaderProgram.WebGPU.Added.Compute.Invalid
+PASS: Should not create a ShaderProgram for an invalid descriptor.
+
+-- Running test case: Canvas.ShaderProgram.WebGPU.Added.Render.Valid
+PASS: Added "render" ShaderProgram.
+
+-- Running test case: Canvas.ShaderProgram.WebGPU.Added.Render.Invalid
+PASS: Should not create a ShaderProgram for an invalid descriptor.
+
+-- Running test case: Canvas.ShaderProgram.WebGPU.ParentDeviceRemoved
+PASS: Removed ShaderProgram before Canvas.
+
diff --git a/LayoutTests/inspector/canvas/shaderProgram-add-remove-webgpu.html b/LayoutTests/inspector/canvas/shaderProgram-add-remove-webgpu.html
new file mode 100644 (file)
index 0000000..d40fab7
--- /dev/null
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="resources/shaderProgram-utilities-webgpu.js"></script>
+<script>
+window.beforeTest = async function() {
+    await Promise.all([
+        createComputePipeline("INVALID"),
+        createRenderPipeline("INVALID"),
+    ]);
+};
+
+function test() {
+    let suite = InspectorTest.createAsyncSuite(`Canvas.ShaderProgram.WebGPU`);
+
+    let canvas = WI.canvasManager.canvases[0];
+    InspectorTest.assert(canvas, "There should be a canvas.");
+    InspectorTest.assert(WI.canvasManager.canvases.length === 1, "There should only be one canvas.");
+    InspectorTest.assert(canvas.contextType === WI.Canvas.ContextType.WebGPU, "Canvas should be WebGPU.");
+
+    async function awaitProgramAdded(programType) {
+        return new Promise((resolve, reject) => {
+            let listenerItemAdded = canvas.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemAdded, (event) => {
+                let program = event.data.item;
+                if (program.programType !== programType)
+                    return;
+
+                InspectorTest.expectThat(program instanceof WI.ShaderProgram, `Added "${programType}" ShaderProgram.`);
+                InspectorTest.assert(program.canvas === canvas, "ShaderProgram should be for the known Canvas.");
+
+                resolve(program);
+            });
+        });
+    }
+
+    suite.addTestCase({
+        name: "Canvas.ShaderProgram.WebGPU.Existing",
+        description: "Check that ShaderProgramAdded is sent for a program created before CanvasAgent is enabled.",
+        async test() {
+            async function checkExists(programType) {
+                if (InspectorTest.ShaderProgram.programForType(programType)) {
+                    InspectorTest.pass(`Added "${programType}" ShaderProgram.`);
+                    return;
+                }
+
+                await awaitProgramAdded(programType);
+            }
+
+            await Promise.all([
+                checkExists(WI.ShaderProgram.ProgramType.Compute),
+                checkExists(WI.ShaderProgram.ProgramType.Render),
+            ]);
+
+            InspectorTest.expectEqual(canvas.shaderProgramCollection.size, 2, "There should be two ShaderProgram.");
+        }
+    });
+
+    suite.addTestCase({
+        name: "Canvas.ShaderProgram.WebGPU.Added.Compute.Valid",
+        description: "Check that added/removed events are sent.",
+        async test() {
+            await Promise.all([
+                awaitProgramAdded(WI.ShaderProgram.ProgramType.Compute),
+                InspectorTest.evaluateInPage(`createComputePipeline()`),
+            ]);
+        }
+    });
+
+    suite.addTestCase({
+        name: "Canvas.ShaderProgram.WebGPU.Added.Compute.Invalid",
+        description: "Check that added/removed events are sent.",
+        async test() {
+            let shaderProgramAdded = false;
+
+            let listener = canvas.shaderProgramCollection.singleFireEventListener(WI.Collection.Event.ItemAdded, (event) => {
+                shaderProgramAdded = true;
+            });
+
+            await InspectorTest.evaluateInPage(`createComputePipeline("INVALID")`);
+
+            canvas.shaderProgramCollection.removeEventListener(WI.Collection.Event.ItemAdded, listener);
+            InspectorTest.expectFalse(shaderProgramAdded, "Should not create a ShaderProgram for an invalid descriptor.");
+        }
+    });
+
+    suite.addTestCase({
+        name: "Canvas.ShaderProgram.WebGPU.Added.Render.Valid",
+        description: "Check that added/removed events are sent.",
+        async test() {
+            await Promise.all([
+                awaitProgramAdded(WI.ShaderProgram.ProgramType.Render),
+                InspectorTest.evaluateInPage(`createRenderPipeline()`),
+            ]);
+        }
+    });
+
+    suite.addTestCase({
+        name: "Canvas.ShaderProgram.WebGPU.Added.Render.Invalid",
+        description: "Check that added/removed events are sent.",
+        async test() {
+            let shaderProgramAdded = false;
+
+            let listener = canvas.shaderProgramCollection.singleFireEventListener(WI.Collection.Event.ItemAdded, (event) => {
+                shaderProgramAdded = true;
+            });
+
+            await InspectorTest.evaluateInPage(`createRenderPipeline("INVALID")`);
+
+            canvas.shaderProgramCollection.removeEventListener(WI.Collection.Event.ItemAdded, listener);
+            InspectorTest.expectFalse(shaderProgramAdded, "Should not create a ShaderProgram for an invalid descriptor.");
+        }
+    });
+
+    suite.addTestCase({
+        name: "Canvas.ShaderProgram.WebGPU.ParentDeviceRemoved",
+        description: "Check that the ShaderProgram is removed before it's parent Canvas.",
+        test(resolve, reject) {
+            let canvasRemoved = false;
+
+            WI.canvasManager.singleFireEventListener(WI.CanvasManager.Event.CanvasRemoved, (event) => {
+                canvasRemoved = true;
+            });
+
+            let shaderProgramCount = canvas.shaderProgramCollection.size;
+            let listenerItemRemoved = canvas.shaderProgramCollection.addEventListener(WI.Collection.Event.ItemRemoved, (event) => {
+                if (--shaderProgramCount)
+                    return;
+
+                canvas.shaderProgramCollection.removeEventListener(WI.Collection.Event.ItemRemoved, listenerItemRemoved);
+                InspectorTest.expectFalse(canvasRemoved, "Removed ShaderProgram before Canvas.");
+                resolve();
+            });
+
+            InspectorTest.evaluateInPage(`deleteDevice()`);
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="load()">
+    <p>Test that CanvasManager tracks creation and destruction of WebGPU shader programs.</p>
+</body>
+</html>
index 8f3fee9..ce37e8e 100644 (file)
@@ -1,38 +1,8 @@
-CONSOLE MESSAGE: WebGL: ERROR: 0:1: 'INVALID' : syntax error
-CONSOLE MESSAGE: WebGL: ERROR: 0:1: 'INVALID' : syntax error
-Test compilation of shaders after being attached to a program, with and without syntax errors.
+Common tests for Canvas.updateShader command.
 
 
 == Running test suite: Canvas.updateShader
--- Running test case: Canvas.updateShader.vertexShaderValid
-
-    void main(void) {
-        gl_Position = vec4(1, 2, 3, 4);
-    }
-
-
--- Running test case: Canvas.updateShader.fragmentShaderValid
-
-    precision mediump float;
-
-    void main(void) {
-        gl_FragColor = vec4(0.1, 0.2, 0.3, 0.4);
-    }
-
-
--- Running test case: Canvas.updateShader.invalidProgramId
+-- Running test case: Canvas.updateShader.ProgramId.Invalid
 PASS: Should produce an error.
 Error: Missing program for given programId
 
--- Running test case: Canvas.updateShader.invalidShaderType
-PASS: Should produce an error.
-Error: Missing shader for given shaderType
-
--- Running test case: Canvas.updateShader.invalidVertexShaderSource
-PASS: Should produce error.
-Error: Failed to update shader
-
--- Running test case: Canvas.updateShader.invalidFragmentShaderSource
-PASS: Should produce error.
-Error: Failed to update shader
-
diff --git a/LayoutTests/inspector/canvas/updateShader-webgl-expected.txt b/LayoutTests/inspector/canvas/updateShader-webgl-expected.txt
new file mode 100644 (file)
index 0000000..2bbba72
--- /dev/null
@@ -0,0 +1,34 @@
+CONSOLE MESSAGE: WebGL: ERROR: 0:1: 'INVALID' : syntax error
+CONSOLE MESSAGE: WebGL: ERROR: 0:1: 'INVALID' : syntax error
+WebGL tests for Canvas.updateShader command.
+
+
+== Running test suite: Canvas.updateShader.WebGL
+-- Running test case: Canvas.updateShader.WebGL.Vertex.Valid
+
+    void main(void) {
+        gl_Position = vec4(1, 2, 3, 4);
+    }
+
+
+-- Running test case: Canvas.updateShader.WebGL.Fragment.Valid
+
+    precision mediump float;
+
+    void main(void) {
+        gl_FragColor = vec4(0.1, 0.2, 0.3, 0.4);
+    }
+
+
+-- Running test case: Canvas.updateShader.WebGL.Vertex.Invalid
+PASS: Should produce error.
+Error: Failed to update shader of given shaderType for given programId
+
+-- Running test case: Canvas.updateShader.WebGL.Fragment.Invalid
+PASS: Should produce error.
+Error: Failed to update shader of given shaderType for given programId
+
+-- Running test case: Canvas.updateShader.WebGL.ShaderType.Invalid
+PASS: Should produce an error.
+Error: Unknown shaderType: INVALID_SHADER_TYPE
+
diff --git a/LayoutTests/inspector/canvas/updateShader-webgl.html b/LayoutTests/inspector/canvas/updateShader-webgl.html
new file mode 100644 (file)
index 0000000..fd578e4
--- /dev/null
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="resources/shaderProgram-utilities-webgl.js"></script>
+<script id="vertex-shader" type="x-shader/x-vertex">
+    void main(void) {
+        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+    }
+</script>
+<script id="fragment-shader" type="x-shader/x-fragment">
+    precision mediump float;
+
+    void main(void) {
+        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+    }
+</script>
+<script>
+function load() {
+    createProgram("webgl");
+    linkProgram("vertex-shader", "fragment-shader");
+
+    runTest();
+}
+
+function test() {
+    let suite = InspectorTest.createAsyncSuite("Canvas.updateShader.WebGL");
+
+    function validSourceTest({name, shaderType, source}) {
+        suite.addTestCase({
+            name,
+            test(resolve, reject) {
+                let shaderProgram = WI.canvasManager.shaderPrograms[0];
+                if (!shaderProgram) {
+                    reject("Missing shader program")
+                    return;
+                }
+
+                let programId = shaderProgram.identifier;
+
+                CanvasAgent.updateShader(programId, shaderType, source)
+                .then(() => CanvasAgent.requestShaderSource(programId, shaderType))
+                .then(({source}) => InspectorTest.log(source))
+                .then(resolve, reject);
+            }
+        });
+    }
+
+    validSourceTest({
+        name: "Canvas.updateShader.WebGL.Vertex.Valid",
+        shaderType: CanvasAgent.ShaderType.Vertex,
+        source: `
+    void main(void) {
+        gl_Position = vec4(1, 2, 3, 4);
+    }
+`,
+    });
+
+    validSourceTest({
+        name: "Canvas.updateShader.WebGL.Fragment.Valid",
+        shaderType: CanvasAgent.ShaderType.Fragment,
+        source: `
+    precision mediump float;
+
+    void main(void) {
+        gl_FragColor = vec4(0.1, 0.2, 0.3, 0.4);
+    }
+`,
+    });
+
+    function invalidSourceTest({name, shaderType, source}) {
+        suite.addTestCase({
+            name,
+            test(resolve, reject) {
+                let shaderProgram = WI.canvasManager.shaderPrograms[0];
+                if (!shaderProgram) {
+                    reject("Missing shader program")
+                    return;
+                }
+
+                CanvasAgent.updateShader(shaderProgram.identifier, shaderType, source, (error) => {
+                    InspectorTest.expectThat(error, "Should produce error.");
+                    InspectorTest.log("Error: " + error);
+                    resolve();
+                });
+            }
+        });
+    }
+
+    invalidSourceTest({
+        name: "Canvas.updateShader.WebGL.Vertex.Invalid",
+        shaderType: CanvasAgent.ShaderType.Vertex,
+        source: "INVALID",
+    });
+
+    invalidSourceTest({
+        name: "Canvas.updateShader.WebGL.Fragment.Invalid",
+        shaderType: CanvasAgent.ShaderType.Fragment,
+        source: "INVALID",
+    });
+
+    suite.addTestCase({
+        name: "Canvas.updateShader.WebGL.ShaderType.Invalid",
+        description: "Invalid shader types should cause an error.",
+        test(resolve, reject) {
+            let shaderProgram = WI.canvasManager.shaderPrograms[0];
+            if (!shaderProgram) {
+                reject("Missing shader program")
+                return;
+            }
+
+            const shaderType = "INVALID_SHADER_TYPE";
+            const source = "INVALID_SOURCE";
+            CanvasAgent.updateShader(shaderProgram.identifier, shaderType, source, (error) => {
+                InspectorTest.expectThat(error, "Should produce an error.");
+                InspectorTest.log("Error: " + error);
+                resolve();
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="load()">
+<p>WebGL tests for Canvas.updateShader command.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/canvas/updateShader-webgpu-expected.txt b/LayoutTests/inspector/canvas/updateShader-webgpu-expected.txt
new file mode 100644 (file)
index 0000000..bbed372
--- /dev/null
@@ -0,0 +1,28 @@
+WebGPU tests for Canvas.updateShader command.
+
+
+== Running test suite: Canvas.updateShader.WebGPU
+-- Running test case: Canvas.updateShader.WebGPU.Compute.Valid
+PASS: Source should have changed.
+
+-- Running test case: Canvas.updateShader.WebGPU.Compute.Invalid
+PASS: Should produce an exception.
+Error: Failed to update shader of given shaderType for given programId
+PASS: Source should have changed.
+
+-- Running test case: Canvas.updateShader.WebGPU.Vertex.Valid
+PASS: Source should have changed.
+
+-- Running test case: Canvas.updateShader.WebGPU.Vertex.Invalid
+PASS: Should produce an exception.
+Error: Failed to update shader of given shaderType for given programId
+PASS: Source should have changed.
+
+-- Running test case: Canvas.updateShader.WebGPU.Fragment.Valid
+PASS: Source should have changed.
+
+-- Running test case: Canvas.updateShader.WebGPU.Fragment.Invalid
+PASS: Should produce an exception.
+Error: Failed to update shader of given shaderType for given programId
+PASS: Source should have changed.
+
diff --git a/LayoutTests/inspector/canvas/updateShader-webgpu.html b/LayoutTests/inspector/canvas/updateShader-webgpu.html
new file mode 100644 (file)
index 0000000..93c0e86
--- /dev/null
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="resources/shaderProgram-utilities-webgpu.js"></script>
+<script>
+function test() {
+    let suite = InspectorTest.createAsyncSuite("Canvas.updateShader.WebGPU");
+
+    function test({name, programType, shaderType, source, shouldThrow}) {
+        suite.addTestCase({
+            name,
+            async test() {
+                let shaderProgram = InspectorTest.ShaderProgram.programForType(programType);
+                if (!shaderProgram)
+                    throw "Missing shader program";
+
+                let originalSource = await CanvasAgent.requestShaderSource(shaderProgram.identifier, shaderType);
+
+                if (shouldThrow) {
+                    await InspectorTest.expectException(async () => {
+                        await CanvasAgent.updateShader(shaderProgram.identifier, shaderType, source);
+                    });
+                } else
+                    await CanvasAgent.updateShader(shaderProgram.identifier, shaderType, source);
+
+                let newSource = await CanvasAgent.requestShaderSource(shaderProgram.identifier, shaderType);
+
+                InspectorTest.expectNotShallowEqual(originalSource, newSource, "Source should have changed.");
+            }
+        });
+    }
+
+    test({
+        name: "Canvas.updateShader.WebGPU.Compute.Valid",
+        programType: WI.ShaderProgram.ProgramType.Compute,
+        shaderType: WI.ShaderProgram.ShaderType.Compute,
+        source: `// CHANGED COMPUTE
+[numthreads(2, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0;
+}
+`,
+    });
+
+    test({
+        name: "Canvas.updateShader.WebGPU.Compute.Invalid",
+        programType: WI.ShaderProgram.ProgramType.Compute,
+        shaderType: WI.ShaderProgram.ShaderType.Compute,
+        source: "INVALID",
+        shouldThrow: true,
+    });
+
+    test({
+        name: "Canvas.updateShader.WebGPU.Vertex.Valid",
+        programType: WI.ShaderProgram.ProgramType.Render,
+        shaderType: WI.ShaderProgram.ShaderType.Vertex,
+        source: `// CHANGED VERTEX
+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;
+}
+`,
+    });
+
+    test({
+        name: "Canvas.updateShader.WebGPU.Vertex.Invalid",
+        programType: WI.ShaderProgram.ProgramType.Render,
+        shaderType: WI.ShaderProgram.ShaderType.Vertex,
+        source: "INVALID",
+        shouldThrow: true,
+    });
+
+    test({
+        name: "Canvas.updateShader.WebGPU.Fragment.Valid",
+        programType: WI.ShaderProgram.ProgramType.Render,
+        shaderType: WI.ShaderProgram.ShaderType.Fragment,
+        source: `// CHANGED FRAGMENT
+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;
+}
+`,
+    });
+
+    test({
+        name: "Canvas.updateShader.WebGPU.Fragment.Invalid",
+        programType: WI.ShaderProgram.ProgramType.Render,
+        shaderType: WI.ShaderProgram.ShaderType.Fragment,
+        source: "INVALID",
+        shouldThrow: true,
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="load()">
+<p>WebGPU tests for Canvas.updateShader command.</p>
+</body>
+</html>
index e49ad2b..7b0a4cf 100644 (file)
@@ -2,74 +2,12 @@
 <html>
 <head>
 <script src="../../http/tests/inspector/resources/inspector-test.js"></script>
-<script src="resources/shaderProgram-utilities.js"></script>
-<script id="vertex-shader" type="x-shader/x-vertex">
-    void main(void) {
-        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-    }
-</script>
-<script id="fragment-shader" type="x-shader/x-fragment">
-    precision mediump float;
-
-    void main(void) {
-        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
-    }
-</script>
 <script>
-function load() {
-    createProgram("webgl");
-    linkProgram("vertex-shader", "fragment-shader");
-
-    runTest();
-}
-
 function test() {
     let suite = InspectorTest.createAsyncSuite("Canvas.updateShader");
 
-    function validSourceTest({name, shaderType, source}) {
-        suite.addTestCase({
-            name,
-            test(resolve, reject) {
-                let shaderProgram = WI.canvasManager.shaderPrograms[0];
-                if (!shaderProgram) {
-                    reject("Missing shader program")
-                    return;
-                }
-
-                let programId = shaderProgram.identifier;
-
-                CanvasAgent.updateShader(programId, shaderType, source)
-                .then(() => CanvasAgent.requestShaderSource(programId, shaderType))
-                .then(({content}) => InspectorTest.log(content))
-                .then(resolve, reject);
-            }
-        });
-    }
-
-    validSourceTest({
-        name: "Canvas.updateShader.vertexShaderValid",
-        shaderType: CanvasAgent.ShaderType.Vertex,
-        source: `
-    void main(void) {
-        gl_Position = vec4(1, 2, 3, 4);
-    }
-`,
-    });
-
-    validSourceTest({
-        name: "Canvas.updateShader.fragmentShaderValid",
-        shaderType: CanvasAgent.ShaderType.Fragment,
-        source: `
-    precision mediump float;
-
-    void main(void) {
-        gl_FragColor = vec4(0.1, 0.2, 0.3, 0.4);
-    }
-`,
-    });
-
     suite.addTestCase({
-        name: "Canvas.updateShader.invalidProgramId",
+        name: "Canvas.updateShader.ProgramId.Invalid",
         description: "Invalid program identifiers should cause an error.",
         test(resolve, reject) {
             const programId = "INVALID_PROGRAM_ID";
@@ -83,62 +21,11 @@ function test() {
         }
     });
 
-    suite.addTestCase({
-        name: "Canvas.updateShader.invalidShaderType",
-        description: "Invalid shader types should cause an error.",
-        test(resolve, reject) {
-            let shaderProgram = WI.canvasManager.shaderPrograms[0];
-            if (!shaderProgram) {
-                reject("Missing shader program")
-                return;
-            }
-
-            const shaderType = "INVALID_SHADER_TYPE";
-            const source = "INVALID_SOURCE";
-            CanvasAgent.updateShader(shaderProgram.identifier, shaderType, source, (error) => {
-                InspectorTest.expectThat(error, "Should produce an error.");
-                InspectorTest.log("Error: " + error);
-                resolve();
-            });
-        }
-    });
-
-    function invalidSourceTest({name, shaderType, source}) {
-        suite.addTestCase({
-            name,
-            test(resolve, reject) {
-                let shaderProgram = WI.canvasManager.shaderPrograms[0];
-                if (!shaderProgram) {
-                    reject("Missing shader program")
-                    return;
-                }
-
-                CanvasAgent.updateShader(shaderProgram.identifier, shaderType, source, (error) => {
-                    InspectorTest.expectThat(error, "Should produce error.");
-                    InspectorTest.log("Error: " + error);
-                    resolve();
-                });
-            }
-        });
-    }
-
-    invalidSourceTest({
-        name: "Canvas.updateShader.invalidVertexShaderSource",
-        shaderType: CanvasAgent.ShaderType.Vertex,
-        source: "INVALID",
-    });
-
-    invalidSourceTest({
-        name: "Canvas.updateShader.invalidFragmentShaderSource",
-        shaderType: CanvasAgent.ShaderType.Fragment,
-        source: "INVALID",
-    });
-
     suite.runTestCasesAndFinish();
 }
 </script>
 </head>
-<body onload="load()">
-    <p>Test compilation of shaders after being attached to a program, with and without syntax errors.</p>
+<body onload="runTest()">
+<p>Common tests for Canvas.updateShader command.</p>
 </body>
 </html>
index 6e19e15..8d1f10e 100644 (file)
@@ -1150,7 +1150,10 @@ webkit.org/b/168466 http/tests/security/bypassing-cors-checks-for-extension-urls
 webkit.org/b/191005 webgpu/ [ Skip ]
 webkit.org/b/191005 inspector/canvas/create-context-webgpu.html [ Skip ]
 webkit.org/b/191005 inspector/canvas/requestClientNodes-webgpu.html [ Skip ]
+webkit.org/b/191005 inspector/canvas/requestShaderSource-webgpu.html [ Skip ]
 webkit.org/b/191005 inspector/canvas/resolveContext-webgpu.html [ Skip ]
+webkit.org/b/191005 inspector/canvas/shaderProgram-add-remove-webgpu.html [ Skip ]
+webkit.org/b/191005 inspector/canvas/updateShader-webgpu.html [ Skip ]
 
 # No support for resource load statistics yet
 http/tests/resourceLoadStatistics/ [ Skip ]
index 0919735..31bfa98 100644 (file)
@@ -45,7 +45,10 @@ webkit.org/b/200308 fast/events/touch/ios/content-observation/non-visible-conten
 webgpu [ Skip ]
 inspector/canvas/create-context-webgpu.html [ Skip ]
 inspector/canvas/requestClientNodes-webgpu.html [ Skip ]
+inspector/canvas/requestShaderSource-webgpu.html [ Skip ]
 inspector/canvas/resolveContext-webgpu.html [ Skip ]
+inspector/canvas/shaderProgram-add-remove-webgpu.html [ Skip ]
+inspector/canvas/updateShader-webgpu.html [ Skip ]
 
 # Encrypted Media Extensions are not enabled
 media/encrypted-media/
index d34932d..b1fe5f0 100644 (file)
@@ -47,7 +47,10 @@ css-dark-mode [ Skip ]
 webgpu [ Skip ]
 inspector/canvas/create-context-webgpu.html [ Skip ]
 inspector/canvas/requestClientNodes-webgpu.html [ Skip ]
+inspector/canvas/requestShaderSource-webgpu.html [ Skip ]
 inspector/canvas/resolveContext-webgpu.html [ Skip ]
+inspector/canvas/shaderProgram-add-remove-webgpu.html [ Skip ]
+inspector/canvas/updateShader-webgpu.html [ Skip ]
 
 # Media Stream API testing is not supported for WK1 yet.
 fast/mediastream
index 1a5c4df..372b5bd 100644 (file)
@@ -1781,7 +1781,10 @@ webkit.org/b/190976 imported/w3c/web-platform-tests/media-source/mediasource-cha
 webkit.org/b/199275 [ HighSierra ] webgpu [ Skip ]
 webkit.org/b/199275 [ HighSierra ] inspector/canvas/create-context-webgpu.html [ Skip ]
 webkit.org/b/199275 [ HighSierra ] inspector/canvas/requestClientNodes-webgpu.html [ Skip ]
+webkit.org/b/199275 [ HighSierra ] inspector/canvas/requestShaderSource-webgpu.html [ Skip ]
 webkit.org/b/199275 [ HighSierra ] inspector/canvas/resolveContext-webgpu.html [ Skip ]
+webkit.org/b/199275 [ HighSierra ] inspector/canvas/shaderProgram-add-remove-webgpu.html [ Skip ]
+webkit.org/b/199275 [ HighSierra ] inspector/canvas/updateShader-webgpu.html [ Skip ]
 
 webkit.org/b/189680 platform/mac/media/audio-session-category-video-paused.html [ Pass Timeout ]
 
index 6c60917..a59a295 100644 (file)
@@ -2001,12 +2001,13 @@ inspector/canvas/recording-webgl2-memoryLimit.html [ Skip ]
 inspector/canvas/recording-webgl2-snapshots.html [ Skip ]
 inspector/canvas/requestContent-webgl.html [ Skip ]
 inspector/canvas/requestContent-webgl2.html [ Skip ]
-inspector/canvas/requestShaderSource.html [ Skip ]
+inspector/canvas/requestShaderSource-webgl.html [ Skip ]
 inspector/canvas/resolveContext-webgl.html [ Skip ]
 inspector/canvas/resolveContext-webgl2.html [ Skip ]
 inspector/canvas/shaderProgram-add-remove-webgl.html [ Skip ]
 inspector/canvas/shaderProgram-add-remove-webgl2.html [ Skip ]
-inspector/canvas/updateShader.html [ Skip ]
+inspector/canvas/updateShader-webgl.html [ Skip ]
+
 ################################################################################
 #################          End WebGL Issues              #######################
 ################################################################################
@@ -4247,7 +4248,10 @@ webkit.org/b/190520 editing/pasteboard/copy-paste-across-shadow-boundaries-with-
 webgpu [ Skip ]
 inspector/canvas/create-context-webgpu.html [ Skip ]
 inspector/canvas/requestClientNodes-webgpu.html [ Skip ]
+inspector/canvas/requestShaderSource-webgpu.html [ Skip ]
 inspector/canvas/resolveContext-webgpu.html [ Skip ]
+inspector/canvas/shaderProgram-add-remove-webgpu.html [ Skip ]
+inspector/canvas/updateShader-webgpu.html [ Skip ]
 
 webkit.org/b/191194 fast/block/basic/inline-content-with-floating-image.html [ Failure ]
 webkit.org/b/191194 fast/block/basic/inline-content-with-floating-images2.html [ Failure ]
index abd8cc9..8275d0e 100644 (file)
@@ -298,7 +298,10 @@ webgl/webgl2-rendering-context-obtain.html [ Skip ]
 webgpu [ Skip ]
 inspector/canvas/create-context-webgpu.html [ Skip ]
 inspector/canvas/requestClientNodes-webgpu.html [ Skip ]
+inspector/canvas/requestShaderSource-webgpu.html [ Skip ]
 inspector/canvas/resolveContext-webgpu.html [ Skip ]
+inspector/canvas/shaderProgram-add-remove-webgpu.html [ Skip ]
+inspector/canvas/updateShader-webgpu.html [ Skip ]
 
 # WIRELESS_PLAYBACK_TARGET is disabled
 media/airplay-target-availability.html [ Skip ]
index 2cd1d17..6860d78 100644 (file)
@@ -302,7 +302,10 @@ Bug(WPE) js/stringimpl-to-jsstring-on-large-strings-3.html [ Skip ]
 webgpu [ Skip ]
 inspector/canvas/create-context-webgpu.html [ Skip ]
 inspector/canvas/requestClientNodes-webgpu.html [ Skip ]
+inspector/canvas/requestShaderSource-webgpu.html [ Skip ]
 inspector/canvas/resolveContext-webgpu.html [ Skip ]
+inspector/canvas/shaderProgram-add-remove-webgpu.html [ Skip ]
+inspector/canvas/updateShader-webgpu.html [ Skip ]
 
 # Skipped due to untestable DRM key system. ClearKey counterparts are tested instead.
 imported/w3c/web-platform-tests/encrypted-media/drm-check-initdata-type.https.html [ Skip ]
index 846399b..d085e40 100644 (file)
@@ -1,3 +1,15 @@
+2019-09-23  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Canvas: show WebGPU shader pipelines
+        https://bugs.webkit.org/show_bug.cgi?id=201675
+        <rdar://problem/55543450>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/protocol/Canvas.json:
+        Add a `ProgramType` enum that conveys the type of shader program/pipeline when notifying the
+        frontend of a new program
+
 2019-09-23  Zan Dobersek  <zdobersek@igalia.com>
 
         testmasm: integer operands loaded as unsigned values
index 798b991..8aee55e 100644 (file)
             "description": "The type of rendering context backing the canvas element."
         },
         {
+            "id": "ProgramType",
+            "type": "string",
+            "enum": ["compute", "render"]
+        },
+        {
             "id": "ShaderType",
             "type": "string",
-            "enum": ["fragment", "vertex"],
-            "description": "Shader type. WebGL supports vertex and fragment shaders."
+            "enum": ["compute", "fragment", "vertex"]
         },
         {
             "id": "ContextAttributes",
                 { "name": "shaderType", "$ref": "ShaderType" }
             ],
             "returns": [
-                { "name": "content", "type": "string" }
+                { "name": "source", "type": "string" }
             ]
         },
         {
         {
             "name": "programCreated",
             "parameters": [
-                { "name": "canvasId", "$ref": "CanvasId", "description": "Canvas identifier." },
-                { "name": "programId", "$ref": "ProgramId", "description": "Program identifier." }
+                { "name": "canvasId", "$ref": "CanvasId"} ,
+                { "name": "programId", "$ref": "ProgramId" },
+                { "name": "programType", "$ref": "ProgramType" }
             ]
         },
         {
             "name": "programDeleted",
             "parameters": [
-                { "name": "programId", "$ref": "ProgramId", "description": "Program identifier." }
+                { "name": "programId", "$ref": "ProgramId" }
             ]
         }
     ]
index 0ff91ee..a261dc2 100644 (file)
@@ -1,3 +1,159 @@
+2019-09-23  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Canvas: show WebGPU shader pipelines
+        https://bugs.webkit.org/show_bug.cgi?id=201675
+        <rdar://problem/55543450>
+
+        Reviewed by Joseph Pecoraro.
+
+        Tests: inspector/canvas/requestShaderSource-webgpu.html
+               inspector/canvas/shaderProgram-add-remove-webgpu.html
+               inspector/canvas/updateShader-webgpu.html
+
+        Create common base classes for `WebGPUPipeline` and `GPUPipeline` so that Web Inspector can
+        instrument both render and compute shader pipelines.
+
+        Refactor `InspectorShaderProgram` to support both `WebGLProgram` and `WebGPUPipeline` so
+        that the same object can be used for all types of shader "program"s.
+
+        Keep a copy of each shader module's source, and allow the shader module to be updated.
+
+        * Modules/webgpu/WebGPUDevice.h:
+        * Modules/webgpu/WebGPUDevice.cpp:
+        (WebCore::WebGPUDevice::WebGPUDevice):
+        (WebCore::WebGPUDevice::~WebGPUDevice):
+        (WebCore::WebGPUDevice::createShaderModule const):
+        (WebCore::WebGPUDevice::createRenderPipeline): Added.
+        (WebCore::WebGPUDevice::createComputePipeline): Added.
+        (WebCore::WebGPUDevice::createRenderPipeline const): Deleted.
+        (WebCore::WebGPUDevice::createComputePipeline const): Deleted.
+
+        * Modules/webgpu/WebGPUPipeline.h: Added.
+        (WebCore::WebGPUPipeline::isRenderPipeline const):
+        (WebCore::WebGPUPipeline::isComputePipeline const):
+        (WebCore::WebGPUPipeline::scriptExecutionContext const):
+        * Modules/webgpu/WebGPUPipeline.cpp: Added.
+        (WebCore::WebGPUPipeline::instancesMutex):
+        (WebCore::WebGPUPipeline::WebGPUPipeline):
+        (WebCore::WebGPUPipeline::~WebGPUPipeline):
+        * platform/graphics/gpu/GPUPipeline.cpp: Added.
+        * platform/graphics/gpu/GPUPipeline.h: Added.
+        (WebCore::GPUPipeline::isRenderPipeline const):
+        (WebCore::GPUPipeline::isComputePipeline const):
+
+        * Modules/webgpu/WebGPUComputePipeline.idl:
+        * Modules/webgpu/WebGPUComputePipeline.h:
+        (WebCore::WebGPUComputePipeline::computePipeline const): Deleted.
+        * Modules/webgpu/WebGPUComputePipeline.cpp:
+        (WebCore::WebGPUComputePipeline::create):
+        (WebCore::WebGPUComputePipeline::WebGPUComputePipeline):
+        (WebCore::WebGPUComputePipeline::recompile): Added.
+        * platform/graphics/gpu/GPUComputePipeline.h:
+        (WebCore::GPUComputePipeline::isComputePipeline): Added.
+        * platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
+        (WebCore::GPUComputePipeline::tryCreate):
+        (WebCore::GPUComputePipeline::GPUComputePipeline):
+        (WebCore::GPUComputePipeline::recompile): Added.
+
+        * Modules/webgpu/WebGPURenderPipeline.idl:
+        * Modules/webgpu/WebGPURenderPipeline.h:
+        (WebCore::WebGPURenderPipeline::renderPipeline const): Deleted.
+        * Modules/webgpu/WebGPURenderPipeline.cpp:
+        (WebCore::WebGPURenderPipeline::create):
+        (WebCore::WebGPURenderPipeline::WebGPURenderPipeline):
+        (WebCore::WebGPURenderPipeline::recompile): Added.
+        * platform/graphics/gpu/GPURenderPipeline.h:
+        (WebCore::GPURenderPipeline::isRenderPipeline): Added.
+        * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
+        (WebCore::tryCreateMtlRenderPipelineState):
+        (WebCore::GPURenderPipeline::tryCreate):
+        (WebCore::GPURenderPipeline::GPURenderPipeline):
+        (WebCore::GPURenderPipeline::recompile): Added.
+
+        * Modules/webgpu/WebGPUShaderModule.h:
+        (WebCore::WebGPUShaderModule::source const): Added.
+        * Modules/webgpu/WebGPUShaderModule.cpp:
+        (WebCore::WebGPUShaderModule::update): Added.
+        * Modules/webgpu/WebGPUProgrammableStageDescriptor.h:
+        * platform/graphics/gpu/GPUProgrammableStageDescriptor.h:
+        (WebCore::GPUProgrammableStageDescriptor::GPUProgrammableStageDescriptor):
+
+        * inspector/InspectorShaderProgram.h:
+        * inspector/InspectorShaderProgram.cpp:
+        (WebCore::InspectorShaderProgram::create):
+        (WebCore::InspectorShaderProgram::InspectorShaderProgram):
+        (WebCore::InspectorShaderProgram::program const): Added.
+        (WebCore::InspectorShaderProgram::pipeline const): Added.
+        (WebCore::shaderForType): Added.
+        (WebCore::InspectorShaderProgram::requestShaderSource): Added.
+        (WebCore::InspectorShaderProgram::updateShader): Added.
+        (WebCore::InspectorShaderProgram::context const): Deleted.
+        (WebCore::InspectorShaderProgram::shaderForType): Deleted.
+
+        * inspector/agents/InspectorCanvasAgent.h:
+        * inspector/agents/InspectorCanvasAgent.cpp:
+        (WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
+        (WebCore::InspectorCanvasAgent::discardAgent):
+        (WebCore::InspectorCanvasAgent::enable):
+        (WebCore::InspectorCanvasAgent::disable):
+        (WebCore::InspectorCanvasAgent::requestShaderSource):
+        (WebCore::InspectorCanvasAgent::updateShader):
+        (WebCore::InspectorCanvasAgent::setShaderProgramDisabled):
+        (WebCore::InspectorCanvasAgent::setShaderProgramHighlighted):
+        (WebCore::InspectorCanvasAgent::frameNavigated):
+        (WebCore::InspectorCanvasAgent::didCreateWebGLProgram): Added.
+        (WebCore::InspectorCanvasAgent::willDestroyWebGLProgram): Added.
+        (WebCore::InspectorCanvasAgent::isWebGLProgramDisabled): Added.
+        (WebCore::InspectorCanvasAgent::isWebGLProgramHighlighted): Added.
+        (WebCore::InspectorCanvasAgent::didCreateWebGPUPipeline): Added.
+        (WebCore::InspectorCanvasAgent::willDestroyWebGPUPipeline): Added.
+        (WebCore::InspectorCanvasAgent::programDestroyedTimerFired): Added.
+        (WebCore::InspectorCanvasAgent::reset): Added.
+        (WebCore::InspectorCanvasAgent::unbindProgram):
+        (WebCore::InspectorCanvasAgent::findInspectorProgram):
+        (WebCore::InspectorCanvasAgent::didCreateProgram): Deleted.
+        (WebCore::InspectorCanvasAgent::willDeleteProgram): Deleted.
+        (WebCore::InspectorCanvasAgent::isShaderProgramDisabled): Deleted.
+        (WebCore::InspectorCanvasAgent::isShaderProgramHighlighted): Deleted.
+        (WebCore::InspectorCanvasAgent::clearCanvasData): Deleted.
+        * inspector/InspectorInstrumentation.h:
+        (WebCore::InspectorInstrumentation::didCreateWebGLProgram): Added.
+        (WebCore::InspectorInstrumentation::willDestroyWebGLProgram): Added.
+        (WebCore::InspectorInstrumentation::isWebGLProgramDisabled): Added.
+        (WebCore::InspectorInstrumentation::isWebGLProgramHighlighted): Added.
+        (WebCore::InspectorInstrumentation::didCreateWebGPUPipeline): Added.
+        (WebCore::InspectorInstrumentation::willDestroyWebGPUPipeline): Added.
+        (WebCore::InspectorInstrumentation::didCreateProgram): Deleted.
+        (WebCore::InspectorInstrumentation::willDeleteProgram): Deleted.
+        (WebCore::InspectorInstrumentation::isShaderProgramDisabled): Deleted.
+        (WebCore::InspectorInstrumentation::isShaderProgramHighlighted): Deleted.
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::didCreateWebGLProgramImpl): Added.
+        (WebCore::InspectorInstrumentation::willDestroyWebGLProgramImpl): Added.
+        (WebCore::InspectorInstrumentation::isWebGLProgramDisabledImpl): Added.
+        (WebCore::InspectorInstrumentation::isWebGLProgramHighlightedImpl): Added.
+        (WebCore::InspectorInstrumentation::didCreateWebGPUPipelineImpl): Added.
+        (WebCore::InspectorInstrumentation::willDestroyWebGPUPipelineImpl): Added.
+        (WebCore::InspectorInstrumentation::didCreateProgramImpl): Deleted.
+        (WebCore::InspectorInstrumentation::willDeleteProgramImpl): Deleted.
+        (WebCore::InspectorInstrumentation::isShaderProgramDisabledImpl): Deleted.
+        (WebCore::InspectorInstrumentation::isShaderProgramHighlightedImpl): Deleted.
+
+        * html/canvas/WebGLProgram.h:
+        * html/canvas/WebGLProgram.cpp:
+        (WebCore::WebGLProgram::WebGLProgram):
+        (WebCore::WebGLProgram::~WebGLProgram):
+        * html/canvas/WebGLRenderingContextBase.cpp:
+        (WebCore::InspectorScopedShaderProgramHighlight::showHightlight):
+        (WebCore::WebGLRenderingContextBase::createProgram):
+        (WebCore::WebGLRenderingContextBase::deleteProgram):
+        (WebCore::WebGLRenderingContextBase::drawArrays):
+        (WebCore::WebGLRenderingContextBase::drawElements):
+        Rename WebGL program instrumentation points to be less ambiguous.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
 2019-09-23  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [iOS] Drop animation when dragging images from Photos to WebKit2 Mail compose is incorrect
index cd11ecb..3535392 100644 (file)
 
 #if ENABLE(WEBGPU)
 
+#include "GPUComputePipeline.h"
+#include "GPUErrorScopes.h"
+#include "GPUPipeline.h"
+#include "GPUProgrammableStageDescriptor.h"
+#include "WebGPUDevice.h"
+#include <wtf/Optional.h>
+#include <wtf/Ref.h>
+
 namespace WebCore {
 
-Ref<WebGPUComputePipeline> WebGPUComputePipeline::create(RefPtr<GPUComputePipeline>&& pipeline, GPUErrorScopes& errorScopes)
+Ref<WebGPUComputePipeline> WebGPUComputePipeline::create(WebGPUDevice& device, RefPtr<GPUComputePipeline>&& pipeline, GPUErrorScopes& errorScopes, Optional<WebGPUPipeline::ShaderData> computeShader)
 {
-    return adoptRef(*new WebGPUComputePipeline(WTFMove(pipeline), errorScopes));
+    return adoptRef(*new WebGPUComputePipeline(device, WTFMove(pipeline), errorScopes, computeShader));
 }
 
-WebGPUComputePipeline::WebGPUComputePipeline(RefPtr<GPUComputePipeline>&& pipeline, GPUErrorScopes& errorScopes)
-    : GPUObjectBase(makeRef(errorScopes))
-    , m_computePipeline { WTFMove(pipeline) }
+WebGPUComputePipeline::WebGPUComputePipeline(WebGPUDevice& device, RefPtr<GPUComputePipeline>&& pipeline, GPUErrorScopes& errorScopes, Optional<WebGPUPipeline::ShaderData> computeShader)
+    : WebGPUPipeline(device, errorScopes)
+    , m_computePipeline(WTFMove(pipeline))
+    , m_computeShader(computeShader)
+{
+}
+
+WebGPUComputePipeline::~WebGPUComputePipeline() = default;
+
+bool WebGPUComputePipeline::recompile(const WebGPUDevice& device)
 {
+    if (m_computePipeline && m_computeShader) {
+        if (auto& webGPUComputeShaderModule = m_computeShader.value().module) {
+            if (auto* gpuComputeShaderModule = webGPUComputeShaderModule->module()) {
+                GPUProgrammableStageDescriptor computeStage(makeRef(*gpuComputeShaderModule), { m_computeShader.value().entryPoint });
+                return m_computePipeline->recompile(device.device(), WTFMove(computeStage));
+            }
+        }
+    }
+    return false;
 }
 
 } // namespace WebCore
index 2ed7c98..c1a7180 100644 (file)
 
 #if ENABLE(WEBGPU)
 
-#include "GPUComputePipeline.h"
-#include "GPUObjectBase.h"
-#include <wtf/RefPtr.h>
+#include "WebGPUPipeline.h"
+#include <wtf/Forward.h>
 
 namespace WebCore {
 
-class WebGPUComputePipeline : public GPUObjectBase {
+class GPUComputePipeline;
+class GPUPipeline;
+class GPUErrorScopes;
+class WebGPUDevice;
+
+class WebGPUComputePipeline final : public WebGPUPipeline {
 public:
-    static Ref<WebGPUComputePipeline> create(RefPtr<GPUComputePipeline>&&, GPUErrorScopes&);
+    virtual ~WebGPUComputePipeline();
+
+    static Ref<WebGPUComputePipeline> create(WebGPUDevice&, RefPtr<GPUComputePipeline>&&, GPUErrorScopes&, Optional<WebGPUPipeline::ShaderData> computeShader);
+
+    bool isComputePipeline() const { return true; }
 
+    bool isValid() const { return computePipeline(); }
     const GPUComputePipeline* computePipeline() const { return m_computePipeline.get(); }
+    Optional<WebGPUPipeline::ShaderData> computeShader() const { return m_computeShader; }
+
+    bool recompile(const WebGPUDevice&);
 
 private:
-    WebGPUComputePipeline(RefPtr<GPUComputePipeline>&&, GPUErrorScopes&);
+    WebGPUComputePipeline(WebGPUDevice&, RefPtr<GPUComputePipeline>&&, GPUErrorScopes&, Optional<WebGPUPipeline::ShaderData> computeShader);
 
     RefPtr<GPUComputePipeline> m_computePipeline;
+
+    // Preserved for Web Inspector recompilation.
+    Optional<WebGPUPipeline::ShaderData> m_computeShader;
 };
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_WEBGPUPIPELINE(WebCore::WebGPUComputePipeline, isComputePipeline())
+
 #endif // ENABLE(WEBGPU)
index a552ba9..4b8a77e 100644 (file)
@@ -27,7 +27,6 @@
 [
     Conditional=WEBGPU,
     EnabledAtRuntime=WebGPU,
-    ImplementationLacksVTable,
     InterfaceName=GPUComputePipeline
 ] interface WebGPUComputePipeline {
 };
index 5ebf083..7d5de79 100644 (file)
 #include "GPUBufferBinding.h"
 #include "GPUBufferDescriptor.h"
 #include "GPUCommandBuffer.h"
+#include "GPUComputePipeline.h"
 #include "GPUComputePipelineDescriptor.h"
 #include "GPUProgrammableStageDescriptor.h"
+#include "GPURenderPipeline.h"
 #include "GPURenderPipelineDescriptor.h"
 #include "GPUSampler.h"
 #include "GPUSamplerDescriptor.h"
@@ -61,6 +63,7 @@
 #include "WebGPUCommandEncoder.h"
 #include "WebGPUComputePipeline.h"
 #include "WebGPUComputePipelineDescriptor.h"
+#include "WebGPUPipeline.h"
 #include "WebGPUPipelineLayout.h"
 #include "WebGPUPipelineLayoutDescriptor.h"
 #include "WebGPUProgrammableStageDescriptor.h"
@@ -124,17 +127,32 @@ WebGPUDevice::WebGPUDevice(ScriptExecutionContext& context, Ref<const WebGPUAdap
 {
     ASSERT(m_scriptExecutionContext.isDocument());
 
-    LockHolder lock(instancesMutex());
-    instances(lock).add(this);
+    {
+        LockHolder lock(instancesMutex());
+        instances(lock).add(this);
+    }
 }
 
 WebGPUDevice::~WebGPUDevice()
 {
     InspectorInstrumentation::willDestroyWebGPUDevice(*this);
 
-    LockHolder lock(instancesMutex());
-    ASSERT(instances(lock).contains(this));
-    instances(lock).remove(this);
+    {
+        LockHolder lock(WebGPUPipeline::instancesMutex());
+        for (auto& entry : WebGPUPipeline::instances(lock)) {
+            if (entry.value == this) {
+                // Don't remove any WebGPUPipeline from the instances list, as they may still exist.
+                // Only remove the association with a WebGPU device.
+                entry.value = nullptr;
+            }
+        }
+    }
+
+    {
+        LockHolder lock(instancesMutex());
+        ASSERT(instances(lock).contains(this));
+        instances(lock).remove(this);
+    }
 }
 
 Ref<WebGPUBuffer> WebGPUDevice::createBuffer(const GPUBufferDescriptor& descriptor) const
@@ -205,31 +223,47 @@ Ref<WebGPUShaderModule> WebGPUDevice::createShaderModule(const WebGPUShaderModul
 {
     // FIXME: What can be validated here?
     auto module = m_device->tryCreateShaderModule(GPUShaderModuleDescriptor { descriptor.code });
-    return WebGPUShaderModule::create(WTFMove(module));
+    return WebGPUShaderModule::create(WTFMove(module), descriptor.code);
 }
 
-Ref<WebGPURenderPipeline> WebGPUDevice::createRenderPipeline(const WebGPURenderPipelineDescriptor& descriptor) const
+Ref<WebGPURenderPipeline> WebGPUDevice::createRenderPipeline(const WebGPURenderPipelineDescriptor& descriptor)
 {
     m_errorScopes->setErrorPrefix("GPUDevice.createRenderPipeline(): ");
 
     auto gpuDescriptor = descriptor.tryCreateGPURenderPipelineDescriptor(m_errorScopes);
     if (!gpuDescriptor)
-        return WebGPURenderPipeline::create(nullptr, m_errorScopes);
+        return WebGPURenderPipeline::create(*this, nullptr, m_errorScopes, WTF::nullopt, WTF::nullopt);
+
+    auto gpuPipeline = m_device->tryCreateRenderPipeline(*gpuDescriptor, m_errorScopes);
 
-    auto pipeline = m_device->tryCreateRenderPipeline(*gpuDescriptor, m_errorScopes);
-    return WebGPURenderPipeline::create(WTFMove(pipeline), m_errorScopes);
+    WebGPUPipeline::ShaderData vertexShader = { descriptor.vertexStage.module, descriptor.vertexStage.entryPoint };
+
+    Optional<WebGPUPipeline::ShaderData> fragmentShader;
+    if (descriptor.fragmentStage)
+        fragmentShader = { { descriptor.fragmentStage.value().module, descriptor.fragmentStage.value().entryPoint } };
+
+    auto webGPUPipeline = WebGPURenderPipeline::create(*this, WTFMove(gpuPipeline), m_errorScopes, vertexShader, fragmentShader);
+    if (webGPUPipeline->isValid())
+        InspectorInstrumentation::didCreateWebGPUPipeline(*this, webGPUPipeline.get());
+    return webGPUPipeline;
 }
 
-Ref<WebGPUComputePipeline> WebGPUDevice::createComputePipeline(const WebGPUComputePipelineDescriptor& descriptor) const
+Ref<WebGPUComputePipeline> WebGPUDevice::createComputePipeline(const WebGPUComputePipelineDescriptor& descriptor)
 {
     m_errorScopes->setErrorPrefix("GPUDevice.createComputePipeline(): ");
 
     auto gpuDescriptor = descriptor.tryCreateGPUComputePipelineDescriptor(m_errorScopes);
     if (!gpuDescriptor)
-        return WebGPUComputePipeline::create(nullptr, m_errorScopes);
+        return WebGPUComputePipeline::create(*this, nullptr, m_errorScopes, WTF::nullopt);
+
+    auto gpuPipeline = m_device->tryCreateComputePipeline(*gpuDescriptor, m_errorScopes);
+
+    WebGPUPipeline::ShaderData computeShader = { descriptor.computeStage.module, descriptor.computeStage.entryPoint };
 
-    auto pipeline = m_device->tryCreateComputePipeline(*gpuDescriptor, m_errorScopes);
-    return WebGPUComputePipeline::create(WTFMove(pipeline), m_errorScopes);
+    auto webGPUPipeline = WebGPUComputePipeline::create(*this, WTFMove(gpuPipeline), m_errorScopes, computeShader);
+    if (webGPUPipeline->isValid())
+        InspectorInstrumentation::didCreateWebGPUPipeline(*this, webGPUPipeline.get());
+    return webGPUPipeline;
 }
 
 Ref<WebGPUCommandEncoder> WebGPUDevice::createCommandEncoder() const
index d98f23c..21b5417 100644 (file)
@@ -99,8 +99,8 @@ public:
     Ref<WebGPUBindGroup> createBindGroup(const WebGPUBindGroupDescriptor&) const;
 
     Ref<WebGPUShaderModule> createShaderModule(const WebGPUShaderModuleDescriptor&) const;
-    Ref<WebGPURenderPipeline> createRenderPipeline(const WebGPURenderPipelineDescriptor&) const;
-    Ref<WebGPUComputePipeline> createComputePipeline(const WebGPUComputePipelineDescriptor&) const;
+    Ref<WebGPURenderPipeline> createRenderPipeline(const WebGPURenderPipelineDescriptor&);
+    Ref<WebGPUComputePipeline> createComputePipeline(const WebGPUComputePipelineDescriptor&);
 
     Ref<WebGPUCommandEncoder> createCommandEncoder() const;
 
diff --git a/Source/WebCore/Modules/webgpu/WebGPUPipeline.cpp b/Source/WebCore/Modules/webgpu/WebGPUPipeline.cpp
new file mode 100644 (file)
index 0000000..7a12159
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebGPUPipeline.h"
+
+#if ENABLE(WEBGPU)
+
+#include "GPUErrorScopes.h"
+#include "InspectorInstrumentation.h"
+#include "ScriptExecutionContext.h"
+#include "WebGPUDevice.h"
+#include <wtf/HashMap.h>
+#include <wtf/Lock.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Ref.h>
+
+namespace WebCore {
+
+HashMap<WebGPUPipeline*, WebGPUDevice*>& WebGPUPipeline::instances(const LockHolder&)
+{
+    static NeverDestroyed<HashMap<WebGPUPipeline*, WebGPUDevice*>> instances;
+    return instances;
+}
+
+Lock& WebGPUPipeline::instancesMutex()
+{
+    static LazyNeverDestroyed<Lock> mutex;
+    static std::once_flag initializeMutex;
+    std::call_once(initializeMutex, [] {
+        mutex.construct();
+    });
+    return mutex.get();
+}
+
+WebGPUPipeline::WebGPUPipeline(WebGPUDevice& device, GPUErrorScopes& errorScopes)
+    : GPUObjectBase(makeRef(errorScopes))
+    , m_scriptExecutionContext(device.scriptExecutionContext())
+{
+    ASSERT(m_scriptExecutionContext);
+
+    {
+        LockHolder lock(instancesMutex());
+        instances(lock).add(this, &device);
+    }
+}
+
+WebGPUPipeline::~WebGPUPipeline()
+{
+    InspectorInstrumentation::willDestroyWebGPUPipeline(*this);
+
+    {
+        LockHolder lock(instancesMutex());
+        ASSERT(instances(lock).contains(this));
+        instances(lock).remove(this);
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGPU)
diff --git a/Source/WebCore/Modules/webgpu/WebGPUPipeline.h b/Source/WebCore/Modules/webgpu/WebGPUPipeline.h
new file mode 100644 (file)
index 0000000..1e323c7
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBGPU)
+
+#include "GPUObjectBase.h"
+#include "WebGPUShaderModule.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+class GPUErrorScopes;
+class WebGPUDevice;
+
+class WebGPUPipeline : public GPUObjectBase {
+public:
+    virtual ~WebGPUPipeline();
+
+    static HashMap<WebGPUPipeline*, WebGPUDevice*>& instances(const LockHolder&);
+    static Lock& instancesMutex();
+
+    virtual bool isRenderPipeline() const { return false; }
+    virtual bool isComputePipeline() const { return false; }
+
+    ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext; }
+    virtual bool isValid() const = 0;
+
+    struct ShaderData {
+        RefPtr<WebGPUShaderModule> module;
+        String entryPoint;
+    };
+
+    virtual bool recompile(const WebGPUDevice&) = 0;
+
+protected:
+    WebGPUPipeline(WebGPUDevice&, GPUErrorScopes&);
+
+    ScriptExecutionContext* m_scriptExecutionContext;
+};
+
+} // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_WEBGPUPIPELINE(ToValueTypeName, predicate) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
+    static bool isType(const WebCore::WebGPUPipeline& pipeline) { return pipeline.predicate; } \
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // ENABLE(WEBGPU)
index ffbc5b8..1a4414a 100644 (file)
@@ -37,7 +37,7 @@ namespace WebCore {
 struct WebGPUProgrammableStageDescriptor : GPUProgrammableStageDescriptorBase {
     Optional<GPUProgrammableStageDescriptor> tryCreateGPUProgrammableStageDescriptor() const;
 
-    RefPtr<const WebGPUShaderModule> module;
+    RefPtr<WebGPUShaderModule> module;
 };
 
 } // namespace WebCore
index 17aedc6..fe957f5 100644 (file)
 
 #if ENABLE(WEBGPU)
 
+#include "GPUErrorScopes.h"
+#include "GPUPipeline.h"
+#include "GPUProgrammableStageDescriptor.h"
+#include "GPURenderPipeline.h"
+#include "WebGPUDevice.h"
+#include <wtf/Optional.h>
+#include <wtf/Ref.h>
+
 namespace WebCore {
 
-Ref<WebGPURenderPipeline> WebGPURenderPipeline::create(RefPtr<GPURenderPipeline>&& pipeline, GPUErrorScopes& errorScopes)
+Ref<WebGPURenderPipeline> WebGPURenderPipeline::create(WebGPUDevice& device, RefPtr<GPURenderPipeline>&& pipeline, GPUErrorScopes& errorScopes, Optional<WebGPUPipeline::ShaderData> vertexShader, Optional<WebGPUPipeline::ShaderData> fragmentShader)
 {
-    return adoptRef(*new WebGPURenderPipeline(WTFMove(pipeline), errorScopes));
+    return adoptRef(*new WebGPURenderPipeline(device, WTFMove(pipeline), errorScopes, vertexShader, fragmentShader));
 }
 
-WebGPURenderPipeline::WebGPURenderPipeline(RefPtr<GPURenderPipeline>&& pipeline, GPUErrorScopes& errorScopes)
-    : GPUObjectBase(makeRef(errorScopes))
+WebGPURenderPipeline::WebGPURenderPipeline(WebGPUDevice& device, RefPtr<GPURenderPipeline>&& pipeline, GPUErrorScopes& errorScopes, Optional<WebGPUPipeline::ShaderData> vertexShader, Optional<WebGPUPipeline::ShaderData> fragmentShader)
+    : WebGPUPipeline(device, errorScopes)
     , m_renderPipeline(WTFMove(pipeline))
+    , m_vertexShader(vertexShader)
+    , m_fragmentShader(fragmentShader)
+{
+}
+
+WebGPURenderPipeline::~WebGPURenderPipeline() = default;
+
+bool WebGPURenderPipeline::recompile(const WebGPUDevice& device)
 {
+    if (m_renderPipeline && m_vertexShader) {
+        if (auto& webGPUVertexShaderModule = m_vertexShader.value().module) {
+            if (auto* gpuVertexShaderModule = webGPUVertexShaderModule->module()) {
+                GPUProgrammableStageDescriptor vertexStage(makeRef(*gpuVertexShaderModule), { m_vertexShader.value().entryPoint });
+                Optional<GPUProgrammableStageDescriptor> fragmentStage;
+                if (m_fragmentShader) {
+                    if (auto& webGPUFragmentShaderModule = m_fragmentShader.value().module) {
+                        if (auto* gpuFragmentShaderModule = webGPUFragmentShaderModule->module())
+                            fragmentStage = GPUProgrammableStageDescriptor(makeRef(*gpuFragmentShaderModule), { m_fragmentShader.value().entryPoint });
+                    }
+                }
+                return m_renderPipeline->recompile(device.device(), WTFMove(vertexStage), WTFMove(fragmentStage));
+            }
+        }
+    }
+    return false;
 }
 
 } // namespace WebCore
index 8f00ca6..b2b8094 100644 (file)
 
 #if ENABLE(WEBGPU)
 
-#include "GPUObjectBase.h"
-#include "GPURenderPipeline.h"
-#include <wtf/RefPtr.h>
+#include "WebGPUPipeline.h"
+#include <wtf/Forward.h>
 
 namespace WebCore {
 
-class WebGPURenderPipeline : public GPUObjectBase {
+class GPUPipeline;
+class GPURenderPipeline;
+class GPUErrorScopes;
+class WebGPUDevice;
+
+class WebGPURenderPipeline final : public WebGPUPipeline {
 public:
-    static Ref<WebGPURenderPipeline> create(RefPtr<GPURenderPipeline>&&, GPUErrorScopes&);
+    virtual ~WebGPURenderPipeline();
+
+    static Ref<WebGPURenderPipeline> create(WebGPUDevice&, RefPtr<GPURenderPipeline>&&, GPUErrorScopes&, Optional<WebGPUPipeline::ShaderData> vertexShader, Optional<WebGPUPipeline::ShaderData> fragmentShader);
+
+    bool isRenderPipeline() const { return true; }
 
+    bool isValid() const { return renderPipeline(); }
     const GPURenderPipeline* renderPipeline() const { return m_renderPipeline.get(); }
+    Optional<WebGPUPipeline::ShaderData> vertexShader() const { return m_vertexShader; }
+    Optional<WebGPUPipeline::ShaderData> fragmentShader() const { return m_fragmentShader; }
+
+    bool recompile(const WebGPUDevice&);
 
 private:
-    WebGPURenderPipeline(RefPtr<GPURenderPipeline>&&, GPUErrorScopes&);
+    WebGPURenderPipeline(WebGPUDevice&, RefPtr<GPURenderPipeline>&&, GPUErrorScopes&, Optional<WebGPUPipeline::ShaderData> vertexShader, Optional<WebGPUPipeline::ShaderData> fragmentShader);
 
     RefPtr<GPURenderPipeline> m_renderPipeline;
+
+    // Preserved for Web Inspector recompilation.
+    Optional<WebGPUPipeline::ShaderData> m_vertexShader;
+    Optional<WebGPUPipeline::ShaderData> m_fragmentShader;
 };
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_WEBGPUPIPELINE(WebCore::WebGPURenderPipeline, isRenderPipeline())
+
 #endif // ENABLE(WEBGPU)
index a989fd4..a9b4000 100644 (file)
@@ -27,7 +27,6 @@
 [
     Conditional=WEBGPU,
     EnabledAtRuntime=WebGPU,
-    ImplementationLacksVTable,
     InterfaceName=GPURenderPipeline
 ] interface WebGPURenderPipeline {
 };
index ee85f92..d314545 100644 (file)
 
 #if ENABLE(WEBGPU)
 
+#include "GPUShaderModuleDescriptor.h"
+#include "WebGPUDevice.h"
+#include <wtf/RefPtr.h>
+
 namespace WebCore {
 
-Ref<WebGPUShaderModule> WebGPUShaderModule::create(RefPtr<GPUShaderModule>&& module)
+Ref<WebGPUShaderModule> WebGPUShaderModule::create(RefPtr<GPUShaderModule>&& module, const String& source)
 {
-    return adoptRef(*new WebGPUShaderModule(WTFMove(module)));
+    return adoptRef(*new WebGPUShaderModule(WTFMove(module), source));
 }
 
-WebGPUShaderModule::WebGPUShaderModule(RefPtr<GPUShaderModule>&& module)
+WebGPUShaderModule::WebGPUShaderModule(RefPtr<GPUShaderModule>&& module, const String& source)
     : m_module(WTFMove(module))
+    , m_source(source)
+{
+}
+
+void WebGPUShaderModule::update(const WebGPUDevice& device, const String& source)
 {
+    m_source = source;
+    m_module = GPUShaderModule::tryCreate(device.device(), { m_source });
 }
 
 } // namespace WebCore
index 8377053..7864611 100644 (file)
 #if ENABLE(WEBGPU)
 
 #include "GPUShaderModule.h"
-
+#include <wtf/Forward.h>
 #include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
 
 namespace WebCore {
 
+class WebGPUDevice;
+
 class WebGPUShaderModule : public RefCounted<WebGPUShaderModule> {
 public:
-    static Ref<WebGPUShaderModule> create(RefPtr<GPUShaderModule>&&);
+    static Ref<WebGPUShaderModule> create(RefPtr<GPUShaderModule>&&, const String& source);
 
-    const GPUShaderModule* module() const { return m_module.get(); }
+    GPUShaderModule* module() const { return m_module.get(); }
+    const String& source() const { return m_source; }
+
+    void update(const WebGPUDevice&, const String& source);
 
 private:
-    WebGPUShaderModule(RefPtr<GPUShaderModule>&&);
+    WebGPUShaderModule(RefPtr<GPUShaderModule>&&, const String& source);
 
     RefPtr<GPUShaderModule> m_module;
+
+    // Preserved for Web Inspector recompilation.
+    String m_source;
 };
 
 } // namespace WebCore
index fd4dd31..f40384d 100644 (file)
@@ -373,6 +373,7 @@ Modules/webgpu/WebGPUComputePipelineDescriptor.cpp
 Modules/webgpu/WebGPUDevice.cpp
 Modules/webgpu/WebGPUDeviceErrorScopes.cpp
 Modules/webgpu/WebGPUQueue.cpp
+Modules/webgpu/WebGPUPipeline.cpp
 Modules/webgpu/WebGPUPipelineLayout.cpp
 Modules/webgpu/WebGPUPipelineLayoutDescriptor.cpp
 Modules/webgpu/WebGPUProgrammableStageDescriptor.cpp
@@ -1898,6 +1899,7 @@ platform/graphics/gpu/GPUDevice.cpp
 platform/graphics/gpu/GPUError.cpp
 platform/graphics/gpu/GPUErrorScopes.cpp
 platform/graphics/gpu/GPUValidationError.cpp
+platform/graphics/gpu/GPUPipeline.cpp
 platform/graphics/gpu/GPUPipelineLayout.cpp
 platform/graphics/gpu/GPUProgrammablePassEncoder.cpp
 
index 300fc4b..5ca08c3 100644 (file)
                9175CE5921E281EC00DF2C28 /* JSInspectorAuditAccessibilityObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSInspectorAuditAccessibilityObject.cpp; sourceTree = "<group>"; };
                9175CE5A21E281ED00DF2C27 /* InspectorAuditAccessibilityObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorAuditAccessibilityObject.h; sourceTree = "<group>"; };
                9175CE5A21E281ED00DF2C28 /* JSInspectorAuditAccessibilityObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInspectorAuditAccessibilityObject.h; sourceTree = "<group>"; };
+               9186F3B32329FB0500AFF857 /* GPUPipeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPUPipeline.h; sourceTree = "<group>"; };
+               9186F3B62329FB4E00AFF857 /* WebGPUPipeline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebGPUPipeline.cpp; sourceTree = "<group>"; };
+               9186F3B72329FB4F00AFF857 /* WebGPUPipeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebGPUPipeline.h; sourceTree = "<group>"; };
+               9186F3BA2329FE6800AFF857 /* GPUPipeline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GPUPipeline.cpp; sourceTree = "<group>"; };
                91B8F0B321953D65000C2B00 /* CertificateInfoBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CertificateInfoBase.h; sourceTree = "<group>"; };
                91B952221F58A58000931DC2 /* RecordingSwizzleTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RecordingSwizzleTypes.h; sourceTree = "<group>"; };
                91C9F2F81AE3BE240095B61C /* AXTextStateChangeIntent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AXTextStateChangeIntent.h; sourceTree = "<group>"; };
                                D08AA02F220D0BD50058C502 /* GPULoadOp.h */,
                                D09AFB3722D7D5C600C4538C /* GPUObjectBase.h */,
                                D09AFB1922D6698A00C4538C /* GPUOutOfMemoryError.h */,
+                               9186F3BA2329FE6800AFF857 /* GPUPipeline.cpp */,
+                               9186F3B32329FB0500AFF857 /* GPUPipeline.h */,
                                312FF8C421A4C2F400EB199D /* GPUPipelineDescriptorBase.h */,
                                D003288721C9A4E500622AA6 /* GPUPipelineLayout.cpp */,
                                D003288621C9A4E500622AA6 /* GPUPipelineLayout.h */,
                                D09AFB0322D40CC500C4538C /* WebGPUDeviceErrorScopes.idl */,
                                D09AC00A231735BE00187762 /* WebGPUDeviceEventHandler.h */,
                                D09AC00B231735BE00187762 /* WebGPUDeviceEventHandler.idl */,
+                               9186F3B62329FB4E00AFF857 /* WebGPUPipeline.cpp */,
+                               9186F3B72329FB4F00AFF857 /* WebGPUPipeline.h */,
                                D0C419F02183EB31009EC1DE /* WebGPUPipelineDescriptorBase.h */,
                                D0C419F12183EB31009EC1DE /* WebGPUPipelineDescriptorBase.idl */,
                                D05A99E521C9BF2C00032B75 /* WebGPUPipelineLayout.cpp */,
index 6ba381a..fe1b0c5 100644 (file)
@@ -28,6 +28,8 @@
 
 #if ENABLE(WEBGL)
 
+#include "InspectorInstrumentation.h"
+#include "ScriptExecutionContext.h"
 #include "WebGLContextGroup.h"
 #include "WebGLRenderingContextBase.h"
 #include "WebGLShader.h"
@@ -60,7 +62,10 @@ Ref<WebGLProgram> WebGLProgram::create(WebGLRenderingContextBase& ctx)
 
 WebGLProgram::WebGLProgram(WebGLRenderingContextBase& ctx)
     : WebGLSharedObject(ctx)
+    , m_scriptExecutionContext(ctx.scriptExecutionContext())
 {
+    ASSERT(m_scriptExecutionContext);
+
     {
         LockHolder lock(instancesMutex());
         instances(lock).add(this, &ctx);
@@ -71,6 +76,8 @@ WebGLProgram::WebGLProgram(WebGLRenderingContextBase& ctx)
 
 WebGLProgram::~WebGLProgram()
 {
+    InspectorInstrumentation::willDestroyWebGLProgram(*this);
+
     deleteObject(0);
 
     {
index 88a8979..6769d1d 100644 (file)
@@ -32,6 +32,8 @@
 
 namespace WebCore {
 
+class ScriptExecutionContext;
+class WebGLRenderingContextBase;
 class WebGLShader;
 
 class WebGLProgram final : public WebGLSharedObject {
@@ -42,6 +44,8 @@ public:
     static HashMap<WebGLProgram*, WebGLRenderingContextBase*>& instances(const LockHolder&);
     static Lock& instancesMutex();
 
+    ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext; }
+
     unsigned numActiveAttribLocations();
     GC3Dint getActiveAttribLocation(GC3Duint index);
 
@@ -71,6 +75,8 @@ private:
     void cacheActiveAttribLocations(GraphicsContext3D*);
     void cacheInfoIfNeeded();
 
+    ScriptExecutionContext* m_scriptExecutionContext;
+
     Vector<GC3Dint> m_activeAttribLocations;
 
     GC3Dint m_linkStatus { 0 };
index 224e34d..6eea91f 100644 (file)
@@ -411,7 +411,7 @@ public:
 private:
     void showHightlight()
     {
-        if (!m_program || LIKELY(!InspectorInstrumentation::isShaderProgramHighlighted(m_context, *m_program)))
+        if (!m_program || LIKELY(!InspectorInstrumentation::isWebGLProgramHighlighted(m_context, *m_program)))
             return;
 
         if (hasBufferBinding(GraphicsContext3D::FRAMEBUFFER_BINDING)) {
@@ -1754,7 +1754,7 @@ RefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
     auto program = WebGLProgram::create(*this);
     addSharedObject(program.get());
 
-    InspectorInstrumentation::didCreateProgram(*this, program.get());
+    InspectorInstrumentation::didCreateWebGLProgram(*this, program.get());
 
     return program;
 }
@@ -1840,7 +1840,7 @@ void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
 {
     if (program)
-        InspectorInstrumentation::willDeleteProgram(*this, *program);
+        InspectorInstrumentation::willDestroyWebGLProgram(*program);
 
     deleteObject(program);
     // We don't reset m_currentProgram to 0 here because the deletion of the
@@ -2255,7 +2255,7 @@ void WebGLRenderingContextBase::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsiz
     if (!validateDrawArrays("drawArrays", mode, first, count, 0))
         return;
 
-    if (m_currentProgram && InspectorInstrumentation::isShaderProgramDisabled(*this, *m_currentProgram))
+    if (m_currentProgram && InspectorInstrumentation::isWebGLProgramDisabled(*this, *m_currentProgram))
         return;
 
     clearIfComposited();
@@ -2309,7 +2309,7 @@ void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3
     if (!validateDrawElements("drawElements", mode, count, type, offset, numElements, 0))
         return;
 
-    if (m_currentProgram && InspectorInstrumentation::isShaderProgramDisabled(*this, *m_currentProgram))
+    if (m_currentProgram && InspectorInstrumentation::isWebGLProgramDisabled(*this, *m_currentProgram))
         return;
 
     clearIfComposited();
index 6964650..912c845 100644 (file)
@@ -1079,29 +1079,29 @@ void InspectorInstrumentation::didEnableExtensionImpl(InstrumentingAgents& instr
         canvasAgent->didEnableExtension(contextWebGLBase, extension);
 }
 
-void InspectorInstrumentation::didCreateProgramImpl(InstrumentingAgents& instrumentingAgents, WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
+void InspectorInstrumentation::didCreateWebGLProgramImpl(InstrumentingAgents& instrumentingAgents, WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
 {
     if (InspectorCanvasAgent* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
-        canvasAgent->didCreateProgram(contextWebGLBase, program);
+        canvasAgent->didCreateWebGLProgram(contextWebGLBase, program);
 }
 
-void InspectorInstrumentation::willDeleteProgramImpl(InstrumentingAgents& instrumentingAgents, WebGLProgram& program)
+void InspectorInstrumentation::willDestroyWebGLProgramImpl(InstrumentingAgents& instrumentingAgents, WebGLProgram& program)
 {
     if (InspectorCanvasAgent* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
-        canvasAgent->willDeleteProgram(program);
+        canvasAgent->willDestroyWebGLProgram(program);
 }
 
-bool InspectorInstrumentation::isShaderProgramDisabledImpl(InstrumentingAgents& instrumentingAgents, WebGLProgram& program)
+bool InspectorInstrumentation::isWebGLProgramDisabledImpl(InstrumentingAgents& instrumentingAgents, WebGLProgram& program)
 {
     if (InspectorCanvasAgent* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
-        return canvasAgent->isShaderProgramDisabled(program);
+        return canvasAgent->isWebGLProgramDisabled(program);
     return false;
 }
 
-bool InspectorInstrumentation::isShaderProgramHighlightedImpl(InstrumentingAgents& instrumentingAgents, WebGLProgram& program)
+bool InspectorInstrumentation::isWebGLProgramHighlightedImpl(InstrumentingAgents& instrumentingAgents, WebGLProgram& program)
 {
     if (InspectorCanvasAgent* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
-        return canvasAgent->isShaderProgramHighlighted(program);
+        return canvasAgent->isWebGLProgramHighlighted(program);
     return false;
 }
 #endif
@@ -1124,6 +1124,18 @@ void InspectorInstrumentation::willConfigureSwapChainImpl(InstrumentingAgents& i
     if (auto* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
         canvasAgent->willConfigureSwapChain(contextGPU, newSwapChain);
 }
+
+void InspectorInstrumentation::didCreateWebGPUPipelineImpl(InstrumentingAgents& instrumentingAgents, WebGPUDevice& device, WebGPUPipeline& pipeline)
+{
+    if (auto* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
+        canvasAgent->didCreateWebGPUPipeline(device, pipeline);
+}
+
+void InspectorInstrumentation::willDestroyWebGPUPipelineImpl(InstrumentingAgents& instrumentingAgents, WebGPUPipeline& pipeline)
+{
+    if (auto* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
+        canvasAgent->willDestroyWebGPUPipeline(pipeline);
+}
 #endif
 
 #if ENABLE(RESOURCE_USAGE)
index 81f3cdc..549aa17 100644 (file)
@@ -63,6 +63,7 @@
 #if ENABLE(WEBGPU)
 #include "GPUCanvasContext.h"
 #include "WebGPUDevice.h"
+#include "WebGPUPipeline.h"
 #endif
 
 namespace Inspector {
@@ -289,15 +290,17 @@ public:
     static void didFinishRecordingCanvasFrame(CanvasRenderingContext&, bool forceDispatch = false);
 #if ENABLE(WEBGL)
     static void didEnableExtension(WebGLRenderingContextBase&, const String&);
-    static void didCreateProgram(WebGLRenderingContextBase&, WebGLProgram&);
-    static void willDeleteProgram(WebGLRenderingContextBase&, WebGLProgram&);
-    static bool isShaderProgramDisabled(WebGLRenderingContextBase&, WebGLProgram&);
-    static bool isShaderProgramHighlighted(WebGLRenderingContextBase&, WebGLProgram&);
+    static void didCreateWebGLProgram(WebGLRenderingContextBase&, WebGLProgram&);
+    static void willDestroyWebGLProgram(WebGLProgram&);
+    static bool isWebGLProgramDisabled(WebGLRenderingContextBase&, WebGLProgram&);
+    static bool isWebGLProgramHighlighted(WebGLRenderingContextBase&, WebGLProgram&);
 #endif
 #if ENABLE(WEBGPU)
     static void didCreateWebGPUDevice(WebGPUDevice&);
     static void willDestroyWebGPUDevice(WebGPUDevice&);
     static void willConfigureSwapChain(GPUCanvasContext&, WebGPUSwapChain&);
+    static void didCreateWebGPUPipeline(WebGPUDevice&, WebGPUPipeline&);
+    static void willDestroyWebGPUPipeline(WebGPUPipeline&);
 #endif
 
     static void networkStateChanged(Page&);
@@ -481,15 +484,17 @@ private:
     static void didFinishRecordingCanvasFrameImpl(InstrumentingAgents&, CanvasRenderingContext&, bool forceDispatch = false);
 #if ENABLE(WEBGL)
     static void didEnableExtensionImpl(InstrumentingAgents&, WebGLRenderingContextBase&, const String&);
-    static void didCreateProgramImpl(InstrumentingAgents&, WebGLRenderingContextBase&, WebGLProgram&);
-    static void willDeleteProgramImpl(InstrumentingAgents&, WebGLProgram&);
-    static bool isShaderProgramDisabledImpl(InstrumentingAgents&, WebGLProgram&);
-    static bool isShaderProgramHighlightedImpl(InstrumentingAgents&, WebGLProgram&);
+    static void didCreateWebGLProgramImpl(InstrumentingAgents&, WebGLRenderingContextBase&, WebGLProgram&);
+    static void willDestroyWebGLProgramImpl(InstrumentingAgents&, WebGLProgram&);
+    static bool isWebGLProgramDisabledImpl(InstrumentingAgents&, WebGLProgram&);
+    static bool isWebGLProgramHighlightedImpl(InstrumentingAgents&, WebGLProgram&);
 #endif
 #if ENABLE(WEBGPU)
     static void didCreateWebGPUDeviceImpl(InstrumentingAgents&, WebGPUDevice&);
     static void willDestroyWebGPUDeviceImpl(InstrumentingAgents&, WebGPUDevice&);
     static void willConfigureSwapChainImpl(InstrumentingAgents&, GPUCanvasContext&, WebGPUSwapChain&);
+    static void didCreateWebGPUPipelineImpl(InstrumentingAgents&, WebGPUDevice&, WebGPUPipeline&);
+    static void willDestroyWebGPUPipelineImpl(InstrumentingAgents&, WebGPUPipeline&);
 #endif
 
     static void layerTreeDidChangeImpl(InstrumentingAgents&);
@@ -1384,33 +1389,33 @@ inline void InspectorInstrumentation::didEnableExtension(WebGLRenderingContextBa
         didEnableExtensionImpl(*instrumentingAgents, contextWebGLBase, extension);
 }
 
-inline void InspectorInstrumentation::didCreateProgram(WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
+inline void InspectorInstrumentation::didCreateWebGLProgram(WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
     if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(contextWebGLBase.canvasBase().scriptExecutionContext()))
-        didCreateProgramImpl(*instrumentingAgents, contextWebGLBase, program);
+        didCreateWebGLProgramImpl(*instrumentingAgents, contextWebGLBase, program);
 }
 
-inline void InspectorInstrumentation::willDeleteProgram(WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
+inline void InspectorInstrumentation::willDestroyWebGLProgram(WebGLProgram& program)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
-    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(contextWebGLBase.canvasBase().scriptExecutionContext()))
-        willDeleteProgramImpl(*instrumentingAgents, program);
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(program.scriptExecutionContext()))
+        willDestroyWebGLProgramImpl(*instrumentingAgents, program);
 }
 
-inline bool InspectorInstrumentation::isShaderProgramDisabled(WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
+inline bool InspectorInstrumentation::isWebGLProgramDisabled(WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
 {
     FAST_RETURN_IF_NO_FRONTENDS(false);
     if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(contextWebGLBase.canvasBase().scriptExecutionContext()))
-        return isShaderProgramDisabledImpl(*instrumentingAgents, program);
+        return isWebGLProgramDisabledImpl(*instrumentingAgents, program);
     return false;
 }
 
-inline bool InspectorInstrumentation::isShaderProgramHighlighted(WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
+inline bool InspectorInstrumentation::isWebGLProgramHighlighted(WebGLRenderingContextBase& contextWebGLBase, WebGLProgram& program)
 {
     FAST_RETURN_IF_NO_FRONTENDS(false);
     if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(contextWebGLBase.canvasBase().scriptExecutionContext()))
-        return isShaderProgramHighlightedImpl(*instrumentingAgents, program);
+        return isWebGLProgramHighlightedImpl(*instrumentingAgents, program);
     return false;
 }
 #endif
@@ -1436,6 +1441,20 @@ inline void InspectorInstrumentation::willConfigureSwapChain(GPUCanvasContext& c
     if (auto* instrumentingAgents = instrumentingAgentsForContext(contextGPU.canvasBase().scriptExecutionContext()))
         willConfigureSwapChainImpl(*instrumentingAgents, contextGPU, newSwapChain);
 }
+
+inline void InspectorInstrumentation::didCreateWebGPUPipeline(WebGPUDevice& device, WebGPUPipeline& pipeline)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* instrumentingAgents = instrumentingAgentsForContext(device.scriptExecutionContext()))
+        didCreateWebGPUPipelineImpl(*instrumentingAgents, device, pipeline);
+}
+
+inline void InspectorInstrumentation::willDestroyWebGPUPipeline(WebGPUPipeline& pipeline)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* instrumentingAgents = instrumentingAgentsForContext(pipeline.scriptExecutionContext()))
+        willDestroyWebGPUPipelineImpl(*instrumentingAgents, pipeline);
+}
 #endif
 
 inline void InspectorInstrumentation::networkStateChanged(Page& page)
index d529550..7af7196 100644 (file)
 #include "config.h"
 #include "InspectorShaderProgram.h"
 
-#if ENABLE(WEBGL)
+#include "InspectorCanvas.h"
+#include <JavaScriptCore/IdentifiersFactory.h>
+#include <wtf/Optional.h>
+#include <wtf/Ref.h>
+#include <wtf/Variant.h>
+#include <wtf/text/WTFString.h>
 
+#if ENABLE(WEBGL)
 #include "GraphicsContext3D.h"
-#include "GraphicsTypes3D.h"
-#include "HTMLCanvasElement.h"
-#include "InspectorCanvas.h"
 #include "WebGLProgram.h"
 #include "WebGLRenderingContextBase.h"
 #include "WebGLShader.h"
-#include <JavaScriptCore/IdentifiersFactory.h>
+#endif
+
+#if ENABLE(WEBGPU)
+#include "GPUShaderModule.h"
+#include "WHLSLPrepare.h"
+#include "WebGPUComputePipeline.h"
+#include "WebGPUPipeline.h"
+#include "WebGPURenderPipeline.h"
+#include "WebGPUShaderModule.h"
+#endif
 
 namespace WebCore {
 
 using namespace Inspector;
 
+#if ENABLE(WEBGL)
 Ref<InspectorShaderProgram> InspectorShaderProgram::create(WebGLProgram& program, InspectorCanvas& inspectorCanvas)
 {
     return adoptRef(*new InspectorShaderProgram(program, inspectorCanvas));
 }
+#endif
+
+#if ENABLE(WEBGPU)
+Ref<InspectorShaderProgram> InspectorShaderProgram::create(WebGPUPipeline& pipeline, InspectorCanvas& inspectorCanvas)
+{
+    return adoptRef(*new InspectorShaderProgram(pipeline, inspectorCanvas));
+}
+#endif
 
+#if ENABLE(WEBGL)
 InspectorShaderProgram::InspectorShaderProgram(WebGLProgram& program, InspectorCanvas& inspectorCanvas)
     : m_identifier("program:" + IdentifiersFactory::createIdentifier())
+    , m_canvas(inspectorCanvas)
     , m_program(program)
+{
+    ASSERT(is<WebGLRenderingContextBase>(m_canvas.canvasContext()));
+}
+#endif
+
+#if ENABLE(WEBGPU)
+InspectorShaderProgram::InspectorShaderProgram(WebGPUPipeline& pipeline, InspectorCanvas& inspectorCanvas)
+    : m_identifier("pipeline:" + IdentifiersFactory::createIdentifier())
     , m_canvas(inspectorCanvas)
+    , m_program(pipeline)
+{
+    ASSERT(m_canvas.deviceContext());
+}
+#endif
+
+#if ENABLE(WEBGL)
+WebGLProgram* InspectorShaderProgram::program() const
 {
+    if (auto* programWrapper = WTF::get_if<std::reference_wrapper<WebGLProgram>>(m_program))
+        return &programWrapper->get();
+    return nullptr;
 }
+#endif
 
-WebGLRenderingContextBase& InspectorShaderProgram::context() const
+#if ENABLE(WEBGPU)
+WebGPUPipeline* InspectorShaderProgram::pipeline() const
 {
-    ASSERT(m_canvas.canvasContext());
-    ASSERT(is<WebGLRenderingContextBase>(*m_canvas.canvasContext()));
-    return downcast<WebGLRenderingContextBase>(*m_canvas.canvasContext());
+    if (auto* pipelineWrapper = WTF::get_if<std::reference_wrapper<WebGPUPipeline>>(m_program))
+        return &pipelineWrapper->get();
+    return nullptr;
 }
+#endif
 
-WebGLShader* InspectorShaderProgram::shaderForType(const String& protocolType)
+#if ENABLE(WEBGL)
+static WebGLShader* shaderForType(WebGLProgram& program, Inspector::Protocol::Canvas::ShaderType shaderType)
 {
-    GC3Denum shaderType;
-    if (protocolType == "vertex")
-        shaderType = GraphicsContext3D::VERTEX_SHADER;
-    else if (protocolType == "fragment")
-        shaderType = GraphicsContext3D::FRAGMENT_SHADER;
-    else
+    switch (shaderType) {
+    case Inspector::Protocol::Canvas::ShaderType::Fragment:
+        return program.getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER);
+
+    case Inspector::Protocol::Canvas::ShaderType::Vertex:
+        return program.getAttachedShader(GraphicsContext3D::VERTEX_SHADER);
+
+    // Compute shaders are a WebGPU concept.
+    case Inspector::Protocol::Canvas::ShaderType::Compute:
         return nullptr;
+    }
 
-    return m_program.getAttachedShader(shaderType);
+    ASSERT_NOT_REACHED();
+    return nullptr;
 }
+#endif
 
-} // namespace WebCore
+#if ENABLE(WEBGPU)
+static Optional<WebGPUPipeline::ShaderData> shaderForType(WebGPUPipeline& pipeline, Inspector::Protocol::Canvas::ShaderType shaderType)
+{
+    switch (shaderType) {
+    case Inspector::Protocol::Canvas::ShaderType::Compute:
+        if (is<WebGPUComputePipeline>(pipeline))
+            return downcast<WebGPUComputePipeline>(pipeline).computeShader();
+        return WTF::nullopt;
+
+    case Inspector::Protocol::Canvas::ShaderType::Fragment:
+        if (is<WebGPURenderPipeline>(pipeline))
+            return downcast<WebGPURenderPipeline>(pipeline).fragmentShader();
+        return WTF::nullopt;
+
+    case Inspector::Protocol::Canvas::ShaderType::Vertex:
+        if (is<WebGPURenderPipeline>(pipeline))
+            return downcast<WebGPURenderPipeline>(pipeline).vertexShader();
+        return WTF::nullopt;
+    }
+
+    ASSERT_NOT_REACHED();
+    return WTF::nullopt;
+}
+#endif
+
+String InspectorShaderProgram::requestShaderSource(Inspector::Protocol::Canvas::ShaderType shaderType)
+{
+#if !ENABLE(WEBGL) && !ENABLE(WEBGPU)
+    UNUSED_PARAM(shaderType);
+#endif
+
+    return WTF::switchOn(m_program,
+#if ENABLE(WEBGL)
+        [&] (std::reference_wrapper<WebGLProgram> programWrapper) {
+            auto& program = programWrapper.get();
+            if (auto* shader = shaderForType(program, shaderType))
+                return shader->getSource();
+            return String();
+        },
+#endif
+#if ENABLE(WEBGPU)
+        [&] (std::reference_wrapper<WebGPUPipeline> pipelineWrapper) {
+            auto& pipeline = pipelineWrapper.get();
+            if (auto shaderData = shaderForType(pipeline, shaderType)) {
+                if (auto module = shaderData.value().module)
+                    return module->source();
+            }
+            return String();
+        },
+#endif
+        [&] (Monostate) {
+#if ENABLE(WEBGL) || ENABLE(WEBGPU)
+            ASSERT_NOT_REACHED();
+#endif
+            return String();
+        }
+    );
+}
+
+bool InspectorShaderProgram::updateShader(Inspector::Protocol::Canvas::ShaderType shaderType, const String& source)
+{
+#if !ENABLE(WEBGL) && !ENABLE(WEBGPU)
+    UNUSED_PARAM(shaderType);
+    UNUSED_PARAM(source);
+#endif
 
-#endif // ENABLE(WEBGL)
+    return WTF::switchOn(m_program,
+#if ENABLE(WEBGL)
+        [&] (std::reference_wrapper<WebGLProgram> programWrapper) {
+            auto& program = programWrapper.get();
+            if (auto* shader = shaderForType(program, shaderType)) {
+                if (auto* context = m_canvas.canvasContext()) {
+                    if (is<WebGLRenderingContextBase>(context)) {
+                        auto& contextWebGLBase = downcast<WebGLRenderingContextBase>(*context);
+                        contextWebGLBase.shaderSource(shader, source);
+                        contextWebGLBase.compileShader(shader);
+                        if (shader->isValid()) {
+                            contextWebGLBase.linkProgramWithoutInvalidatingAttribLocations(&program);
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        },
+#endif
+#if ENABLE(WEBGPU)
+        [&] (std::reference_wrapper<WebGPUPipeline> pipelineWrapper) {
+            auto& pipeline = pipelineWrapper.get();
+            if (auto* device = m_canvas.deviceContext()) {
+                if (auto shaderData = shaderForType(pipeline, shaderType)) {
+                    if (auto module = shaderData.value().module) {
+                        module->update(*device, source);
+                        if (pipeline.recompile(*device))
+                            return true;
+                    }
+                }
+            }
+            return false;
+        },
+#endif
+        [&] (Monostate) {
+#if ENABLE(WEBGL) || ENABLE(WEBGPU)
+            ASSERT_NOT_REACHED();
+#endif
+            return false;
+        }
+    );
+}
+
+} // namespace WebCore
index 9467e84..0e0e116 100644 (file)
 #pragma once
 
 #include <JavaScriptCore/InspectorProtocolObjects.h>
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
 
 namespace WebCore {
 
 class InspectorCanvas;
+
+#if ENABLE(WEBGL)
 class WebGLProgram;
 class WebGLRenderingContextBase;
-class WebGLShader;
+#endif
 
-typedef String ErrorString;
+#if ENABLE(WEBGPU)
+class WebGPUPipeline;
+#endif
 
 class InspectorShaderProgram final : public RefCounted<InspectorShaderProgram> {
 public:
+#if ENABLE(WEBGL)
     static Ref<InspectorShaderProgram> create(WebGLProgram&, InspectorCanvas&);
+#endif
+#if ENABLE(WEBGPU)
+    static Ref<InspectorShaderProgram> create(WebGPUPipeline&, InspectorCanvas&);
+#endif
 
     const String& identifier() const { return m_identifier; }
     InspectorCanvas& canvas() const { return m_canvas; }
-    WebGLRenderingContextBase& context() const;
-    WebGLProgram& program() const { return m_program; }
-    WebGLShader* shaderForType(const String&);
+
+#if ENABLE(WEBGL)
+    WebGLProgram* program() const;
+#endif
+#if ENABLE(WEBGPU)
+    WebGPUPipeline* pipeline() const;
+#endif
+
+    String requestShaderSource(Inspector::Protocol::Canvas::ShaderType);
+    bool updateShader(Inspector::Protocol::Canvas::ShaderType, const String& source);
 
     bool disabled() const { return m_disabled; }
     void setDisabled(bool disabled) { m_disabled = disabled; }
@@ -52,15 +70,27 @@ public:
     bool highlighted() const { return m_highlighted; }
     void setHighlighted(bool value) { m_highlighted = value; }
 
-    ~InspectorShaderProgram() = default;
-
 private:
+#if ENABLE(WEBGL)
     InspectorShaderProgram(WebGLProgram&, InspectorCanvas&);
+#endif
+#if ENABLE(WEBGPU)
+    InspectorShaderProgram(WebGPUPipeline&, InspectorCanvas&);
+#endif
 
     String m_identifier;
-    WebGLProgram& m_program;
     InspectorCanvas& m_canvas;
 
+    Variant<
+#if ENABLE(WEBGL)
+        std::reference_wrapper<WebGLProgram>,
+#endif
+#if ENABLE(WEBGPU)
+        std::reference_wrapper<WebGPUPipeline>,
+#endif
+        Monostate
+    > m_program;
+
     bool m_disabled { false };
     bool m_highlighted { false };
 };
index 1852248..30321a6 100644 (file)
@@ -35,6 +35,7 @@
 #include "HTMLCanvasElement.h"
 #include "ImageBitmapRenderingContext.h"
 #include "InspectorDOMAgent.h"
+#include "InspectorShaderProgram.h"
 #include "InstrumentingAgents.h"
 #include "JSExecState.h"
 #include "Microtasks.h"
 #include <JavaScriptCore/InjectedScriptManager.h>
 #include <JavaScriptCore/InspectorProtocolObjects.h>
 #include <JavaScriptCore/JSCInlines.h>
+#include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 #include <wtf/Lock.h>
+#include <wtf/Optional.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
 
 #if ENABLE(WEBGL)
 #include "WebGLProgram.h"
 #include "WebGLRenderingContext.h"
 #include "WebGLRenderingContextBase.h"
-#include "WebGLShader.h"
 #endif
 
 #if ENABLE(WEBGL2)
 
 #if ENABLE(WEBGPU)
 #include "GPUCanvasContext.h"
+#include "WebGPUComputePipeline.h"
 #include "WebGPUDevice.h"
+#include "WebGPUPipeline.h"
+#include "WebGPURenderPipeline.h"
+#include "WebGPUSwapChain.h"
 #endif
 
 namespace WebCore {
@@ -76,6 +85,7 @@ InspectorCanvasAgent::InspectorCanvasAgent(PageAgentContext& context)
     , m_injectedScriptManager(context.injectedScriptManager)
     , m_inspectedPage(context.inspectedPage)
     , m_canvasDestroyedTimer(*this, &InspectorCanvasAgent::canvasDestroyedTimerFired)
+    , m_programDestroyedTimer(*this, &InspectorCanvasAgent::programDestroyedTimerFired)
 {
 }
 
@@ -93,7 +103,7 @@ void InspectorCanvasAgent::willDestroyFrontendAndBackend(Inspector::DisconnectRe
 
 void InspectorCanvasAgent::discardAgent()
 {
-    clearCanvasData();
+    reset();
 }
 
 void InspectorCanvasAgent::enable(ErrorString&)
@@ -141,7 +151,17 @@ void InspectorCanvasAgent::enable(ErrorString&)
         LockHolder lock(WebGLProgram::instancesMutex());
         for (auto& [program, contextWebGLBase] : WebGLProgram::instances(lock)) {
             if (contextWebGLBase && existsInCurrentPage(contextWebGLBase->canvasBase().scriptExecutionContext()))
-                didCreateProgram(*contextWebGLBase, *program);
+                didCreateWebGLProgram(*contextWebGLBase, *program);
+        }
+    }
+#endif
+
+#if ENABLE(WEBGPU)
+    {
+        LockHolder lock(WebGPUPipeline::instancesMutex());
+        for (auto& [pipeline, device] : WebGPUPipeline::instances(lock)) {
+            if (device && existsInCurrentPage(device->scriptExecutionContext()) && pipeline->isValid())
+                didCreateWebGPUPipeline(*device, *pipeline);
         }
     }
 #endif
@@ -151,7 +171,7 @@ void InspectorCanvasAgent::disable(ErrorString&)
 {
     m_instrumentingAgents.setInspectorCanvasAgent(nullptr);
 
-    clearCanvasData();
+    reset();
 
     m_recordingAutoCaptureFrameCount = WTF::nullopt;
 }
@@ -280,93 +300,65 @@ void InspectorCanvasAgent::stopRecording(ErrorString& errorString, const String&
     didFinishRecordingCanvasFrame(*context, true);
 }
 
-void InspectorCanvasAgent::requestShaderSource(ErrorString& errorString, const String& programId, const String& shaderType, String* content)
+void InspectorCanvasAgent::requestShaderSource(ErrorString& errorString, const String& programId, const String& shaderTypeString, String* outSource)
 {
-#if ENABLE(WEBGL)
     auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
-    auto* shader = inspectorProgram->shaderForType(shaderType);
-    if (!shader) {
-        errorString = "Missing shader for given shaderType"_s;
+    auto shaderType = Inspector::Protocol::InspectorHelpers::parseEnumValueFromString<Inspector::Protocol::Canvas::ShaderType>(shaderTypeString);
+    if (!shaderType) {
+        errorString = makeString("Unknown shaderType: "_s, shaderTypeString);
         return;
     }
 
-    *content = shader->getSource();
-#else
-    UNUSED_PARAM(programId);
-    UNUSED_PARAM(shaderType);
-    UNUSED_PARAM(content);
-    errorString = "Not supported"_s;
-#endif
+    auto source = inspectorProgram->requestShaderSource(shaderType.value());
+    if (!source) {
+        errorString = "Missing shader of given shaderType for given programId"_s;
+        return;
+    }
+
+    *outSource = source;
 }
 
-void InspectorCanvasAgent::updateShader(ErrorString& errorString, const String& programId, const String& shaderType, const String& source)
+void InspectorCanvasAgent::updateShader(ErrorString& errorString, const String& programId, const String& shaderTypeString, const String& source)
 {
-#if ENABLE(WEBGL)
     auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
-    auto* shader = inspectorProgram->shaderForType(shaderType);
-    if (!shader) {
-        errorString = "Missing shader for given shaderType"_s;
-        return;
-    }
-
-    WebGLRenderingContextBase& contextWebGL = inspectorProgram->context();
-    contextWebGL.shaderSource(shader, source);
-    contextWebGL.compileShader(shader);
-
-    if (!shader->isValid()) {
-        errorString = "Failed to update shader"_s;
+    auto shaderType = Inspector::Protocol::InspectorHelpers::parseEnumValueFromString<Inspector::Protocol::Canvas::ShaderType>(shaderTypeString);
+    if (!shaderType) {
+        errorString = makeString("Unknown shaderType: "_s, shaderTypeString);
         return;
     }
 
-    contextWebGL.linkProgramWithoutInvalidatingAttribLocations(&inspectorProgram->program());
-#else
-    UNUSED_PARAM(programId);
-    UNUSED_PARAM(shaderType);
-    UNUSED_PARAM(source);
-    errorString = "Not supported"_s;
-#endif
+    if (!inspectorProgram->updateShader(shaderType.value(), source))
+        errorString = "Failed to update shader of given shaderType for given programId"_s;
 }
 
 void InspectorCanvasAgent::setShaderProgramDisabled(ErrorString& errorString, const String& programId, bool disabled)
 {
-#if ENABLE(WEBGL)
     auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
     inspectorProgram->setDisabled(disabled);
-#else
-    UNUSED_PARAM(programId);
-    UNUSED_PARAM(disabled);
-    errorString = "Not supported"_s;
-#endif
 }
 
 void InspectorCanvasAgent::setShaderProgramHighlighted(ErrorString& errorString, const String& programId, bool highlighted)
 {
-#if ENABLE(WEBGL)
     auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
     inspectorProgram->setHighlighted(highlighted);
-#else
-    UNUSED_PARAM(programId);
-    UNUSED_PARAM(highlighted);
-    errorString = "Not supported"_s;
-#endif
 }
 
 void InspectorCanvasAgent::frameNavigated(Frame& frame)
 {
     if (frame.isMainFrame()) {
-        clearCanvasData();
+        reset();
         return;
     }
 
@@ -568,7 +560,7 @@ void InspectorCanvasAgent::didEnableExtension(WebGLRenderingContextBase& context
     m_frontendDispatcher->extensionEnabled(inspectorCanvas->identifier(), extension);
 }
 
-void InspectorCanvasAgent::didCreateProgram(WebGLRenderingContextBase& context, WebGLProgram& program)
+void InspectorCanvasAgent::didCreateWebGLProgram(WebGLRenderingContextBase& context, WebGLProgram& program)
 {
     auto inspectorCanvas = findInspectorCanvas(context);
     ASSERT(inspectorCanvas);
@@ -578,20 +570,19 @@ void InspectorCanvasAgent::didCreateProgram(WebGLRenderingContextBase& context,
     auto inspectorProgram = InspectorShaderProgram::create(program, *inspectorCanvas);
     String programIdentifier = inspectorProgram->identifier();
     m_identifierToInspectorProgram.set(programIdentifier, WTFMove(inspectorProgram));
-    m_frontendDispatcher->programCreated(inspectorCanvas->identifier(), programIdentifier);
+    m_frontendDispatcher->programCreated(inspectorCanvas->identifier(), programIdentifier, Inspector::Protocol::Canvas::ProgramType::Render);
 }
 
-void InspectorCanvasAgent::willDeleteProgram(WebGLProgram& program)
+void InspectorCanvasAgent::willDestroyWebGLProgram(WebGLProgram& program)
 {
     auto inspectorProgram = findInspectorProgram(program);
     if (!inspectorProgram)
         return;
 
-    String identifier = unbindProgram(*inspectorProgram);
-    m_frontendDispatcher->programDeleted(identifier);
+    unbindProgram(*inspectorProgram);
 }
 
-bool InspectorCanvasAgent::isShaderProgramDisabled(WebGLProgram& program)
+bool InspectorCanvasAgent::isWebGLProgramDisabled(WebGLProgram& program)
 {
     auto inspectorProgram = findInspectorProgram(program);
     ASSERT(inspectorProgram);
@@ -601,7 +592,7 @@ bool InspectorCanvasAgent::isShaderProgramDisabled(WebGLProgram& program)
     return inspectorProgram->disabled();
 }
 
-bool InspectorCanvasAgent::isShaderProgramHighlighted(WebGLProgram& program)
+bool InspectorCanvasAgent::isWebGLProgramHighlighted(WebGLProgram& program)
 {
     auto inspectorProgram = findInspectorProgram(program);
     ASSERT(inspectorProgram);
@@ -649,6 +640,38 @@ void InspectorCanvasAgent::willConfigureSwapChain(GPUCanvasContext& contextGPU,
 
     notifyDeviceForSwapChain(newSwapChain);
 }
+
+void InspectorCanvasAgent::didCreateWebGPUPipeline(WebGPUDevice& device, WebGPUPipeline& pipeline)
+{
+    auto inspectorCanvas = findInspectorCanvas(device);
+    ASSERT(inspectorCanvas);
+    if (!inspectorCanvas)
+        return;
+
+    ASSERT(pipeline.isValid());
+
+    auto inspectorProgram = InspectorShaderProgram::create(pipeline, *inspectorCanvas);
+    String programIdentifier = inspectorProgram->identifier();
+    m_identifierToInspectorProgram.set(programIdentifier, WTFMove(inspectorProgram));
+
+    Optional<Inspector::Protocol::Canvas::ProgramType> programType;
+    if (is<WebGPUComputePipeline>(pipeline))
+        programType = Inspector::Protocol::Canvas::ProgramType::Compute;
+    else if (is<WebGPURenderPipeline>(pipeline))
+        programType = Inspector::Protocol::Canvas::ProgramType::Render;
+    ASSERT(programType);
+
+    m_frontendDispatcher->programCreated(inspectorCanvas->identifier(), programIdentifier, programType.value());
+}
+
+void InspectorCanvasAgent::willDestroyWebGPUPipeline(WebGPUPipeline& pipeline)
+{
+    auto inspectorProgram = findInspectorProgram(pipeline);
+    if (!inspectorProgram)
+        return;
+
+    unbindProgram(*inspectorProgram);
+}
 #endif
 
 void InspectorCanvasAgent::startRecording(InspectorCanvas& inspectorCanvas, Inspector::Protocol::Recording::Initiator initiator, RecordingOptions&& recordingOptions)
@@ -694,7 +717,18 @@ void InspectorCanvasAgent::canvasDestroyedTimerFired()
     m_removedCanvasIdentifiers.clear();
 }
 
-void InspectorCanvasAgent::clearCanvasData()
+void InspectorCanvasAgent::programDestroyedTimerFired()
+{
+    if (!m_removedProgramIdentifiers.size())
+        return;
+
+    for (auto& identifier : m_removedProgramIdentifiers)
+        m_frontendDispatcher->programDeleted(identifier);
+
+    m_removedProgramIdentifiers.clear();
+}
+
+void InspectorCanvasAgent::reset()
 {
     for (auto& inspectorCanvas : m_identifierToInspectorCanvas.values()) {
         if (auto* context = inspectorCanvas->canvasContext())
@@ -702,13 +736,14 @@ void InspectorCanvasAgent::clearCanvasData()
     }
 
     m_identifierToInspectorCanvas.clear();
-#if ENABLE(WEBGL)
-    m_identifierToInspectorProgram.clear();
     m_removedCanvasIdentifiers.clear();
-#endif
-
     if (m_canvasDestroyedTimer.isActive())
         m_canvasDestroyedTimer.stop();
+
+    m_identifierToInspectorProgram.clear();
+    m_removedProgramIdentifiers.clear();
+    if (m_programDestroyedTimer.isActive())
+        m_programDestroyedTimer.stop();
 }
 
 InspectorCanvas& InspectorCanvasAgent::bindCanvas(CanvasRenderingContext& context, bool captureBacktrace)
@@ -805,13 +840,18 @@ RefPtr<InspectorCanvas> InspectorCanvasAgent::findInspectorCanvas(WebGPUDevice&
 }
 #endif
 
-#if ENABLE(WEBGL)
-String InspectorCanvasAgent::unbindProgram(InspectorShaderProgram& inspectorProgram)
+void InspectorCanvasAgent::unbindProgram(InspectorShaderProgram& inspectorProgram)
 {
     String identifier = inspectorProgram.identifier();
     m_identifierToInspectorProgram.remove(identifier);
 
-    return identifier;
+    // This can be called in response to GC. Due to the single-process model used in WebKit1, the
+    // event must be dispatched from a timer to prevent the frontend from making JS allocations
+    // while the GC is still active.
+    m_removedProgramIdentifiers.append(identifier);
+
+    if (!m_programDestroyedTimer.isActive())
+        m_programDestroyedTimer.startOneShot(0_s);
 }
 
 RefPtr<InspectorShaderProgram> InspectorCanvasAgent::assertInspectorProgram(ErrorString& errorString, const String& programId)
@@ -824,10 +864,22 @@ RefPtr<InspectorShaderProgram> InspectorCanvasAgent::assertInspectorProgram(Erro
     return inspectorProgram;
 }
 
+#if ENABLE(WEBGL)
 RefPtr<InspectorShaderProgram> InspectorCanvasAgent::findInspectorProgram(WebGLProgram& program)
 {
     for (auto& inspectorProgram : m_identifierToInspectorProgram.values()) {
-        if (&inspectorProgram->program() == &program)
+        if (inspectorProgram->program() == &program)
+            return inspectorProgram;
+    }
+    return nullptr;
+}
+#endif
+
+#if ENABLE(WEBGPU)
+RefPtr<InspectorShaderProgram> InspectorCanvasAgent::findInspectorProgram(WebGPUPipeline& pipeline)
+{
+    for (auto& inspectorProgram : m_identifierToInspectorProgram.values()) {
+        if (inspectorProgram->pipeline() == &pipeline)
             return inspectorProgram;
     }
     return nullptr;
index baedd46..60c56e9 100644 (file)
 #include <JavaScriptCore/InspectorBackendDispatchers.h>
 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
 #include <initializer_list>
-#include <wtf/HashMap.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
-#include <wtf/text/WTFString.h>
-
-#if ENABLE(WEBGL)
-#include "InspectorShaderProgram.h"
-#endif
+#include <wtf/Forward.h>
 
 namespace Inspector {
 class InjectedScriptManager;
@@ -49,6 +42,7 @@ class InjectedScriptManager;
 namespace WebCore {
 
 class CanvasRenderingContext;
+class InspectorShaderProgram;
 #if ENABLE(WEBGL)
 class WebGLProgram;
 class WebGLRenderingContextBase;
@@ -56,6 +50,7 @@ class WebGLRenderingContextBase;
 #if ENABLE(WEBGPU)
 class GPUCanvasContext;
 class WebGPUDevice;
+class WebGPUPipeline;
 class WebGPUSwapChain;
 #endif
 
@@ -83,7 +78,7 @@ public:
     void setRecordingAutoCaptureFrameCount(ErrorString&, int count);
     void startRecording(ErrorString&, const String& canvasId, const int* frameCount, const int* memoryLimit);
     void stopRecording(ErrorString&, const String& canvasId);
-    void requestShaderSource(ErrorString&, const String& programId, const String& shaderType, String*);
+    void requestShaderSource(ErrorString&, const String& programId, const String& shaderType, String* source);
     void updateShader(ErrorString&, const String& programId, const String& shaderType, const String& source);
     void setShaderProgramDisabled(ErrorString&, const String& programId, bool disabled);
     void setShaderProgramHighlighted(ErrorString&, const String& programId, bool highlighted);
@@ -103,15 +98,17 @@ public:
     void consoleStartRecordingCanvas(CanvasRenderingContext&, JSC::ExecState&, JSC::JSObject* options);
 #if ENABLE(WEBGL)
     void didEnableExtension(WebGLRenderingContextBase&, const String&);
-    void didCreateProgram(WebGLRenderingContextBase&, WebGLProgram&);
-    void willDeleteProgram(WebGLProgram&);
-    bool isShaderProgramDisabled(WebGLProgram&);
-    bool isShaderProgramHighlighted(WebGLProgram&);
+    void didCreateWebGLProgram(WebGLRenderingContextBase&, WebGLProgram&);
+    void willDestroyWebGLProgram(WebGLProgram&);
+    bool isWebGLProgramDisabled(WebGLProgram&);
+    bool isWebGLProgramHighlighted(WebGLProgram&);
 #endif
 #if ENABLE(WEBGPU)
     void didCreateWebGPUDevice(WebGPUDevice&);
     void willDestroyWebGPUDevice(WebGPUDevice&);
     void willConfigureSwapChain(GPUCanvasContext&, WebGPUSwapChain&);
+    void didCreateWebGPUPipeline(WebGPUDevice&, WebGPUPipeline&);
+    void willDestroyWebGPUPipeline(WebGPUPipeline&);
 #endif
 
 private:
@@ -123,7 +120,9 @@ private:
     void startRecording(InspectorCanvas&, Inspector::Protocol::Recording::Initiator, RecordingOptions&& = { });
 
     void canvasDestroyedTimerFired();
-    void clearCanvasData();
+    void programDestroyedTimerFired();
+    void reset();
+
     InspectorCanvas& bindCanvas(CanvasRenderingContext&, bool captureBacktrace);
 #if ENABLE(WEBGPU)
     InspectorCanvas& bindCanvas(WebGPUDevice&, bool captureBacktrace);
@@ -135,11 +134,14 @@ private:
     RefPtr<InspectorCanvas> findInspectorCanvas(WebGPUDevice&);
 #endif
 
-#if ENABLE(WEBGL)
-    String unbindProgram(InspectorShaderProgram&);
+    void unbindProgram(InspectorShaderProgram&);
     RefPtr<InspectorShaderProgram> assertInspectorProgram(ErrorString&, const String& programId);
+#if ENABLE(WEBGL)
     RefPtr<InspectorShaderProgram> findInspectorProgram(WebGLProgram&);
 #endif
+#if ENABLE(WEBGPU)
+    RefPtr<InspectorShaderProgram> findInspectorProgram(WebGPUPipeline&);
+#endif
 
     std::unique_ptr<Inspector::CanvasFrontendDispatcher> m_frontendDispatcher;
     RefPtr<Inspector::CanvasBackendDispatcher> m_backendDispatcher;
@@ -148,14 +150,14 @@ private:
     Page& m_inspectedPage;
 
     HashMap<String, RefPtr<InspectorCanvas>> m_identifierToInspectorCanvas;
-#if ENABLE(WEBGL)
-    HashMap<String, RefPtr<InspectorShaderProgram>> m_identifierToInspectorProgram;
-#endif
     Vector<String> m_removedCanvasIdentifiers;
+    Timer m_canvasDestroyedTimer;
 
-    Optional<size_t> m_recordingAutoCaptureFrameCount;
+    HashMap<String, RefPtr<InspectorShaderProgram>> m_identifierToInspectorProgram;
+    Vector<String> m_removedProgramIdentifiers;
+    Timer m_programDestroyedTimer;
 
-    Timer m_canvasDestroyedTimer;
+    Optional<size_t> m_recordingAutoCaptureFrameCount;
 };
 
 } // namespace WebCore
index cafc6e4..391ceae 100644 (file)
@@ -27,6 +27,8 @@
 
 #if ENABLE(WEBGPU)
 
+#include "GPUPipeline.h"
+#include "GPUProgrammableStageDescriptor.h"
 #include "WHLSLPrepare.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
@@ -38,27 +40,39 @@ namespace WebCore {
 
 class GPUDevice;
 class GPUErrorScopes;
+class GPUPipelineLayout;
 
 struct GPUComputePipelineDescriptor;
 
 using PlatformComputePipeline = MTLComputePipelineState;
 using PlatformComputePipelineSmartPtr = RetainPtr<MTLComputePipelineState>;
 
-class GPUComputePipeline : public RefCounted<GPUComputePipeline> {
+class GPUComputePipeline final : public GPUPipeline {
 public:
+    virtual ~GPUComputePipeline();
+
     static RefPtr<GPUComputePipeline> tryCreate(const GPUDevice&, const GPUComputePipelineDescriptor&, GPUErrorScopes&);
 
+    bool isComputePipeline() const { return true; }
+
+    bool recompile(const GPUDevice&, GPUProgrammableStageDescriptor&& computeStage);
+
     const PlatformComputePipeline* platformComputePipeline() const { return m_platformComputePipeline.get(); }
 
     WHLSL::ComputeDimensions computeDimensions() const { return m_computeDimensions; }
 
 private:
-    GPUComputePipeline(PlatformComputePipelineSmartPtr&&, WHLSL::ComputeDimensions);
+    GPUComputePipeline(PlatformComputePipelineSmartPtr&&, WHLSL::ComputeDimensions, const RefPtr<GPUPipelineLayout>&);
 
     PlatformComputePipelineSmartPtr m_platformComputePipeline;
     WHLSL::ComputeDimensions m_computeDimensions { 0, 0, 0 };
+
+    // Preserved for Web Inspector recompilation.
+    RefPtr<GPUPipelineLayout> m_layout;
 };
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_GPUPIPELINE(WebCore::GPUComputePipeline, isComputePipeline())
+
 #endif // ENABLE(WEBGPU)
diff --git a/Source/WebCore/platform/graphics/gpu/GPUPipeline.cpp b/Source/WebCore/platform/graphics/gpu/GPUPipeline.cpp
new file mode 100644 (file)
index 0000000..7c88165
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GPUPipeline.h"
+
+#if ENABLE(WEBGPU)
+
+namespace WebCore {
+
+GPUPipeline::~GPUPipeline() = default;
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGPU)
diff --git a/Source/WebCore/platform/graphics/gpu/GPUPipeline.h b/Source/WebCore/platform/graphics/gpu/GPUPipeline.h
new file mode 100644 (file)
index 0000000..942ee8d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBGPU)
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class GPUPipeline : public RefCounted<GPUPipeline> {
+public:
+    virtual ~GPUPipeline();
+
+    virtual bool isRenderPipeline() const { return false; }
+    virtual bool isComputePipeline() const { return false; }
+};
+
+} // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_GPUPIPELINE(ToValueTypeName, predicate) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
+    static bool isType(const WebCore::GPUPipeline& pipeline) { return pipeline.predicate; } \
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // ENABLE(WEBGPU)
index 0ee1afa..27c0628 100644 (file)
@@ -38,13 +38,13 @@ struct GPUProgrammableStageDescriptorBase {
 };
 
 struct GPUProgrammableStageDescriptor : GPUProgrammableStageDescriptorBase {
-    GPUProgrammableStageDescriptor(Ref<const GPUShaderModule>&& module, const GPUProgrammableStageDescriptorBase& base)
+    GPUProgrammableStageDescriptor(Ref<GPUShaderModule>&& module, const GPUProgrammableStageDescriptorBase& base)
         : GPUProgrammableStageDescriptorBase(base)
         , module { WTFMove(module) }
     {
     }
 
-    Ref<const GPUShaderModule> module;
+    Ref<GPUShaderModule> module;
 };
 
 } // namespace WebCore
index 83c8e1d..ac2583f 100644 (file)
@@ -27,6 +27,8 @@
 
 #if ENABLE(WEBGPU)
 
+#include "GPUPipeline.h"
+#include "GPUProgrammableStageDescriptor.h"
 #include "GPURenderPipelineDescriptor.h"
 #include <wtf/Optional.h>
 #include <wtf/RefCounted.h>
@@ -46,10 +48,16 @@ class GPUErrorScopes;
 using PlatformRenderPipeline = MTLRenderPipelineState;
 using PlatformRenderPipelineSmartPtr = RetainPtr<MTLRenderPipelineState>;
 
-class GPURenderPipeline : public RefCounted<GPURenderPipeline> {
+class GPURenderPipeline final : public GPUPipeline {
 public:
+    virtual ~GPURenderPipeline();
+
     static RefPtr<GPURenderPipeline> tryCreate(const GPUDevice&, const GPURenderPipelineDescriptor&, GPUErrorScopes&);
 
+    bool isRenderPipeline() const { return true; }
+
+    bool recompile(const GPUDevice&, GPUProgrammableStageDescriptor&& vertexStage, Optional<GPUProgrammableStageDescriptor>&& fragmentStage);
+
 #if USE(METAL)
     MTLDepthStencilState *depthStencilState() const { return m_depthStencilState.get(); }
 #endif
@@ -59,15 +67,21 @@ public:
 
 private:
 #if USE(METAL)
-    GPURenderPipeline(RetainPtr<MTLDepthStencilState>&&, PlatformRenderPipelineSmartPtr&&, GPUPrimitiveTopology, Optional<GPUIndexFormat>);
+    GPURenderPipeline(RetainPtr<MTLDepthStencilState>&&, PlatformRenderPipelineSmartPtr&&, GPUPrimitiveTopology, Optional<GPUIndexFormat>, const RefPtr<GPUPipelineLayout>&, const GPURenderPipelineDescriptorBase&);
 
     RetainPtr<MTLDepthStencilState> m_depthStencilState;
 #endif // USE(METAL)
     PlatformRenderPipelineSmartPtr m_platformRenderPipeline;
     GPUPrimitiveTopology m_primitiveTopology;
     Optional<GPUIndexFormat> m_indexFormat;
+
+    // Preserved for Web Inspector recompilation.
+    RefPtr<GPUPipelineLayout> m_layout;
+    GPURenderPipelineDescriptorBase m_renderDescriptorBase;
 };
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_GPUPIPELINE(WebCore::GPURenderPipeline, isRenderPipeline())
+
 #endif // ENABLE(WEBGPU)
index 7d8f8b2..c2000a1 100644 (file)
@@ -31,6 +31,7 @@
 #import "GPUComputePipelineDescriptor.h"
 #import "GPUDevice.h"
 #import "GPUErrorScopes.h"
+#import "GPUPipelineLayout.h"
 #import "GPUPipelineMetalConvertLayout.h"
 #import "WHLSLPrepare.h"
 #import <Metal/Metal.h>
@@ -194,15 +195,32 @@ RefPtr<GPUComputePipeline> GPUComputePipeline::tryCreate(const GPUDevice& device
     if (!createResult)
         return nullptr;
 
-    return adoptRef(new GPUComputePipeline(WTFMove(createResult->pipelineState), createResult->computeDimensions));
+    return adoptRef(new GPUComputePipeline(WTFMove(createResult->pipelineState), createResult->computeDimensions, descriptor.layout));
 }
 
-GPUComputePipeline::GPUComputePipeline(RetainPtr<MTLComputePipelineState>&& pipeline, WHLSL::ComputeDimensions computeDimensions)
-    : m_platformComputePipeline(WTFMove(pipeline))
+GPUComputePipeline::GPUComputePipeline(RetainPtr<MTLComputePipelineState>&& pipeline, WHLSL::ComputeDimensions computeDimensions, const RefPtr<GPUPipelineLayout>& layout)
+    : GPUPipeline()
+    , m_platformComputePipeline(WTFMove(pipeline))
     , m_computeDimensions(computeDimensions)
+    , m_layout(layout)
 {
 }
 
+GPUComputePipeline::~GPUComputePipeline() = default;
+
+bool GPUComputePipeline::recompile(const GPUDevice& device, GPUProgrammableStageDescriptor&& computeStage)
+{
+    GPUComputePipelineDescriptor descriptor(makeRefPtr(m_layout.get()), WTFMove(computeStage));
+    auto errorScopes = GPUErrorScopes::create([] (GPUError&&) { });
+    if (auto createResult = tryCreateMTLComputePipelineState(device, descriptor, errorScopes)) {
+        m_platformComputePipeline = WTFMove(createResult->pipelineState);
+        m_computeDimensions = createResult->computeDimensions;
+        return true;
+    }
+
+    return false;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGPU)
index 2824087..044f1fe 100644 (file)
@@ -32,6 +32,7 @@
 #import "GPUErrorScopes.h"
 #import "GPULimits.h"
 #import "GPUPipelineMetalConvertLayout.h"
+#import "GPURenderPipelineDescriptor.h"
 #import "GPUUtils.h"
 #import "WHLSLPrepare.h"
 #import "WHLSLVertexBufferIndexCalculator.h"
@@ -483,7 +484,7 @@ static RetainPtr<MTLRenderPipelineDescriptor> convertRenderPipelineDescriptor(co
     return mtlDescriptor;
 }
 
-static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device, GPUErrorScopes& errorScopes)
+static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const GPUDevice& device, const GPURenderPipelineDescriptor& descriptor, GPUErrorScopes& errorScopes)
 {
     if (!device.platformDevice()) {
         errorScopes.generatePrefixedError("Invalid GPUDevice!");
@@ -522,21 +523,38 @@ RefPtr<GPURenderPipeline> GPURenderPipeline::tryCreate(const GPUDevice& device,
 
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198387 depthStencilAttachmentDescriptor isn't implemented yet for WHLSL compiler.
 
-    auto pipeline = tryCreateMtlRenderPipelineState(descriptor, device, errorScopes);
+    auto pipeline = tryCreateMtlRenderPipelineState(device, descriptor, errorScopes);
     if (!pipeline)
         return nullptr;
 
-    return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.vertexInput.indexFormat));
+    return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.vertexInput.indexFormat, descriptor.layout, descriptor));
 }
 
-GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology, Optional<GPUIndexFormat> format)
-    : m_depthStencilState(WTFMove(depthStencil))
+GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology, Optional<GPUIndexFormat> format, const RefPtr<GPUPipelineLayout>& layout, const GPURenderPipelineDescriptorBase& renderDescriptorBase)
+    : GPUPipeline()
+    , m_depthStencilState(WTFMove(depthStencil))
     , m_platformRenderPipeline(WTFMove(pipeline))
     , m_primitiveTopology(topology)
     , m_indexFormat(format)
+    , m_layout(layout)
+    , m_renderDescriptorBase(renderDescriptorBase)
 {
 }
 
+GPURenderPipeline::~GPURenderPipeline() = default;
+
+bool GPURenderPipeline::recompile(const GPUDevice& device, GPUProgrammableStageDescriptor&& vertexStage, Optional<GPUProgrammableStageDescriptor>&& fragmentStage)
+{
+    GPURenderPipelineDescriptor descriptor(makeRefPtr(m_layout.get()), WTFMove(vertexStage), WTFMove(fragmentStage), m_renderDescriptorBase);
+    auto errorScopes = GPUErrorScopes::create([] (GPUError&&) { });
+    if (auto pipeline = tryCreateMtlRenderPipelineState(device, descriptor, errorScopes)) {
+        m_platformRenderPipeline = WTFMove(pipeline);
+        return true;
+    }
+
+    return false;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGPU)
index 9aae834..dd4b1ed 100644 (file)
@@ -1,3 +1,79 @@
+2019-09-23  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Canvas: show WebGPU shader pipelines
+        https://bugs.webkit.org/show_bug.cgi?id=201675
+        <rdar://problem/55543450>
+
+        Reviewed by Joseph Pecoraro.
+
+        Show WebGPU shader pipelines ("programs") underneath each corresponding WebGPU device.
+
+        Allow editing of attached shader modules for each WebGPU shader pipeline, but don't allow
+        highlighting/disabling, as WebGPU pipelines don't have those capabilities/concepts yet.
+
+        * UserInterface/Protocol/CanvasObserver.js:
+        (WI.CanvasObserver.prototype.programCreated):
+        * UserInterface/Controllers/CanvasManager.js:
+        (WI.CanvasManager.prototype.programCreated):
+
+        * UserInterface/Models/Canvas.js:
+        (WI.Canvas.prototype.nextShaderProgramDisplayNumberForProgramType): Added.
+        (WI.Canvas.prototype.nextShaderProgramDisplayNumber): Deleted.
+
+        * UserInterface/Models/ShaderProgram.js:
+        (WI.ShaderProgram):
+        (WI.ShaderProgram.contextTypeSupportsProgramType): Added.
+        (WI.ShaderProgram.programTypeSupportsShaderType): Added.
+        (WI.ShaderProgram.prototype.get programType): Added.
+        (WI.ShaderProgram.prototype.get displayName):
+        (WI.ShaderProgram.prototype.set disabled):
+        (WI.ShaderProgram.prototype.requestShaderSource):
+        (WI.ShaderProgram.prototype.updateShader):
+        (WI.ShaderProgram.prototype.showHighlight):
+        (WI.ShaderProgram.prototype.hideHighlight):
+        (WI.ShaderProgram.prototype.requestVertexShaderSource): Deleted.
+        (WI.ShaderProgram.prototype.requestFragmentShaderSource): Deleted.
+        (WI.ShaderProgram.prototype.updateVertexShader): Deleted.
+        (WI.ShaderProgram.prototype.updateFragmentShader): Deleted.
+        (WI.ShaderProgram.prototype._requestShaderSource): Deleted.
+        (WI.ShaderProgram.prototype._updateShader): Deleted.
+
+        * UserInterface/Views/ShaderProgramContentView.js:
+        (WI.ShaderProgramContentView):
+        (WI.ShaderProgramContentView.prototype.get navigationItems): Added.
+        (WI.ShaderProgramContentView.prototype.shown):
+        (WI.ShaderProgramContentView.prototype.hidden):
+        (WI.ShaderProgramContentView.prototype.get saveData):
+        (WI.ShaderProgramContentView.prototype._refreshContent):
+        (WI.ShaderProgramContentView.prototype._updateShader):
+        (WI.ShaderProgramContentView.prototype._contentDidChange):
+        * UserInterface/Views/ShaderProgramContentView.css:
+        (.content-view.shader-program > .shader): Added.
+        (.content-view.shader-program > .shader.compute): Added.
+        (body[dir=ltr] .content-view.shader-program > .shader.vertex,): Added.
+        (body[dir=ltr] .content-view.shader-program > .shader.fragment,): Added.
+        (.content-view.shader-program > .shader + .shader): Added.
+        (.content-view.shader-program > .shader > header > *): Added.
+        (.content-view.shader-program > .shader > header > .shader-type): Added.
+        (@media (prefers-color-scheme: dark) .content-view.shader-program > .shader > header): Added.
+        (.content-view.shader-program > .text-editor.shader): Deleted.
+        (body[dir=ltr] .content-view.shader-program > .text-editor.shader.vertex,): Deleted.
+        (body[dir=ltr] .content-view.shader-program > .text-editor.shader.fragment,): Deleted.
+        (body[dir=ltr] .content-view.shader-program > .text-editor.shader + .text-editor.shader): Deleted.
+        (body[dir=rtl] .content-view.shader-program > .text-editor.shader + .text-editor.shader): Deleted.
+        (.content-view.shader-program > .text-editor.shader > .type-title): Deleted.
+        (.content-view.shader-program > .text-editor.shader > .CodeMirror): Deleted.
+        * UserInterface/Views/CodeMirrorAdditions.js:
+
+        * UserInterface/Views/ShaderProgramTreeElement.js:
+        (WI.ShaderProgramTreeElement):
+        (WI.ShaderProgramTreeElement.prototype.onattach):
+        (WI.ShaderProgramTreeElement.prototype.ondetach):
+        (WI.ShaderProgramTreeElement.prototype.canSelectOnMouseDown):
+        (WI.ShaderProgramTreeElement.prototype.populateContextMenu):
+
+        * Localizations/en.lproj/localizedStrings.js:
+
 2019-09-23  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Improve the Uncaught Exception View file a bug link
index d8d1251..2c13e72 100644 (file)
@@ -266,6 +266,9 @@ localizedStrings["Composited"] = "Composited";
 localizedStrings["Compressed"] = "Compressed";
 localizedStrings["Compression"] = "Compression";
 localizedStrings["Compression:"] = "Compression:";
+localizedStrings["Compute"] = "Compute";
+localizedStrings["Compute Pipeline %d"] = "Compute Pipeline %d";
+localizedStrings["Compute Shader"] = "Compute Shader";
 localizedStrings["Computed"] = "Computed";
 localizedStrings["Condition"] = "Condition";
 localizedStrings["Conditional expression"] = "Conditional expression";
@@ -463,6 +466,7 @@ localizedStrings["Ensure that only one main content section is used on the page.
 localizedStrings["Ensure that values for \u0022%s\u0022 are valid."] = "Ensure that values for \u0022%s\u0022 are valid.";
 localizedStrings["Entered Full-Screen Mode"] = "Entered Full-Screen Mode";
 localizedStrings["Entire Recording"] = "Entire Recording";
+localizedStrings["Entry point: "] = "Entry point: ";
 localizedStrings["Error"] = "Error";
 localizedStrings["Error: "] = "Error: ";
 localizedStrings["Errors"] = "Errors";
@@ -880,6 +884,7 @@ localizedStrings["Remove Watch Expression"] = "Remove Watch Expression";
 localizedStrings["Remove probe"] = "Remove probe";
 localizedStrings["Remove this breakpoint action"] = "Remove this breakpoint action";
 localizedStrings["Removed descendant "] = "Removed descendant ";
+localizedStrings["Render Pipeline %d"] = "Render Pipeline %d";
 localizedStrings["Rendering Frames"] = "Rendering Frames";
 localizedStrings["Repeating Linear Gradient"] = "Repeating Linear Gradient";
 localizedStrings["Repeating Radial Gradient"] = "Repeating Radial Gradient";
@@ -996,7 +1001,6 @@ localizedStrings["Session Storage"] = "Session Storage";
 localizedStrings["Set to Automatically Continue"] = "Set to Automatically Continue";
 localizedStrings["Setter"] = "Setter";
 localizedStrings["Settings"] = "Settings";
-localizedStrings["Shader"] = "Shader";
 localizedStrings["Shader Programs"] = "Shader Programs";
 localizedStrings["Shadow Content"] = "Shadow Content";
 localizedStrings["Shadow Content (%s)"] = "Shadow Content (%s)";
index 389cb71..38f01bb 100644 (file)
@@ -234,7 +234,7 @@ WI.CanvasManager = class CanvasManager extends WI.Object
         canvas.enableExtension(extension);
     }
 
-    programCreated(canvasIdentifier, programIdentifier)
+    programCreated(canvasIdentifier, programIdentifier, programType)
     {
         let canvas = this._canvasIdentifierMap.get(canvasIdentifier);
         console.assert(canvas);
@@ -243,7 +243,11 @@ WI.CanvasManager = class CanvasManager extends WI.Object
 
         console.assert(!this._shaderProgramIdentifierMap.has(programIdentifier), `ShaderProgram already exists with id ${programIdentifier}.`);
 
-        let program = new WI.ShaderProgram(programIdentifier, canvas);
+        // COMPATIBILITY (iOS 13): `programType` did not exist yet.
+        if (!programType)
+            programType = WI.ShaderProgram.ProgramType.Render;
+
+        let program = new WI.ShaderProgram(programIdentifier, programType, canvas);
         this._shaderProgramIdentifierMap.set(program.identifier, program);
 
         canvas.shaderProgramCollection.add(program);
index b929f06..7d56ec1 100644 (file)
@@ -45,7 +45,7 @@ WI.Canvas = class Canvas extends WI.Object
         this._shaderProgramCollection = new WI.ShaderProgramCollection;
         this._recordingCollection = new WI.RecordingCollection;
 
-        this._nextShaderProgramDisplayNumber = 1;
+        this._nextShaderProgramDisplayNumber = null;
 
         this._requestNodePromise = null;
 
@@ -409,11 +409,15 @@ WI.Canvas = class Canvas extends WI.Object
         this.dispatchEventToListeners(WI.Canvas.Event.RecordingStopped, {recording, initiatedByUser});
     }
 
-    nextShaderProgramDisplayNumber()
+    nextShaderProgramDisplayNumberForProgramType(programType)
     {
         // Called from WI.ShaderProgram.
 
-        return this._nextShaderProgramDisplayNumber++;
+        if (!this._nextShaderProgramDisplayNumber)
+            this._nextShaderProgramDisplayNumber = {};
+
+        this._nextShaderProgramDisplayNumber[programType] = (this._nextShaderProgramDisplayNumber[programType] || 0) + 1;
+        return this._nextShaderProgramDisplayNumber[programType];
     }
 };
 
index c1ed9c8..c9b6e03 100644 (file)
 
 WI.ShaderProgram = class ShaderProgram extends WI.Object
 {
-    constructor(identifier, canvas)
+    constructor(identifier, programType, canvas)
     {
         console.assert(identifier);
+        console.assert(Object.values(ShaderProgram.ProgramType).includes(programType));
         console.assert(canvas instanceof WI.Canvas);
+        console.assert(ShaderProgram.contextTypeSupportsProgramType(canvas.contextType, programType));
 
         super();
 
         this._identifier = identifier;
+        this._programType = programType;
         this._canvas = canvas;
-        this._uniqueDisplayNumber = canvas.nextShaderProgramDisplayNumber();
         this._disabled = false;
     }
 
+    // Static
+
+    static contextTypeSupportsProgramType(contextType, programType)
+    {
+        switch (contextType) {
+        case WI.Canvas.ContextType.WebGL:
+        case WI.Canvas.ContextType.WebGL2:
+            return programType === ShaderProgram.ProgramType.Render;
+
+        case WI.Canvas.ContextType.WebGPU:
+            return programType === ShaderProgram.ProgramType.Compute
+                || programType === ShaderProgram.ProgramType.Render;
+        }
+
+        console.assert();
+        return false;
+    }
+
+    static programTypeSupportsShaderType(programType, shaderType)
+    {
+        switch (programType) {
+        case ShaderProgram.ProgramType.Compute:
+            return shaderType === ShaderProgram.ShaderType.Compute;
+
+        case ShaderProgram.ProgramType.Render:
+            return shaderType === ShaderProgram.ShaderType.Fragment
+                || shaderType === ShaderProgram.ShaderType.Vertex;
+        }
+
+        console.assert();
+        return false;
+    }
+
     // Public
 
     get identifier() { return this._identifier; }
+    get programType() { return this._programType; }
     get canvas() { return this._canvas; }
 
     get displayName()
     {
-        return WI.UIString("Program %d").format(this._uniqueDisplayNumber);
+        let format = null;
+        switch (this._canvas.contextType) {
+        case WI.Canvas.ContextType.WebGL:
+        case WI.Canvas.ContextType.WebGL2:
+            format = WI.UIString("Program %d");
+            break;
+        case WI.Canvas.ContextType.WebGPU:
+            switch (this._programType) {
+            case ShaderProgram.ProgramType.Compute:
+                format = WI.UIString("Compute Pipeline %d");
+                break;
+            case ShaderProgram.ProgramType.Render:
+                format = WI.UIString("Render Pipeline %d");
+                break;
+            }
+            break;
+        }
+        console.assert(format);
+        if (!this._uniqueDisplayNumber)
+            this._uniqueDisplayNumber = this._canvas.nextShaderProgramDisplayNumberForProgramType(this._programType);
+        return format.format(this._uniqueDisplayNumber);
     }
 
     get disabled()
@@ -55,6 +111,12 @@ WI.ShaderProgram = class ShaderProgram extends WI.Object
 
     set disabled(disabled)
     {
+        console.assert(this._programType === ShaderProgram.ProgramType.Render);
+        console.assert(this._canvas.contextType === WI.Canvas.ContextType.WebGL || this._canvas.contextType === WI.Canvas.ContextType.WebGL2);
+
+        if (this._canvas.contextType === WI.Canvas.ContextType.WebGPU)
+            return;
+
         if (this._disabled === disabled)
             return;
 
@@ -65,67 +127,57 @@ WI.ShaderProgram = class ShaderProgram extends WI.Object
         this.dispatchEventToListeners(ShaderProgram.Event.DisabledChanged);
     }
 
-    requestVertexShaderSource(callback)
+    requestShaderSource(shaderType, callback)
     {
-        this._requestShaderSource(CanvasAgent.ShaderType.Vertex, callback);
-    }
+        console.assert(Object.values(ShaderProgram.ShaderType).includes(shaderType));
+        console.assert(ShaderProgram.programTypeSupportsShaderType(this._programType, shaderType));
 
-    requestFragmentShaderSource(callback)
-    {
-        this._requestShaderSource(CanvasAgent.ShaderType.Fragment, callback);
-    }
+        // COMPATIBILITY (iOS 13): `content` was renamed to `source`.
+        CanvasAgent.requestShaderSource(this._identifier, shaderType, (error, source) => {
+            if (error) {
+                WI.reportInternalError(error);
+                callback(null);
+                return;
+            }
 
-    updateVertexShader(source)
-    {
-        this._updateShader(CanvasAgent.ShaderType.Vertex, source);
+            callback(source);
+        });
     }
 
-    updateFragmentShader(source)
+    updateShader(shaderType, source)
     {
-        this._updateShader(CanvasAgent.ShaderType.Fragment, source);
+        console.assert(Object.values(ShaderProgram.ShaderType).includes(shaderType));
+        console.assert(ShaderProgram.programTypeSupportsShaderType(this._programType, shaderType));
+
+        CanvasAgent.updateShader(this._identifier, shaderType, source);
     }
 
     showHighlight()
     {
-        const highlighted = true;
-        CanvasAgent.setShaderProgramHighlighted(this._identifier, highlighted, (error) => {
-            console.assert(!error, error);
-        });
+        console.assert(this._programType === ShaderProgram.ProgramType.Render);
+        console.assert(this._canvas.contextType === WI.Canvas.ContextType.WebGL || this._canvas.contextType === WI.Canvas.ContextType.WebGL2);
+
+        CanvasAgent.setShaderProgramHighlighted(this._identifier, true);
     }
 
     hideHighlight()
     {
-        const highlighted = false;
-        CanvasAgent.setShaderProgramHighlighted(this._identifier, highlighted, (error) => {
-            console.assert(!error, error);
-        });
-    }
-
-    // Private
+        console.assert(this._programType === ShaderProgram.ProgramType.Render);
+        console.assert(this._canvas.contextType === WI.Canvas.ContextType.WebGL || this._canvas.contextType === WI.Canvas.ContextType.WebGL2);
 
-    _requestShaderSource(shaderType, callback)
-    {
-        CanvasAgent.requestShaderSource(this._identifier, shaderType, (error, content) => {
-            if (error) {
-                callback(null);
-                return;
-            }
-
-            callback(content);
-        });
+        CanvasAgent.setShaderProgramHighlighted(this._identifier, false);
     }
+};
 
-    _updateShader(shaderType, source)
-    {
-        CanvasAgent.updateShader(this._identifier, shaderType, source, (error) => {
-            console.assert(!error, error);
-        });
-    }
+WI.ShaderProgram.ProgramType = {
+    Compute: "compute",
+    Render: "render",
 };
 
 WI.ShaderProgram.ShaderType = {
-    Fragment: "shader-type-fragment",
-    Vertex: "shader-type-vertex",
+    Compute: "compute",
+    Fragment: "fragment",
+    Vertex: "vertex",
 };
 
 WI.ShaderProgram.Event = {
index 3e5dd6c..6f53574 100644 (file)
@@ -67,9 +67,9 @@ WI.CanvasObserver = class CanvasObserver
         WI.canvasManager.extensionEnabled(canvasId, extension);
     }
 
-    programCreated(canvasId, programId)
+    programCreated(canvasId, programId, programType)
     {
-        WI.canvasManager.programCreated(canvasId, programId);
+        WI.canvasManager.programCreated(canvasId, programId, programType);
     }
 
     programDeleted(programId)
index 9afc4ab..3a3aadf 100644 (file)
     extraJSONTypes.forEach(function(type) {
         CodeMirror.defineMIME(type, {name: "javascript", json: true});
     });
+
+    // FIXME: Add WHLSL specific modes.
+    CodeMirror.defineMIME("x-pipeline/x-compute", "x-shader/x-vertex");
+    CodeMirror.defineMIME("x-pipeline/x-fragment", "x-shader/x-fragment");
+    CodeMirror.defineMIME("x-pipeline/x-vertex", "x-shader/x-vertex");
 })();
 
 WI.compareCodeMirrorPositions = function(a, b)
index 55ef41f..0d0a77a 100644 (file)
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-.content-view.shader-program > .text-editor.shader {
+.content-view.shader-program > .shader {
+    display: flex;
+    flex-direction: column;
     position: absolute;
     top: 0;
     bottom: 0;
+}
 
-    --border-start-style: 1px solid lightgrey;
+.content-view.shader-program > .shader.compute {
+    right: 0;
+    left: 0;
 }
 
-body[dir=ltr] .content-view.shader-program > .text-editor.shader.vertex,
-body[dir=rtl] .content-view.shader-program > .text-editor.shader.fragment {
+body[dir=ltr] .content-view.shader-program > .shader.vertex,
+body[dir=rtl] .content-view.shader-program > .shader.fragment {
     width: calc(50% - 1px);
     left: 0;
 }
 
-body[dir=ltr] .content-view.shader-program > .text-editor.shader.fragment,
-body[dir=rtl] .content-view.shader-program > .text-editor.shader.vertex {
+body[dir=ltr] .content-view.shader-program > .shader.fragment,
+body[dir=rtl] .content-view.shader-program > .shader.vertex {
     width: calc(50% + 1px);
     right: 0;
 }
 
-body[dir=ltr] .content-view.shader-program > .text-editor.shader + .text-editor.shader {
-    border-left: var(--border-start-style);
-}
-
-body[dir=rtl] .content-view.shader-program > .text-editor.shader + .text-editor.shader {
-    border-right: var(--border-start-style);
+.content-view.shader-program > .shader + .shader {
+    border-left: 1px solid var(--border-color);
 }
 
-.content-view.shader-program > .text-editor.shader > .type-title {
+.content-view.shader-program > .shader > header > * {
     padding: 2px 4px;
-    background-color: hsl(0, 0%, 95%);
     border-bottom: 1px solid lightgrey;
 }
 
-.content-view.shader-program > .text-editor.shader > .CodeMirror {
-    top: 18px;
+.content-view.shader-program > .shader > header > .shader-type {
+    background-color: hsl(0, 0%, 95%);
 }
 
 @media (prefers-color-scheme: dark) {
-    .content-view.shader-program > .text-editor.shader {
-        --border-start-style: 1px solid var(--text-color-quaternary);
-    }
-
-    .content-view.shader-program > .text-editor.shader > .type-title {
+    .content-view.shader-program > .shader > header {
         background-color: var(--background-color);
         border-bottom-color: var(--text-color-quaternary);
     }
index dd9254e..42645d8 100644 (file)
@@ -31,13 +31,26 @@ WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentV
 
         super(shaderProgram);
 
+        let isWebGPU = this.representedObject.contextType === WI.Canvas.ContextType.WebGPU;
+
+        this._refreshButtonNavigationItem = new WI.ButtonNavigationItem("refresh", WI.UIString("Refresh"), "Images/ReloadFull.svg", 13, 13);
+        this._refreshButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
+        this._refreshButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._refreshContent, this);
+
         let contentDidChangeDebouncer = new Debouncer((event) => {
             this._contentDidChange(event);
         });
 
-        this.element.classList.add("shader-program");
+        this.element.classList.add("shader-program", this.representedObject.programType);
 
         let createEditor = (shaderType) => {
+            let container = this.element.appendChild(document.createElement("div"));
+
+            let header = container.appendChild(document.createElement("header"));
+
+            let shaderTypeContainer = header.appendChild(document.createElement("div"));
+            shaderTypeContainer.classList.add("shader-type");
+
             let textEditor = new WI.TextEditor;
             textEditor.readOnly = false;
             textEditor.addEventListener(WI.TextEditor.Event.Focused, this._editorFocused, this);
@@ -45,32 +58,61 @@ WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentV
             textEditor.addEventListener(WI.TextEditor.Event.ContentDidChange, (event) => {
                 contentDidChangeDebouncer.delayForTime(250, event);
             }, this);
-            textEditor.element.classList.add("shader");
-
-            let shaderTypeContainer = textEditor.element.insertAdjacentElement("afterbegin", document.createElement("div"));
-            shaderTypeContainer.classList.add("type-title");
 
             switch (shaderType) {
-            case WI.ShaderProgram.ShaderType.Vertex:
-                shaderTypeContainer.textContent = WI.UIString("Vertex Shader");
-                textEditor.mimeType = "x-shader/x-vertex";
-                textEditor.element.classList.add("vertex");
+            case WI.ShaderProgram.ShaderType.Compute:
+                shaderTypeContainer.textContent = WI.UIString("Compute Shader");
+                textEditor.mimeType = isWebGPU ? "x-pipeline/x-compute" : "x-shader/x-compute";
                 break;
 
             case WI.ShaderProgram.ShaderType.Fragment:
                 shaderTypeContainer.textContent = WI.UIString("Fragment Shader");
-                textEditor.mimeType = "x-shader/x-fragment";
-                textEditor.element.classList.add("fragment");
+                textEditor.mimeType = isWebGPU ? "x-pipeline/x-fragment" : "x-shader/x-fragment";
+                break;
+
+            case WI.ShaderProgram.ShaderType.Vertex:
+                shaderTypeContainer.textContent = WI.UIString("Vertex Shader");
+                textEditor.mimeType = isWebGPU ? "x-pipeline/x-vertex" : "x-shader/x-vertex";
                 break;
             }
 
             this.addSubview(textEditor);
-            return textEditor;
+            container.appendChild(textEditor.element);
+            container.classList.add("shader", shaderType);
+
+            return {container, textEditor};
         };
 
-        this._vertexEditor = createEditor(WI.ShaderProgram.ShaderType.Vertex);
-        this._fragmentEditor = createEditor(WI.ShaderProgram.ShaderType.Fragment);
-        this._lastActiveEditor = this._vertexEditor;
+        switch (this.representedObject.programType) {
+        case WI.ShaderProgram.ProgramType.Compute: {
+            let computeEditor = createEditor(WI.ShaderProgram.ShaderType.Compute);
+            this._computeContainer = computeEditor.container;
+            this._computeEditor = computeEditor.textEditor;
+
+            this._lastActiveEditor = this._computeEditor;
+            break;
+        }
+
+        case WI.ShaderProgram.ProgramType.Render: {
+            let vertexEditor = createEditor(WI.ShaderProgram.ShaderType.Vertex);
+            this._vertexContainer = vertexEditor.container;
+            this._vertexEditor = vertexEditor.textEditor;
+
+            let fragmentEditor = createEditor(WI.ShaderProgram.ShaderType.Fragment);
+            this._fragmentContainer = fragmentEditor.container;
+            this._fragmentEditor = fragmentEditor.textEditor;
+
+            this._lastActiveEditor = this._vertexEditor;
+            break;
+        }
+        }
+    }
+
+    // Public
+
+    get navigationItems()
+    {
+        return [this._refreshButtonNavigationItem];
     }
 
     // Protected
@@ -79,22 +121,32 @@ WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentV
     {
         super.shown();
 
-        this._vertexEditor.shown();
-        this._fragmentEditor.shown();
+        switch (this.representedObject.programType) {
+        case WI.ShaderProgram.ProgramType.Compute:
+            this._computeEditor.shown();
+            break;
 
-        this.representedObject.requestVertexShaderSource((content) => {
-            this._vertexEditor.string = content || "";
-        });
+        case WI.ShaderProgram.ProgramType.Render:
+            this._vertexEditor.shown();
+            this._fragmentEditor.shown();
+            break;
+        }
 
-        this.representedObject.requestFragmentShaderSource((content) => {
-            this._fragmentEditor.string = content || "";
-        });
+        this._refreshContent();
     }
 
     hidden()
     {
-        this._vertexEditor.hidden();
-        this._fragmentEditor.hidden();
+        switch (this.representedObject.programType) {
+        case WI.ShaderProgram.ProgramType.Compute:
+            this._computeEditor.hidden();
+            break;
+
+        case WI.ShaderProgram.ProgramType.Render:
+            this._vertexEditor.hidden();
+            this._fragmentEditor.hidden();
+            break;
+        }
 
         super.hidden();
     }
@@ -106,14 +158,34 @@ WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentV
 
     get saveData()
     {
-        let filename = WI.UIString("Shader");
-        if (this._lastActiveEditor === this._vertexEditor)
-            filename = WI.UIString("Vertex");
-        else if (this._lastActiveEditor === this._fragmentEditor)
+        let filename = "";
+        switch (this._lastActiveEditor) {
+        case this._computeEditor:
+            filename = WI.UIString("Compute");
+            break;
+        case this._fragmentEditor:
             filename = WI.UIString("Fragment");
+            break;
+        case this._vertexEditor:
+            filename = WI.UIString("Vertex");
+            break;
+        }
+        console.assert(filename);
+
+        let extension = "";
+        switch (this.representedObject.canvas.contextType) {
+        case WI.Canvas.ContextType.WebGL:
+        case WI.Canvas.ContextType.WebGL2:
+            extension = WI.unlocalizedString(".glsl");
+            break;
+        case WI.Canvas.ContextType.WebGPU:
+            extension = WI.unlocalizedString(".wsl");
+            break;
+        }
+        console.assert(extension);
 
         return {
-            url: WI.FileUtilities.inspectorURLForFilename(filename + ".glsl"),
+            url: WI.FileUtilities.inspectorURLForFilename(filename + extension),
             content: this._lastActiveEditor.string,
             forceSaveAs: true,
         };
@@ -171,6 +243,65 @@ WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentV
 
     // Private
 
+    _refreshContent()
+    {
+        let createCallback = (container, textEditor) => {
+            return (source) => {
+                if (source === null) {
+                    container.remove();
+                    return;
+                }
+
+                if (!container.parentNode) {
+                    switch (container) {
+                    case this._computeContainer:
+                    case this._vertexContainer:
+                        this.element.insertAdjacentElement("afterbegin", container);
+                        break;
+
+                    case this._fragmentContainer:
+                        this.element.insertAdjacentElement("beforeend", container);
+                        break;
+                    }
+                }
+
+                textEditor.string = source || "";
+            };
+        };
+
+        switch (this.representedObject.programType) {
+        case WI.ShaderProgram.ProgramType.Compute:
+            this.representedObject.requestShaderSource(WI.ShaderProgram.ShaderType.Compute, createCallback(this._computeContainer, this._computeEditor));
+            return;
+
+        case WI.ShaderProgram.ProgramType.Render:
+            this.representedObject.requestShaderSource(WI.ShaderProgram.ShaderType.Vertex, createCallback(this._vertexContainer, this._vertexEditor));
+            this.representedObject.requestShaderSource(WI.ShaderProgram.ShaderType.Fragment, createCallback(this._fragmentContainer, this._fragmentEditor));
+            return;
+        }
+
+        console.assert();
+    }
+
+    _updateShader(shaderType)
+    {
+        switch (shaderType) {
+        case WI.ShaderProgram.ShaderType.Compute:
+            this.representedObject.updateShader(shaderType, this._computeEditor.string);
+            return;
+
+        case WI.ShaderProgram.ShaderType.Fragment:
+            this.representedObject.updateShader(shaderType, this._fragmentEditor.string);
+            return;
+
+        case WI.ShaderProgram.ShaderType.Vertex:
+            this.representedObject.updateShader(shaderType, this._vertexEditor.string);
+            return;
+        }
+
+        console.assert();
+    }
+
     _editorFocused(event)
     {
         if (this._lastActiveEditor === event.target)
@@ -197,9 +328,20 @@ WI.ShaderProgramContentView = class ShaderProgramContentView extends WI.ContentV
 
     _contentDidChange(event)
     {
-        if (event.target === this._vertexEditor)
-            this.representedObject.updateVertexShader(this._vertexEditor.string);
-        else if (event.target === this._fragmentEditor)
-            this.representedObject.updateFragmentShader(this._fragmentEditor.string);
+        switch (event.target) {
+        case this._computeEditor:
+            this._updateShader(WI.ShaderProgram.ShaderType.Compute);
+            return;
+
+        case this._fragmentEditor:
+            this._updateShader(WI.ShaderProgram.ShaderType.Fragment);
+            return;
+
+        case this._vertexEditor:
+            this._updateShader(WI.ShaderProgram.ShaderType.Vertex);
+            return;
+        }
+
+        console.assert();
     }
 };
index cda75b4..c2d3f75 100644 (file)
@@ -32,10 +32,14 @@ WI.ShaderProgramTreeElement = class ShaderProgramTreeElement extends WI.GeneralT
         const subtitle = null;
         super("shader-program", shaderProgram.displayName, subtitle, shaderProgram);
 
-        this._disabledImageElement = document.createElement("img");
-        this._disabledImageElement.title = WI.UIString("Disable Program");
-        this._disabledImageElement.addEventListener("click", this._disabledImageElementClicked.bind(this));
-        this.status = this._disabledImageElement;
+        // FIXME: add support for disabling/highlighting WebGPU shader pipelines.
+        let contextType = this.representedObject.canvas.contextType;
+        if (contextType === WI.Canvas.ContextType.WebGL || contextType === WI.Canvas.ContextType.WebGL2) {
+            this._disabledImageElement = document.createElement("img");
+            this._disabledImageElement.title = WI.UIString("Disable Program");
+            this._disabledImageElement.addEventListener("click", this._disabledImageElementClicked.bind(this));
+            this.status = this._disabledImageElement;
+        }
     }
 
     // Protected
@@ -44,34 +48,45 @@ WI.ShaderProgramTreeElement = class ShaderProgramTreeElement extends WI.GeneralT
     {
         super.onattach();
 
-        this.representedObject.addEventListener(WI.ShaderProgram.Event.DisabledChanged, this._handleShaderProgramDisabledChanged, this);
+        // FIXME: add support for disabling/highlighting WebGPU shader pipelines.
+        let contextType = this.representedObject.canvas.contextType;
+        if (contextType === WI.Canvas.ContextType.WebGL || contextType === WI.Canvas.ContextType.WebGL2) {
+            this.representedObject.addEventListener(WI.ShaderProgram.Event.DisabledChanged, this._handleShaderProgramDisabledChanged, this);
 
-        this.element.addEventListener("mouseover", this._handleMouseOver.bind(this));
-        this.element.addEventListener("mouseout", this._handleMouseOut.bind(this));
+            this.element.addEventListener("mouseover", this._handleMouseOver.bind(this));
+            this.element.addEventListener("mouseout", this._handleMouseOut.bind(this));
+        }
     }
 
     ondetach()
     {
-        this.representedObject.removeEventListener(WI.ShaderProgram.Event.DisabledChanged, this._handleShaderProgramDisabledChanged, this);
+        // FIXME: add support for disabling/highlighting WebGPU shader pipelines.
+        let contextType = this.representedObject.canvas.contextType;
+        if (contextType === WI.Canvas.ContextType.WebGL || contextType === WI.Canvas.ContextType.WebGL2)
+            this.representedObject.removeEventListener(WI.ShaderProgram.Event.DisabledChanged, this._handleShaderProgramDisabledChanged, this);
 
         super.ondetach();
     }
 
     canSelectOnMouseDown(event)
     {
-        if (this._disabledImageElement.contains(event.target))
+        if (this._disabledImageElement && this._disabledImageElement.contains(event.target))
             return false;
         return super.canSelectOnMouseDown(event);
     }
 
     populateContextMenu(contextMenu, event)
     {
-        let disabled = this.representedObject.disabled;
-        contextMenu.appendItem(disabled ? WI.UIString("Enable Program") : WI.UIString("Disable Program"), () => {
-            this.representedObject.disabled = !disabled;
-        });
-
-        contextMenu.appendSeparator();
+        // FIXME: add support for disabling/highlighting WebGPU shader pipelines.
+        let contextType = this.representedObject.canvas.contextType;
+        if (contextType === WI.Canvas.ContextType.WebGL || contextType === WI.Canvas.ContextType.WebGL2) {
+            let disabled = this.representedObject.disabled;
+            contextMenu.appendItem(disabled ? WI.UIString("Enable Program") : WI.UIString("Disable Program"), () => {
+                this.representedObject.disabled = !disabled;
+            });
+
+            contextMenu.appendSeparator();
+        }
 
         super.populateContextMenu(contextMenu, event);
     }