Reland "[WGPUFuture] Move the EventManager in the wire to appear in the Instance."
- Remove attempts to serialize the event manager handle for fuzzing. It
shouldn't be important because its a value that is just passed through
from the client to the server so that the client can identify the
event manager later, but since the fuzz tests don't actually run a
Dawn wire client, the value is unimportant.
This is a reland of commit 6ecbeedd4e016dfa304082bc7e3639b54d179ce1
Original change's description:
> [WGPUFuture] Move the EventManager in the wire to appear in the Instance.
>
> - Note that the EventManager only appears to be in the Instance because
> it may need to outlive the Instance, and so actually lives on the
> Client.
>
> Bug: dawn:2061
> Change-Id: I601a27cd7ee90e4dcb53fd9e45144a6059c00054
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/167840
> Commit-Queue: Loko Kung <lokokung@google.com>
> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
> Reviewed-by: Austin Eng <enga@chromium.org>
> Kokoro: Kokoro <noreply+kokoro@google.com>
Bug: dawn:2061
Change-Id: I7d24a9dd44057d90ecf3b0a562c0eeee5f2b308e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/169063
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp b/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp
index 102f498..7d0e990 100644
--- a/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp
+++ b/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp
@@ -69,7 +69,10 @@
{% elif member.type.name.get() == "ObjectId" %}
{{ convert_objectid(member, in, out, access) }}
{% elif member.type.name.get() == "ObjectHandle" %}
- {{ convert_objecthandle(member, in, out, in_access) }}
+ //* Only convert the handle if it maps to an object. Otherwise don't serialize it at all.
+ {% if member.handle_type %}
+ {{ convert_objecthandle(member, in, out, in_access) }}
+ {% endif %}
{% else %}
{{out}} = {{in}}({{in_access}});
{% endif %}
diff --git a/generator/templates/dawn/wire/client/ApiProcs.cpp b/generator/templates/dawn/wire/client/ApiProcs.cpp
index c1cff6d..6f27e18 100644
--- a/generator/templates/dawn/wire/client/ApiProcs.cpp
+++ b/generator/templates/dawn/wire/client/ApiProcs.cpp
@@ -36,6 +36,18 @@
namespace dawn::wire::client {
+ // Template function for constexpr branching when creating new objects.
+ template <typename Parent, typename Child, typename... Args>
+ Child* Create(Parent p, Args... args) {
+ if constexpr (std::is_constructible_v<Child, const ObjectBaseParams&, decltype(args)...>) {
+ return p->GetClient()->template Make<Child>(args...);
+ } else if constexpr (std::is_constructible_v<Child, const ObjectBaseParams&, const ObjectHandle&, decltype(args)...>) {
+ return p->GetClient()->template Make<Child>(p->GetEventManagerHandle(), args...);
+ } else {
+ return p->GetClient()->template Make<Child>();
+ }
+ }
+
//* Outputs an rvalue that's the number of elements a pointer member points to.
{% macro member_length(member, accessor) -%}
{%- if member.length == "constant" -%}
@@ -73,22 +85,11 @@
//* For object creation, store the object ID the client will use for the result.
{% if method.return_type.category == "object" %}
{% set ReturnObj = method.return_type.name.CamelCase() %}
-
- {{ReturnObj}}* returnObject;
- if constexpr (std::is_constructible_v<
- {{- ReturnObj}}, const ObjectBaseParams&
+ {{ReturnObj}}* returnObject = Create<{{as_wireType(type)}}, {{ReturnObj}}>(self
{%- for arg in method.arguments -%}
- , decltype({{as_varName(arg.name)}})
+ , {{as_varName(arg.name)}}
{%- endfor -%}
- >) {
- returnObject = self->GetClient()->Make<{{ReturnObj}}>(
- {%- for arg in method.arguments -%}
- {% if not loop.first %}, {% endif %}{{as_varName(arg.name)}}
- {%- endfor -%}
- );
- } else {
- returnObject = self->GetClient()->Make<{{ReturnObj}}>();
- }
+ );
cmd.result = returnObject->GetWireHandle();
{% endif %}
diff --git a/include/dawn/wire/WireClient.h b/include/dawn/wire/WireClient.h
index 448318f..5b0a3fa 100644
--- a/include/dawn/wire/WireClient.h
+++ b/include/dawn/wire/WireClient.h
@@ -86,7 +86,7 @@
ReservedTexture ReserveTexture(WGPUDevice device, const WGPUTextureDescriptor* descriptor);
ReservedSwapChain ReserveSwapChain(WGPUDevice device,
const WGPUSwapChainDescriptor* descriptor);
- ReservedDevice ReserveDevice();
+ ReservedDevice ReserveDevice(WGPUInstance instance);
ReservedInstance ReserveInstance(const WGPUInstanceDescriptor* descriptor = nullptr);
void ReclaimTextureReservation(const ReservedTexture& reservation);
diff --git a/src/dawn/dawn_wire.json b/src/dawn/dawn_wire.json
index 09f0fad..d0ded98 100644
--- a/src/dawn/dawn_wire.json
+++ b/src/dawn/dawn_wire.json
@@ -33,6 +33,7 @@
"commands": {
"buffer map async": [
{ "name": "buffer id", "type": "ObjectId", "id_type": "buffer" },
+ { "name": "event manager handle", "type": "ObjectHandle" },
{ "name": "future", "type": "future" },
{ "name": "mode", "type": "map mode" },
{ "name": "offset", "type": "uint64_t"},
@@ -76,6 +77,7 @@
],
"queue on submitted work done": [
{ "name": "queue id", "type": "ObjectId", "id_type": "queue" },
+ { "name": "event manager handle", "type": "ObjectHandle" },
{ "name": "future", "type": "future" }
],
"queue write buffer": [
@@ -99,6 +101,7 @@
],
"instance request adapter": [
{ "name": "instance id", "type": "ObjectId", "id_type": "instance" },
+ { "name": "event manager handle", "type": "ObjectHandle" },
{ "name": "future", "type": "future" },
{ "name": "adapter object handle", "type": "ObjectHandle", "handle_type": "adapter"},
{ "name": "options", "type": "request adapter options", "annotation": "const*", "optional": true }
@@ -112,7 +115,8 @@
},
"return commands": {
"buffer map async callback": [
- { "name": "buffer", "type": "ObjectHandle", "handle_type": "buffer" },
+ { "name": "buffer", "type": "ObjectHandle", "handle_type": "buffer", "_comment": "TODO(dawn:2061) Remove this field once mapping is updated." },
+ { "name": "event manager", "type": "ObjectHandle" },
{ "name": "future", "type": "future" },
{ "name": "status", "type": "uint32_t" },
{ "name": "read data update info length", "type": "uint64_t" },
@@ -152,8 +156,8 @@
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
],
"queue work done callback": [
- { "name": "queue", "type": "ObjectHandle", "handle_type": "queue" },
- { "name": "future", "type": "future" },
+ { "name": "event manager", "type": "ObjectHandle" },
+ { "name": "future", "type": "future" },
{ "name": "status", "type": "queue work done status" }
],
"shader module get compilation info callback": [
@@ -163,7 +167,7 @@
{ "name": "info", "type": "compilation info", "annotation": "const*", "optional": true }
],
"instance request adapter callback": [
- { "name": "instance", "type": "ObjectHandle", "handle_type": "instance" },
+ { "name": "event manager", "type": "ObjectHandle" },
{ "name": "future", "type": "future" },
{ "name": "status", "type": "request adapter status" },
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true },
diff --git a/src/dawn/samples/SampleUtils.cpp b/src/dawn/samples/SampleUtils.cpp
index 7c48112..f1aa2a9 100644
--- a/src/dawn/samples/SampleUtils.cpp
+++ b/src/dawn/samples/SampleUtils.cpp
@@ -236,7 +236,11 @@
procs = dawn::wire::client::GetProcs();
s2cBuf->SetHandler(wireClient);
- auto deviceReservation = wireClient->ReserveDevice();
+ auto instanceReservation = wireClient->ReserveInstance();
+ wireServer->InjectInstance(instance->Get(), instanceReservation.id,
+ instanceReservation.generation);
+
+ auto deviceReservation = wireClient->ReserveDevice(instanceReservation.instance);
wireServer->InjectDevice(backendDevice, deviceReservation.id,
deviceReservation.generation);
cDevice = deviceReservation.device;
diff --git a/src/dawn/tests/unittests/GetProcAddressTests.cpp b/src/dawn/tests/unittests/GetProcAddressTests.cpp
index b3ea500..1f8dabc 100644
--- a/src/dawn/tests/unittests/GetProcAddressTests.cpp
+++ b/src/dawn/tests/unittests/GetProcAddressTests.cpp
@@ -91,7 +91,8 @@
clientDesc.serializer = mC2sBuf.get();
mWireClient = std::make_unique<wire::WireClient>(clientDesc);
- mDevice = wgpu::Device::Acquire(mWireClient->ReserveDevice().device);
+ mDevice = wgpu::Device::Acquire(
+ mWireClient->ReserveDevice(ToAPI(mNativeInstance.Get())).device);
mProcs = wire::client::GetProcs();
break;
}
diff --git a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
index d3c8af7..469ef93 100644
--- a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
@@ -55,18 +55,9 @@
void SetUp() override {
WireTest::SetUp();
- auto reservation = GetWireClient()->ReserveInstance();
- instance = wgpu::Instance::Acquire(reservation.instance);
-
- WGPUInstance apiInstance = api.GetNewInstance();
- EXPECT_CALL(api, InstanceReference(apiInstance));
- EXPECT_TRUE(
- GetWireServer()->InjectInstance(apiInstance, reservation.id, reservation.generation));
-
- wgpu::RequestAdapterOptions options = {};
+ WGPURequestAdapterOptions options = {};
MockCallback<WGPURequestAdapterCallback> cb;
- auto* userdata = cb.MakeUserdata(this);
- instance.RequestAdapter(&options, cb.Callback(), userdata);
+ wgpuInstanceRequestAdapter(instance, &options, cb.Callback(), cb.MakeUserdata(this));
// Expect the server to receive the message. Then, mock a fake reply.
apiAdapter = api.GetNewAdapter();
@@ -111,12 +102,10 @@
void TearDown() override {
adapter = nullptr;
- instance = nullptr;
WireTest::TearDown();
}
WGPUAdapter apiAdapter;
- wgpu::Instance instance;
wgpu::Adapter adapter;
};
diff --git a/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp b/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
index d9c96b9..889b52f 100644
--- a/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
@@ -173,7 +173,7 @@
// Expect release on all objects created by the client. Note: the device
// should be deleted first because it may free its reference to the default queue
// on deletion.
- Sequence s1, s2, s3;
+ Sequence s1, s2, s3, s4;
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
.Times(1)
.InSequence(s1, s2);
@@ -183,10 +183,11 @@
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, nullptr, nullptr))
.Times(1)
.InSequence(s1, s2);
- EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2, s3);
+ EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2, s3, s4);
EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1).InSequence(s1);
EXPECT_CALL(api, CommandEncoderRelease(apiCommandEncoder)).Times(1).InSequence(s2);
EXPECT_CALL(api, SamplerRelease(apiSampler)).Times(1).InSequence(s3);
+ EXPECT_CALL(api, InstanceRelease(apiInstance)).Times(1).InSequence(s4);
FlushClient();
// Signal that we already released and cleared callbacks for |apiDevice|
diff --git a/src/dawn/tests/unittests/wire/WireFutureTest.h b/src/dawn/tests/unittests/wire/WireFutureTest.h
index b065ddd..042db62 100644
--- a/src/dawn/tests/unittests/wire/WireFutureTest.h
+++ b/src/dawn/tests/unittests/wire/WireFutureTest.h
@@ -96,20 +96,6 @@
protected:
using testing::WithParamInterface<Params>::GetParam;
- void SetUp() override {
- WireTest::SetUp();
-
- auto reservation = GetWireClient()->ReserveInstance();
- instance = reservation.instance;
-
- apiInstance = api.GetNewInstance();
- EXPECT_CALL(api, InstanceReference(apiInstance));
- EXPECT_TRUE(
- GetWireServer()->InjectInstance(apiInstance, reservation.id, reservation.generation));
- }
-
- void TearDown() override { WireTest::TearDown(); }
-
// Calls the actual API that the test suite is exercising given the callback mode. This should
// be used in favor of directly calling the API because the Async mode actually calls a
// different entry point.
@@ -203,9 +189,6 @@
}
}
- WGPUInstance instance;
- WGPUInstance apiInstance;
-
private:
AsyncFT mAsyncF = AsyncF;
FutureFT mFutureF = FutureF;
diff --git a/src/dawn/tests/unittests/wire/WireInjectDeviceTests.cpp b/src/dawn/tests/unittests/wire/WireInjectDeviceTests.cpp
index 2e129ae..5b0a92f 100644
--- a/src/dawn/tests/unittests/wire/WireInjectDeviceTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireInjectDeviceTests.cpp
@@ -47,7 +47,7 @@
// Test that reserving and injecting a device makes calls on the client object forward to the
// server object correctly.
TEST_F(WireInjectDeviceTests, CallAfterReserveInject) {
- ReservedDevice reservation = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation = GetWireClient()->ReserveDevice(instance);
WGPUDevice serverDevice = api.GetNewDevice();
EXPECT_CALL(api, DeviceReference(serverDevice));
@@ -73,8 +73,8 @@
// Test that reserve correctly returns different IDs each time.
TEST_F(WireInjectDeviceTests, ReserveDifferentIDs) {
- ReservedDevice reservation1 = GetWireClient()->ReserveDevice();
- ReservedDevice reservation2 = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation1 = GetWireClient()->ReserveDevice(instance);
+ ReservedDevice reservation2 = GetWireClient()->ReserveDevice(instance);
ASSERT_NE(reservation1.id, reservation2.id);
ASSERT_NE(reservation1.device, reservation2.device);
@@ -82,7 +82,7 @@
// Test that injecting the same id without a destroy first fails.
TEST_F(WireInjectDeviceTests, InjectExistingID) {
- ReservedDevice reservation = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation = GetWireClient()->ReserveDevice(instance);
WGPUDevice serverDevice = api.GetNewDevice();
EXPECT_CALL(api, DeviceReference(serverDevice));
@@ -106,7 +106,7 @@
// Test that the server only borrows the device and does a single reference-release
TEST_F(WireInjectDeviceTests, InjectedDeviceLifetime) {
- ReservedDevice reservation = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation = GetWireClient()->ReserveDevice(instance);
// Injecting the device adds a reference
WGPUDevice serverDevice = api.GetNewDevice();
@@ -133,7 +133,7 @@
// Test that it is an error to get the primary queue of a device before it has been
// injected on the server.
TEST_F(WireInjectDeviceTests, GetQueueBeforeInject) {
- ReservedDevice reservation = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation = GetWireClient()->ReserveDevice(instance);
wgpuDeviceGetQueue(reservation.device);
FlushClient(false);
@@ -142,7 +142,7 @@
// Test that it is valid to get the primary queue of a device after it has been
// injected on the server.
TEST_F(WireInjectDeviceTests, GetQueueAfterInject) {
- ReservedDevice reservation = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation = GetWireClient()->ReserveDevice(instance);
WGPUDevice serverDevice = api.GetNewDevice();
EXPECT_CALL(api, DeviceReference(serverDevice));
@@ -169,8 +169,8 @@
// Test that the list of live devices can be reflected using GetDevice.
TEST_F(WireInjectDeviceTests, ReflectLiveDevices) {
// Reserve two devices.
- ReservedDevice reservation1 = GetWireClient()->ReserveDevice();
- ReservedDevice reservation2 = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation1 = GetWireClient()->ReserveDevice(instance);
+ ReservedDevice reservation2 = GetWireClient()->ReserveDevice(instance);
// Inject both devices.
@@ -217,7 +217,7 @@
// objects instead.
TEST_F(WireInjectDeviceTests, TrackChildObjectsWithTwoReservedDevices) {
// Reserve one device, inject it, and get the primary queue.
- ReservedDevice reservation1 = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation1 = GetWireClient()->ReserveDevice(instance);
WGPUDevice serverDevice1 = api.GetNewDevice();
EXPECT_CALL(api, DeviceReference(serverDevice1));
@@ -236,7 +236,7 @@
FlushClient();
// Reserve a second device, and inject it.
- ReservedDevice reservation2 = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation2 = GetWireClient()->ReserveDevice(instance);
WGPUDevice serverDevice2 = api.GetNewDevice();
EXPECT_CALL(api, DeviceReference(serverDevice2));
@@ -267,17 +267,17 @@
TEST_F(WireInjectDeviceTests, ReclaimDeviceReservation) {
// Test that doing a reservation and full release is an error.
{
- ReservedDevice reservation = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation = GetWireClient()->ReserveDevice(instance);
wgpuDeviceRelease(reservation.device);
FlushClient(false);
}
// Test that doing a reservation and then reclaiming it recycles the ID.
{
- ReservedDevice reservation1 = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation1 = GetWireClient()->ReserveDevice(instance);
GetWireClient()->ReclaimDeviceReservation(reservation1);
- ReservedDevice reservation2 = GetWireClient()->ReserveDevice();
+ ReservedDevice reservation2 = GetWireClient()->ReserveDevice(instance);
// The ID is the same, but the generation is still different.
ASSERT_EQ(reservation1.id, reservation2.id);
diff --git a/src/dawn/tests/unittests/wire/WireTest.cpp b/src/dawn/tests/unittests/wire/WireTest.cpp
index c268bbd..479ebcc 100644
--- a/src/dawn/tests/unittests/wire/WireTest.cpp
+++ b/src/dawn/tests/unittests/wire/WireTest.cpp
@@ -53,7 +53,6 @@
void WireTest::SetUp() {
DawnProcTable mockProcs;
api.GetProcTable(&mockProcs);
- WGPUDevice mockDevice = api.GetNewDevice();
// This SetCallback call cannot be ignored because it is done as soon as we start the server
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(_, _, _)).Times(Exactly(1));
@@ -81,12 +80,18 @@
dawnProcSetProcs(&dawn::wire::client::GetProcs());
- auto deviceReservation = mWireClient->ReserveDevice();
- EXPECT_CALL(api, DeviceReference(mockDevice));
- mWireServer->InjectDevice(mockDevice, deviceReservation.id, deviceReservation.generation);
+ auto instanceReservation = GetWireClient()->ReserveInstance();
+ instance = instanceReservation.instance;
+ apiInstance = api.GetNewInstance();
+ EXPECT_CALL(api, InstanceReference(apiInstance));
+ EXPECT_TRUE(GetWireServer()->InjectInstance(apiInstance, instanceReservation.id,
+ instanceReservation.generation));
+ auto deviceReservation = mWireClient->ReserveDevice(instance);
device = deviceReservation.device;
- apiDevice = mockDevice;
+ apiDevice = api.GetNewDevice();
+ EXPECT_CALL(api, DeviceReference(apiDevice));
+ mWireServer->InjectDevice(apiDevice, deviceReservation.id, deviceReservation.generation);
// The GetQueue is done on WireClient startup so we expect it now.
queue = wgpuDeviceGetQueue(device);
@@ -145,6 +150,7 @@
void WireTest::DeleteServer() {
EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1);
EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1);
+ EXPECT_CALL(api, InstanceRelease(apiInstance)).Times(1);
if (mWireServer) {
// These are called on server destruction to clear the callbacks. They must not be
diff --git a/src/dawn/tests/unittests/wire/WireTest.h b/src/dawn/tests/unittests/wire/WireTest.h
index e7d6710..a45c651 100644
--- a/src/dawn/tests/unittests/wire/WireTest.h
+++ b/src/dawn/tests/unittests/wire/WireTest.h
@@ -145,6 +145,8 @@
void DefaultApiDeviceWasReleased();
testing::StrictMock<MockProcTable> api;
+ WGPUInstance instance;
+ WGPUInstance apiInstance;
WGPUDevice apiDevice;
WGPUQueue apiQueue;
WGPUDevice device;
diff --git a/src/dawn/wire/ObjectHandle.cpp b/src/dawn/wire/ObjectHandle.cpp
index 436901c..813dcd2 100644
--- a/src/dawn/wire/ObjectHandle.cpp
+++ b/src/dawn/wire/ObjectHandle.cpp
@@ -59,6 +59,10 @@
return *this;
}
+bool ObjectHandle::operator==(const ObjectHandle& other) const {
+ return id == other.id && generation == other.generation;
+}
+
bool ObjectHandle::IsValid() const {
return id > 0;
}
diff --git a/src/dawn/wire/ObjectHandle.h b/src/dawn/wire/ObjectHandle.h
index 443df72..117a43a 100644
--- a/src/dawn/wire/ObjectHandle.h
+++ b/src/dawn/wire/ObjectHandle.h
@@ -28,8 +28,11 @@
#ifndef DAWN_WIRE_OBJECTHANDLE_H_
#define DAWN_WIRE_OBJECTHANDLE_H_
+#include <cstddef>
#include <cstdint>
+#include "dawn/common/HashUtils.h"
+
namespace dawn::wire {
using ObjectId = uint32_t;
@@ -59,9 +62,20 @@
ObjectHandle& AssignFrom(const ObjectHandle& rhs);
ObjectHandle& AssignFrom(const volatile ObjectHandle& rhs);
+ bool operator==(const ObjectHandle& other) const;
+
bool IsValid() const;
};
} // namespace dawn::wire
+template <>
+struct std::hash<dawn::wire::ObjectHandle> {
+ size_t operator()(const dawn::wire::ObjectHandle& value) const {
+ size_t hash = dawn::Hash(value.id);
+ dawn::HashCombine(&hash, value.generation);
+ return hash;
+ }
+};
+
#endif // DAWN_WIRE_OBJECTHANDLE_H_
diff --git a/src/dawn/wire/WireClient.cpp b/src/dawn/wire/WireClient.cpp
index 21f62d5..313073f 100644
--- a/src/dawn/wire/WireClient.cpp
+++ b/src/dawn/wire/WireClient.cpp
@@ -51,8 +51,8 @@
return mImpl->ReserveSwapChain(device, descriptor);
}
-ReservedDevice WireClient::ReserveDevice() {
- return mImpl->ReserveDevice();
+ReservedDevice WireClient::ReserveDevice(WGPUInstance instance) {
+ return mImpl->ReserveDevice(instance);
}
ReservedInstance WireClient::ReserveInstance(const WGPUInstanceDescriptor* descriptor) {
diff --git a/src/dawn/wire/client/Adapter.cpp b/src/dawn/wire/client/Adapter.cpp
index c98cc93..3a85769 100644
--- a/src/dawn/wire/client/Adapter.cpp
+++ b/src/dawn/wire/client/Adapter.cpp
@@ -163,7 +163,7 @@
// The descriptor is passed so that the deviceLostCallback can be tracked client-side and called
// when the device is lost.
- Device* device = client->Make<Device>(descriptor);
+ Device* device = client->Make<Device>(GetEventManagerHandle(), descriptor);
uint64_t serial = mRequestDeviceRequests.Add({callback, device->GetWireId(), userdata});
// Ensure the device lost callback isn't serialized as part of the command, as it cannot be
diff --git a/src/dawn/wire/client/Adapter.h b/src/dawn/wire/client/Adapter.h
index b7cf683..dd88635 100644
--- a/src/dawn/wire/client/Adapter.h
+++ b/src/dawn/wire/client/Adapter.h
@@ -39,9 +39,9 @@
namespace dawn::wire::client {
-class Adapter final : public ObjectBase {
+class Adapter final : public ObjectWithEventsBase {
public:
- using ObjectBase::ObjectBase;
+ using ObjectWithEventsBase::ObjectWithEventsBase;
~Adapter() override;
void CancelCallbacksForDisconnect() override;
diff --git a/src/dawn/wire/client/Buffer.cpp b/src/dawn/wire/client/Buffer.cpp
index 974d2c5..d5e44c8 100644
--- a/src/dawn/wire/client/Buffer.cpp
+++ b/src/dawn/wire/client/Buffer.cpp
@@ -159,7 +159,7 @@
// Create the buffer and send the creation command.
// This must happen after any potential error buffer creation
// as server expects allocating ids to be monotonically increasing
- Buffer* buffer = wireClient->Make<Buffer>(descriptor);
+ Buffer* buffer = wireClient->Make<Buffer>(device->GetEventManagerHandle(), descriptor);
buffer->mDestructWriteHandleOnUnmap = false;
if (descriptor->mappedAtCreation) {
@@ -205,8 +205,10 @@
return ToAPI(buffer);
}
-Buffer::Buffer(const ObjectBaseParams& params, const WGPUBufferDescriptor* descriptor)
- : ObjectBase(params),
+Buffer::Buffer(const ObjectBaseParams& params,
+ const ObjectHandle& eventManagerHandle,
+ const WGPUBufferDescriptor* descriptor)
+ : ObjectWithEventsBase(params, eventManagerHandle),
mMapStateData(AcquireRef(new MapStateData{})),
mSize(descriptor->size),
mUsage(static_cast<WGPUBufferUsage>(descriptor->usage)) {}
@@ -218,8 +220,8 @@
bool Buffer::SetFutureStatus(WGPUBufferMapAsyncStatus status) {
DAWN_ASSERT(mMapStateData->pendingRequest);
- return GetClient()->GetEventManager()->SetFutureReady<MapAsyncEvent>(
- mMapStateData->pendingRequest->futureID, status) == WireResult::Success;
+ return GetEventManager().SetFutureReady<MapAsyncEvent>(mMapStateData->pendingRequest->futureID,
+ status) == WireResult::Success;
}
void Buffer::SetFutureStatusAndClearPending(WGPUBufferMapAsyncStatus status) {
@@ -231,7 +233,7 @@
FutureID futureID = mMapStateData->pendingRequest->futureID;
mMapStateData->pendingRequest = std::nullopt;
- DAWN_UNUSED(GetClient()->GetEventManager()->SetFutureReady<MapAsyncEvent>(futureID, status));
+ DAWN_UNUSED(GetEventManager().SetFutureReady<MapAsyncEvent>(futureID, status));
return;
}
@@ -254,14 +256,14 @@
DAWN_ASSERT(GetRefcount() != 0);
Client* client = GetClient();
- auto [futureIDInternal, tracked] = client->GetEventManager()->TrackEvent(
- std::make_unique<MapAsyncEvent>(callbackInfo, mMapStateData));
+ auto [futureIDInternal, tracked] =
+ GetEventManager().TrackEvent(std::make_unique<MapAsyncEvent>(callbackInfo, mMapStateData));
if (!tracked) {
return {futureIDInternal};
}
if (mMapStateData->pendingRequest) {
- DAWN_UNUSED(client->GetEventManager()->SetFutureReady<MapAsyncEvent>(
+ DAWN_UNUSED(GetEventManager().SetFutureReady<MapAsyncEvent>(
futureIDInternal, WGPUBufferMapAsyncStatus_MappingAlreadyPending));
return {futureIDInternal};
}
@@ -284,6 +286,7 @@
// Serialize the command to send to the server.
BufferMapAsyncCmd cmd;
cmd.bufferId = GetWireId();
+ cmd.eventManagerHandle = GetEventManagerHandle();
cmd.future = {futureIDInternal};
cmd.mode = mode;
cmd.offset = offset;
diff --git a/src/dawn/wire/client/Buffer.h b/src/dawn/wire/client/Buffer.h
index 5cf4c6a..f86c918 100644
--- a/src/dawn/wire/client/Buffer.h
+++ b/src/dawn/wire/client/Buffer.h
@@ -64,11 +64,13 @@
MapState mapState = MapState::Unmapped;
};
-class Buffer final : public ObjectBase {
+class Buffer final : public ObjectWithEventsBase {
public:
static WGPUBuffer Create(Device* device, const WGPUBufferDescriptor* descriptor);
- Buffer(const ObjectBaseParams& params, const WGPUBufferDescriptor* descriptor);
+ Buffer(const ObjectBaseParams& params,
+ const ObjectHandle& eventManagerHandle,
+ const WGPUBufferDescriptor* descriptor);
~Buffer() override;
bool OnMapAsyncCallback(WGPUFuture future,
diff --git a/src/dawn/wire/client/Client.cpp b/src/dawn/wire/client/Client.cpp
index 569976b..32d78d2 100644
--- a/src/dawn/wire/client/Client.cpp
+++ b/src/dawn/wire/client/Client.cpp
@@ -52,7 +52,6 @@
Client::Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService)
: ClientBase(), mSerializer(serializer), mMemoryTransferService(memoryTransferService) {
- mEventManager = std::make_unique<EventManager>(this);
if (mMemoryTransferService == nullptr) {
// If a MemoryTransferService is not provided, fall back to inline memory.
mOwnedMemoryTransferService = CreateInlineMemoryTransferService();
@@ -61,7 +60,6 @@
}
Client::~Client() {
- mEventManager->ShutDown();
DestroyAllObjects();
}
@@ -121,8 +119,8 @@
return result;
}
-ReservedDevice Client::ReserveDevice() {
- Device* device = Make<Device>(nullptr);
+ReservedDevice Client::ReserveDevice(WGPUInstance instance) {
+ Device* device = Make<Device>(FromAPI(instance)->GetEventManagerHandle(), nullptr);
ReservedDevice result;
result.device = ToAPI(device);
@@ -139,6 +137,10 @@
return {nullptr, 0, 0};
}
+ // Reserve an EventManager for the given instance and make the association in the map.
+ mEventManagers[ObjectHandle(instance->GetWireId(), instance->GetWireGeneration())] =
+ std::make_unique<EventManager>();
+
ReservedInstance result;
result.instance = ToAPI(instance);
result.id = instance->GetWireId();
@@ -162,8 +164,10 @@
Free(FromAPI(reservation.instance));
}
-EventManager* Client::GetEventManager() {
- return mEventManager.get();
+EventManager& Client::GetEventManager(const ObjectHandle& instance) {
+ auto it = mEventManagers.find(instance);
+ DAWN_ASSERT(it != mEventManagers.end());
+ return *it->second;
}
void Client::Disconnect() {
@@ -184,7 +188,11 @@
object->value()->CancelCallbacksForDisconnect();
}
}
- mEventManager->ShutDown();
+
+ // Transition all event managers to ClientDropped state.
+ for (auto& [_, eventManager] : mEventManagers) {
+ eventManager->TransitionTo(EventManager::State::ClientDropped);
+ }
}
bool Client::IsDisconnected() const {
diff --git a/src/dawn/wire/client/Client.h b/src/dawn/wire/client/Client.h
index 2e112f9..833cdba 100644
--- a/src/dawn/wire/client/Client.h
+++ b/src/dawn/wire/client/Client.h
@@ -29,6 +29,7 @@
#define SRC_DAWN_WIRE_CLIENT_CLIENT_H_
#include <memory>
+#include <unordered_map>
#include <utility>
#include "dawn/common/LinkedList.h"
@@ -88,7 +89,7 @@
ReservedTexture ReserveTexture(WGPUDevice device, const WGPUTextureDescriptor* descriptor);
ReservedSwapChain ReserveSwapChain(WGPUDevice device,
const WGPUSwapChainDescriptor* descriptor);
- ReservedDevice ReserveDevice();
+ ReservedDevice ReserveDevice(WGPUInstance instance);
ReservedInstance ReserveInstance(const WGPUInstanceDescriptor* descriptor);
void ReclaimTextureReservation(const ReservedTexture& reservation);
@@ -106,7 +107,7 @@
mSerializer.SerializeCommand(cmd, *this, std::forward<Extensions>(es)...);
}
- EventManager* GetEventManager();
+ EventManager& GetEventManager(const ObjectHandle& instance);
void Disconnect();
bool IsDisconnected() const;
@@ -122,8 +123,14 @@
MemoryTransferService* mMemoryTransferService = nullptr;
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
PerObjectType<LinkedList<ObjectBase>> mObjects;
- // TODO(crbug.com/dawn/2061) Eventually we want an EventManager per instance not per client.
- std::unique_ptr<EventManager> mEventManager = nullptr;
+ // Map of instance object handles to a corresponding event manager. Note that for now because we
+ // do not have an internal refcount on the instances, i.e. we don't know when the last object
+ // associated with a particular instance is destroyed, this map is not cleaned up until the
+ // client is destroyed. This should only be a problem for users that are creating many
+ // instances. We also cannot currently store the EventManger on the Instance because
+ // spontaneous mode callbacks outlive the instance. We also can't reuse the ObjectStore for the
+ // EventManagers because we need to track old instance handles even after they are reclaimed.
+ std::unordered_map<ObjectHandle, std::unique_ptr<EventManager>> mEventManagers;
bool mDisconnected = false;
};
diff --git a/src/dawn/wire/client/ClientDoers.cpp b/src/dawn/wire/client/ClientDoers.cpp
index 57602d9..210cc53 100644
--- a/src/dawn/wire/client/ClientDoers.cpp
+++ b/src/dawn/wire/client/ClientDoers.cpp
@@ -88,7 +88,9 @@
return device->OnPopErrorScopeCallback(requestSerial, errorType, message);
}
+// TODO(dawn:2061) May be able to move this to Buffer.cpp once we move all mapping logic.
bool Client::DoBufferMapAsyncCallback(Buffer* buffer,
+ ObjectHandle eventManager,
WGPUFuture future,
uint32_t status,
uint64_t readDataUpdateInfoLength,
@@ -100,16 +102,6 @@
return buffer->OnMapAsyncCallback(future, status, readDataUpdateInfoLength, readDataUpdateInfo);
}
-bool Client::DoQueueWorkDoneCallback(Queue* queue,
- WGPUFuture future,
- WGPUQueueWorkDoneStatus status) {
- // The queue might have been deleted or recreated so this isn't an error.
- if (queue == nullptr) {
- return true;
- }
- return queue->OnWorkDoneCallback(future, status);
-}
-
bool Client::DoDeviceCreateComputePipelineAsyncCallback(Device* device,
uint64_t requestSerial,
WGPUCreatePipelineAsyncStatus status,
diff --git a/src/dawn/wire/client/Device.cpp b/src/dawn/wire/client/Device.cpp
index 5000fd3..c87800c 100644
--- a/src/dawn/wire/client/Device.cpp
+++ b/src/dawn/wire/client/Device.cpp
@@ -36,8 +36,10 @@
namespace dawn::wire::client {
-Device::Device(const ObjectBaseParams& params, const WGPUDeviceDescriptor* descriptor)
- : ObjectBase(params), mIsAlive(std::make_shared<bool>()) {
+Device::Device(const ObjectBaseParams& params,
+ const ObjectHandle& eventManagerHandle,
+ const WGPUDeviceDescriptor* descriptor)
+ : ObjectWithEventsBase(params, eventManagerHandle), mIsAlive(std::make_shared<bool>()) {
if (descriptor && descriptor->deviceLostCallback) {
mDeviceLostCallback = descriptor->deviceLostCallback;
mDeviceLostUserdata = descriptor->deviceLostUserdata;
@@ -232,7 +234,7 @@
if (mQueue == nullptr) {
// Get the primary queue for this device.
Client* client = GetClient();
- mQueue = client->Make<Queue>();
+ mQueue = client->Make<Queue>(GetEventManagerHandle());
DeviceGetQueueCmd cmd;
cmd.self = ToAPI(this);
diff --git a/src/dawn/wire/client/Device.h b/src/dawn/wire/client/Device.h
index 0ecbb02..12aca84 100644
--- a/src/dawn/wire/client/Device.h
+++ b/src/dawn/wire/client/Device.h
@@ -43,9 +43,11 @@
class Client;
class Queue;
-class Device final : public ObjectBase {
+class Device final : public ObjectWithEventsBase {
public:
- explicit Device(const ObjectBaseParams& params, const WGPUDeviceDescriptor* descriptor);
+ explicit Device(const ObjectBaseParams& params,
+ const ObjectHandle& eventManagerHandle,
+ const WGPUDeviceDescriptor* descriptor);
~Device() override;
void SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata);
diff --git a/src/dawn/wire/client/EventManager.cpp b/src/dawn/wire/client/EventManager.cpp
index 1614515..130a64e 100644
--- a/src/dawn/wire/client/EventManager.cpp
+++ b/src/dawn/wire/client/EventManager.cpp
@@ -65,14 +65,27 @@
// EventManager
-EventManager::EventManager(Client* client) : mClient(client) {}
+EventManager::~EventManager() {
+ TransitionTo(State::ClientDropped);
+}
std::pair<FutureID, bool> EventManager::TrackEvent(std::unique_ptr<TrackedEvent> event) {
FutureID futureID = mNextFutureID++;
- if (mClient->IsDisconnected()) {
- event->Complete(futureID, EventCompletionType::Shutdown);
- return {futureID, false};
+ switch (mState) {
+ case State::InstanceDropped: {
+ if (event->GetCallbackMode() != WGPUCallbackMode_AllowSpontaneous) {
+ event->Complete(futureID, EventCompletionType::Shutdown);
+ return {futureID, false};
+ }
+ break;
+ }
+ case State::ClientDropped: {
+ event->Complete(futureID, EventCompletionType::Shutdown);
+ return {futureID, false};
+ }
+ case State::Nominal:
+ break;
}
mTrackedEvents.Use([&](auto trackedEvents) {
@@ -83,22 +96,46 @@
return {futureID, true};
}
-void EventManager::ShutDown() {
- // Call any outstanding callbacks before destruction.
+void EventManager::TransitionTo(EventManager::State state) {
+ // If the client is disconnected, this becomes a no-op.
+ if (mState == State::ClientDropped) {
+ return;
+ }
+
+ // Only forward state transitions are allowed.
+ DAWN_ASSERT(state > mState);
+ mState = state;
+
while (true) {
std::map<FutureID, std::unique_ptr<TrackedEvent>> events;
- mTrackedEvents.Use([&](auto trackedEvents) { events = std::move(*trackedEvents); });
-
+ switch (state) {
+ case State::InstanceDropped: {
+ mTrackedEvents.Use([&](auto trackedEvents) {
+ for (auto it = trackedEvents->begin(); it != trackedEvents->end();) {
+ auto& event = it->second;
+ if (event->GetCallbackMode() != WGPUCallbackMode_AllowSpontaneous) {
+ events.emplace(it->first, std::move(event));
+ it = trackedEvents->erase(it);
+ }
+ }
+ });
+ break;
+ }
+ case State::ClientDropped: {
+ mTrackedEvents.Use([&](auto trackedEvents) { events = std::move(*trackedEvents); });
+ break;
+ }
+ case State::Nominal:
+ // We always start in the nominal state so we should never be transitioning to it.
+ DAWN_UNREACHABLE();
+ }
if (events.empty()) {
break;
}
-
- // Ordering guaranteed because we are using a sorted map.
for (auto& [futureID, event] : events) {
event->Complete(futureID, EventCompletionType::Shutdown);
}
}
- mIsShutdown = true;
}
void EventManager::ProcessPollEvents() {
diff --git a/src/dawn/wire/client/EventManager.h b/src/dawn/wire/client/EventManager.h
index 8c891ce..478c7ac 100644
--- a/src/dawn/wire/client/EventManager.h
+++ b/src/dawn/wire/client/EventManager.h
@@ -88,36 +88,35 @@
// TODO(crbug.com/dawn/2060): This should probably be merged together with RequestTracker.
class EventManager final : NonMovable {
public:
- explicit EventManager(Client*);
- ~EventManager() = default;
+ ~EventManager();
+
+ // See mState for breakdown of these states.
+ enum class State { Nominal, InstanceDropped, ClientDropped };
// Returns a pair of the FutureID and a bool that is true iff the event was successfuly tracked,
// false otherwise. Events may not be tracked if the client is already disconnected.
std::pair<FutureID, bool> TrackEvent(std::unique_ptr<TrackedEvent> event);
- void ShutDown();
+
+ // Transitions the EventManager to the given state. Note that states can only go in one
+ // direction, i.e. once the EventManager transitions to InstanceDropped, it cannot transition
+ // back to Nominal, though it may transition to ClientDropped later on.
+ void TransitionTo(State state);
template <typename Event, typename... ReadyArgs>
WireResult SetFutureReady(FutureID futureID, ReadyArgs&&... readyArgs) {
DAWN_ASSERT(futureID > 0);
- // If already shutdown, then all the callbacks should already have fired so we don't need to
- // fire the callback anymore. This may happen if cleanup/dtor functions try to call this
- // unconditionally on objects.
- if (mIsShutdown) {
-#if DAWN_ENABLE_ASSERTS
- // Note we need to use an if clause here because otherwise the DAWN_ASSERT macro will
- // generate code that results in the lambda being in an unevaluated context.
- DAWN_ASSERT(mTrackedEvents.Use([&](auto trackedEvents) {
- return trackedEvents->find(futureID) == trackedEvents->end();
- }));
-#endif
- return WireResult::Success;
+
+ // If the future id is greater than what we have assigned, it must be invalid.
+ if (futureID > mNextFutureID) {
+ return WireResult::FatalError;
}
std::unique_ptr<TrackedEvent> spontaneousEvent;
WIRE_TRY(mTrackedEvents.Use([&](auto trackedEvents) {
auto it = trackedEvents->find(futureID);
if (it == trackedEvents->end()) {
- return WireResult::FatalError;
+ // If the future is not found, it must've already been completed.
+ return WireResult::Success;
}
auto& trackedEvent = it->second;
@@ -150,8 +149,17 @@
WGPUWaitStatus WaitAny(size_t count, WGPUFutureWaitInfo* infos, uint64_t timeoutNS);
private:
- Client* mClient;
- bool mIsShutdown = false;
+ // Different states of the EventManager dictate how new incoming events are handled.
+ // Nominal: Usual state of the manager. All events are tracked and callbacks are fired
+ // depending on the callback modes.
+ // InstanceDropped: Transitioned to this state if the last external reference of the Instance
+ // is dropped. In this mode, any non-spontaneous events are no longer tracked and their
+ // callbacks are immediately called since the user cannot call WaitAny or ProcessEvents
+ // anymore. Any existing non-spontaneous events' callbacks are also called on transition.
+ // ClientDropped: Transitioned to this state once the client is dropped. In this mode, no new
+ // events are tracked and callbacks are all immediately fired. Any existing tracked events'
+ // callbacks are also called on transition.
+ State mState = State::Nominal;
// Tracks all kinds of events (for both WaitAny and ProcessEvents). We use an ordered map so
// that in most cases, event ordering is already implicit when we iterate the map. (Not true for
diff --git a/src/dawn/wire/client/Instance.cpp b/src/dawn/wire/client/Instance.cpp
index 6c0597f0..280ea4b 100644
--- a/src/dawn/wire/client/Instance.cpp
+++ b/src/dawn/wire/client/Instance.cpp
@@ -134,6 +134,12 @@
// Instance
+Instance::Instance(const ObjectBaseParams& params) : ObjectWithEventsBase(params, params.handle) {}
+
+Instance::~Instance() {
+ GetEventManager().TransitionTo(EventManager::State::InstanceDropped);
+}
+
WireResult Instance::Initialize(const WGPUInstanceDescriptor* descriptor) {
if (descriptor == nullptr) {
return WireResult::Success;
@@ -185,15 +191,16 @@
WGPUFuture Instance::RequestAdapterF(const WGPURequestAdapterOptions* options,
const WGPURequestAdapterCallbackInfo& callbackInfo) {
Client* client = GetClient();
- Adapter* adapter = client->Make<Adapter>();
- auto [futureIDInternal, tracked] = client->GetEventManager()->TrackEvent(
- std::make_unique<RequestAdapterEvent>(callbackInfo, adapter));
+ Adapter* adapter = client->Make<Adapter>(GetEventManagerHandle());
+ auto [futureIDInternal, tracked] =
+ GetEventManager().TrackEvent(std::make_unique<RequestAdapterEvent>(callbackInfo, adapter));
if (!tracked) {
return {futureIDInternal};
}
InstanceRequestAdapterCmd cmd;
cmd.instanceId = GetWireId();
+ cmd.eventManagerHandle = GetEventManagerHandle();
cmd.future = {futureIDInternal};
cmd.adapterObjectHandle = adapter->GetWireHandle();
cmd.options = options;
@@ -202,7 +209,7 @@
return {futureIDInternal};
}
-bool Client::DoInstanceRequestAdapterCallback(Instance* instance,
+bool Client::DoInstanceRequestAdapterCallback(ObjectHandle eventManager,
WGPUFuture future,
WGPURequestAdapterStatus status,
const char* message,
@@ -210,30 +217,13 @@
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features) {
- // May have been deleted or recreated so this isn't an error.
- if (instance == nullptr) {
- return true;
- }
- return instance->OnRequestAdapterCallback(future, status, message, properties, limits,
- featuresCount, features);
-}
-
-bool Instance::OnRequestAdapterCallback(WGPUFuture future,
- WGPURequestAdapterStatus status,
- const char* message,
- const WGPUAdapterProperties* properties,
- const WGPUSupportedLimits* limits,
- uint32_t featuresCount,
- const WGPUFeatureName* features) {
- return GetClient()->GetEventManager()->SetFutureReady<RequestAdapterEvent>(
- future.id, status, message, properties, limits, featuresCount, features) ==
- WireResult::Success;
+ return GetEventManager(eventManager)
+ .SetFutureReady<RequestAdapterEvent>(future.id, status, message, properties, limits,
+ featuresCount, features) == WireResult::Success;
}
void Instance::ProcessEvents() {
- // TODO(crbug.com/dawn/2061): This should only process events for this Instance, not others
- // on the same client. When EventManager is moved to Instance, this can be fixed.
- GetClient()->GetEventManager()->ProcessPollEvents();
+ GetEventManager().ProcessPollEvents();
// TODO(crbug.com/dawn/1987): The responsibility of ProcessEvents here is a bit mixed. It both
// processes events coming in from the server, and also prompts the server to check for and
@@ -255,10 +245,7 @@
}
WGPUWaitStatus Instance::WaitAny(size_t count, WGPUFutureWaitInfo* infos, uint64_t timeoutNS) {
- // In principle the EventManager should be on the Instance, not the Client.
- // But it's hard to get from an object to its Instance right now, so we can
- // store it on the Client.
- return GetClient()->GetEventManager()->WaitAny(count, infos, timeoutNS);
+ return GetEventManager().WaitAny(count, infos, timeoutNS);
}
void Instance::GatherWGSLFeatures(const WGPUDawnWireWGSLControl* wgslControl,
diff --git a/src/dawn/wire/client/Instance.h b/src/dawn/wire/client/Instance.h
index 3fce377..43301ef 100644
--- a/src/dawn/wire/client/Instance.h
+++ b/src/dawn/wire/client/Instance.h
@@ -41,9 +41,10 @@
WGPUBool ClientGetInstanceFeatures(WGPUInstanceFeatures* features);
WGPUInstance ClientCreateInstance(WGPUInstanceDescriptor const* descriptor);
-class Instance final : public ObjectBase {
+class Instance final : public ObjectWithEventsBase {
public:
- using ObjectBase::ObjectBase;
+ explicit Instance(const ObjectBaseParams& params);
+ ~Instance() override;
WireResult Initialize(const WGPUInstanceDescriptor* descriptor);
@@ -52,13 +53,6 @@
void* userdata);
WGPUFuture RequestAdapterF(const WGPURequestAdapterOptions* options,
const WGPURequestAdapterCallbackInfo& callbackInfo);
- bool OnRequestAdapterCallback(WGPUFuture future,
- WGPURequestAdapterStatus status,
- const char* message,
- const WGPUAdapterProperties* properties,
- const WGPUSupportedLimits* limits,
- uint32_t featuresCount,
- const WGPUFeatureName* features);
void ProcessEvents();
WGPUWaitStatus WaitAny(size_t count, WGPUFutureWaitInfo* infos, uint64_t timeoutNS);
diff --git a/src/dawn/wire/client/ObjectBase.cpp b/src/dawn/wire/client/ObjectBase.cpp
index 84b6af7..d66f521 100644
--- a/src/dawn/wire/client/ObjectBase.cpp
+++ b/src/dawn/wire/client/ObjectBase.cpp
@@ -28,6 +28,7 @@
#include "dawn/wire/client/ObjectBase.h"
#include "dawn/common/Assert.h"
+#include "dawn/wire/client/Client.h"
namespace dawn::wire::client {
@@ -64,4 +65,16 @@
return mRefcount == 0;
}
+ObjectWithEventsBase::ObjectWithEventsBase(const ObjectBaseParams& params,
+ const ObjectHandle& eventManagerHandle)
+ : ObjectBase(params), mEventManagerHandle(eventManagerHandle) {}
+
+const ObjectHandle& ObjectWithEventsBase::GetEventManagerHandle() const {
+ return mEventManagerHandle;
+}
+
+EventManager& ObjectWithEventsBase::GetEventManager() const {
+ return GetClient()->GetEventManager(mEventManagerHandle);
+}
+
} // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/ObjectBase.h b/src/dawn/wire/client/ObjectBase.h
index 5e1688c..8c90683 100644
--- a/src/dawn/wire/client/ObjectBase.h
+++ b/src/dawn/wire/client/ObjectBase.h
@@ -32,6 +32,7 @@
#include "dawn/common/LinkedList.h"
#include "dawn/wire/ObjectHandle.h"
+#include "dawn/wire/client/EventManager.h"
namespace dawn::wire::client {
@@ -73,6 +74,23 @@
uint32_t mRefcount;
};
+// Compositable functionality for objects on the client side that need to have access to the event
+// manager.
+class ObjectWithEventsBase : public ObjectBase {
+ public:
+ // Note that the ObjectHandle associated with an EventManager is the same handle associated to
+ // the Instance that "owns" the EventManager.
+ ObjectWithEventsBase(const ObjectBaseParams& params, const ObjectHandle& eventManager);
+
+ const ObjectHandle& GetEventManagerHandle() const;
+ EventManager& GetEventManager() const;
+
+ private:
+ // The EventManager is owned by the client and long-lived. When the client is destroyed all
+ // objects are also freed.
+ ObjectHandle mEventManagerHandle;
+};
+
} // namespace dawn::wire::client
#endif // SRC_DAWN_WIRE_CLIENT_OBJECTBASE_H_
diff --git a/src/dawn/wire/client/Queue.cpp b/src/dawn/wire/client/Queue.cpp
index 89c0bb5..eee8a00 100644
--- a/src/dawn/wire/client/Queue.cpp
+++ b/src/dawn/wire/client/Queue.cpp
@@ -69,8 +69,10 @@
Queue::~Queue() = default;
-bool Queue::OnWorkDoneCallback(WGPUFuture future, WGPUQueueWorkDoneStatus status) {
- return GetClient()->GetEventManager()->SetFutureReady<WorkDoneEvent>(future.id, status) ==
+bool Client::DoQueueWorkDoneCallback(ObjectHandle eventManager,
+ WGPUFuture future,
+ WGPUQueueWorkDoneStatus status) {
+ return GetEventManager(eventManager).SetFutureReady<WorkDoneEvent>(future.id, status) ==
WireResult::Success;
}
@@ -89,13 +91,14 @@
Client* client = GetClient();
auto [futureIDInternal, tracked] =
- client->GetEventManager()->TrackEvent(std::make_unique<WorkDoneEvent>(callbackInfo));
+ GetEventManager().TrackEvent(std::make_unique<WorkDoneEvent>(callbackInfo));
if (!tracked) {
return {futureIDInternal};
}
QueueOnSubmittedWorkDoneCmd cmd;
cmd.queueId = GetWireId();
+ cmd.eventManagerHandle = GetEventManagerHandle();
cmd.future = {futureIDInternal};
client->SerializeCommand(cmd);
diff --git a/src/dawn/wire/client/Queue.h b/src/dawn/wire/client/Queue.h
index 0b47342..0d4cc55 100644
--- a/src/dawn/wire/client/Queue.h
+++ b/src/dawn/wire/client/Queue.h
@@ -36,13 +36,11 @@
namespace dawn::wire::client {
-class Queue final : public ObjectBase {
+class Queue final : public ObjectWithEventsBase {
public:
- using ObjectBase::ObjectBase;
+ using ObjectWithEventsBase::ObjectWithEventsBase;
~Queue() override;
- bool OnWorkDoneCallback(WGPUFuture future, WGPUQueueWorkDoneStatus status);
-
// Dawn API
void OnSubmittedWorkDone(WGPUQueueWorkDoneCallback callback, void* userdata);
WGPUFuture OnSubmittedWorkDoneF(const WGPUQueueWorkDoneCallbackInfo& callbackInfo);
diff --git a/src/dawn/wire/server/Server.h b/src/dawn/wire/server/Server.h
index e20a300..5f21a51 100644
--- a/src/dawn/wire/server/Server.h
+++ b/src/dawn/wire/server/Server.h
@@ -105,6 +105,7 @@
ObjectHandle buffer;
WGPUBuffer bufferObj;
+ ObjectHandle eventManager;
WGPUFuture future;
uint64_t offset;
uint64_t size;
@@ -129,6 +130,7 @@
using CallbackUserdata::CallbackUserdata;
ObjectHandle queue;
+ ObjectHandle eventManager;
WGPUFuture future;
};
@@ -144,6 +146,7 @@
using CallbackUserdata::CallbackUserdata;
ObjectHandle instance;
+ ObjectHandle eventManager;
WGPUFuture future;
ObjectId adapterObjectId;
};
diff --git a/src/dawn/wire/server/ServerBuffer.cpp b/src/dawn/wire/server/ServerBuffer.cpp
index 5869a5d..ca1471c 100644
--- a/src/dawn/wire/server/ServerBuffer.cpp
+++ b/src/dawn/wire/server/ServerBuffer.cpp
@@ -65,6 +65,7 @@
}
WireResult Server::DoBufferMapAsync(Known<WGPUBuffer> buffer,
+ ObjectHandle eventManager,
WGPUFuture future,
WGPUMapModeFlags mode,
uint64_t offset64,
@@ -73,6 +74,7 @@
// client will require in the return command.
std::unique_ptr<MapUserdata> userdata = MakeUserdata<MapUserdata>();
userdata->buffer = buffer.AsHandle();
+ userdata->eventManager = eventManager;
userdata->bufferObj = buffer->handle;
userdata->future = future;
userdata->mode = mode;
@@ -223,7 +225,9 @@
bool isSuccess = status == WGPUBufferMapAsyncStatus_Success;
ReturnBufferMapAsyncCallbackCmd cmd;
+ // TODO(dawn:2061) Should be able to remove buffer once mapping is updated.
cmd.buffer = data->buffer;
+ cmd.eventManager = data->eventManager;
cmd.future = data->future;
cmd.status = status;
cmd.readDataUpdateInfoLength = 0;
diff --git a/src/dawn/wire/server/ServerInstance.cpp b/src/dawn/wire/server/ServerInstance.cpp
index 3f3f8c4..660c339 100644
--- a/src/dawn/wire/server/ServerInstance.cpp
+++ b/src/dawn/wire/server/ServerInstance.cpp
@@ -34,6 +34,7 @@
namespace dawn::wire::server {
WireResult Server::DoInstanceRequestAdapter(Known<WGPUInstance> instance,
+ ObjectHandle eventManager,
WGPUFuture future,
ObjectHandle adapterHandle,
const WGPURequestAdapterOptions* options) {
@@ -42,6 +43,7 @@
auto userdata = MakeUserdata<RequestAdapterUserdata>();
userdata->instance = instance.AsHandle();
+ userdata->eventManager = eventManager;
userdata->future = future;
userdata->adapterObjectId = adapter.id;
@@ -56,7 +58,7 @@
WGPUAdapter adapter,
const char* message) {
ReturnInstanceRequestAdapterCallbackCmd cmd = {};
- cmd.instance = data->instance;
+ cmd.eventManager = data->eventManager;
cmd.future = data->future;
cmd.status = status;
cmd.message = message;
diff --git a/src/dawn/wire/server/ServerQueue.cpp b/src/dawn/wire/server/ServerQueue.cpp
index a4d9c0a..807861b 100644
--- a/src/dawn/wire/server/ServerQueue.cpp
+++ b/src/dawn/wire/server/ServerQueue.cpp
@@ -34,16 +34,19 @@
void Server::OnQueueWorkDone(QueueWorkDoneUserdata* data, WGPUQueueWorkDoneStatus status) {
ReturnQueueWorkDoneCallbackCmd cmd;
- cmd.queue = data->queue;
+ cmd.eventManager = data->eventManager;
cmd.future = data->future;
cmd.status = status;
SerializeCommand(cmd);
}
-WireResult Server::DoQueueOnSubmittedWorkDone(Known<WGPUQueue> queue, WGPUFuture future) {
+WireResult Server::DoQueueOnSubmittedWorkDone(Known<WGPUQueue> queue,
+ ObjectHandle eventManager,
+ WGPUFuture future) {
auto userdata = MakeUserdata<QueueWorkDoneUserdata>();
userdata->queue = queue.AsHandle();
+ userdata->eventManager = eventManager;
userdata->future = future;
mProcs.queueOnSubmittedWorkDone(queue->handle, ForwardToServer<&Server::OnQueueWorkDone>,