1 // Copyright 2023 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 "VirtioGpuAddressSpaceStream.h"
16 
17 #include "util.h"
18 
GetRingParamsFromCapset(enum VirtGpuCapset capset,const VirtGpuCaps & caps,uint32_t & ringSize,uint32_t & bufferSize,uint32_t & blobAlignment)19 static bool GetRingParamsFromCapset(enum VirtGpuCapset capset, const VirtGpuCaps& caps,
20                                     uint32_t& ringSize, uint32_t& bufferSize,
21                                     uint32_t& blobAlignment) {
22     switch (capset) {
23         case kCapsetGfxStreamVulkan:
24             ringSize = caps.vulkanCapset.ringSize;
25             bufferSize = caps.vulkanCapset.bufferSize;
26             blobAlignment = caps.vulkanCapset.blobAlignment;
27             break;
28         case kCapsetGfxStreamMagma:
29             ringSize = caps.magmaCapset.ringSize;
30             bufferSize = caps.magmaCapset.bufferSize;
31             blobAlignment = caps.magmaCapset.blobAlignment;
32             break;
33         case kCapsetGfxStreamGles:
34             ringSize = caps.glesCapset.ringSize;
35             bufferSize = caps.glesCapset.bufferSize;
36             blobAlignment = caps.glesCapset.blobAlignment;
37             break;
38         case kCapsetGfxStreamComposer:
39             ringSize = caps.composerCapset.ringSize;
40             bufferSize = caps.composerCapset.bufferSize;
41             blobAlignment = caps.composerCapset.blobAlignment;
42             break;
43         default:
44             return false;
45     }
46 
47     return true;
48 }
49 
virtgpu_address_space_open()50 address_space_handle_t virtgpu_address_space_open() {
51     return (address_space_handle_t)(-EINVAL);
52 }
53 
virtgpu_address_space_close(address_space_handle_t)54 void virtgpu_address_space_close(address_space_handle_t) {
55     // Handle opened by VirtioGpuDevice wrapper
56 }
57 
virtgpu_address_space_ping(address_space_handle_t,struct address_space_ping * info)58 bool virtgpu_address_space_ping(address_space_handle_t, struct address_space_ping* info) {
59     int ret;
60     struct VirtGpuExecBuffer exec = {};
61     VirtGpuDevice* instance = VirtGpuDevice::getInstance();
62     struct gfxstreamContextPing ping = {};
63 
64     ping.hdr.opCode = GFXSTREAM_CONTEXT_PING;
65     ping.resourceId = info->resourceId;
66 
67     exec.command = static_cast<void*>(&ping);
68     exec.command_size = sizeof(ping);
69 
70     ret = instance->execBuffer(exec, nullptr);
71     if (ret)
72         return false;
73 
74     return true;
75 }
76 
createVirtioGpuAddressSpaceStream(enum VirtGpuCapset capset,HealthMonitor<> * healthMonitor)77 AddressSpaceStream* createVirtioGpuAddressSpaceStream(enum VirtGpuCapset capset,
78                                                       HealthMonitor<>* healthMonitor) {
79     VirtGpuResourcePtr pipe, blob;
80     VirtGpuResourceMappingPtr pipeMapping, blobMapping;
81     struct VirtGpuExecBuffer exec = {};
82     struct VirtGpuCreateBlob blobCreate = {};
83     struct gfxstreamContextCreate contextCreate = {};
84 
85     uint32_t ringSize = 0;
86     uint32_t bufferSize = 0;
87     uint32_t blobAlignment = 0;
88 
89     char* blobAddr, *bufferPtr;
90     int ret;
91 
92     VirtGpuDevice* instance = VirtGpuDevice::getInstance();
93     auto caps = instance->getCaps();
94 
95     if (!GetRingParamsFromCapset(capset, caps, ringSize, bufferSize, blobAlignment)) {
96         ALOGE("Failed to get ring parameters");
97         return nullptr;
98     }
99 
100     blobCreate.blobId = 0;
101     blobCreate.blobMem = kBlobMemHost3d;
102     blobCreate.flags = kBlobFlagMappable;
103     blobCreate.size = ALIGN(ringSize + bufferSize, blobAlignment);
104     blob = instance->createBlob(blobCreate);
105     if (!blob)
106         return nullptr;
107 
108     // Context creation command
109     contextCreate.hdr.opCode = GFXSTREAM_CONTEXT_CREATE;
110     contextCreate.resourceId = blob->getResourceHandle();
111 
112     exec.command = static_cast<void*>(&contextCreate);
113     exec.command_size = sizeof(contextCreate);
114 
115     ret = instance->execBuffer(exec, blob.get());
116     if (ret)
117         return nullptr;
118 
119     // Wait occurs on global timeline -- should we use context specific one?
120     ret = blob->wait();
121     if (ret)
122         return nullptr;
123 
124     blobMapping = blob->createMapping();
125     if (!blobMapping)
126         return nullptr;
127 
128     blobAddr = reinterpret_cast<char*>(blobMapping->asRawPtr());
129 
130     bufferPtr = blobAddr + sizeof(struct asg_ring_storage);
131     struct asg_context context = asg_context_create(blobAddr, bufferPtr, bufferSize);
132 
133     context.ring_config->transfer_mode = 1;
134     context.ring_config->host_consumed_pos = 0;
135     context.ring_config->guest_write_pos = 0;
136 
137     struct address_space_ops ops = {
138         .open = virtgpu_address_space_open,
139         .close = virtgpu_address_space_close,
140         .ping = virtgpu_address_space_ping,
141     };
142 
143     AddressSpaceStream* res =
144             new AddressSpaceStream((address_space_handle_t)(-1), 1, context, 0, 0, ops, healthMonitor);
145 
146     res->setMapping(blobMapping);
147     res->setResourceId(contextCreate.resourceId);
148     return res;
149 }
150