• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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