summaryrefslogtreecommitdiff
path: root/loader
diff options
context:
space:
mode:
authorMark Young <marky@lunarg.com>2017-03-10 17:31:18 -0700
committerMark Young <marky@lunarg.com>2017-03-16 10:38:05 -0600
commit61ff81af2702610eb1121f3a392f4f73d79a3b28 (patch)
treec8e744cc5fc1a037aec4798d4e3c7378e154989b /loader
parentbc230cab8dfa71848d4c81af8c6ce718e56d2711 (diff)
loader: Fix vkEnumeratePhysicalDeviceGroupsKHX
vkEnumeratePhysicalDeviceGroupsKHX was not properly generating the physical device information or groups. Several changes resolve most of the issue, however, I'm still seeing issues when certain layers enabled. Change-Id: Id8d4553da25491a3d0a97e8d44e21340b41bc09c
Diffstat (limited to 'loader')
-rw-r--r--loader/CMakeLists.txt1
-rw-r--r--loader/extension_manual.c586
-rw-r--r--loader/extension_manual.h49
-rw-r--r--loader/loader.c64
-rw-r--r--loader/loader.h11
-rw-r--r--loader/trampoline.c59
6 files changed, 724 insertions, 46 deletions
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index 76f6d525..c784a22e 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -58,6 +58,7 @@ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
set(NORMAL_LOADER_SRCS
+ extension_manual.c
loader.c
loader.h
vk_loader_platform.h
diff --git a/loader/extension_manual.c b/loader/extension_manual.c
new file mode 100644
index 00000000..6ddb9b09
--- /dev/null
+++ b/loader/extension_manual.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2015-2017 The Khronos Group Inc.
+ * Copyright (c) 2015-2017 Valve Corporation
+ * Copyright (c) 2015-2017 LunarG, 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.
+ *
+ * Author: Mark Young <marky@lunarg.com>
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vk_loader_platform.h"
+#include "loader.h"
+#include "vk_loader_extensions.h"
+#include <vulkan/vk_icd.h>
+#include "wsi.h"
+#include "debug_report.h"
+
+// ---- Manually added trampoline/terminator functions
+
+// These functions, for whatever reason, require more complex changes than
+// can easily be automatically generated.
+VkResult setupLoaderTrampPhysDevGroups(VkInstance instance);
+VkResult setupLoaderTermPhysDevGroups(struct loader_instance *inst);
+
+VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
+ VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
+ VkResult res = VK_SUCCESS;
+ uint32_t count;
+ uint32_t i;
+ struct loader_instance *inst = NULL;
+
+ loader_platform_thread_lock_mutex(&loader_lock);
+
+ inst = loader_get_instance(instance);
+ if (NULL == inst) {
+ res = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+
+ if (NULL == pPhysicalDeviceGroupCount) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "vkEnumeratePhysicalDeviceGroupsKHX: Received NULL pointer for physical "
+ "device group count return value.");
+ res = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+
+ VkResult setup_res = setupLoaderTrampPhysDevGroups(instance);
+ if (VK_SUCCESS != setup_res) {
+ res = setup_res;
+ goto out;
+ }
+
+ count = inst->phys_dev_group_count_tramp;
+
+ // Wrap the PhysDev object for loader usage, return wrapped objects
+ if (NULL != pPhysicalDeviceGroupProperties) {
+ if (inst->phys_dev_group_count_tramp > *pPhysicalDeviceGroupCount) {
+ loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
+ "vkEnumeratePhysicalDeviceGroupsKHX: Trimming device group count down"
+ " by application request from %d to %d physical device groups",
+ inst->phys_dev_group_count_tramp, *pPhysicalDeviceGroupCount);
+ count = *pPhysicalDeviceGroupCount;
+ res = VK_INCOMPLETE;
+ }
+ for (i = 0; i < count; i++) {
+ memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_tramp[i],
+ sizeof(VkPhysicalDeviceGroupPropertiesKHX));
+ }
+ }
+
+ *pPhysicalDeviceGroupCount = count;
+
+out:
+
+ loader_platform_thread_unlock_mutex(&loader_lock);
+ return res;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroupsKHX(
+ VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
+ struct loader_instance *inst = (struct loader_instance *)instance;
+ VkResult res = VK_SUCCESS;
+
+ // Always call the setup loader terminator physical device groups because they may
+ // have changed at any point.
+ res = setupLoaderTermPhysDevGroups(inst);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+
+ uint32_t copy_count = inst->phys_dev_group_count_term;
+ if (NULL != pPhysicalDeviceGroupProperties) {
+ if (copy_count > *pPhysicalDeviceGroupCount) {
+ copy_count = *pPhysicalDeviceGroupCount;
+ res = VK_INCOMPLETE;
+ }
+
+ for (uint32_t i = 0; i < copy_count; i++) {
+ memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_term[i],
+ sizeof(VkPhysicalDeviceGroupPropertiesKHX));
+ }
+ }
+
+ *pPhysicalDeviceGroupCount = copy_count;
+
+out:
+
+ return res;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+GetPhysicalDeviceExternalImageFormatPropertiesNV(
+ VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
+ VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
+ VkExternalMemoryHandleTypeFlagsNV externalHandleType,
+ VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties) {
+ const VkLayerInstanceDispatchTable *disp;
+ VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
+ disp = loader_get_instance_layer_dispatch(physicalDevice);
+
+ return disp->GetPhysicalDeviceExternalImageFormatPropertiesNV(
+ unwrapped_phys_dev, format, type, tiling, usage, flags,
+ externalHandleType, pExternalImageFormatProperties);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV(
+ VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
+ VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
+ VkExternalMemoryHandleTypeFlagsNV externalHandleType,
+ VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties) {
+ struct loader_physical_device_term *phys_dev_term =
+ (struct loader_physical_device_term *)physicalDevice;
+ struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+
+ if (!icd_term->dispatch.GetPhysicalDeviceExternalImageFormatPropertiesNV) {
+ if (externalHandleType) {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if (!icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ pExternalImageFormatProperties->externalMemoryFeatures = 0;
+ pExternalImageFormatProperties->exportFromImportedHandleTypes = 0;
+ pExternalImageFormatProperties->compatibleHandleTypes = 0;
+
+ return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(
+ phys_dev_term->phys_dev, format, type, tiling, usage, flags,
+ &pExternalImageFormatProperties->imageFormatProperties);
+ }
+
+ return icd_term->dispatch.GetPhysicalDeviceExternalImageFormatPropertiesNV(
+ phys_dev_term->phys_dev, format, type, tiling, usage, flags,
+ externalHandleType, pExternalImageFormatProperties);
+}
+
+
+VkResult setupLoaderTrampPhysDevGroups(VkInstance instance) {
+ VkResult res = VK_SUCCESS;
+ struct loader_instance *inst;
+ uint32_t total_count = 0;
+ VkPhysicalDeviceGroupPropertiesKHX **new_phys_dev_groups = NULL;
+ VkPhysicalDeviceGroupPropertiesKHX *local_phys_dev_groups = NULL;
+
+ inst = loader_get_instance(instance);
+ if (NULL == inst) {
+ res = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+
+ // Setup the trampoline loader physical devices. This will actually
+ // call down and setup the terminator loader physical devices during the
+ // process.
+ VkResult setup_res = setupLoaderTrampPhysDevs(instance);
+ if (setup_res != VK_SUCCESS && setup_res != VK_INCOMPLETE) {
+ res = setup_res;
+ goto out;
+ }
+
+ // Query how many physical device groups there
+ res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroupsKHX(instance, &total_count, NULL);
+ if (res != VK_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTrampPhysDevGroups: Failed during dispatch call of "
+ "\'EnumeratePhysicalDeviceGroupsKHX\' to lower layers or "
+ "loader to get count.");
+ goto out;
+ }
+
+ // Create an array for the new physical device groups, which will be stored
+ // in the instance for the trampoline code.
+ new_phys_dev_groups = (VkPhysicalDeviceGroupPropertiesKHX **)loader_instance_heap_alloc(
+ inst, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL == new_phys_dev_groups) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTrampPhysDevGroups: Failed to allocate new physical device"
+ " group array of size %d",
+ total_count);
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ memset(new_phys_dev_groups, 0, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *));
+
+ // Create a temporary array (on the stack) to keep track of the
+ // returned VkPhysicalDevice values.
+ local_phys_dev_groups = loader_stack_alloc(sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
+ if (NULL == local_phys_dev_groups) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTrampPhysDevGroups: Failed to allocate local "
+ "physical device group array of size %d",
+ total_count);
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ // Initialize the memory to something valid
+ memset(local_phys_dev_groups, 0, sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
+ for (uint32_t group = 0; group < total_count; group++) {
+ local_phys_dev_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX;
+ local_phys_dev_groups[group].pNext = NULL;
+ local_phys_dev_groups[group].subsetAllocation = false;
+ }
+
+ // Call down and get the content
+ res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroupsKHX(instance, &total_count, local_phys_dev_groups);
+ if (VK_SUCCESS != res) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTrampPhysDevGroups: Failed during dispatch call of "
+ "\'EnumeratePhysicalDeviceGroupsKHX\' to lower layers or "
+ "loader to get content.");
+ goto out;
+ }
+
+ // Replace all the physical device IDs with the proper loader values
+ for (uint32_t group = 0; group < total_count; group++) {
+ for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].physicalDeviceCount; group_gpu++) {
+ bool found = false;
+ for (uint32_t tramp_gpu = 0; tramp_gpu < inst->phys_dev_count_tramp; tramp_gpu++) {
+ if (local_phys_dev_groups[group].physicalDevices[group_gpu] == inst->phys_devs_tramp[tramp_gpu]->phys_dev) {
+ local_phys_dev_groups[group].physicalDevices[group_gpu] = (VkPhysicalDevice)inst->phys_devs_tramp[tramp_gpu];
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTrampPhysDevGroups: Failed to find GPU %d in group %d"
+ " returned by \'EnumeratePhysicalDeviceGroupsKHX\' in list returned"
+ " by \'EnumeratePhysicalDevices\'", group_gpu, group);
+ res = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+ }
+ }
+
+ // Copy or create everything to fill the new array of physical device groups
+ for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
+ // Check if this physical device group with the same contents is already in the old buffer
+ for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_tramp; old_idx++) {
+ if (local_phys_dev_groups[new_idx].physicalDeviceCount == inst->phys_dev_groups_tramp[old_idx]->physicalDeviceCount) {
+ bool found_all_gpus = true;
+ for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_tramp[old_idx]->physicalDeviceCount; old_gpu++) {
+ bool found_gpu = false;
+ for (uint32_t new_gpu = 0; new_gpu < local_phys_dev_groups[new_idx].physicalDeviceCount; new_gpu++) {
+ if (local_phys_dev_groups[new_idx].physicalDevices[new_gpu] == inst->phys_dev_groups_tramp[old_idx]->physicalDevices[old_gpu]) {
+ found_gpu = true;
+ break;
+ }
+ }
+
+ if (!found_gpu) {
+ found_all_gpus = false;
+ break;
+ }
+ }
+ if (!found_all_gpus) {
+ continue;
+ } else {
+ new_phys_dev_groups[new_idx] = inst->phys_dev_groups_tramp[old_idx];
+ break;
+ }
+ }
+ }
+
+ // If this physical device group isn't in the old buffer, create it
+ if (NULL == new_phys_dev_groups[new_idx]) {
+ new_phys_dev_groups[new_idx] = (VkPhysicalDeviceGroupPropertiesKHX *)loader_instance_heap_alloc(
+ inst, sizeof(VkPhysicalDeviceGroupPropertiesKHX), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL == new_phys_dev_groups[new_idx]) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTrampPhysDevGroups: Failed to allocate "
+ "physical device group trampoline object %d",
+ new_idx);
+ total_count = new_idx;
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ memcpy(new_phys_dev_groups[new_idx], &local_phys_dev_groups[new_idx],
+ sizeof(VkPhysicalDeviceGroupPropertiesKHX));
+ }
+ }
+
+out:
+
+ if (VK_SUCCESS != res) {
+ if (NULL != new_phys_dev_groups) {
+ for (uint32_t i = 0; i < total_count; i++) {
+ loader_instance_heap_free(inst, new_phys_dev_groups[i]);
+ }
+ loader_instance_heap_free(inst, new_phys_dev_groups);
+ }
+ total_count = 0;
+ } else {
+ // Free everything that didn't carry over to the new array of
+ // physical device groups
+ if (NULL != inst->phys_dev_groups_tramp) {
+ for (uint32_t i = 0; i < inst->phys_dev_group_count_tramp; i++) {
+ bool found = false;
+ for (uint32_t j = 0; j < total_count; j++) {
+ if (inst->phys_dev_groups_tramp[i] == new_phys_dev_groups[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ loader_instance_heap_free(inst, inst->phys_dev_groups_tramp[i]);
+ }
+ }
+ loader_instance_heap_free(inst, inst->phys_dev_groups_tramp);
+ }
+
+ // Swap in the new physical device group list
+ inst->phys_dev_group_count_tramp = total_count;
+ inst->phys_dev_groups_tramp = new_phys_dev_groups;
+ }
+
+ return res;
+}
+
+VkResult setupLoaderTermPhysDevGroups(struct loader_instance *inst) {
+ VkResult res = VK_SUCCESS;
+ struct loader_icd_term *icd_term;
+ uint32_t total_count = 0;
+ uint32_t cur_icd_group_count = 0;
+ VkPhysicalDeviceGroupPropertiesKHX **new_phys_dev_groups = NULL;
+ VkPhysicalDeviceGroupPropertiesKHX *local_phys_dev_groups = NULL;
+
+ if (0 == inst->phys_dev_count_term) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Loader failed to setup physical "
+ "device terminator info before calling \'EnumeratePhysicalDeviceGroupsKHX\'.");
+ assert(false);
+ res = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+
+ // For each ICD, query the number of physical device groups, and then get an
+ // internal value for those physical devices.
+ icd_term = inst->icd_terms;
+ for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
+ cur_icd_group_count = 0;
+ if (NULL == icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX) {
+ // Treat each ICD's GPU as it's own group if the extension isn't supported
+ res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &cur_icd_group_count, NULL);
+ if (res != VK_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
+ "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
+ icd_idx);
+ goto out;
+ }
+ } else {
+ // Query the actual group info
+ res = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX(icd_term->instance, &cur_icd_group_count, NULL);
+ if (res != VK_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
+ "\'EnumeratePhysicalDeviceGroupsKHX\' to ICD %d to get count.",
+ icd_idx);
+ goto out;
+ }
+ }
+ total_count += cur_icd_group_count;
+ }
+
+ // Create an array for the new physical device groups, which will be stored
+ // in the instance for the Terminator code.
+ new_phys_dev_groups = (VkPhysicalDeviceGroupPropertiesKHX **)loader_instance_heap_alloc(
+ inst, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL == new_phys_dev_groups) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed to allocate new physical device"
+ " group array of size %d",
+ total_count);
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ memset(new_phys_dev_groups, 0, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *));
+
+ // Create a temporary array (on the stack) to keep track of the
+ // returned VkPhysicalDevice values.
+ local_phys_dev_groups = loader_stack_alloc(sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
+ if (NULL == local_phys_dev_groups) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed to allocate local "
+ "physical device group array of size %d",
+ total_count);
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ // Initialize the memory to something valid
+ memset(local_phys_dev_groups, 0, sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
+ for (uint32_t group = 0; group < total_count; group++) {
+ local_phys_dev_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX;
+ local_phys_dev_groups[group].pNext = NULL;
+ local_phys_dev_groups[group].subsetAllocation = false;
+ }
+
+ cur_icd_group_count = 0;
+ icd_term = inst->icd_terms;
+ for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
+ uint32_t count_this_time = total_count - cur_icd_group_count;
+
+ if (NULL == icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX) {
+ VkPhysicalDevice* phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * count_this_time);
+ if (NULL == phys_dev_array) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed to allocate local "
+ "physical device array of size %d",
+ count_this_time);
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+
+ res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array);
+ if (res != VK_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
+ "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
+ icd_idx);
+ goto out;
+ }
+
+ // Add each GPU as it's own group
+ for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) {
+ local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDeviceCount = 1;
+ local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDevices[0] = phys_dev_array[indiv_gpu];
+ }
+
+ } else {
+ res = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX(icd_term->instance, &count_this_time, &local_phys_dev_groups[cur_icd_group_count]);
+ if (VK_SUCCESS != res) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed during dispatch call of "
+ "\'EnumeratePhysicalDeviceGroupsKHX\' to ICD %d to get content.",
+ icd_idx);
+ goto out;
+ }
+ }
+
+ cur_icd_group_count += count_this_time;
+ }
+
+ // Replace all the physical device IDs with the proper loader values
+ for (uint32_t group = 0; group < total_count; group++) {
+ for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].physicalDeviceCount; group_gpu++) {
+ bool found = false;
+ for (uint32_t term_gpu = 0; term_gpu < inst->phys_dev_count_term; term_gpu++) {
+ if (local_phys_dev_groups[group].physicalDevices[group_gpu] == inst->phys_devs_term[term_gpu]->phys_dev) {
+ local_phys_dev_groups[group].physicalDevices[group_gpu] = (VkPhysicalDevice)inst->phys_devs_term[term_gpu];
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed to find GPU %d in group %d"
+ " returned by \'EnumeratePhysicalDeviceGroupsKHX\' in list returned"
+ " by \'EnumeratePhysicalDevices\'", group_gpu, group);
+ res = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+ }
+ }
+
+ // Copy or create everything to fill the new array of physical device groups
+ for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
+ // Check if this physical device group with the same contents is already in the old buffer
+ for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
+ if (local_phys_dev_groups[new_idx].physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) {
+ bool found_all_gpus = true;
+ for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_term[old_idx]->physicalDeviceCount; old_gpu++) {
+ bool found_gpu = false;
+ for (uint32_t new_gpu = 0; new_gpu < local_phys_dev_groups[new_idx].physicalDeviceCount; new_gpu++) {
+ if (local_phys_dev_groups[new_idx].physicalDevices[new_gpu] == inst->phys_dev_groups_term[old_idx]->physicalDevices[old_gpu]) {
+ found_gpu = true;
+ break;
+ }
+ }
+
+ if (!found_gpu) {
+ found_all_gpus = false;
+ break;
+ }
+ }
+ if (!found_all_gpus) {
+ continue;
+ } else {
+ new_phys_dev_groups[new_idx] = inst->phys_dev_groups_term[old_idx];
+ break;
+ }
+ }
+ }
+
+ // If this physical device group isn't in the old buffer, create it
+ if (NULL == new_phys_dev_groups[new_idx]) {
+ new_phys_dev_groups[new_idx] = (VkPhysicalDeviceGroupPropertiesKHX *)loader_instance_heap_alloc(
+ inst, sizeof(VkPhysicalDeviceGroupPropertiesKHX), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL == new_phys_dev_groups[new_idx]) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTermPhysDevGroups: Failed to allocate "
+ "physical device group Terminator object %d",
+ new_idx);
+ total_count = new_idx;
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ memcpy(new_phys_dev_groups[new_idx], &local_phys_dev_groups[new_idx],
+ sizeof(VkPhysicalDeviceGroupPropertiesKHX));
+ }
+ }
+
+out:
+
+ if (VK_SUCCESS != res) {
+ if (NULL != new_phys_dev_groups) {
+ for (uint32_t i = 0; i < total_count; i++) {
+ loader_instance_heap_free(inst, new_phys_dev_groups[i]);
+ }
+ loader_instance_heap_free(inst, new_phys_dev_groups);
+ }
+ total_count = 0;
+ } else {
+ // Free everything that didn't carry over to the new array of
+ // physical device groups
+ if (NULL != inst->phys_dev_groups_term) {
+ for (uint32_t i = 0; i < inst->phys_dev_group_count_term; i++) {
+ bool found = false;
+ for (uint32_t j = 0; j < total_count; j++) {
+ if (inst->phys_dev_groups_term[i] == new_phys_dev_groups[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ loader_instance_heap_free(inst, inst->phys_dev_groups_term[i]);
+ }
+ }
+ loader_instance_heap_free(inst, inst->phys_dev_groups_term);
+ }
+
+ // Swap in the new physical device group list
+ inst->phys_dev_group_count_term = total_count;
+ inst->phys_dev_groups_term = new_phys_dev_groups;
+ }
+
+ return res;
+} \ No newline at end of file
diff --git a/loader/extension_manual.h b/loader/extension_manual.h
new file mode 100644
index 00000000..35d7c6fa
--- /dev/null
+++ b/loader/extension_manual.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015-2017 The Khronos Group Inc.
+ * Copyright (c) 2015-2017 Valve Corporation
+ * Copyright (c) 2015-2017 LunarG, 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.
+ *
+ * Author: Mark Young <marky@lunarg.com>
+ */
+
+#pragma once
+
+// ---- Manually added trampoline/terminator functions
+
+// These functions, for whatever reason, require more complex changes than
+// can easily be automatically generated.
+
+VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
+ VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroupsKHX(
+ VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL
+GetPhysicalDeviceExternalImageFormatPropertiesNV(
+ VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
+ VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
+ VkExternalMemoryHandleTypeFlagsNV externalHandleType,
+ VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL
+terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV(
+ VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
+ VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
+ VkExternalMemoryHandleTypeFlagsNV externalHandleType,
+ VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties);
+
diff --git a/loader/loader.c b/loader/loader.c
index 9b794b63..e4da0bd6 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -2761,10 +2761,16 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
}
res = loader_get_json(inst, file_str, &json);
- if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
- break;
- } else if (VK_SUCCESS != res || NULL == json) {
- continue;
+ if (NULL == json || res != VK_SUCCESS) {
+ if (NULL != json) {
+ cJSON_Delete(json);
+ json = NULL;
+ }
+ if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
+ break;
+ } else {
+ continue;
+ }
}
cJSON *item, *itemICD;
@@ -2781,10 +2787,10 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
json = NULL;
continue;
}
+
char *file_vers = cJSON_Print(item);
if (NULL == file_vers) {
- // Only reason the print can fail is if there was an allocation
- // issue
+ // Only reason the print can fail is if there was an allocation issue
if (num_good_icds == 0) {
res = VK_ERROR_OUT_OF_HOST_MEMORY;
}
@@ -2797,6 +2803,7 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
continue;
}
loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Found ICD manifest file %s, version %s", file_str, file_vers);
+
// Get the major/minor/and patch as integers for easier comparison
vers_tok = strtok(file_vers, ".\"\n\r");
if (NULL != vers_tok) {
@@ -2810,11 +2817,14 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
}
}
}
- if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1)
+
+ if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
"loader_icd_scan: Unexpected manifest file version "
"(expected 1.0.0 or 1.0.1), may cause errors");
+ }
cJSON_Free(file_vers);
+
itemICD = cJSON_GetObjectItem(json, "ICD");
if (itemICD != NULL) {
item = cJSON_GetObjectItem(itemICD, "library_path");
@@ -2911,6 +2921,8 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
"loader_icd_scan: Failed to add ICD JSON %s. "
" Skipping ICD JSON.",
fullpath);
+ cJSON_Delete(json);
+ json = NULL;
continue;
}
num_good_icds++;
@@ -2936,6 +2948,7 @@ out:
if (NULL != json) {
cJSON_Delete(json);
}
+
if (NULL != manifest_files.filename_list) {
for (uint32_t i = 0; i < manifest_files.count; i++) {
if (NULL != manifest_files.filename_list[i]) {
@@ -2947,6 +2960,7 @@ out:
if (lockedMutex) {
loader_platform_thread_unlock_mutex(&loader_json_lock);
}
+
return res;
}
@@ -4484,6 +4498,12 @@ VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const
}
loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
}
+ if (NULL != ptr_instance->phys_dev_groups_term) {
+ for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_term; i++) {
+ loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term[i]);
+ }
+ loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term);
+ }
loader_free_dev_ext_table(ptr_instance);
loader_free_phys_dev_ext_table(ptr_instance);
}
@@ -4639,6 +4659,19 @@ VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
res = VK_ERROR_INITIALIZATION_FAILED;
goto out;
}
+
+ // Query how many gpus there
+ res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, NULL);
+ if (res != VK_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "setupLoaderTrampPhysDevs: Failed during dispatch call "
+ "of \'vkEnumeratePhysicalDevices\' to lower layers or "
+ "loader to get count.");
+ goto out;
+ }
+
+ // Really use what the total GPU count is since Optimus and other layers may mess
+ // the count up.
total_count = inst->total_gpu_count;
// Create an array for the new physical devices, which will be stored
@@ -4673,7 +4706,7 @@ VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
"setupLoaderTrampPhysDevs: Failed during dispatch call "
"of \'vkEnumeratePhysicalDevices\' to lower layers or "
- "loader.");
+ "loader to get content.");
goto out;
}
@@ -4868,9 +4901,6 @@ out:
}
loader_instance_heap_free(inst, new_phys_devs);
}
- if (NULL != inst->phys_devs_term) {
- loader_instance_heap_free(inst, inst->phys_devs_term);
- }
inst->total_gpu_count = 0;
} else {
// Free everything that didn't carry over to the new array of
@@ -4905,13 +4935,11 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(VkInstance in
struct loader_instance *inst = (struct loader_instance *)instance;
VkResult res = VK_SUCCESS;
- // Only do the setup if we're re-querying the number of devices, or
- // our count is currently 0.
- if (NULL == pPhysicalDevices || 0 == inst->total_gpu_count) {
- res = setupLoaderTermPhysDevs(inst);
- if (VK_SUCCESS != res) {
- goto out;
- }
+ // Always call the setup loader terminator physical devices because they may
+ // have changed at any point.
+ res = setupLoaderTermPhysDevs(inst);
+ if (VK_SUCCESS != res) {
+ goto out;
}
uint32_t copy_count = inst->total_gpu_count;
diff --git a/loader/loader.h b/loader/loader.h
index a341f6cf..78160d0d 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -223,12 +223,23 @@ struct loader_instance_dispatch_table {
struct loader_instance {
struct loader_instance_dispatch_table *disp; // must be first entry in structure
+ // We need to manually track physical devices over time. If the user
+ // re-queries the information, we don't want to delete old data or
+ // create new data unless necessary.
uint32_t total_gpu_count;
uint32_t phys_dev_count_term;
struct loader_physical_device_term **phys_devs_term;
uint32_t phys_dev_count_tramp;
struct loader_physical_device_tramp **phys_devs_tramp;
+ // We also need to manually track physical device groups, but we don't need
+ // loader specific structures since we have that content in the physical
+ // device stored internal to the public structures.
+ uint32_t phys_dev_group_count_term;
+ struct VkPhysicalDeviceGroupPropertiesKHX **phys_dev_groups_term;
+ uint32_t phys_dev_group_count_tramp;
+ struct VkPhysicalDeviceGroupPropertiesKHX **phys_dev_groups_tramp;
+
struct loader_instance *next;
uint32_t total_icd_count;
diff --git a/loader/trampoline.c b/loader/trampoline.c
index f2e72530..6e11476b 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -447,6 +447,13 @@ LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance,
loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_tramp);
}
+ if (ptr_instance->phys_dev_groups_tramp) {
+ for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_tramp; i++) {
+ loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_tramp[i]);
+ }
+ loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_tramp);
+ }
+
if (callback_setup) {
util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_callbacks, ptr_instance->tmp_callbacks);
util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_dbg_create_infos, ptr_instance->tmp_callbacks);
@@ -458,11 +465,10 @@ LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance,
LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
VkPhysicalDevice *pPhysicalDevices) {
- const VkLayerInstanceDispatchTable *disp;
VkResult res = VK_SUCCESS;
- uint32_t count, i;
+ uint32_t count;
+ uint32_t i;
struct loader_instance *inst;
- disp = loader_get_instance_layer_dispatch(instance);
loader_platform_thread_lock_mutex(&loader_lock);
@@ -472,43 +478,40 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan
goto out;
}
- if (NULL == pPhysicalDevices || 0 == inst->total_gpu_count) {
- // Call down. At the lower levels, this will setup the terminator structures in the loader.
- res = disp->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
- if (VK_SUCCESS != res) {
- loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
- "vkEnumeratePhysicalDevices: Failed in dispatch call"
- " used to determine number of available GPUs");
- }
- }
-
- if (NULL == pPhysicalDevices) {
- // Goto out, even on success since we don't need to fill in the rest.
+ if (NULL == pPhysicalDeviceCount) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "vkEnumeratePhysicalDevices: Received NULL pointer for physical device count return value.");
+ res = VK_ERROR_INITIALIZATION_FAILED;
goto out;
}
+ // Setup the trampoline loader physical devices. This will actually
+ // call down and setup the terminator loader physical devices during the
+ // process.
VkResult setup_res = setupLoaderTrampPhysDevs(instance);
if (setup_res != VK_SUCCESS && setup_res != VK_INCOMPLETE) {
res = setup_res;
goto out;
}
+ count = inst->phys_dev_count_tramp;
+
// Wrap the PhysDev object for loader usage, return wrapped objects
- if (inst->phys_dev_count_tramp > *pPhysicalDeviceCount) {
- loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
- "vkEnumeratePhysicalDevices: Trimming device count down"
- " by application request from %d to %d physical devices",
- inst->phys_dev_count_tramp, *pPhysicalDeviceCount);
- count = *pPhysicalDeviceCount;
- res = VK_INCOMPLETE;
- } else {
- count = inst->phys_dev_count_tramp;
- *pPhysicalDeviceCount = count;
+ if (NULL != pPhysicalDevices) {
+ if (inst->phys_dev_count_tramp > *pPhysicalDeviceCount) {
+ loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
+ "vkEnumeratePhysicalDevices: Trimming device count down"
+ " by application request from %d to %d physical devices",
+ inst->phys_dev_count_tramp, *pPhysicalDeviceCount);
+ count = *pPhysicalDeviceCount;
+ res = VK_INCOMPLETE;
+ }
+ for (i = 0; i < count; i++) {
+ pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_tramp[i];
+ }
}
- for (i = 0; i < count; i++) {
- pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_tramp[i];
- }
+ *pPhysicalDeviceCount = count;
out: