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 31static char g_error[128] = {}; 32 33const char *dlerror_fuchsia(void) { return g_error; } 34 35static zx_handle_t vulkan_loader_svc = ZX_HANDLE_INVALID; 36void 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 48static once_flag svc_connect_once_flag = ONCE_FLAG_INIT; 49 50void *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