Add the entry point of CreateReadyRenderPipeline

BUG=dawn:529
TEST=dawn_end2end_tests

Change-Id: I42ac0edc77e5b6119eb374da72698fca14596f7b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30540
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_wire/client/ClientDoers.cpp b/src/dawn_wire/client/ClientDoers.cpp
index 338863e..cd9b5ab 100644
--- a/src/dawn_wire/client/ClientDoers.cpp
+++ b/src/dawn_wire/client/ClientDoers.cpp
@@ -85,8 +85,13 @@
     bool Client::DoDeviceCreateReadyComputePipelineCallback(uint64_t requestSerial,
                                                             WGPUCreateReadyPipelineStatus status,
                                                             const char* message) {
-        mDevice->OnCreateReadyComputePipelineCallback(requestSerial, status, message);
-        return true;
+        return mDevice->OnCreateReadyComputePipelineCallback(requestSerial, status, message);
+    }
+
+    bool Client::DoDeviceCreateReadyRenderPipelineCallback(uint64_t requestSerial,
+                                                           WGPUCreateReadyPipelineStatus status,
+                                                           const char* message) {
+        return mDevice->OnCreateReadyRenderPipelineCallback(requestSerial, status, message);
     }
 
 }}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Device.cpp b/src/dawn_wire/client/Device.cpp
index fd175fe..b49f8a4 100644
--- a/src/dawn_wire/client/Device.cpp
+++ b/src/dawn_wire/client/Device.cpp
@@ -43,10 +43,18 @@
             it.second.callback(WGPUErrorType_Unknown, "Device destroyed", it.second.userdata);
         }
 
-        auto createReadyComputePipelineRequests = std::move(mCreateReadyComputePipelineRequests);
-        for (const auto& it : createReadyComputePipelineRequests) {
-            it.second.callback(WGPUCreateReadyPipelineStatus_Unknown, nullptr, "Device destroyed",
-                               it.second.userdata);
+        auto createReadyPipelineRequests = std::move(mCreateReadyPipelineRequests);
+        for (const auto& it : createReadyPipelineRequests) {
+            if (it.second.createReadyComputePipelineCallback != nullptr) {
+                it.second.createReadyComputePipelineCallback(WGPUCreateReadyPipelineStatus_Unknown,
+                                                             nullptr, "Device destroyed",
+                                                             it.second.userdata);
+            } else {
+                ASSERT(it.second.createReadyRenderPipelineCallback != nullptr);
+                it.second.createReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus_Unknown,
+                                                            nullptr, "Device destroyed",
+                                                            it.second.userdata);
+            }
         }
 
         // Destroy the default queue
@@ -170,33 +178,32 @@
         cmd.device = ToAPI(this);
         cmd.descriptor = descriptor;
 
-        uint64_t serial = mCreateReadyComputePipelineRequestSerial++;
-        ASSERT(mCreateReadyComputePipelineRequests.find(serial) ==
-               mCreateReadyComputePipelineRequests.end());
+        uint64_t serial = mCreateReadyPipelineRequestSerial++;
+        ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
         cmd.requestSerial = serial;
 
         auto* allocation = GetClient()->ComputePipelineAllocator().New(this);
-        CreateReadyComputePipelineRequest request = {};
-        request.callback = callback;
+        CreateReadyPipelineRequest request = {};
+        request.createReadyComputePipelineCallback = callback;
         request.userdata = userdata;
         request.pipelineObjectID = allocation->object->id;
 
         cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
         GetClient()->SerializeCommand(cmd);
 
-        mCreateReadyComputePipelineRequests[serial] = std::move(request);
+        mCreateReadyPipelineRequests[serial] = std::move(request);
     }
 
     bool Device::OnCreateReadyComputePipelineCallback(uint64_t requestSerial,
                                                       WGPUCreateReadyPipelineStatus status,
                                                       const char* message) {
-        const auto& requestIt = mCreateReadyComputePipelineRequests.find(requestSerial);
-        if (requestIt == mCreateReadyComputePipelineRequests.end()) {
+        const auto& requestIt = mCreateReadyPipelineRequests.find(requestSerial);
+        if (requestIt == mCreateReadyPipelineRequests.end()) {
             return false;
         }
 
-        CreateReadyComputePipelineRequest request = std::move(requestIt->second);
-        mCreateReadyComputePipelineRequests.erase(requestIt);
+        CreateReadyPipelineRequest request = std::move(requestIt->second);
+        mCreateReadyPipelineRequests.erase(requestIt);
 
         auto pipelineAllocation =
             GetClient()->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
@@ -205,14 +212,64 @@
         // free the allocation both on the client side and the server side.
         if (status != WGPUCreateReadyPipelineStatus_Success) {
             GetClient()->ComputePipelineAllocator().Free(pipelineAllocation);
-            request.callback(status, nullptr, message, request.userdata);
+            request.createReadyComputePipelineCallback(status, nullptr, message, request.userdata);
             return true;
         }
 
         WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation);
-        request.callback(status, pipeline, message, request.userdata);
+        request.createReadyComputePipelineCallback(status, pipeline, message, request.userdata);
 
         return true;
     }
 
+    void Device::CreateReadyRenderPipeline(WGPURenderPipelineDescriptor const* descriptor,
+                                           WGPUCreateReadyRenderPipelineCallback callback,
+                                           void* userdata) {
+        DeviceCreateReadyRenderPipelineCmd cmd;
+        cmd.device = ToAPI(this);
+        cmd.descriptor = descriptor;
+
+        uint64_t serial = mCreateReadyPipelineRequestSerial++;
+        ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
+        cmd.requestSerial = serial;
+
+        auto* allocation = GetClient()->RenderPipelineAllocator().New(this);
+        CreateReadyPipelineRequest request = {};
+        request.createReadyRenderPipelineCallback = callback;
+        request.userdata = userdata;
+        request.pipelineObjectID = allocation->object->id;
+
+        cmd.pipelineObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
+        GetClient()->SerializeCommand(cmd);
+
+        mCreateReadyPipelineRequests[serial] = std::move(request);
+    }
+
+    bool Device::OnCreateReadyRenderPipelineCallback(uint64_t requestSerial,
+                                                     WGPUCreateReadyPipelineStatus status,
+                                                     const char* message) {
+        const auto& requestIt = mCreateReadyPipelineRequests.find(requestSerial);
+        if (requestIt == mCreateReadyPipelineRequests.end()) {
+            return false;
+        }
+
+        CreateReadyPipelineRequest request = std::move(requestIt->second);
+        mCreateReadyPipelineRequests.erase(requestIt);
+
+        auto pipelineAllocation =
+            GetClient()->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
+
+        // If the return status is a failure we should give a null pipeline to the callback and
+        // free the allocation both on the client side and the server side.
+        if (status != WGPUCreateReadyPipelineStatus_Success) {
+            GetClient()->RenderPipelineAllocator().Free(pipelineAllocation);
+            request.createReadyRenderPipelineCallback(status, nullptr, message, request.userdata);
+            return true;
+        }
+
+        WGPURenderPipeline pipeline = reinterpret_cast<WGPURenderPipeline>(pipelineAllocation);
+        request.createReadyRenderPipelineCallback(status, pipeline, message, request.userdata);
+
+        return true;
+    }
 }}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Device.h b/src/dawn_wire/client/Device.h
index 087c72c..7d14c6f 100644
--- a/src/dawn_wire/client/Device.h
+++ b/src/dawn_wire/client/Device.h
@@ -43,6 +43,9 @@
         void CreateReadyComputePipeline(WGPUComputePipelineDescriptor const* descriptor,
                                         WGPUCreateReadyComputePipelineCallback callback,
                                         void* userdata);
+        void CreateReadyRenderPipeline(WGPURenderPipelineDescriptor const* descriptor,
+                                       WGPUCreateReadyRenderPipelineCallback callback,
+                                       void* userdata);
 
         void HandleError(WGPUErrorType errorType, const char* message);
         void HandleDeviceLost(const char* message);
@@ -52,6 +55,9 @@
         bool OnCreateReadyComputePipelineCallback(uint64_t requestSerial,
                                                   WGPUCreateReadyPipelineStatus status,
                                                   const char* message);
+        bool OnCreateReadyRenderPipelineCallback(uint64_t requestSerial,
+                                                 WGPUCreateReadyPipelineStatus status,
+                                                 const char* message);
 
         WGPUQueue GetDefaultQueue();
 
@@ -64,13 +70,14 @@
         uint64_t mErrorScopeRequestSerial = 0;
         uint64_t mErrorScopeStackSize = 0;
 
-        struct CreateReadyComputePipelineRequest {
-            WGPUCreateReadyComputePipelineCallback callback = nullptr;
+        struct CreateReadyPipelineRequest {
+            WGPUCreateReadyComputePipelineCallback createReadyComputePipelineCallback = nullptr;
+            WGPUCreateReadyRenderPipelineCallback createReadyRenderPipelineCallback = nullptr;
             void* userdata = nullptr;
             ObjectId pipelineObjectID;
         };
-        std::map<uint64_t, CreateReadyComputePipelineRequest> mCreateReadyComputePipelineRequests;
-        uint64_t mCreateReadyComputePipelineRequestSerial = 0;
+        std::map<uint64_t, CreateReadyPipelineRequest> mCreateReadyPipelineRequests;
+        uint64_t mCreateReadyPipelineRequestSerial = 0;
 
         Client* mClient = nullptr;
         WGPUErrorCallback mErrorCallback = nullptr;
diff --git a/src/dawn_wire/server/Server.h b/src/dawn_wire/server/Server.h
index acf321a..4e725a8 100644
--- a/src/dawn_wire/server/Server.h
+++ b/src/dawn_wire/server/Server.h
@@ -99,6 +99,10 @@
                                                       WGPUComputePipeline pipeline,
                                                       const char* message,
                                                       void* userdata);
+        static void ForwardCreateReadyRenderPipeline(WGPUCreateReadyPipelineStatus status,
+                                                     WGPURenderPipeline pipeline,
+                                                     const char* message,
+                                                     void* userdata);
 
         // Error callbacks
         void OnUncapturedError(WGPUErrorType type, const char* message);
@@ -115,6 +119,10 @@
                                                   WGPUComputePipeline pipeline,
                                                   const char* message,
                                                   CreateReadyPipelineUserData* userdata);
+        void OnCreateReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus status,
+                                                 WGPURenderPipeline pipeline,
+                                                 const char* message,
+                                                 CreateReadyPipelineUserData* userdata);
 
 #include "dawn_wire/server/ServerPrototypes_autogen.inc"
 
diff --git a/src/dawn_wire/server/ServerDevice.cpp b/src/dawn_wire/server/ServerDevice.cpp
index 9975562..b3accf8 100644
--- a/src/dawn_wire/server/ServerDevice.cpp
+++ b/src/dawn_wire/server/ServerDevice.cpp
@@ -36,6 +36,16 @@
             status, pipeline, message, createReadyPipelineUserData);
     }
 
+    void Server::ForwardCreateReadyRenderPipeline(WGPUCreateReadyPipelineStatus status,
+                                                  WGPURenderPipeline pipeline,
+                                                  const char* message,
+                                                  void* userdata) {
+        CreateReadyPipelineUserData* createReadyPipelineUserData =
+            static_cast<CreateReadyPipelineUserData*>(userdata);
+        createReadyPipelineUserData->server->OnCreateReadyRenderPipelineCallback(
+            status, pipeline, message, createReadyPipelineUserData);
+    }
+
     void Server::OnUncapturedError(WGPUErrorType type, const char* message) {
         ReturnDeviceUncapturedErrorCallbackCmd cmd;
         cmd.type = type;
@@ -105,6 +115,47 @@
         SerializeCommand(cmd);
     }
 
+    bool Server::DoDeviceCreateReadyRenderPipeline(WGPUDevice cDevice,
+                                                   uint64_t requestSerial,
+                                                   ObjectHandle pipelineObjectHandle,
+                                                   const WGPURenderPipelineDescriptor* descriptor) {
+        auto* resultData = RenderPipelineObjects().Allocate(pipelineObjectHandle.id);
+        if (resultData == nullptr) {
+            return false;
+        }
+
+        resultData->generation = pipelineObjectHandle.generation;
+
+        std::unique_ptr<CreateReadyPipelineUserData> userdata =
+            std::make_unique<CreateReadyPipelineUserData>();
+        userdata->server = this;
+        userdata->requestSerial = requestSerial;
+        userdata->pipelineObjectID = pipelineObjectHandle.id;
+
+        mProcs.deviceCreateReadyRenderPipeline(
+            cDevice, descriptor, ForwardCreateReadyRenderPipeline, userdata.release());
+        return true;
+    }
+
+    void Server::OnCreateReadyRenderPipelineCallback(WGPUCreateReadyPipelineStatus status,
+                                                     WGPURenderPipeline pipeline,
+                                                     const char* message,
+                                                     CreateReadyPipelineUserData* userdata) {
+        std::unique_ptr<CreateReadyPipelineUserData> data(userdata);
+        if (status != WGPUCreateReadyPipelineStatus_Success) {
+            RenderPipelineObjects().Free(data->pipelineObjectID);
+        } else {
+            RenderPipelineObjects().Get(data->pipelineObjectID)->handle = pipeline;
+        }
+
+        ReturnDeviceCreateReadyRenderPipelineCallbackCmd cmd;
+        cmd.status = status;
+        cmd.requestSerial = data->requestSerial;
+        cmd.message = message;
+
+        SerializeCommand(cmd);
+    }
+
     // static
     void Server::ForwardPopErrorScope(WGPUErrorType type, const char* message, void* userdata) {
         auto* data = reinterpret_cast<ErrorScopeUserdata*>(userdata);