• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "RutabagaLayer.h"
18 
19 #include <inttypes.h>
20 #include <log/log.h>
21 #include <string.h>
22 
23 #include <algorithm>
24 #include <cstdlib>
25 #include <future>
26 #include <memory>
27 #include <optional>
28 #include <queue>
29 #include <sstream>
30 #include <string>
31 #include <thread>
32 #include <unordered_map>
33 #include <variant>
34 
35 // Blueprint and Meson builds place things differently
36 #if defined(ANDROID)
37 #include "rutabaga_gfx_ffi.h"
38 #else
39 #include "rutabaga_gfx/rutabaga_gfx_ffi.h"
40 #endif
41 
42 namespace gfxstream {
43 namespace {
44 
45 constexpr const uint32_t kInvalidContextId = 0;
46 
Split(const std::string & s,const std::string & delimiters)47 std::vector<std::string> Split(const std::string& s, const std::string& delimiters) {
48     if (delimiters.empty()) {
49         return {};
50     }
51 
52     std::vector<std::string> result;
53 
54     size_t base = 0;
55     size_t found;
56     while (true) {
57         found = s.find_first_of(delimiters, base);
58         result.push_back(s.substr(base, found - base));
59         if (found == s.npos) break;
60         base = found + 1;
61     }
62 
63     return result;
64 }
65 
Join(const std::vector<std::string> & things,const std::string & separator)66 std::string Join(const std::vector<std::string>& things, const std::string& separator) {
67     if (things.empty()) {
68         return "";
69     }
70 
71     std::ostringstream result;
72     result << *things.begin();
73     for (auto it = std::next(things.begin()); it != things.end(); ++it) {
74         result << separator << *it;
75     }
76     return result.str();
77 }
78 
79 }  // namespace
80 
81 class EmulatedVirtioGpu::EmulatedVirtioGpuImpl {
82    public:
83     EmulatedVirtioGpuImpl();
84     ~EmulatedVirtioGpuImpl();
85 
86     bool Init(bool withGl, bool withVk, const std::string& features, EmulatedVirtioGpu* parent);
87 
88     bool GetCaps(uint32_t capsetId, uint32_t guestCapsSize, uint8_t* capset);
89 
90     std::optional<uint32_t> CreateContext(uint32_t contextInit);
91     void DestroyContext(uint32_t contextId);
92 
93     uint8_t* Map(uint32_t resourceId);
94     void Unmap(uint32_t resourceId);
95 
96     int SubmitCmd(uint32_t contextId, uint32_t cmdSize, void* cmd, uint32_t ringIdx,
97                   VirtioGpuFenceFlags fenceFlags, uint32_t& fenceId,
98                   std::optional<uint32_t> blobResourceId);
99 
100     int Wait(uint32_t resourceId);
101 
102     int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
103                          uint32_t transferSize);
104     int TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y,
105                          uint32_t w, uint32_t h);
106 
107     int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t transferOffset,
108                        uint32_t transferSize);
109     int TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x, uint32_t y, uint32_t w,
110                        uint32_t h);
111 
112     std::optional<uint32_t> CreateBlob(uint32_t contextId, uint32_t blobMem, uint32_t blobFlags,
113                                        uint64_t blobId, uint64_t blobSize);
114     std::optional<uint32_t> CreateVirglBlob(uint32_t contextId, uint32_t width, uint32_t height,
115                                             uint32_t virglFormat, uint32_t target, uint32_t bind,
116                                             uint32_t size);
117 
118     void DestroyResource(uint32_t contextId, uint32_t resourceId);
119     void SnapshotSave(const std::string& directory);
120     void SnapshotRestore(const std::string& directory);
121 
122     uint32_t CreateEmulatedFence();
123 
124     void SignalEmulatedFence(uint32_t fenceId);
125 
126     int WaitOnEmulatedFence(int fenceAsFileDescriptor, int timeoutMilliseconds);
127 
128    private:
129     struct VirtioGpuTaskContextAttachResource {
130         uint32_t contextId;
131         uint32_t resourceId;
132     };
133     struct VirtioGpuTaskContextDetachResource {
134         uint32_t contextId;
135         uint32_t resourceId;
136     };
137     struct VirtioGpuTaskCreateContext {
138         uint32_t contextId;
139         uint32_t contextInit;
140         std::string contextName;
141     };
142     struct VirtioGpuTaskCreateBlob {
143         uint32_t contextId;
144         uint32_t resourceId;
145         struct rutabaga_create_blob params;
146     };
147     struct VirtioGpuTaskCreateResource {
148         uint32_t contextId;
149         uint32_t resourceId;
150         uint8_t* resourceBytes;
151         struct rutabaga_create_3d params;
152     };
153     struct VirtioGpuTaskDestroyContext {
154         uint32_t contextId;
155     };
156     struct VirtioGpuTaskMap {
157         uint32_t resourceId;
158         std::promise<uint8_t*> resourceMappedPromise;
159     };
160     struct VirtioGpuTaskUnmap {
161         uint32_t resourceId;
162     };
163     struct VirtioGpuTaskSubmitCmd {
164         uint32_t contextId;
165         std::vector<std::byte> commandBuffer;
166     };
167     struct VirtioGpuTaskTransferToHost {
168         uint32_t contextId;
169         uint32_t resourceId;
170         uint32_t x;
171         uint32_t y;
172         uint32_t w;
173         uint32_t h;
174     };
175     struct VirtioGpuTaskTransferFromHost {
176         uint32_t contextId;
177         uint32_t resourceId;
178         uint32_t x;
179         uint32_t y;
180         uint32_t w;
181         uint32_t h;
182     };
183     struct VirtioGpuTaskUnrefResource {
184         uint32_t resourceId;
185     };
186     struct VirtioGpuTaskSnapshotSave {
187         std::string directory;
188     };
189     struct VirtioGpuTaskSnapshotRestore {
190         std::string directory;
191     };
192     using VirtioGpuTask =
193         std::variant<VirtioGpuTaskContextAttachResource, VirtioGpuTaskContextDetachResource,
194                      VirtioGpuTaskCreateBlob, VirtioGpuTaskCreateContext,
195                      VirtioGpuTaskCreateResource, VirtioGpuTaskDestroyContext, VirtioGpuTaskMap,
196                      VirtioGpuTaskUnmap, VirtioGpuTaskSubmitCmd, VirtioGpuTaskTransferFromHost,
197                      VirtioGpuTaskTransferToHost, VirtioGpuTaskUnrefResource,
198                      VirtioGpuTaskSnapshotSave, VirtioGpuTaskSnapshotRestore>;
199 
200     struct VirtioGpuFence {
201         uint32_t fenceId;
202         uint32_t ringIdx;
203     };
204 
205     struct VirtioGpuTaskWithWaitable {
206         uint32_t contextId;
207         VirtioGpuTask task;
208         std::promise<void> taskCompletedSignaler;
209         std::optional<VirtioGpuFence> fence;
210     };
211 
212     std::shared_future<void> EnqueueVirtioGpuTask(
213         uint32_t contextId, VirtioGpuTask task, std::optional<VirtioGpuFence> fence = std::nullopt);
214     void DoTask(VirtioGpuTaskContextAttachResource task);
215     void DoTask(VirtioGpuTaskContextDetachResource task);
216     void DoTask(VirtioGpuTaskCreateContext task);
217     void DoTask(VirtioGpuTaskCreateBlob task);
218     void DoTask(VirtioGpuTaskCreateResource task);
219     void DoTask(VirtioGpuTaskDestroyContext task);
220     void DoTask(VirtioGpuTaskMap task);
221     void DoTask(VirtioGpuTaskUnmap task);
222     void DoTask(VirtioGpuTaskSubmitCmd task);
223     void DoTask(VirtioGpuTaskTransferFromHost task);
224     void DoTask(VirtioGpuTaskTransferToHost task);
225     void DoTask(VirtioGpuTaskWithWaitable task);
226     void DoTask(VirtioGpuTaskUnrefResource task);
227     void DoTask(VirtioGpuTaskSnapshotSave task);
228     void DoTask(VirtioGpuTaskSnapshotRestore task);
229 
230     void RunVirtioGpuTaskProcessingLoop();
231 
232     std::atomic<uint32_t> mNextContextId{1};
233     std::atomic<uint32_t> mNextVirtioGpuResourceId{1};
234     std::atomic<uint32_t> mNextVirtioGpuFenceId{1};
235 
236     std::atomic_bool mShuttingDown{false};
237 
238     std::mutex mTasksMutex;
239     std::queue<VirtioGpuTaskWithWaitable> mTasks;
240 
241     enum class EmulatedResourceType {
242         kBlob,
243         kPipe,
244     };
245     struct EmulatedResource {
246         EmulatedResourceType type;
247 
248         std::mutex pendingWaitablesMutex;
249         std::vector<std::shared_future<void>> pendingWaitables;
250 
251         // For non-blob resources, the guest shadow memory.
252         std::unique_ptr<uint8_t[]> guestBytes;
253 
254         // For mappable blob resources, the host memory once it is mapped.
255         std::shared_future<uint8_t*> mappedHostBytes;
256 
257         // For resources with iovecs.  Test layer just needs 1.
258         struct iovec iovec;
259     };
260     std::mutex mResourcesMutex;
261     std::unordered_map<uint32_t, EmulatedResource> mResources;
262 
CreateResource(uint32_t resourceId,EmulatedResourceType resourceType)263     EmulatedResource* CreateResource(uint32_t resourceId, EmulatedResourceType resourceType) {
264         std::lock_guard<std::mutex> lock(mResourcesMutex);
265 
266         auto [it, created] = mResources.emplace(
267             std::piecewise_construct, std::forward_as_tuple(resourceId), std::forward_as_tuple());
268         if (!created) {
269             ALOGE("Created resource %" PRIu32 " twice?", resourceId);
270         }
271 
272         EmulatedResource* resource = &it->second;
273         resource->type = resourceType;
274         return resource;
275     }
276 
GetResource(uint32_t resourceId)277     EmulatedResource* GetResource(uint32_t resourceId) {
278         std::lock_guard<std::mutex> lock(mResourcesMutex);
279 
280         auto it = mResources.find(resourceId);
281         if (it == mResources.end()) {
282             return nullptr;
283         }
284 
285         return &it->second;
286     }
287 
DeleteResource(uint32_t resourceId)288     void DeleteResource(uint32_t resourceId) {
289         std::lock_guard<std::mutex> lock(mResourcesMutex);
290         mResources.erase(resourceId);
291     }
292 
293     struct EmulatedFence {
294         std::promise<void> signaler;
295         std::shared_future<void> waitable;
296     };
297     std::mutex mVirtioGpuFencesMutex;
298     std::unordered_map<uint32_t, EmulatedFence> mVirtioGpuFences;
299 
300     std::thread mWorkerThread;
301     struct rutabaga* mRutabaga = nullptr;
302     std::unordered_map<uint32_t, std::vector<uint8_t>> mCapsets;
303 };
304 
EmulatedVirtioGpuImpl()305 EmulatedVirtioGpu::EmulatedVirtioGpuImpl::EmulatedVirtioGpuImpl()
306     : mWorkerThread([this]() { RunVirtioGpuTaskProcessingLoop(); }) {}
307 
~EmulatedVirtioGpuImpl()308 EmulatedVirtioGpu::EmulatedVirtioGpuImpl::~EmulatedVirtioGpuImpl() {
309     mShuttingDown = true;
310     mWorkerThread.join();
311 
312     if (mRutabaga) {
313         rutabaga_finish(&mRutabaga);
314         mRutabaga = nullptr;
315     }
316 }
317 
318 namespace {
319 
WriteFenceTrampoline(uint64_t cookie,const struct rutabaga_fence * fence)320 void WriteFenceTrampoline(uint64_t cookie, const struct rutabaga_fence* fence) {
321     auto* gpu = reinterpret_cast<EmulatedVirtioGpu*>(cookie);
322     gpu->SignalEmulatedFence(fence->fence_id);
323 }
324 
325 }  // namespace
326 
Init(bool withGl,bool withVk,const std::string & features,EmulatedVirtioGpu * parent)327 bool EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Init(bool withGl, bool withVk,
328                                                     const std::string& features,
329                                                     EmulatedVirtioGpu* parent) {
330     int32_t ret;
331     uint64_t capsetMask = 0;
332     uint32_t numCapsets = 0;
333     struct rutabaga_builder builder = {0};
334 
335     if (withGl) {
336         capsetMask |= (1 << RUTABAGA_CAPSET_GFXSTREAM_GLES);
337     }
338 
339     if (withVk) {
340         capsetMask |= (1 << RUTABAGA_CAPSET_GFXSTREAM_VULKAN);
341     }
342 
343     builder.user_data = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(parent)),
344     builder.fence_cb = WriteFenceTrampoline;
345     builder.capset_mask = capsetMask;
346     builder.wsi = RUTABAGA_WSI_SURFACELESS;
347     if (!features.empty()) {
348         builder.renderer_features = features.c_str();
349     }
350 
351     ret = rutabaga_init(&builder, &mRutabaga);
352     if (ret) {
353         ALOGE("Failed to initialize rutabaga");
354         return false;
355     }
356 
357     ret = rutabaga_get_num_capsets(mRutabaga, &numCapsets);
358     if (ret) {
359         ALOGE("Failed to get number of capsets");
360         return false;
361     }
362 
363     for (uint32_t i = 0; i < numCapsets; i++) {
364         uint32_t capsetId, capsetVersion, capsetSize;
365         std::vector<uint8_t> capsetData;
366 
367         ret = rutabaga_get_capset_info(mRutabaga, i, &capsetId, &capsetVersion, &capsetSize);
368         if (ret) {
369             ALOGE("Failed to get capset info");
370             return false;
371         }
372 
373         capsetData.resize(capsetSize);
374 
375         ret = rutabaga_get_capset(mRutabaga, capsetId, capsetVersion, (uint8_t*)capsetData.data(),
376                                   capsetSize);
377 
378         if (ret) {
379             ALOGE("Failed to get capset");
380             return false;
381         }
382 
383         mCapsets[capsetId] = capsetData;
384     }
385 
386     return true;
387 }
388 
GetCaps(uint32_t capsetId,uint32_t guestCapsSize,uint8_t * capset)389 bool EmulatedVirtioGpu::EmulatedVirtioGpuImpl::GetCaps(uint32_t capsetId, uint32_t guestCapsSize,
390                                                        uint8_t* capset) {
391     if (mCapsets.count(capsetId) == 0) return false;
392 
393     auto capsetData = mCapsets[capsetId];
394     auto copySize = std::min(static_cast<size_t>(guestCapsSize), capsetData.size());
395     memcpy(capset, capsetData.data(), copySize);
396 
397     return true;
398 }
399 
CreateContext(uint32_t contextInit)400 std::optional<uint32_t> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateContext(
401     uint32_t contextInit) {
402     const uint32_t contextId = mNextContextId++;
403 
404     VirtioGpuTaskCreateContext task = {
405         .contextId = contextId,
406         .contextInit = contextInit,
407         .contextName = "EmulatedVirtioGpu Context " + std::to_string(contextId),
408     };
409     EnqueueVirtioGpuTask(contextId, std::move(task));
410     return contextId;
411 }
412 
DestroyContext(uint32_t contextId)413 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DestroyContext(uint32_t contextId) {
414     VirtioGpuTaskDestroyContext task = {
415         .contextId = contextId,
416     };
417     EnqueueVirtioGpuTask(contextId, std::move(task));
418 }
419 
Map(uint32_t resourceId)420 uint8_t* EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Map(uint32_t resourceId) {
421     EmulatedResource* resource = GetResource(resourceId);
422     if (resource == nullptr) {
423         ALOGE("Failed to Map() resource %" PRIu32 ": not found.", resourceId);
424         return nullptr;
425     }
426 
427     uint8_t* mapped = nullptr;
428     if (resource->type == EmulatedResourceType::kBlob) {
429         if (!resource->mappedHostBytes.valid()) {
430             ALOGE("Failed to Map() resource %" PRIu32
431                   ": attempting to map blob "
432                   "without mappable flag?",
433                   resourceId);
434             return nullptr;
435         }
436         mapped = resource->mappedHostBytes.get();
437     } else if (resource->type == EmulatedResourceType::kPipe) {
438         mapped = resource->guestBytes.get();
439     }
440     return mapped;
441 }
442 
Unmap(uint32_t resourceId)443 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Unmap(uint32_t resourceId) {
444     VirtioGpuTaskUnmap task = {
445         .resourceId = resourceId,
446     };
447     EnqueueVirtioGpuTask(0, std::move(task));
448 }
449 
Wait(uint32_t resourceId)450 int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::Wait(uint32_t resourceId) {
451     EmulatedResource* resource = GetResource(resourceId);
452     if (resource == nullptr) {
453         ALOGE("Failed to Wait() on resource %" PRIu32 ": not found.", resourceId);
454         return -1;
455     }
456 
457     std::vector<std::shared_future<void>> pendingWaitables;
458     {
459         std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
460         pendingWaitables = resource->pendingWaitables;
461         resource->pendingWaitables.clear();
462     }
463     for (auto& waitable : pendingWaitables) {
464         waitable.wait();
465     }
466 
467     return 0;
468 }
469 
TransferFromHost(uint32_t contextId,uint32_t resourceId,uint32_t transferOffset,uint32_t transferSize)470 int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferFromHost(uint32_t contextId,
471                                                                uint32_t resourceId,
472                                                                uint32_t transferOffset,
473                                                                uint32_t transferSize) {
474     return TransferFromHost(contextId, resourceId, transferOffset, 0, transferSize, 1);
475 }
476 
TransferFromHost(uint32_t contextId,uint32_t resourceId,uint32_t x,uint32_t y,uint32_t w,uint32_t h)477 int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferFromHost(uint32_t contextId,
478                                                                uint32_t resourceId, uint32_t x,
479                                                                uint32_t y, uint32_t w, uint32_t h) {
480     EmulatedResource* resource = GetResource(resourceId);
481     if (resource == nullptr) {
482         ALOGE("Failed to TransferFromHost() on resource %" PRIu32 ": not found.", resourceId);
483         return -1;
484     }
485 
486     VirtioGpuTaskTransferFromHost task = {
487         .contextId = contextId,
488         .resourceId = resourceId,
489         .x = x,
490         .y = y,
491         .w = w,
492         .h = h,
493     };
494     auto waitable = EnqueueVirtioGpuTask(contextId, std::move(task));
495 
496     {
497         std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
498         resource->pendingWaitables.push_back(std::move(waitable));
499     }
500 
501     return 0;
502 }
503 
TransferToHost(uint32_t contextId,uint32_t resourceId,uint32_t transferOffset,uint32_t transferSize)504 int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferToHost(uint32_t contextId,
505                                                              uint32_t resourceId,
506                                                              uint32_t transferOffset,
507                                                              uint32_t transferSize) {
508     return TransferToHost(contextId, resourceId, transferOffset, 0, transferSize, 1);
509 }
510 
TransferToHost(uint32_t contextId,uint32_t resourceId,uint32_t x,uint32_t y,uint32_t w,uint32_t h)511 int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::TransferToHost(uint32_t contextId,
512                                                              uint32_t resourceId, uint32_t x,
513                                                              uint32_t y, uint32_t w, uint32_t h) {
514     EmulatedResource* resource = GetResource(resourceId);
515     if (resource == nullptr) {
516         ALOGE("Failed to TransferFromHost() on resource %" PRIu32 ": not found.", resourceId);
517         return -1;
518     }
519 
520     VirtioGpuTaskTransferToHost task = {
521         .contextId = contextId,
522         .resourceId = resourceId,
523         .x = x,
524         .y = y,
525         .w = w,
526         .h = h,
527     };
528     auto waitable = EnqueueVirtioGpuTask(contextId, std::move(task));
529 
530     {
531         std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
532         resource->pendingWaitables.push_back(std::move(waitable));
533     }
534 
535     return 0;
536 }
537 
CreateBlob(uint32_t contextId,uint32_t blobMem,uint32_t blobFlags,uint64_t blobId,uint64_t blobSize)538 std::optional<uint32_t> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateBlob(
539     uint32_t contextId, uint32_t blobMem, uint32_t blobFlags, uint64_t blobId, uint64_t blobSize) {
540     const uint32_t resourceId = mNextVirtioGpuResourceId++;
541 
542     ALOGV("Enquing task to create blob resource-id:%d size:%" PRIu64, resourceId, blobSize);
543 
544     EmulatedResource* resource = CreateResource(resourceId, EmulatedResourceType::kBlob);
545 
546     VirtioGpuTaskCreateBlob createTask{
547         .contextId = contextId,
548         .resourceId = resourceId,
549         .params =
550             {
551                 .blob_mem = blobMem,
552                 .blob_flags = blobFlags,
553                 .blob_id = blobId,
554                 .size = blobSize,
555             },
556     };
557     auto createBlobCompletedWaitable = EnqueueVirtioGpuTask(contextId, std::move(createTask));
558     resource->pendingWaitables.push_back(std::move(createBlobCompletedWaitable));
559 
560     if (blobFlags & 0x001 /*kBlobFlagMappable*/) {
561         std::promise<uint8_t*> mappedBytesPromise;
562         std::shared_future<uint8_t*> mappedBytesWaitable = mappedBytesPromise.get_future();
563 
564         VirtioGpuTaskMap mapTask{
565             .resourceId = resourceId,
566             .resourceMappedPromise = std::move(mappedBytesPromise),
567         };
568         EnqueueVirtioGpuTask(contextId, std::move(mapTask));
569         resource->mappedHostBytes = std::move(mappedBytesWaitable);
570     }
571 
572     VirtioGpuTaskContextAttachResource attachTask{
573         .contextId = contextId,
574         .resourceId = resourceId,
575     };
576     EnqueueVirtioGpuTask(contextId, std::move(attachTask));
577 
578     return resourceId;
579 }
580 
CreateVirglBlob(uint32_t contextId,uint32_t width,uint32_t height,uint32_t virglFormat,uint32_t target,uint32_t bind,uint32_t size)581 std::optional<uint32_t> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateVirglBlob(
582     uint32_t contextId, uint32_t width, uint32_t height, uint32_t virglFormat, uint32_t target,
583     uint32_t bind, uint32_t size) {
584     const uint32_t resourceId = mNextVirtioGpuResourceId++;
585 
586     EmulatedResource* resource = CreateResource(resourceId, EmulatedResourceType::kPipe);
587 
588     resource->guestBytes = std::make_unique<uint8_t[]>(size);
589 
590     VirtioGpuTaskCreateResource task{
591         .contextId = contextId,
592         .resourceId = resourceId,
593         .resourceBytes = resource->guestBytes.get(),
594         .params =
595             {
596                 .target = target,
597                 .format = virglFormat,
598                 .bind = bind,
599                 .width = width,
600                 .height = height,
601                 .depth = 1,
602                 .array_size = 1,
603                 .last_level = 0,
604                 .nr_samples = 0,
605                 .flags = 0,
606             },
607     };
608     auto taskCompletedWaitable = EnqueueVirtioGpuTask(contextId, std::move(task));
609     resource->pendingWaitables.push_back(std::move(taskCompletedWaitable));
610 
611     VirtioGpuTaskContextAttachResource attachTask{
612         .contextId = contextId,
613         .resourceId = resourceId,
614     };
615     EnqueueVirtioGpuTask(contextId, std::move(attachTask));
616 
617     return resourceId;
618 }
619 
DestroyResource(uint32_t contextId,uint32_t resourceId)620 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DestroyResource(uint32_t contextId,
621                                                                uint32_t resourceId) {
622     DeleteResource(resourceId);
623 
624     VirtioGpuTaskUnrefResource unrefTask{
625         .resourceId = resourceId,
626     };
627     EnqueueVirtioGpuTask(contextId, std::move(unrefTask));
628 
629     VirtioGpuTaskContextDetachResource detachTask{
630         .contextId = contextId,
631         .resourceId = resourceId,
632     };
633     EnqueueVirtioGpuTask(contextId, std::move(detachTask));
634 }
635 
SnapshotSave(const std::string & directory)636 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SnapshotSave(const std::string& directory) {
637     uint32_t contextId = 0;
638 
639     VirtioGpuTaskSnapshotSave saveTask{
640         .directory = directory,
641     };
642     EnqueueVirtioGpuTask(contextId, std::move(saveTask)).wait();
643 }
644 
SnapshotRestore(const std::string & directory)645 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SnapshotRestore(const std::string& directory) {
646     uint32_t contextId = 0;
647 
648     VirtioGpuTaskSnapshotRestore restoreTask{
649         .directory = directory,
650     };
651 
652     EnqueueVirtioGpuTask(contextId, std::move(restoreTask)).wait();
653 }
654 
SubmitCmd(uint32_t contextId,uint32_t cmdSize,void * cmd,uint32_t ringIdx,VirtioGpuFenceFlags fenceFlags,uint32_t & fenceId,std::optional<uint32_t> blobResourceId)655 int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SubmitCmd(uint32_t contextId, uint32_t cmdSize,
656                                                         void* cmd, uint32_t ringIdx,
657                                                         VirtioGpuFenceFlags fenceFlags,
658                                                         uint32_t& fenceId,
659                                                         std::optional<uint32_t> blobResourceId) {
660     std::optional<VirtioGpuFence> fence;
661     if (fenceFlags & kFlagFence) {
662         fence = VirtioGpuFence{.fenceId = CreateEmulatedFence(), .ringIdx = ringIdx};
663     }
664 
665     const VirtioGpuTaskSubmitCmd task = {
666         .contextId = contextId,
667         .commandBuffer = std::vector<std::byte>(reinterpret_cast<std::byte*>(cmd),
668                                                 reinterpret_cast<std::byte*>(cmd) + cmdSize),
669     };
670     auto taskCompletedWaitable = EnqueueVirtioGpuTask(contextId, std::move(task), fence);
671 
672     if (blobResourceId) {
673         EmulatedResource* resource = GetResource(*blobResourceId);
674         if (resource == nullptr) {
675             ALOGE("Failed to SubmitCmd() with resource %" PRIu32 ": not found.", *blobResourceId);
676             return -1;
677         }
678 
679         {
680             std::lock_guard<std::mutex> lock(resource->pendingWaitablesMutex);
681             resource->pendingWaitables.push_back(std::move(taskCompletedWaitable));
682         }
683     }
684 
685     if (fenceFlags & kFlagFence) {
686         fenceId = (*fence).fenceId;
687     }
688 
689     return 0;
690 }
691 
WaitOnEmulatedFence(int fenceAsFileDescriptor,int timeoutMilliseconds)692 int EmulatedVirtioGpu::EmulatedVirtioGpuImpl::WaitOnEmulatedFence(int fenceAsFileDescriptor,
693                                                                   int timeoutMilliseconds) {
694     uint32_t fenceId = static_cast<uint32_t>(fenceAsFileDescriptor);
695     ALOGV("Waiting on fence:%d", (int)fenceId);
696 
697     std::shared_future<void> waitable;
698 
699     {
700         std::lock_guard<std::mutex> lock(mVirtioGpuFencesMutex);
701 
702         auto fenceIt = mVirtioGpuFences.find(fenceId);
703         if (fenceIt == mVirtioGpuFences.end()) {
704             ALOGE("Fence:%d already signaled", (int)fenceId);
705             return 0;
706         }
707         auto& fence = fenceIt->second;
708 
709         waitable = fence.waitable;
710     }
711 
712     auto status = waitable.wait_for(std::chrono::milliseconds(timeoutMilliseconds));
713     if (status == std::future_status::ready) {
714         ALOGV("Finished waiting for fence:%d", (int)fenceId);
715         return 0;
716     } else {
717         ALOGE("Timed out waiting for fence:%d", (int)fenceId);
718         return -1;
719     }
720 }
721 
SignalEmulatedFence(uint32_t fenceId)722 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::SignalEmulatedFence(uint32_t fenceId) {
723     ALOGV("Signaling fence:%d", (int)fenceId);
724 
725     std::lock_guard<std::mutex> lock(mVirtioGpuFencesMutex);
726 
727     auto fenceIt = mVirtioGpuFences.find(fenceId);
728     if (fenceIt == mVirtioGpuFences.end()) {
729         ALOGE("Failed to find fence %" PRIu32, fenceId);
730         return;
731     }
732     auto& fenceInfo = fenceIt->second;
733     fenceInfo.signaler.set_value();
734 }
735 
CreateEmulatedFence()736 uint32_t EmulatedVirtioGpu::EmulatedVirtioGpuImpl::CreateEmulatedFence() {
737     const uint32_t fenceId = mNextVirtioGpuFenceId++;
738 
739     ALOGV("Creating fence:%d", (int)fenceId);
740 
741     std::lock_guard<std::mutex> lock(mVirtioGpuFencesMutex);
742 
743     auto [fenceIt, fenceCreated] = mVirtioGpuFences.emplace(fenceId, EmulatedFence{});
744     if (!fenceCreated) {
745         ALOGE("Attempting to recreate fence %" PRIu32, fenceId);
746     }
747 
748     auto& fenceInfo = fenceIt->second;
749     fenceInfo.waitable = fenceInfo.signaler.get_future();
750 
751     return fenceId;
752 }
753 
EnqueueVirtioGpuTask(uint32_t contextId,VirtioGpuTask task,std::optional<VirtioGpuFence> fence)754 std::shared_future<void> EmulatedVirtioGpu::EmulatedVirtioGpuImpl::EnqueueVirtioGpuTask(
755     uint32_t contextId, VirtioGpuTask task, std::optional<VirtioGpuFence> fence) {
756     std::promise<void> taskCompletedSignaler;
757     std::shared_future<void> taskCompletedWaitable(taskCompletedSignaler.get_future());
758 
759     std::lock_guard<std::mutex> lock(mTasksMutex);
760     mTasks.push(VirtioGpuTaskWithWaitable{
761         .contextId = contextId,
762         .task = std::move(task),
763         .taskCompletedSignaler = std::move(taskCompletedSignaler),
764         .fence = fence,
765     });
766 
767     return taskCompletedWaitable;
768 }
769 
DoTask(VirtioGpuTaskContextAttachResource task)770 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskContextAttachResource task) {
771     ALOGV("Performing task to attach resource-id:%d to context-id:%d", task.resourceId,
772           task.contextId);
773 
774     rutabaga_context_attach_resource(mRutabaga, task.contextId, task.resourceId);
775 
776     ALOGV("Performing task to attach resource-id:%d to context-id:%d - done", task.resourceId,
777           task.contextId);
778 }
779 
DoTask(VirtioGpuTaskContextDetachResource task)780 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskContextDetachResource task) {
781     ALOGV("Performing task to detach resource-id:%d to context-id:%d", task.resourceId,
782           task.contextId);
783 
784     rutabaga_context_detach_resource(mRutabaga, task.contextId, task.resourceId);
785 
786     ALOGV("Performing task to detach resource-id:%d to context-id:%d - done", task.resourceId,
787           task.contextId);
788 }
789 
DoTask(VirtioGpuTaskCreateBlob task)790 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskCreateBlob task) {
791     ALOGV("Performing task to create blob resource-id:%d", task.resourceId);
792 
793     int ret =
794         rutabaga_resource_create_blob(mRutabaga, task.contextId, task.resourceId, &task.params,
795                                       /*iovecs=*/nullptr,
796                                       /*handle=*/nullptr);
797     if (ret) {
798         ALOGE("Failed to create blob.");
799     }
800 
801     ALOGV("Performing task to create blob resource-id:%d - done", task.resourceId);
802 }
803 
DoTask(VirtioGpuTaskCreateContext task)804 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskCreateContext task) {
805     ALOGV("Performing task to create context-id:%" PRIu32 " context-init:%" PRIu32
806           " context-name:%s",
807           task.contextId, task.contextInit, task.contextName.c_str());
808 
809     int ret = rutabaga_context_create(mRutabaga, task.contextId, task.contextName.size(),
810                                       task.contextName.data(), task.contextInit);
811     if (ret) {
812         ALOGE("Failed to create context-id:%" PRIu32 ".", task.contextId);
813         return;
814     }
815 
816     ALOGV("Performing task to create context-id:%" PRIu32 " context-init:%" PRIu32
817           " context-name:%s - done",
818           task.contextId, task.contextInit, task.contextName.c_str());
819 }
820 
DoTask(VirtioGpuTaskCreateResource task)821 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskCreateResource task) {
822     ALOGV("Performing task to create resource resource:%d", task.resourceId);
823 
824     EmulatedResource* resource = GetResource(task.resourceId);
825 
826     int ret = rutabaga_resource_create_3d(mRutabaga, task.resourceId, &task.params);
827     if (ret) {
828         ALOGE("Failed to create resource:%d", task.resourceId);
829     }
830 
831     resource->iovec.iov_base = task.resourceBytes;
832     resource->iovec.iov_len = task.params.width * task.params.height * 4;
833 
834     struct rutabaga_iovecs vecs = {0};
835     vecs.iovecs = &resource->iovec;
836     vecs.num_iovecs = 1;
837 
838     ret = rutabaga_resource_attach_backing(mRutabaga, task.resourceId, &vecs);
839     if (ret) {
840         ALOGE("Failed to attach iov to resource:%d", task.resourceId);
841     }
842 
843     ALOGV("Performing task to create resource resource:%d - done", task.resourceId);
844 
845     rutabaga_context_attach_resource(mRutabaga, task.contextId, task.resourceId);
846 }
847 
DoTask(VirtioGpuTaskDestroyContext task)848 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskDestroyContext task) {
849     ALOGV("Performing task to destroy context-id:%" PRIu32, task.contextId);
850 
851     rutabaga_context_destroy(mRutabaga, task.contextId);
852 
853     ALOGV("Performing task to destroy context-id:%" PRIu32 " - done", task.contextId);
854 }
855 
DoTask(VirtioGpuTaskMap task)856 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskMap task) {
857     ALOGV("Performing task to map resource resource:%d", task.resourceId);
858 
859     struct rutabaga_mapping mapping;
860     int ret = rutabaga_resource_map(mRutabaga, task.resourceId, &mapping);
861     if (ret) {
862         ALOGE("Failed to map resource:%d", task.resourceId);
863         return;
864     }
865 
866     task.resourceMappedPromise.set_value(reinterpret_cast<uint8_t*>(mapping.ptr));
867     ALOGV("Performing task to map resource resource:%d - done", task.resourceId);
868 }
869 
DoTask(VirtioGpuTaskUnmap task)870 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskUnmap task) {
871     ALOGV("Performing task to unmap resource resource:%d", task.resourceId);
872     rutabaga_resource_unmap(mRutabaga, task.resourceId);
873     ALOGV("Performing task to unmap resource:%d - done", task.resourceId);
874 }
875 
DoTask(VirtioGpuTaskSubmitCmd task)876 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskSubmitCmd task) {
877     ALOGV("Performing task to execbuffer");
878 
879     if (task.commandBuffer.size() % 4 != 0) {
880         ALOGE("Unaligned command buffer?");
881         return;
882     }
883 
884     struct rutabaga_command cmd = {
885         .ctx_id = task.contextId,
886         .cmd_size = static_cast<uint32_t>(task.commandBuffer.size()),
887         .cmd = reinterpret_cast<uint8_t*>(task.commandBuffer.data()),
888         .num_in_fences = 0,
889         .fence_ids = nullptr,
890     };
891 
892     int ret = rutabaga_submit_command(mRutabaga, &cmd);
893     if (ret) {
894         ALOGE("Failed to execbuffer.");
895     }
896 
897     ALOGV("Performing task to execbuffer - done");
898 }
899 
DoTask(VirtioGpuTaskTransferFromHost task)900 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskTransferFromHost task) {
901     struct rutabaga_transfer transfer = {0};
902     transfer.x = task.x;
903     transfer.y = task.y;
904     transfer.z = 0;
905     transfer.w = task.w;
906     transfer.h = task.h;
907     transfer.d = 1;
908 
909     int ret = rutabaga_resource_transfer_read(mRutabaga, task.contextId, task.resourceId, &transfer,
910                                               nullptr);
911     if (ret) {
912         ALOGE("Failed to transferFromHost() for resource:%" PRIu32, task.resourceId);
913     }
914 }
915 
DoTask(VirtioGpuTaskTransferToHost task)916 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskTransferToHost task) {
917     struct rutabaga_transfer transfer = {0};
918     transfer.x = task.x;
919     transfer.y = task.y;
920     transfer.z = 0;
921     transfer.w = task.w;
922     transfer.h = task.h;
923     transfer.d = 1;
924 
925     int ret =
926         rutabaga_resource_transfer_write(mRutabaga, task.contextId, task.resourceId, &transfer);
927     if (ret) {
928         ALOGE("Failed to transferToHost() for resource:%" PRIu32, task.resourceId);
929     }
930 }
931 
DoTask(VirtioGpuTaskUnrefResource task)932 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskUnrefResource task) {
933     rutabaga_resource_unref(mRutabaga, task.resourceId);
934 }
935 
DoTask(VirtioGpuTaskSnapshotSave task)936 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskSnapshotSave task) {
937     int ret = rutabaga_snapshot(mRutabaga, task.directory.c_str());
938     if (ret) {
939         ALOGE("snapshotting failed");
940     }
941 }
942 
DoTask(VirtioGpuTaskSnapshotRestore task)943 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskSnapshotRestore task) {
944     int ret = rutabaga_restore(mRutabaga, task.directory.c_str());
945     if (ret) {
946         ALOGE("snapshot restore failed");
947     }
948 }
949 
DoTask(VirtioGpuTaskWithWaitable task)950 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::DoTask(VirtioGpuTaskWithWaitable task) {
951     std::visit(
952         [this](auto&& work) {
953             using T = std::decay_t<decltype(work)>;
954             if constexpr (std::is_same_v<T, VirtioGpuTaskContextAttachResource>) {
955                 DoTask(std::move(work));
956             } else if constexpr (std::is_same_v<T, VirtioGpuTaskContextDetachResource>) {
957                 DoTask(std::move(work));
958             } else if constexpr (std::is_same_v<T, VirtioGpuTaskCreateBlob>) {
959                 DoTask(std::move(work));
960             } else if constexpr (std::is_same_v<T, VirtioGpuTaskCreateContext>) {
961                 DoTask(std::move(work));
962             } else if constexpr (std::is_same_v<T, VirtioGpuTaskCreateResource>) {
963                 DoTask(std::move(work));
964             } else if constexpr (std::is_same_v<T, VirtioGpuTaskDestroyContext>) {
965                 DoTask(std::move(work));
966             } else if constexpr (std::is_same_v<T, VirtioGpuTaskMap>) {
967                 DoTask(std::move(work));
968             } else if constexpr (std::is_same_v<T, VirtioGpuTaskUnmap>) {
969                 DoTask(std::move(work));
970             } else if constexpr (std::is_same_v<T, VirtioGpuTaskSubmitCmd>) {
971                 DoTask(std::move(work));
972             } else if constexpr (std::is_same_v<T, VirtioGpuTaskTransferFromHost>) {
973                 DoTask(std::move(work));
974             } else if constexpr (std::is_same_v<T, VirtioGpuTaskTransferToHost>) {
975                 DoTask(std::move(work));
976             } else if constexpr (std::is_same_v<T, VirtioGpuTaskUnrefResource>) {
977                 DoTask(std::move(work));
978             } else if constexpr (std::is_same_v<T, VirtioGpuTaskSnapshotSave>) {
979                 DoTask(std::move(work));
980             } else if constexpr (std::is_same_v<T, VirtioGpuTaskSnapshotRestore>) {
981                 DoTask(std::move(work));
982             }
983         },
984         task.task);
985 
986     if (task.fence) {
987         const struct rutabaga_fence fenceInfo = {
988             .flags = RUTABAGA_FLAG_INFO_RING_IDX,
989             .fence_id = (*task.fence).fenceId,
990             .ctx_id = task.contextId,
991             .ring_idx = (*task.fence).ringIdx,
992         };
993         int ret = rutabaga_create_fence(mRutabaga, &fenceInfo);
994         if (ret) {
995             ALOGE("Failed to create fence.");
996         }
997     }
998 
999     task.taskCompletedSignaler.set_value();
1000 }
1001 
RunVirtioGpuTaskProcessingLoop()1002 void EmulatedVirtioGpu::EmulatedVirtioGpuImpl::RunVirtioGpuTaskProcessingLoop() {
1003     while (!mShuttingDown.load()) {
1004         std::optional<VirtioGpuTaskWithWaitable> task;
1005 
1006         {
1007             std::lock_guard<std::mutex> lock(mTasksMutex);
1008             if (!mTasks.empty()) {
1009                 task = std::move(mTasks.front());
1010                 mTasks.pop();
1011             }
1012         }
1013 
1014         if (task) {
1015             DoTask(std::move(*task));
1016         }
1017     }
1018 }
1019 
EmulatedVirtioGpu()1020 EmulatedVirtioGpu::EmulatedVirtioGpu()
1021     : mImpl{std::make_unique<EmulatedVirtioGpu::EmulatedVirtioGpuImpl>()} {}
1022 
1023 namespace {
1024 
1025 static std::mutex sInstanceMutex;
1026 static std::weak_ptr<EmulatedVirtioGpu> sInstance;
1027 
1028 }  // namespace
1029 
1030 /*static*/
Get()1031 std::shared_ptr<EmulatedVirtioGpu> EmulatedVirtioGpu::Get() {
1032     std::lock_guard<std::mutex> lock(sInstanceMutex);
1033 
1034     std::shared_ptr<EmulatedVirtioGpu> instance = sInstance.lock();
1035     if (instance != nullptr) {
1036         return instance;
1037     }
1038 
1039     instance = std::shared_ptr<EmulatedVirtioGpu>(new EmulatedVirtioGpu());
1040 
1041     bool withGl = false;
1042     bool withVk = false;
1043     std::string features;
1044 
1045     struct BoolOption {
1046         std::string env;
1047         bool* val;
1048     };
1049     const std::vector<BoolOption> options = {
1050         {"GFXSTREAM_EMULATED_VIRTIO_GPU_WITH_GL", &withGl},
1051         {"GFXSTREAM_EMULATED_VIRTIO_GPU_WITH_VK", &withVk},
1052     };
1053     for (const BoolOption& option : options) {
1054         const char* val = std::getenv(option.env.c_str());
1055         if (val != nullptr && (val[0] == 'Y' || val[0] == 'y')) {
1056             *option.val = true;
1057         }
1058     }
1059 
1060     struct StringOption {
1061         std::string env;
1062         std::string* val;
1063     };
1064     const std::vector<StringOption> stringOptions = {
1065         {"GFXSTREAM_EMULATED_VIRTIO_GPU_RENDERER_FEATURES", &features},
1066     };
1067     for (const StringOption& option : stringOptions) {
1068         const char* val = std::getenv(option.env.c_str());
1069         if (val != nullptr) {
1070             *option.val = std::string(val);
1071         }
1072     }
1073 
1074     ALOGE("Initializing withGl:%d withVk:%d features:%s", withGl, withVk, features.c_str());
1075     if (!instance->Init(withGl, withVk, features)) {
1076         ALOGE("Failed to initialize EmulatedVirtioGpu.");
1077         return nullptr;
1078     }
1079     ALOGE("Successfully initialized EmulatedVirtioGpu.");
1080     sInstance = instance;
1081     return instance;
1082 }
1083 
1084 /*static*/
GetNumActiveUsers()1085 uint32_t EmulatedVirtioGpu::GetNumActiveUsers() {
1086     std::lock_guard<std::mutex> lock(sInstanceMutex);
1087     std::shared_ptr<EmulatedVirtioGpu> instance = sInstance.lock();
1088     return instance.use_count();
1089 }
1090 
Init(bool withGl,bool withVk,const std::string & features)1091 bool EmulatedVirtioGpu::Init(bool withGl, bool withVk, const std::string& features) {
1092     return mImpl->Init(withGl, withVk, features, this);
1093 }
1094 
CreateContext(uint32_t contextInit)1095 std::optional<uint32_t> EmulatedVirtioGpu::CreateContext(uint32_t contextInit) {
1096     return mImpl->CreateContext(contextInit);
1097 }
1098 
DestroyContext(uint32_t contextId)1099 void EmulatedVirtioGpu::DestroyContext(uint32_t contextId) { mImpl->DestroyContext(contextId); }
1100 
GetCaps(uint32_t capsetId,uint32_t guestCapsSize,uint8_t * capset)1101 bool EmulatedVirtioGpu::GetCaps(uint32_t capsetId, uint32_t guestCapsSize, uint8_t* capset) {
1102     return mImpl->GetCaps(capsetId, guestCapsSize, capset);
1103 }
1104 
Map(uint32_t resourceId)1105 uint8_t* EmulatedVirtioGpu::Map(uint32_t resourceId) { return mImpl->Map(resourceId); }
1106 
Unmap(uint32_t resourceId)1107 void EmulatedVirtioGpu::Unmap(uint32_t resourceId) { mImpl->Unmap(resourceId); }
1108 
SubmitCmd(uint32_t contextId,uint32_t cmdSize,void * cmd,uint32_t ringIdx,VirtioGpuFenceFlags fenceFlags,uint32_t & fenceId,std::optional<uint32_t> blobResourceId)1109 int EmulatedVirtioGpu::SubmitCmd(uint32_t contextId, uint32_t cmdSize, void* cmd, uint32_t ringIdx,
1110                                  VirtioGpuFenceFlags fenceFlags, uint32_t& fenceId,
1111                                  std::optional<uint32_t> blobResourceId) {
1112     return mImpl->SubmitCmd(contextId, cmdSize, cmd, ringIdx, fenceFlags, fenceId, blobResourceId);
1113 }
1114 
Wait(uint32_t resourceId)1115 int EmulatedVirtioGpu::Wait(uint32_t resourceId) { return mImpl->Wait(resourceId); }
1116 
TransferFromHost(uint32_t contextId,uint32_t resourceId,uint32_t offset,uint32_t size)1117 int EmulatedVirtioGpu::TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t offset,
1118                                         uint32_t size) {
1119     return mImpl->TransferFromHost(contextId, resourceId, offset, size);
1120 }
1121 
TransferFromHost(uint32_t contextId,uint32_t resourceId,uint32_t x,uint32_t y,uint32_t w,uint32_t h)1122 int EmulatedVirtioGpu::TransferFromHost(uint32_t contextId, uint32_t resourceId, uint32_t x,
1123                                         uint32_t y, uint32_t w, uint32_t h) {
1124     return mImpl->TransferFromHost(contextId, resourceId, x, y, w, h);
1125 }
1126 
TransferToHost(uint32_t contextId,uint32_t resourceId,uint32_t offset,uint32_t size)1127 int EmulatedVirtioGpu::TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t offset,
1128                                       uint32_t size) {
1129     return mImpl->TransferToHost(contextId, resourceId, offset, size);
1130 }
1131 
TransferToHost(uint32_t contextId,uint32_t resourceId,uint32_t x,uint32_t y,uint32_t w,uint32_t h)1132 int EmulatedVirtioGpu::TransferToHost(uint32_t contextId, uint32_t resourceId, uint32_t x,
1133                                       uint32_t y, uint32_t w, uint32_t h) {
1134     return mImpl->TransferToHost(contextId, resourceId, x, y, w, h);
1135 }
1136 
CreateBlob(uint32_t contextId,uint32_t blobMem,uint32_t blobFlags,uint64_t blobId,uint64_t blobSize)1137 std::optional<uint32_t> EmulatedVirtioGpu::CreateBlob(uint32_t contextId, uint32_t blobMem,
1138                                                       uint32_t blobFlags, uint64_t blobId,
1139                                                       uint64_t blobSize) {
1140     return mImpl->CreateBlob(contextId, blobMem, blobFlags, blobId, blobSize);
1141 }
1142 
CreateVirglBlob(uint32_t contextId,uint32_t width,uint32_t height,uint32_t virglFormat,uint32_t target,uint32_t bind,uint32_t size)1143 std::optional<uint32_t> EmulatedVirtioGpu::CreateVirglBlob(uint32_t contextId, uint32_t width,
1144                                                            uint32_t height, uint32_t virglFormat,
1145                                                            uint32_t target, uint32_t bind,
1146                                                            uint32_t size) {
1147     return mImpl->CreateVirglBlob(contextId, width, height, virglFormat, target, bind, size);
1148 }
1149 
DestroyResource(uint32_t contextId,uint32_t resourceId)1150 void EmulatedVirtioGpu::DestroyResource(uint32_t contextId, uint32_t resourceId) {
1151     mImpl->DestroyResource(contextId, resourceId);
1152 }
1153 
SnapshotSave(const std::string & directory)1154 void EmulatedVirtioGpu::SnapshotSave(const std::string& directory) {
1155     mImpl->SnapshotSave(directory);
1156 }
1157 
SnapshotRestore(const std::string & directory)1158 void EmulatedVirtioGpu::SnapshotRestore(const std::string& directory) {
1159     mImpl->SnapshotRestore(directory);
1160 }
1161 
WaitOnEmulatedFence(int fenceAsFileDescriptor,int timeoutMilliseconds)1162 int EmulatedVirtioGpu::WaitOnEmulatedFence(int fenceAsFileDescriptor, int timeoutMilliseconds) {
1163     return mImpl->WaitOnEmulatedFence(fenceAsFileDescriptor, timeoutMilliseconds);
1164 }
1165 
SignalEmulatedFence(int fenceId)1166 void EmulatedVirtioGpu::SignalEmulatedFence(int fenceId) { mImpl->SignalEmulatedFence(fenceId); }
1167 
GetNumActiveEmulatedVirtioGpuUsers()1168 bool GetNumActiveEmulatedVirtioGpuUsers() { return EmulatedVirtioGpu::GetNumActiveUsers(); }
1169 
1170 }  // namespace gfxstream
1171