Implement GPUCompilationInfo

Implements the GPUCompilationInfo and GPUCompilationMessage interfaces,
adds the GPUCompilationMessageType enum, and adds the compilationInfo
method to GPUShaderModule.

BUG: dawn:746
Change-Id: Ied70cbbfedbf4890916ec076993714e5042f70e4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/46600
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_wire/BUILD.gn b/src/dawn_wire/BUILD.gn
index ad72394..4a3f127 100644
--- a/src/dawn_wire/BUILD.gn
+++ b/src/dawn_wire/BUILD.gn
@@ -85,6 +85,8 @@
     "client/ObjectAllocator.h",
     "client/Queue.cpp",
     "client/Queue.h",
+    "client/ShaderModule.cpp",
+    "client/ShaderModule.h",
     "server/ObjectStorage.h",
     "server/Server.cpp",
     "server/Server.h",
@@ -93,6 +95,7 @@
     "server/ServerFence.cpp",
     "server/ServerInlineMemoryTransferService.cpp",
     "server/ServerQueue.cpp",
+    "server/ServerShaderModule.cpp",
   ]
 
   # Make headers publicly visible
diff --git a/src/dawn_wire/CMakeLists.txt b/src/dawn_wire/CMakeLists.txt
index 77e96c0..b1f9ba4 100644
--- a/src/dawn_wire/CMakeLists.txt
+++ b/src/dawn_wire/CMakeLists.txt
@@ -57,6 +57,8 @@
     "client/ObjectAllocator.h"
     "client/Queue.cpp"
     "client/Queue.h"
+    "client/ShaderModule.cpp"
+    "client/ShaderModule.h"
     "server/ObjectStorage.h"
     "server/Server.cpp"
     "server/Server.h"
@@ -65,6 +67,7 @@
     "server/ServerFence.cpp"
     "server/ServerInlineMemoryTransferService.cpp"
     "server/ServerQueue.cpp"
+    "server/ServerShaderModule.cpp"
 )
 target_link_libraries(dawn_wire
     PUBLIC dawn_headers
diff --git a/src/dawn_wire/client/ApiObjects.h b/src/dawn_wire/client/ApiObjects.h
index f842d53..8ec482a 100644
--- a/src/dawn_wire/client/ApiObjects.h
+++ b/src/dawn_wire/client/ApiObjects.h
@@ -21,6 +21,7 @@
 #include "dawn_wire/client/Device.h"
 #include "dawn_wire/client/Fence.h"
 #include "dawn_wire/client/Queue.h"
+#include "dawn_wire/client/ShaderModule.h"
 
 #include "dawn_wire/client/ApiObjects_autogen.h"
 
diff --git a/src/dawn_wire/client/ClientDoers.cpp b/src/dawn_wire/client/ClientDoers.cpp
index 2c6e23f..4073baa 100644
--- a/src/dawn_wire/client/ClientDoers.cpp
+++ b/src/dawn_wire/client/ClientDoers.cpp
@@ -122,4 +122,15 @@
         return device->OnCreateRenderPipelineAsyncCallback(requestSerial, status, message);
     }
 
+    bool Client::DoShaderModuleGetCompilationInfoCallback(ShaderModule* shaderModule,
+                                                          uint64_t requestSerial,
+                                                          WGPUCompilationInfoRequestStatus status,
+                                                          const WGPUCompilationInfo* info) {
+        // The shader module might have been deleted or recreated so this isn't an error.
+        if (shaderModule == nullptr) {
+            return true;
+        }
+        return shaderModule->GetCompilationInfoCallback(requestSerial, status, info);
+    }
+
 }}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/ShaderModule.cpp b/src/dawn_wire/client/ShaderModule.cpp
new file mode 100644
index 0000000..97e0204
--- /dev/null
+++ b/src/dawn_wire/client/ShaderModule.cpp
@@ -0,0 +1,66 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_wire/client/ShaderModule.h"
+
+#include "dawn_wire/client/Client.h"
+
+namespace dawn_wire { namespace client {
+
+    ShaderModule::~ShaderModule() {
+        // Callbacks need to be fired in all cases, as they can handle freeing resources. So we call
+        // them with "Unknown" status.
+        for (auto& it : mCompilationInfoRequests) {
+            if (it.second.callback) {
+                it.second.callback(WGPUCompilationInfoRequestStatus_Unknown, nullptr,
+                                   it.second.userdata);
+            }
+        }
+        mCompilationInfoRequests.clear();
+    }
+
+    void ShaderModule::GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata) {
+        if (client->IsDisconnected()) {
+            callback(WGPUCompilationInfoRequestStatus_DeviceLost, nullptr, userdata);
+            return;
+        }
+
+        uint64_t serial = mCompilationInfoRequestSerial++;
+        ShaderModuleGetCompilationInfoCmd cmd;
+        cmd.shaderModuleId = this->id;
+        cmd.requestSerial = serial;
+
+        mCompilationInfoRequests[serial] = {callback, userdata};
+
+        client->SerializeCommand(cmd);
+    }
+
+    bool ShaderModule::GetCompilationInfoCallback(uint64_t requestSerial,
+                                                  WGPUCompilationInfoRequestStatus status,
+                                                  const WGPUCompilationInfo* info) {
+        auto requestIt = mCompilationInfoRequests.find(requestSerial);
+        if (requestIt == mCompilationInfoRequests.end()) {
+            return false;
+        }
+
+        // Remove the request data so that the callback cannot be called again.
+        // ex.) inside the callback: if the shader module is deleted, all callbacks reject.
+        CompilationInfoRequest request = std::move(requestIt->second);
+        mCompilationInfoRequests.erase(requestIt);
+
+        request.callback(status, info, request.userdata);
+        return true;
+    }
+
+}}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/ShaderModule.h b/src/dawn_wire/client/ShaderModule.h
new file mode 100644
index 0000000..add5b97
--- /dev/null
+++ b/src/dawn_wire/client/ShaderModule.h
@@ -0,0 +1,46 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef DAWNWIRE_CLIENT_SHADER_MODULE_H_
+#define DAWNWIRE_CLIENT_SHADER_MODULE_H_
+
+#include <dawn/webgpu.h>
+
+#include "common/SerialMap.h"
+#include "dawn_wire/client/ObjectBase.h"
+
+namespace dawn_wire { namespace client {
+
+    class ShaderModule final : public ObjectBase {
+      public:
+        using ObjectBase::ObjectBase;
+        ~ShaderModule();
+
+        void GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata);
+        bool GetCompilationInfoCallback(uint64_t requestSerial,
+                                        WGPUCompilationInfoRequestStatus status,
+                                        const WGPUCompilationInfo* info);
+
+      private:
+        struct CompilationInfoRequest {
+            WGPUCompilationInfoCallback callback = nullptr;
+            void* userdata = nullptr;
+        };
+        uint64_t mCompilationInfoRequestSerial = 0;
+        std::map<uint64_t, CompilationInfoRequest> mCompilationInfoRequests;
+    };
+
+}}  // namespace dawn_wire::client
+
+#endif  // DAWNWIRE_CLIENT_SHADER_MODULE_H_
diff --git a/src/dawn_wire/server/Server.h b/src/dawn_wire/server/Server.h
index 1124cba..5baea19 100644
--- a/src/dawn_wire/server/Server.h
+++ b/src/dawn_wire/server/Server.h
@@ -141,6 +141,13 @@
         uint64_t requestSerial;
     };
 
+    struct ShaderModuleGetCompilationInfoUserdata : CallbackUserdata {
+        using CallbackUserdata::CallbackUserdata;
+
+        ObjectHandle shaderModule;
+        uint64_t requestSerial;
+    };
+
     struct QueueWorkDoneUserdata : CallbackUserdata {
         using CallbackUserdata::CallbackUserdata;
 
@@ -218,6 +225,9 @@
                                                  WGPURenderPipeline pipeline,
                                                  const char* message,
                                                  CreatePipelineAsyncUserData* userdata);
+        void OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status,
+                                              const WGPUCompilationInfo* info,
+                                              ShaderModuleGetCompilationInfoUserdata* userdata);
 
 #include "dawn_wire/server/ServerPrototypes_autogen.inc"
 
diff --git a/src/dawn_wire/server/ServerShaderModule.cpp b/src/dawn_wire/server/ServerShaderModule.cpp
new file mode 100644
index 0000000..cec0dc4
--- /dev/null
+++ b/src/dawn_wire/server/ServerShaderModule.cpp
@@ -0,0 +1,51 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_wire/server/Server.h"
+
+#include <memory>
+
+namespace dawn_wire { namespace server {
+
+    bool Server::DoShaderModuleGetCompilationInfo(ObjectId shaderModuleId, uint64_t requestSerial) {
+        auto* shaderModule = ShaderModuleObjects().Get(shaderModuleId);
+        if (shaderModule == nullptr) {
+            return false;
+        }
+
+        auto userdata = MakeUserdata<ShaderModuleGetCompilationInfoUserdata>();
+        userdata->shaderModule = ObjectHandle{shaderModuleId, shaderModule->generation};
+        userdata->requestSerial = requestSerial;
+
+        mProcs.shaderModuleGetCompilationInfo(
+            shaderModule->handle,
+            ForwardToServer<decltype(&Server::OnShaderModuleGetCompilationInfo)>::Func<
+                &Server::OnShaderModuleGetCompilationInfo>(),
+            userdata.release());
+        return true;
+    }
+
+    void Server::OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status,
+                                                  const WGPUCompilationInfo* info,
+                                                  ShaderModuleGetCompilationInfoUserdata* data) {
+        ReturnShaderModuleGetCompilationInfoCallbackCmd cmd;
+        cmd.shaderModule = data->shaderModule;
+        cmd.requestSerial = data->requestSerial;
+        cmd.status = status;
+        cmd.info = info;
+
+        SerializeCommand(cmd);
+    }
+
+}}  // namespace dawn_wire::server