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