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