1 /*
2 *
3 * Copyright (c) 2018 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include "dlopen_fuchsia.h"
20
21 #include <fcntl.h>
22 #include <fuchsia/vulkan/loader/c/fidl.h>
23 #include <lib/fdio/io.h>
24 #include <lib/fdio/directory.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <threads.h>
28 #include <zircon/dlfcn.h>
29 #include <zircon/syscalls.h>
30
31 static char g_error[128] = {};
32
dlerror_fuchsia(void)33 const char *dlerror_fuchsia(void) { return g_error; }
34
35 static zx_handle_t vulkan_loader_svc = ZX_HANDLE_INVALID;
connect_to_vulkan_loader_svc(void)36 void connect_to_vulkan_loader_svc(void) {
37 zx_handle_t svc1, svc2;
38 if (zx_channel_create(0, &svc1, &svc2) != ZX_OK) return;
39
40 if (fdio_service_connect("/svc/" fuchsia_vulkan_loader_Loader_Name, svc1) != ZX_OK) {
41 zx_handle_close(svc2);
42 return;
43 }
44
45 vulkan_loader_svc = svc2;
46 }
47
48 static once_flag svc_connect_once_flag = ONCE_FLAG_INIT;
49
dlopen_fuchsia(const char * name,int mode,bool driver)50 void *dlopen_fuchsia(const char *name, int mode, bool driver) {
51 // First try to just dlopen() from our own namespace. This will succeed for
52 // any layers that are packaged with the application, but will fail for
53 // client drivers loaded from the system.
54 void *result;
55 if (!driver) {
56 result = dlopen(name, mode);
57 if (result != NULL) return result;
58 }
59
60 // If we couldn't find the library in our own namespace, connect to the
61 // loader service to request this library.
62 call_once(&svc_connect_once_flag, connect_to_vulkan_loader_svc);
63
64 if (vulkan_loader_svc == ZX_HANDLE_INVALID) {
65 snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: no connection to loader svc\n");
66 return NULL;
67 }
68
69 zx_handle_t vmo = ZX_HANDLE_INVALID;
70 zx_status_t st = fuchsia_vulkan_loader_LoaderGet(vulkan_loader_svc, name, strlen(name), &vmo);
71 if (st != ZX_OK) {
72 snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() failed: %d\n", st);
73 return NULL;
74 }
75
76 if (vmo == ZX_HANDLE_INVALID) {
77 snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() returned invalid vmo\n");
78 return NULL;
79 }
80
81 result = dlopen_vmo(vmo, mode);
82 zx_handle_close(vmo);
83 if (!result) {
84 snprintf(g_error, sizeof(g_error), "%s", dlerror());
85 }
86 return result;
87 }
88