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 "VirtioGpuContext.h"
16
17 #include "host-common/AddressSpaceService.h"
18 #include "host-common/opengles.h"
19
20 namespace gfxstream {
21 namespace host {
22
23 /*static*/
Create(const GoldfishPipeServiceOps * ops,VirtioGpuContextId contextId,const std::string & contextName,uint32_t capsetId)24 std::optional<VirtioGpuContext> VirtioGpuContext::Create(const GoldfishPipeServiceOps* ops,
25 VirtioGpuContextId contextId,
26 const std::string& contextName,
27 uint32_t capsetId) {
28 VirtioGpuContext context = {};
29 context.mId = contextId;
30 context.mName = contextName;
31 context.mCapsetId = capsetId;
32
33 auto hostPipe = ops->guest_open_with_flags(reinterpret_cast<GoldfishHwPipe*>(contextId),
34 0x1 /* is virtio */);
35 if (!hostPipe) {
36 stream_renderer_error("failed to create context %u: failed to create pipe.", contextId);
37 return std::nullopt;
38 }
39 stream_renderer_debug("created initial pipe for context %u: %p", contextId, hostPipe);
40 context.mHostPipe = hostPipe;
41
42 android_onGuestGraphicsProcessCreate(contextId);
43
44 return context;
45 }
46
Destroy(const GoldfishPipeServiceOps * pipeOps,const struct address_space_device_control_ops * asgOps)47 int VirtioGpuContext::Destroy(const GoldfishPipeServiceOps* pipeOps,
48 const struct address_space_device_control_ops* asgOps) {
49 for (const auto& [_, handle] : mAddressSpaceHandles) {
50 // Note: this can hang as is but this has only been observed to
51 // happen during shutdown. See b/329287602#comment8.
52 asgOps->destroy_handle(handle);
53 }
54
55 if (!mHostPipe) {
56 stream_renderer_error("failed to destroy context %u: missing pipe?", mId);
57 return -EINVAL;
58 }
59 pipeOps->guest_close(mHostPipe, GOLDFISH_PIPE_CLOSE_GRACEFUL);
60
61 android_cleanupProcGLObjects(mId);
62
63 return 0;
64 }
65
AttachResource(VirtioGpuResource & resource)66 void VirtioGpuContext::AttachResource(VirtioGpuResource& resource) {
67 // Associate the host pipe of the resource entry with the host pipe of
68 // the context entry. That is, the last context to call attachResource
69 // wins if there is any conflict.
70 resource.AttachToContext(mId);
71 resource.SetHostPipe(mHostPipe);
72
73 mAttachedResources.insert(resource.GetId());
74 }
75
DetachResource(VirtioGpuResource & resource)76 void VirtioGpuContext::DetachResource(VirtioGpuResource& resource) {
77 mAttachedResources.erase(resource.GetId());
78 resource.DetachFromContext(mId);
79 }
80
GetAttachedResources() const81 const std::unordered_set<VirtioGpuResourceId>& VirtioGpuContext::GetAttachedResources() const {
82 return mAttachedResources;
83 }
84
SetHostPipe(GoldfishHostPipe * pipe)85 void VirtioGpuContext::SetHostPipe(GoldfishHostPipe* pipe) { mHostPipe = pipe; }
86
AcquireSync(uint64_t syncId)87 int VirtioGpuContext::AcquireSync(uint64_t syncId) {
88 if (mLatestSync) {
89 stream_renderer_error(
90 "failed to acquire sync %" PRIu64 " on context %u: sync already present?", syncId, mId);
91 return -EINVAL;
92 }
93
94 auto descriptorOpt = ExternalObjectManager::get()->removeSyncDescriptorInfo(mId, syncId);
95 if (!descriptorOpt) {
96 stream_renderer_error("failed to acquire sync %" PRIu64 " on context %u: sync not found.",
97 syncId, mId);
98 return -EINVAL;
99 }
100
101 mLatestSync = std::move(*descriptorOpt);
102 return 0;
103 }
104
TakeSync()105 std::optional<SyncDescriptorInfo> VirtioGpuContext::TakeSync() {
106 if (!mLatestSync) {
107 return std::nullopt;
108 }
109
110 auto info = std::move(*mLatestSync);
111 mLatestSync.reset();
112 return std::move(info);
113 }
114
CreateAddressSpaceGraphicsInstance(const struct address_space_device_control_ops * asgOps,VirtioGpuResource & resource)115 int VirtioGpuContext::CreateAddressSpaceGraphicsInstance(
116 const struct address_space_device_control_ops* asgOps, VirtioGpuResource& resource) {
117 const VirtioGpuResourceId resourceId = resource.GetId();
118
119 void* resourceHva = nullptr;
120 uint64_t resourceHvaSize = 0;
121 if (resource.Map(&resourceHva, &resourceHvaSize) != 0) {
122 stream_renderer_error(
123 "failed to create ASG instance on context %d: failed to map resource %u", mId,
124 resourceId);
125 return -EINVAL;
126 }
127
128 const std::string asgName = mName + "-" + std::to_string(resourceId);
129
130 // Note: resource ids can not be used as ASG handles because ASGs may outlive the
131 // containing resource due asynchronous ASG destruction.
132 const uint32_t asgId = asgOps->gen_handle();
133
134 struct AddressSpaceCreateInfo createInfo = {
135 .handle = asgId,
136 .type = android::emulation::VirtioGpuGraphics,
137 .createRenderThread = true,
138 .externalAddr = resourceHva,
139 .externalAddrSize = resourceHvaSize,
140 .virtioGpuContextId = mId,
141 .virtioGpuCapsetId = mCapsetId,
142 .contextName = asgName.c_str(),
143 .contextNameSize = static_cast<uint32_t>(asgName.size()),
144 };
145 asgOps->create_instance(createInfo);
146
147 mAddressSpaceHandles[resourceId] = asgId;
148 return 0;
149 }
150
AsgInstances() const151 const std::unordered_map<VirtioGpuResourceId, uint32_t>& VirtioGpuContext::AsgInstances() const {
152 return mAddressSpaceHandles;
153 }
154
TakeAddressSpaceGraphicsHandle(VirtioGpuResourceId resourceId)155 std::optional<uint32_t> VirtioGpuContext::TakeAddressSpaceGraphicsHandle(
156 VirtioGpuResourceId resourceId) {
157 auto asgIt = mAddressSpaceHandles.find(resourceId);
158 if (asgIt == mAddressSpaceHandles.end()) {
159 return std::nullopt;
160 }
161
162 auto asgId = asgIt->second;
163 mAddressSpaceHandles.erase(asgIt);
164 return asgId;
165 }
166
PingAddressSpaceGraphicsInstance(const struct address_space_device_control_ops * asgOps,VirtioGpuResourceId resourceId)167 int VirtioGpuContext::PingAddressSpaceGraphicsInstance(
168 const struct address_space_device_control_ops* asgOps, VirtioGpuResourceId resourceId) {
169 auto asgIt = mAddressSpaceHandles.find(resourceId);
170 if (asgIt == mAddressSpaceHandles.end()) {
171 stream_renderer_error(
172 "failed to ping ASG instance on context %u resource %d: ASG not found.", mId,
173 resourceId);
174 return -EINVAL;
175 }
176 auto asgId = asgIt->second;
177
178 struct android::emulation::AddressSpaceDevicePingInfo ping = {0};
179 ping.metadata = ASG_NOTIFY_AVAILABLE;
180 asgOps->ping_at_hva(asgId, &ping);
181
182 return 0;
183 }
184
AddPendingBlob(uint32_t blobId,struct stream_renderer_resource_create_args blobArgs)185 int VirtioGpuContext::AddPendingBlob(uint32_t blobId,
186 struct stream_renderer_resource_create_args blobArgs) {
187 auto [_, inserted] = mPendingBlobs.try_emplace(blobId, blobArgs);
188 if (!inserted) {
189 stream_renderer_error(
190 "failed to add pending blob %u to context %u: blob ID already in use?", blobId, mId);
191 return -EINVAL;
192 }
193 return 0;
194 }
195
TakePendingBlob(uint32_t blobId)196 std::optional<struct stream_renderer_resource_create_args> VirtioGpuContext::TakePendingBlob(
197 uint32_t blobId) {
198 auto it = mPendingBlobs.find(blobId);
199 if (it == mPendingBlobs.end()) {
200 return std::nullopt;
201 }
202
203 auto args = it->second;
204 mPendingBlobs.erase(it);
205 return args;
206 }
207
208 #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT
209
210 using gfxstream::host::snapshot::VirtioGpuContextSnapshot;
211
Snapshot() const212 std::optional<VirtioGpuContextSnapshot> VirtioGpuContext::Snapshot() const {
213 VirtioGpuContextSnapshot contextSnapshot;
214 contextSnapshot.set_id(mId);
215 contextSnapshot.set_name(mName);
216 contextSnapshot.set_capset(mCapsetId);
217 contextSnapshot.mutable_attached_resources()->Add(mAttachedResources.begin(),
218 mAttachedResources.end());
219 contextSnapshot.mutable_resource_asgs()->insert(mAddressSpaceHandles.begin(),
220 mAddressSpaceHandles.end());
221 return contextSnapshot;
222 }
223
224 /*static*/
Restore(const VirtioGpuContextSnapshot & contextSnapshot)225 std::optional<VirtioGpuContext> VirtioGpuContext::Restore(
226 const VirtioGpuContextSnapshot& contextSnapshot) {
227 VirtioGpuContext context = {};
228 context.mId = contextSnapshot.id();
229 context.mName = contextSnapshot.name();
230 context.mCapsetId = contextSnapshot.capset();
231 context.mAttachedResources.insert(contextSnapshot.attached_resources().begin(),
232 contextSnapshot.attached_resources().end());
233 context.mAddressSpaceHandles.insert(contextSnapshot.resource_asgs().begin(),
234 contextSnapshot.resource_asgs().end());
235 return context;
236 }
237
238 #endif
239
240 } // namespace host
241 } // namespace gfxstream