dawn_native: Add RequestDevice to the Adapter

Adds a basic RequestDevice method to the adapter, only in
dawn_native. We will revisit this when we implement adapters
in dawn_wire.

RequestDevice allows us to have tests of the limit bounds
because it receives a callback which can return status codes
and error messages.

Bug: dawn:685
Change-Id: I7a68922b078c6a436f49a16346cb41fb9df9cfee
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63982
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/dawn.json b/dawn.json
index 6b56785..c8e2b3f 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1535,7 +1535,26 @@
                     {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
                 ]
             }
-        
+
+        ]
+    },
+
+    "request device callback": {
+        "category": "callback",
+        "args": [
+            {"name": "status", "type": "request device status"},
+            {"name": "device", "type": "device"},
+            {"name": "message", "type": "char", "annotation": "const*"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+
+    "request device status": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "error"},
+            {"value": 2, "name": "unknown"}
         ]
     },
 
diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp
index 5f84306..2b478c9 100644
--- a/src/dawn_native/Adapter.cpp
+++ b/src/dawn_native/Adapter.cpp
@@ -78,6 +78,24 @@
         return result;
     }
 
+    void AdapterBase::RequestDevice(const DeviceDescriptor* descriptor,
+                                    WGPURequestDeviceCallback callback,
+                                    void* userdata) {
+        DeviceBase* result = nullptr;
+        MaybeError err = CreateDeviceInternal(&result, descriptor);
+        WGPUDevice device = reinterpret_cast<WGPUDevice>(result);
+
+        if (err.IsError()) {
+            std::unique_ptr<ErrorData> errorData = err.AcquireError();
+            callback(WGPURequestDeviceStatus_Error, device, errorData->GetMessage().c_str(),
+                     userdata);
+            return;
+        }
+        WGPURequestDeviceStatus status =
+            device == nullptr ? WGPURequestDeviceStatus_Unknown : WGPURequestDeviceStatus_Success;
+        callback(status, device, nullptr, userdata);
+    }
+
     MaybeError AdapterBase::CreateDeviceInternal(DeviceBase** result,
                                                  const DeviceDescriptor* descriptor) {
         if (descriptor != nullptr) {
diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h
index 7587eeb..4bc6f2d 100644
--- a/src/dawn_native/Adapter.h
+++ b/src/dawn_native/Adapter.h
@@ -40,6 +40,10 @@
 
         DeviceBase* CreateDevice(const DeviceDescriptor* descriptor = nullptr);
 
+        void RequestDevice(const DeviceDescriptor* descriptor,
+                           WGPURequestDeviceCallback callback,
+                           void* userdata);
+
         void ResetInternalDeviceForTesting();
 
         ExtensionsSet GetSupportedExtensions() const;
diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp
index 3cdea54..bd072b6 100644
--- a/src/dawn_native/DawnNative.cpp
+++ b/src/dawn_native/DawnNative.cpp
@@ -118,6 +118,12 @@
         return reinterpret_cast<WGPUDevice>(mImpl->CreateDevice(deviceDescriptor));
     }
 
+    void Adapter::RequestDevice(const DeviceDescriptor* descriptor,
+                                WGPURequestDeviceCallback callback,
+                                void* userdata) {
+        mImpl->RequestDevice(descriptor, callback, userdata);
+    }
+
     void Adapter::ResetInternalDeviceForTesting() {
         mImpl->ResetInternalDeviceForTesting();
     }
diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h
index 77f46d7..b8668dd 100644
--- a/src/include/dawn_native/DawnNative.h
+++ b/src/include/dawn_native/DawnNative.h
@@ -120,6 +120,10 @@
         // On an error, nullptr is returned.
         WGPUDevice CreateDevice(const DeviceDescriptor* deviceDescriptor = nullptr);
 
+        void RequestDevice(const DeviceDescriptor* descriptor,
+                           WGPURequestDeviceCallback callback,
+                           void* userdata);
+
         // Reset the backend device object for testing purposes.
         void ResetInternalDeviceForTesting();