diff --git a/BUILD.gn b/BUILD.gn index 4171f62bbd..e3ebd1d940 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -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", diff --git a/generator/main.py b/generator/main.py index ab4c6c7abc..bbc08691f3 100644 --- a/generator/main.py +++ b/generator/main.py @@ -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)) diff --git a/generator/templates/dawn_wire/client/ApiProcs.cpp b/generator/templates/dawn_wire/client/ApiProcs.cpp index 9544e93dd9..a5c628209d 100644 --- a/generator/templates/dawn_wire/client/ApiProcs.cpp +++ b/generator/templates/dawn_wire/client/ApiProcs.cpp @@ -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(device->GetCmdSpace(requiredSize)); - cmd.Serialize(allocatedBuffer, *device); + char* allocatedBuffer = static_cast(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(obj->device->GetCmdSpace(requiredSize)); + char* allocatedBuffer = static_cast(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) { diff --git a/generator/templates/dawn_wire/client/ClientBase.h b/generator/templates/dawn_wire/client/ClientBase.h new file mode 100644 index 0000000000..fa77852513 --- /dev/null +++ b/generator/templates/dawn_wire/client/ClientBase.h @@ -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_ diff --git a/generator/templates/dawn_wire/client/ClientHandlers.cpp b/generator/templates/dawn_wire/client/ClientHandlers.cpp index 31a8081051..75beddc505 100644 --- a/generator/templates/dawn_wire/client/ClientHandlers.cpp +++ b/generator/templates/dawn_wire/client/ClientHandlers.cpp @@ -14,7 +14,6 @@ #include "common/Assert.h" #include "dawn_wire/client/Client.h" -#include "dawn_wire/client/Device_autogen.h" #include @@ -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) { diff --git a/generator/templates/dawn_wire/client/Device.h b/generator/templates/dawn_wire/client/Device.h deleted file mode 100644 index 796383a3aa..0000000000 --- a/generator/templates/dawn_wire/client/Device.h +++ /dev/null @@ -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 - -#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_ diff --git a/src/dawn_wire/DawnWire.cpp b/src/dawn_wire/DawnWire.cpp index 7dca809f92..56792d0b6e 100644 --- a/src/dawn_wire/DawnWire.cpp +++ b/src/dawn_wire/DawnWire.cpp @@ -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(clientDevice); - *procs = client::GetProcs(); - - return new client::Client(clientDevice); + return new client::Client(procs, device, serializer); } CommandHandler* NewServerCommandHandler(dawnDevice device, diff --git a/src/dawn_wire/client/ApiObjects.h b/src/dawn_wire/client/ApiObjects.h index c7a52c3cba..b74eefe615 100644 --- a/src/dawn_wire/client/ApiObjects.h +++ b/src/dawn_wire/client/ApiObjects.h @@ -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" diff --git a/src/dawn_wire/client/ApiProcs.cpp b/src/dawn_wire/client/ApiProcs.cpp index 99f620a61b..d5a4494de9 100644 --- a/src/dawn_wire/client/ApiProcs.cpp +++ b/src/dawn_wire/client/ApiProcs.cpp @@ -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(buffer->device->GetCmdSpace(requiredSize)); + char* allocatedBuffer = + static_cast(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(buffer->device->GetCmdSpace(requiredSize)); + char* allocatedBuffer = + static_cast(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(buffer->device->GetCmdSpace(requiredSize)); + static_cast(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(cSelf); - self->errorCallback = callback; - self->errorUserdata = userdata; + Device* device = reinterpret_cast(cSelf); + device->SetErrorCallback(callback, userdata); } }} // namespace dawn_wire::client diff --git a/src/dawn_wire/client/Client.cpp b/src/dawn_wire/client/Client.cpp index 6921fa9588..ecd332ec94 100644 --- a/src/dawn_wire/client/Client.cpp +++ b/src/dawn_wire/client/Client.cpp @@ -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(mDevice); + *procs = client::GetProcs(); + } + + Client::~Client() { + DeviceAllocator().Free(mDevice); } }} // namespace dawn_wire::client diff --git a/src/dawn_wire/client/Client.h b/src/dawn_wire/client/Client.h index cf975e8b95..3f8a7034ec 100644 --- a/src/dawn_wire/client/Client.h +++ b/src/dawn_wire/client/Client.h @@ -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; }; diff --git a/src/dawn_wire/client/ClientHandlers.cpp b/src/dawn_wire/client/ClientHandlers.cpp index dc64ec2cc2..913b7a5f78 100644 --- a/src/dawn_wire/client/ClientHandlers.cpp +++ b/src/dawn_wire/client/ClientHandlers.cpp @@ -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) { diff --git a/src/dawn_wire/client/Device.cpp b/src/dawn_wire/client/Device.cpp new file mode 100644 index 0000000000..57e6e16ba3 --- /dev/null +++ b/src/dawn_wire/client/Device.cpp @@ -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 diff --git a/src/dawn_wire/client/Device.h b/src/dawn_wire/client/Device.h new file mode 100644 index 0000000000..f3d49d778d --- /dev/null +++ b/src/dawn_wire/client/Device.h @@ -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 + +#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_ diff --git a/src/dawn_wire/client/ObjectAllocator.h b/src/dawn_wire/client/ObjectAllocator.h index c50307cc1b..3b1b60e6d0 100644 --- a/src/dawn_wire/client/ObjectAllocator.h +++ b/src/dawn_wire/client/ObjectAllocator.h @@ -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 class ObjectAllocator { + using ObjectOwner = + typename std::conditional::value, Client, Device>::type; + public: struct ObjectAndSerial { ObjectAndSerial(std::unique_ptr 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(result); if (id >= mObjects.size()) { diff --git a/src/tests/unittests/WireTests.cpp b/src/tests/unittests/WireTests.cpp index 48db4e6a7b..b032fc23ec 100644 --- a/src/tests/unittests/WireTests.cpp +++ b/src/tests/unittests/WireTests.cpp @@ -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;