1 // Copyright (C) 2024 The Android Open Source Project
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 "VirtioGpuRingBlob.h"
16
17 #include <string>
18
19 #include "gfxstream/virtio-gpu-gfxstream-renderer.h"
20
21 namespace gfxstream {
22 namespace host {
23
24 using android::base::SharedMemory;
25
RingBlob(uint32_t id,uint64_t size,uint64_t alignment,std::variant<std::unique_ptr<AlignedMemory>,std::unique_ptr<SharedMemory>> memory)26 RingBlob::RingBlob(uint32_t id,
27 uint64_t size,
28 uint64_t alignment,
29 std::variant<std::unique_ptr<AlignedMemory>, std::unique_ptr<SharedMemory>> memory) :
30 mId(id), mSize(size), mAlignment(alignment), mMemory(std::move(memory)) {}
31
isExportable() const32 bool RingBlob::isExportable() const {
33 return std::holds_alternative<std::unique_ptr<SharedMemory>>(mMemory);
34 }
35
releaseHandle()36 android::base::SharedMemory::handle_type RingBlob::releaseHandle() {
37 if (!isExportable()) {
38 return SharedMemory::invalidHandle();
39 }
40 return std::get<std::unique_ptr<SharedMemory>>(mMemory)->releaseHandle();
41 }
42
map()43 void* RingBlob::map() {
44 if (std::holds_alternative<std::unique_ptr<AlignedMemory>>(mMemory)) {
45 return std::get<std::unique_ptr<AlignedMemory>>(mMemory)->addr;
46 } else {
47 return std::get<std::unique_ptr<SharedMemory>>(mMemory)->get();
48 }
49 }
50
51 /*static*/
CreateWithShmem(uint32_t id,uint64_t size)52 std::unique_ptr<RingBlob> RingBlob::CreateWithShmem(uint32_t id, uint64_t size) {
53 const std::string name = "gfxstream-ringblob-shmem-" + std::to_string(id);
54
55 auto shmem = std::make_unique<SharedMemory>(name, size);
56 int ret = shmem->create(0600);
57 if (ret) {
58 stream_renderer_error("Failed to allocate ring blob shared memory.");
59 return nullptr;
60 }
61
62 return std::unique_ptr<RingBlob>(new RingBlob(id, size, 1, std::move(shmem)));
63 }
64
65 /*static*/
CreateWithHostMemory(uint32_t id,uint64_t size,uint64_t alignment)66 std::unique_ptr<RingBlob> RingBlob::CreateWithHostMemory(uint32_t id, uint64_t size, uint64_t alignment) {
67 auto memory = std::make_unique<AlignedMemory>(alignment, size);
68 if (memory->addr == nullptr) {
69 stream_renderer_error("Failed to allocate ring blob host memory.");
70 return nullptr;
71 }
72
73 return std::unique_ptr<RingBlob>(new RingBlob(id, size, alignment, std::move(memory)));
74 }
75
76 #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT
77
78 using gfxstream::host::snapshot::VirtioGpuRingBlobSnapshot;
79
Snapshot()80 std::optional<VirtioGpuRingBlobSnapshot> RingBlob::Snapshot() {
81 VirtioGpuRingBlobSnapshot snapshot;
82
83 snapshot.set_id(mId);
84 snapshot.set_size(mSize);
85 snapshot.set_alignment(mAlignment);
86 if (std::holds_alternative<std::unique_ptr<SharedMemory>>(mMemory)) {
87 snapshot.set_type(VirtioGpuRingBlobSnapshot::TYPE_SHARED_MEMORY);
88 } else {
89 snapshot.set_type(VirtioGpuRingBlobSnapshot::TYPE_HOST_MEMORY);
90 }
91
92 void* mapped = map();
93 if (!mapped) {
94 stream_renderer_error("Failed to map ring blob memory for snapshot.");
95 return std::nullopt;
96 }
97 snapshot.set_memory(mapped, mSize);
98
99 return snapshot;
100 }
101
Restore(const VirtioGpuRingBlobSnapshot & snapshot)102 /*static*/ std::optional<std::unique_ptr<RingBlob>> RingBlob::Restore(
103 const VirtioGpuRingBlobSnapshot& snapshot) {
104
105 std::unique_ptr<RingBlob> resource;
106 if (snapshot.type() == VirtioGpuRingBlobSnapshot::TYPE_SHARED_MEMORY) {
107 resource = RingBlob::CreateWithShmem(snapshot.id(), snapshot.size());
108 } else {
109 resource = RingBlob::CreateWithHostMemory(snapshot.id(), snapshot.size(), snapshot.alignment());
110 }
111 if (!resource) {
112 return std::nullopt;
113 }
114
115 void* mapped = resource->map();
116 if (!mapped) {
117 stream_renderer_error("Failed to map ring blob memory for restore.");
118 return std::nullopt;
119 }
120
121 std::memcpy(mapped, snapshot.memory().c_str(), snapshot.memory().size());
122
123 return resource;
124 }
125
126 #endif
127
128 } // namespace host
129 } // namespace gfxstream