xref: /aosp_15_r20/external/mesa3d/src/gfxstream/guest/vulkan/gfxstream_vk_fuchsia.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2023 Google LLC
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include <cutils/log.h>
7 #include <fidl/fuchsia.logger/cpp/wire.h>
8 #include <lib/syslog/structured_backend/cpp/fuchsia_syslog.h>
9 #include <lib/zx/channel.h>
10 #include <lib/zx/socket.h>
11 #include <lib/zxio/zxio.h>
12 #include <unistd.h>
13 #include <zircon/system/public/zircon/process.h>
14 
15 #include <cstdarg>
16 
17 #include "ResourceTracker.h"
18 #include "TraceProviderFuchsia.h"
19 #include "services/service_connector.h"
20 
21 namespace {
22 
23 zx::socket g_log_socket = zx::socket(ZX_HANDLE_INVALID);
24 
25 typedef VkResult(VKAPI_PTR* PFN_vkOpenInNamespaceAddr)(const char* pName, uint32_t handle);
26 
27 PFN_vkOpenInNamespaceAddr g_vulkan_connector;
28 
GetKoid(zx_handle_t handle)29 zx_koid_t GetKoid(zx_handle_t handle) {
30     zx_info_handle_basic_t info;
31     zx_status_t status =
32         zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
33     return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
34 }
35 
36 static zx_koid_t pid = GetKoid(zx_process_self());
37 
38 static thread_local zx_koid_t tid = GetKoid(zx_thread_self());
39 
CStringToStringView(const char * cstr)40 cpp17::optional<cpp17::string_view> CStringToStringView(const char* cstr) {
41     if (!cstr) {
42         return cpp17::nullopt;
43     }
44     return cstr;
45 }
46 
StripDots(const char * path)47 const char* StripDots(const char* path) {
48     while (strncmp(path, "../", 3) == 0) {
49         path += 3;
50     }
51     return path;
52 }
53 
StripPath(const char * path)54 const char* StripPath(const char* path) {
55     auto p = strrchr(path, '/');
56     if (p) {
57         return p + 1;
58     } else {
59         return path;
60     }
61 }
62 
StripFile(const char * file,FuchsiaLogSeverity severity)63 const char* StripFile(const char* file, FuchsiaLogSeverity severity) {
64     return severity > FUCHSIA_LOG_INFO ? StripDots(file) : StripPath(file);
65 }
66 
gfxstream_fuchsia_log(int8_t severity,const char * tag,const char * file,int line,const char * format,va_list va)67 extern "C" void gfxstream_fuchsia_log(int8_t severity, const char* tag, const char* file, int line,
68                                       const char* format, va_list va) {
69     if (!g_log_socket.is_valid()) {
70         abort();
71     }
72     fuchsia_syslog::LogBuffer buffer;
73     constexpr size_t kFormatStringLength = 1024;
74     char fmt_string[kFormatStringLength];
75     fmt_string[kFormatStringLength - 1] = 0;
76     int n = kFormatStringLength;
77     // Format
78     // Number of bytes written not including null terminator
79     int count = vsnprintf(fmt_string, n, format, va) + 1;
80     if (count < 0) {
81         // No message to write.
82         return;
83     }
84 
85     if (count >= n) {
86         // truncated
87         constexpr char kEllipsis[] = "...";
88         constexpr size_t kEllipsisSize = sizeof(kEllipsis);
89         snprintf(fmt_string + kFormatStringLength - 1 - kEllipsisSize, kEllipsisSize, kEllipsis);
90     }
91 
92     if (file) {
93         file = StripFile(file, severity);
94     }
95     buffer.BeginRecord(severity, CStringToStringView(file), line, fmt_string, g_log_socket.borrow(),
96                        0, pid, tid);
97     if (tag) {
98         buffer.WriteKeyValue("tag", tag);
99     }
100     buffer.FlushRecord();
101 }
102 
LocalConnectToServiceFunction(const char * pName)103 zx_handle_t LocalConnectToServiceFunction(const char* pName) {
104     zx::channel remote_endpoint, local_endpoint;
105     zx_status_t status;
106     if ((status = zx::channel::create(0, &remote_endpoint, &local_endpoint)) != ZX_OK) {
107         ALOGE("zx::channel::create failed: %d", status);
108         return ZX_HANDLE_INVALID;
109     }
110     if ((status = g_vulkan_connector(pName, remote_endpoint.release())) != ZX_OK) {
111         ALOGE("vulkan_connector failed: %d", status);
112         return ZX_HANDLE_INVALID;
113     }
114     return local_endpoint.release();
115 }
116 
117 }  // namespace
118 
119 class VulkanDevice {
120    public:
VulkanDevice()121     VulkanDevice() : mHostSupportsGoldfish(IsAccessible(QEMU_PIPE_PATH)) {
122         InitTraceProvider();
123         gfxstream::vk::ResourceTracker::get();
124     }
125 
126     static void InitLogger();
127 
IsAccessible(const char * name)128     static bool IsAccessible(const char* name) {
129         zx_handle_t handle = GetConnectToServiceFunction()(name);
130         if (handle == ZX_HANDLE_INVALID) return false;
131 
132         zxio_storage_t io_storage;
133         zx_status_t status = zxio_create(handle, &io_storage);
134         if (status != ZX_OK) return false;
135 
136         status = zxio_close(&io_storage.io, /*should_wait=*/true);
137         if (status != ZX_OK) return false;
138 
139         return true;
140     }
141 
GetInstance()142     static VulkanDevice& GetInstance() {
143         static VulkanDevice g_instance;
144         return g_instance;
145     }
146 
147    private:
148     void InitTraceProvider();
149 
150     TraceProviderFuchsia mTraceProvider;
151     const bool mHostSupportsGoldfish;
152 };
153 
InitLogger()154 void VulkanDevice::InitLogger() {
155     auto log_socket = ([]() -> std::optional<zx::socket> {
156         fidl::ClientEnd<fuchsia_logger::LogSink> channel{
157             zx::channel{GetConnectToServiceFunction()("/svc/fuchsia.logger.LogSink")}};
158         if (!channel.is_valid()) return std::nullopt;
159 
160         zx::socket local_socket, remote_socket;
161         zx_status_t status = zx::socket::create(ZX_SOCKET_DATAGRAM, &local_socket, &remote_socket);
162         if (status != ZX_OK) return std::nullopt;
163 
164         auto result = fidl::WireCall(channel)->ConnectStructured(std::move(remote_socket));
165 
166         if (!result.ok()) return std::nullopt;
167 
168         return local_socket;
169     })();
170     if (!log_socket) return;
171 
172     g_log_socket = std::move(*log_socket);
173 }
174 
InitTraceProvider()175 void VulkanDevice::InitTraceProvider() {
176     if (!mTraceProvider.Initialize()) {
177         ALOGE("Trace provider failed to initialize");
178     }
179 }
180 
vk_icdInitializeOpenInNamespaceCallback(PFN_vkOpenInNamespaceAddr callback)181 extern "C" __attribute__((visibility("default"))) void vk_icdInitializeOpenInNamespaceCallback(
182     PFN_vkOpenInNamespaceAddr callback) {
183     g_vulkan_connector = callback;
184     SetConnectToServiceFunction(&LocalConnectToServiceFunction);
185 
186     VulkanDevice::InitLogger();
187 
188     ALOGV("Gfxstream on Fuchsia initialized");
189 }
190