1 // Copyright 2019 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_wire/server/Server.h" 16 #include "dawn_wire/WireServer.h" 17 18 namespace dawn_wire { namespace server { 19 Server(const DawnProcTable & procs,CommandSerializer * serializer,MemoryTransferService * memoryTransferService)20 Server::Server(const DawnProcTable& procs, 21 CommandSerializer* serializer, 22 MemoryTransferService* memoryTransferService) 23 : mSerializer(serializer), 24 mProcs(procs), 25 mMemoryTransferService(memoryTransferService), 26 mIsAlive(std::make_shared<bool>(true)) { 27 if (mMemoryTransferService == nullptr) { 28 // If a MemoryTransferService is not provided, fallback to inline memory. 29 mOwnedMemoryTransferService = CreateInlineMemoryTransferService(); 30 mMemoryTransferService = mOwnedMemoryTransferService.get(); 31 } 32 } 33 ~Server()34 Server::~Server() { 35 // Un-set the error and lost callbacks since we cannot forward them 36 // after the server has been destroyed. 37 for (WGPUDevice device : DeviceObjects().GetAllHandles()) { 38 ClearDeviceCallbacks(device); 39 } 40 DestroyAllObjects(mProcs); 41 } 42 InjectTexture(WGPUTexture texture,uint32_t id,uint32_t generation,uint32_t deviceId,uint32_t deviceGeneration)43 bool Server::InjectTexture(WGPUTexture texture, 44 uint32_t id, 45 uint32_t generation, 46 uint32_t deviceId, 47 uint32_t deviceGeneration) { 48 ASSERT(texture != nullptr); 49 ObjectData<WGPUDevice>* device = DeviceObjects().Get(deviceId); 50 if (device == nullptr || device->generation != deviceGeneration) { 51 return false; 52 } 53 54 ObjectData<WGPUTexture>* data = TextureObjects().Allocate(id); 55 if (data == nullptr) { 56 return false; 57 } 58 59 data->handle = texture; 60 data->generation = generation; 61 data->state = AllocationState::Allocated; 62 data->deviceInfo = device->info.get(); 63 64 if (!TrackDeviceChild(data->deviceInfo, ObjectType::Texture, id)) { 65 return false; 66 } 67 68 // The texture is externally owned so it shouldn't be destroyed when we receive a destroy 69 // message from the client. Add a reference to counterbalance the eventual release. 70 mProcs.textureReference(texture); 71 72 return true; 73 } 74 InjectSwapChain(WGPUSwapChain swapchain,uint32_t id,uint32_t generation,uint32_t deviceId,uint32_t deviceGeneration)75 bool Server::InjectSwapChain(WGPUSwapChain swapchain, 76 uint32_t id, 77 uint32_t generation, 78 uint32_t deviceId, 79 uint32_t deviceGeneration) { 80 ASSERT(swapchain != nullptr); 81 ObjectData<WGPUDevice>* device = DeviceObjects().Get(deviceId); 82 if (device == nullptr || device->generation != deviceGeneration) { 83 return false; 84 } 85 86 ObjectData<WGPUSwapChain>* data = SwapChainObjects().Allocate(id); 87 if (data == nullptr) { 88 return false; 89 } 90 91 data->handle = swapchain; 92 data->generation = generation; 93 data->state = AllocationState::Allocated; 94 data->deviceInfo = device->info.get(); 95 96 if (!TrackDeviceChild(data->deviceInfo, ObjectType::SwapChain, id)) { 97 return false; 98 } 99 100 // The texture is externally owned so it shouldn't be destroyed when we receive a destroy 101 // message from the client. Add a reference to counterbalance the eventual release. 102 mProcs.swapChainReference(swapchain); 103 104 return true; 105 } 106 InjectDevice(WGPUDevice device,uint32_t id,uint32_t generation)107 bool Server::InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation) { 108 ASSERT(device != nullptr); 109 ObjectData<WGPUDevice>* data = DeviceObjects().Allocate(id); 110 if (data == nullptr) { 111 return false; 112 } 113 114 data->handle = device; 115 data->generation = generation; 116 data->state = AllocationState::Allocated; 117 data->info->server = this; 118 data->info->self = ObjectHandle{id, generation}; 119 120 // The device is externally owned so it shouldn't be destroyed when we receive a destroy 121 // message from the client. Add a reference to counterbalance the eventual release. 122 mProcs.deviceReference(device); 123 124 // Set callbacks to forward errors to the client. 125 // Note: these callbacks are manually inlined here since they do not acquire and 126 // free their userdata. Also unlike other callbacks, these are cleared and unset when 127 // the server is destroyed, so we don't need to check if the server is still alive 128 // inside them. 129 mProcs.deviceSetUncapturedErrorCallback( 130 device, 131 [](WGPUErrorType type, const char* message, void* userdata) { 132 DeviceInfo* info = static_cast<DeviceInfo*>(userdata); 133 info->server->OnUncapturedError(info->self, type, message); 134 }, 135 data->info.get()); 136 // Set callback to post warning and other infomation to client. 137 // Almost the same with UncapturedError. 138 mProcs.deviceSetLoggingCallback( 139 device, 140 [](WGPULoggingType type, const char* message, void* userdata) { 141 DeviceInfo* info = static_cast<DeviceInfo*>(userdata); 142 info->server->OnLogging(info->self, type, message); 143 }, 144 data->info.get()); 145 mProcs.deviceSetDeviceLostCallback( 146 device, 147 [](WGPUDeviceLostReason reason, const char* message, void* userdata) { 148 DeviceInfo* info = static_cast<DeviceInfo*>(userdata); 149 info->server->OnDeviceLost(info->self, reason, message); 150 }, 151 data->info.get()); 152 153 return true; 154 } 155 GetDevice(uint32_t id,uint32_t generation)156 WGPUDevice Server::GetDevice(uint32_t id, uint32_t generation) { 157 ObjectData<WGPUDevice>* data = DeviceObjects().Get(id); 158 if (data == nullptr || data->generation != generation) { 159 return nullptr; 160 } 161 return data->handle; 162 } 163 ClearDeviceCallbacks(WGPUDevice device)164 void Server::ClearDeviceCallbacks(WGPUDevice device) { 165 // Un-set the error and lost callbacks since we cannot forward them 166 // after the server has been destroyed. 167 mProcs.deviceSetUncapturedErrorCallback(device, nullptr, nullptr); 168 mProcs.deviceSetLoggingCallback(device, nullptr, nullptr); 169 mProcs.deviceSetDeviceLostCallback(device, nullptr, nullptr); 170 } 171 TrackDeviceChild(DeviceInfo * info,ObjectType type,ObjectId id)172 bool TrackDeviceChild(DeviceInfo* info, ObjectType type, ObjectId id) { 173 auto it = info->childObjectTypesAndIds.insert(PackObjectTypeAndId(type, id)); 174 if (!it.second) { 175 // An object of this type and id already exists. 176 return false; 177 } 178 return true; 179 } 180 UntrackDeviceChild(DeviceInfo * info,ObjectType type,ObjectId id)181 bool UntrackDeviceChild(DeviceInfo* info, ObjectType type, ObjectId id) { 182 auto& children = info->childObjectTypesAndIds; 183 auto it = children.find(PackObjectTypeAndId(type, id)); 184 if (it == children.end()) { 185 // An object of this type and id was already deleted. 186 return false; 187 } 188 children.erase(it); 189 return true; 190 } 191 192 }} // namespace dawn_wire::server 193