diff --git a/src/vulkan/wrapper/graphics_env_hooks.cpp b/src/vulkan/wrapper/graphics_env_hooks.cpp new file mode 100644 index 00000000000..e383da72bb9 --- /dev/null +++ b/src/vulkan/wrapper/graphics_env_hooks.cpp @@ -0,0 +1,60 @@ +#include "graphics_env_hooks.h" +#include +#include +#include +#include + +extern "C" { +#include "wrapper_log.h" +#include "wrapper_debug.h" +} + +#define PATH "/data/data/com.winlator.cmod/files/imagefs/usr/lib" + +extern "C" +bool set_layer_paths() { + void* handle = dlopen("libgraphicsenv.so", RTLD_NOW); +#define LAYER_ERROR(fmt, ...) \ + WLOGE(fmt, ## __VA_ARGS__); \ + dlclose(handle); \ + return false + + if (!handle) { + LAYER_ERROR("Cannot open libgraphicsenv.so"); + } + + #define FIND(var, sig, name) auto var = sig (dlsym(handle, name)); \ + if (!var) { \ + LAYER_ERROR("Cannot find symbol in libgraphicsenv.so: " #name); \ + } \ + WLOGD("Found " #name " in libgraphicsenv.so at %p", var); + + FIND(getInstance, (void* (*)()), "_ZN7android11GraphicsEnv11getInstanceEv"); + FIND(getLayerPaths, (const std::string&(*)(void*)), "_ZN7android11GraphicsEnv13getLayerPathsEv"); + FIND(getAppNamespace, (void* (*)(void*)), "_ZN7android11GraphicsEnv15getAppNamespaceEv"); + FIND(setLayerPaths, (void (*)(void*, void*, const std::string)), "_ZN7android11GraphicsEnv13setLayerPathsEPNS_21NativeLoaderNamespaceENSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE"); + + void* instance = getInstance(); + if (!instance) { + LAYER_ERROR("GraphicsEnv::getInstance() failed"); + } + + auto path = getLayerPaths(instance); + if (!path.empty()) { + if (path == PATH) { + WLOGD("GraphicsEnv::mLayerPaths is already set correctly"); + dlclose(handle); + return true; + } + LAYER_ERROR("GraphicsEnv::mLayerPaths is already set to %s, cannot perform hijacking", path.c_str()); + } + void* app_namespace = getAppNamespace(instance); + setLayerPaths(instance, app_namespace, PATH); + path = getLayerPaths(instance); + if (path != PATH) { + LAYER_ERROR("GraphicsEnv::mLayerPaths failed to be set correctly, found %s", path.c_str()); + } + + WLOGD("GraphicsEnv::mLayerPaths set to %s", path.c_str()); + return true; +} \ No newline at end of file diff --git a/src/vulkan/wrapper/graphics_env_hooks.h b/src/vulkan/wrapper/graphics_env_hooks.h new file mode 100644 index 00000000000..ba50e1ec051 --- /dev/null +++ b/src/vulkan/wrapper/graphics_env_hooks.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +bool set_layer_paths(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/vulkan/wrapper/meson.build b/src/vulkan/wrapper/meson.build index d03e4387169..51a2fd792c4 100644 --- a/src/vulkan/wrapper/meson.build +++ b/src/vulkan/wrapper/meson.build @@ -121,6 +121,7 @@ wrapper_files = files( 'wrapper_debug.c', 'wrapper_objects.c', 'spirv_edit.cpp', + 'graphics_env_hooks.cpp', ) wrapper_deps = [ diff --git a/src/vulkan/wrapper/wrapper_instance.c b/src/vulkan/wrapper/wrapper_instance.c index cacacc8e225..8a18a7f87dc 100644 --- a/src/vulkan/wrapper/wrapper_instance.c +++ b/src/vulkan/wrapper/wrapper_instance.c @@ -7,6 +7,7 @@ #include "vk_debug_utils.h" #include "wrapper_debug.h" #include "vk_printers.h" +#include "graphics_env_hooks.h" const struct vk_instance_extension_table wrapper_instance_extensions = { .KHR_get_surface_capabilities2 = true, @@ -52,6 +53,8 @@ static struct vk_instance_extension_table *supported_instance_extensions; #include +static bool g_intercepted_layer_path = false; + static void *get_vulkan_handle_icd() { char *path = getenv("ADRENOTOOLS_DRIVER_PATH"); @@ -64,6 +67,10 @@ static void *get_vulkan_handle_icd() struct stat sb; + if (CHECK_FLAG("USE_VVL")) { + g_intercepted_layer_path = set_layer_paths(); + } + if (hooks && path && (stat(path, &sb) == 0)) { WLOG("get_vulkan_handle: hooks=%s, path=%s, name=%s", hooks, path, name); char *temp; @@ -76,15 +83,8 @@ static void *get_vulkan_handle_icd() } } -// static void* icd_handle; - static void *get_vulkan_handle() { - // __log("in get_vulkan_handle"); - // if (!icd_handle) - // icd_handle = get_vulkan_handle_icd(); - // void* vvl = dlopen("/data/user/0/com.winlator.cmod/files/imagefs/usr/lib/libVkLayer_khronos_validation.so", RTLD_NOW | RTLD_LOCAL); - // __log("Got vvl layer: %p", vvl); return get_vulkan_handle_icd(); } @@ -298,43 +298,118 @@ WRAPPER_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, wrapper_create_info.pApplicationInfo = &wrapper_application_info; wrapper_create_info.enabledExtensionCount = wrapper_enable_extension_count; wrapper_create_info.ppEnabledExtensionNames = wrapper_enable_extensions; + + const char* layers[wrapper_create_info.enabledLayerCount + 1]; + char time_str[20]; + char path[256]; + const char* log_filename[] = { path }; + const char* report_flags[] = { "error", "info", "warn" }; + VkBool32 validate_sync[] = { VK_TRUE }; + VkBool32 printf_enable[] = { VK_TRUE }; + VkBool32 printf_verbose[] = { VK_TRUE }; + VkBool32 validate_best_practices[] = { VK_TRUE }; + VkBool32 validate_best_practices_arm[] = { VK_TRUE }; + + const VkLayerSettingEXT layer_setting[] = { + { + "VK_LAYER_KHRONOS_validation", + "log_filename", + VK_LAYER_SETTING_TYPE_STRING_EXT, + 1, + log_filename, + }, + { + "VK_LAYER_KHRONOS_validation", + "report_flags", + VK_LAYER_SETTING_TYPE_STRING_EXT, + 3, + report_flags, + }, + { + "VK_LAYER_KHRONOS_validation", + "validate_sync", + VK_LAYER_SETTING_TYPE_BOOL32_EXT, + 1, + validate_sync, + }, + { + "VK_LAYER_KHRONOS_validation", + "printf_enable", + VK_LAYER_SETTING_TYPE_BOOL32_EXT, + 1, + printf_enable, + }, + { + "VK_LAYER_KHRONOS_validation", + "printf_verbose", + VK_LAYER_SETTING_TYPE_BOOL32_EXT, + 1, + printf_verbose, + }, + { + "VK_LAYER_KHRONOS_validation", + "validate_best_practices", + VK_LAYER_SETTING_TYPE_BOOL32_EXT, + 1, + validate_best_practices, + }, + { + "VK_LAYER_KHRONOS_validation", + "validate_best_practices_arm", + VK_LAYER_SETTING_TYPE_BOOL32_EXT, + 1, + validate_best_practices_arm, + }, + }; + + VkLayerSettingsCreateInfoEXT layer_settings_create_info = { + VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, + NULL, + 3, + layer_setting, + }; + + if (CHECK_FLAG("USE_VVL")) { + if (!g_intercepted_layer_path) { + WLOGE("Failed to intercept GraphicsEnv::SetLayerPaths(), cannot load VVL"); + return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); + } + + uint32_t layerCount; + _vkEnumerateInstanceLayerProperties(&layerCount, NULL); - // Initialize vvl - // if (icd_handle != vulkan_library_handle) { - // __log("Additional initialization - adding more pnext chains"); - // VkLayerInstanceCreateInfo *chain_info = (VkLayerInstanceCreateInfo *)&wrapper_create_info; - // while ((chain_info->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO || chain_info->function != 0) && chain_info->pNext) { - // chain_info = (VkLayerInstanceCreateInfo *)&chain_info->pNext; - // } - // if (chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && chain_info->function == 0) { - // __log("ERROR: Found a loader create info"); - // unreachable(""); - // } else { - // if (!chain_info->pNext) { - // __log("Starting new loader create info"); - // void* next = dlsym(icd_handle, "vkGetInstanceProcAddr"); - // __log("Next: %p", next); - // VkLayerInstanceLink deviceInfo = { - // .pfnNextGetInstanceProcAddr = next - // }; - - // VkLayerInstanceCreateInfo info = { - // .sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO, - // .function = 0, - // .u.pLayerInfo = &deviceInfo - // }; - // chain_info->pNext = &info; - // __log("Created new loader create info"); - // } else { - // __log("ERROR"); - // unreachable(""); - // } - // } - // } + if (layerCount == 0) { + WLOGE("No layers found, make sure that /data/data/com.winlator.cmod/files/imagefs/usr/lib/libVkLayer_khronos_validation.so exists"); + return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); + } else { + VkLayerProperties availableLayers[layerCount]; + _vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); + + WLOGD("Found %d layers in /data/data/com.winlator.cmod/files/imagefs/usr/lib/", layerCount); + for (int i = 0; i < layerCount; i++) { + WLOGD(" Layer[%d]: %s", i, availableLayers[i].layerName); + } + } + + wrapper_create_info.enabledLayerCount += 1; + for (int i = 0; i < wrapper_create_info.enabledLayerCount - 1; i++) { + WLOGD("enabled_layer[%d]: %s", i, wrapper_create_info.ppEnabledLayerNames[i]); + layers[i] = wrapper_create_info.ppEnabledLayerNames[i]; + } + layers[wrapper_create_info.enabledLayerCount - 1] = "VK_LAYER_KHRONOS_validation"; + wrapper_create_info.ppEnabledLayerNames = layers; + + get_current_time_string(time_str, sizeof(time_str)); + sprintf(path, "/sdcard/Documents/Wrapper/%s_%s.%s.%d.txt", "vvl", time_str, getprogname(), getpid()); + layer_settings_create_info.pNext = wrapper_create_info.pNext; + wrapper_create_info.pNext = &layer_settings_create_info; + } result = dispatch_create_instance(&wrapper_create_info, pAllocator, &instance->dispatch_handle); + if (result != VK_SUCCESS) { + WLOGE("vkCreateInstance failed, result = %d", result); vk_instance_finish(&instance->vk); vk_free2(vk_default_allocator(), pAllocator, instance); return vk_error(NULL, result); diff --git a/src/vulkan/wrapper/wrapper_private.h b/src/vulkan/wrapper/wrapper_private.h index 3d44474468f..4e15ca41315 100644 --- a/src/vulkan/wrapper/wrapper_private.h +++ b/src/vulkan/wrapper/wrapper_private.h @@ -163,62 +163,6 @@ static inline uint32_t get_bc_block_size(VkFormat format) { } } - -typedef enum VkLayerFunction_ { - VK_LAYER_FUNCTION_LINK = 0, - VK_LAYER_FUNCTION_DEVICE = 1, - VK_LAYER_FUNCTION_INSTANCE = 2 -} VkLayerFunction; -/* - * When creating the device chain the loader needs to pass - * down information about it's device structure needed at - * the end of the chain. Passing the data via the - * VkLayerInstanceInfo avoids issues with finding the - * exact instance being used. - */ -typedef struct VkLayerInstanceInfo_ { - void* instance_info; - PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; -} VkLayerInstanceInfo; -typedef struct VkLayerInstanceLink_ { - struct VkLayerInstanceLink_* pNext; - PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; -} VkLayerInstanceLink; -/* - * When creating the device chain the loader needs to pass - * down information about it's device structure needed at - * the end of the chain. Passing the data via the - * VkLayerDeviceInfo avoids issues with finding the - * exact instance being used. - */ -typedef struct VkLayerDeviceInfo_ { - void* device_info; - PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; -} VkLayerDeviceInfo; -typedef struct { - VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO - const void* pNext; - VkLayerFunction function; - union { - VkLayerInstanceLink* pLayerInfo; - VkLayerInstanceInfo instanceInfo; - } u; -} VkLayerInstanceCreateInfo; -typedef struct VkLayerDeviceLink_ { - struct VkLayerDeviceLink_* pNext; - PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr; -} VkLayerDeviceLink; -typedef struct { - VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - const void* pNext; - VkLayerFunction function; - union { - VkLayerDeviceLink* pLayerInfo; - VkLayerDeviceInfo deviceInfo; - } u; -} VkLayerDeviceCreateInfo; - static VkFormat unwrap_vk_format_physical_device(struct wrapper_physical_device* pdevice, VkFormat in_format) { if (!pdevice) { WLOGE("unwrap_vk_format: null pdevice");