dawn::wire::client: Merge object allocators, add variadic Make.
This commit changes all the [Object]Allocators from the Client into a
PerType<ObjectStore> member that contains a bunch of ObjectStore acting
on ObjectBase.
Adds a new (template) member functions to the client, Make/Get/Free that
act on any object type, and update all the uses of previous
[Object]Allocator to use these new methods.
Also removes generated code that was generated per object type in favor
of using the type-generic ObjectAllocator.
Bug: dawn:1451
Change-Id: I6463b2fc4a827e3000c2a666abf08aa1a71c3b3b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/93141
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/generator/templates/dawn/wire/client/ApiProcs.cpp b/generator/templates/dawn/wire/client/ApiProcs.cpp
index ef46293..85fe15d 100644
--- a/generator/templates/dawn/wire/client/ApiProcs.cpp
+++ b/generator/templates/dawn/wire/client/ApiProcs.cpp
@@ -58,7 +58,7 @@
//* For object creation, store the object ID the client will use for the result.
{% if method.return_type.category == "object" %}
- auto* returnObject = self->GetClient()->{{method.return_type.name.CamelCase()}}Allocator().New(self->GetClient());
+ auto* returnObject = self->GetClient()->Make<{{method.return_type.name.CamelCase()}}>();
cmd.result = returnObject->GetWireHandle();
{% endif %}
@@ -97,7 +97,7 @@
Client* client = obj->GetClient();
client->SerializeCommand(cmd);
- client->{{type.name.CamelCase()}}Allocator().Free(obj);
+ client->Free(obj);
}
void Client{{as_MethodSuffix(type.name, Name("reference"))}}({{cType}} cObj) {
diff --git a/generator/templates/dawn/wire/client/ClientBase.h b/generator/templates/dawn/wire/client/ClientBase.h
index 2fb1e5d..03d08e9 100644
--- a/generator/templates/dawn/wire/client/ClientBase.h
+++ b/generator/templates/dawn/wire/client/ClientBase.h
@@ -18,7 +18,6 @@
#include "dawn/wire/ChunkedCommandHandler.h"
#include "dawn/wire/WireCmd_autogen.h"
#include "dawn/wire/client/ApiObjects.h"
-#include "dawn/wire/client/ObjectAllocator.h"
namespace dawn::wire::client {
@@ -27,25 +26,6 @@
ClientBase() = default;
~ClientBase() override = default;
- {% for type in by_category["object"] %}
- const ObjectAllocator<{{type.name.CamelCase()}}>& {{type.name.CamelCase()}}Allocator() const {
- return m{{type.name.CamelCase()}}Allocator;
- }
- ObjectAllocator<{{type.name.CamelCase()}}>& {{type.name.CamelCase()}}Allocator() {
- return m{{type.name.CamelCase()}}Allocator;
- }
- {% endfor %}
-
- void FreeObject(ObjectType objectType, ObjectBase* obj) {
- switch (objectType) {
- {% for type in by_category["object"] %}
- case ObjectType::{{type.name.CamelCase()}}:
- m{{type.name.CamelCase()}}Allocator.Free(static_cast<{{type.name.CamelCase()}}*>(obj));
- break;
- {% endfor %}
- }
- }
-
private:
// Implementation of the ObjectIdProvider interface
{% for type in by_category["object"] %}
@@ -63,10 +43,6 @@
return WireResult::Success;
}
{% endfor %}
-
- {% for type in by_category["object"] %}
- ObjectAllocator<{{type.name.CamelCase()}}> m{{type.name.CamelCase()}}Allocator;
- {% endfor %}
};
} // namespace dawn::wire::client
diff --git a/generator/templates/dawn/wire/client/ClientHandlers.cpp b/generator/templates/dawn/wire/client/ClientHandlers.cpp
index f682c34..d09c0f5 100644
--- a/generator/templates/dawn/wire/client/ClientHandlers.cpp
+++ b/generator/templates/dawn/wire/client/ClientHandlers.cpp
@@ -21,7 +21,7 @@
{% for command in cmd_records["return command"] %}
bool Client::Handle{{command.name.CamelCase()}}(DeserializeBuffer* deserializeBuffer) {
Return{{command.name.CamelCase()}}Cmd cmd;
- WireResult deserializeResult = cmd.Deserialize(deserializeBuffer, &mAllocator);
+ WireResult deserializeResult = cmd.Deserialize(deserializeBuffer, &mWireCommandAllocator);
if (deserializeResult == WireResult::FatalError) {
return false;
@@ -32,7 +32,7 @@
{% set name = as_varName(member.name) %}
{% if member.type.dict_name == "ObjectHandle" %}
- {{Type}}* {{name}} = {{Type}}Allocator().GetObject(cmd.{{name}}.id);
+ {{Type}}* {{name}} = Get<{{Type}}>(cmd.{{name}}.id);
if ({{name}} != nullptr && {{name}}->GetWireGeneration() != cmd.{{name}}.generation) {
{{name}} = nullptr;
}
@@ -84,7 +84,7 @@
if (!success) {
return nullptr;
}
- mAllocator.Reset();
+ mWireCommandAllocator.Reset();
}
if (deserializeBuffer.AvailableSize() != 0) {
diff --git a/src/dawn/wire/BUILD.gn b/src/dawn/wire/BUILD.gn
index 5b26626..56aa038 100644
--- a/src/dawn/wire/BUILD.gn
+++ b/src/dawn/wire/BUILD.gn
@@ -90,9 +90,10 @@
"client/Instance.h",
"client/LimitsAndFeatures.cpp",
"client/LimitsAndFeatures.h",
- "client/ObjectAllocator.h",
"client/ObjectBase.cpp",
"client/ObjectBase.h",
+ "client/ObjectStore.cpp",
+ "client/ObjectStore.h",
"client/QuerySet.cpp",
"client/QuerySet.h",
"client/Queue.cpp",
diff --git a/src/dawn/wire/CMakeLists.txt b/src/dawn/wire/CMakeLists.txt
index 9a79484..c470cea 100644
--- a/src/dawn/wire/CMakeLists.txt
+++ b/src/dawn/wire/CMakeLists.txt
@@ -63,7 +63,8 @@
"client/Instance.h"
"client/LimitsAndFeatures.cpp"
"client/LimitsAndFeatures.h"
- "client/ObjectAllocator.h"
+ "client/ObjectStore.cpp"
+ "client/ObjectStore.h"
"client/ObjectBase.cpp"
"client/ObjectBase.h"
"client/QuerySet.cpp"
diff --git a/src/dawn/wire/client/Adapter.cpp b/src/dawn/wire/client/Adapter.cpp
index ceab7b0..6edf63c 100644
--- a/src/dawn/wire/client/Adapter.cpp
+++ b/src/dawn/wire/client/Adapter.cpp
@@ -71,7 +71,7 @@
return;
}
- Device* device = client->DeviceAllocator().New(client);
+ Device* device = client->Make<Device>();
uint64_t serial = mRequestDeviceRequests.Add({callback, device->GetWireId(), userdata});
AdapterRequestDeviceCmd cmd;
@@ -110,12 +110,12 @@
}
Client* client = GetClient();
- Device* device = client->DeviceAllocator().GetObject(request.deviceObjectId);
+ Device* device = client->Get<Device>(request.deviceObjectId);
// If the return status is a failure we should give a null device to the callback and
// free the allocation.
if (status != WGPURequestDeviceStatus_Success) {
- client->DeviceAllocator().Free(device);
+ client->Free(device);
request.callback(status, nullptr, message, request.userdata);
return true;
}
diff --git a/src/dawn/wire/client/Buffer.cpp b/src/dawn/wire/client/Buffer.cpp
index b66e49b..aaf6282 100644
--- a/src/dawn/wire/client/Buffer.cpp
+++ b/src/dawn/wire/client/Buffer.cpp
@@ -74,7 +74,7 @@
// Create the buffer and send the creation command.
// This must happen after any potential device->CreateErrorBuffer()
// as server expects allocating ids to be monotonically increasing
- Buffer* buffer = wireClient->BufferAllocator().New(wireClient);
+ Buffer* buffer = wireClient->Make<Buffer>();
buffer->mDevice = device;
buffer->mDeviceIsAlive = device->GetAliveWeakPtr();
buffer->mSize = descriptor->size;
@@ -127,7 +127,7 @@
WGPUBuffer Buffer::CreateError(Device* device, const WGPUBufferDescriptor* descriptor) {
Client* client = device->GetClient();
- Buffer* buffer = client->BufferAllocator().New(client);
+ Buffer* buffer = client->Make<Buffer>();
buffer->mDevice = device;
buffer->mDeviceIsAlive = device->GetAliveWeakPtr();
buffer->mSize = descriptor->size;
diff --git a/src/dawn/wire/client/Client.cpp b/src/dawn/wire/client/Client.cpp
index a41c020..6c5e631 100644
--- a/src/dawn/wire/client/Client.cpp
+++ b/src/dawn/wire/client/Client.cpp
@@ -61,7 +61,7 @@
cmd.objectType = ObjectType::Device;
cmd.objectId = object->GetWireId();
SerializeCommand(cmd);
- FreeObject(ObjectType::Device, object);
+ mObjectStores[ObjectType::Device].Free(object);
}
for (auto& objectList : mObjects) {
@@ -76,13 +76,13 @@
cmd.objectType = objectType;
cmd.objectId = object->GetWireId();
SerializeCommand(cmd);
- FreeObject(objectType, object);
+ mObjectStores[objectType].Free(object);
}
}
}
ReservedTexture Client::ReserveTexture(WGPUDevice device) {
- Texture* texture = TextureAllocator().New(this);
+ Texture* texture = Make<Texture>();
ReservedTexture result;
result.texture = ToAPI(texture);
@@ -94,7 +94,7 @@
}
ReservedSwapChain Client::ReserveSwapChain(WGPUDevice device) {
- SwapChain* swapChain = SwapChainAllocator().New(this);
+ SwapChain* swapChain = Make<SwapChain>();
ReservedSwapChain result;
result.swapchain = ToAPI(swapChain);
@@ -106,7 +106,7 @@
}
ReservedDevice Client::ReserveDevice() {
- Device* device = DeviceAllocator().New(this);
+ Device* device = Make<Device>();
ReservedDevice result;
result.device = ToAPI(device);
@@ -116,7 +116,7 @@
}
ReservedInstance Client::ReserveInstance() {
- Instance* instance = InstanceAllocator().New(this);
+ Instance* instance = Make<Instance>();
ReservedInstance result;
result.instance = ToAPI(instance);
@@ -126,19 +126,19 @@
}
void Client::ReclaimTextureReservation(const ReservedTexture& reservation) {
- TextureAllocator().Free(FromAPI(reservation.texture));
+ Free(FromAPI(reservation.texture));
}
void Client::ReclaimSwapChainReservation(const ReservedSwapChain& reservation) {
- SwapChainAllocator().Free(FromAPI(reservation.swapchain));
+ Free(FromAPI(reservation.swapchain));
}
void Client::ReclaimDeviceReservation(const ReservedDevice& reservation) {
- DeviceAllocator().Free(FromAPI(reservation.device));
+ Free(FromAPI(reservation.device));
}
void Client::ReclaimInstanceReservation(const ReservedInstance& reservation) {
- InstanceAllocator().Free(FromAPI(reservation.instance));
+ Free(FromAPI(reservation.instance));
}
void Client::Disconnect() {
@@ -165,4 +165,8 @@
return mDisconnected;
}
+void Client::Free(ObjectBase* obj, ObjectType type) {
+ mObjectStores[type].Free(obj);
+}
+
} // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/Client.h b/src/dawn/wire/client/Client.h
index d045f0c..ad5769a 100644
--- a/src/dawn/wire/client/Client.h
+++ b/src/dawn/wire/client/Client.h
@@ -16,6 +16,7 @@
#define SRC_DAWN_WIRE_CLIENT_CLIENT_H_
#include <memory>
+#include <utility>
#include "dawn/common/LinkedList.h"
#include "dawn/common/NonCopyable.h"
@@ -26,6 +27,7 @@
#include "dawn/wire/WireCmd_autogen.h"
#include "dawn/wire/WireDeserializeAllocator.h"
#include "dawn/wire/client/ClientBase_autogen.h"
+#include "dawn/wire/client/ObjectStore.h"
namespace dawn::wire::client {
@@ -37,6 +39,32 @@
Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService);
~Client() override;
+ // Make<T>(arg1, arg2, arg3) creates a new T, calling a constructor of the form:
+ //
+ // T::T(ObjectBaseParams, arg1, arg2, arg3)
+ template <typename T, typename... Args>
+ T* Make(Args&&... args) {
+ constexpr ObjectType type = ObjectTypeToTypeEnum<T>::value;
+
+ ObjectBaseParams params = {this, mObjectStores[type].ReserveHandle()};
+ T* object = new T(params, std::forward<Args>(args)...);
+
+ mObjects[type].Append(object);
+ mObjectStores[type].Insert(std::unique_ptr<T>(object));
+ return object;
+ }
+
+ template <typename T>
+ void Free(T* obj) {
+ Free(obj, ObjectTypeToTypeEnum<T>::value);
+ }
+ void Free(ObjectBase* obj, ObjectType type);
+
+ template <typename T>
+ T* Get(ObjectId id) {
+ return static_cast<T*>(mObjectStores[ObjectTypeToTypeEnum<T>::value].Get(id));
+ }
+
// ChunkedCommandHandler implementation
const volatile char* HandleCommandsImpl(const volatile char* commands, size_t size) override;
@@ -67,21 +95,16 @@
void Disconnect();
bool IsDisconnected() const;
- template <typename T>
- void TrackObject(T* object) {
- mObjects[ObjectTypeToTypeEnum<T>::value].Append(object);
- }
-
private:
void DestroyAllObjects();
#include "dawn/wire/client/ClientPrototypes_autogen.inc"
ChunkedCommandSerializer mSerializer;
- WireDeserializeAllocator mAllocator;
+ WireDeserializeAllocator mWireCommandAllocator;
+ PerObjectType<ObjectStore> mObjectStores;
MemoryTransferService* mMemoryTransferService = nullptr;
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
-
PerObjectType<LinkedList<ObjectBase>> mObjects;
bool mDisconnected = false;
};
diff --git a/src/dawn/wire/client/Device.cpp b/src/dawn/wire/client/Device.cpp
index c09cb3b..d945694 100644
--- a/src/dawn/wire/client/Device.cpp
+++ b/src/dawn/wire/client/Device.cpp
@@ -20,7 +20,6 @@
#include "dawn/common/Log.h"
#include "dawn/wire/client/ApiObjects_autogen.h"
#include "dawn/wire/client/Client.h"
-#include "dawn/wire/client/ObjectAllocator.h"
namespace dawn::wire::client {
@@ -221,7 +220,7 @@
if (mQueue == nullptr) {
// Get the primary queue for this device.
Client* client = GetClient();
- mQueue = client->QueueAllocator().New(client);
+ mQueue = client->Make<Queue>();
DeviceGetQueueCmd cmd;
cmd.self = ToAPI(this);
@@ -243,7 +242,7 @@
"GPU device disconnected", userdata);
}
- ComputePipeline* pipeline = client->ComputePipelineAllocator().New(client);
+ ComputePipeline* pipeline = client->Make<ComputePipeline>();
CreatePipelineAsyncRequest request = {};
request.createComputePipelineAsyncCallback = callback;
@@ -270,20 +269,17 @@
}
Client* client = GetClient();
- auto* pipelineAllocation =
- client->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
+ ComputePipeline* pipeline = client->Get<ComputePipeline>(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
// free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
- client->ComputePipelineAllocator().Free(pipelineAllocation);
+ client->Free(pipeline);
request.createComputePipelineAsyncCallback(status, nullptr, message, request.userdata);
return true;
}
- WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation);
- request.createComputePipelineAsyncCallback(status, pipeline, message, request.userdata);
-
+ request.createComputePipelineAsyncCallback(status, ToAPI(pipeline), message, request.userdata);
return true;
}
@@ -296,7 +292,7 @@
"GPU device disconnected", userdata);
}
- RenderPipeline* pipeline = client->RenderPipelineAllocator().New(client);
+ RenderPipeline* pipeline = client->Make<RenderPipeline>();
CreatePipelineAsyncRequest request = {};
request.createRenderPipelineAsyncCallback = callback;
@@ -323,20 +319,17 @@
}
Client* client = GetClient();
- auto* pipelineAllocation =
- client->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
+ RenderPipeline* pipeline = client->Get<RenderPipeline>(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
// free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
- client->RenderPipelineAllocator().Free(pipelineAllocation);
+ client->Free(pipeline);
request.createRenderPipelineAsyncCallback(status, nullptr, message, request.userdata);
return true;
}
- WGPURenderPipeline pipeline = reinterpret_cast<WGPURenderPipeline>(pipelineAllocation);
- request.createRenderPipelineAsyncCallback(status, pipeline, message, request.userdata);
-
+ request.createRenderPipelineAsyncCallback(status, ToAPI(pipeline), message, request.userdata);
return true;
}
diff --git a/src/dawn/wire/client/Instance.cpp b/src/dawn/wire/client/Instance.cpp
index 9812f2e..efd9b74 100644
--- a/src/dawn/wire/client/Instance.cpp
+++ b/src/dawn/wire/client/Instance.cpp
@@ -41,7 +41,7 @@
return;
}
- Adapter* adapter = client->AdapterAllocator().New(client);
+ Adapter* adapter = client->Make<Adapter>();
uint64_t serial = mRequestAdapterRequests.Add({callback, adapter->GetWireId(), userdata});
InstanceRequestAdapterCmd cmd;
@@ -82,12 +82,12 @@
}
Client* client = GetClient();
- Adapter* adapter = client->AdapterAllocator().GetObject(request.adapterObjectId);
+ 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->AdapterAllocator().Free(adapter);
+ client->Free(adapter);
request.callback(status, nullptr, message, request.userdata);
return true;
}
diff --git a/src/dawn/wire/client/ObjectAllocator.h b/src/dawn/wire/client/ObjectAllocator.h
deleted file mode 100644
index f369a70..0000000
--- a/src/dawn/wire/client/ObjectAllocator.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2019 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_DAWN_WIRE_CLIENT_OBJECTALLOCATOR_H_
-#define SRC_DAWN_WIRE_CLIENT_OBJECTALLOCATOR_H_
-
-#include <limits>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "dawn/common/Assert.h"
-#include "dawn/common/Compiler.h"
-#include "dawn/wire/WireCmd_autogen.h"
-#include "dawn/wire/client/ObjectBase.h"
-
-namespace dawn::wire::client {
-
-template <typename T>
-class ObjectAllocator {
- public:
- ObjectAllocator() {
- // ID 0 is nullptr
- mObjects.emplace_back(nullptr);
- }
-
- template <typename Client>
- T* New(Client* client) {
- ObjectHandle handle = GetFreeHandle();
- ObjectBaseParams params = {client, handle};
- auto object = std::make_unique<T>(params);
- client->TrackObject(object.get());
-
- if (handle.id >= mObjects.size()) {
- ASSERT(handle.id == mObjects.size());
- mObjects.emplace_back(std::move(object));
- } else {
- // The generation should never overflow. We don't recycle ObjectIds that would
- // overflow their next generation.
- ASSERT(handle.generation != 0);
- ASSERT(mObjects[handle.id] == nullptr);
- mObjects[handle.id] = std::move(object);
- }
-
- return mObjects[handle.id].get();
- }
- void Free(T* obj) {
- ASSERT(obj->IsInList());
- // The wire reuses ID for objects to keep them in a packed array starting from 0.
- // To avoid issues with asynchronous server->client communication referring to an ID that's
- // already reused, each handle also has a generation that's increment by one on each reuse.
- // Avoid overflows by only reusing the ID if the increment of the generation won't overflow.
- ObjectHandle currentHandle = obj->GetWireHandle();
- if (DAWN_LIKELY(currentHandle.generation != std::numeric_limits<ObjectGeneration>::max())) {
- mFreeHandles.push_back({currentHandle.id, currentHandle.generation + 1});
- }
- mObjects[currentHandle.id] = nullptr;
- }
-
- T* GetObject(uint32_t id) {
- if (id >= mObjects.size()) {
- return nullptr;
- }
- return mObjects[id].get();
- }
-
- private:
- ObjectHandle GetFreeHandle() {
- if (mFreeHandles.empty()) {
- return {mCurrentId++, 0};
- }
- ObjectHandle handle = mFreeHandles.back();
- mFreeHandles.pop_back();
- return handle;
- }
-
- // 0 is an ID reserved to represent nullptr
- uint32_t mCurrentId = 1;
- std::vector<ObjectHandle> mFreeHandles;
- std::vector<std::unique_ptr<T>> mObjects;
-};
-} // namespace dawn::wire::client
-
-#endif // SRC_DAWN_WIRE_CLIENT_OBJECTALLOCATOR_H_
diff --git a/src/dawn/wire/client/ObjectStore.cpp b/src/dawn/wire/client/ObjectStore.cpp
new file mode 100644
index 0000000..299a678
--- /dev/null
+++ b/src/dawn/wire/client/ObjectStore.cpp
@@ -0,0 +1,72 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn/wire/client/ObjectStore.h"
+
+#include <limits>
+#include <utility>
+
+namespace dawn::wire::client {
+
+ObjectStore::ObjectStore() {
+ // ID 0 is nullptr
+ mObjects.emplace_back(nullptr);
+ mCurrentId = 1;
+}
+
+ObjectHandle ObjectStore::ReserveHandle() {
+ if (mFreeHandles.empty()) {
+ return {mCurrentId++, 0};
+ }
+ ObjectHandle handle = mFreeHandles.back();
+ mFreeHandles.pop_back();
+ return handle;
+}
+
+void ObjectStore::Insert(std::unique_ptr<ObjectBase> obj) {
+ ObjectId id = obj->GetWireId();
+
+ if (id >= mObjects.size()) {
+ ASSERT(id == mObjects.size());
+ mObjects.emplace_back(std::move(obj));
+ } else {
+ // The generation should never overflow. We don't recycle ObjectIds that would
+ // overflow their next generation.
+ ASSERT(obj->GetWireGeneration() != 0);
+ ASSERT(mObjects[id] == nullptr);
+ mObjects[id] = std::move(obj);
+ }
+}
+
+void ObjectStore::Free(ObjectBase* obj) {
+ ASSERT(obj->IsInList());
+ // The wire reuses ID for objects to keep them in a packed array starting from 0.
+ // To avoid issues with asynchronous server->client communication referring to an ID that's
+ // already reused, each handle also has a generation that's increment by one on each reuse.
+ // Avoid overflows by only reusing the ID if the increment of the generation won't overflow.
+ const ObjectHandle& currentHandle = obj->GetWireHandle();
+ if (DAWN_LIKELY(currentHandle.generation != std::numeric_limits<ObjectGeneration>::max())) {
+ mFreeHandles.push_back({currentHandle.id, currentHandle.generation + 1});
+ }
+ mObjects[currentHandle.id] = nullptr;
+}
+
+ObjectBase* ObjectStore::Get(ObjectId id) const {
+ if (id >= mObjects.size()) {
+ return nullptr;
+ }
+ return mObjects[id].get();
+}
+
+} // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/ObjectStore.h b/src/dawn/wire/client/ObjectStore.h
new file mode 100644
index 0000000..5d9b741
--- /dev/null
+++ b/src/dawn/wire/client/ObjectStore.h
@@ -0,0 +1,51 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_WIRE_CLIENT_OBJECTSTORE_H_
+#define SRC_DAWN_WIRE_CLIENT_OBJECTSTORE_H_
+
+#include <memory>
+#include <vector>
+
+#include "dawn/wire/client/ObjectBase.h"
+
+namespace dawn::wire::client {
+
+class Client;
+
+// A helper class used in Client, ObjectStore owns the association of some ObjectBase and
+// ObjectHandles. The lifetime of the ObjectBase is then owned by the ObjectStore, destruction
+// happening when Free is called.
+//
+// Since the wire has one "ID" namespace per type of object, each ObjectStore should contain a
+// single type of objects. However no templates are used because Client wraps ObjectStore and is
+// type-generic, so ObjectStore is type-erased to only work on ObjectBase.
+class ObjectStore {
+ public:
+ ObjectStore();
+
+ ObjectHandle ReserveHandle();
+ void Insert(std::unique_ptr<ObjectBase> obj);
+ void Free(ObjectBase* obj);
+ ObjectBase* Get(ObjectId id) const;
+
+ private:
+ uint32_t mCurrentId;
+ std::vector<ObjectHandle> mFreeHandles;
+ std::vector<std::unique_ptr<ObjectBase>> mObjects;
+};
+
+} // namespace dawn::wire::client
+
+#endif // SRC_DAWN_WIRE_CLIENT_OBJECTSTORE_H_
diff --git a/src/dawn/wire/client/QuerySet.cpp b/src/dawn/wire/client/QuerySet.cpp
index 903c65d..4a22a0c 100644
--- a/src/dawn/wire/client/QuerySet.cpp
+++ b/src/dawn/wire/client/QuerySet.cpp
@@ -22,7 +22,7 @@
// static
WGPUQuerySet QuerySet::Create(Device* device, const WGPUQuerySetDescriptor* descriptor) {
Client* wireClient = device->GetClient();
- QuerySet* querySet = wireClient->QuerySetAllocator().New(wireClient);
+ QuerySet* querySet = wireClient->Make<QuerySet>();
// Copy over descriptor data for reflection.
querySet->mType = descriptor->type;
diff --git a/src/dawn/wire/client/Texture.cpp b/src/dawn/wire/client/Texture.cpp
index 99ea97f..1fffde2 100644
--- a/src/dawn/wire/client/Texture.cpp
+++ b/src/dawn/wire/client/Texture.cpp
@@ -22,7 +22,7 @@
// static
WGPUTexture Texture::Create(Device* device, const WGPUTextureDescriptor* descriptor) {
Client* wireClient = device->GetClient();
- Texture* texture = wireClient->TextureAllocator().New(wireClient);
+ Texture* texture = wireClient->Make<Texture>();
// Copy over descriptor data for reflection.
texture->mSize = descriptor->size;