[WGPUFuture] Implement and use Futures in wire for requestAdapter.
Bug: dawn:1987, dawn:2060
Change-Id: Ia5030ce122b0da20ad08af3489500ffc8aac8684
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/153921
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Loko Kung <lokokung@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/dawn.json b/dawn.json
index 9aa4089..6a5c97e 100644
--- a/dawn.json
+++ b/dawn.json
@@ -72,6 +72,24 @@
{"name": "compatibility mode", "type": "bool", "default": "false", "tags": ["dawn", "emscripten"]}
]
},
+ "request adapter callback": {
+ "category": "function pointer",
+ "args": [
+ {"name": "status", "type": "request adapter status"},
+ {"name": "adapter", "type": "adapter", "optional": true},
+ {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+ {"name": "userdata", "type": "void *"}
+ ]
+ },
+ "request adapter callback info": {
+ "category": "structure",
+ "extensible": "in",
+ "members": [
+ {"name": "mode", "type": "callback mode"},
+ {"name": "callback", "type": "request adapter callback"},
+ {"name": "userdata", "type": "void *"}
+ ]
+ },
"request adapter status": {
"category": "enum",
"emscripten_no_enum_table": true,
@@ -82,15 +100,6 @@
{"value": 3, "name": "unknown"}
]
},
- "request adapter callback": {
- "category": "function pointer",
- "args": [
- {"name": "status", "type": "request adapter status"},
- {"name": "adapter", "type": "adapter", "optional": true},
- {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
- {"name": "userdata", "type": "void *"}
- ]
- },
"adapter": {
"category": "object",
"no autolock": true,
@@ -578,7 +587,7 @@
{"name": "mode", "type": "callback mode"},
{"name": "callback", "type": "buffer map callback"},
{"name": "userdata", "type": "void *"}
- ]
+ ]
},
"buffer map async status": {
"category": "enum",
@@ -2009,6 +2018,16 @@
{"name": "callback", "type": "request adapter callback"},
{"name": "userdata", "type": "void *"}
]
+ },
+ {
+ "name": "request adapter f",
+ "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+ "tags": ["dawn", "emscripten"],
+ "returns": "future",
+ "args": [
+ {"name": "options", "type": "request adapter options", "annotation": "const*", "optional": true, "no_default": true},
+ {"name": "callback info", "type": "request adapter callback info"}
+ ]
}
]
},
diff --git a/dawn_wire.json b/dawn_wire.json
index 8815d41..cc541ed 100644
--- a/dawn_wire.json
+++ b/dawn_wire.json
@@ -99,7 +99,7 @@
],
"instance request adapter": [
{ "name": "instance id", "type": "ObjectId", "id_type": "instance" },
- { "name": "request serial", "type": "uint64_t" },
+ { "name": "future", "type": "future" },
{ "name": "adapter object handle", "type": "ObjectHandle", "handle_type": "adapter"},
{ "name": "options", "type": "request adapter options", "annotation": "const*", "optional": true }
],
@@ -164,7 +164,7 @@
],
"instance request adapter callback": [
{ "name": "instance", "type": "ObjectHandle", "handle_type": "instance" },
- { "name": "request serial", "type": "uint64_t" },
+ { "name": "future", "type": "future" },
{ "name": "status", "type": "request adapter status" },
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true },
{ "name": "properties", "type": "adapter properties", "annotation": "const*", "optional": "true" },
@@ -217,6 +217,7 @@
"DeviceSetUncapturedErrorCallback",
"DeviceSetLoggingCallback",
"InstanceRequestAdapter",
+ "InstanceRequestAdapterF",
"ShaderModuleGetCompilationInfo",
"QuerySetGetType",
"QuerySetGetCount",
diff --git a/src/dawn/native/Instance.cpp b/src/dawn/native/Instance.cpp
index d058ff5..2a9069b 100644
--- a/src/dawn/native/Instance.cpp
+++ b/src/dawn/native/Instance.cpp
@@ -240,6 +240,12 @@
}
}
+Future InstanceBase::APIRequestAdapterF(const RequestAdapterOptions* options,
+ const RequestAdapterCallbackInfo& callbackInfo) {
+ // TODO(dawn:1987) Implement this.
+ DAWN_UNREACHABLE();
+}
+
Ref<AdapterBase> InstanceBase::CreateAdapter(Ref<PhysicalDeviceBase> physicalDevice,
FeatureLevel featureLevel,
const DawnTogglesDescriptor* requiredAdapterToggles,
diff --git a/src/dawn/native/Instance.h b/src/dawn/native/Instance.h
index 56b3e60..8a74906 100644
--- a/src/dawn/native/Instance.h
+++ b/src/dawn/native/Instance.h
@@ -76,6 +76,8 @@
void APIRequestAdapter(const RequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata);
+ Future APIRequestAdapterF(const RequestAdapterOptions* options,
+ const RequestAdapterCallbackInfo& callbackInfo);
// Discovers and returns a vector of adapters.
// All systems adapters that can be found are returned if no options are passed.
diff --git a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
index 5fdf01f..59a2594 100644
--- a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
@@ -29,6 +29,7 @@
#include <vector>
#include "dawn/tests/MockCallback.h"
+#include "dawn/tests/unittests/wire/WireFutureTest.h"
#include "dawn/tests/unittests/wire/WireTest.h"
#include "dawn/wire/WireClient.h"
@@ -42,6 +43,7 @@
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::MockCallback;
+using testing::NiceMock;
using testing::NotNull;
using testing::Return;
using testing::SetArgPointee;
@@ -49,28 +51,6 @@
using testing::WithArg;
class WireInstanceBasicTest : public WireTest {};
-class WireInstanceTests : public WireTest {
- protected:
- void SetUp() override {
- WireTest::SetUp();
-
- auto reservation = GetWireClient()->ReserveInstance();
- instance = wgpu::Instance::Acquire(reservation.instance);
-
- apiInstance = api.GetNewInstance();
- EXPECT_CALL(api, InstanceReference(apiInstance));
- EXPECT_TRUE(
- GetWireServer()->InjectInstance(apiInstance, reservation.id, reservation.generation));
- }
-
- void TearDown() override {
- instance = nullptr;
- WireTest::TearDown();
- }
-
- wgpu::Instance instance;
- WGPUInstance apiInstance;
-};
// Test that an Instance can be reserved and injected into the wire.
TEST_F(WireInstanceBasicTest, ReserveAndInject) {
@@ -88,37 +68,55 @@
FlushClient();
}
-// Test that RequestAdapterOptions are passed from the client to the server.
-TEST_F(WireInstanceTests, RequestAdapterPassesOptions) {
- MockCallback<WGPURequestAdapterCallback> cb;
- auto* userdata = cb.MakeUserdata(this);
+using WireInstanceTestBase = WireFutureTestWithParams<WGPURequestAdapterCallback,
+ WGPURequestAdapterCallbackInfo,
+ wgpuInstanceRequestAdapter,
+ wgpuInstanceRequestAdapterF>;
+class WireInstanceTests : public WireInstanceTestBase {
+ protected:
+ // Overriden version of wgpuInstanceRequestAdapter that defers to the API call based on the
+ // test callback mode.
+ void InstanceRequestAdapter(WGPUInstance i,
+ WGPURequestAdapterOptions const* options,
+ void* userdata = nullptr) {
+ CallImpl(userdata, i, options);
+ }
+};
- for (wgpu::PowerPreference powerPreference :
- {wgpu::PowerPreference::LowPower, wgpu::PowerPreference::HighPerformance}) {
- wgpu::RequestAdapterOptions options = {};
+DAWN_INSTANTIATE_WIRE_FUTURE_TEST_P(WireInstanceTests);
+
+// Test that RequestAdapterOptions are passed from the client to the server.
+TEST_P(WireInstanceTests, RequestAdapterPassesOptions) {
+ for (WGPUPowerPreference powerPreference :
+ {WGPUPowerPreference_LowPower, WGPUPowerPreference_HighPerformance}) {
+ WGPURequestAdapterOptions options = {};
options.powerPreference = powerPreference;
- instance.RequestAdapter(&options, cb.Callback(), userdata);
+ InstanceRequestAdapter(instance, &options, nullptr);
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
.WillOnce(WithArg<1>(Invoke([&](const WGPURequestAdapterOptions* apiOptions) {
EXPECT_EQ(apiOptions->powerPreference,
static_cast<WGPUPowerPreference>(options.powerPreference));
EXPECT_EQ(apiOptions->forceFallbackAdapter, options.forceFallbackAdapter);
+ api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Error,
+ nullptr, nullptr);
})));
- FlushClient();
- }
- // Delete the instance now, or it'll call the mock callback after it's deleted.
- instance = nullptr;
+ FlushClient();
+ FlushFutures();
+ ExpectWireCallbacksWhen([&](auto& mockCb) {
+ EXPECT_CALL(mockCb, Call).Times(1);
+
+ FlushCallbacks();
+ });
+ }
}
// Test that RequestAdapter forwards the adapter information to the client.
-TEST_F(WireInstanceTests, RequestAdapterSuccess) {
- wgpu::RequestAdapterOptions options = {};
- MockCallback<WGPURequestAdapterCallback> cb;
- auto* userdata = cb.MakeUserdata(this);
- instance.RequestAdapter(&options, cb.Callback(), userdata);
+TEST_P(WireInstanceTests, RequestAdapterSuccess) {
+ WGPURequestAdapterOptions options = {};
+ InstanceRequestAdapter(instance, &options, nullptr);
WGPUAdapterProperties fakeProperties = {};
fakeProperties.vendorID = 0x134;
@@ -130,13 +128,14 @@
fakeProperties.backendType = WGPUBackendType_D3D12;
fakeProperties.adapterType = WGPUAdapterType_IntegratedGPU;
- wgpu::SupportedLimits fakeLimits = {};
+ WGPUSupportedLimits fakeLimits = {};
+ fakeLimits.nextInChain = nullptr;
fakeLimits.limits.maxTextureDimension1D = 433;
fakeLimits.limits.maxVertexAttributes = 1243;
- std::initializer_list<wgpu::FeatureName> fakeFeatures = {
- wgpu::FeatureName::Depth32FloatStencil8,
- wgpu::FeatureName::TextureCompressionBC,
+ std::initializer_list<WGPUFeatureName> fakeFeatures = {
+ WGPUFeatureName_Depth32FloatStencil8,
+ WGPUFeatureName_TextureCompressionBC,
};
// Expect the server to receive the message. Then, mock a fake reply.
@@ -148,7 +147,7 @@
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
.WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
- *reinterpret_cast<wgpu::SupportedLimits*>(limits) = fakeLimits;
+ *limits = fakeLimits;
return true;
})));
@@ -157,63 +156,64 @@
EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, NotNull()))
.WillOnce(WithArg<1>(Invoke([&](WGPUFeatureName* features) {
- for (wgpu::FeatureName feature : fakeFeatures) {
- *(features++) = static_cast<WGPUFeatureName>(feature);
+ for (WGPUFeatureName feature : fakeFeatures) {
+ *(features++) = feature;
}
return fakeFeatures.size();
})));
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Success,
apiAdapter, nullptr);
}));
+
FlushClient();
+ FlushFutures();
// Expect the callback in the client and all the adapter information to match.
- EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, this))
- .WillOnce(WithArg<1>(Invoke([&](WGPUAdapter cAdapter) {
- wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+ ExpectWireCallbacksWhen([&](auto& mockCb) {
+ EXPECT_CALL(mockCb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, nullptr))
+ .WillOnce(WithArg<1>(Invoke([&](WGPUAdapter adapter) {
+ WGPUAdapterProperties properties = {};
+ wgpuAdapterGetProperties(adapter, &properties);
+ EXPECT_EQ(properties.vendorID, fakeProperties.vendorID);
+ EXPECT_STREQ(properties.vendorName, fakeProperties.vendorName);
+ EXPECT_STREQ(properties.architecture, fakeProperties.architecture);
+ EXPECT_EQ(properties.deviceID, fakeProperties.deviceID);
+ EXPECT_STREQ(properties.name, fakeProperties.name);
+ EXPECT_STREQ(properties.driverDescription, fakeProperties.driverDescription);
+ EXPECT_EQ(properties.backendType, fakeProperties.backendType);
+ EXPECT_EQ(properties.adapterType, fakeProperties.adapterType);
- wgpu::AdapterProperties properties;
- adapter.GetProperties(&properties);
- const auto& rhs = *reinterpret_cast<wgpu::AdapterProperties*>(&fakeProperties);
- EXPECT_EQ(properties.vendorID, rhs.vendorID);
- EXPECT_STREQ(properties.vendorName, rhs.vendorName);
- EXPECT_STREQ(properties.architecture, rhs.architecture);
- EXPECT_EQ(properties.deviceID, rhs.deviceID);
- EXPECT_STREQ(properties.name, rhs.name);
- EXPECT_STREQ(properties.driverDescription, rhs.driverDescription);
- EXPECT_EQ(properties.backendType, rhs.backendType);
- EXPECT_EQ(properties.adapterType, rhs.adapterType);
+ WGPUSupportedLimits limits = {};
+ EXPECT_TRUE(wgpuAdapterGetLimits(adapter, &limits));
+ EXPECT_EQ(limits.limits.maxTextureDimension1D,
+ fakeLimits.limits.maxTextureDimension1D);
+ EXPECT_EQ(limits.limits.maxVertexAttributes, fakeLimits.limits.maxVertexAttributes);
- wgpu::SupportedLimits limits;
- EXPECT_TRUE(adapter.GetLimits(&limits));
- EXPECT_EQ(limits.limits.maxTextureDimension1D, fakeLimits.limits.maxTextureDimension1D);
- EXPECT_EQ(limits.limits.maxVertexAttributes, fakeLimits.limits.maxVertexAttributes);
+ std::vector<WGPUFeatureName> features;
+ features.resize(wgpuAdapterEnumerateFeatures(adapter, nullptr));
+ ASSERT_EQ(features.size(), fakeFeatures.size());
+ EXPECT_EQ(wgpuAdapterEnumerateFeatures(adapter, &features[0]), features.size());
- std::vector<wgpu::FeatureName> features;
- features.resize(adapter.EnumerateFeatures(nullptr));
- ASSERT_EQ(features.size(), fakeFeatures.size());
- EXPECT_EQ(adapter.EnumerateFeatures(&features[0]), features.size());
+ std::unordered_set<WGPUFeatureName> featureSet(fakeFeatures);
+ for (WGPUFeatureName feature : features) {
+ EXPECT_EQ(featureSet.erase(feature), 1u);
+ }
+ })));
- std::unordered_set<wgpu::FeatureName> featureSet(fakeFeatures);
- for (wgpu::FeatureName feature : features) {
- EXPECT_EQ(featureSet.erase(feature), 1u);
- }
- })));
- FlushServer();
+ FlushCallbacks();
+ });
}
-// Test that features returned by the implementation that aren't supported
-// in the wire are not exposed.
-TEST_F(WireInstanceTests, RequestAdapterWireLacksFeatureSupport) {
- wgpu::RequestAdapterOptions options = {};
- MockCallback<WGPURequestAdapterCallback> cb;
- auto* userdata = cb.MakeUserdata(this);
- instance.RequestAdapter(&options, cb.Callback(), userdata);
+// Test that features returned by the implementation that aren't supported in the wire are not
+// exposed.
+TEST_P(WireInstanceTests, RequestAdapterWireLacksFeatureSupport) {
+ WGPURequestAdapterOptions options = {};
+ InstanceRequestAdapter(instance, &options, nullptr);
- std::initializer_list<wgpu::FeatureName> fakeFeatures = {
- wgpu::FeatureName::Depth32FloatStencil8,
+ std::initializer_list<WGPUFeatureName> fakeFeatures = {
+ WGPUFeatureName_Depth32FloatStencil8,
// Some value that is not a valid feature
- static_cast<wgpu::FeatureName>(-2),
+ static_cast<WGPUFeatureName>(-2),
};
// Expect the server to receive the message. Then, mock a fake reply.
@@ -240,36 +240,36 @@
EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, NotNull()))
.WillOnce(WithArg<1>(Invoke([&](WGPUFeatureName* features) {
- for (wgpu::FeatureName feature : fakeFeatures) {
- *(features++) = static_cast<WGPUFeatureName>(feature);
+ for (WGPUFeatureName feature : fakeFeatures) {
+ *(features++) = feature;
}
return fakeFeatures.size();
})));
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Success,
apiAdapter, nullptr);
}));
+
FlushClient();
+ FlushFutures();
// Expect the callback in the client and all the adapter information to match.
- EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, this))
- .WillOnce(WithArg<1>(Invoke([&](WGPUAdapter cAdapter) {
- wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+ ExpectWireCallbacksWhen([&](auto& mockCb) {
+ EXPECT_CALL(mockCb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, nullptr))
+ .WillOnce(WithArg<1>(Invoke([&](WGPUAdapter adapter) {
+ WGPUFeatureName feature;
+ ASSERT_EQ(wgpuAdapterEnumerateFeatures(adapter, nullptr), 1u);
+ wgpuAdapterEnumerateFeatures(adapter, &feature);
+ EXPECT_EQ(feature, WGPUFeatureName_Depth32FloatStencil8);
+ })));
- wgpu::FeatureName feature;
- ASSERT_EQ(adapter.EnumerateFeatures(nullptr), 1u);
- adapter.EnumerateFeatures(&feature);
-
- EXPECT_EQ(feature, wgpu::FeatureName::Depth32FloatStencil8);
- })));
- FlushServer();
+ FlushCallbacks();
+ });
}
// Test that RequestAdapter errors forward to the client.
-TEST_F(WireInstanceTests, RequestAdapterError) {
- wgpu::RequestAdapterOptions options = {};
- MockCallback<WGPURequestAdapterCallback> cb;
- auto* userdata = cb.MakeUserdata(this);
- instance.RequestAdapter(&options, cb.Callback(), userdata);
+TEST_P(WireInstanceTests, RequestAdapterError) {
+ WGPURequestAdapterOptions options = {};
+ InstanceRequestAdapter(instance, &options, nullptr);
// Expect the server to receive the message. Then, mock an error.
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
@@ -277,36 +277,49 @@
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Error,
nullptr, "Some error");
}));
+
FlushClient();
+ FlushFutures();
// Expect the callback in the client.
- EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Error, nullptr, StrEq("Some error"), this))
- .Times(1);
- FlushServer();
+ ExpectWireCallbacksWhen([&](auto& mockCb) {
+ EXPECT_CALL(mockCb,
+ Call(WGPURequestAdapterStatus_Error, nullptr, StrEq("Some error"), nullptr))
+ .Times(1);
+
+ FlushCallbacks();
+ });
}
-// Test that RequestAdapter receives unknown status if the instance is deleted
-// before the callback happens.
-TEST_F(WireInstanceTests, RequestAdapterInstanceDestroyedBeforeCallback) {
- wgpu::RequestAdapterOptions options = {};
- MockCallback<WGPURequestAdapterCallback> cb;
- auto* userdata = cb.MakeUserdata(this);
- instance.RequestAdapter(&options, cb.Callback(), userdata);
+// Test that RequestAdapter receives unknown status if the instance is deleted before the callback
+// happens.
+TEST_P(WireInstanceTests, DISABLED_RequestAdapterInstanceDestroyedBeforeCallback) {
+ // TODO(crbug.com/dawn/2061) This test does not currently pass because the callbacks aren't
+ // actually triggered by the destruction of the instance at the moment. Once we move the
+ // EventManager to be per-Instance, this test should pass.
+ WGPURequestAdapterOptions options = {};
+ InstanceRequestAdapter(instance, &options, nullptr);
- EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Unknown, nullptr, NotNull(), this)).Times(1);
- instance = nullptr;
+ ExpectWireCallbacksWhen([&](auto& mockCb) {
+ EXPECT_CALL(mockCb, Call(WGPURequestAdapterStatus_Unknown, nullptr, NotNull(), nullptr))
+ .Times(1);
+
+ wgpuInstanceRelease(instance);
+ });
}
// Test that RequestAdapter receives unknown status if the wire is disconnected
// before the callback happens.
-TEST_F(WireInstanceTests, RequestAdapterWireDisconnectBeforeCallback) {
- wgpu::RequestAdapterOptions options = {};
- MockCallback<WGPURequestAdapterCallback> cb;
- auto* userdata = cb.MakeUserdata(this);
- instance.RequestAdapter(&options, cb.Callback(), userdata);
+TEST_P(WireInstanceTests, RequestAdapterWireDisconnectBeforeCallback) {
+ WGPURequestAdapterOptions options = {};
+ InstanceRequestAdapter(instance, &options, nullptr);
- EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Unknown, nullptr, NotNull(), this)).Times(1);
- GetWireClient()->Disconnect();
+ ExpectWireCallbacksWhen([&](auto& mockCb) {
+ EXPECT_CALL(mockCb, Call(WGPURequestAdapterStatus_Unknown, nullptr, NotNull(), nullptr))
+ .Times(1);
+
+ GetWireClient()->Disconnect();
+ });
}
} // anonymous namespace
diff --git a/src/dawn/wire/client/Client.cpp b/src/dawn/wire/client/Client.cpp
index 0112574..52ebab8 100644
--- a/src/dawn/wire/client/Client.cpp
+++ b/src/dawn/wire/client/Client.cpp
@@ -61,8 +61,8 @@
}
Client::~Client() {
- DestroyAllObjects();
mEventManager->ShutDown();
+ DestroyAllObjects();
}
void Client::DestroyAllObjects() {
diff --git a/src/dawn/wire/client/EventManager.h b/src/dawn/wire/client/EventManager.h
index 277c088..8c891ce 100644
--- a/src/dawn/wire/client/EventManager.h
+++ b/src/dawn/wire/client/EventManager.h
@@ -46,13 +46,16 @@
enum class EventType {
MapAsync,
+ RequestAdapter,
WorkDone,
};
-// Implementations of TrackedEvents must implement the CompleteImpl and ReadyHook functions. In most
-// scenarios, the CompleteImpl function should call the callbacks while the ReadyHook should process
-// and copy memory (if necessary) from the wire deserialization buffer into a local copy that can be
-// readily used by the user callback.
+// Implementations of TrackedEvents must implement the GetType, CompleteImpl, and ReadyHook
+// functions. In most scenarios, the CompleteImpl function should call the callbacks while the
+// ReadyHook should process and copy memory (if necessary) from the wire deserialization buffer
+// into a local copy that can be readily used by the user callback. Specifically, the wire
+// deserialization data is guaranteed to be alive when the ReadyHook is called, but not when
+// CompleteImpl is called.
class TrackedEvent : NonMovable {
public:
explicit TrackedEvent(WGPUCallbackMode mode);
diff --git a/src/dawn/wire/client/Instance.cpp b/src/dawn/wire/client/Instance.cpp
index aa36c1f..f88b467 100644
--- a/src/dawn/wire/client/Instance.cpp
+++ b/src/dawn/wire/client/Instance.cpp
@@ -27,10 +27,80 @@
#include "dawn/wire/client/Instance.h"
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "dawn/common/Log.h"
#include "dawn/wire/client/Client.h"
#include "dawn/wire/client/EventManager.h"
namespace dawn::wire::client {
+namespace {
+
+class RequestAdapterEvent : public TrackedEvent {
+ public:
+ static constexpr EventType kType = EventType::RequestAdapter;
+
+ RequestAdapterEvent(const WGPURequestAdapterCallbackInfo& callbackInfo, Adapter* adapter)
+ : TrackedEvent(callbackInfo.mode),
+ mCallback(callbackInfo.callback),
+ mUserdata(callbackInfo.userdata),
+ mAdapter(adapter) {}
+
+ EventType GetType() override { return kType; }
+
+ void ReadyHook(WGPURequestAdapterStatus status,
+ const char* message,
+ const WGPUAdapterProperties* properties,
+ const WGPUSupportedLimits* limits,
+ uint32_t featuresCount,
+ const WGPUFeatureName* features) {
+ DAWN_ASSERT(mAdapter != nullptr);
+ mStatus = status;
+ if (message != nullptr) {
+ mMessage = message;
+ }
+ if (status == WGPURequestAdapterStatus_Success) {
+ mAdapter->SetProperties(properties);
+ mAdapter->SetLimits(limits);
+ mAdapter->SetFeatures(features, featuresCount);
+ }
+ }
+
+ private:
+ void CompleteImpl(FutureID futureID, EventCompletionType completionType) override {
+ if (completionType == EventCompletionType::Shutdown) {
+ mStatus = WGPURequestAdapterStatus_Unknown;
+ mMessage = "GPU connection lost";
+ }
+ if (mStatus != WGPURequestAdapterStatus_Success && mAdapter != nullptr) {
+ // If there was an error, we may need to reclaim the adapter allocation, otherwise the
+ // adapter is returned to the user who owns it.
+ mAdapter->GetClient()->Free(mAdapter);
+ mAdapter = nullptr;
+ }
+ if (mCallback) {
+ mCallback(mStatus, ToAPI(mAdapter), mMessage ? mMessage->c_str() : nullptr, mUserdata);
+ }
+ }
+
+ WGPURequestAdapterCallback mCallback;
+ void* mUserdata;
+
+ // Note that the message is optional because we want to return nullptr when it wasn't set
+ // instead of a pointer to an empty string.
+ WGPURequestAdapterStatus mStatus;
+ std::optional<std::string> mMessage;
+
+ // The adapter is created when we call RequestAdapter(F). It is guaranteed to be alive
+ // throughout the duration of a RequestAdapterEvent because the Event essentially takes
+ // ownership of it until either an error occurs at which point the Event cleans it up, or it
+ // returns the adapter to the user who then takes ownership as the Event goes away.
+ Adapter* mAdapter = nullptr;
+};
+
+} // anonymous namespace
// Free-standing API functions
@@ -51,43 +121,38 @@
// Instance
-Instance::~Instance() {
- mRequestAdapterRequests.CloseAll([](RequestAdapterData* request) {
- request->callback(WGPURequestAdapterStatus_Unknown, nullptr,
- "Instance destroyed before callback", request->userdata);
- });
-}
-
-void Instance::CancelCallbacksForDisconnect() {
- mRequestAdapterRequests.CloseAll([](RequestAdapterData* request) {
- request->callback(WGPURequestAdapterStatus_Unknown, nullptr, "GPU connection lost",
- request->userdata);
- });
-}
-
void Instance::RequestAdapter(const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata) {
- Client* client = GetClient();
- if (client->IsDisconnected()) {
- callback(WGPURequestAdapterStatus_Error, nullptr, "GPU connection lost", userdata);
- return;
- }
+ WGPURequestAdapterCallbackInfo callbackInfo = {};
+ callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
+ callbackInfo.callback = callback;
+ callbackInfo.userdata = userdata;
+ RequestAdapterF(options, callbackInfo);
+}
+WGPUFuture Instance::RequestAdapterF(const WGPURequestAdapterOptions* options,
+ const WGPURequestAdapterCallbackInfo& callbackInfo) {
+ Client* client = GetClient();
Adapter* adapter = client->Make<Adapter>();
- uint64_t serial = mRequestAdapterRequests.Add({callback, adapter->GetWireId(), userdata});
+ auto [futureIDInternal, tracked] = client->GetEventManager()->TrackEvent(
+ std::make_unique<RequestAdapterEvent>(callbackInfo, adapter));
+ if (!tracked) {
+ return {futureIDInternal};
+ }
InstanceRequestAdapterCmd cmd;
cmd.instanceId = GetWireId();
- cmd.requestSerial = serial;
+ cmd.future = {futureIDInternal};
cmd.adapterObjectHandle = adapter->GetWireHandle();
cmd.options = options;
client->SerializeCommand(cmd);
+ return {futureIDInternal};
}
bool Client::DoInstanceRequestAdapterCallback(Instance* instance,
- uint64_t requestSerial,
+ WGPUFuture future,
WGPURequestAdapterStatus status,
const char* message,
const WGPUAdapterProperties* properties,
@@ -98,39 +163,20 @@
if (instance == nullptr) {
return true;
}
- return instance->OnRequestAdapterCallback(requestSerial, status, message, properties, limits,
+ return instance->OnRequestAdapterCallback(future, status, message, properties, limits,
featuresCount, features);
}
-bool Instance::OnRequestAdapterCallback(uint64_t requestSerial,
+bool Instance::OnRequestAdapterCallback(WGPUFuture future,
WGPURequestAdapterStatus status,
const char* message,
const WGPUAdapterProperties* properties,
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features) {
- RequestAdapterData request;
- if (!mRequestAdapterRequests.Acquire(requestSerial, &request)) {
- return false;
- }
-
- Client* client = GetClient();
- Adapter* adapter = client->Get<Adapter>(request.adapterObjectId);
-
- // If the return status is a failure we should give a null adapter to the callback and
- // free the allocation.
- if (status != WGPURequestAdapterStatus_Success) {
- client->Free(adapter);
- request.callback(status, nullptr, message, request.userdata);
- return true;
- }
-
- adapter->SetProperties(properties);
- adapter->SetLimits(limits);
- adapter->SetFeatures(features, featuresCount);
-
- request.callback(status, ToAPI(adapter), message, request.userdata);
- return true;
+ return GetClient()->GetEventManager()->SetFutureReady<RequestAdapterEvent>(
+ future.id, status, message, properties, limits, featuresCount, features) ==
+ WireResult::Success;
}
void Instance::ProcessEvents() {
diff --git a/src/dawn/wire/client/Instance.h b/src/dawn/wire/client/Instance.h
index 4186392..9c9f92d 100644
--- a/src/dawn/wire/client/Instance.h
+++ b/src/dawn/wire/client/Instance.h
@@ -42,14 +42,13 @@
class Instance final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
- ~Instance() override;
-
- void CancelCallbacksForDisconnect() override;
void RequestAdapter(const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata);
- bool OnRequestAdapterCallback(uint64_t requestSerial,
+ WGPUFuture RequestAdapterF(const WGPURequestAdapterOptions* options,
+ const WGPURequestAdapterCallbackInfo& callbackInfo);
+ bool OnRequestAdapterCallback(WGPUFuture future,
WGPURequestAdapterStatus status,
const char* message,
const WGPUAdapterProperties* properties,
@@ -59,14 +58,6 @@
void ProcessEvents();
WGPUWaitStatus WaitAny(size_t count, WGPUFutureWaitInfo* infos, uint64_t timeoutNS);
-
- private:
- struct RequestAdapterData {
- WGPURequestAdapterCallback callback = nullptr;
- ObjectId adapterObjectId;
- void* userdata = nullptr;
- };
- RequestTracker<RequestAdapterData> mRequestAdapterRequests;
};
} // namespace dawn::wire::client
diff --git a/src/dawn/wire/server/Server.h b/src/dawn/wire/server/Server.h
index d6bce51..e20a300 100644
--- a/src/dawn/wire/server/Server.h
+++ b/src/dawn/wire/server/Server.h
@@ -144,7 +144,7 @@
using CallbackUserdata::CallbackUserdata;
ObjectHandle instance;
- uint64_t requestSerial;
+ WGPUFuture future;
ObjectId adapterObjectId;
};
diff --git a/src/dawn/wire/server/ServerInstance.cpp b/src/dawn/wire/server/ServerInstance.cpp
index 1f4b5fa..446e089 100644
--- a/src/dawn/wire/server/ServerInstance.cpp
+++ b/src/dawn/wire/server/ServerInstance.cpp
@@ -34,7 +34,7 @@
namespace dawn::wire::server {
WireResult Server::DoInstanceRequestAdapter(Known<WGPUInstance> instance,
- uint64_t requestSerial,
+ WGPUFuture future,
ObjectHandle adapterHandle,
const WGPURequestAdapterOptions* options) {
Known<WGPUAdapter> adapter;
@@ -42,7 +42,7 @@
auto userdata = MakeUserdata<RequestAdapterUserdata>();
userdata->instance = instance.AsHandle();
- userdata->requestSerial = requestSerial;
+ userdata->future = future;
userdata->adapterObjectId = adapter.id;
mProcs.instanceRequestAdapter(instance->handle, options,
@@ -57,7 +57,7 @@
const char* message) {
ReturnInstanceRequestAdapterCallbackCmd cmd = {};
cmd.instance = data->instance;
- cmd.requestSerial = data->requestSerial;
+ cmd.future = data->future;
cmd.status = status;
cmd.message = message;