Merge tag 'vulkan-sdk-1.3.268.0'
Bug:b/319117470
Change-Id: Iace0288ab6fdfc0d711f20f745122498de071452
diff --git a/BUILD.gn b/BUILD.gn
index 760356b..c914caa 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -44,14 +44,16 @@
"-Wno-conversion",
"-Wno-extra-semi",
"-Wno-sign-compare",
+ "-Wno-strict-prototypes",
"-Wno-unreachable-code",
"-Wno-unused-function",
"-Wno-unused-variable",
+ "-Wno-write-strings",
]
}
if (is_fuchsia) {
defines += [
- "SYSCONFDIR=\"/config\"",
+ "SYSCONFDIR=\"/vulkan-loader-configuration\"",
"EXTRASYSCONFDIR=\"/pkg/data\"",
]
}
@@ -87,9 +89,13 @@
# assume secure_getenv() is available
defines += [
"HAVE_SECURE_GETENV",
+ "_POSIX_C_SOURCE=200809L",
"LOADER_ENABLE_LINUX_SORT",
]
}
+ if (is_fuchsia || is_linux || is_chromeos) {
+ defines += [ "HAVE_ALLOCA_H" ]
+ }
}
if (!is_android) {
@@ -123,6 +129,7 @@
"loader/loader_environment.h",
"loader/loader.c",
"loader/loader.h",
+ "loader/loader_common.h",
"loader/log.c",
"loader/log.h",
"loader/phys_dev_ext.c",
@@ -161,9 +168,9 @@
sources += [
"loader/dirent_on_windows.c",
"loader/dirent_on_windows.h",
+ "loader/loader.rc",
"loader/loader_windows.c",
"loader/loader_windows.h",
- "loader/loader.rc",
"loader/vulkan-1.def",
]
if (!is_clang) {
@@ -188,6 +195,7 @@
libs = [ "Cfgmgr32.lib" ]
}
if (is_linux || is_chromeos) {
+ libs = [ "dl" ]
sources += [
"loader/loader_linux.c",
"loader/loader_linux.h",
@@ -196,9 +204,11 @@
if (is_mac) {
frameworks = [ "CoreFoundation.framework" ]
}
+ if (build_with_chromium) {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
public_deps = [ "$vulkan_headers_dir:vulkan_headers" ]
- configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [ "//build/config/compiler:no_chromium_code" ]
configs += [ ":vulkan_internal_config" ]
public_configs = [ ":vulkan_loader_config" ]
configs -= vulkan_undefine_configs
@@ -206,16 +216,27 @@
if (is_fuchsia) {
category = "partner"
+ symbols_api = "vulkan.ifs"
+
# The Vulkan loader's interface is defined by standard Khronos vulkan headers
# which can be obtained separately from the loader implementation itself.
no_headers = true
+ sources += [ "fuchsia/loader_extensions.cc" ]
+
deps = [
":dlopen_fuchsia",
+ "//sdk/fidl/fuchsia.io:fuchsia.io_cpp",
+ "//sdk/fidl/fuchsia.vulkan.loader:fuchsia.vulkan.loader_cpp",
"//sdk/lib/fdio",
]
- runtime_deps = [ "//sdk/lib/fdio:fdio_sdk" ]
+ runtime_deps = [
+ "//sdk/lib/fdio:fdio_sdk",
+ "//zircon/system/ulib/trace-engine:trace-engine_sdk",
+ ]
+
+ libcxx_linkage = "static"
}
}
}
@@ -223,18 +244,32 @@
if (is_fuchsia) {
config("fuchsia_config") {
include_dirs = [ "fuchsia" ]
+
+ if (is_clang || !is_win) {
+ cflags = [
+ "-Wno-newline-eof",
+ "-Wno-strict-prototypes",
+ ]
+ }
}
source_set("dlopen_fuchsia") {
public_configs = [ ":fuchsia_config" ]
+ configs += [ ":vulkan_loader_config" ]
sources = [
- "fuchsia/dlopen_fuchsia.c",
+ "fuchsia/dlopen_fuchsia.cc",
"fuchsia/dlopen_fuchsia.h",
+ "fuchsia/loader_fuchsia.h",
+ "fuchsia/loader_service.cc",
+ "fuchsia/loader_service.h",
+ "loader/log.h",
]
deps = [
- "//sdk/fidl/fuchsia.vulkan.loader:fuchsia.vulkan.loader_c_client",
+ "$vulkan_headers_dir:vulkan_headers",
+ "//sdk/fidl/fuchsia.vulkan.loader:fuchsia.vulkan.loader_cpp",
+ "//sdk/lib/component/incoming/cpp",
"//sdk/lib/fdio",
]
}
@@ -251,3 +286,7 @@
]
}
}
+
+group("tests") {
+ # TODO(fxbug.dev/13288)
+}
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..3db216e
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+
+rosasco@google.com
+cstout@google.com
+jbauman@google.com
diff --git a/README.fuchsia b/README.fuchsia
new file mode 100644
index 0000000..06b2a86
--- /dev/null
+++ b/README.fuchsia
@@ -0,0 +1,10 @@
+Name: Vulkan-Loader
+License: Apache 2.0
+License File: LICENSE.txt
+Upstream Git: https://github.com/KhronosGroup/Vulkan-Loader
+Description:
+
+The Khronos official Vulkan ICD desktop loader.
+
+
+
diff --git a/fuchsia/README.md b/fuchsia/README.md
new file mode 100644
index 0000000..a50bd3e
--- /dev/null
+++ b/fuchsia/README.md
@@ -0,0 +1,34 @@
+# Fuchsia extensions to the loader
+
+## Shared library opening
+
+The loader doesn't have direct access to the filesystem containing an ICD. Instead, it must connect
+to the [Vulkan loader service][loader-service] at `/svc/fuchsia.vulkan.loader.Loader`. That service
+can provide an executable VMO for an ICD, which can be loaded using `dlopen_vmo`.
+
+## Open in namespace callback
+
+According to the [Fuchsia system ABI][abi], Vulkan ICDs cannot directly use the filesystem to read
+files or connect to services. Instead loader will call the `vk_icdInitializeOpenInNamespaceCallback`
+function in the ICD immediately after the ICD is dlopened. The callback may be used by the ICD to
+connect to services, or the driver device node or to read from files.
+
+## Exporting device nodes
+
+If an ICD tries to open a path under `/loader-gpu-devices` using
+`vk_icdInitializeOpenInNamespaceCallback`, the loader will redirect that request to a directory
+returned by [fuchsia.vulkan.loader/Loader.ConnectToDeviceFs][connect-device-fs]. This allows the
+loader service to ensure all devnodes the ICD needs are accessible to it, without the application or
+application runtime needing to special-case device nodes in the application's component manifest.
+
+## Getting ICD manifests
+
+[ICD manifests][manifests] are retrieved using [ConnectToManifestFs][connect-manifest-fs] on the
+loader service instead of being read directly from the filesystem. This allows ICD manifests to be
+packaged alongside the ICD shared library. Layer manifests are read from the filesystem like normal.
+
+[loader-service]: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/graphics/bin/vulkan_loader/README.md
+[abi]: https://fuchsia.dev/fuchsia-src/concepts/system/abi/system?hl=en
+[connect-device-fs]: https://fuchsia.dev/reference/fidl/fuchsia.vulkan.loader?hl=en#fuchsia.vulkan.loader/Loader.ConnectToDeviceFs
+[connect-manifest-fs]: https://fuchsia.dev/reference/fidl/fuchsia.vulkan.loader?hl=en#fuchsia.vulkan.loader/Loader.ConnectToManifestFs
+[manifests]: ../loader/LoaderAndLayerInterface.md
\ No newline at end of file
diff --git a/fuchsia/dlopen_fuchsia.c b/fuchsia/dlopen_fuchsia.c
deleted file mode 100644
index c973b35..0000000
--- a/fuchsia/dlopen_fuchsia.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *
- * Copyright (c) 2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "dlopen_fuchsia.h"
-
-#include <fcntl.h>
-#include <fuchsia/vulkan/loader/c/fidl.h>
-#include <lib/fdio/io.h>
-#include <lib/fdio/directory.h>
-#include <stdio.h>
-#include <string.h>
-#include <threads.h>
-#include <zircon/dlfcn.h>
-#include <zircon/syscalls.h>
-
-static char g_error[128] = {};
-
-const char *dlerror_fuchsia(void) { return g_error; }
-
-static zx_handle_t vulkan_loader_svc = ZX_HANDLE_INVALID;
-void connect_to_vulkan_loader_svc(void) {
- zx_handle_t svc1, svc2;
- if (zx_channel_create(0, &svc1, &svc2) != ZX_OK) return;
-
- if (fdio_service_connect("/svc/" fuchsia_vulkan_loader_Loader_Name, svc1) != ZX_OK) {
- zx_handle_close(svc2);
- return;
- }
-
- vulkan_loader_svc = svc2;
-}
-
-static once_flag svc_connect_once_flag = ONCE_FLAG_INIT;
-
-void *dlopen_fuchsia(const char *name, int mode, bool driver) {
- // First try to just dlopen() from our own namespace. This will succeed for
- // any layers that are packaged with the application, but will fail for
- // client drivers loaded from the system.
- void *result;
- if (!driver) {
- result = dlopen(name, mode);
- if (result != NULL) return result;
- }
-
- // If we couldn't find the library in our own namespace, connect to the
- // loader service to request this library.
- call_once(&svc_connect_once_flag, connect_to_vulkan_loader_svc);
-
- if (vulkan_loader_svc == ZX_HANDLE_INVALID) {
- snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: no connection to loader svc\n");
- return NULL;
- }
-
- zx_handle_t vmo = ZX_HANDLE_INVALID;
- zx_status_t st = fuchsia_vulkan_loader_LoaderGet(vulkan_loader_svc, name, strlen(name), &vmo);
- if (st != ZX_OK) {
- snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() failed: %d\n", st);
- return NULL;
- }
-
- if (vmo == ZX_HANDLE_INVALID) {
- snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() returned invalid vmo\n");
- return NULL;
- }
-
- result = dlopen_vmo(vmo, mode);
- zx_handle_close(vmo);
- if (!result) {
- snprintf(g_error, sizeof(g_error), "%s", dlerror());
- }
- return result;
-}
diff --git a/fuchsia/dlopen_fuchsia.cc b/fuchsia/dlopen_fuchsia.cc
new file mode 100644
index 0000000..a8dbea0
--- /dev/null
+++ b/fuchsia/dlopen_fuchsia.cc
@@ -0,0 +1,174 @@
+/*
+ *
+ * Copyright (c) 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "dlopen_fuchsia.h"
+
+#include <fcntl.h>
+#include <fidl/fuchsia.io/cpp/wire.h>
+#include <lib/fdio/directory.h>
+#include <lib/fdio/io.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <threads.h>
+#include <zircon/dlfcn.h>
+#include <zircon/syscalls.h>
+
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "loader_service.h"
+
+static char g_error[256] = {};
+
+const char *dlerror_fuchsia(void) { return g_error; }
+
+namespace fio = fuchsia_io;
+
+struct FuchsiaLoaderData {
+ std::mutex table_lock;
+
+ // Keep a cache of ICD shared libraries to avoid loading the same library
+ // multiple times. dlclose doesn't currently do anything on Fuchsia, so we never
+ // bother calling it.
+ std::unordered_map<std::string, void *> icd_dso_map __attribute__((guarded_by(table_lock)));
+ std::unordered_set<void *> icd_dso_set __attribute__((guarded_by(table_lock)));
+};
+
+static FuchsiaLoaderData *fuchsia_loader_data;
+
+void fuchsia_initialize() { fuchsia_loader_data = new FuchsiaLoaderData; }
+
+void fuchsia_teardown() { delete fuchsia_loader_data; }
+
+static void append_to_error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+static void append_to_error(const char *format, ...) {
+ // Size of an individual error message. Multiple can be concatenated.
+ constexpr size_t kErrorSize = 128;
+ char local_error[kErrorSize];
+
+ va_list args;
+ va_start(args, format);
+ vsnprintf(local_error, sizeof(local_error), format, args);
+ va_end(args);
+
+ // Subtract 1 because the NUL-terminator isn't counted.
+ strncat(g_error, local_error, sizeof(g_error) - strlen(g_error) - 1);
+ // Set last byte to 0 in case there wasn't enough room in g_error to fit the entire string.
+ g_error[sizeof(g_error) - 1] = '\0';
+}
+
+// Some VMOs may be loaded from directories outside the package which the shared library loader doesn't
+// have access to. They can only be loaded by opening the file and using dlopen_vmo.
+static void *dlopen_using_vmo(const char *name, int mode) {
+ int fd;
+ zx_status_t status = fdio_open_fd(
+ name, static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightExecutable), &fd);
+ if (status != ZX_OK) {
+ append_to_error("libvulkan.so:dlopen_using_vmo: couldn't open \"%s\" as fd, %s\n", name, zx_status_get_string(status));
+ return nullptr;
+ }
+ zx::vmo vmo;
+ status = fdio_get_vmo_exec(fd, vmo.reset_and_get_address());
+ close(fd);
+ if (status != ZX_OK) {
+ append_to_error("libvulkan.so:dlopen_using_vmo: couldn't get vmo \"%s\" as exec: %s\n", name, zx_status_get_string(status));
+ return nullptr;
+ }
+ void *result = dlopen_vmo(vmo.get(), mode);
+ if (!result) {
+ append_to_error("%s", dlerror());
+ }
+ return result;
+}
+
+static void *dlopen_from_vulkan_loader(const char *name, int mode, bool *retry_out) {
+ // Connect to the vulkan loader service to request this library.
+ // If loading fails at these early points, the ICD may just not be available
+ // through the loader service, so retry using plain dlopen.
+ *retry_out = true;
+
+ std::lock_guard<std::mutex> lock(fuchsia_loader_data->table_lock);
+ auto it = fuchsia_loader_data->icd_dso_map.find(name);
+ if (it != fuchsia_loader_data->icd_dso_map.end()) {
+ return it->second;
+ }
+
+ auto &loader_svc = get_vulkan_loader_service();
+ if (!loader_svc.is_valid()) {
+ append_to_error("libvulkan.so:dlopen_fuchsia: no connection to loader svc\n");
+ return nullptr;
+ }
+
+ auto get_result = loader_svc->Get(fidl::StringView::FromExternal(name));
+ if (!get_result.ok()) {
+ append_to_error("libvulkan.so:dlopen_fuchsia: Get() of \"%s\" failed: %s\n", name, get_result.status_string());
+ return nullptr;
+ }
+
+ if (!get_result.value().lib) {
+ append_to_error("libvulkan.so:dlopen_fuchsia: Get() returned invalid vmo\n");
+ return nullptr;
+ }
+ // If we've got a valid VMO matching the name then that VMO is expected to work.
+ *retry_out = false;
+
+ void *result = dlopen_vmo(get_result.value().lib.get(), mode);
+ if (!result) {
+ append_to_error("%s", dlerror());
+ } else {
+ fuchsia_loader_data->icd_dso_map[name] = result;
+ fuchsia_loader_data->icd_dso_set.insert(result);
+ }
+ return result;
+}
+
+void *dlopen_fuchsia(const char *name, int mode, bool driver) {
+ // All errors are appended to g_error, so reset it to empty.
+ g_error[0] = '\0';
+ void *result;
+ if (driver) {
+ // ICDs generally should by loaded from the loader service, so try that first.
+ bool retry{};
+ result = dlopen_from_vulkan_loader(name, mode, &retry);
+ if (result || !retry) {
+ return result;
+ }
+ }
+ result = dlopen(name, mode);
+ if (result != nullptr) {
+ return result;
+ }
+ return dlopen_using_vmo(name, mode);
+}
+
+void dlclose_fuchsia(void *dso) {
+ {
+ std::lock_guard<std::mutex> lock(fuchsia_loader_data->table_lock);
+ if (fuchsia_loader_data->icd_dso_set.count(dso)) {
+ // dlclose doesn't actually do anything on Fuchsia, so it's better
+ // to cache the shared object forever rather than leak it.
+ return;
+ }
+ }
+ // It's fine to dlclose normal shared objects with sonames because the
+ // library loader caches them by soname.
+ dlclose(dso);
+}
diff --git a/fuchsia/dlopen_fuchsia.h b/fuchsia/dlopen_fuchsia.h
index a674b8d..2310ccb 100644
--- a/fuchsia/dlopen_fuchsia.h
+++ b/fuchsia/dlopen_fuchsia.h
@@ -25,5 +25,6 @@
// If not |driver|, then the request is to load a layer.
void *dlopen_fuchsia(const char *name, int mode, bool driver);
const char *dlerror_fuchsia(void);
+void dlclose_fuchsia(void *dso);
__END_CDECLS
diff --git a/fuchsia/loader_extensions.cc b/fuchsia/loader_extensions.cc
new file mode 100644
index 0000000..790fd96
--- /dev/null
+++ b/fuchsia/loader_extensions.cc
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright (c) 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fidl/fuchsia.io/cpp/wire.h>
+#include <lib/fdio/directory.h>
+#include <lib/stdcompat/string_view.h>
+#include <limits.h>
+
+#include "loader.h"
+#include "loader_service.h"
+#include "log.h"
+
+namespace {
+
+using PFN_vkOpenInNamespaceAddr = VkResult (*)(const char*, uint32_t);
+using PFN_vkInitializeOpenInNamespaceCallbackAddr = PFN_vkVoidFunction (*)(PFN_vkOpenInNamespaceAddr);
+
+VKAPI_ATTR VkResult VKAPI_CALL loader_fdio_open_in_namespace(const char* const pName, uint32_t handle) {
+ constexpr std::string_view kGpuDevicePrefix = "/loader-gpu-devices";
+ zx_status_t status;
+ if (cpp20::starts_with(std::string_view{pName}, kGpuDevicePrefix)) {
+ // Accesses to subpaths of /loader-gpu-devices should be redirected through the devicefs
+ // exposed by the loader service. See README.md in this directory for details.
+ zx_handle_t device_fs = get_device_fs();
+ if (!device_fs) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ const char* new_name = pName + kGpuDevicePrefix.length();
+ if (std::string_view{new_name}.empty()) {
+ new_name = ".";
+ } else {
+ if (new_name[0] != '/') {
+ // Name must be "/loader-gpu-devices/", or that's a bug.
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ }
+ status = fdio_service_connect_at(device_fs, new_name, handle);
+ } else {
+ status = fdio_service_connect(pName, handle);
+ }
+
+ if (status == ZX_OK) {
+ return VK_SUCCESS;
+ }
+ loader_log(nullptr, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Failed to open in namespace %s - error %d", pName, status);
+ return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+} // namespace
+
+void loader_initialize_icd_services(loader_platform_dl_handle handle) {
+ PFN_vkInitializeOpenInNamespaceCallbackAddr fp_initialize_open_in_namespace_callback_addr;
+
+ fp_initialize_open_in_namespace_callback_addr = reinterpret_cast<PFN_vkInitializeOpenInNamespaceCallbackAddr>(
+ loader_platform_get_proc_address(handle, "vk_icdInitializeOpenInNamespaceCallback"));
+ if (fp_initialize_open_in_namespace_callback_addr) {
+ fp_initialize_open_in_namespace_callback_addr(&loader_fdio_open_in_namespace);
+ // ICD isn't required to expose this entrypoint.
+ return;
+ }
+}
diff --git a/fuchsia/loader_fuchsia.h b/fuchsia/loader_fuchsia.h
new file mode 100644
index 0000000..0d4f7d0
--- /dev/null
+++ b/fuchsia/loader_fuchsia.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright (c) 2021 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#pragma once
+
+#include <zircon/compiler.h>
+
+__BEGIN_CDECLS
+
+// Returns a file descriptor with a directory FD for the loader manifest FS. May
+// return -1 if the loader doesn't support ConnectToManifestFs.
+int get_manifest_fs_fd(void);
+
+// Called on loader shared library construction.
+void fuchsia_initialize();
+// Called on loader shared library destruction.
+void fuchsia_teardown();
+
+__END_CDECLS
diff --git a/fuchsia/loader_service.cc b/fuchsia/loader_service.cc
new file mode 100644
index 0000000..ccdffef
--- /dev/null
+++ b/fuchsia/loader_service.cc
@@ -0,0 +1,134 @@
+/*
+ *
+ * Copyright (c) 2021 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "loader_service.h"
+
+#include <fcntl.h>
+#include <fidl/fuchsia.io/cpp/wire.h>
+#include <fidl/fuchsia.vulkan.loader/cpp/wire.h>
+#include <lib/component/incoming/cpp/protocol.h>
+#include <lib/fdio/directory.h>
+#include <lib/fdio/fd.h>
+#include <lib/fdio/io.h>
+#include <lib/fidl/cpp/wire/connect_service.h>
+#include <stdio.h>
+#include <string.h>
+#include <threads.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+
+#include "loader.h"
+#include "log.h"
+
+static fidl::WireSyncClient<fuchsia_vulkan_loader::Loader> vulkan_loader_svc;
+
+static zx_handle_t device_fs = ZX_HANDLE_INVALID;
+
+static int manifest_fs_fd = -1;
+
+void connect_to_vulkan_loader_svc() {
+ auto client_end = component::Connect<fuchsia_vulkan_loader::Loader>();
+ if (!client_end.is_ok()) {
+ loader_log(nullptr, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "connect_to_vulkan_loader_svc: Failed to connect to loader service: %s", client_end.status_string());
+ return;
+ }
+ auto client = fidl::WireSyncClient(std::move(*client_end));
+ auto feature_result = client->GetSupportedFeatures();
+ fuchsia_vulkan_loader::wire::Features features;
+ if (!feature_result.ok()) {
+ loader_log(nullptr, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
+ "connect_to_vulkan_loader_svc: Failed to get supported features, error \"%s\".",
+ feature_result.error().lossy_description());
+ return;
+ }
+ features = feature_result.value().features;
+ constexpr fuchsia_vulkan_loader::wire::Features kMandatoryFeatures =
+ fuchsia_vulkan_loader::wire::Features::kConnectToDeviceFs | fuchsia_vulkan_loader::wire::Features::kConnectToManifestFs |
+ fuchsia_vulkan_loader::wire::Features::kGet;
+ if ((features & kMandatoryFeatures) != kMandatoryFeatures) {
+ loader_log(nullptr, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "connect_to_vulkan_loader_svc: Missing mandatory feature 0x%x",
+ kMandatoryFeatures & ~features);
+ return;
+ }
+ zx::channel device_fs_client;
+ {
+ zx::channel device_fs_server;
+ zx_status_t status = zx::channel::create(0, &device_fs_server, &device_fs_client);
+ if (status != ZX_OK) {
+ loader_log(nullptr, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "connect_to_vulkan_loader_svc: Failed to create channel: %s",
+ zx_status_get_string(status));
+ return;
+ }
+
+ auto result = client->ConnectToDeviceFs(std::move(device_fs_server));
+ if (!result.ok()) {
+ loader_log(nullptr, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "connect_to_vulkan_loader_svc: Failed to connect to device fs: %s", result.status_string());
+ return;
+ }
+ }
+ {
+ zx::channel manifest_fs_client;
+ zx::channel manifest_fs_server;
+ zx_status_t status = zx::channel::create(0, &manifest_fs_server, &manifest_fs_client);
+ if (status != ZX_OK) {
+ loader_log(nullptr, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "connect_to_vulkan_loader_svc: Failed to create channel: %s",
+ zx_status_get_string(status));
+ return;
+ }
+
+ // Wait for idle so clients will be sure that any existing ICDs will be completely available.
+ auto result = client->ConnectToManifestFs(fuchsia_vulkan_loader::wire::ConnectToManifestOptions::kWaitForIdle,
+ std::move(manifest_fs_server));
+ if (!result.ok()) {
+ loader_log(nullptr, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "connect_to_vulkan_loader_svc: Failed to connect to manifest fs: %s", result.status_string());
+ return;
+ }
+ status = fdio_fd_create(manifest_fs_client.release(), &manifest_fs_fd);
+ if (status != ZX_OK) {
+ loader_log(nullptr, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "connect_to_vulkan_loader_svc: Failed to create manifest fs fd: %s", zx_status_get_string(status));
+ return;
+ }
+ }
+
+ vulkan_loader_svc = std::move(client);
+ device_fs = device_fs_client.release();
+}
+
+static once_flag svc_connect_once_flag = ONCE_FLAG_INIT;
+
+fidl::WireSyncClient<fuchsia_vulkan_loader::Loader>& get_vulkan_loader_service() {
+ call_once(&svc_connect_once_flag, connect_to_vulkan_loader_svc);
+
+ return vulkan_loader_svc;
+}
+
+zx_handle_t get_device_fs() {
+ call_once(&svc_connect_once_flag, connect_to_vulkan_loader_svc);
+
+ return device_fs;
+}
+
+int get_manifest_fs_fd(void) {
+ call_once(&svc_connect_once_flag, connect_to_vulkan_loader_svc);
+
+ return manifest_fs_fd;
+}
diff --git a/fuchsia/loader_service.h b/fuchsia/loader_service.h
new file mode 100644
index 0000000..715ffb6
--- /dev/null
+++ b/fuchsia/loader_service.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright (c) 2021 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef LOADER_SERVICE_H
+#define LOADER_SERVICE_H
+
+#include <fidl/fuchsia.vulkan.loader/cpp/wire.h>
+#include <zircon/types.h>
+
+#include "loader_fuchsia.h"
+
+// Returns a singleton handle to the fuchsia.vulkan.loader.Loader service. Does not transfer
+// ownership.
+fidl::WireSyncClient<fuchsia_vulkan_loader::Loader>& get_vulkan_loader_service();
+
+// Returns a singleton handle to the device fs retrieved from
+// fuchsia.vulkan.loader/Loader.ConnectToDeviceFs. Does not transfer ownership.
+zx_handle_t get_device_fs();
+
+#endif // LOADER_SERVICE_H
diff --git a/loader/cJSON.c b/loader/cJSON.c
index 04349fd..256cd94 100644
--- a/loader/cJSON.c
+++ b/loader/cJSON.c
@@ -27,6 +27,7 @@
/* JSON parser in C. */
#include <ctype.h>
+#include <fcntl.h>
#include <float.h>
#include <limits.h>
#include <math.h>
@@ -933,7 +934,7 @@
return c;
}
-VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) {
+VkResult loader_get_json(const struct loader_instance *inst, int dir_fd, const char *filename, cJSON **json) {
FILE *file = NULL;
char *json_buf = NULL;
size_t len;
@@ -954,11 +955,27 @@
}
}
}
-#elif COMMON_UNIX_PLATFORMS
- file = fopen(filename, "rb");
+#else
+#if !defined(__Fuchsia__)
+ assert(dir_fd < 0);
+#endif
+
+ if (dir_fd >= 0) {
+ int file_fd = openat(dir_fd, filename, O_RDONLY);
+ if (file_fd < 0) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Failed to open JSON file \"%s\"", filename);
+ res = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+ file = fdopen(file_fd, "rb");
+ } else {
+#if COMMON_UNIX_PLATFORMS
+ file = fopen(filename, "rb");
#else
#warning fopen not available on this platform
#endif
+ }
+#endif
if (!file) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to open JSON file %s", filename);
diff --git a/loader/cJSON.h b/loader/cJSON.h
index 4878288..0b24894 100644
--- a/loader/cJSON.h
+++ b/loader/cJSON.h
@@ -93,7 +93,7 @@
//
// @return - A pointer to a cJSON object representing the JSON parse tree.
// This returned buffer should be freed by caller.
-VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json);
+VkResult loader_get_json(const struct loader_instance *inst, int dir_fd, const char *filename, cJSON **json);
// Given a cJSON object, find the string associated with the key and puts an pre-allocated string into out_string.
// Length is given by out_str_len, and this function truncates the string with a null terminator if it the provided space isn't
diff --git a/loader/loader.c b/loader/loader.c
index 471a7d8..29eac46 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -28,6 +28,7 @@
#include "loader.h"
+#include <fcntl.h>
#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
@@ -69,6 +70,10 @@
#include "loader_linux.h"
#endif // LOADER_ENABLE_LINUX_SORT
+#if defined(__Fuchsia__)
+#include "loader_fuchsia.h"
+#endif
+
// Generated file containing all the extension data
#include "vk_loader_extensions.c"
@@ -1662,6 +1667,11 @@
goto out;
}
+#if defined(__Fuchsia__)
+ loader_initialize_icd_services(handle);
+#endif
+
+ // Get and settle on an ICD interface version
// Try to load the driver's exported vk_icdNegotiateLoaderICDInterfaceVersion
fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
@@ -1839,6 +1849,9 @@
windows_initialization();
#endif
+#if defined(__Fuchsia__)
+ fuchsia_initialize();
+#endif
loader_api_version version = loader_make_full_version(VK_HEADER_VERSION_COMPLETE);
loader_log(NULL, VULKAN_LOADER_INFO_BIT, 0, "Vulkan Loader Version %d.%d.%d", version.major, version.minor, version.patch);
@@ -1864,6 +1877,10 @@
// Guarantee release of the preloaded ICD libraries. This may have already been called in vkDestroyInstance.
loader_unload_preloaded_icds();
+#if defined(__Fuchsia__)
+ fuchsia_teardown();
+#endif
+
// release mutexes
teardown_global_loader_settings();
loader_platform_thread_delete_mutex(&loader_lock);
@@ -2181,6 +2198,8 @@
struct loader_layer_properties *props = &instance_layers->list[i];
if (strcmp(props->info.layerName, VK_OVERRIDE_LAYER_NAME) == 0) {
if (props->app_key_paths.count > 0) { // not the global layer
+ // cur_path is unset on Fuchsia, so app_key_path is not supported.
+#if !defined(__Fuchsia__)
for (uint32_t j = 0; j < props->app_key_paths.count; j++) {
if (strcmp(props->app_key_paths.list[j], cur_path) == 0) {
if (!found_active_override_layer) {
@@ -2197,6 +2216,7 @@
}
}
}
+#endif
if (!found_active_override_layer) {
loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
"--Override layer found but not used because app \'%s\' is not in \'app_keys\' list!", cur_path);
@@ -2844,7 +2864,7 @@
// Add any files found in the search_path. If any path in the search path points to a specific JSON, attempt to
// only open that one JSON. Otherwise, if the path is a folder, search the folder for JSON files.
-VkResult add_data_files(const struct loader_instance *inst, char *search_path, struct loader_string_list *out_files,
+VkResult add_data_files(const struct loader_instance *inst, int dir_fd, char *search_path, struct loader_string_list *out_files,
bool use_first_found_manifest) {
VkResult vk_result = VK_SUCCESS;
DIR *dir_stream = NULL;
@@ -2856,6 +2876,9 @@
#if !defined(_WIN32)
char temp_path[2048];
#endif
+#if !defined(__Fuchsia__)
+ assert(dir_fd < 0);
+#endif
// Now, parse the paths
next_file = search_path;
@@ -2900,7 +2923,12 @@
break;
}
} else { // Otherwise, treat it as a directory
- dir_stream = loader_opendir(inst, cur_file);
+ if (dir_fd >= 0) {
+ int new_dir_fd = openat(dir_fd, cur_file, O_DIRECTORY);
+ dir_stream = fdopendir(new_dir_fd);
+ } else {
+ dir_stream = loader_opendir(inst, cur_file);
+ }
if (NULL == dir_stream) {
continue;
}
@@ -2956,6 +2984,7 @@
char *relative_location = NULL; // Only used on unix platforms
size_t rel_size = 0; // unused in windows, dont declare so no compiler warnings are generated
#endif
+ int dir_fd = -1;
#if defined(_WIN32)
char *package_path = NULL;
@@ -3073,6 +3102,15 @@
override_path = override_env;
}
+#if defined(__Fuchsia__)
+ if (!override_path && manifest_type == LOADER_DATA_FILE_MANIFEST_DRIVER) {
+ dir_fd = get_manifest_fs_fd();
+ if (dir_fd >= 0) {
+ override_path = ".";
+ }
+ }
+#endif
+
// Add two by default for NULL terminator and one path separator on end (just in case)
search_path_size = 2;
@@ -3261,7 +3299,7 @@
}
// Now, parse the paths and add any manifest files found in them.
- vk_result = add_data_files(inst, search_path, out_files, use_first_found_manifest);
+ vk_result = add_data_files(inst, dir_fd, search_path, out_files, use_first_found_manifest);
if (log_flags != 0 && out_files->count > 0) {
loader_log(inst, log_flags, 0, " Found the following files:");
@@ -3385,7 +3423,7 @@
// Takes a json file, opens, reads, and parses an ICD Manifest out of it.
// Should only return VK_SUCCESS, VK_ERROR_INCOMPATIBLE_DRIVER, or VK_ERROR_OUT_OF_HOST_MEMORY
-VkResult loader_parse_icd_manifest(const struct loader_instance *inst, char *file_str, struct ICDManifestInfo *icd,
+VkResult loader_parse_icd_manifest(const struct loader_instance *inst, int dir_fd, char *file_str, struct ICDManifestInfo *icd,
bool *skipped_portability_drivers) {
VkResult res = VK_SUCCESS;
cJSON *json = NULL;
@@ -3397,7 +3435,7 @@
goto out;
}
- res = loader_get_json(inst, file_str, &json);
+ res = loader_get_json(inst, dir_fd, file_str, &json);
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
goto out;
}
@@ -3602,9 +3640,13 @@
memset(icd_details, 0, sizeof(struct ICDManifestInfo) * manifest_files.count);
for (uint32_t i = 0; i < manifest_files.count; i++) {
+ int dir_fd = -1;
+#if defined(__Fuchsia__)
+ dir_fd = get_manifest_fs_fd();
+#endif
VkResult icd_res = VK_SUCCESS;
- icd_res = loader_parse_icd_manifest(inst, manifest_files.list[i], &icd_details[i], skipped_portability_drivers);
+ icd_res = loader_parse_icd_manifest(inst, dir_fd, manifest_files.list[i], &icd_details[i], skipped_portability_drivers);
if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_res) {
res = icd_res;
goto out;
@@ -3706,7 +3748,7 @@
// Parse file into JSON struct
cJSON *json = NULL;
- VkResult local_res = loader_get_json(inst, file_str, &json);
+ VkResult local_res = loader_get_json(inst, -1, file_str, &json);
if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
@@ -5006,7 +5048,8 @@
prop = loader_find_layer_property(ppEnabledLayerNames[i], list);
if (NULL == prop) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
- "loader_validate_layers: Layer %d does not exist in the list of available layers", i);
+ "loader_validate_layers: Layer at index %d (%s) does not exist in the list of available layers", i,
+ ppEnabledLayerNames[i]);
return VK_ERROR_LAYER_NOT_PRESENT;
}
if (inst->settings.settings_active && prop->settings_control_value != LOADER_SETTINGS_LAYER_CONTROL_ON &&
diff --git a/loader/loader.h b/loader/loader.h
index 93346a9..87cc753 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -32,6 +32,10 @@
#include "loader_common.h"
#include "cJSON.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// Declare the once_init variable
LOADER_PLATFORM_THREAD_ONCE_EXTERN_DEFINITION(once_init)
@@ -201,8 +205,9 @@
VkPhysicalDeviceGroupProperties *groups);
VkStringErrorFlags vk_string_validate(const int max_length, const char *char_array);
+
char *loader_get_next_path(char *path);
-VkResult add_data_files(const struct loader_instance *inst, char *search_path, struct loader_string_list *out_files,
+VkResult add_data_files(const struct loader_instance *inst, int dir_fd, char *search_path, struct loader_string_list *out_files,
bool use_first_found_manifest);
loader_api_version loader_make_version(uint32_t version);
@@ -219,3 +224,11 @@
#if !defined(LOADER_VERSION_1_1_0)
#define LOADER_VERSION_1_1_0 loader_combine_version(1, 1, 0)
#endif
+
+#if defined(__Fuchsia__)
+void loader_initialize_icd_services(loader_platform_dl_handle handle);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/loader/log.h b/loader/log.h
index 58db918..7c7522c 100644
--- a/loader/log.h
+++ b/loader/log.h
@@ -35,6 +35,10 @@
struct loader_instance;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum vulkan_loader_debug_flags {
VULKAN_LOADER_INFO_BIT = 0x01,
VULKAN_LOADER_WARN_BIT = 0x02,
@@ -75,3 +79,7 @@
const char *func_name) ASM_NAME("loader_log_asm_function_not_supported");
#undef ASM_NAME
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/loader/settings.c b/loader/settings.c
index c12ebac..f7780c7 100644
--- a/loader/settings.c
+++ b/loader/settings.c
@@ -312,7 +312,7 @@
#warning "Unsupported platform - must specify platform specific location for vk_loader_settings.json"
#endif
- res = loader_get_json(inst, settings_file_path, &json);
+ res = loader_get_json(inst, -1, settings_file_path, &json);
// Make sure sure the top level json value is an object
if (res != VK_SUCCESS || NULL == json || json->type != 6) {
goto out;
@@ -567,7 +567,7 @@
}
cJSON* json = NULL;
- VkResult local_res = loader_get_json(inst, layer_config->path, &json);
+ VkResult local_res = loader_get_json(inst, -1, layer_config->path, &json);
if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h
index 3a8cafb..aa8aa6d 100644
--- a/loader/vk_loader_platform.h
+++ b/loader/vk_loader_platform.h
@@ -55,6 +55,8 @@
#include <pthread.h>
#include <stdlib.h>
#include <libgen.h>
+#include <stdio.h>
+#include <unistd.h>
#elif defined(_WIN32)
// WinBase.h defines CreateSemaphore and synchapi.h defines CreateEvent
@@ -312,7 +314,15 @@
return buffer;
}
-#elif defined(__Fuchsia__) || defined(__OpenBSD__)
+#elif defined(__Fuchsia__)
+static inline char *loader_platform_executable_path(char *buffer, size_t size) {
+ if (size < 1)
+ return NULL;
+ // Fuchsia doesn't support getting the executable path. The blank path should match no layers.
+ buffer[0] = '\0';
+ return buffer;
+}
+#elif defined(__OpenBSD__)
static inline char *loader_platform_executable_path(char *buffer, size_t size) { return NULL; }
#elif defined(__QNX__)
@@ -378,7 +388,11 @@
}
static inline void loader_platform_close_library(loader_platform_dl_handle library) {
if (!loader_disable_dynamic_library_unloading) {
+#if defined(__Fuchsia__)
+ dlclose_fuchsia(library);
+#else
dlclose(library);
+#endif
} else {
(void)library;
}
diff --git a/scripts/loader_extension_generator.py b/scripts/loader_extension_generator.py
index c52ca88..be9d22b 100644
--- a/scripts/loader_extension_generator.py
+++ b/scripts/loader_extension_generator.py
@@ -44,6 +44,7 @@
'VK_KHR_swapchain',
'VK_KHR_display_swapchain',
'VK_KHR_get_display_properties2',
+ 'VK_FUCHSIA_imagepipe_surface',
'VK_KHR_get_surface_capabilities2',
'VK_QNX_screen_surface',
'VK_NN_vi_surface']
diff --git a/vulkan.ifs b/vulkan.ifs
new file mode 100644
index 0000000..7ca217b
--- /dev/null
+++ b/vulkan.ifs
@@ -0,0 +1,250 @@
+--- !ifs-v1
+IfsVersion: 3.0
+SoName: libvulkan.so
+Symbols:
+ - { Name: vkAcquireNextImage2KHR, Type: Func }
+ - { Name: vkAcquireNextImageKHR, Type: Func }
+ - { Name: vkAllocateCommandBuffers, Type: Func }
+ - { Name: vkAllocateDescriptorSets, Type: Func }
+ - { Name: vkAllocateMemory, Type: Func }
+ - { Name: vkBeginCommandBuffer, Type: Func }
+ - { Name: vkBindBufferMemory, Type: Func }
+ - { Name: vkBindBufferMemory2, Type: Func }
+ - { Name: vkBindImageMemory, Type: Func }
+ - { Name: vkBindImageMemory2, Type: Func }
+ - { Name: vkCmdBeginQuery, Type: Func }
+ - { Name: vkCmdBeginRenderPass, Type: Func }
+ - { Name: vkCmdBeginRenderPass2, Type: Func }
+ - { Name: vkCmdBeginRendering, Type: Func }
+ - { Name: vkCmdBindDescriptorSets, Type: Func }
+ - { Name: vkCmdBindIndexBuffer, Type: Func }
+ - { Name: vkCmdBindPipeline, Type: Func }
+ - { Name: vkCmdBindVertexBuffers, Type: Func }
+ - { Name: vkCmdBindVertexBuffers2, Type: Func }
+ - { Name: vkCmdBlitImage, Type: Func }
+ - { Name: vkCmdBlitImage2, Type: Func }
+ - { Name: vkCmdClearAttachments, Type: Func }
+ - { Name: vkCmdClearColorImage, Type: Func }
+ - { Name: vkCmdClearDepthStencilImage, Type: Func }
+ - { Name: vkCmdCopyBuffer, Type: Func }
+ - { Name: vkCmdCopyBuffer2, Type: Func }
+ - { Name: vkCmdCopyBufferToImage, Type: Func }
+ - { Name: vkCmdCopyBufferToImage2, Type: Func }
+ - { Name: vkCmdCopyImage, Type: Func }
+ - { Name: vkCmdCopyImage2, Type: Func }
+ - { Name: vkCmdCopyImageToBuffer, Type: Func }
+ - { Name: vkCmdCopyImageToBuffer2, Type: Func }
+ - { Name: vkCmdCopyQueryPoolResults, Type: Func }
+ - { Name: vkCmdDispatch, Type: Func }
+ - { Name: vkCmdDispatchBase, Type: Func }
+ - { Name: vkCmdDispatchIndirect, Type: Func }
+ - { Name: vkCmdDraw, Type: Func }
+ - { Name: vkCmdDrawIndexed, Type: Func }
+ - { Name: vkCmdDrawIndexedIndirect, Type: Func }
+ - { Name: vkCmdDrawIndexedIndirectCount, Type: Func }
+ - { Name: vkCmdDrawIndirect, Type: Func }
+ - { Name: vkCmdDrawIndirectCount, Type: Func }
+ - { Name: vkCmdEndQuery, Type: Func }
+ - { Name: vkCmdEndRenderPass, Type: Func }
+ - { Name: vkCmdEndRenderPass2, Type: Func }
+ - { Name: vkCmdEndRendering, Type: Func }
+ - { Name: vkCmdExecuteCommands, Type: Func }
+ - { Name: vkCmdFillBuffer, Type: Func }
+ - { Name: vkCmdNextSubpass, Type: Func }
+ - { Name: vkCmdNextSubpass2, Type: Func }
+ - { Name: vkCmdPipelineBarrier, Type: Func }
+ - { Name: vkCmdPipelineBarrier2, Type: Func }
+ - { Name: vkCmdPushConstants, Type: Func }
+ - { Name: vkCmdResetEvent, Type: Func }
+ - { Name: vkCmdResetEvent2, Type: Func }
+ - { Name: vkCmdResetQueryPool, Type: Func }
+ - { Name: vkCmdResolveImage, Type: Func }
+ - { Name: vkCmdResolveImage2, Type: Func }
+ - { Name: vkCmdSetBlendConstants, Type: Func }
+ - { Name: vkCmdSetCullMode, Type: Func }
+ - { Name: vkCmdSetDepthBias, Type: Func }
+ - { Name: vkCmdSetDepthBiasEnable, Type: Func }
+ - { Name: vkCmdSetDepthBounds, Type: Func }
+ - { Name: vkCmdSetDepthBoundsTestEnable, Type: Func }
+ - { Name: vkCmdSetDepthCompareOp, Type: Func }
+ - { Name: vkCmdSetDepthTestEnable, Type: Func }
+ - { Name: vkCmdSetDepthWriteEnable, Type: Func }
+ - { Name: vkCmdSetDeviceMask, Type: Func }
+ - { Name: vkCmdSetEvent, Type: Func }
+ - { Name: vkCmdSetEvent2, Type: Func }
+ - { Name: vkCmdSetFrontFace, Type: Func }
+ - { Name: vkCmdSetLineWidth, Type: Func }
+ - { Name: vkCmdSetPrimitiveRestartEnable, Type: Func }
+ - { Name: vkCmdSetPrimitiveTopology, Type: Func }
+ - { Name: vkCmdSetRasterizerDiscardEnable, Type: Func }
+ - { Name: vkCmdSetScissor, Type: Func }
+ - { Name: vkCmdSetScissorWithCount, Type: Func }
+ - { Name: vkCmdSetStencilCompareMask, Type: Func }
+ - { Name: vkCmdSetStencilOp, Type: Func }
+ - { Name: vkCmdSetStencilReference, Type: Func }
+ - { Name: vkCmdSetStencilTestEnable, Type: Func }
+ - { Name: vkCmdSetStencilWriteMask, Type: Func }
+ - { Name: vkCmdSetViewport, Type: Func }
+ - { Name: vkCmdSetViewportWithCount, Type: Func }
+ - { Name: vkCmdUpdateBuffer, Type: Func }
+ - { Name: vkCmdWaitEvents, Type: Func }
+ - { Name: vkCmdWaitEvents2, Type: Func }
+ - { Name: vkCmdWriteTimestamp, Type: Func }
+ - { Name: vkCmdWriteTimestamp2, Type: Func }
+ - { Name: vkCreateBuffer, Type: Func }
+ - { Name: vkCreateBufferView, Type: Func }
+ - { Name: vkCreateCommandPool, Type: Func }
+ - { Name: vkCreateComputePipelines, Type: Func }
+ - { Name: vkCreateDescriptorPool, Type: Func }
+ - { Name: vkCreateDescriptorSetLayout, Type: Func }
+ - { Name: vkCreateDescriptorUpdateTemplate, Type: Func }
+ - { Name: vkCreateDevice, Type: Func }
+ - { Name: vkCreateDisplayModeKHR, Type: Func }
+ - { Name: vkCreateDisplayPlaneSurfaceKHR, Type: Func }
+ - { Name: vkCreateEvent, Type: Func }
+ - { Name: vkCreateFence, Type: Func }
+ - { Name: vkCreateFramebuffer, Type: Func }
+ - { Name: vkCreateGraphicsPipelines, Type: Func }
+ - { Name: vkCreateHeadlessSurfaceEXT, Type: Func }
+ - { Name: vkCreateImage, Type: Func }
+ - { Name: vkCreateImagePipeSurfaceFUCHSIA, Type: Func }
+ - { Name: vkCreateImageView, Type: Func }
+ - { Name: vkCreateInstance, Type: Func }
+ - { Name: vkCreatePipelineCache, Type: Func }
+ - { Name: vkCreatePipelineLayout, Type: Func }
+ - { Name: vkCreatePrivateDataSlot, Type: Func }
+ - { Name: vkCreateQueryPool, Type: Func }
+ - { Name: vkCreateRenderPass, Type: Func }
+ - { Name: vkCreateRenderPass2, Type: Func }
+ - { Name: vkCreateSampler, Type: Func }
+ - { Name: vkCreateSamplerYcbcrConversion, Type: Func }
+ - { Name: vkCreateSemaphore, Type: Func }
+ - { Name: vkCreateShaderModule, Type: Func }
+ - { Name: vkCreateSharedSwapchainsKHR, Type: Func }
+ - { Name: vkCreateSwapchainKHR, Type: Func }
+ - { Name: vkDestroyBuffer, Type: Func }
+ - { Name: vkDestroyBufferView, Type: Func }
+ - { Name: vkDestroyCommandPool, Type: Func }
+ - { Name: vkDestroyDescriptorPool, Type: Func }
+ - { Name: vkDestroyDescriptorSetLayout, Type: Func }
+ - { Name: vkDestroyDescriptorUpdateTemplate, Type: Func }
+ - { Name: vkDestroyDevice, Type: Func }
+ - { Name: vkDestroyEvent, Type: Func }
+ - { Name: vkDestroyFence, Type: Func }
+ - { Name: vkDestroyFramebuffer, Type: Func }
+ - { Name: vkDestroyImage, Type: Func }
+ - { Name: vkDestroyImageView, Type: Func }
+ - { Name: vkDestroyInstance, Type: Func }
+ - { Name: vkDestroyPipeline, Type: Func }
+ - { Name: vkDestroyPipelineCache, Type: Func }
+ - { Name: vkDestroyPipelineLayout, Type: Func }
+ - { Name: vkDestroyPrivateDataSlot, Type: Func }
+ - { Name: vkDestroyQueryPool, Type: Func }
+ - { Name: vkDestroyRenderPass, Type: Func }
+ - { Name: vkDestroySampler, Type: Func }
+ - { Name: vkDestroySamplerYcbcrConversion, Type: Func }
+ - { Name: vkDestroySemaphore, Type: Func }
+ - { Name: vkDestroyShaderModule, Type: Func }
+ - { Name: vkDestroySurfaceKHR, Type: Func }
+ - { Name: vkDestroySwapchainKHR, Type: Func }
+ - { Name: vkDeviceWaitIdle, Type: Func }
+ - { Name: vkEndCommandBuffer, Type: Func }
+ - { Name: vkEnumerateDeviceExtensionProperties, Type: Func }
+ - { Name: vkEnumerateDeviceLayerProperties, Type: Func }
+ - { Name: vkEnumerateInstanceExtensionProperties, Type: Func }
+ - { Name: vkEnumerateInstanceLayerProperties, Type: Func }
+ - { Name: vkEnumerateInstanceVersion, Type: Func }
+ - { Name: vkEnumeratePhysicalDeviceGroups, Type: Func }
+ - { Name: vkEnumeratePhysicalDevices, Type: Func }
+ - { Name: vkFlushMappedMemoryRanges, Type: Func }
+ - { Name: vkFreeCommandBuffers, Type: Func }
+ - { Name: vkFreeDescriptorSets, Type: Func }
+ - { Name: vkFreeMemory, Type: Func }
+ - { Name: vkGetBufferDeviceAddress, Type: Func }
+ - { Name: vkGetBufferMemoryRequirements, Type: Func }
+ - { Name: vkGetBufferMemoryRequirements2, Type: Func }
+ - { Name: vkGetBufferOpaqueCaptureAddress, Type: Func }
+ - { Name: vkGetDescriptorSetLayoutSupport, Type: Func }
+ - { Name: vkGetDeviceBufferMemoryRequirements, Type: Func }
+ - { Name: vkGetDeviceGroupPeerMemoryFeatures, Type: Func }
+ - { Name: vkGetDeviceGroupPresentCapabilitiesKHR, Type: Func }
+ - { Name: vkGetDeviceGroupSurfacePresentModesKHR, Type: Func }
+ - { Name: vkGetDeviceImageMemoryRequirements, Type: Func }
+ - { Name: vkGetDeviceImageSparseMemoryRequirements, Type: Func }
+ - { Name: vkGetDeviceMemoryCommitment, Type: Func }
+ - { Name: vkGetDeviceMemoryOpaqueCaptureAddress, Type: Func }
+ - { Name: vkGetDeviceProcAddr, Type: Func }
+ - { Name: vkGetDeviceQueue, Type: Func }
+ - { Name: vkGetDeviceQueue2, Type: Func }
+ - { Name: vkGetDisplayModeProperties2KHR, Type: Func }
+ - { Name: vkGetDisplayModePropertiesKHR, Type: Func }
+ - { Name: vkGetDisplayPlaneCapabilities2KHR, Type: Func }
+ - { Name: vkGetDisplayPlaneCapabilitiesKHR, Type: Func }
+ - { Name: vkGetDisplayPlaneSupportedDisplaysKHR, Type: Func }
+ - { Name: vkGetEventStatus, Type: Func }
+ - { Name: vkGetFenceStatus, Type: Func }
+ - { Name: vkGetImageMemoryRequirements, Type: Func }
+ - { Name: vkGetImageMemoryRequirements2, Type: Func }
+ - { Name: vkGetImageSparseMemoryRequirements, Type: Func }
+ - { Name: vkGetImageSparseMemoryRequirements2, Type: Func }
+ - { Name: vkGetImageSubresourceLayout, Type: Func }
+ - { Name: vkGetInstanceProcAddr, Type: Func }
+ - { Name: vkGetPhysicalDeviceDisplayPlaneProperties2KHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceDisplayPlanePropertiesKHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceDisplayProperties2KHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceDisplayPropertiesKHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceExternalBufferProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceExternalFenceProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceExternalSemaphoreProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceFeatures, Type: Func }
+ - { Name: vkGetPhysicalDeviceFeatures2, Type: Func }
+ - { Name: vkGetPhysicalDeviceFormatProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceFormatProperties2, Type: Func }
+ - { Name: vkGetPhysicalDeviceImageFormatProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceImageFormatProperties2, Type: Func }
+ - { Name: vkGetPhysicalDeviceMemoryProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceMemoryProperties2, Type: Func }
+ - { Name: vkGetPhysicalDevicePresentRectanglesKHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceProperties2, Type: Func }
+ - { Name: vkGetPhysicalDeviceQueueFamilyProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceQueueFamilyProperties2, Type: Func }
+ - { Name: vkGetPhysicalDeviceSparseImageFormatProperties, Type: Func }
+ - { Name: vkGetPhysicalDeviceSparseImageFormatProperties2, Type: Func }
+ - { Name: vkGetPhysicalDeviceSurfaceCapabilities2KHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceSurfaceCapabilitiesKHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceSurfaceFormats2KHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceSurfaceFormatsKHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceSurfacePresentModesKHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceSurfaceSupportKHR, Type: Func }
+ - { Name: vkGetPhysicalDeviceToolProperties, Type: Func }
+ - { Name: vkGetPipelineCacheData, Type: Func }
+ - { Name: vkGetPrivateData, Type: Func }
+ - { Name: vkGetQueryPoolResults, Type: Func }
+ - { Name: vkGetRenderAreaGranularity, Type: Func }
+ - { Name: vkGetSemaphoreCounterValue, Type: Func }
+ - { Name: vkGetSwapchainImagesKHR, Type: Func }
+ - { Name: vkInvalidateMappedMemoryRanges, Type: Func }
+ - { Name: vkMapMemory, Type: Func }
+ - { Name: vkMergePipelineCaches, Type: Func }
+ - { Name: vkQueueBindSparse, Type: Func }
+ - { Name: vkQueuePresentKHR, Type: Func }
+ - { Name: vkQueueSubmit, Type: Func }
+ - { Name: vkQueueSubmit2, Type: Func }
+ - { Name: vkQueueWaitIdle, Type: Func }
+ - { Name: vkResetCommandBuffer, Type: Func }
+ - { Name: vkResetCommandPool, Type: Func }
+ - { Name: vkResetDescriptorPool, Type: Func }
+ - { Name: vkResetEvent, Type: Func }
+ - { Name: vkResetFences, Type: Func }
+ - { Name: vkResetQueryPool, Type: Func }
+ - { Name: vkSetEvent, Type: Func }
+ - { Name: vkSetPrivateData, Type: Func }
+ - { Name: vkSignalSemaphore, Type: Func }
+ - { Name: vkTrimCommandPool, Type: Func }
+ - { Name: vkUnmapMemory, Type: Func }
+ - { Name: vkUpdateDescriptorSetWithTemplate, Type: Func }
+ - { Name: vkUpdateDescriptorSets, Type: Func }
+ - { Name: vkWaitForFences, Type: Func }
+ - { Name: vkWaitSemaphores, Type: Func }
+...