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 <cutils/log.h>
18 #include <lib/zx/vmo.h>
19 #include <msd-virtio-gpu/magma-virtio-gpu-defs.h>
20 #include <os_dirent.h>
21 #include <services/service_connector.h>
22
23 #include <climits>
24 #include <cstdio>
25 #include <cstdlib>
26
27 #include "FuchsiaVirtGpu.h"
28
FuchsiaVirtGpuDevice(enum VirtGpuCapset capset,magma_device_t device)29 FuchsiaVirtGpuDevice::FuchsiaVirtGpuDevice(enum VirtGpuCapset capset, magma_device_t device)
30 : VirtGpuDevice(capset), device_(device) {
31 memset(&mCaps, 0, sizeof(struct VirtGpuCaps));
32
33 // Hard-coded values that may be assumed on Fuchsia.
34 mCaps.params[kParam3D] = 1;
35 mCaps.params[kParamCapsetFix] = 1;
36 mCaps.params[kParamResourceBlob] = 1;
37 mCaps.params[kParamHostVisible] = 1;
38 mCaps.params[kParamCrossDevice] = 0;
39 mCaps.params[kParamContextInit] = 1;
40 mCaps.params[kParamSupportedCapsetIds] = 0;
41 mCaps.params[kParamExplicitDebugName] = 0;
42 mCaps.params[kParamCreateGuestHandle] = 0;
43
44 if (capset == kCapsetGfxStreamVulkan) {
45 uint64_t query_id = kMagmaVirtioGpuQueryCapset;
46 query_id |= static_cast<uint64_t>(kCapsetGfxStreamVulkan) << 32;
47 constexpr uint16_t kVersion = 0;
48 query_id |= static_cast<uint64_t>(kVersion) << 16;
49
50 magma_handle_t buffer;
51 magma_status_t status = magma_device_query(device_, query_id, &buffer, nullptr);
52 if (status == MAGMA_STATUS_OK) {
53 zx::vmo capset_info(buffer);
54 zx_status_t status =
55 capset_info.read(&mCaps.vulkanCapset, /*offset=*/0, sizeof(struct vulkanCapset));
56 ALOGD("Got capset result, read status %d", status);
57 } else {
58 ALOGE("Query(%lu) failed: status %d, expected buffer result", query_id, status);
59 }
60
61 // We always need an ASG blob in some cases, so always define blobAlignment
62 if (!mCaps.vulkanCapset.blobAlignment) {
63 mCaps.vulkanCapset.blobAlignment = 4096;
64 }
65 }
66 }
67
~FuchsiaVirtGpuDevice()68 FuchsiaVirtGpuDevice::~FuchsiaVirtGpuDevice() { magma_device_release(device_); }
69
getDeviceHandle(void)70 int64_t FuchsiaVirtGpuDevice::getDeviceHandle(void) { return device_; }
71
createBlob(const struct VirtGpuCreateBlob & blobCreate)72 VirtGpuResourcePtr FuchsiaVirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
73 ALOGE("%s: unimplemented", __func__);
74 return nullptr;
75 }
76
createResource(uint32_t width,uint32_t height,uint32_t stride,uint32_t virglFormat,uint32_t target,uint32_t bind)77 VirtGpuResourcePtr FuchsiaVirtGpuDevice::createResource(uint32_t width, uint32_t height,
78 uint32_t stride, uint32_t virglFormat,
79 uint32_t target, uint32_t bind) {
80 ALOGE("%s: unimplemented", __func__);
81 return nullptr;
82 }
83
importBlob(const struct VirtGpuExternalHandle & handle)84 VirtGpuResourcePtr FuchsiaVirtGpuDevice::importBlob(const struct VirtGpuExternalHandle& handle) {
85 ALOGE("%s: unimplemented", __func__);
86 return nullptr;
87 }
88
execBuffer(struct VirtGpuExecBuffer & execbuffer,const VirtGpuResource * blob)89 int FuchsiaVirtGpuDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer,
90 const VirtGpuResource* blob) {
91 ALOGE("%s: unimplemented", __func__);
92 return 0;
93 }
94
getCaps(void)95 struct VirtGpuCaps FuchsiaVirtGpuDevice::getCaps(void) { return {}; }
96
createPlatformVirtGpuDevice(enum VirtGpuCapset capset,int fd)97 VirtGpuDevice* createPlatformVirtGpuDevice(enum VirtGpuCapset capset, int fd) {
98 // We don't handle the VirtioGpuPipeStream case.
99 if (fd >= 0) {
100 ALOGE("Fuchsia: fd not handled");
101 abort();
102 return nullptr;
103 }
104
105 const char kDevGpu[] = "/loader-gpu-devices/class/gpu";
106
107 struct os_dirent* de;
108 os_dir_t* dir = os_opendir(kDevGpu);
109 if (!dir) {
110 ALOGE("Error opening %s", kDevGpu);
111 return nullptr;
112 }
113
114 ALOGD("Opened dir %s", kDevGpu);
115
116 VirtGpuDevice* gpu_device = nullptr;
117
118 while ((de = os_readdir(dir)) != NULL) {
119 ALOGD("Got name %s", de->d_name);
120
121 if (strcmp(de->d_name, ".") == 0) {
122 continue;
123 }
124 // extra +1 ensures space for null termination
125 char name[sizeof(kDevGpu) + sizeof('/') + sizeof(de->d_name) + 1];
126 snprintf(name, sizeof(name), "%s/%s", kDevGpu, de->d_name);
127
128 zx_handle_t device_channel = GetConnectToServiceFunction()(name);
129 if (device_channel == ZX_HANDLE_INVALID) {
130 ALOGE("Failed to open device: %s", name);
131 continue;
132 }
133
134 magma_device_t magma_device;
135 magma_status_t status = magma_device_import(device_channel, &magma_device);
136 if (status != MAGMA_STATUS_OK) {
137 ALOGE("magma_device_import failed: %d", status);
138 continue;
139 }
140
141 gpu_device = new FuchsiaVirtGpuDevice(capset, magma_device);
142 break;
143 }
144 os_closedir(dir);
145
146 return gpu_device;
147 }
148