| // 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, | |
| std::shared_ptr<const DawnProcTable>& procs) | |
| : server(server), procs(procs) {} | |
| // static | |
| std::shared_ptr<Server> Server::Create(const DawnProcTable& procs, | |
| CommandSerializer* serializer, | |
| MemoryTransferService* memoryTransferService, | |
| bool useSpontaneousCallbacks) { | |
| auto server = std::shared_ptr<Server>( | |
| new Server(procs, serializer, memoryTransferService, useSpontaneousCallbacks)); | |
| server->mSelf = server; | |
| return server; | |
| } | |
| Server::Server(const DawnProcTable& procs, | |
| CommandSerializer* serializer, | |
| MemoryTransferService* memoryTransferService, | |
| bool useSpontaneousCallbacks) | |
| : ServerBase(procs), | |
| mSerializer(serializer), | |
| mMemoryTransferService(memoryTransferService), | |
| mUseSpontaneousCallbacks(useSpontaneousCallbacks) { | |
| if (mMemoryTransferService == nullptr) { | |
| // If a MemoryTransferService is not provided, fallback to inline memory. | |
| mOwnedMemoryTransferService = CreateInlineMemoryTransferService(); | |
| mMemoryTransferService = mOwnedMemoryTransferService.get(); | |
| } | |
| } | |
| Server::~Server() { | |
| // Destroy all the devices to un-set the error and lost callbacks since we cannot forward | |
| // them after the server has been destroyed. | |
| for (WGPUDevice device : GetAllDeviceHandles()) { | |
| mProcs->deviceDestroy(device); | |
| } | |
| DestroyAllObjects(); | |
| } | |
| WireResult Server::InjectBuffer(WGPUBuffer buffer, | |
| const Handle& handle, | |
| const Handle& deviceHandle) { | |
| DAWN_ASSERT(buffer != nullptr); | |
| Known<WGPUDevice> device; | |
| WIRE_TRY(Get(deviceHandle.id, &device)); | |
| if (device->generation != deviceHandle.generation) { | |
| return WireResult::FatalError; | |
| } | |
| Reserved<WGPUBuffer> data; | |
| WIRE_TRY(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(Get(deviceHandle.id, &device)); | |
| if (device->generation != deviceHandle.generation) { | |
| return WireResult::FatalError; | |
| } | |
| Reserved<WGPUTexture> data; | |
| WIRE_TRY(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::InjectSurface(WGPUSurface surface, | |
| const Handle& handle, | |
| const Handle& instanceHandle) { | |
| DAWN_ASSERT(surface != nullptr); | |
| Known<WGPUInstance> instance; | |
| WIRE_TRY(Get(instanceHandle.id, &instance)); | |
| if (instance->generation != instanceHandle.generation) { | |
| return WireResult::FatalError; | |
| } | |
| Reserved<WGPUSurface> data; | |
| WIRE_TRY(Allocate(&data, handle)); | |
| data->handle = surface; | |
| data->generation = handle.generation; | |
| data->state = AllocationState::Allocated; | |
| // The surface 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->surfaceAddRef(surface); | |
| return WireResult::Success; | |
| } | |
| WireResult Server::InjectInstance(WGPUInstance instance, const Handle& handle) { | |
| DAWN_ASSERT(instance != nullptr); | |
| Reserved<WGPUInstance> data; | |
| WIRE_TRY(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 (Get(id, &device) != WireResult::Success || device->generation != generation) { | |
| return nullptr; | |
| } | |
| return device->handle; | |
| } | |
| void Server::Flush() { | |
| if (mUseSpontaneousCallbacks) { | |
| mSerializer->Flush(); | |
| } | |
| } | |
| 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::DoUnregisterObject to call Destroy. | |
| // This ensures that callbacks will not fire after |deviceObject| is freed. | |
| // Set callback to post warning and other information to client. | |
| mProcs->deviceSetLoggingCallback( | |
| device->handle, {nullptr, | |
| [](WGPULoggingType type, WGPUStringView message, void* userdata, void*) { | |
| DeviceInfo* info = static_cast<DeviceInfo*>(userdata); | |
| info->server->OnLogging(info->self, type, message); | |
| info->server->Flush(); | |
| }, | |
| device->info.get(), nullptr}); | |
| } | |
| } // namespace dawn::wire::server |