• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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