Implement upstream RequestAdapter

Bug: dawn:160
Change-Id: Ifbce6f71fdf43a749c332bd691b63119929e0128
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/75640
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/src/common/Result.h b/src/common/Result.h
index 797f2d5..f913808 100644
--- a/src/common/Result.h
+++ b/src/common/Result.h
@@ -179,6 +179,8 @@
 
     template <typename U>
     Result(Ref<U>&& success);
+    template <typename U>
+    Result(const Ref<U>& success);
     Result(std::unique_ptr<E> error);
 
     template <typename U>
@@ -412,6 +414,11 @@
 }
 
 template <typename T, typename E>
+template <typename U>
+Result<Ref<T>, E>::Result(const Ref<U>& success) : Result(Ref<U>(success)) {
+}
+
+template <typename T, typename E>
 Result<Ref<T>, E>::Result(std::unique_ptr<E> error)
     : mPayload(detail::MakePayload(error.release(), detail::Error)) {
 }
diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp
index 7c09235..2c485e7 100644
--- a/src/dawn_native/Adapter.cpp
+++ b/src/dawn_native/Adapter.cpp
@@ -107,10 +107,15 @@
     void AdapterBase::APIRequestDevice(const DeviceDescriptor* descriptor,
                                        WGPURequestDeviceCallback callback,
                                        void* userdata) {
+        static constexpr DeviceDescriptor kDefaultDescriptor = {};
+        if (descriptor == nullptr) {
+            descriptor = &kDefaultDescriptor;
+        }
         auto result = CreateDeviceInternal(descriptor);
 
         if (result.IsError()) {
             std::unique_ptr<ErrorData> errorData = result.AcquireError();
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
             callback(WGPURequestDeviceStatus_Error, nullptr,
                      errorData->GetFormattedMessage().c_str(), userdata);
             return;
@@ -120,6 +125,7 @@
 
         WGPURequestDeviceStatus status =
             device == nullptr ? WGPURequestDeviceStatus_Unknown : WGPURequestDeviceStatus_Success;
+        // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
         callback(status, ToAPI(device.Detach()), nullptr, userdata);
     }
 
diff --git a/src/dawn_native/BackendConnection.cpp b/src/dawn_native/BackendConnection.cpp
index a25010f..b0aae67 100644
--- a/src/dawn_native/BackendConnection.cpp
+++ b/src/dawn_native/BackendConnection.cpp
@@ -28,7 +28,7 @@
         return mInstance;
     }
 
-    ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> BackendConnection::DiscoverAdapters(
+    ResultOrError<std::vector<Ref<AdapterBase>>> BackendConnection::DiscoverAdapters(
         const AdapterDiscoveryOptionsBase* options) {
         return DAWN_FORMAT_VALIDATION_ERROR("DiscoverAdapters not implemented for this backend.");
     }
diff --git a/src/dawn_native/BackendConnection.h b/src/dawn_native/BackendConnection.h
index e9007e3..5105142 100644
--- a/src/dawn_native/BackendConnection.h
+++ b/src/dawn_native/BackendConnection.h
@@ -34,10 +34,10 @@
 
         // Returns all the adapters for the system that can be created by the backend, without extra
         // options (such as debug adapters, custom driver libraries, etc.)
-        virtual std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() = 0;
+        virtual std::vector<Ref<AdapterBase>> DiscoverDefaultAdapters() = 0;
 
         // Returns new adapters created with the backend-specific options.
-        virtual ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> DiscoverAdapters(
+        virtual ResultOrError<std::vector<Ref<AdapterBase>>> DiscoverAdapters(
             const AdapterDiscoveryOptionsBase* options);
 
       private:
diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp
index 4079cd6..b166c44 100644
--- a/src/dawn_native/DawnNative.cpp
+++ b/src/dawn_native/DawnNative.cpp
@@ -76,14 +76,33 @@
     Adapter::Adapter() = default;
 
     Adapter::Adapter(AdapterBase* impl) : mImpl(impl) {
+        if (mImpl != nullptr) {
+            mImpl->Reference();
+        }
     }
 
     Adapter::~Adapter() {
+        if (mImpl != nullptr) {
+            mImpl->Release();
+        }
         mImpl = nullptr;
     }
 
-    Adapter::Adapter(const Adapter& other) = default;
-    Adapter& Adapter::operator=(const Adapter& other) = default;
+    Adapter::Adapter(const Adapter& other) : Adapter(other.mImpl) {
+    }
+
+    Adapter& Adapter::operator=(const Adapter& other) {
+        if (this != &other) {
+            if (mImpl) {
+                mImpl->Release();
+            }
+            mImpl = other.mImpl;
+            if (mImpl) {
+                mImpl->Reference();
+            }
+        }
+        return *this;
+    }
 
     void Adapter::GetProperties(wgpu::AdapterProperties* properties) const {
         GetProperties(reinterpret_cast<WGPUAdapterProperties*>(properties));
@@ -189,8 +208,8 @@
     std::vector<Adapter> Instance::GetAdapters() const {
         // Adapters are owned by mImpl so it is safe to return non RAII pointers to them
         std::vector<Adapter> adapters;
-        for (const std::unique_ptr<AdapterBase>& adapter : mImpl->GetAdapters()) {
-            adapters.push_back({adapter.get()});
+        for (const Ref<AdapterBase>& adapter : mImpl->GetAdapters()) {
+            adapters.push_back({adapter.Get()});
         }
         return adapters;
     }
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index a08bc06..559fa93 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -535,6 +535,7 @@
         }
         ErrorScope scope = mErrorScopeStack->Pop();
         if (callback != nullptr) {
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
             callback(static_cast<WGPUErrorType>(scope.GetErrorType()), scope.GetErrorMessage(),
                      userdata);
         }
@@ -973,6 +974,7 @@
         // callback.
         if (maybeResult.IsError()) {
             std::unique_ptr<ErrorData> error = maybeResult.AcquireError();
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
             callback(WGPUCreatePipelineAsyncStatus_Error, nullptr, error->GetMessage().c_str(),
                      userdata);
         }
@@ -1015,6 +1017,7 @@
         // callback.
         if (maybeResult.IsError()) {
             std::unique_ptr<ErrorData> error = maybeResult.AcquireError();
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
             callback(WGPUCreatePipelineAsyncStatus_Error, nullptr, error->GetMessage().c_str(),
                      userdata);
         }
@@ -1325,6 +1328,7 @@
         Ref<ComputePipelineBase> cachedComputePipeline =
             GetCachedComputePipeline(uninitializedComputePipeline.Get());
         if (cachedComputePipeline.Get() != nullptr) {
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
             callback(WGPUCreatePipelineAsyncStatus_Success, ToAPI(cachedComputePipeline.Detach()),
                      "", userdata);
         } else {
@@ -1471,6 +1475,7 @@
         Ref<RenderPipelineBase> cachedRenderPipeline =
             GetCachedRenderPipeline(uninitializedRenderPipeline.Get());
         if (cachedRenderPipeline != nullptr) {
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
             callback(WGPUCreatePipelineAsyncStatus_Success, ToAPI(cachedRenderPipeline.Detach()),
                      "", userdata);
         } else {
diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp
index 12abde6..201487e 100644
--- a/src/dawn_native/Instance.cpp
+++ b/src/dawn_native/Instance.cpp
@@ -15,16 +15,24 @@
 #include "dawn_native/Instance.h"
 
 #include "common/Assert.h"
+#include "common/GPUInfo.h"
 #include "common/Log.h"
 #include "dawn_native/ErrorData.h"
 #include "dawn_native/Surface.h"
 #include "dawn_native/ValidationUtils_autogen.h"
 #include "dawn_platform/DawnPlatform.h"
 
+// For SwiftShader fallback
+#if defined(DAWN_ENABLE_BACKEND_VULKAN)
+#    include "dawn_native/VulkanBackend.h"
+#endif  // defined(DAWN_ENABLE_BACKEND_VULKAN)
+
 #if defined(DAWN_USE_X11)
 #    include "dawn_native/XlibXcbFunctions.h"
 #endif  // defined(DAWN_USE_X11)
 
+#include <optional>
+
 namespace dawn::native {
 
     // Forward definitions of each backend's "Connect" function that creates new BackendConnection.
@@ -102,7 +110,100 @@
     void InstanceBase::APIRequestAdapter(const RequestAdapterOptions* options,
                                          WGPURequestAdapterCallback callback,
                                          void* userdata) {
-        callback(WGPURequestAdapterStatus_Error, nullptr, "Not implemented", userdata);
+        static constexpr RequestAdapterOptions kDefaultOptions = {};
+        if (options == nullptr) {
+            options = &kDefaultOptions;
+        }
+        auto result = RequestAdapterInternal(options);
+        if (result.IsError()) {
+            auto err = result.AcquireError();
+            std::string msg = err->GetFormattedMessage();
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
+            callback(WGPURequestAdapterStatus_Error, nullptr, msg.c_str(), userdata);
+        } else {
+            Ref<AdapterBase> adapter = result.AcquireSuccess();
+            // TODO(crbug.com/dawn/1122): Call callbacks only on wgpuInstanceProcessEvents
+            callback(WGPURequestAdapterStatus_Success, ToAPI(adapter.Detach()), nullptr, userdata);
+        }
+    }
+
+    ResultOrError<Ref<AdapterBase>> InstanceBase::RequestAdapterInternal(
+        const RequestAdapterOptions* options) {
+        ASSERT(options != nullptr);
+        if (options->forceFallbackAdapter) {
+#if defined(DAWN_ENABLE_BACKEND_VULKAN)
+            if (GetEnabledBackends()[wgpu::BackendType::Vulkan]) {
+                dawn_native::vulkan::AdapterDiscoveryOptions vulkanOptions;
+                vulkanOptions.forceSwiftShader = true;
+                DAWN_TRY(DiscoverAdaptersInternal(&vulkanOptions));
+            }
+#else
+            return Ref<AdapterBase>(nullptr);
+#endif  // defined(DAWN_ENABLE_BACKEND_VULKAN)
+        } else {
+            DiscoverDefaultAdapters();
+        }
+
+        wgpu::AdapterType preferredType;
+        switch (options->powerPreference) {
+            case wgpu::PowerPreference::LowPower:
+                preferredType = wgpu::AdapterType::IntegratedGPU;
+                break;
+            case wgpu::PowerPreference::Undefined:
+            case wgpu::PowerPreference::HighPerformance:
+                preferredType = wgpu::AdapterType::DiscreteGPU;
+                break;
+        }
+
+        std::optional<size_t> discreteGPUAdapterIndex;
+        std::optional<size_t> integratedGPUAdapterIndex;
+        std::optional<size_t> cpuAdapterIndex;
+        std::optional<size_t> unknownAdapterIndex;
+
+        for (size_t i = 0; i < mAdapters.size(); ++i) {
+            AdapterProperties properties;
+            mAdapters[i]->APIGetProperties(&properties);
+
+            if (options->forceFallbackAdapter) {
+                if (!gpu_info::IsSwiftshader(properties.vendorID, properties.deviceID)) {
+                    continue;
+                }
+                return mAdapters[i];
+            }
+            if (properties.adapterType == preferredType) {
+                return mAdapters[i];
+            }
+            switch (properties.adapterType) {
+                case wgpu::AdapterType::DiscreteGPU:
+                    discreteGPUAdapterIndex = i;
+                    break;
+                case wgpu::AdapterType::IntegratedGPU:
+                    integratedGPUAdapterIndex = i;
+                    break;
+                case wgpu::AdapterType::CPU:
+                    cpuAdapterIndex = i;
+                    break;
+                case wgpu::AdapterType::Unknown:
+                    unknownAdapterIndex = i;
+                    break;
+            }
+        }
+
+        // For now, we always prefer the discrete GPU
+        if (discreteGPUAdapterIndex) {
+            return mAdapters[*discreteGPUAdapterIndex];
+        }
+        if (integratedGPUAdapterIndex) {
+            return mAdapters[*integratedGPUAdapterIndex];
+        }
+        if (cpuAdapterIndex) {
+            return mAdapters[*cpuAdapterIndex];
+        }
+        if (unknownAdapterIndex) {
+            return mAdapters[*unknownAdapterIndex];
+        }
+
+        return Ref<AdapterBase>(nullptr);
     }
 
     void InstanceBase::DiscoverDefaultAdapters() {
@@ -116,10 +217,9 @@
 
         // Query and merge all default adapters for all backends
         for (std::unique_ptr<BackendConnection>& backend : mBackends) {
-            std::vector<std::unique_ptr<AdapterBase>> backendAdapters =
-                backend->DiscoverDefaultAdapters();
+            std::vector<Ref<AdapterBase>> backendAdapters = backend->DiscoverDefaultAdapters();
 
-            for (std::unique_ptr<AdapterBase>& adapter : backendAdapters) {
+            for (Ref<AdapterBase>& adapter : backendAdapters) {
                 ASSERT(adapter->GetBackendType() == backend->GetType());
                 ASSERT(adapter->GetInstance() == this);
                 mAdapters.push_back(std::move(adapter));
@@ -146,7 +246,7 @@
         return mFeaturesInfo.GetFeatureInfo(feature);
     }
 
-    const std::vector<std::unique_ptr<AdapterBase>>& InstanceBase::GetAdapters() const {
+    const std::vector<Ref<AdapterBase>>& InstanceBase::GetAdapters() const {
         return mAdapters;
     }
 
@@ -226,10 +326,10 @@
             }
             foundBackend = true;
 
-            std::vector<std::unique_ptr<AdapterBase>> newAdapters;
+            std::vector<Ref<AdapterBase>> newAdapters;
             DAWN_TRY_ASSIGN(newAdapters, backend->DiscoverAdapters(options));
 
-            for (std::unique_ptr<AdapterBase>& adapter : newAdapters) {
+            for (Ref<AdapterBase>& adapter : newAdapters) {
                 ASSERT(adapter->GetBackendType() == backend->GetType());
                 ASSERT(adapter->GetInstance() == this);
                 mAdapters.push_back(std::move(adapter));
@@ -246,7 +346,6 @@
 
             ASSERT(error != nullptr);
             dawn::InfoLog() << error->GetFormattedMessage();
-
             return true;
         }
         return false;
diff --git a/src/dawn_native/Instance.h b/src/dawn_native/Instance.h
index e7a72ca..913b2b6 100644
--- a/src/dawn_native/Instance.h
+++ b/src/dawn_native/Instance.h
@@ -52,7 +52,7 @@
         void DiscoverDefaultAdapters();
         bool DiscoverAdapters(const AdapterDiscoveryOptionsBase* options);
 
-        const std::vector<std::unique_ptr<AdapterBase>>& GetAdapters() const;
+        const std::vector<Ref<AdapterBase>>& GetAdapters() const;
 
         // Used to handle error that happen up to device creation.
         bool ConsumedError(MaybeError maybeError);
@@ -96,6 +96,9 @@
 
         MaybeError DiscoverAdaptersInternal(const AdapterDiscoveryOptionsBase* options);
 
+        ResultOrError<Ref<AdapterBase>> RequestAdapterInternal(
+            const RequestAdapterOptions* options);
+
         BackendsBitset mBackendsConnected;
 
         bool mDiscoveredDefaultAdapters = false;
@@ -107,7 +110,7 @@
         std::unique_ptr<dawn::platform::Platform> mDefaultPlatform;
 
         std::vector<std::unique_ptr<BackendConnection>> mBackends;
-        std::vector<std::unique_ptr<AdapterBase>> mAdapters;
+        std::vector<Ref<AdapterBase>> mAdapters;
 
         FeaturesInfo mFeaturesInfo;
         TogglesInfo mTogglesInfo;
diff --git a/src/dawn_native/d3d12/BackendD3D12.cpp b/src/dawn_native/d3d12/BackendD3D12.cpp
index 8476553..cb29d69 100644
--- a/src/dawn_native/d3d12/BackendD3D12.cpp
+++ b/src/dawn_native/d3d12/BackendD3D12.cpp
@@ -66,13 +66,12 @@
             return std::move(factory);
         }
 
-        ResultOrError<std::unique_ptr<AdapterBase>> CreateAdapterFromIDXGIAdapter(
+        ResultOrError<Ref<AdapterBase>> CreateAdapterFromIDXGIAdapter(
             Backend* backend,
             ComPtr<IDXGIAdapter> dxgiAdapter) {
             ComPtr<IDXGIAdapter3> dxgiAdapter3;
             DAWN_TRY(CheckHRESULT(dxgiAdapter.As(&dxgiAdapter3), "DXGIAdapter retrieval"));
-            std::unique_ptr<Adapter> adapter =
-                std::make_unique<Adapter>(backend, std::move(dxgiAdapter3));
+            Ref<Adapter> adapter = AcquireRef(new Adapter(backend, std::move(dxgiAdapter3)));
             DAWN_TRY(adapter->Initialize());
 
             return {std::move(adapter)};
@@ -150,7 +149,7 @@
         return mFunctions.get();
     }
 
-    std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
+    std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
         AdapterDiscoveryOptions options;
         auto result = DiscoverAdapters(&options);
         if (result.IsError()) {
@@ -160,16 +159,16 @@
         return result.AcquireSuccess();
     }
 
-    ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
+    ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
         const AdapterDiscoveryOptionsBase* optionsBase) {
         ASSERT(optionsBase->backendType == WGPUBackendType_D3D12);
         const AdapterDiscoveryOptions* options =
             static_cast<const AdapterDiscoveryOptions*>(optionsBase);
 
-        std::vector<std::unique_ptr<AdapterBase>> adapters;
+        std::vector<Ref<AdapterBase>> adapters;
         if (options->dxgiAdapter != nullptr) {
             // |dxgiAdapter| was provided. Discover just that adapter.
-            std::unique_ptr<AdapterBase> adapter;
+            Ref<AdapterBase> adapter;
             DAWN_TRY_ASSIGN(adapter, CreateAdapterFromIDXGIAdapter(this, options->dxgiAdapter));
             adapters.push_back(std::move(adapter));
             return std::move(adapters);
@@ -183,14 +182,14 @@
             }
 
             ASSERT(dxgiAdapter != nullptr);
-            ResultOrError<std::unique_ptr<AdapterBase>> adapter =
+            ResultOrError<Ref<AdapterBase>> adapter =
                 CreateAdapterFromIDXGIAdapter(this, dxgiAdapter);
             if (adapter.IsError()) {
                 GetInstance()->ConsumedError(adapter.AcquireError());
                 continue;
             }
 
-            adapters.push_back(std::move(adapter.AcquireSuccess()));
+            adapters.push_back(adapter.AcquireSuccess());
         }
 
         return adapters;
diff --git a/src/dawn_native/d3d12/BackendD3D12.h b/src/dawn_native/d3d12/BackendD3D12.h
index 8fb237d..ef339bf 100644
--- a/src/dawn_native/d3d12/BackendD3D12.h
+++ b/src/dawn_native/d3d12/BackendD3D12.h
@@ -40,8 +40,8 @@
 
         const PlatformFunctions* GetFunctions() const;
 
-        std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override;
-        ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> DiscoverAdapters(
+        std::vector<Ref<AdapterBase>> DiscoverDefaultAdapters() override;
+        ResultOrError<std::vector<Ref<AdapterBase>>> DiscoverAdapters(
             const AdapterDiscoveryOptionsBase* optionsBase) override;
 
       private:
diff --git a/src/dawn_native/metal/BackendMTL.h b/src/dawn_native/metal/BackendMTL.h
index da67335..26738f6 100644
--- a/src/dawn_native/metal/BackendMTL.h
+++ b/src/dawn_native/metal/BackendMTL.h
@@ -23,8 +23,8 @@
       public:
         Backend(InstanceBase* instance);
 
-        std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override;
-        ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> DiscoverAdapters(
+        std::vector<Ref<AdapterBase>> DiscoverDefaultAdapters() override;
+        ResultOrError<std::vector<Ref<AdapterBase>>> DiscoverAdapters(
             const AdapterDiscoveryOptionsBase* optionsBase) override;
     };
 
diff --git a/src/dawn_native/metal/BackendMTL.mm b/src/dawn_native/metal/BackendMTL.mm
index bc9c6fc..5959e6b 100644
--- a/src/dawn_native/metal/BackendMTL.mm
+++ b/src/dawn_native/metal/BackendMTL.mm
@@ -558,7 +558,7 @@
         }
     }
 
-    std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
+    std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
         AdapterDiscoveryOptions options;
         auto result = DiscoverAdapters(&options);
         if (result.IsError()) {
@@ -568,11 +568,11 @@
         return result.AcquireSuccess();
     }
 
-    ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
+    ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
         const AdapterDiscoveryOptionsBase* optionsBase) {
         ASSERT(optionsBase->backendType == WGPUBackendType_Metal);
 
-        std::vector<std::unique_ptr<AdapterBase>> adapters;
+        std::vector<Ref<AdapterBase>> adapters;
         BOOL supportedVersion = NO;
 #if defined(DAWN_PLATFORM_MACOS)
         if (@available(macOS 10.11, *)) {
@@ -581,7 +581,7 @@
             NSRef<NSArray<id<MTLDevice>>> devices = AcquireNSRef(MTLCopyAllDevices());
 
             for (id<MTLDevice> device in devices.Get()) {
-                std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(GetInstance(), device);
+                Ref<Adapter> adapter = AcquireRef(new Adapter(GetInstance(), device));
                 if (!GetInstance()->ConsumedError(adapter->Initialize())) {
                     adapters.push_back(std::move(adapter));
                 }
@@ -593,8 +593,8 @@
         if (@available(iOS 8.0, *)) {
             supportedVersion = YES;
             // iOS only has a single device so MTLCopyAllDevices doesn't exist there.
-            std::unique_ptr<Adapter> adapter =
-                std::make_unique<Adapter>(GetInstance(), MTLCreateSystemDefaultDevice());
+            Ref<Adapter> adapter =
+                AcquireRef(new Adapter(GetInstance(), MTLCreateSystemDefaultDevice()));
             if (!GetInstance()->ConsumedError(adapter->Initialize())) {
                 adapters.push_back(std::move(adapter));
             }
diff --git a/src/dawn_native/null/DeviceNull.cpp b/src/dawn_native/null/DeviceNull.cpp
index 3259f44..7aa1483 100644
--- a/src/dawn_native/null/DeviceNull.cpp
+++ b/src/dawn_native/null/DeviceNull.cpp
@@ -71,11 +71,11 @@
         Backend(InstanceBase* instance) : BackendConnection(instance, wgpu::BackendType::Null) {
         }
 
-        std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override {
+        std::vector<Ref<AdapterBase>> DiscoverDefaultAdapters() override {
             // There is always a single Null adapter because it is purely CPU based and doesn't
             // depend on the system.
-            std::vector<std::unique_ptr<AdapterBase>> adapters;
-            std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(GetInstance());
+            std::vector<Ref<AdapterBase>> adapters;
+            Ref<Adapter> adapter = AcquireRef(new Adapter(GetInstance()));
             adapters.push_back(std::move(adapter));
             return adapters;
         }
diff --git a/src/dawn_native/opengl/BackendGL.cpp b/src/dawn_native/opengl/BackendGL.cpp
index 2d5901e..982e84a 100644
--- a/src/dawn_native/opengl/BackendGL.cpp
+++ b/src/dawn_native/opengl/BackendGL.cpp
@@ -270,12 +270,12 @@
         : BackendConnection(instance, backendType) {
     }
 
-    std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
+    std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
         // The OpenGL backend needs at least "getProcAddress" to discover an adapter.
         return {};
     }
 
-    ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
+    ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
         const AdapterDiscoveryOptionsBase* optionsBase) {
         // TODO(cwallez@chromium.org): For now only create a single OpenGL adapter because don't
         // know how to handle MakeCurrent.
@@ -288,14 +288,13 @@
         DAWN_INVALID_IF(options->getProc == nullptr,
                         "AdapterDiscoveryOptions::getProc must be set");
 
-        std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(
-            GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType));
+        Ref<Adapter> adapter = AcquireRef(
+            new Adapter(GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType)));
         DAWN_TRY(adapter->InitializeGLFunctions(options->getProc));
         DAWN_TRY(adapter->Initialize());
 
         mCreatedAdapter = true;
-        std::vector<std::unique_ptr<AdapterBase>> adapters;
-        adapters.push_back(std::unique_ptr<AdapterBase>(adapter.release()));
+        std::vector<Ref<AdapterBase>> adapters{std::move(adapter)};
         return std::move(adapters);
     }
 
diff --git a/src/dawn_native/opengl/BackendGL.h b/src/dawn_native/opengl/BackendGL.h
index 9b925e4..2e38173 100644
--- a/src/dawn_native/opengl/BackendGL.h
+++ b/src/dawn_native/opengl/BackendGL.h
@@ -23,8 +23,8 @@
       public:
         Backend(InstanceBase* instance, wgpu::BackendType backendType);
 
-        std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override;
-        ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> DiscoverAdapters(
+        std::vector<Ref<AdapterBase>> DiscoverDefaultAdapters() override;
+        ResultOrError<std::vector<Ref<AdapterBase>>> DiscoverAdapters(
             const AdapterDiscoveryOptionsBase* options) override;
 
       private:
diff --git a/src/dawn_native/vulkan/BackendVk.cpp b/src/dawn_native/vulkan/BackendVk.cpp
index 4378413..4916fe6 100644
--- a/src/dawn_native/vulkan/BackendVk.cpp
+++ b/src/dawn_native/vulkan/BackendVk.cpp
@@ -395,7 +395,7 @@
 
     Backend::~Backend() = default;
 
-    std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
+    std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
         AdapterDiscoveryOptions options;
         auto result = DiscoverAdapters(&options);
         if (result.IsError()) {
@@ -405,14 +405,14 @@
         return result.AcquireSuccess();
     }
 
-    ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
+    ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
         const AdapterDiscoveryOptionsBase* optionsBase) {
         ASSERT(optionsBase->backendType == WGPUBackendType_Vulkan);
 
         const AdapterDiscoveryOptions* options =
             static_cast<const AdapterDiscoveryOptions*>(optionsBase);
 
-        std::vector<std::unique_ptr<AdapterBase>> adapters;
+        std::vector<Ref<AdapterBase>> adapters;
 
         InstanceBase* instance = GetInstance();
         for (ICD icd : kICDs) {
@@ -429,8 +429,8 @@
             const std::vector<VkPhysicalDevice>& physicalDevices =
                 mVulkanInstances[icd]->GetPhysicalDevices();
             for (uint32_t i = 0; i < physicalDevices.size(); ++i) {
-                std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(
-                    instance, mVulkanInstances[icd].Get(), physicalDevices[i]);
+                Ref<Adapter> adapter = AcquireRef(
+                    new Adapter(instance, mVulkanInstances[icd].Get(), physicalDevices[i]));
                 if (instance->ConsumedError(adapter->Initialize())) {
                     continue;
                 }
diff --git a/src/dawn_native/vulkan/BackendVk.h b/src/dawn_native/vulkan/BackendVk.h
index dd4a5da..3889401 100644
--- a/src/dawn_native/vulkan/BackendVk.h
+++ b/src/dawn_native/vulkan/BackendVk.h
@@ -73,8 +73,8 @@
 
         MaybeError Initialize();
 
-        std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override;
-        ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> DiscoverAdapters(
+        std::vector<Ref<AdapterBase>> DiscoverDefaultAdapters() override;
+        ResultOrError<std::vector<Ref<AdapterBase>>> DiscoverAdapters(
             const AdapterDiscoveryOptionsBase* optionsBase) override;
 
       private:
diff --git a/src/tests/end2end/AdapterDiscoveryTests.cpp b/src/tests/end2end/AdapterDiscoveryTests.cpp
index 8957ee4..e2841cf 100644
--- a/src/tests/end2end/AdapterDiscoveryTests.cpp
+++ b/src/tests/end2end/AdapterDiscoveryTests.cpp
@@ -13,10 +13,13 @@
 // limitations under the License.
 
 #include "common/GPUInfo.h"
+#include "common/Log.h"
 #include "common/Platform.h"
 #include "common/SystemUtils.h"
+#include "dawn/dawn_proc.h"
 #include "dawn/webgpu_cpp.h"
 #include "dawn_native/DawnNative.h"
+#include "tests/MockCallback.h"
 
 #if defined(DAWN_ENABLE_BACKEND_VULKAN)
 #    include "dawn_native/VulkanBackend.h"
@@ -43,6 +46,8 @@
 
 namespace {
 
+    using namespace testing;
+
     class AdapterDiscoveryTests : public ::testing::Test {};
 
 #if defined(DAWN_ENABLE_BACKEND_VULKAN)
@@ -266,4 +271,145 @@
     }
 #endif  // defined(DAWN_ENABLE_BACKEND_VULKAN) && defined(DAWN_ENABLE_BACKEND_METAL)
 
+    class AdapterCreationTest : public ::testing::Test {
+      protected:
+        void SetUp() override {
+            dawnProcSetProcs(&dawn_native::GetProcs());
+
+            {
+                auto nativeInstance = std::make_unique<dawn_native::Instance>();
+                nativeInstance->DiscoverDefaultAdapters();
+                for (dawn_native::Adapter& nativeAdapter : nativeInstance->GetAdapters()) {
+                    anyAdapterAvailable = true;
+
+                    wgpu::AdapterProperties properties;
+                    nativeAdapter.GetProperties(&properties);
+                    swiftShaderAvailable =
+                        swiftShaderAvailable ||
+                        gpu_info::IsSwiftshader(properties.vendorID, properties.deviceID);
+                    discreteGPUAvailable = discreteGPUAvailable ||
+                                           properties.adapterType == wgpu::AdapterType::DiscreteGPU;
+                    integratedGPUAvailable =
+                        integratedGPUAvailable ||
+                        properties.adapterType == wgpu::AdapterType::IntegratedGPU;
+                }
+            }
+
+            instance = wgpu::CreateInstance();
+        }
+
+        void TearDown() override {
+            instance = nullptr;
+            dawnProcSetProcs(nullptr);
+        }
+
+        wgpu::Instance instance;
+        bool anyAdapterAvailable = false;
+        bool swiftShaderAvailable = false;
+        bool discreteGPUAvailable = false;
+        bool integratedGPUAvailable = false;
+    };
+
+    // Test that requesting the default adapter works
+    TEST_F(AdapterCreationTest, DefaultAdapter) {
+        wgpu::RequestAdapterOptions options = {};
+
+        MockCallback<WGPURequestAdapterCallback> cb;
+
+        WGPUAdapter cAdapter = nullptr;
+        EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+            .WillOnce(SaveArg<1>(&cAdapter));
+        instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+        wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+        EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+    }
+
+    // Test that passing nullptr for the options gets the default adapter
+    TEST_F(AdapterCreationTest, NullGivesDefaultAdapter) {
+        wgpu::RequestAdapterOptions options = {};
+
+        MockCallback<WGPURequestAdapterCallback> cb;
+
+        WGPUAdapter cAdapter = nullptr;
+        EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+            .WillOnce(SaveArg<1>(&cAdapter));
+        instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+        wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+        EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+
+        EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this + 1))
+            .WillOnce(SaveArg<1>(&cAdapter));
+        instance.RequestAdapter(nullptr, cb.Callback(), cb.MakeUserdata(this + 1));
+
+        wgpu::Adapter adapter2 = wgpu::Adapter::Acquire(cAdapter);
+        EXPECT_EQ(adapter.Get(), adapter2.Get());
+    }
+
+    // Test that requesting the fallback adapter returns SwiftShader.
+    TEST_F(AdapterCreationTest, FallbackAdapter) {
+        wgpu::RequestAdapterOptions options = {};
+        options.forceFallbackAdapter = true;
+
+        MockCallback<WGPURequestAdapterCallback> cb;
+
+        WGPUAdapter cAdapter = nullptr;
+        EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+            .WillOnce(SaveArg<1>(&cAdapter));
+        instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+        wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+        EXPECT_EQ(adapter != nullptr, swiftShaderAvailable);
+        if (adapter != nullptr) {
+            wgpu::AdapterProperties properties;
+            adapter.GetProperties(&properties);
+
+            EXPECT_EQ(properties.adapterType, wgpu::AdapterType::CPU);
+            EXPECT_TRUE(gpu_info::IsSwiftshader(properties.vendorID, properties.deviceID));
+        }
+    }
+
+    // Test that requesting a high performance GPU works
+    TEST_F(AdapterCreationTest, PreferHighPerformance) {
+        wgpu::RequestAdapterOptions options = {};
+        options.powerPreference = wgpu::PowerPreference::HighPerformance;
+
+        MockCallback<WGPURequestAdapterCallback> cb;
+
+        WGPUAdapter cAdapter = nullptr;
+        EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+            .WillOnce(SaveArg<1>(&cAdapter));
+        instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+        wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+        EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+        if (discreteGPUAvailable) {
+            wgpu::AdapterProperties properties;
+            adapter.GetProperties(&properties);
+            EXPECT_EQ(properties.adapterType, wgpu::AdapterType::DiscreteGPU);
+        }
+    }
+
+    // Test that requesting a low power GPU works
+    TEST_F(AdapterCreationTest, PreferLowPower) {
+        wgpu::RequestAdapterOptions options = {};
+        options.powerPreference = wgpu::PowerPreference::LowPower;
+
+        MockCallback<WGPURequestAdapterCallback> cb;
+
+        WGPUAdapter cAdapter = nullptr;
+        EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+            .WillOnce(SaveArg<1>(&cAdapter));
+        instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+        wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+        EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+        if (integratedGPUAvailable) {
+            wgpu::AdapterProperties properties;
+            adapter.GetProperties(&properties);
+            EXPECT_EQ(properties.adapterType, wgpu::AdapterType::IntegratedGPU);
+        }
+    }
+
 }  // anonymous namespace
diff --git a/src/tests/unittests/native/DeviceCreationTests.cpp b/src/tests/unittests/native/DeviceCreationTests.cpp
index 1a8ddb6..3d67255 100644
--- a/src/tests/unittests/native/DeviceCreationTests.cpp
+++ b/src/tests/unittests/native/DeviceCreationTests.cpp
@@ -99,6 +99,21 @@
         EXPECT_NE(device, nullptr);
     }
 
+    // Test successful call to RequestDevice with a null descriptor
+    TEST_F(DeviceCreationTest, RequestDeviceNullDescriptorSuccess) {
+        WGPUDevice cDevice;
+        {
+            MockCallback<WGPURequestDeviceCallback> cb;
+            EXPECT_CALL(cb, Call(WGPURequestDeviceStatus_Success, NotNull(), nullptr, this))
+                .WillOnce(SaveArg<1>(&cDevice));
+
+            adapter.RequestDevice(nullptr, cb.Callback(), cb.MakeUserdata(this));
+        }
+
+        wgpu::Device device = wgpu::Device::Acquire(cDevice);
+        EXPECT_NE(device, nullptr);
+    }
+
     // Test failing call to RequestDevice with invalid feature
     TEST_F(DeviceCreationTest, RequestDeviceFailure) {
         MockCallback<WGPURequestDeviceCallback> cb;