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>
This commit is contained in:
parent
e57c296035
commit
0ebe86d1ca
|
@ -58,7 +58,7 @@ namespace dawn::wire::client {
|
|||
|
||||
//* 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 @@ namespace dawn::wire::client {
|
|||
|
||||
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) {
|
||||
|
|
|
@ -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 @@ namespace dawn::wire::client {
|
|||
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 @@ namespace dawn::wire::client {
|
|||
return WireResult::Success;
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
{% for type in by_category["object"] %}
|
||||
ObjectAllocator<{{type.name.CamelCase()}}> m{{type.name.CamelCase()}}Allocator;
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
} // namespace dawn::wire::client
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace dawn::wire::client {
|
|||
{% 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 @@ namespace dawn::wire::client {
|
|||
{% 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 @@ namespace dawn::wire::client {
|
|||
if (!success) {
|
||||
return nullptr;
|
||||
}
|
||||
mAllocator.Reset();
|
||||
mWireCommandAllocator.Reset();
|
||||
}
|
||||
|
||||
if (deserializeBuffer.AvailableSize() != 0) {
|
||||
|
|
|
@ -90,9 +90,10 @@ dawn_component("wire") {
|
|||
"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",
|
||||
|
|
|
@ -63,7 +63,8 @@ target_sources(dawn_wire PRIVATE
|
|||
"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"
|
||||
|
|
|
@ -71,7 +71,7 @@ void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
|
|||
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 @@ bool Adapter::OnRequestDeviceCallback(uint64_t requestSerial,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor
|
|||
// 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::Create(Device* device, const WGPUBufferDescriptor* descriptor
|
|||
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;
|
||||
|
|
|
@ -61,7 +61,7 @@ void Client::DestroyAllObjects() {
|
|||
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 @@ void Client::DestroyAllObjects() {
|
|||
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 @@ ReservedTexture Client::ReserveTexture(WGPUDevice device) {
|
|||
}
|
||||
|
||||
ReservedSwapChain Client::ReserveSwapChain(WGPUDevice device) {
|
||||
SwapChain* swapChain = SwapChainAllocator().New(this);
|
||||
SwapChain* swapChain = Make<SwapChain>();
|
||||
|
||||
ReservedSwapChain result;
|
||||
result.swapchain = ToAPI(swapChain);
|
||||
|
@ -106,7 +106,7 @@ ReservedSwapChain Client::ReserveSwapChain(WGPUDevice device) {
|
|||
}
|
||||
|
||||
ReservedDevice Client::ReserveDevice() {
|
||||
Device* device = DeviceAllocator().New(this);
|
||||
Device* device = Make<Device>();
|
||||
|
||||
ReservedDevice result;
|
||||
result.device = ToAPI(device);
|
||||
|
@ -116,7 +116,7 @@ ReservedDevice Client::ReserveDevice() {
|
|||
}
|
||||
|
||||
ReservedInstance Client::ReserveInstance() {
|
||||
Instance* instance = InstanceAllocator().New(this);
|
||||
Instance* instance = Make<Instance>();
|
||||
|
||||
ReservedInstance result;
|
||||
result.instance = ToAPI(instance);
|
||||
|
@ -126,19 +126,19 @@ ReservedInstance Client::ReserveInstance() {
|
|||
}
|
||||
|
||||
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 @@ bool Client::IsDisconnected() const {
|
|||
return mDisconnected;
|
||||
}
|
||||
|
||||
void Client::Free(ObjectBase* obj, ObjectType type) {
|
||||
mObjectStores[type].Free(obj);
|
||||
}
|
||||
|
||||
} // namespace dawn::wire::client
|
||||
|
|
|
@ -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 @@ class Client : public ClientBase {
|
|||
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 @@ class Client : public ClientBase {
|
|||
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;
|
||||
};
|
||||
|
|
|
@ -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 @@ WGPUQueue Device::GetQueue() {
|
|||
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 @@ void Device::CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* des
|
|||
"GPU device disconnected", userdata);
|
||||
}
|
||||
|
||||
ComputePipeline* pipeline = client->ComputePipelineAllocator().New(client);
|
||||
ComputePipeline* pipeline = client->Make<ComputePipeline>();
|
||||
|
||||
CreatePipelineAsyncRequest request = {};
|
||||
request.createComputePipelineAsyncCallback = callback;
|
||||
|
@ -270,20 +269,17 @@ bool Device::OnCreateComputePipelineAsyncCallback(uint64_t requestSerial,
|
|||
}
|
||||
|
||||
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 @@ void Device::CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descr
|
|||
"GPU device disconnected", userdata);
|
||||
}
|
||||
|
||||
RenderPipeline* pipeline = client->RenderPipelineAllocator().New(client);
|
||||
RenderPipeline* pipeline = client->Make<RenderPipeline>();
|
||||
|
||||
CreatePipelineAsyncRequest request = {};
|
||||
request.createRenderPipelineAsyncCallback = callback;
|
||||
|
@ -323,20 +319,17 @@ bool Device::OnCreateRenderPipelineAsyncCallback(uint64_t requestSerial,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ void Instance::RequestAdapter(const WGPURequestAdapterOptions* options,
|
|||
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 @@ bool Instance::OnRequestAdapterCallback(uint64_t requestSerial,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -22,7 +22,7 @@ namespace dawn::wire::client {
|
|||
// 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;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace dawn::wire::client {
|
|||
// 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;
|
||||
|
|
Loading…
Reference in New Issue