• 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 "common/Assert.h"
16 #include "dawn_wire/BufferConsumer_impl.h"
17 #include "dawn_wire/WireCmd_autogen.h"
18 #include "dawn_wire/server/Server.h"
19 
20 #include <memory>
21 
22 namespace dawn_wire { namespace server {
23 
PreHandleBufferUnmap(const BufferUnmapCmd & cmd)24     bool Server::PreHandleBufferUnmap(const BufferUnmapCmd& cmd) {
25         auto* buffer = BufferObjects().Get(cmd.selfId);
26         DAWN_ASSERT(buffer != nullptr);
27 
28         if (buffer->mappedAtCreation && !(buffer->usage & WGPUMapMode_Write)) {
29             // This indicates the writeHandle is for mappedAtCreation only. Destroy on unmap
30             // writeHandle could have possibly been deleted if buffer is already destroyed so we
31             // don't assert it's non-null
32             buffer->writeHandle = nullptr;
33         }
34 
35         buffer->mapWriteState = BufferMapWriteState::Unmapped;
36 
37         return true;
38     }
39 
PreHandleBufferDestroy(const BufferDestroyCmd & cmd)40     bool Server::PreHandleBufferDestroy(const BufferDestroyCmd& cmd) {
41         // Destroying a buffer does an implicit unmapping.
42         auto* buffer = BufferObjects().Get(cmd.selfId);
43         DAWN_ASSERT(buffer != nullptr);
44 
45         // The buffer was destroyed. Clear the Read/WriteHandle.
46         buffer->readHandle = nullptr;
47         buffer->writeHandle = nullptr;
48         buffer->mapWriteState = BufferMapWriteState::Unmapped;
49 
50         return true;
51     }
52 
DoBufferMapAsync(ObjectId bufferId,uint64_t requestSerial,WGPUMapModeFlags mode,uint64_t offset64,uint64_t size64)53     bool Server::DoBufferMapAsync(ObjectId bufferId,
54                                   uint64_t requestSerial,
55                                   WGPUMapModeFlags mode,
56                                   uint64_t offset64,
57                                   uint64_t size64) {
58         // These requests are just forwarded to the buffer, with userdata containing what the
59         // client will require in the return command.
60 
61         // The null object isn't valid as `self`
62         if (bufferId == 0) {
63             return false;
64         }
65 
66         auto* buffer = BufferObjects().Get(bufferId);
67         if (buffer == nullptr) {
68             return false;
69         }
70 
71         std::unique_ptr<MapUserdata> userdata = MakeUserdata<MapUserdata>();
72         userdata->buffer = ObjectHandle{bufferId, buffer->generation};
73         userdata->bufferObj = buffer->handle;
74         userdata->requestSerial = requestSerial;
75         userdata->mode = mode;
76 
77         // Make sure that the deserialized offset and size are no larger than
78         // std::numeric_limits<size_t>::max() so that they are CPU-addressable, and size is not
79         // WGPU_WHOLE_MAP_SIZE, which is by definition std::numeric_limits<size_t>::max(). Since
80         // client does the default size computation, we should always have a valid actual size here
81         // in server. All other invalid actual size can be caught by dawn native side validation.
82         if (offset64 > std::numeric_limits<size_t>::max() || size64 >= WGPU_WHOLE_MAP_SIZE) {
83             OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus_Error, userdata.get());
84             return true;
85         }
86 
87         size_t offset = static_cast<size_t>(offset64);
88         size_t size = static_cast<size_t>(size64);
89 
90         userdata->offset = offset;
91         userdata->size = size;
92 
93         mProcs.bufferMapAsync(
94             buffer->handle, mode, offset, size,
95             ForwardToServer<decltype(
96                 &Server::OnBufferMapAsyncCallback)>::Func<&Server::OnBufferMapAsyncCallback>(),
97             userdata.release());
98 
99         return true;
100     }
101 
DoDeviceCreateBuffer(ObjectId deviceId,const WGPUBufferDescriptor * descriptor,ObjectHandle bufferResult,uint64_t readHandleCreateInfoLength,const uint8_t * readHandleCreateInfo,uint64_t writeHandleCreateInfoLength,const uint8_t * writeHandleCreateInfo)102     bool Server::DoDeviceCreateBuffer(ObjectId deviceId,
103                                       const WGPUBufferDescriptor* descriptor,
104                                       ObjectHandle bufferResult,
105                                       uint64_t readHandleCreateInfoLength,
106                                       const uint8_t* readHandleCreateInfo,
107                                       uint64_t writeHandleCreateInfoLength,
108                                       const uint8_t* writeHandleCreateInfo) {
109         auto* device = DeviceObjects().Get(deviceId);
110         if (device == nullptr) {
111             return false;
112         }
113 
114         // Create and register the buffer object.
115         auto* resultData = BufferObjects().Allocate(bufferResult.id);
116         if (resultData == nullptr) {
117             return false;
118         }
119         resultData->generation = bufferResult.generation;
120         resultData->handle = mProcs.deviceCreateBuffer(device->handle, descriptor);
121         resultData->deviceInfo = device->info.get();
122         resultData->usage = descriptor->usage;
123         resultData->mappedAtCreation = descriptor->mappedAtCreation;
124         if (!TrackDeviceChild(resultData->deviceInfo, ObjectType::Buffer, bufferResult.id)) {
125             return false;
126         }
127 
128         // isReadMode and isWriteMode could be true at the same time if usage contains
129         // WGPUMapMode_Read and buffer is mappedAtCreation
130         bool isReadMode = descriptor->usage & WGPUMapMode_Read;
131         bool isWriteMode = descriptor->usage & WGPUMapMode_Write || descriptor->mappedAtCreation;
132 
133         // This is the size of data deserialized from the command stream to create the read/write
134         // handle, which must be CPU-addressable.
135         if (readHandleCreateInfoLength > std::numeric_limits<size_t>::max() ||
136             writeHandleCreateInfoLength > std::numeric_limits<size_t>::max() ||
137             readHandleCreateInfoLength >
138                 std::numeric_limits<size_t>::max() - writeHandleCreateInfoLength) {
139             return false;
140         }
141 
142         if (isWriteMode) {
143             MemoryTransferService::WriteHandle* writeHandle = nullptr;
144             // Deserialize metadata produced from the client to create a companion server handle.
145             if (!mMemoryTransferService->DeserializeWriteHandle(
146                     writeHandleCreateInfo, static_cast<size_t>(writeHandleCreateInfoLength),
147                     &writeHandle)) {
148                 return false;
149             }
150             ASSERT(writeHandle != nullptr);
151             resultData->writeHandle.reset(writeHandle);
152             writeHandle->SetDataLength(descriptor->size);
153 
154             if (descriptor->mappedAtCreation) {
155                 void* mapping =
156                     mProcs.bufferGetMappedRange(resultData->handle, 0, descriptor->size);
157                 if (mapping == nullptr) {
158                     // A zero mapping is used to indicate an allocation error of an error buffer.
159                     // This is a valid case and isn't fatal. Remember the buffer is an error so as
160                     // to skip subsequent mapping operations.
161                     resultData->mapWriteState = BufferMapWriteState::MapError;
162                     return true;
163                 }
164                 ASSERT(mapping != nullptr);
165                 writeHandle->SetTarget(mapping);
166 
167                 resultData->mapWriteState = BufferMapWriteState::Mapped;
168             }
169         }
170 
171         if (isReadMode) {
172             MemoryTransferService::ReadHandle* readHandle = nullptr;
173             // Deserialize metadata produced from the client to create a companion server handle.
174             if (!mMemoryTransferService->DeserializeReadHandle(
175                     readHandleCreateInfo, static_cast<size_t>(readHandleCreateInfoLength),
176                     &readHandle)) {
177                 return false;
178             }
179             ASSERT(readHandle != nullptr);
180 
181             resultData->readHandle.reset(readHandle);
182         }
183 
184         return true;
185     }
186 
DoBufferUpdateMappedData(ObjectId bufferId,uint64_t writeDataUpdateInfoLength,const uint8_t * writeDataUpdateInfo,uint64_t offset,uint64_t size)187     bool Server::DoBufferUpdateMappedData(ObjectId bufferId,
188                                           uint64_t writeDataUpdateInfoLength,
189                                           const uint8_t* writeDataUpdateInfo,
190                                           uint64_t offset,
191                                           uint64_t size) {
192         // The null object isn't valid as `self`
193         if (bufferId == 0) {
194             return false;
195         }
196 
197         if (writeDataUpdateInfoLength > std::numeric_limits<size_t>::max() ||
198             offset > std::numeric_limits<size_t>::max() ||
199             size > std::numeric_limits<size_t>::max()) {
200             return false;
201         }
202 
203         auto* buffer = BufferObjects().Get(bufferId);
204         if (buffer == nullptr) {
205             return false;
206         }
207         switch (buffer->mapWriteState) {
208             case BufferMapWriteState::Unmapped:
209                 return false;
210             case BufferMapWriteState::MapError:
211                 // The buffer is mapped but there was an error allocating mapped data.
212                 // Do not perform the memcpy.
213                 return true;
214             case BufferMapWriteState::Mapped:
215                 break;
216         }
217         if (!buffer->writeHandle) {
218             // This check is performed after the check for the MapError state. It is permissible
219             // to Unmap and attempt to update mapped data of an error buffer.
220             return false;
221         }
222 
223         // Deserialize the flush info and flush updated data from the handle into the target
224         // of the handle. The target is set via WriteHandle::SetTarget.
225         return buffer->writeHandle->DeserializeDataUpdate(
226             writeDataUpdateInfo, static_cast<size_t>(writeDataUpdateInfoLength),
227             static_cast<size_t>(offset), static_cast<size_t>(size));
228     }
229 
OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status,MapUserdata * data)230     void Server::OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, MapUserdata* data) {
231         // Skip sending the callback if the buffer has already been destroyed.
232         auto* bufferData = BufferObjects().Get(data->buffer.id);
233         if (bufferData == nullptr || bufferData->generation != data->buffer.generation) {
234             return;
235         }
236 
237         bool isRead = data->mode & WGPUMapMode_Read;
238         bool isSuccess = status == WGPUBufferMapAsyncStatus_Success;
239 
240         ReturnBufferMapAsyncCallbackCmd cmd;
241         cmd.buffer = data->buffer;
242         cmd.requestSerial = data->requestSerial;
243         cmd.status = status;
244         cmd.readDataUpdateInfoLength = 0;
245         cmd.readDataUpdateInfo = nullptr;
246 
247         const void* readData = nullptr;
248         if (isSuccess) {
249             if (isRead) {
250                 // Get the serialization size of the message to initialize ReadHandle data.
251                 readData =
252                     mProcs.bufferGetConstMappedRange(data->bufferObj, data->offset, data->size);
253                 cmd.readDataUpdateInfoLength =
254                     bufferData->readHandle->SizeOfSerializeDataUpdate(data->offset, data->size);
255             } else {
256                 ASSERT(data->mode & WGPUMapMode_Write);
257                 // The in-flight map request returned successfully.
258                 bufferData->mapWriteState = BufferMapWriteState::Mapped;
259                 // Set the target of the WriteHandle to the mapped buffer data.
260                 // writeHandle Target always refers to the buffer base address.
261                 // but we call getMappedRange exactly with the range of data that is potentially
262                 // modified (i.e. we don't want getMappedRange(0, wholeBufferSize) if only a
263                 // subset of the buffer is actually mapped) in case the implementation does some
264                 // range tracking.
265                 bufferData->writeHandle->SetTarget(
266                     static_cast<uint8_t*>(
267                         mProcs.bufferGetMappedRange(data->bufferObj, data->offset, data->size)) -
268                     data->offset);
269             }
270         }
271 
272         SerializeCommand(cmd, cmd.readDataUpdateInfoLength, [&](SerializeBuffer* serializeBuffer) {
273             if (isSuccess && isRead) {
274                 char* readHandleBuffer;
275                 WIRE_TRY(serializeBuffer->NextN(cmd.readDataUpdateInfoLength, &readHandleBuffer));
276                 // The in-flight map request returned successfully.
277                 bufferData->readHandle->SerializeDataUpdate(readData, data->offset, data->size,
278                                                             readHandleBuffer);
279             }
280             return WireResult::Success;
281         });
282     }
283 
284 }}  // namespace dawn_wire::server
285