15db71995Sopenharmony_ci/*
25db71995Sopenharmony_ci *
35db71995Sopenharmony_ci * Copyright (c) 2018 Google Inc.
45db71995Sopenharmony_ci *
55db71995Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
65db71995Sopenharmony_ci * you may not use this file except in compliance with the License.
75db71995Sopenharmony_ci * You may obtain a copy of the License at
85db71995Sopenharmony_ci *
95db71995Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
105db71995Sopenharmony_ci *
115db71995Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
125db71995Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
135db71995Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145db71995Sopenharmony_ci * See the License for the specific language governing permissions and
155db71995Sopenharmony_ci * limitations under the License.
165db71995Sopenharmony_ci *
175db71995Sopenharmony_ci */
185db71995Sopenharmony_ci
195db71995Sopenharmony_ci#include "dlopen_fuchsia.h"
205db71995Sopenharmony_ci
215db71995Sopenharmony_ci#include <fcntl.h>
225db71995Sopenharmony_ci#include <fuchsia/vulkan/loader/c/fidl.h>
235db71995Sopenharmony_ci#include <lib/fdio/io.h>
245db71995Sopenharmony_ci#include <lib/fdio/directory.h>
255db71995Sopenharmony_ci#include <stdio.h>
265db71995Sopenharmony_ci#include <string.h>
275db71995Sopenharmony_ci#include <threads.h>
285db71995Sopenharmony_ci#include <zircon/dlfcn.h>
295db71995Sopenharmony_ci#include <zircon/syscalls.h>
305db71995Sopenharmony_ci
315db71995Sopenharmony_cistatic char g_error[128] = {};
325db71995Sopenharmony_ci
335db71995Sopenharmony_ciconst char *dlerror_fuchsia(void) { return g_error; }
345db71995Sopenharmony_ci
355db71995Sopenharmony_cistatic zx_handle_t vulkan_loader_svc = ZX_HANDLE_INVALID;
365db71995Sopenharmony_civoid connect_to_vulkan_loader_svc(void) {
375db71995Sopenharmony_ci    zx_handle_t svc1, svc2;
385db71995Sopenharmony_ci    if (zx_channel_create(0, &svc1, &svc2) != ZX_OK) return;
395db71995Sopenharmony_ci
405db71995Sopenharmony_ci    if (fdio_service_connect("/svc/" fuchsia_vulkan_loader_Loader_Name, svc1) != ZX_OK) {
415db71995Sopenharmony_ci        zx_handle_close(svc2);
425db71995Sopenharmony_ci        return;
435db71995Sopenharmony_ci    }
445db71995Sopenharmony_ci
455db71995Sopenharmony_ci    vulkan_loader_svc = svc2;
465db71995Sopenharmony_ci}
475db71995Sopenharmony_ci
485db71995Sopenharmony_cistatic once_flag svc_connect_once_flag = ONCE_FLAG_INIT;
495db71995Sopenharmony_ci
505db71995Sopenharmony_civoid *dlopen_fuchsia(const char *name, int mode, bool driver) {
515db71995Sopenharmony_ci    // First try to just dlopen() from our own namespace. This will succeed for
525db71995Sopenharmony_ci    // any layers that are packaged with the application, but will fail for
535db71995Sopenharmony_ci    // client drivers loaded from the system.
545db71995Sopenharmony_ci    void *result;
555db71995Sopenharmony_ci    if (!driver) {
565db71995Sopenharmony_ci        result = dlopen(name, mode);
575db71995Sopenharmony_ci        if (result != NULL) return result;
585db71995Sopenharmony_ci    }
595db71995Sopenharmony_ci
605db71995Sopenharmony_ci    // If we couldn't find the library in our own namespace, connect to the
615db71995Sopenharmony_ci    // loader service to request this library.
625db71995Sopenharmony_ci    call_once(&svc_connect_once_flag, connect_to_vulkan_loader_svc);
635db71995Sopenharmony_ci
645db71995Sopenharmony_ci    if (vulkan_loader_svc == ZX_HANDLE_INVALID) {
655db71995Sopenharmony_ci        snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: no connection to loader svc\n");
665db71995Sopenharmony_ci        return NULL;
675db71995Sopenharmony_ci    }
685db71995Sopenharmony_ci
695db71995Sopenharmony_ci    zx_handle_t vmo = ZX_HANDLE_INVALID;
705db71995Sopenharmony_ci    zx_status_t st = fuchsia_vulkan_loader_LoaderGet(vulkan_loader_svc, name, strlen(name), &vmo);
715db71995Sopenharmony_ci    if (st != ZX_OK) {
725db71995Sopenharmony_ci        snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() failed: %d\n", st);
735db71995Sopenharmony_ci        return NULL;
745db71995Sopenharmony_ci    }
755db71995Sopenharmony_ci
765db71995Sopenharmony_ci    if (vmo == ZX_HANDLE_INVALID) {
775db71995Sopenharmony_ci        snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() returned invalid vmo\n");
785db71995Sopenharmony_ci        return NULL;
795db71995Sopenharmony_ci    }
805db71995Sopenharmony_ci
815db71995Sopenharmony_ci    result = dlopen_vmo(vmo, mode);
825db71995Sopenharmony_ci    zx_handle_close(vmo);
835db71995Sopenharmony_ci    if (!result) {
845db71995Sopenharmony_ci        snprintf(g_error, sizeof(g_error), "%s", dlerror());
855db71995Sopenharmony_ci    }
865db71995Sopenharmony_ci    return result;
875db71995Sopenharmony_ci}
88