blob: 2796966a4cde3647ef352d9e3e7eac9baafff18d [file] [log] [blame] [edit]
// 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/server/Server.h"
#include "dawn/wire/WireServer.h"
namespace dawn::wire::server {
CallbackUserdata::CallbackUserdata(Server* server, const std::shared_ptr<bool>& serverIsAlive)
: server(server), serverIsAlive(serverIsAlive) {}
Server::Server(const DawnProcTable& procs,
CommandSerializer* serializer,
MemoryTransferService* memoryTransferService)
: mSerializer(serializer),
mProcs(procs),
mMemoryTransferService(memoryTransferService),
mIsAlive(std::make_shared<bool>(true)) {
if (mMemoryTransferService == nullptr) {
// If a MemoryTransferService is not provided, fallback to inline memory.
mOwnedMemoryTransferService = CreateInlineMemoryTransferService();
mMemoryTransferService = mOwnedMemoryTransferService.get();
}
}
Server::~Server() {
// Un-set the error and lost callbacks since we cannot forward them
// after the server has been destroyed.
for (WGPUDevice device : DeviceObjects().GetAllHandles()) {
ClearDeviceCallbacks(device);
}
DestroyAllObjects(mProcs);
}
bool Server::InjectTexture(WGPUTexture texture,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration) {
ASSERT(texture != nullptr);
ObjectData<WGPUDevice>* device = DeviceObjects().Get(deviceId);
if (device == nullptr || device->generation != deviceGeneration) {
return false;
}
ObjectData<WGPUTexture>* data = TextureObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = texture;
data->generation = generation;
data->state = AllocationState::Allocated;
// The texture is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.textureReference(texture);
return true;
}
bool Server::InjectSwapChain(WGPUSwapChain swapchain,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration) {
ASSERT(swapchain != nullptr);
ObjectData<WGPUDevice>* device = DeviceObjects().Get(deviceId);
if (device == nullptr || device->generation != deviceGeneration) {
return false;
}
ObjectData<WGPUSwapChain>* data = SwapChainObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = swapchain;
data->generation = generation;
data->state = AllocationState::Allocated;
// The texture is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.swapChainReference(swapchain);
return true;
}
bool Server::InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation) {
ASSERT(device != nullptr);
ObjectData<WGPUDevice>* data = DeviceObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = device;
data->generation = generation;
data->state = AllocationState::Allocated;
data->info->server = this;
data->info->self = ObjectHandle{id, generation};
// The device is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.deviceReference(device);
// Set callbacks to forward errors to the client.
SetForwardingDeviceCallbacks(data);
return true;
}
bool Server::InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation) {
ASSERT(instance != nullptr);
ObjectData<WGPUInstance>* data = InstanceObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = instance;
data->generation = generation;
data->state = AllocationState::Allocated;
// The instance is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.instanceReference(instance);
return true;
}
WGPUDevice Server::GetDevice(uint32_t id, uint32_t generation) {
ObjectData<WGPUDevice>* data = DeviceObjects().Get(id);
if (data == nullptr || data->generation != generation) {
return nullptr;
}
return data->handle;
}
bool Server::IsDeviceKnown(WGPUDevice device) const {
return DeviceObjects().IsKnown(device);
}
void Server::SetForwardingDeviceCallbacks(ObjectData<WGPUDevice>* deviceObject) {
// Note: these callbacks are manually inlined here since they do not acquire and
// free their userdata. Also unlike other callbacks, these are cleared and unset when
// the server is destroyed, so we don't need to check if the server is still alive
// inside them.
// Also, the device is special-cased in Server::DoDestroyObject to call
// ClearDeviceCallbacks. This ensures that callbacks will not fire after |deviceObject|
// is freed.
mProcs.deviceSetUncapturedErrorCallback(
deviceObject->handle,
[](WGPUErrorType type, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnUncapturedError(info->self, type, message);
},
deviceObject->info.get());
// Set callback to post warning and other infomation to client.
// Almost the same with UncapturedError.
mProcs.deviceSetLoggingCallback(
deviceObject->handle,
[](WGPULoggingType type, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnLogging(info->self, type, message);
},
deviceObject->info.get());
mProcs.deviceSetDeviceLostCallback(
deviceObject->handle,
[](WGPUDeviceLostReason reason, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnDeviceLost(info->self, reason, message);
},
deviceObject->info.get());
}
void Server::ClearDeviceCallbacks(WGPUDevice device) {
// Un-set the error and lost callbacks since we cannot forward them
// after the server has been destroyed.
mProcs.deviceSetUncapturedErrorCallback(device, nullptr, nullptr);
mProcs.deviceSetLoggingCallback(device, nullptr, nullptr);
mProcs.deviceSetDeviceLostCallback(device, nullptr, nullptr);
}
} // namespace dawn::wire::server