#include "unknown_function_handling.h"
#if !defined(UNKNOWN_FUNCTIONS_SUPPORTED)
void loader_init_dispatch_dev_ext(struct loader_instance *inst, struct loader_device *dev) { … }
void *loader_dev_ext_gpa_tramp(struct loader_instance *inst, const char *funcName) { … }
void *loader_dev_ext_gpa_term(struct loader_instance *inst, const char *funcName) { … }
void *loader_phys_dev_ext_gpa_tramp(struct loader_instance *inst, const char *funcName) { … }
void *loader_phys_dev_ext_gpa_term(struct loader_instance *inst, const char *funcName) { … }
void loader_free_dev_ext_table(struct loader_instance *inst) { … }
void loader_free_phys_dev_ext_table(struct loader_instance *inst) { … }
#else
#include "allocation.h"
#include "log.h"
void *loader_get_dev_ext_trampoline(uint32_t index);
void *loader_get_phys_dev_ext_tramp(uint32_t index);
void *loader_get_phys_dev_ext_termin(uint32_t index);
void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst, struct loader_device *dev, uint32_t idx, const char *funcName)
{
void *gdpa_value;
if (dev != NULL) {
gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(dev->chain_device, funcName);
if (gdpa_value != NULL) dev->loader_dispatch.ext_dispatch[idx] = (PFN_vkDevExt)gdpa_value;
} else {
for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term != NULL; icd_term = icd_term->next) {
struct loader_device *ldev = icd_term->logical_device_list;
while (ldev) {
gdpa_value = ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(ldev->chain_device, funcName);
if (gdpa_value != NULL) ldev->loader_dispatch.ext_dispatch[idx] = (PFN_vkDevExt)gdpa_value;
ldev = ldev->next;
}
}
}
}
void loader_init_dispatch_dev_ext(struct loader_instance *inst, struct loader_device *dev) {
for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
if (inst->dev_ext_disp_functions[i] != NULL)
loader_init_dispatch_dev_ext_entry(inst, dev, i, inst->dev_ext_disp_functions[i]);
}
}
bool loader_check_icds_for_dev_ext_address(struct loader_instance *inst, const char *funcName) {
struct loader_icd_term *icd_term;
icd_term = inst->icd_terms;
while (NULL != icd_term) {
if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance, funcName))
return true;
icd_term = icd_term->next;
}
return false;
}
bool loader_check_layer_list_for_dev_ext_address(struct loader_instance *inst, const char *funcName) {
for (uint32_t layer = 0; layer < inst->expanded_activated_layer_list.count; ++layer) {
const struct loader_device_extension_list *const extensions =
&(inst->expanded_activated_layer_list.list[layer]->device_extension_list);
for (uint32_t extension = 0; extension < extensions->count; ++extension) {
const struct loader_dev_ext_props *const property = &(extensions->list[extension]);
for (uint32_t entry = 0; entry < property->entrypoints.count; ++entry) {
if (strcmp(property->entrypoints.list[entry], funcName) == 0) {
return true;
}
}
}
}
if (inst->expanded_activated_layer_list.count > 0) {
const struct loader_layer_functions *const functions = &(inst->expanded_activated_layer_list.list[0]->functions);
if (NULL != functions->get_instance_proc_addr) {
return NULL != functions->get_instance_proc_addr((VkInstance)inst->instance, funcName);
}
}
return false;
}
void loader_free_dev_ext_table(struct loader_instance *inst) {
for (uint32_t i = 0; i < inst->dev_ext_disp_function_count; i++) {
loader_instance_heap_free(inst, inst->dev_ext_disp_functions[i]);
}
memset(inst->dev_ext_disp_functions, 0, sizeof(inst->dev_ext_disp_functions));
}
void *loader_dev_ext_gpa_impl(struct loader_instance *inst, const char *funcName, bool is_tramp) {
for (uint32_t i = 0; i < inst->dev_ext_disp_function_count; i++) {
if (inst->dev_ext_disp_functions[i] && !strcmp(inst->dev_ext_disp_functions[i], funcName))
return loader_get_dev_ext_trampoline(i);
}
if (!loader_check_icds_for_dev_ext_address(inst, funcName)) {
if (!is_tramp || !loader_check_layer_list_for_dev_ext_address(inst, funcName)) {
return NULL;
}
}
if (inst->dev_ext_disp_function_count >= MAX_NUM_UNKNOWN_EXTS) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_dev_ext_gpa: Exhausted the unknown device function array!");
return NULL;
}
size_t funcName_len = strlen(funcName) + 1;
inst->dev_ext_disp_functions[inst->dev_ext_disp_function_count] =
(char *)loader_instance_heap_alloc(inst, funcName_len, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == inst->dev_ext_disp_functions[inst->dev_ext_disp_function_count]) {
return NULL;
}
loader_strncpy(inst->dev_ext_disp_functions[inst->dev_ext_disp_function_count], funcName_len, funcName, funcName_len);
loader_init_dispatch_dev_ext_entry(inst, NULL, inst->dev_ext_disp_function_count, funcName);
void *out_function = loader_get_dev_ext_trampoline(inst->dev_ext_disp_function_count);
inst->dev_ext_disp_function_count++;
return out_function;
}
void *loader_dev_ext_gpa_tramp(struct loader_instance *inst, const char *funcName) {
return loader_dev_ext_gpa_impl(inst, funcName, true);
}
void *loader_dev_ext_gpa_term(struct loader_instance *inst, const char *funcName) {
return loader_dev_ext_gpa_impl(inst, funcName, false);
}
bool loader_check_icds_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
struct loader_icd_term *icd_term;
icd_term = inst->icd_terms;
while (NULL != icd_term) {
if (icd_term->scanned_icd->interface_version >= MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION &&
icd_term->scanned_icd->GetPhysicalDeviceProcAddr &&
icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName))
return true;
icd_term = icd_term->next;
}
return false;
}
bool loader_check_layer_list_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
for (uint32_t layer = 0; layer < inst->expanded_activated_layer_list.count; layer++) {
struct loader_layer_properties *layer_prop_list = inst->expanded_activated_layer_list.list[layer];
if (layer_prop_list->interface_version > 1) {
const struct loader_layer_functions *const functions = &(layer_prop_list->functions);
if (NULL != functions->get_physical_device_proc_addr) {
return NULL != functions->get_physical_device_proc_addr((VkInstance)inst->instance, funcName);
}
}
}
return false;
}
void loader_free_phys_dev_ext_table(struct loader_instance *inst) {
for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
loader_instance_heap_free(inst, inst->phys_dev_ext_disp_functions[i]);
}
memset(inst->phys_dev_ext_disp_functions, 0, sizeof(inst->phys_dev_ext_disp_functions));
}
void *loader_phys_dev_ext_gpa_impl(struct loader_instance *inst, const char *funcName, bool is_tramp) {
assert(NULL != inst);
if (!loader_check_icds_for_phys_dev_ext_address(inst, funcName)) {
if (!is_tramp || !loader_check_layer_list_for_phys_dev_ext_address(inst, funcName)) {
return NULL;
}
}
bool has_found = false;
uint32_t new_function_index = 0;
for (uint32_t i = 0; i < inst->phys_dev_ext_disp_function_count; i++) {
if (inst->phys_dev_ext_disp_functions[i] && !strcmp(inst->phys_dev_ext_disp_functions[i], funcName)) {
has_found = true;
new_function_index = i;
break;
}
}
if (!has_found) {
if (inst->phys_dev_ext_disp_function_count >= MAX_NUM_UNKNOWN_EXTS) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
"loader_dev_ext_gpa: Exhausted the unknown physical device function array!");
return NULL;
}
loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
"loader_phys_dev_ext_gpa: Adding unknown physical function %s to internal store at index %u", funcName,
inst->phys_dev_ext_disp_function_count);
size_t funcName_len = strlen(funcName) + 1;
inst->phys_dev_ext_disp_functions[inst->phys_dev_ext_disp_function_count] =
(char *)loader_instance_heap_alloc(inst, funcName_len, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == inst->phys_dev_ext_disp_functions[inst->phys_dev_ext_disp_function_count]) {
return NULL;
}
loader_strncpy(inst->phys_dev_ext_disp_functions[inst->phys_dev_ext_disp_function_count], funcName_len, funcName,
funcName_len);
new_function_index = inst->phys_dev_ext_disp_function_count;
inst->phys_dev_ext_disp_function_count++;
}
struct loader_icd_term *icd_term = inst->icd_terms;
while (NULL != icd_term) {
if (MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION <= icd_term->scanned_icd->interface_version &&
NULL != icd_term->scanned_icd->GetPhysicalDeviceProcAddr) {
icd_term->phys_dev_ext[new_function_index] =
(PFN_PhysDevExt)icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName);
if (NULL != icd_term->phys_dev_ext[new_function_index]) {
inst->disp->phys_dev_ext[new_function_index] = loader_get_phys_dev_ext_termin(new_function_index);
loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "loader_phys_dev_ext_gpa: Driver %s returned ptr %p for %s",
icd_term->scanned_icd->lib_name, inst->disp->phys_dev_ext[new_function_index], funcName);
}
} else {
icd_term->phys_dev_ext[new_function_index] = NULL;
}
icd_term = icd_term->next;
}
if (is_tramp) {
for (uint32_t i = 0; i < inst->expanded_activated_layer_list.count; i++) {
struct loader_layer_properties *layer_prop = inst->expanded_activated_layer_list.list[i];
if (layer_prop->interface_version > 1 && NULL != layer_prop->functions.get_physical_device_proc_addr) {
void *layer_ret_function =
(PFN_PhysDevExt)layer_prop->functions.get_physical_device_proc_addr(inst->instance, funcName);
if (NULL != layer_ret_function) {
inst->disp->phys_dev_ext[new_function_index] = layer_ret_function;
loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "loader_phys_dev_ext_gpa: Layer %s returned ptr %p for %s",
layer_prop->info.layerName, inst->disp->phys_dev_ext[new_function_index], funcName);
break;
}
}
}
}
if (is_tramp) {
return loader_get_phys_dev_ext_tramp(new_function_index);
} else {
return loader_get_phys_dev_ext_termin(new_function_index);
}
}
void *loader_phys_dev_ext_gpa_tramp(struct loader_instance *inst, const char *funcName) {
return loader_phys_dev_ext_gpa_impl(inst, funcName, true);
}
void *loader_phys_dev_ext_gpa_term(struct loader_instance *inst, const char *funcName) {
return loader_phys_dev_ext_gpa_impl(inst, funcName, false);
}
#endif