blob: b363c1986172fc0ad54ae2e82553736558f704a1 [file] [log] [blame] [edit]
// Copyright 2019 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dawn/wire/server/Server.h"
#include "dawn/wire/WireServer.h"
namespace dawn::wire::server {
CallbackUserdata::CallbackUserdata(const std::weak_ptr<Server>& server) : server(server) {}
// static
std::shared_ptr<Server> Server::Create(const DawnProcTable& procs,
CommandSerializer* serializer,
MemoryTransferService* memoryTransferService) {
auto server = std::shared_ptr<Server>(new Server(procs, serializer, memoryTransferService));
server->mSelf = server;
return server;
}
Server::Server(const DawnProcTable& procs,
CommandSerializer* serializer,
MemoryTransferService* memoryTransferService)
: mSerializer(serializer), mProcs(procs), mMemoryTransferService(memoryTransferService) {
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 : Objects<WGPUDevice>().GetAllHandles()) {
ClearDeviceCallbacks(device);
}
DestroyAllObjects(mProcs);
}
WireResult Server::InjectBuffer(WGPUBuffer buffer,
const Handle& handle,
const Handle& deviceHandle) {
DAWN_ASSERT(buffer != nullptr);
Known<WGPUDevice> device;
WIRE_TRY(Objects<WGPUDevice>().Get(deviceHandle.id, &device));
if (device->generation != deviceHandle.generation) {
return WireResult::FatalError;
}
Reserved<WGPUBuffer> data;
WIRE_TRY(Objects<WGPUBuffer>().Allocate(&data, handle));
data->handle = buffer;
data->generation = handle.generation;
data->state = AllocationState::Allocated;
// The Buffer 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.bufferAddRef(buffer);
return WireResult::Success;
}
WireResult Server::InjectTexture(WGPUTexture texture,
const Handle& handle,
const Handle& deviceHandle) {
DAWN_ASSERT(texture != nullptr);
Known<WGPUDevice> device;
WIRE_TRY(Objects<WGPUDevice>().Get(deviceHandle.id, &device));
if (device->generation != deviceHandle.generation) {
return WireResult::FatalError;
}
Reserved<WGPUTexture> data;
WIRE_TRY(Objects<WGPUTexture>().Allocate(&data, handle));
data->handle = texture;
data->generation = handle.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.textureAddRef(texture);
return WireResult::Success;
}
WireResult Server::InjectSwapChain(WGPUSwapChain swapchain,
const Handle& handle,
const Handle& deviceHandle) {
DAWN_ASSERT(swapchain != nullptr);
Known<WGPUDevice> device;
WIRE_TRY(Objects<WGPUDevice>().Get(deviceHandle.id, &device));
if (device->generation != deviceHandle.generation) {
return WireResult::FatalError;
}
Reserved<WGPUSwapChain> data;
WIRE_TRY(Objects<WGPUSwapChain>().Allocate(&data, handle));
data->handle = swapchain;
data->generation = handle.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.swapChainAddRef(swapchain);
return WireResult::Success;
}
WireResult Server::InjectInstance(WGPUInstance instance, const Handle& handle) {
DAWN_ASSERT(instance != nullptr);
Reserved<WGPUInstance> data;
WIRE_TRY(Objects<WGPUInstance>().Allocate(&data, handle));
data->handle = instance;
data->generation = handle.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.instanceAddRef(instance);
return WireResult::Success;
}
WGPUDevice Server::GetDevice(uint32_t id, uint32_t generation) {
Known<WGPUDevice> device;
if (Objects<WGPUDevice>().Get(id, &device) != WireResult::Success ||
device->generation != generation) {
return nullptr;
}
return device->handle;
}
bool Server::IsDeviceKnown(WGPUDevice device) const {
return Objects<WGPUDevice>().IsKnown(device);
}
void Server::SetForwardingDeviceCallbacks(Known<WGPUDevice> device) {
// 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(
device->handle,
[](WGPUErrorType type, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnUncapturedError(info->self, type, message);
},
device->info.get());
// Set callback to post warning and other infomation to client.
// Almost the same with UncapturedError.
mProcs.deviceSetLoggingCallback(
device->handle,
[](WGPULoggingType type, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnLogging(info->self, type, message);
},
device->info.get());
}
void Server::ClearDeviceCallbacks(WGPUDevice device) {
// Un-set the error and logging callbacks since we cannot forward them
// after the server has been destroyed.
mProcs.deviceSetUncapturedErrorCallback(device, nullptr, nullptr);
mProcs.deviceSetLoggingCallback(device, nullptr, nullptr);
}
} // namespace dawn::wire::server