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 #ifndef DAWNWIRE_SERVER_SERVER_H_ 16 #define DAWNWIRE_SERVER_SERVER_H_ 17 18 #include "dawn_wire/ChunkedCommandSerializer.h" 19 #include "dawn_wire/server/ServerBase_autogen.h" 20 21 namespace dawn_wire { namespace server { 22 23 class Server; 24 class MemoryTransferService; 25 26 // CallbackUserdata and its derived classes are intended to be created by 27 // Server::MakeUserdata<T> and then passed as the userdata argument for Dawn 28 // callbacks. 29 // It contains a pointer back to the Server so that the callback can call the 30 // Server to perform operations like serialization, and it contains a weak pointer 31 // |serverIsAlive|. If the weak pointer has expired, it means the server has 32 // been destroyed and the callback must not use the Server pointer. 33 // To assist with checking |serverIsAlive| and lifetime management of the userdata, 34 // |ForwardToServer| (defined later in this file) can be used to acquire the userdata, 35 // return early if |serverIsAlive| has expired, and then forward the arguments 36 // to userdata->server->MyCallbackHandler. 37 // 38 // Example Usage: 39 // 40 // struct MyUserdata : CallbackUserdata { uint32_t foo; }; 41 // 42 // auto userdata = MakeUserdata<MyUserdata>(); 43 // userdata->foo = 2; 44 // 45 // // TODO(enga): Make the template inference for ForwardToServer cleaner with C++17 46 // callMyCallbackHandler( 47 // ForwardToServer<decltype(&Server::MyCallbackHandler)>::Func< 48 // &Server::MyCallbackHandler>(), 49 // userdata.release()); 50 // 51 // void Server::MyCallbackHandler(MyUserdata* userdata) { } 52 struct CallbackUserdata { 53 Server* const server; 54 std::weak_ptr<bool> const serverIsAlive; 55 56 CallbackUserdata() = delete; CallbackUserdataCallbackUserdata57 CallbackUserdata(Server* server, const std::shared_ptr<bool>& serverIsAlive) 58 : server(server), serverIsAlive(serverIsAlive) { 59 } 60 }; 61 62 template <typename F> 63 class ForwardToServer; 64 65 template <typename R, typename... Args> 66 class ForwardToServer<R (Server::*)(Args...)> { 67 private: 68 // Get the type T of the last argument. It has CallbackUserdata as its base. 69 using UserdataT = typename std::remove_pointer<typename std::decay<decltype( 70 std::get<sizeof...(Args) - 1>(std::declval<std::tuple<Args...>>()))>::type>::type; 71 72 static_assert(std::is_base_of<CallbackUserdata, UserdataT>::value, 73 "Last argument of callback handler should derive from CallbackUserdata."); 74 75 template <class T, class... Ts> 76 struct UntypedCallbackImpl; 77 78 template <std::size_t... I, class... Ts> 79 struct UntypedCallbackImpl<std::index_sequence<I...>, Ts...> { 80 template <R (Server::*Func)(Args...)> 81 static auto ForwardToServer( 82 // Unpack and forward the types of the parameter pack. 83 // Append void* as the last argument. 84 typename std::tuple_element<I, std::tuple<Ts...>>::type... args, 85 void* userdata) { 86 // Acquire the userdata, and cast it to UserdataT. 87 std::unique_ptr<UserdataT> data(static_cast<UserdataT*>(userdata)); 88 if (data->serverIsAlive.expired()) { 89 // Do nothing if the server has already been destroyed. 90 return; 91 } 92 // Forward the arguments and the typed userdata to the Server:: member function. 93 (data->server->*Func)(std::forward<decltype(args)>(args)..., data.get()); 94 } 95 }; 96 97 // Generate a free function which has all of the same arguments, except the last 98 // userdata argument is void* instead of UserdataT*. Dawn's userdata args are void*. 99 using UntypedCallback = 100 UntypedCallbackImpl<std::make_index_sequence<sizeof...(Args) - 1>, Args...>; 101 102 public: 103 template <R (Server::*F)(Args...)> 104 static auto Func() { 105 return UntypedCallback::template ForwardToServer<F>; 106 } 107 }; 108 109 struct MapUserdata : CallbackUserdata { 110 using CallbackUserdata::CallbackUserdata; 111 112 ObjectHandle buffer; 113 WGPUBuffer bufferObj; 114 uint64_t requestSerial; 115 uint64_t offset; 116 uint64_t size; 117 WGPUMapModeFlags mode; 118 }; 119 120 struct ErrorScopeUserdata : CallbackUserdata { 121 using CallbackUserdata::CallbackUserdata; 122 123 ObjectHandle device; 124 uint64_t requestSerial; 125 }; 126 127 struct ShaderModuleGetCompilationInfoUserdata : CallbackUserdata { 128 using CallbackUserdata::CallbackUserdata; 129 130 ObjectHandle shaderModule; 131 uint64_t requestSerial; 132 }; 133 134 struct QueueWorkDoneUserdata : CallbackUserdata { 135 using CallbackUserdata::CallbackUserdata; 136 137 ObjectHandle queue; 138 uint64_t requestSerial; 139 }; 140 141 struct CreatePipelineAsyncUserData : CallbackUserdata { 142 using CallbackUserdata::CallbackUserdata; 143 144 ObjectHandle device; 145 uint64_t requestSerial; 146 ObjectId pipelineObjectID; 147 }; 148 149 class Server : public ServerBase { 150 public: 151 Server(const DawnProcTable& procs, 152 CommandSerializer* serializer, 153 MemoryTransferService* memoryTransferService); 154 ~Server() override; 155 156 // ChunkedCommandHandler implementation 157 const volatile char* HandleCommandsImpl(const volatile char* commands, 158 size_t size) override; 159 160 bool InjectTexture(WGPUTexture texture, 161 uint32_t id, 162 uint32_t generation, 163 uint32_t deviceId, 164 uint32_t deviceGeneration); 165 166 bool InjectSwapChain(WGPUSwapChain swapchain, 167 uint32_t id, 168 uint32_t generation, 169 uint32_t deviceId, 170 uint32_t deviceGeneration); 171 172 bool InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation); 173 174 WGPUDevice GetDevice(uint32_t id, uint32_t generation); 175 176 template <typename T, 177 typename Enable = std::enable_if<std::is_base_of<CallbackUserdata, T>::value>> 178 std::unique_ptr<T> MakeUserdata() { 179 return std::unique_ptr<T>(new T(this, mIsAlive)); 180 } 181 182 private: 183 template <typename Cmd> 184 void SerializeCommand(const Cmd& cmd) { 185 mSerializer.SerializeCommand(cmd); 186 } 187 188 template <typename Cmd, typename ExtraSizeSerializeFn> 189 void SerializeCommand(const Cmd& cmd, 190 size_t extraSize, 191 ExtraSizeSerializeFn&& SerializeExtraSize) { 192 mSerializer.SerializeCommand(cmd, extraSize, SerializeExtraSize); 193 } 194 195 void ClearDeviceCallbacks(WGPUDevice device); 196 197 // Error callbacks 198 void OnUncapturedError(ObjectHandle device, WGPUErrorType type, const char* message); 199 void OnDeviceLost(ObjectHandle device, WGPUDeviceLostReason reason, const char* message); 200 void OnLogging(ObjectHandle device, WGPULoggingType type, const char* message); 201 void OnDevicePopErrorScope(WGPUErrorType type, 202 const char* message, 203 ErrorScopeUserdata* userdata); 204 void OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, MapUserdata* userdata); 205 void OnQueueWorkDone(WGPUQueueWorkDoneStatus status, QueueWorkDoneUserdata* userdata); 206 void OnCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status, 207 WGPUComputePipeline pipeline, 208 const char* message, 209 CreatePipelineAsyncUserData* userdata); 210 void OnCreateRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status, 211 WGPURenderPipeline pipeline, 212 const char* message, 213 CreatePipelineAsyncUserData* userdata); 214 void OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status, 215 const WGPUCompilationInfo* info, 216 ShaderModuleGetCompilationInfoUserdata* userdata); 217 218 #include "dawn_wire/server/ServerPrototypes_autogen.inc" 219 220 WireDeserializeAllocator mAllocator; 221 ChunkedCommandSerializer mSerializer; 222 DawnProcTable mProcs; 223 std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr; 224 MemoryTransferService* mMemoryTransferService = nullptr; 225 226 std::shared_ptr<bool> mIsAlive; 227 }; 228 229 bool TrackDeviceChild(DeviceInfo* device, ObjectType type, ObjectId id); 230 bool UntrackDeviceChild(DeviceInfo* device, ObjectType type, ObjectId id); 231 232 std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService(); 233 234 }} // namespace dawn_wire::server 235 236 #endif // DAWNWIRE_SERVER_SERVER_H_ 237