mirror of
https://github.com/openharmony/third_party_vulkan-loader.git
synced 2026-07-20 20:15:56 -04:00
89db313139
Signed-off-by: ZhangLiang <zhangliang335@h-partners.com>
539 lines
21 KiB
C++
539 lines
21 KiB
C++
/*
|
|
* Copyright (c) 2021-2023 The Khronos Group Inc.
|
|
* Copyright (c) 2021-2023 Valve Corporation
|
|
* Copyright (c) 2021-2023 LunarG, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and/or associated documentation files (the "Materials"), to
|
|
* deal in the Materials without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Materials, and to permit persons to whom the Materials are
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice(s) and this permission notice shall be included in
|
|
* all copies or substantial portions of the Materials.
|
|
*
|
|
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
*
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
|
|
* USE OR OTHER DEALINGS IN THE MATERIALS.
|
|
*
|
|
* Author: Charles Giessen <charles@lunarg.com>
|
|
*/
|
|
|
|
#include "test_util.h"
|
|
|
|
#include <fstream>
|
|
|
|
#if defined(WIN32)
|
|
#include <wchar.h>
|
|
#include <strsafe.h>
|
|
const char* win_api_error_str(LSTATUS status) {
|
|
if (status == ERROR_INVALID_FUNCTION) return "ERROR_INVALID_FUNCTION";
|
|
if (status == ERROR_FILE_NOT_FOUND) return "ERROR_FILE_NOT_FOUND";
|
|
if (status == ERROR_PATH_NOT_FOUND) return "ERROR_PATH_NOT_FOUND";
|
|
if (status == ERROR_TOO_MANY_OPEN_FILES) return "ERROR_TOO_MANY_OPEN_FILES";
|
|
if (status == ERROR_ACCESS_DENIED) return "ERROR_ACCESS_DENIED";
|
|
if (status == ERROR_INVALID_HANDLE) return "ERROR_INVALID_HANDLE";
|
|
if (status == ERROR_ENVVAR_NOT_FOUND) return "ERROR_ENVVAR_NOT_FOUND";
|
|
if (status == ERROR_SETENV_FAILED) return "ERROR_SETENV_FAILED";
|
|
return "UNKNOWN ERROR";
|
|
}
|
|
|
|
void print_error_message(LSTATUS status, const char* function_name, std::string optional_message) {
|
|
LPVOID lpMsgBuf;
|
|
DWORD dw = GetLastError();
|
|
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, dw,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
|
|
|
|
std::cerr << function_name << " failed with " << win_api_error_str(status) << ": "
|
|
<< std::string(reinterpret_cast<LPTSTR>(lpMsgBuf));
|
|
if (optional_message != "") {
|
|
std::cerr << " | " << optional_message;
|
|
}
|
|
std::cerr << "\n";
|
|
LocalFree(lpMsgBuf);
|
|
}
|
|
|
|
void EnvVarWrapper::set_env_var() {
|
|
BOOL ret = SetEnvironmentVariableW(widen(name).c_str(), widen(cur_value).c_str());
|
|
if (ret == 0) {
|
|
print_error_message(ERROR_SETENV_FAILED, "SetEnvironmentVariableW");
|
|
}
|
|
}
|
|
void EnvVarWrapper::remove_env_var() const { SetEnvironmentVariableW(widen(name).c_str(), nullptr); }
|
|
std::string get_env_var(std::string const& name, bool report_failure) {
|
|
std::wstring name_utf16 = widen(name);
|
|
DWORD value_size = GetEnvironmentVariableW(name_utf16.c_str(), nullptr, 0);
|
|
if (0 == value_size) {
|
|
if (report_failure) print_error_message(ERROR_ENVVAR_NOT_FOUND, "GetEnvironmentVariableW");
|
|
return {};
|
|
}
|
|
std::wstring value(value_size, L'\0');
|
|
if (GetEnvironmentVariableW(name_utf16.c_str(), &value[0], value_size) != value_size - 1) {
|
|
return {};
|
|
}
|
|
return narrow(value);
|
|
}
|
|
#elif COMMON_UNIX_PLATFORMS
|
|
|
|
void EnvVarWrapper::set_env_var() { setenv(name.c_str(), cur_value.c_str(), 1); }
|
|
void EnvVarWrapper::remove_env_var() const { unsetenv(name.c_str()); }
|
|
std::string get_env_var(std::string const& name, bool report_failure) {
|
|
char* ret = getenv(name.c_str());
|
|
if (ret == nullptr) {
|
|
if (report_failure) std::cerr << "Failed to get environment variable:" << name << "\n";
|
|
return std::string();
|
|
}
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
template <typename T>
|
|
void print_object_of_t(JsonWriter& writer, const char* object_name, std::vector<T> const& vec) {
|
|
if (vec.size() == 0) return;
|
|
writer.StartKeyedObject(object_name);
|
|
for (auto& element : vec) {
|
|
element.get_manifest_str(writer);
|
|
}
|
|
writer.EndObject();
|
|
}
|
|
|
|
template <typename T>
|
|
void print_array_of_t(JsonWriter& writer, const char* object_name, std::vector<T> const& vec) {
|
|
if (vec.size() == 0) return;
|
|
writer.StartKeyedArray(object_name);
|
|
for (auto& element : vec) {
|
|
element.get_manifest_str(writer);
|
|
}
|
|
writer.EndArray();
|
|
}
|
|
void print_vector_of_strings(JsonWriter& writer, const char* object_name, std::vector<std::string> const& strings) {
|
|
if (strings.size() == 0) return;
|
|
writer.StartKeyedArray(object_name);
|
|
for (auto const& str : strings) {
|
|
writer.AddString(std::filesystem::path(str).native());
|
|
}
|
|
writer.EndArray();
|
|
}
|
|
void print_vector_of_strings(JsonWriter& writer, const char* object_name, std::vector<std::filesystem::path> const& paths) {
|
|
if (paths.size() == 0) return;
|
|
writer.StartKeyedArray(object_name);
|
|
for (auto const& path : paths) {
|
|
writer.AddString(path.native());
|
|
}
|
|
writer.EndArray();
|
|
}
|
|
|
|
std::string to_text(bool b) { return b ? std::string("true") : std::string("false"); }
|
|
|
|
std::string ManifestICD::get_manifest_str() const {
|
|
JsonWriter writer;
|
|
writer.StartObject();
|
|
writer.AddKeyedString("file_format_version", file_format_version.get_version_str());
|
|
writer.StartKeyedObject("ICD");
|
|
writer.AddKeyedString("library_path", lib_path.native());
|
|
writer.AddKeyedString("api_version", version_to_string(api_version));
|
|
writer.AddKeyedBool("is_portability_driver", is_portability_driver);
|
|
if (!library_arch.empty()) writer.AddKeyedString("library_arch", library_arch);
|
|
writer.EndObject();
|
|
writer.EndObject();
|
|
return writer.output;
|
|
}
|
|
|
|
void ManifestLayer::LayerDescription::Extension::get_manifest_str(JsonWriter& writer) const {
|
|
writer.StartObject();
|
|
writer.AddKeyedString("name", name);
|
|
writer.AddKeyedString("spec_version", std::to_string(spec_version));
|
|
writer.AddKeyedString("spec_version", std::to_string(spec_version));
|
|
print_vector_of_strings(writer, "entrypoints", entrypoints);
|
|
writer.EndObject();
|
|
}
|
|
|
|
void ManifestLayer::LayerDescription::get_manifest_str(JsonWriter& writer) const {
|
|
writer.AddKeyedString("name", name);
|
|
writer.AddKeyedString("type", get_type_str(type));
|
|
if (!lib_path.empty()) {
|
|
writer.AddKeyedString("library_path", lib_path.native());
|
|
}
|
|
writer.AddKeyedString("api_version", version_to_string(api_version));
|
|
writer.AddKeyedString("implementation_version", std::to_string(implementation_version));
|
|
writer.AddKeyedString("description", description);
|
|
print_object_of_t(writer, "functions", functions);
|
|
print_array_of_t(writer, "instance_extensions", instance_extensions);
|
|
print_array_of_t(writer, "device_extensions", device_extensions);
|
|
if (!enable_environment.empty()) {
|
|
writer.StartKeyedObject("enable_environment");
|
|
writer.AddKeyedString(enable_environment, "1");
|
|
writer.EndObject();
|
|
}
|
|
if (!disable_environment.empty()) {
|
|
writer.StartKeyedObject("disable_environment");
|
|
writer.AddKeyedString(disable_environment, "1");
|
|
writer.EndObject();
|
|
}
|
|
print_vector_of_strings(writer, "component_layers", component_layers);
|
|
print_vector_of_strings(writer, "blacklisted_layers", blacklisted_layers);
|
|
print_vector_of_strings(writer, "override_paths", override_paths);
|
|
print_vector_of_strings(writer, "app_keys", app_keys);
|
|
print_object_of_t(writer, "pre_instance_functions", pre_instance_functions);
|
|
if (!library_arch.empty()) {
|
|
writer.AddKeyedString("library_arch", library_arch);
|
|
}
|
|
}
|
|
|
|
VkLayerProperties ManifestLayer::LayerDescription::get_layer_properties() const {
|
|
VkLayerProperties properties{};
|
|
copy_string_to_char_array(name, properties.layerName, VK_MAX_EXTENSION_NAME_SIZE);
|
|
copy_string_to_char_array(description, properties.description, VK_MAX_EXTENSION_NAME_SIZE);
|
|
properties.implementationVersion = implementation_version;
|
|
properties.specVersion = api_version;
|
|
return properties;
|
|
}
|
|
|
|
std::string ManifestLayer::get_manifest_str() const {
|
|
JsonWriter writer;
|
|
writer.StartObject();
|
|
writer.AddKeyedString("file_format_version", file_format_version.get_version_str());
|
|
if (layers.size() == 1) {
|
|
writer.StartKeyedObject("layer");
|
|
layers.at(0).get_manifest_str(writer);
|
|
writer.EndObject();
|
|
} else {
|
|
writer.StartKeyedArray("layers");
|
|
for (size_t i = 0; i < layers.size(); i++) {
|
|
writer.StartObject();
|
|
layers.at(i).get_manifest_str(writer);
|
|
writer.EndObject();
|
|
}
|
|
writer.EndArray();
|
|
}
|
|
writer.EndObject();
|
|
return writer.output;
|
|
}
|
|
|
|
namespace fs {
|
|
// internal implementation helper for per-platform creating & destroying folders
|
|
int create_folder(std::filesystem::path const& path) {
|
|
#if defined(WIN32)
|
|
return _wmkdir(path.c_str());
|
|
#else
|
|
mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int delete_folder_contents(std::filesystem::path const& folder) {
|
|
#if defined(WIN32)
|
|
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(folder.c_str()) && GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
// nothing to delete
|
|
return 0;
|
|
}
|
|
std::filesystem::path search_path = folder / "*.*";
|
|
WIN32_FIND_DATAW fd;
|
|
HANDLE hFind = ::FindFirstFileW(search_path.c_str(), &fd);
|
|
if (hFind != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
std::filesystem::path file_name = fd.cFileName;
|
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
if (file_name != "." && file_name != "..") {
|
|
delete_folder(fd.cFileName);
|
|
}
|
|
} else {
|
|
DeleteFileW((folder / fd.cFileName).native().c_str());
|
|
}
|
|
} while (::FindNextFileW(hFind, &fd));
|
|
::FindClose(hFind);
|
|
}
|
|
return 0;
|
|
#else
|
|
DIR* dir = opendir(folder.c_str());
|
|
if (!dir) {
|
|
return 0;
|
|
}
|
|
int ret = 0;
|
|
dirent* file;
|
|
while (!ret && (file = readdir(dir))) {
|
|
int ret2 = -1;
|
|
|
|
/* Skip the names "." and ".." as we don't want to recurse on them. */
|
|
if (string_eq(file->d_name, ".") || string_eq(file->d_name, "..")) continue;
|
|
|
|
std::filesystem::path file_path = folder / file->d_name;
|
|
struct stat statbuf;
|
|
if (!stat(file_path.c_str(), &statbuf)) {
|
|
if (S_ISDIR(statbuf.st_mode))
|
|
ret2 = delete_folder(file_path);
|
|
else
|
|
ret2 = unlink(file_path.c_str());
|
|
}
|
|
|
|
ret = ret2;
|
|
}
|
|
closedir(dir);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
int delete_folder(std::filesystem::path const& folder) {
|
|
int ret = delete_folder_contents(folder);
|
|
if (ret != 0) return ret;
|
|
#if defined(WIN32)
|
|
_wrmdir(folder.native().c_str());
|
|
return 0;
|
|
#else
|
|
return rmdir(folder.c_str());
|
|
#endif
|
|
}
|
|
|
|
FolderManager::FolderManager(std::filesystem::path root_path, std::string name) noexcept : folder(root_path / name) {
|
|
delete_folder_contents(folder);
|
|
create_folder(folder);
|
|
}
|
|
FolderManager::~FolderManager() noexcept {
|
|
if (folder.empty()) return;
|
|
auto list_of_files_to_delete = files;
|
|
// remove(file) modifies the files variable, copy the list before deleting it
|
|
// Note: the allocation tests currently leak the loaded driver handles because in an OOM scenario the loader doesn't bother
|
|
// removing those. Since this is in an OOM situation, it is a low priority to fix. It does have the effect that Windows will
|
|
// be unable to delete the binaries that were leaked.
|
|
for (auto& file : list_of_files_to_delete) {
|
|
remove(file);
|
|
}
|
|
delete_folder(folder);
|
|
}
|
|
FolderManager::FolderManager(FolderManager&& other) noexcept : folder(other.folder), files(other.files) { other.folder.clear(); }
|
|
FolderManager& FolderManager::operator=(FolderManager&& other) noexcept {
|
|
folder = other.folder;
|
|
files = other.files;
|
|
other.folder.clear();
|
|
return *this;
|
|
}
|
|
|
|
std::filesystem::path FolderManager::write_manifest(std::filesystem::path const& name, std::string const& contents) {
|
|
std::filesystem::path out_path = folder / name;
|
|
auto found = std::find(files.begin(), files.end(), name);
|
|
if (found != files.end()) {
|
|
std::cout << "Overwriting manifest " << name << ". Was this intended?\n";
|
|
} else {
|
|
files.emplace_back(name);
|
|
}
|
|
auto file = std::ofstream(out_path, std::ios_base::trunc | std::ios_base::out);
|
|
if (!file) {
|
|
std::cerr << "Failed to create manifest " << name << " at " << out_path << "\n";
|
|
return out_path;
|
|
}
|
|
file << contents << std::endl;
|
|
return out_path;
|
|
}
|
|
void FolderManager::add_existing_file(std::filesystem::path const& file_name) { files.emplace_back(file_name); }
|
|
|
|
// close file handle, delete file, remove `name` from managed file list.
|
|
void FolderManager::remove(std::filesystem::path const& name) {
|
|
std::filesystem::path out_path = folder / name;
|
|
auto found = std::find(files.begin(), files.end(), name);
|
|
if (found != files.end()) {
|
|
#if defined(WIN32)
|
|
int rc = _wremove(out_path.c_str());
|
|
#else
|
|
int rc = std::remove(out_path.c_str());
|
|
#endif
|
|
if (rc != 0) {
|
|
std::cerr << "Failed to remove file " << name << " at " << out_path << "\n";
|
|
}
|
|
|
|
files.erase(found);
|
|
|
|
} else {
|
|
std::cout << "Couldn't remove file " << name << " at " << out_path << ".\n";
|
|
}
|
|
}
|
|
|
|
// copy file into this folder
|
|
std::filesystem::path FolderManager::copy_file(std::filesystem::path const& file, std::filesystem::path const& new_name) {
|
|
auto new_filepath = folder / new_name;
|
|
auto found = std::find(files.begin(), files.end(), new_name);
|
|
if (found != files.end()) {
|
|
std::cout << "File location already contains" << new_name << ". Is this a bug?\n";
|
|
} else if (file == new_filepath) {
|
|
std::cout << "Trying to copy " << new_name << " into itself. Is this a bug?\n";
|
|
} else {
|
|
files.emplace_back(new_name);
|
|
}
|
|
std::ifstream src(file, std::ios::binary);
|
|
if (!src) {
|
|
std::cerr << "Failed to create file " << file << " for copying from\n";
|
|
return new_filepath;
|
|
}
|
|
std::ofstream dst(new_filepath, std::ios::binary);
|
|
if (!dst) {
|
|
std::cerr << "Failed to create file " << new_filepath << " for copying to\n";
|
|
return new_filepath;
|
|
}
|
|
dst << src.rdbuf();
|
|
return new_filepath;
|
|
}
|
|
} // namespace fs
|
|
|
|
const char* get_platform_wsi_extension([[maybe_unused]] const char* api_selection) {
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
return "VK_KHR_android_surface";
|
|
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
|
|
return "VK_EXT_directfb_surface";
|
|
#elif defined(VK_USE_PLATFORM_FUCHSIA)
|
|
return "VK_FUCHSIA_imagepipe_surface";
|
|
#elif defined(VK_USE_PLATFORM_GGP)
|
|
return "VK_GGP_stream_descriptor_surface";
|
|
#elif defined(VK_USE_PLATFORM_IOS_MVK)
|
|
return "VK_MVK_ios_surface";
|
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)
|
|
#if defined(VK_USE_PLATFORM_MACOS_MVK)
|
|
if (string_eq(api_selection, "VK_USE_PLATFORM_MACOS_MVK")) return "VK_MVK_macos_surface";
|
|
#endif
|
|
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
|
if (string_eq(api_selection, "VK_USE_PLATFORM_METAL_EXT")) return "VK_EXT_metal_surface";
|
|
return "VK_EXT_metal_surface";
|
|
#endif
|
|
#elif defined(VK_USE_PLATFORM_SCREEN_QNX)
|
|
return "VK_QNX_screen_surface";
|
|
#elif defined(VK_USE_PLATFORM_VI_NN)
|
|
return "VK_NN_vi_surface";
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
#if defined(VK_USE_PLATFORM_XCB_KHR)
|
|
if (string_eq(api_selection, "VK_USE_PLATFORM_XCB_KHR")) return "VK_KHR_xcb_surface";
|
|
#endif
|
|
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
if (string_eq(api_selection, "VK_USE_PLATFORM_XLIB_KHR")) return "VK_KHR_xlib_surface";
|
|
#endif
|
|
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
if (string_eq(api_selection, "VK_USE_PLATFORM_WAYLAND_KHR")) return "VK_KHR_wayland_surface";
|
|
#endif
|
|
#if defined(VK_USE_PLATFORM_XCB_KHR)
|
|
return "VK_KHR_xcb_surface";
|
|
#endif
|
|
#elif defined(VK_USE_PLATFORM_WIN32_KHR)
|
|
return "VK_KHR_win32_surface";
|
|
#else
|
|
return "VK_KHR_display";
|
|
#endif
|
|
}
|
|
|
|
bool string_eq(const char* a, const char* b) noexcept { return a && b && strcmp(a, b) == 0; }
|
|
bool string_eq(const char* a, const char* b, size_t len) noexcept { return a && b && strncmp(a, b, len) == 0; }
|
|
|
|
InstanceCreateInfo::InstanceCreateInfo() {
|
|
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
}
|
|
|
|
VkInstanceCreateInfo* InstanceCreateInfo::get() noexcept {
|
|
if (fill_in_application_info) {
|
|
application_info.pApplicationName = app_name.c_str();
|
|
application_info.pEngineName = engine_name.c_str();
|
|
application_info.applicationVersion = app_version;
|
|
application_info.engineVersion = engine_version;
|
|
application_info.apiVersion = api_version;
|
|
instance_info.pApplicationInfo = &application_info;
|
|
}
|
|
instance_info.flags = flags;
|
|
instance_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
|
|
instance_info.ppEnabledLayerNames = enabled_layers.data();
|
|
instance_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
|
|
instance_info.ppEnabledExtensionNames = enabled_extensions.data();
|
|
return &instance_info;
|
|
}
|
|
InstanceCreateInfo& InstanceCreateInfo::set_api_version(uint32_t major, uint32_t minor, uint32_t patch) {
|
|
this->api_version = VK_MAKE_API_VERSION(0, major, minor, patch);
|
|
return *this;
|
|
}
|
|
InstanceCreateInfo& InstanceCreateInfo::setup_WSI(const char* api_selection) {
|
|
add_extensions({"VK_KHR_surface", get_platform_wsi_extension(api_selection)});
|
|
return *this;
|
|
}
|
|
|
|
DeviceQueueCreateInfo::DeviceQueueCreateInfo() { queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; }
|
|
DeviceQueueCreateInfo::DeviceQueueCreateInfo(const VkDeviceQueueCreateInfo* create_info) {
|
|
queue_create_info = *create_info;
|
|
for (uint32_t i = 0; i < create_info->queueCount; i++) {
|
|
priorities.push_back(create_info->pQueuePriorities[i]);
|
|
}
|
|
}
|
|
|
|
VkDeviceQueueCreateInfo DeviceQueueCreateInfo::get() noexcept {
|
|
queue_create_info.pQueuePriorities = priorities.data();
|
|
queue_create_info.queueCount = 1;
|
|
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
return queue_create_info;
|
|
}
|
|
|
|
DeviceCreateInfo::DeviceCreateInfo(const VkDeviceCreateInfo* create_info) {
|
|
dev = *create_info;
|
|
for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
|
|
enabled_extensions.push_back(create_info->ppEnabledExtensionNames[i]);
|
|
}
|
|
for (uint32_t i = 0; i < create_info->enabledLayerCount; i++) {
|
|
enabled_layers.push_back(create_info->ppEnabledLayerNames[i]);
|
|
}
|
|
for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
|
|
device_queue_infos.push_back(create_info->pQueueCreateInfos[i]);
|
|
}
|
|
}
|
|
|
|
VkDeviceCreateInfo* DeviceCreateInfo::get() noexcept {
|
|
dev.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
dev.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
|
|
dev.ppEnabledLayerNames = enabled_layers.data();
|
|
dev.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
|
|
dev.ppEnabledExtensionNames = enabled_extensions.data();
|
|
uint32_t index = 0;
|
|
for (auto& queue : queue_info_details) {
|
|
queue.queue_create_info.queueFamilyIndex = index++;
|
|
queue.queue_create_info.queueCount = 1;
|
|
device_queue_infos.push_back(queue.get());
|
|
}
|
|
|
|
dev.queueCreateInfoCount = static_cast<uint32_t>(device_queue_infos.size());
|
|
dev.pQueueCreateInfos = device_queue_infos.data();
|
|
return &dev;
|
|
}
|
|
|
|
#if defined(WIN32)
|
|
std::string narrow(const std::wstring& utf16) {
|
|
if (utf16.empty()) {
|
|
return {};
|
|
}
|
|
int size = WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()), nullptr, 0, nullptr, nullptr);
|
|
if (size <= 0) {
|
|
return {};
|
|
}
|
|
std::string utf8(size, '\0');
|
|
if (WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()), &utf8[0], size, nullptr, nullptr) != size) {
|
|
return {};
|
|
}
|
|
return utf8;
|
|
}
|
|
|
|
std::wstring widen(const std::string& utf8) {
|
|
if (utf8.empty()) {
|
|
return {};
|
|
}
|
|
int size = MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), nullptr, 0);
|
|
if (size <= 0) {
|
|
return {};
|
|
}
|
|
std::wstring utf16(size, L'\0');
|
|
if (MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), &utf16[0], size) != size) {
|
|
return {};
|
|
}
|
|
return utf16;
|
|
}
|
|
#else
|
|
std::string narrow(const std::string& utf16) { return utf16; }
|
|
std::string widen(const std::string& utf8) { return utf8; }
|
|
#endif
|