Make the wire Client own ObjectAllocators and CommandSerializer

This moves ownership of ObjectAllocators and CommandSerializers
from the Device to the Client. There may be also be multiple
Devices, so New() now takes the Device the object belongs to.
Device allocation specializes New() to take the owning Client so
that we can get a pointer to the Client from any Dawn API object.

Bug: dawn:88
Change-Id: Ie4274d46313884c44a857159e95d236dc1141c0c
Reviewed-on: https://dawn-review.googlesource.com/c/4001
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Austin Eng 2019-01-30 02:31:37 +00:00 committed by Commit Bot service account
parent fd4688e8d0
commit cd4fd8e7cd
16 changed files with 207 additions and 112 deletions

View File

@ -763,9 +763,9 @@ dawn_generator("libdawn_wire_gen") {
"dawn_wire/client/ApiObjects_autogen.h",
"dawn_wire/client/ApiProcs_autogen.cpp",
"dawn_wire/client/ApiProcs_autogen.h",
"dawn_wire/client/ClientBase_autogen.h",
"dawn_wire/client/ClientHandlers_autogen.cpp",
"dawn_wire/client/ClientPrototypes_autogen.inl",
"dawn_wire/client/Device_autogen.h",
"dawn_wire/server/ServerBase_autogen.h",
"dawn_wire/server/ServerCallbacks_autogen.cpp",
"dawn_wire/server/ServerHandlers_autogen.cpp",
@ -795,6 +795,8 @@ dawn_component("libdawn_wire") {
"src/dawn_wire/client/Client.cpp",
"src/dawn_wire/client/Client.h",
"src/dawn_wire/client/ClientHandlers.cpp",
"src/dawn_wire/client/Device.cpp",
"src/dawn_wire/client/Device.h",
"src/dawn_wire/client/Fence.cpp",
"src/dawn_wire/client/Fence.h",
"src/dawn_wire/client/ObjectAllocator.h",

View File

@ -387,9 +387,9 @@ def get_renders_for_targets(api_params, wire_json, targets):
renders.append(FileRender('dawn_wire/client/ApiObjects.h', 'dawn_wire/client/ApiObjects_autogen.h', wire_params))
renders.append(FileRender('dawn_wire/client/ApiProcs.cpp', 'dawn_wire/client/ApiProcs_autogen.cpp', wire_params))
renders.append(FileRender('dawn_wire/client/ApiProcs.h', 'dawn_wire/client/ApiProcs_autogen.h', wire_params))
renders.append(FileRender('dawn_wire/client/ClientBase.h', 'dawn_wire/client/ClientBase_autogen.h', wire_params))
renders.append(FileRender('dawn_wire/client/ClientHandlers.cpp', 'dawn_wire/client/ClientHandlers_autogen.cpp', wire_params))
renders.append(FileRender('dawn_wire/client/ClientPrototypes.inl', 'dawn_wire/client/ClientPrototypes_autogen.inl', wire_params))
renders.append(FileRender('dawn_wire/client/Device.h', 'dawn_wire/client/Device_autogen.h', wire_params))
renders.append(FileRender('dawn_wire/server/ServerBase.h', 'dawn_wire/server/ServerBase_autogen.h', wire_params))
renders.append(FileRender('dawn_wire/server/ServerCallbacks.cpp', 'dawn_wire/server/ServerCallbacks_autogen.cpp', wire_params))
renders.append(FileRender('dawn_wire/server/ServerHandlers.cpp', 'dawn_wire/server/ServerHandlers_autogen.cpp', wire_params))

View File

@ -15,7 +15,6 @@
#include "dawn_wire/client/ApiObjects.h"
#include "dawn_wire/client/ApiProcs_autogen.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device_autogen.h"
namespace dawn_wire { namespace client {
//* Implementation of the client API functions.
@ -42,7 +41,7 @@ namespace dawn_wire { namespace client {
//* For object creation, store the object ID the client will use for the result.
{% if method.return_type.category == "object" %}
auto* allocation = self->device->{{method.return_type.name.camelCase()}}.New();
auto* allocation = self->device->GetClient()->{{method.return_type.name.CamelCase()}}Allocator().New(self->device);
{% if type.is_builder %}
//* We are in GetResult, so the callback that should be called is the
@ -61,8 +60,8 @@ namespace dawn_wire { namespace client {
//* Allocate space to send the command and copy the value args over.
size_t requiredSize = cmd.GetRequiredSize();
char* allocatedBuffer = static_cast<char*>(device->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer, *device);
char* allocatedBuffer = static_cast<char*>(device->GetClient()->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer, *device->GetClient());
{% if method.return_type.category == "object" %}
return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get());
@ -100,10 +99,10 @@ namespace dawn_wire { namespace client {
cmd.objectId = obj->id;
size_t requiredSize = cmd.GetRequiredSize();
char* allocatedBuffer = static_cast<char*>(obj->device->GetCmdSpace(requiredSize));
char* allocatedBuffer = static_cast<char*>(obj->device->GetClient()->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer);
obj->device->{{type.name.camelCase()}}.Free(obj);
obj->device->GetClient()->{{type.name.CamelCase()}}Allocator().Free(obj);
}
void Client{{as_MethodSuffix(type.name, Name("reference"))}}({{cType}} cObj) {

View File

@ -0,0 +1,62 @@
//* 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 DAWNWIRE_CLIENT_CLIENTBASE_AUTOGEN_H_
#define DAWNWIRE_CLIENT_CLIENTBASE_AUTOGEN_H_
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/ApiObjects.h"
#include "dawn_wire/client/ObjectAllocator.h"
namespace dawn_wire { namespace client {
class ClientBase : public ObjectIdProvider {
public:
ClientBase() {
}
virtual ~ClientBase() {
}
{% 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 %}
private:
// Implementation of the ObjectIdProvider interface
{% for type in by_category["object"] %}
ObjectId GetId({{as_cType(type.name)}} object) const final {
return object == nullptr ? 0 : reinterpret_cast<{{as_wireType(type)}}>(object)->id;
}
ObjectId GetOptionalId({{as_cType(type.name)}} object) const final {
if (object == nullptr) {
return 0;
}
return GetId(object);
}
{% endfor %}
{% for type in by_category["object"] %}
ObjectAllocator<{{type.name.CamelCase()}}> m{{type.name.CamelCase()}}Allocator;
{% endfor %}
};
}} // namespace dawn_wire::client
#endif // DAWNWIRE_CLIENT_CLIENTBASE_AUTOGEN_H_

View File

@ -14,7 +14,6 @@
#include "common/Assert.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device_autogen.h"
#include <string>
@ -31,8 +30,8 @@ namespace dawn_wire { namespace client {
DAWN_ASSERT(cmd.message != nullptr);
auto* builtObject = mDevice->{{type.built_type.name.camelCase()}}.GetObject(cmd.builtObject.id);
uint32_t objectSerial = mDevice->{{type.built_type.name.camelCase()}}.GetSerial(cmd.builtObject.id);
auto* builtObject = mDevice->GetClient()->{{type.built_type.name.CamelCase()}}Allocator().GetObject(cmd.builtObject.id);
uint32_t objectSerial = mDevice->GetClient()->{{type.built_type.name.CamelCase()}}Allocator().GetSerial(cmd.builtObject.id);
//* The object might have been deleted or a new object created with the same ID.
if (builtObject == nullptr || objectSerial != cmd.builtObject.serial) {

View File

@ -1,73 +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 DAWNWIRE_CLIENT_DEVICE_AUTOGEN_H_
#define DAWNWIRE_CLIENT_DEVICE_AUTOGEN_H_
#include <dawn/dawn.h>
#include "dawn_wire/Wire.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/ApiObjects.h"
#include "dawn_wire/client/ObjectAllocator.h"
namespace dawn_wire { namespace client {
//* The client wire uses the global Dawn device to store its global data such as the serializer
//* and the object id allocators.
class Device : public ObjectBase, public ObjectIdProvider {
public:
Device(CommandSerializer* serializer)
: ObjectBase(this, 1, 1),
{% for type in by_category["object"] if not type.name.canonical_case() == "device" %}
{{type.name.camelCase()}}(this),
{% endfor %}
mSerializer(serializer) {
}
void* GetCmdSpace(size_t size) {
return mSerializer->GetCmdSpace(size);
}
{% for type in by_category["object"] if not type.name.canonical_case() == "device" %}
ObjectAllocator<{{type.name.CamelCase()}}> {{type.name.camelCase()}};
{% endfor %}
// Implementation of the ObjectIdProvider interface
{% for type in by_category["object"] %}
ObjectId GetId({{as_cType(type.name)}} object) const final {
return reinterpret_cast<{{as_wireType(type)}}>(object)->id;
}
ObjectId GetOptionalId({{as_cType(type.name)}} object) const final {
if (object == nullptr) {
return 0;
}
return GetId(object);
}
{% endfor %}
void HandleError(const char* message) {
if (errorCallback) {
errorCallback(message, errorUserdata);
}
}
dawnDeviceErrorCallback errorCallback = nullptr;
dawnCallbackUserdata errorUserdata;
private:
CommandSerializer* mSerializer = nullptr;
};
}} // namespace dawn_wire::client
#endif // DAWNWIRE_CLIENT_DEVICE_AUTOGEN_H_

View File

@ -13,19 +13,13 @@
// limitations under the License.
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device_autogen.h"
#include "dawn_wire/server/Server.h"
namespace dawn_wire {
CommandHandler* NewClientDevice(dawnProcTable* procs,
dawnDevice* device,
CommandSerializer* serializer) {
auto clientDevice = new client::Device(serializer);
*device = reinterpret_cast<dawnDeviceImpl*>(clientDevice);
*procs = client::GetProcs();
return new client::Client(clientDevice);
return new client::Client(procs, device, serializer);
}
CommandHandler* NewServerCommandHandler(dawnDevice device,

View File

@ -18,6 +18,7 @@
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/Buffer.h"
#include "dawn_wire/client/Device.h"
#include "dawn_wire/client/Fence.h"
#include "dawn_wire/client/ApiObjects_autogen.h"

View File

@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/ApiObjects.h"
#include "dawn_wire/client/ApiProcs_autogen.h"
#include "dawn_wire/client/Device_autogen.h"
#include "dawn_wire/client/Client.h"
namespace dawn_wire { namespace client {
@ -42,7 +43,8 @@ namespace dawn_wire { namespace client {
cmd.isWrite = false;
size_t requiredSize = cmd.GetRequiredSize();
char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
char* allocatedBuffer =
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer);
}
@ -71,7 +73,8 @@ namespace dawn_wire { namespace client {
cmd.isWrite = true;
size_t requiredSize = cmd.GetRequiredSize();
char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
char* allocatedBuffer =
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer);
}
@ -124,7 +127,7 @@ namespace dawn_wire { namespace client {
size_t requiredSize = cmd.GetRequiredSize();
char* allocatedBuffer =
static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer);
}
@ -164,9 +167,8 @@ namespace dawn_wire { namespace client {
void ClientDeviceSetErrorCallback(dawnDevice cSelf,
dawnDeviceErrorCallback callback,
dawnCallbackUserdata userdata) {
Device* self = reinterpret_cast<Device*>(cSelf);
self->errorCallback = callback;
self->errorUserdata = userdata;
Device* device = reinterpret_cast<Device*>(cSelf);
device->SetErrorCallback(callback, userdata);
}
}} // namespace dawn_wire::client

View File

@ -13,10 +13,20 @@
// limitations under the License.
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device.h"
namespace dawn_wire { namespace client {
Client::Client(Device* device) : mDevice(device) {
Client::Client(dawnProcTable* procs, dawnDevice* device, CommandSerializer* serializer)
: ClientBase(),
mDevice(DeviceAllocator().New(this)->object.get()),
mSerializer(serializer) {
*device = reinterpret_cast<dawnDeviceImpl*>(mDevice);
*procs = client::GetProcs();
}
Client::~Client() {
DeviceAllocator().Free(mDevice);
}
}} // namespace dawn_wire::client

View File

@ -19,20 +19,28 @@
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/WireDeserializeAllocator.h"
#include "dawn_wire/client/ClientBase_autogen.h"
namespace dawn_wire { namespace client {
class Device;
class Client : public CommandHandler {
class Client : public ClientBase, public CommandHandler {
public:
Client(Device* device);
Client(dawnProcTable* procs, dawnDevice* device, CommandSerializer* serializer);
~Client();
const char* HandleCommands(const char* commands, size_t size);
void* GetCmdSpace(size_t size) {
return mSerializer->GetCmdSpace(size);
}
private:
#include "dawn_wire/client/ClientPrototypes_autogen.inl"
Device* mDevice;
Device* mDevice = nullptr;
CommandSerializer* mSerializer = nullptr;
WireDeserializeAllocator mAllocator;
};

View File

@ -14,7 +14,7 @@
#include "common/Assert.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device_autogen.h"
#include "dawn_wire/client/Device.h"
namespace dawn_wire { namespace client {
@ -40,8 +40,8 @@ namespace dawn_wire { namespace client {
return false;
}
auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
auto* buffer = mDevice->GetClient()->BufferAllocator().GetObject(cmd.buffer.id);
uint32_t bufferSerial = mDevice->GetClient()->BufferAllocator().GetSerial(cmd.buffer.id);
// The buffer might have been deleted or recreated so this isn't an error.
if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
@ -102,8 +102,8 @@ namespace dawn_wire { namespace client {
return false;
}
auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
auto* buffer = mDevice->GetClient()->BufferAllocator().GetObject(cmd.buffer.id);
uint32_t bufferSerial = mDevice->GetClient()->BufferAllocator().GetSerial(cmd.buffer.id);
// The buffer might have been deleted or recreated so this isn't an error.
if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
@ -156,8 +156,8 @@ namespace dawn_wire { namespace client {
return false;
}
auto* fence = mDevice->fence.GetObject(cmd.fence.id);
uint32_t fenceSerial = mDevice->fence.GetSerial(cmd.fence.id);
auto* fence = mDevice->GetClient()->FenceAllocator().GetObject(cmd.fence.id);
uint32_t fenceSerial = mDevice->GetClient()->FenceAllocator().GetSerial(cmd.fence.id);
// The fence might have been deleted or recreated so this isn't an error.
if (fence == nullptr || fenceSerial != cmd.fence.serial) {

View File

@ -0,0 +1,40 @@
// 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.
#include "dawn_wire/client/Device.h"
namespace dawn_wire { namespace client {
Device::Device(Client* client, uint32_t refcount, uint32_t id)
: ObjectBase(this, refcount, id), mClient(client) {
this->device = this;
}
Client* Device::GetClient() {
return mClient;
}
void Device::HandleError(const char* message) {
if (mErrorCallback) {
mErrorCallback(message, mErrorUserdata);
}
}
void Device::SetErrorCallback(dawnDeviceErrorCallback errorCallback,
dawnCallbackUserdata errorUserdata) {
mErrorCallback = errorCallback;
mErrorUserdata = errorUserdata;
}
}} // namespace dawn_wire::client

View File

@ -0,0 +1,43 @@
// 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 DAWNWIRE_CLIENT_DEVICE_H_
#define DAWNWIRE_CLIENT_DEVICE_H_
#include <dawn/dawn.h>
#include "dawn_wire/client/ObjectBase.h"
namespace dawn_wire { namespace client {
class Client;
class Device : public ObjectBase {
public:
Device(Client* client, uint32_t refcount, uint32_t id);
Client* GetClient();
void HandleError(const char* message);
void SetErrorCallback(dawnDeviceErrorCallback errorCallback,
dawnCallbackUserdata errorUserdata);
private:
Client* mClient = nullptr;
dawnDeviceErrorCallback mErrorCallback = nullptr;
dawnCallbackUserdata mErrorUserdata;
};
}} // namespace dawn_wire::client
#endif // DAWNWIRE_CLIENT_DEVICE_H_

View File

@ -22,12 +22,16 @@
namespace dawn_wire { namespace client {
class Client;
class Device;
// TODO(cwallez@chromium.org): Do something with objects before they are destroyed ?
// - Call still uncalled builder callbacks
template <typename T>
class ObjectAllocator {
using ObjectOwner =
typename std::conditional<std::is_same<T, Device>::value, Client, Device>::type;
public:
struct ObjectAndSerial {
ObjectAndSerial(std::unique_ptr<T> object, uint32_t serial)
@ -37,14 +41,14 @@ namespace dawn_wire { namespace client {
uint32_t serial;
};
ObjectAllocator(Device* device) : mDevice(device) {
ObjectAllocator() {
// ID 0 is nullptr
mObjects.emplace_back(nullptr, 0);
}
ObjectAndSerial* New() {
ObjectAndSerial* New(ObjectOwner* owner) {
uint32_t id = GetNewId();
T* result = new T(mDevice, 1, id);
T* result = new T(owner, 1, id);
auto object = std::unique_ptr<T>(result);
if (id >= mObjects.size()) {

View File

@ -170,6 +170,10 @@ class WireTestsBase : public Test {
void TearDown() override {
dawnSetProcs(nullptr);
// Reset client before mocks are deleted.
// Incomplete callbacks will be called on deletion, so the mocks cannot be null.
mWireClient = nullptr;
// Delete mocks so that expectations are checked
mockDeviceErrorCallback = nullptr;
mockBuilderErrorCallback = nullptr;