• 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 #ifndef DAWNWIRE_SERVER_OBJECTSTORAGE_H_
16 #define DAWNWIRE_SERVER_OBJECTSTORAGE_H_
17 
18 #include "dawn_wire/WireCmd_autogen.h"
19 #include "dawn_wire/WireServer.h"
20 
21 #include <algorithm>
22 #include <map>
23 #include <unordered_set>
24 
25 namespace dawn_wire { namespace server {
26 
27     struct DeviceInfo {
28         std::unordered_set<uint64_t> childObjectTypesAndIds;
29         Server* server;
30         ObjectHandle self;
31     };
32 
33     // Whether this object has been allocated, or reserved for async object creation.
34     // Used by the KnownObjects queries
35     enum class AllocationState : uint32_t {
36         Free,
37         Reserved,
38         Allocated,
39     };
40 
41     template <typename T>
42     struct ObjectDataBase {
43         // The backend-provided handle and generation to this object.
44         T handle;
45         uint32_t generation = 0;
46 
47         AllocationState state;
48 
49         // This points to an allocation that is owned by the device.
50         DeviceInfo* deviceInfo = nullptr;
51     };
52 
53     // Stores what the backend knows about the type.
54     template <typename T>
55     struct ObjectData : public ObjectDataBase<T> {};
56 
57     enum class BufferMapWriteState { Unmapped, Mapped, MapError };
58 
59     template <>
60     struct ObjectData<WGPUBuffer> : public ObjectDataBase<WGPUBuffer> {
61         // TODO(enga): Use a tagged pointer to save space.
62         std::unique_ptr<MemoryTransferService::ReadHandle> readHandle;
63         std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle;
64         BufferMapWriteState mapWriteState = BufferMapWriteState::Unmapped;
65         WGPUBufferUsageFlags usage = WGPUBufferUsage_None;
66         // Indicate if writeHandle needs to be destroyed on unmap
67         bool mappedAtCreation = false;
68     };
69 
70     // Pack the ObjectType and ObjectId as a single value for storage in
71     // an std::unordered_set. This lets us avoid providing our own hash and
72     // equality comparison operators.
73     inline uint64_t PackObjectTypeAndId(ObjectType type, ObjectId id) {
74         static_assert(sizeof(ObjectType) * 8 <= 32, "");
75         static_assert(sizeof(ObjectId) * 8 <= 32, "");
76         return (static_cast<uint64_t>(type) << 32) + id;
77     }
78 
79     inline std::pair<ObjectType, ObjectId> UnpackObjectTypeAndId(uint64_t payload) {
80         ObjectType type = static_cast<ObjectType>(payload >> 32);
81         ObjectId id = payload & 0xFFFFFFFF;
82         return std::make_pair(type, id);
83     }
84 
85     template <>
86     struct ObjectData<WGPUDevice> : public ObjectDataBase<WGPUDevice> {
87         // Store |info| as a separate allocation so that its address does not move.
88         // The pointer to |info| is stored in device child objects.
89         std::unique_ptr<DeviceInfo> info = std::make_unique<DeviceInfo>();
90     };
91 
92     // Keeps track of the mapping between client IDs and backend objects.
93     template <typename T>
94     class KnownObjects {
95       public:
96         using Data = ObjectData<T>;
97 
98         KnownObjects() {
99             // Reserve ID 0 so that it can be used to represent nullptr for optional object values
100             // in the wire format. However don't tag it as allocated so that it is an error to ask
101             // KnownObjects for ID 0.
102             Data reservation;
103             reservation.handle = nullptr;
104             reservation.state = AllocationState::Free;
105             mKnown.push_back(std::move(reservation));
106         }
107 
108         // Get a backend objects for a given client ID.
109         // Returns nullptr if the ID hasn't previously been allocated.
110         const Data* Get(uint32_t id, AllocationState expected = AllocationState::Allocated) const {
111             if (id >= mKnown.size()) {
112                 return nullptr;
113             }
114 
115             const Data* data = &mKnown[id];
116 
117             if (data->state != expected) {
118                 return nullptr;
119             }
120 
121             return data;
122         }
123         Data* Get(uint32_t id, AllocationState expected = AllocationState::Allocated) {
124             if (id >= mKnown.size()) {
125                 return nullptr;
126             }
127 
128             Data* data = &mKnown[id];
129 
130             if (data->state != expected) {
131                 return nullptr;
132             }
133 
134             return data;
135         }
136 
137         // Allocates the data for a given ID and returns it.
138         // Returns nullptr if the ID is already allocated, or too far ahead, or if ID is 0 (ID 0 is
139         // reserved for nullptr). Invalidates all the Data*
140         Data* Allocate(uint32_t id, AllocationState state = AllocationState::Allocated) {
141             if (id == 0 || id > mKnown.size()) {
142                 return nullptr;
143             }
144 
145             Data data;
146             data.state = state;
147             data.handle = nullptr;
148 
149             if (id >= mKnown.size()) {
150                 mKnown.push_back(std::move(data));
151                 return &mKnown.back();
152             }
153 
154             if (mKnown[id].state != AllocationState::Free) {
155                 return nullptr;
156             }
157 
158             mKnown[id] = std::move(data);
159             return &mKnown[id];
160         }
161 
162         // Marks an ID as deallocated
163         void Free(uint32_t id) {
164             ASSERT(id < mKnown.size());
165             mKnown[id].state = AllocationState::Free;
166         }
167 
168         std::vector<T> AcquireAllHandles() {
169             std::vector<T> objects;
170             for (Data& data : mKnown) {
171                 if (data.state == AllocationState::Allocated && data.handle != nullptr) {
172                     objects.push_back(data.handle);
173                     data.state = AllocationState::Free;
174                     data.handle = nullptr;
175                 }
176             }
177 
178             return objects;
179         }
180 
181         std::vector<T> GetAllHandles() {
182             std::vector<T> objects;
183             for (Data& data : mKnown) {
184                 if (data.state == AllocationState::Allocated && data.handle != nullptr) {
185                     objects.push_back(data.handle);
186                 }
187             }
188 
189             return objects;
190         }
191 
192       private:
193         std::vector<Data> mKnown;
194     };
195 
196     // ObjectIds are lost in deserialization. Store the ids of deserialized
197     // objects here so they can be used in command handlers. This is useful
198     // for creating ReturnWireCmds which contain client ids
199     template <typename T>
200     class ObjectIdLookupTable {
201       public:
202         void Store(T key, ObjectId id) {
203             mTable[key] = id;
204         }
205 
206         // Return the cached ObjectId, or 0 (null handle)
207         ObjectId Get(T key) const {
208             const auto it = mTable.find(key);
209             if (it != mTable.end()) {
210                 return it->second;
211             }
212             return 0;
213         }
214 
215         void Remove(T key) {
216             auto it = mTable.find(key);
217             if (it != mTable.end()) {
218                 mTable.erase(it);
219             }
220         }
221 
222       private:
223         std::map<T, ObjectId> mTable;
224     };
225 
226 }}  // namespace dawn_wire::server
227 
228 #endif  // DAWNWIRE_SERVER_OBJECTSTORAGE_H_
229