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 <log/log.h>
18 
19 #include "RutabagaLayer.h"
20 #include "RutabagaVirtGpu.h"
21 
22 namespace gfxstream {
23 
RutabagaVirtGpuDevice(std::shared_ptr<EmulatedVirtioGpu> emulation,VirtGpuCapset capset)24 RutabagaVirtGpuDevice::RutabagaVirtGpuDevice(std::shared_ptr<EmulatedVirtioGpu> emulation,
25                                              VirtGpuCapset capset)
26     : VirtGpuDevice(capset), mEmulation(emulation), mCapset(capset) {}
27 
~RutabagaVirtGpuDevice()28 RutabagaVirtGpuDevice::~RutabagaVirtGpuDevice() { mEmulation->DestroyContext(mContextId); }
29 
Init()30 bool RutabagaVirtGpuDevice::Init() {
31     uint32_t capsetId = 0;
32     uint32_t capsetSize = 0;
33     uint32_t contextInit = 0;
34     uint8_t* capsetPtr = nullptr;
35 
36     mCaps = {
37         .params =
38             {
39                 [kParam3D] = 1,
40                 [kParamCapsetFix] = 1,
41                 [kParamResourceBlob] = 1,
42                 [kParamHostVisible] = 1,
43                 [kParamCrossDevice] = 0,
44                 [kParamContextInit] = 1,
45                 [kParamSupportedCapsetIds] = 0,
46                 [kParamExplicitDebugName] = 0,
47                 [kParamCreateGuestHandle] = 0,
48             },
49     };
50 
51     capsetId = static_cast<uint32_t>(mCapset);
52     switch (mCapset) {
53         case kCapsetGfxStreamVulkan:
54             capsetSize = sizeof(struct vulkanCapset);
55             capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.vulkanCapset);
56             break;
57         case kCapsetGfxStreamMagma:
58             capsetSize = sizeof(struct magmaCapset);
59             capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.magmaCapset);
60             break;
61         case kCapsetGfxStreamGles:
62             capsetSize = sizeof(struct vulkanCapset);
63             capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.glesCapset);
64             break;
65         case kCapsetGfxStreamComposer:
66             capsetSize = sizeof(struct vulkanCapset);
67             capsetPtr = reinterpret_cast<uint8_t*>(&mCaps.composerCapset);
68             break;
69         default:
70             capsetSize = 0;
71     }
72 
73     if (capsetId != 0) {
74         bool success = mEmulation->GetCaps(capsetId, capsetSize, capsetPtr);
75         if (!success) {
76             ALOGE("Failed to capability set");
77             return false;
78         }
79     }
80 
81     const auto contextIdOp = mEmulation->CreateContext(capsetId);
82     if (!contextIdOp) {
83         ALOGE("Failed to create RutabagaVirtGpuDevice: failed to create context.");
84         return false;
85     }
86 
87     mContextId = *contextIdOp;
88     return true;
89 }
90 
getDeviceHandle()91 int64_t RutabagaVirtGpuDevice::getDeviceHandle() { return -1; }
92 
getCaps()93 VirtGpuCaps RutabagaVirtGpuDevice::getCaps() { return mCaps; }
94 
createBlob(const struct VirtGpuCreateBlob & blobCreate)95 VirtGpuResourcePtr RutabagaVirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
96     const auto resourceIdOpt = mEmulation->CreateBlob(
97         mContextId, static_cast<uint32_t>(blobCreate.blobMem),
98         static_cast<uint32_t>(blobCreate.flags), blobCreate.blobId, blobCreate.size);
99     if (!resourceIdOpt) {
100         return nullptr;
101     }
102 
103     return VirtGpuResourcePtr(new RutabagaVirtGpuResource(
104         mEmulation, *resourceIdOpt, RutabagaVirtGpuResource::ResourceType::kBlob, mContextId));
105 }
106 
createResource(uint32_t width,uint32_t height,uint32_t stride,uint32_t virglFormat,uint32_t target,uint32_t bind)107 VirtGpuResourcePtr RutabagaVirtGpuDevice::createResource(uint32_t width, uint32_t height,
108                                                          uint32_t stride, uint32_t virglFormat,
109                                                          uint32_t target, uint32_t bind) {
110     uint32_t size = stride * height;
111 
112     const auto resourceIdOpt =
113         mEmulation->CreateVirglBlob(mContextId, width, height, virglFormat, target, bind, size);
114     if (!resourceIdOpt) {
115         return nullptr;
116     }
117 
118     return VirtGpuResourcePtr(new RutabagaVirtGpuResource(
119         mEmulation, *resourceIdOpt, RutabagaVirtGpuResource::ResourceType::kPipe, mContextId));
120 }
121 
execBuffer(struct VirtGpuExecBuffer & execbuffer,const VirtGpuResource * blob)122 int RutabagaVirtGpuDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer,
123                                       const VirtGpuResource* blob) {
124     std::optional<uint32_t> blobResourceId;
125     uint32_t fenceId = 0;
126     VirtioGpuFenceFlags fenceFlags = kFlagNone;
127 
128     if (blob) {
129         blobResourceId = blob->getResourceHandle();
130     }
131 
132     if (execbuffer.flags & kFenceOut) {
133         fenceFlags = kFlagFence;
134     }
135 
136     int ret = mEmulation->SubmitCmd(mContextId, execbuffer.command_size, execbuffer.command,
137                                     execbuffer.ring_idx, fenceFlags, fenceId, blobResourceId);
138 
139     if (execbuffer.flags & kFenceOut) {
140         execbuffer.handle.osHandle = fenceId;
141         execbuffer.handle.type = kFenceHandleSyncFd;
142     }
143 
144     return ret;
145 }
146 
importBlob(const struct VirtGpuExternalHandle &)147 VirtGpuResourcePtr RutabagaVirtGpuDevice::importBlob(const struct VirtGpuExternalHandle&) {
148     ALOGE("Unimplemented %s", __FUNCTION__);
149     return nullptr;
150 }
151 
152 }  // namespace gfxstream
153 
createPlatformVirtGpuDevice(enum VirtGpuCapset capset,int)154 VirtGpuDevice* createPlatformVirtGpuDevice(enum VirtGpuCapset capset, int) {
155     std::shared_ptr<gfxstream::EmulatedVirtioGpu> emulation = gfxstream::EmulatedVirtioGpu::Get();
156     if (!emulation) {
157         ALOGE("Failed to create RutabagaVirtGpuDevice: failed to get emulation layer.");
158         return nullptr;
159     }
160 
161     auto device = new gfxstream::RutabagaVirtGpuDevice(emulation, capset);
162     bool success = device->Init();
163     if (!success) {
164         ALOGE("Failed to create RutabagaVirtGpuDevice: Init failed.");
165         delete device;
166         return nullptr;
167     }
168 
169     return device;
170 }
171