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/client/ApiObjects.h" 16 #include "dawn_wire/client/ApiProcs_autogen.h" 17 #include "dawn_wire/client/Client.h" 18 19 namespace dawn_wire { namespace client { 20 21 namespace { 22 template <typename Handle> SerializeBufferMapAsync(const Buffer * buffer,uint32_t serial,Handle * handle)23 void SerializeBufferMapAsync(const Buffer* buffer, uint32_t serial, Handle* handle) { 24 // TODO(enga): Remove the template when Read/Write handles are combined in a tagged 25 // pointer. 26 constexpr bool isWrite = 27 std::is_same<Handle, MemoryTransferService::WriteHandle>::value; 28 29 // Get the serialization size of the handle. 30 size_t handleCreateInfoLength = handle->SerializeCreateSize(); 31 32 BufferMapAsyncCmd cmd; 33 cmd.bufferId = buffer->id; 34 cmd.requestSerial = serial; 35 cmd.isWrite = isWrite; 36 cmd.handleCreateInfoLength = handleCreateInfoLength; 37 cmd.handleCreateInfo = nullptr; 38 39 size_t commandSize = cmd.GetRequiredSize(); 40 size_t requiredSize = commandSize + handleCreateInfoLength; 41 char* allocatedBuffer = 42 static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize)); 43 cmd.Serialize(allocatedBuffer); 44 // Serialize the handle into the space after the command. 45 handle->SerializeCreate(allocatedBuffer + commandSize); 46 } 47 } // namespace 48 ClientBufferMapReadAsync(WGPUBuffer cBuffer,WGPUBufferMapReadCallback callback,void * userdata)49 void ClientBufferMapReadAsync(WGPUBuffer cBuffer, 50 WGPUBufferMapReadCallback callback, 51 void* userdata) { 52 Buffer* buffer = reinterpret_cast<Buffer*>(cBuffer); 53 54 uint32_t serial = buffer->requestSerial++; 55 ASSERT(buffer->requests.find(serial) == buffer->requests.end()); 56 57 // Create a ReadHandle for the map request. This is the client's intent to read GPU 58 // memory. 59 MemoryTransferService::ReadHandle* readHandle = 60 buffer->device->GetClient()->GetMemoryTransferService()->CreateReadHandle(buffer->size); 61 if (readHandle == nullptr) { 62 callback(WGPUBufferMapAsyncStatus_DeviceLost, nullptr, 0, userdata); 63 return; 64 } 65 66 Buffer::MapRequestData request = {}; 67 request.readCallback = callback; 68 request.userdata = userdata; 69 // The handle is owned by the MapRequest until the callback returns. 70 request.readHandle = std::unique_ptr<MemoryTransferService::ReadHandle>(readHandle); 71 72 // Store a mapping from serial -> MapRequest. The client can map/unmap before the map 73 // operations are returned by the server so multiple requests may be in flight. 74 buffer->requests[serial] = std::move(request); 75 76 SerializeBufferMapAsync(buffer, serial, readHandle); 77 } 78 ClientBufferMapWriteAsync(WGPUBuffer cBuffer,WGPUBufferMapWriteCallback callback,void * userdata)79 void ClientBufferMapWriteAsync(WGPUBuffer cBuffer, 80 WGPUBufferMapWriteCallback callback, 81 void* userdata) { 82 Buffer* buffer = reinterpret_cast<Buffer*>(cBuffer); 83 84 uint32_t serial = buffer->requestSerial++; 85 ASSERT(buffer->requests.find(serial) == buffer->requests.end()); 86 87 // Create a WriteHandle for the map request. This is the client's intent to write GPU 88 // memory. 89 MemoryTransferService::WriteHandle* writeHandle = 90 buffer->device->GetClient()->GetMemoryTransferService()->CreateWriteHandle( 91 buffer->size); 92 if (writeHandle == nullptr) { 93 callback(WGPUBufferMapAsyncStatus_DeviceLost, nullptr, 0, userdata); 94 return; 95 } 96 97 Buffer::MapRequestData request = {}; 98 request.writeCallback = callback; 99 request.userdata = userdata; 100 // The handle is owned by the MapRequest until the callback returns. 101 request.writeHandle = std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle); 102 103 // Store a mapping from serial -> MapRequest. The client can map/unmap before the map 104 // operations are returned by the server so multiple requests may be in flight. 105 buffer->requests[serial] = std::move(request); 106 107 SerializeBufferMapAsync(buffer, serial, writeHandle); 108 } 109 ClientDeviceCreateBuffer(WGPUDevice cDevice,const WGPUBufferDescriptor * descriptor)110 WGPUBuffer ClientDeviceCreateBuffer(WGPUDevice cDevice, 111 const WGPUBufferDescriptor* descriptor) { 112 Device* device = reinterpret_cast<Device*>(cDevice); 113 Client* wireClient = device->GetClient(); 114 115 auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device); 116 Buffer* buffer = bufferObjectAndSerial->object.get(); 117 // Store the size of the buffer so that mapping operations can allocate a 118 // MemoryTransfer handle of the proper size. 119 buffer->size = descriptor->size; 120 121 DeviceCreateBufferCmd cmd; 122 cmd.self = cDevice; 123 cmd.descriptor = descriptor; 124 cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial}; 125 126 size_t requiredSize = cmd.GetRequiredSize(); 127 char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize)); 128 cmd.Serialize(allocatedBuffer, *wireClient); 129 130 return reinterpret_cast<WGPUBuffer>(buffer); 131 } 132 ClientDeviceCreateBufferMapped(WGPUDevice cDevice,const WGPUBufferDescriptor * descriptor)133 WGPUCreateBufferMappedResult ClientDeviceCreateBufferMapped( 134 WGPUDevice cDevice, 135 const WGPUBufferDescriptor* descriptor) { 136 Device* device = reinterpret_cast<Device*>(cDevice); 137 Client* wireClient = device->GetClient(); 138 139 auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device); 140 Buffer* buffer = bufferObjectAndSerial->object.get(); 141 buffer->size = descriptor->size; 142 143 WGPUCreateBufferMappedResult result; 144 result.buffer = reinterpret_cast<WGPUBuffer>(buffer); 145 result.data = nullptr; 146 result.dataLength = 0; 147 148 // Create a WriteHandle for the map request. This is the client's intent to write GPU 149 // memory. 150 std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = 151 std::unique_ptr<MemoryTransferService::WriteHandle>( 152 wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size)); 153 154 if (writeHandle == nullptr) { 155 // TODO(enga): Support context lost generated by the client. 156 return result; 157 } 158 159 // CreateBufferMapped is synchronous and the staging buffer for upload should be immediately 160 // available. 161 // Open the WriteHandle. This returns a pointer and size of mapped memory. 162 // |result.data| may be null on error. 163 std::tie(result.data, result.dataLength) = writeHandle->Open(); 164 165 if (result.data == nullptr) { 166 // TODO(enga): Support context lost generated by the client. 167 return result; 168 } 169 170 // Successfully created staging memory. The buffer now owns the WriteHandle. 171 buffer->writeHandle = std::move(writeHandle); 172 173 // Get the serialization size of the WriteHandle. 174 size_t handleCreateInfoLength = buffer->writeHandle->SerializeCreateSize(); 175 176 DeviceCreateBufferMappedCmd cmd; 177 cmd.device = cDevice; 178 cmd.descriptor = descriptor; 179 cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial}; 180 cmd.handleCreateInfoLength = handleCreateInfoLength; 181 cmd.handleCreateInfo = nullptr; 182 183 size_t commandSize = cmd.GetRequiredSize(); 184 size_t requiredSize = commandSize + handleCreateInfoLength; 185 char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize)); 186 cmd.Serialize(allocatedBuffer, *wireClient); 187 // Serialize the WriteHandle into the space after the command. 188 buffer->writeHandle->SerializeCreate(allocatedBuffer + commandSize); 189 190 return result; 191 } 192 ClientDeviceCreateBufferMappedAsync(WGPUDevice cDevice,const WGPUBufferDescriptor * descriptor,WGPUBufferCreateMappedCallback callback,void * userdata)193 void ClientDeviceCreateBufferMappedAsync(WGPUDevice cDevice, 194 const WGPUBufferDescriptor* descriptor, 195 WGPUBufferCreateMappedCallback callback, 196 void* userdata) { 197 Device* device = reinterpret_cast<Device*>(cDevice); 198 Client* wireClient = device->GetClient(); 199 200 auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device); 201 Buffer* buffer = bufferObjectAndSerial->object.get(); 202 buffer->size = descriptor->size; 203 204 uint32_t serial = buffer->requestSerial++; 205 206 struct CreateBufferMappedInfo { 207 WGPUBuffer buffer; 208 WGPUBufferCreateMappedCallback callback; 209 void* userdata; 210 }; 211 212 CreateBufferMappedInfo* info = new CreateBufferMappedInfo; 213 info->buffer = reinterpret_cast<WGPUBuffer>(buffer); 214 info->callback = callback; 215 info->userdata = userdata; 216 217 // Create a WriteHandle for the map request. This is the client's intent to write GPU 218 // memory. 219 MemoryTransferService::WriteHandle* writeHandle = 220 wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size); 221 if (writeHandle == nullptr) { 222 WGPUCreateBufferMappedResult result; 223 result.buffer = reinterpret_cast<WGPUBuffer>(buffer); 224 result.data = nullptr; 225 result.dataLength = 0; 226 callback(WGPUBufferMapAsyncStatus_DeviceLost, result, userdata); 227 return; 228 } 229 230 Buffer::MapRequestData request; 231 request.writeCallback = [](WGPUBufferMapAsyncStatus status, void* data, uint64_t dataLength, 232 void* userdata) { 233 auto info = std::unique_ptr<CreateBufferMappedInfo>( 234 static_cast<CreateBufferMappedInfo*>(userdata)); 235 236 WGPUCreateBufferMappedResult result; 237 result.buffer = info->buffer; 238 result.data = data; 239 result.dataLength = dataLength; 240 241 info->callback(status, result, info->userdata); 242 }; 243 request.userdata = info; 244 // The handle is owned by the MapRequest until the callback returns. 245 request.writeHandle = std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle); 246 buffer->requests[serial] = std::move(request); 247 248 // Get the serialization size of the WriteHandle. 249 size_t handleCreateInfoLength = writeHandle->SerializeCreateSize(); 250 251 DeviceCreateBufferMappedAsyncCmd cmd; 252 cmd.device = cDevice; 253 cmd.descriptor = descriptor; 254 cmd.requestSerial = serial; 255 cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial}; 256 cmd.handleCreateInfoLength = handleCreateInfoLength; 257 cmd.handleCreateInfo = nullptr; 258 259 size_t commandSize = cmd.GetRequiredSize(); 260 size_t requiredSize = commandSize + handleCreateInfoLength; 261 char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize)); 262 cmd.Serialize(allocatedBuffer, *wireClient); 263 // Serialize the WriteHandle into the space after the command. 264 writeHandle->SerializeCreate(allocatedBuffer + commandSize); 265 } 266 ClientDevicePushErrorScope(WGPUDevice cDevice,WGPUErrorFilter filter)267 void ClientDevicePushErrorScope(WGPUDevice cDevice, WGPUErrorFilter filter) { 268 Device* device = reinterpret_cast<Device*>(cDevice); 269 device->PushErrorScope(filter); 270 } 271 ClientDevicePopErrorScope(WGPUDevice cDevice,WGPUErrorCallback callback,void * userdata)272 bool ClientDevicePopErrorScope(WGPUDevice cDevice, WGPUErrorCallback callback, void* userdata) { 273 Device* device = reinterpret_cast<Device*>(cDevice); 274 return device->RequestPopErrorScope(callback, userdata); 275 } 276 ClientFenceGetCompletedValue(WGPUFence cSelf)277 uint64_t ClientFenceGetCompletedValue(WGPUFence cSelf) { 278 auto fence = reinterpret_cast<Fence*>(cSelf); 279 return fence->completedValue; 280 } 281 ClientFenceOnCompletion(WGPUFence cFence,uint64_t value,WGPUFenceOnCompletionCallback callback,void * userdata)282 void ClientFenceOnCompletion(WGPUFence cFence, 283 uint64_t value, 284 WGPUFenceOnCompletionCallback callback, 285 void* userdata) { 286 Fence* fence = reinterpret_cast<Fence*>(cFence); 287 if (value > fence->signaledValue) { 288 ClientDeviceInjectError(reinterpret_cast<WGPUDevice>(fence->device), 289 WGPUErrorType_Validation, 290 "Value greater than fence signaled value"); 291 callback(WGPUFenceCompletionStatus_Error, userdata); 292 return; 293 } 294 295 if (value <= fence->completedValue) { 296 callback(WGPUFenceCompletionStatus_Success, userdata); 297 return; 298 } 299 300 Fence::OnCompletionData request; 301 request.completionCallback = callback; 302 request.userdata = userdata; 303 fence->requests.Enqueue(std::move(request), value); 304 } 305 ClientBufferSetSubData(WGPUBuffer cBuffer,uint64_t start,uint64_t count,const void * data)306 void ClientBufferSetSubData(WGPUBuffer cBuffer, 307 uint64_t start, 308 uint64_t count, 309 const void* data) { 310 Buffer* buffer = reinterpret_cast<Buffer*>(cBuffer); 311 312 BufferSetSubDataInternalCmd cmd; 313 cmd.bufferId = buffer->id; 314 cmd.start = start; 315 cmd.count = count; 316 cmd.data = static_cast<const uint8_t*>(data); 317 318 Client* wireClient = buffer->device->GetClient(); 319 size_t requiredSize = cmd.GetRequiredSize(); 320 char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize)); 321 cmd.Serialize(allocatedBuffer); 322 } 323 ClientBufferUnmap(WGPUBuffer cBuffer)324 void ClientBufferUnmap(WGPUBuffer cBuffer) { 325 Buffer* buffer = reinterpret_cast<Buffer*>(cBuffer); 326 327 // Invalidate the local pointer, and cancel all other in-flight requests that would 328 // turn into errors anyway (you can't double map). This prevents race when the following 329 // happens, where the application code would have unmapped a buffer but still receive a 330 // callback: 331 // - Client -> Server: MapRequest1, Unmap, MapRequest2 332 // - Server -> Client: Result of MapRequest1 333 // - Unmap locally on the client 334 // - Server -> Client: Result of MapRequest2 335 if (buffer->writeHandle) { 336 // Writes need to be flushed before Unmap is sent. Unmap calls all associated 337 // in-flight callbacks which may read the updated data. 338 ASSERT(buffer->readHandle == nullptr); 339 340 // Get the serialization size of metadata to flush writes. 341 size_t writeFlushInfoLength = buffer->writeHandle->SerializeFlushSize(); 342 343 BufferUpdateMappedDataCmd cmd; 344 cmd.bufferId = buffer->id; 345 cmd.writeFlushInfoLength = writeFlushInfoLength; 346 cmd.writeFlushInfo = nullptr; 347 348 size_t commandSize = cmd.GetRequiredSize(); 349 size_t requiredSize = commandSize + writeFlushInfoLength; 350 char* allocatedBuffer = 351 static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize)); 352 cmd.Serialize(allocatedBuffer); 353 // Serialize flush metadata into the space after the command. 354 // This closes the handle for writing. 355 buffer->writeHandle->SerializeFlush(allocatedBuffer + commandSize); 356 buffer->writeHandle = nullptr; 357 358 } else if (buffer->readHandle) { 359 buffer->readHandle = nullptr; 360 } 361 buffer->ClearMapRequests(WGPUBufferMapAsyncStatus_Unknown); 362 363 BufferUnmapCmd cmd; 364 cmd.self = cBuffer; 365 size_t requiredSize = cmd.GetRequiredSize(); 366 char* allocatedBuffer = 367 static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize)); 368 cmd.Serialize(allocatedBuffer, *buffer->device->GetClient()); 369 } 370 ClientQueueCreateFence(WGPUQueue cSelf,WGPUFenceDescriptor const * descriptor)371 WGPUFence ClientQueueCreateFence(WGPUQueue cSelf, WGPUFenceDescriptor const* descriptor) { 372 Queue* queue = reinterpret_cast<Queue*>(cSelf); 373 Device* device = queue->device; 374 375 QueueCreateFenceCmd cmd; 376 cmd.self = cSelf; 377 auto* allocation = device->GetClient()->FenceAllocator().New(device); 378 cmd.result = ObjectHandle{allocation->object->id, allocation->serial}; 379 cmd.descriptor = descriptor; 380 381 size_t requiredSize = cmd.GetRequiredSize(); 382 char* allocatedBuffer = static_cast<char*>(device->GetClient()->GetCmdSpace(requiredSize)); 383 cmd.Serialize(allocatedBuffer, *device->GetClient()); 384 385 WGPUFence cFence = reinterpret_cast<WGPUFence>(allocation->object.get()); 386 387 Fence* fence = reinterpret_cast<Fence*>(cFence); 388 fence->queue = queue; 389 fence->signaledValue = descriptor->initialValue; 390 fence->completedValue = descriptor->initialValue; 391 return cFence; 392 } 393 ClientQueueSignal(WGPUQueue cQueue,WGPUFence cFence,uint64_t signalValue)394 void ClientQueueSignal(WGPUQueue cQueue, WGPUFence cFence, uint64_t signalValue) { 395 Fence* fence = reinterpret_cast<Fence*>(cFence); 396 Queue* queue = reinterpret_cast<Queue*>(cQueue); 397 if (fence->queue != queue) { 398 ClientDeviceInjectError(reinterpret_cast<WGPUDevice>(fence->device), 399 WGPUErrorType_Validation, 400 "Fence must be signaled on the queue on which it was created."); 401 return; 402 } 403 if (signalValue <= fence->signaledValue) { 404 ClientDeviceInjectError(reinterpret_cast<WGPUDevice>(fence->device), 405 WGPUErrorType_Validation, 406 "Fence value less than or equal to signaled value"); 407 return; 408 } 409 fence->signaledValue = signalValue; 410 411 QueueSignalCmd cmd; 412 cmd.self = cQueue; 413 cmd.fence = cFence; 414 cmd.signalValue = signalValue; 415 416 size_t requiredSize = cmd.GetRequiredSize(); 417 char* allocatedBuffer = 418 static_cast<char*>(fence->device->GetClient()->GetCmdSpace(requiredSize)); 419 cmd.Serialize(allocatedBuffer, *fence->device->GetClient()); 420 } 421 ClientDeviceReference(WGPUDevice)422 void ClientDeviceReference(WGPUDevice) { 423 } 424 ClientDeviceRelease(WGPUDevice)425 void ClientDeviceRelease(WGPUDevice) { 426 } 427 ClientDeviceSetUncapturedErrorCallback(WGPUDevice cSelf,WGPUErrorCallback callback,void * userdata)428 void ClientDeviceSetUncapturedErrorCallback(WGPUDevice cSelf, 429 WGPUErrorCallback callback, 430 void* userdata) { 431 Device* device = reinterpret_cast<Device*>(cSelf); 432 device->SetUncapturedErrorCallback(callback, userdata); 433 } ClientDeviceSetDeviceLostCallback(WGPUDevice cSelf,WGPUDeviceLostCallback callback,void * userdata)434 void ClientDeviceSetDeviceLostCallback(WGPUDevice cSelf, 435 WGPUDeviceLostCallback callback, 436 void* userdata) { 437 Device* device = reinterpret_cast<Device*>(cSelf); 438 device->SetDeviceLostCallback(callback, userdata); 439 } 440 441 }} // namespace dawn_wire::client 442