From c983d247acb745163bfa885896cf8f277eaf46cd Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 10 Jul 2024 17:20:20 +0200 Subject: [PATCH 01/33] vkconfig3: UI for new Vulkan Loader settings Changelog: - [X] Use Vulkan Loader 284 Settings file instead of override layer - [X] Add Vulkan Configurator JSON file to consolidate data - [ ] Redesign UI based on tabs - [ ] Add diagnostics tab - [X] Add application launcher tab - [X] Add multiple launch options per executable - [X] Improve SDK upgrade: vkcube versions, new configurations update, latest layer versions - [X] Add layers tab - [X] Add caching of layer manifest validation to improve loading time - [ ] Add layers configuration tab - [X] Add selection of loader message types - [X] Implement layers drap and drop for ordering - [X] Implement layers version selection - [ ] Implement layers state and tooltips to explain auto - [X] Implement context menu - [X] Implement *all available layers* and *overridden layers only* - [X] Add full control of all layers execution order - [ ] Allow disabling app control layers - [X] Add Per executable path layers configuration or global layers configuration - [X] Add layers configuration version, to support automatic update of built-in configurations - [X] Improve UI responsiveness, remove file saving and loading when switching layers configurations - [X] Add selection of a specific layer version from a list of layer versions - [ ] Add command line settings - [ ] Fix preset display - [ ] Implement command line tool --- CMakeLists.txt | 7 +- scripts/github_ci_linux.py | 6 +- vkconfig/CMakeLists.txt | 56 - vkconfig/README.md | 161 - vkconfig/configurator.cpp | 228 - vkconfig/dialog_about.cpp | 30 - vkconfig/dialog_about.ui | 220 - vkconfig/dialog_applications.cpp | 299 - vkconfig/dialog_applications.h | 65 - vkconfig/dialog_applications.ui | 176 - vkconfig/dialog_layers.cpp | 746 -- vkconfig/dialog_layers.h | 93 - vkconfig/dialog_layers.ui | 555 -- vkconfig/dialog_vulkan_analysis.cpp | 208 - vkconfig/main_doc.h | 25 - vkconfig/main_gui.cpp | 78 - vkconfig/main_gui.h | 25 - vkconfig/main_layers.cpp | 160 - vkconfig/main_reset.cpp | 76 - vkconfig/mainwindow.ui | 820 --- vkconfig/resources.qrc | 82 - vkconfig/settings_tree.cpp | 500 -- vkconfig/settings_tree.h | 70 - vkconfig/settings_validation_areas.cpp | 977 --- vkconfig/settings_validation_areas.h | 217 - vkconfig/vkconfig.pro | 203 - vkconfig/widget_setting.cpp | 63 - vkconfig/widget_setting_float.cpp | 192 - vkconfig/widget_setting_frames.cpp | 164 - vkconfig/widget_setting_int.cpp | 181 - vkconfig/widget_tree_friendly_combobox.cpp | 34 - vkconfig/widget_tree_friendly_combobox.h | 48 - vkconfig3/CHANGELOG.md | 290 - vkconfig3/CONTRIBUTING.md | 98 - vkconfig3/configurator.cpp | 202 - vkconfig3/configurator.h | 64 - vkconfig3/dialog_applications.cpp | 301 - vkconfig3/dialog_applications.h | 64 - vkconfig3/dialog_applications.ui | 176 - vkconfig3/dialog_vulkan_analysis.h | 44 - vkconfig3/dialog_vulkan_analysis.ui | 420 -- vkconfig3/dialog_vulkan_info.cpp | 354 - vkconfig3/dialog_vulkan_info.h | 48 - vkconfig3/dialog_vulkan_info.ui | 41 - vkconfig3/images/NewLunarGLogoBlack.png | Bin 4063 -> 0 bytes vkconfig3/images/presentation.gif | Bin 1803363 -> 0 bytes .../vkconfig_applications_collapsed.png | Bin 82424 -> 0 bytes .../images/vkconfig_applications_dialog.png | Bin 170544 -> 0 bytes .../images/vkconfig_applications_expanded.png | Bin 91459 -> 0 bytes vkconfig3/images/vulkan_layers_order.png | Bin 100095 -> 0 bytes .../images/vulkan_layers_order_small.png | Bin 30984 -> 0 bytes vkconfig3/images/vulkan_loader.png | Bin 283048 -> 0 bytes vkconfig3/images/vulkan_loader_640px.png | Bin 100657 -> 0 bytes vkconfig3/main.cpp | 86 - vkconfig3/main_doc.cpp | 117 - vkconfig3/main_gui.h | 25 - vkconfig3/main_reset.h | 25 - vkconfig3/main_signal.cpp | 53 - vkconfig3/mainwindow.h | 329 - vkconfig3/resourcefiles/lunarg_logo.png | Bin 6909 -> 0 bytes vkconfig3/resourcefiles/qt_logo.png | Bin 2770 -> 0 bytes vkconfig3/resourcefiles/vkconfig-off.png | Bin 1253 -> 0 bytes vkconfig3/resourcefiles/vkconfig-on.png | Bin 892 -> 0 bytes vkconfig3/resourcefiles/vkconfig.aps | Bin 10340 -> 0 bytes vkconfig3/resourcefiles/vkconfig.rc | 1 - vkconfig3/resourcefiles/vulkan.ico | Bin 9662 -> 0 bytes .../resourcefiles/vulkan_configurator.png | Bin 37072 -> 0 bytes vkconfig3/resources.qrc | 81 - vkconfig3/vkconfig.entitlements | 10 - vkconfig3/vulkan_util.cpp | 373 - vkconfig3/widget_preset.cpp | 91 - vkconfig3/widget_setting.h | 58 - vkconfig3/widget_setting_bool.cpp | 71 - vkconfig3/widget_setting_bool.h | 51 - vkconfig3/widget_setting_enum.cpp | 223 - vkconfig3/widget_setting_enum.h | 58 - vkconfig3/widget_setting_filesystem.cpp | 216 - vkconfig3/widget_setting_filesystem.h | 61 - vkconfig3/widget_setting_flags.cpp | 90 - vkconfig3/widget_setting_flags.h | 53 - vkconfig3/widget_setting_float.h | 66 - vkconfig3/widget_setting_frames.h | 67 - vkconfig3/widget_setting_int.h | 65 - vkconfig3/widget_setting_list.cpp | 254 - vkconfig3/widget_setting_list.h | 74 - vkconfig3/widget_setting_list_element.cpp | 109 - vkconfig3/widget_setting_list_element.h | 59 - vkconfig3/widget_setting_string.cpp | 95 - vkconfig3/widget_setting_string.h | 57 - vkconfig_cmd/CMakeLists.txt | 57 + {vkconfig => vkconfig_cmd}/macOS/Info.plist | 0 .../macOS/Resources/VulkanIcon.icns | Bin .../macOS/vkconfig.cmake | 21 +- {vkconfig => vkconfig_cmd}/main.cpp | 15 +- {vkconfig => vkconfig_cmd}/main_doc.cpp | 34 +- {vkconfig3 => vkconfig_cmd}/main_doc.h | 5 +- {vkconfig3 => vkconfig_cmd}/main_layers.cpp | 59 +- {vkconfig3 => vkconfig_cmd}/main_layers.h | 4 +- {vkconfig3 => vkconfig_cmd}/main_reset.cpp | 10 +- {vkconfig => vkconfig_cmd}/main_reset.h | 4 +- vkconfig_core/CMakeLists.txt | 54 +- vkconfig_core/alert.cpp | 97 +- vkconfig_core/alert.h | 21 +- vkconfig_core/application.cpp | 3 +- vkconfig_core/application.h | 28 +- vkconfig_core/bitfield.cpp | 45 + vkconfig_core/bitfield.h | 38 + vkconfig_core/command_line.cpp | 47 +- vkconfig_core/command_line.h | 13 +- vkconfig_core/configuration.cpp | 172 +- vkconfig_core/configuration.h | 16 +- .../configuration_info.cpp | 8 +- vkconfig_core/configuration_info.h | 60 + vkconfig_core/configuration_manager.cpp | 285 +- vkconfig_core/configuration_manager.h | 31 +- .../configurations/2.2.2/Portability.json | 85 - .../{2.2.2 => 3.0.0}/API dump.json | 6 +- .../{2.2.2 => 3.0.0}/Crash Diagnostic.json | 21 +- .../{2.2.2 => 3.0.0}/Frame Capture.json | 6 +- .../configurations/3.0.0/Portability.json | 41 + .../{2.2.2 => 3.0.0}/Synchronization.json | 9 +- .../{2.2.2 => 3.0.0}/Validation.json | 6 +- vkconfig_core/configurator.cpp | 390 ++ {vkconfig => vkconfig_core}/configurator.h | 58 +- .../configurator_signal.cpp | 19 +- .../configurator_signal.h | 4 +- vkconfig_core/doc.cpp | 19 +- vkconfig_core/environment.cpp | 617 +- vkconfig_core/environment.h | 174 +- vkconfig_core/environment_key.h | 40 - vkconfig_core/header.cpp | 2 +- vkconfig_core/header.h | 7 +- vkconfig_core/help.cpp | 2 +- vkconfig_core/json.h | 4 +- vkconfig_core/json_validator.cpp | 2 +- vkconfig_core/json_validator.h | 4 +- vkconfig_core/layer.cpp | 260 +- vkconfig_core/layer.h | 17 +- vkconfig_core/layer_manager.cpp | 327 +- vkconfig_core/layer_manager.h | 41 +- vkconfig_core/layer_state.cpp | 47 - vkconfig_core/layer_state.h | 33 - vkconfig_core/layer_type.cpp | 39 - .../130/VK_LAYER_KHRONOS_validation.json | 328 - .../layers/130/VK_LAYER_LUNARG_api_dump.json | 277 - .../layers/130/VK_LAYER_LUNARG_monitor.json | 22 - .../135/VK_LAYER_KHRONOS_validation.json | 329 - .../layers/135/VK_LAYER_LUNARG_api_dump.json | 277 - .../layers/135/VK_LAYER_LUNARG_monitor.json | 22 - .../135/VK_LAYER_LUNARG_screenshot.json | 93 - .../141/VK_LAYER_KHRONOS_validation.json | 358 - .../layers/141/VK_LAYER_LUNARG_api_dump.json | 276 - .../141/VK_LAYER_LUNARG_gfxreconstruct.json | 409 -- .../layers/141/VK_LAYER_LUNARG_monitor.json | 22 - .../141/VK_LAYER_LUNARG_screenshot.json | 93 - .../148/VK_LAYER_KHRONOS_validation.json | 404 -- .../layers/148/VK_LAYER_LUNARG_api_dump.json | 276 - .../148/VK_LAYER_LUNARG_gfxreconstruct.json | 409 -- .../layers/148/VK_LAYER_LUNARG_monitor.json | 22 - .../148/VK_LAYER_LUNARG_screenshot.json | 93 - .../154/VK_LAYER_KHRONOS_validation.json | 432 -- .../layers/154/VK_LAYER_LUNARG_api_dump.json | 276 - .../154/VK_LAYER_LUNARG_gfxreconstruct.json | 408 -- .../layers/154/VK_LAYER_LUNARG_monitor.json | 22 - .../154/VK_LAYER_LUNARG_screenshot.json | 93 - .../162/VK_LAYER_KHRONOS_validation.json | 510 -- .../layers/162/VK_LAYER_LUNARG_api_dump.json | 276 - .../162/VK_LAYER_LUNARG_gfxreconstruct.json | 429 -- .../layers/162/VK_LAYER_LUNARG_monitor.json | 22 - .../162/VK_LAYER_LUNARG_screenshot.json | 93 - .../170/VK_LAYER_KHRONOS_validation.json | 507 -- .../170/VK_LAYER_LUNARG_screenshot.json | 93 - vkconfig_core/override.cpp | 505 -- vkconfig_core/override.h | 39 - vkconfig_core/parameter.cpp | 97 +- vkconfig_core/parameter.h | 41 +- vkconfig_core/path.cpp | 601 +- vkconfig_core/path.h | 94 +- vkconfig_core/path_manager.cpp | 269 - vkconfig_core/path_manager.h | 79 - vkconfig_core/registry.cpp | 36 +- vkconfig_core/registry.h | 4 +- vkconfig_core/setting.cpp | 8 +- vkconfig_core/setting_filesystem.cpp | 76 +- vkconfig_core/setting_filesystem.h | 24 +- vkconfig_core/setting_list.cpp | 2 +- vkconfig_core/setting_string.cpp | 8 +- vkconfig_core/test/CMakeLists.txt | 25 +- ...on 2.2.2.json => Configuration 3.0.0.json} | 5 +- .../VK_LAYER_LUNARG_reference_1_1_0.json | 0 .../VK_LAYER_LUNARG_reference_1_2_0.json | 0 .../VK_LAYER_LUNARG_reference_1_2_1.json | 0 .../{ => layers}/VK_LAYER_LUNARG_test_00.json | 0 .../{ => layers}/VK_LAYER_LUNARG_test_01.json | 0 .../{ => layers}/VK_LAYER_LUNARG_test_02.json | 0 .../{ => layers}/VK_LAYER_LUNARG_test_03.json | 0 .../{ => layers}/VK_LAYER_LUNARG_test_04.json | 0 .../{ => layers}/VK_LAYER_LUNARG_test_05.json | 0 .../{ => layers}/VK_LAYER_LUNARG_test_06.json | 0 ...2_schema_1_2_1.txt => layers_settings.txt} | 0 ...schema_1_2_1.json => loader_settings.json} | 0 .../test/profiles/VP_KHR_roadmap.json | 390 ++ .../profiles/VP_LUNARG_desktop_baseline.json | 6080 +++++++++++++++++ .../VP_LUNARG_desktop_baseline_config.json | 56 + .../VP_LUNARG_minimum_requirements.json | 400 ++ vkconfig_core/test/resources.qrc | 111 +- .../sdk/VkLayer_api_dump.json} | 55 +- .../sdk/VkLayer_gfxreconstruct.json} | 119 +- .../test/sdk/VkLayer_khronos_profiles.json | 1280 ++++ .../sdk/VkLayer_khronos_shader_object.json | 90 + .../VkLayer_khronos_synchronization2.json} | 28 +- .../test/sdk/VkLayer_khronos_validation.json | 1694 +++++ .../sdk/VkLayer_monitor.json} | 10 +- .../sdk/VkLayer_screenshot.json} | 18 +- vkconfig_core/test/test_bitfield.cpp | 0 vkconfig_core/test/test_command_line.cpp | 30 +- vkconfig_core/test/test_configuration.cpp | 12 +- .../test/test_configuration_built_in.cpp | 294 +- .../test/test_configuration_manager.cpp | 17 +- vkconfig_core/test/test_environment.cpp | 63 +- vkconfig_core/test/test_layer.cpp | 60 +- vkconfig_core/test/test_layer_built_in.cpp | 4 +- vkconfig_core/test/test_layer_manager.cpp | 82 +- vkconfig_core/test/test_override.cpp | 130 +- vkconfig_core/test/test_parameter.cpp | 136 +- vkconfig_core/test/test_path.cpp | 305 +- vkconfig_core/test/test_path_manager.cpp | 149 - .../test/test_setting_type_file_load.cpp | 4 +- .../test/test_setting_type_file_save.cpp | 4 +- .../test/test_setting_type_folder_save.cpp | 8 +- vkconfig_core/test/test_setting_type_list.cpp | 9 + vkconfig_core/test/test_type_hide_message.cpp | 123 + .../test/test_type_layer_control.cpp | 31 + vkconfig_core/test/test_type_layer_type.cpp | 31 + vkconfig_core/test/test_type_layers_mode.cpp | 31 + vkconfig_core/test/test_type_log.cpp | 121 + ...st_platform.cpp => test_type_platform.cpp} | 7 +- vkconfig_core/test/test_type_status.cpp | 31 + ...test_layer_state.cpp => test_type_tab.cpp} | 15 +- vkconfig_core/test/test_util.cpp | 55 +- vkconfig_core/test/test_vulkan.cpp | 19 +- vkconfig_core/type_hide_message.cpp | 122 + vkconfig_core/type_hide_message.h | 63 + vkconfig_core/type_layer_control.cpp | 48 + vkconfig_core/type_layer_control.h | 38 + vkconfig_core/type_layer_type.cpp | 45 + .../{layer_type.h => type_layer_type.h} | 17 +- vkconfig_core/type_layers_mode.cpp | 46 + .../type_layers_mode.h | 30 +- vkconfig_core/type_log.cpp | 122 + vkconfig_core/type_log.h | 64 + .../{platform.cpp => type_platform.cpp} | 31 +- vkconfig_core/{platform.h => type_platform.h} | 19 +- vkconfig_core/type_status.cpp | 51 + .../type_status.h | 25 +- vkconfig_core/type_tab.cpp | 50 + .../combo_box.h => vkconfig_core/type_tab.h | 29 +- .../test_layer_type.cpp => type_update.cpp} | 6 +- .../type_update.h | 18 +- vkconfig_core/util.cpp | 8 +- vkconfig_core/util.h | 24 +- vkconfig_core/version.cpp | 4 +- vkconfig_core/version.h | 4 - .../vulkan_info.cpp | 175 +- vkconfig_core/vulkan_info.h | 41 + vkconfig_core/vulkan_util.cpp | 187 + .../vulkan_util.h | 8 +- {vkconfig => vkconfig_gui}/CHANGELOG.md | 19 +- {vkconfig3 => vkconfig_gui}/CMakeLists.txt | 12 +- {vkconfig => vkconfig_gui}/CONTRIBUTING.md | 0 {vkconfig3 => vkconfig_gui}/README.md | 0 {vkconfig => vkconfig_gui}/combo_box.h | 0 vkconfig_gui/configuration_layer_widget.cpp | 128 + .../configuration_layer_widget.h | 39 +- .../dialog_vulkan_analysis.cpp | 6 +- .../dialog_vulkan_analysis.h | 0 .../dialog_vulkan_analysis.ui | 0 .../dialog_vulkan_info.cpp | 8 +- .../dialog_vulkan_info.h | 0 .../dialog_vulkan_info.ui | 0 .../images/NewLunarGLogoBlack.png | Bin .../images/presentation.gif | Bin .../vkconfig_applications_collapsed.png | Bin .../images/vkconfig_applications_dialog.png | Bin .../images/vkconfig_applications_expanded.png | Bin .../images/vulkan_configurator.png | Bin .../images/vulkan_layers_order.png | Bin .../images/vulkan_layers_order_small.png | Bin .../images/vulkan_loader.png | Bin .../images/vulkan_loader_640px.png | Bin {vkconfig3 => vkconfig_gui}/macOS/Info.plist | 0 .../macOS/Resources/VulkanIcon.icns | Bin .../macOS/vkconfig.cmake | 32 +- .../main_gui.cpp => vkconfig_gui/main.cpp | 66 +- {vkconfig3 => vkconfig_gui}/mainwindow.cpp | 522 +- {vkconfig => vkconfig_gui}/mainwindow.h | 81 +- {vkconfig3 => vkconfig_gui}/mainwindow.ui | 16 +- .../resourcefiles/lunarg_logo.png | Bin .../resourcefiles/qt_logo.png | Bin .../resourcefiles/vkconfig-off.png | Bin .../resourcefiles/vkconfig-on.png | Bin .../resourcefiles/vkconfig.aps | Bin .../resourcefiles/vkconfig.rc | 0 .../resourcefiles/vulkan.ico | Bin .../resourcefiles}/vulkan_configurator.png | Bin vkconfig_gui/resources.qrc | 22 + {vkconfig3 => vkconfig_gui}/settings_tree.cpp | 79 +- {vkconfig3 => vkconfig_gui}/settings_tree.h | 0 .../vkconfig.entitlements | 0 {vkconfig3 => vkconfig_gui}/vkconfig.pro | 69 +- {vkconfig => vkconfig_gui}/widget_preset.cpp | 0 {vkconfig => vkconfig_gui}/widget_preset.h | 0 .../widget_setting.cpp | 0 {vkconfig => vkconfig_gui}/widget_setting.h | 0 .../widget_setting_bool.cpp | 0 .../widget_setting_bool.h | 0 .../widget_setting_enum.cpp | 32 +- .../widget_setting_enum.h | 0 .../widget_setting_filesystem.cpp | 84 +- .../widget_setting_filesystem.h | 9 +- .../widget_setting_flags.cpp | 0 .../widget_setting_flags.h | 0 .../widget_setting_float.cpp | 15 +- .../widget_setting_float.h | 0 .../widget_setting_frames.cpp | 15 +- .../widget_setting_frames.h | 0 .../widget_setting_int.cpp | 15 +- .../widget_setting_int.h | 0 .../widget_setting_list.cpp | 0 .../widget_setting_list.h | 0 .../widget_setting_list_element.cpp | 0 .../widget_setting_list_element.h | 0 .../widget_setting_string.cpp | 0 .../widget_setting_string.h | 0 .../widget_tree_friendly_combobox.cpp | 0 .../widget_tree_friendly_combobox.h | 0 336 files changed, 15169 insertions(+), 23453 deletions(-) delete mode 100644 vkconfig/CMakeLists.txt delete mode 100644 vkconfig/README.md delete mode 100644 vkconfig/configurator.cpp delete mode 100644 vkconfig/dialog_about.cpp delete mode 100644 vkconfig/dialog_about.ui delete mode 100644 vkconfig/dialog_applications.cpp delete mode 100644 vkconfig/dialog_applications.h delete mode 100644 vkconfig/dialog_applications.ui delete mode 100644 vkconfig/dialog_layers.cpp delete mode 100644 vkconfig/dialog_layers.h delete mode 100644 vkconfig/dialog_layers.ui delete mode 100644 vkconfig/dialog_vulkan_analysis.cpp delete mode 100644 vkconfig/main_doc.h delete mode 100644 vkconfig/main_gui.cpp delete mode 100644 vkconfig/main_gui.h delete mode 100644 vkconfig/main_layers.cpp delete mode 100644 vkconfig/main_reset.cpp delete mode 100644 vkconfig/mainwindow.ui delete mode 100644 vkconfig/resources.qrc delete mode 100644 vkconfig/settings_tree.cpp delete mode 100644 vkconfig/settings_tree.h delete mode 100644 vkconfig/settings_validation_areas.cpp delete mode 100644 vkconfig/settings_validation_areas.h delete mode 100644 vkconfig/vkconfig.pro delete mode 100644 vkconfig/widget_setting.cpp delete mode 100644 vkconfig/widget_setting_float.cpp delete mode 100644 vkconfig/widget_setting_frames.cpp delete mode 100644 vkconfig/widget_setting_int.cpp delete mode 100644 vkconfig/widget_tree_friendly_combobox.cpp delete mode 100644 vkconfig/widget_tree_friendly_combobox.h delete mode 100644 vkconfig3/CHANGELOG.md delete mode 100644 vkconfig3/CONTRIBUTING.md delete mode 100644 vkconfig3/configurator.cpp delete mode 100644 vkconfig3/configurator.h delete mode 100644 vkconfig3/dialog_applications.cpp delete mode 100644 vkconfig3/dialog_applications.h delete mode 100644 vkconfig3/dialog_applications.ui delete mode 100644 vkconfig3/dialog_vulkan_analysis.h delete mode 100644 vkconfig3/dialog_vulkan_analysis.ui delete mode 100644 vkconfig3/dialog_vulkan_info.cpp delete mode 100644 vkconfig3/dialog_vulkan_info.h delete mode 100644 vkconfig3/dialog_vulkan_info.ui delete mode 100644 vkconfig3/images/NewLunarGLogoBlack.png delete mode 100644 vkconfig3/images/presentation.gif delete mode 100644 vkconfig3/images/vkconfig_applications_collapsed.png delete mode 100644 vkconfig3/images/vkconfig_applications_dialog.png delete mode 100644 vkconfig3/images/vkconfig_applications_expanded.png delete mode 100644 vkconfig3/images/vulkan_layers_order.png delete mode 100644 vkconfig3/images/vulkan_layers_order_small.png delete mode 100644 vkconfig3/images/vulkan_loader.png delete mode 100644 vkconfig3/images/vulkan_loader_640px.png delete mode 100644 vkconfig3/main.cpp delete mode 100644 vkconfig3/main_doc.cpp delete mode 100644 vkconfig3/main_gui.h delete mode 100644 vkconfig3/main_reset.h delete mode 100644 vkconfig3/main_signal.cpp delete mode 100644 vkconfig3/mainwindow.h delete mode 100644 vkconfig3/resourcefiles/lunarg_logo.png delete mode 100644 vkconfig3/resourcefiles/qt_logo.png delete mode 100644 vkconfig3/resourcefiles/vkconfig-off.png delete mode 100644 vkconfig3/resourcefiles/vkconfig-on.png delete mode 100644 vkconfig3/resourcefiles/vkconfig.aps delete mode 100644 vkconfig3/resourcefiles/vkconfig.rc delete mode 100644 vkconfig3/resourcefiles/vulkan.ico delete mode 100644 vkconfig3/resourcefiles/vulkan_configurator.png delete mode 100644 vkconfig3/resources.qrc delete mode 100644 vkconfig3/vkconfig.entitlements delete mode 100644 vkconfig3/vulkan_util.cpp delete mode 100644 vkconfig3/widget_preset.cpp delete mode 100644 vkconfig3/widget_setting.h delete mode 100644 vkconfig3/widget_setting_bool.cpp delete mode 100644 vkconfig3/widget_setting_bool.h delete mode 100644 vkconfig3/widget_setting_enum.cpp delete mode 100644 vkconfig3/widget_setting_enum.h delete mode 100644 vkconfig3/widget_setting_filesystem.cpp delete mode 100644 vkconfig3/widget_setting_filesystem.h delete mode 100644 vkconfig3/widget_setting_flags.cpp delete mode 100644 vkconfig3/widget_setting_flags.h delete mode 100644 vkconfig3/widget_setting_float.h delete mode 100644 vkconfig3/widget_setting_frames.h delete mode 100644 vkconfig3/widget_setting_int.h delete mode 100644 vkconfig3/widget_setting_list.cpp delete mode 100644 vkconfig3/widget_setting_list.h delete mode 100644 vkconfig3/widget_setting_list_element.cpp delete mode 100644 vkconfig3/widget_setting_list_element.h delete mode 100644 vkconfig3/widget_setting_string.cpp delete mode 100644 vkconfig3/widget_setting_string.h create mode 100644 vkconfig_cmd/CMakeLists.txt rename {vkconfig => vkconfig_cmd}/macOS/Info.plist (100%) rename {vkconfig => vkconfig_cmd}/macOS/Resources/VulkanIcon.icns (100%) rename {vkconfig3 => vkconfig_cmd}/macOS/vkconfig.cmake (71%) rename {vkconfig => vkconfig_cmd}/main.cpp (87%) rename {vkconfig => vkconfig_cmd}/main_doc.cpp (75%) rename {vkconfig3 => vkconfig_cmd}/main_doc.h (84%) rename {vkconfig3 => vkconfig_cmd}/main_layers.cpp (63%) rename {vkconfig3 => vkconfig_cmd}/main_layers.h (89%) rename {vkconfig3 => vkconfig_cmd}/main_reset.cpp (95%) rename {vkconfig => vkconfig_cmd}/main_reset.h (89%) create mode 100644 vkconfig_core/bitfield.cpp create mode 100644 vkconfig_core/bitfield.h rename vkconfig3/main_signal.h => vkconfig_core/configuration_info.cpp (84%) create mode 100644 vkconfig_core/configuration_info.h delete mode 100644 vkconfig_core/configurations/2.2.2/Portability.json rename vkconfig_core/configurations/{2.2.2 => 3.0.0}/API dump.json (76%) rename vkconfig_core/configurations/{2.2.2 => 3.0.0}/Crash Diagnostic.json (95%) rename vkconfig_core/configurations/{2.2.2 => 3.0.0}/Frame Capture.json (82%) create mode 100644 vkconfig_core/configurations/3.0.0/Portability.json rename vkconfig_core/configurations/{2.2.2 => 3.0.0}/Synchronization.json (94%) rename vkconfig_core/configurations/{2.2.2 => 3.0.0}/Validation.json (79%) create mode 100644 vkconfig_core/configurator.cpp rename {vkconfig => vkconfig_core}/configurator.h (53%) rename vkconfig/main_signal.cpp => vkconfig_core/configurator_signal.cpp (78%) rename vkconfig/main_signal.h => vkconfig_core/configurator_signal.h (88%) delete mode 100644 vkconfig_core/environment_key.h delete mode 100644 vkconfig_core/layer_state.cpp delete mode 100644 vkconfig_core/layer_state.h delete mode 100644 vkconfig_core/layer_type.cpp delete mode 100644 vkconfig_core/layers/130/VK_LAYER_KHRONOS_validation.json delete mode 100644 vkconfig_core/layers/130/VK_LAYER_LUNARG_api_dump.json delete mode 100644 vkconfig_core/layers/130/VK_LAYER_LUNARG_monitor.json delete mode 100644 vkconfig_core/layers/135/VK_LAYER_KHRONOS_validation.json delete mode 100644 vkconfig_core/layers/135/VK_LAYER_LUNARG_api_dump.json delete mode 100644 vkconfig_core/layers/135/VK_LAYER_LUNARG_monitor.json delete mode 100644 vkconfig_core/layers/135/VK_LAYER_LUNARG_screenshot.json delete mode 100644 vkconfig_core/layers/141/VK_LAYER_KHRONOS_validation.json delete mode 100644 vkconfig_core/layers/141/VK_LAYER_LUNARG_api_dump.json delete mode 100644 vkconfig_core/layers/141/VK_LAYER_LUNARG_gfxreconstruct.json delete mode 100644 vkconfig_core/layers/141/VK_LAYER_LUNARG_monitor.json delete mode 100644 vkconfig_core/layers/141/VK_LAYER_LUNARG_screenshot.json delete mode 100644 vkconfig_core/layers/148/VK_LAYER_KHRONOS_validation.json delete mode 100644 vkconfig_core/layers/148/VK_LAYER_LUNARG_api_dump.json delete mode 100644 vkconfig_core/layers/148/VK_LAYER_LUNARG_gfxreconstruct.json delete mode 100644 vkconfig_core/layers/148/VK_LAYER_LUNARG_monitor.json delete mode 100644 vkconfig_core/layers/148/VK_LAYER_LUNARG_screenshot.json delete mode 100644 vkconfig_core/layers/154/VK_LAYER_KHRONOS_validation.json delete mode 100644 vkconfig_core/layers/154/VK_LAYER_LUNARG_api_dump.json delete mode 100644 vkconfig_core/layers/154/VK_LAYER_LUNARG_gfxreconstruct.json delete mode 100644 vkconfig_core/layers/154/VK_LAYER_LUNARG_monitor.json delete mode 100644 vkconfig_core/layers/154/VK_LAYER_LUNARG_screenshot.json delete mode 100644 vkconfig_core/layers/162/VK_LAYER_KHRONOS_validation.json delete mode 100644 vkconfig_core/layers/162/VK_LAYER_LUNARG_api_dump.json delete mode 100644 vkconfig_core/layers/162/VK_LAYER_LUNARG_gfxreconstruct.json delete mode 100644 vkconfig_core/layers/162/VK_LAYER_LUNARG_monitor.json delete mode 100644 vkconfig_core/layers/162/VK_LAYER_LUNARG_screenshot.json delete mode 100644 vkconfig_core/layers/170/VK_LAYER_KHRONOS_validation.json delete mode 100644 vkconfig_core/layers/170/VK_LAYER_LUNARG_screenshot.json delete mode 100644 vkconfig_core/override.cpp delete mode 100644 vkconfig_core/override.h delete mode 100644 vkconfig_core/path_manager.cpp delete mode 100644 vkconfig_core/path_manager.h rename vkconfig_core/test/{Configuration 2.2.2.json => Configuration 3.0.0.json} (97%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_reference_1_1_0.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_reference_1_2_0.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_reference_1_2_1.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_test_00.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_test_01.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_test_02.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_test_03.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_test_04.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_test_05.json (100%) rename vkconfig_core/test/{ => layers}/VK_LAYER_LUNARG_test_06.json (100%) rename vkconfig_core/test/{override_settings_2_2_2_schema_1_2_1.txt => layers_settings.txt} (100%) rename vkconfig_core/test/{override_layers_2_2_2_schema_1_2_1.json => loader_settings.json} (100%) create mode 100644 vkconfig_core/test/profiles/VP_KHR_roadmap.json create mode 100644 vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline.json create mode 100644 vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline_config.json create mode 100644 vkconfig_core/test/profiles/VP_LUNARG_minimum_requirements.json rename vkconfig_core/{layers/170/VK_LAYER_LUNARG_api_dump.json => test/sdk/VkLayer_api_dump.json} (88%) rename vkconfig_core/{layers/170/VK_LAYER_LUNARG_gfxreconstruct.json => test/sdk/VkLayer_gfxreconstruct.json} (79%) create mode 100644 vkconfig_core/test/sdk/VkLayer_khronos_profiles.json create mode 100644 vkconfig_core/test/sdk/VkLayer_khronos_shader_object.json rename vkconfig_core/{layers/170/VK_LAYER_KHRONOS_synchronization2.json => test/sdk/VkLayer_khronos_synchronization2.json} (52%) create mode 100644 vkconfig_core/test/sdk/VkLayer_khronos_validation.json rename vkconfig_core/{layers/170/VK_LAYER_LUNARG_monitor.json => test/sdk/VkLayer_monitor.json} (66%) rename vkconfig_core/{layers/130/VK_LAYER_LUNARG_screenshot.json => test/sdk/VkLayer_screenshot.json} (71%) create mode 100644 vkconfig_core/test/test_bitfield.cpp delete mode 100644 vkconfig_core/test/test_path_manager.cpp create mode 100644 vkconfig_core/test/test_type_hide_message.cpp create mode 100644 vkconfig_core/test/test_type_layer_control.cpp create mode 100644 vkconfig_core/test/test_type_layer_type.cpp create mode 100644 vkconfig_core/test/test_type_layers_mode.cpp create mode 100644 vkconfig_core/test/test_type_log.cpp rename vkconfig_core/test/{test_platform.cpp => test_type_platform.cpp} (93%) create mode 100644 vkconfig_core/test/test_type_status.cpp rename vkconfig_core/test/{test_layer_state.cpp => test_type_tab.cpp} (64%) create mode 100644 vkconfig_core/type_hide_message.cpp create mode 100644 vkconfig_core/type_hide_message.h create mode 100644 vkconfig_core/type_layer_control.cpp create mode 100644 vkconfig_core/type_layer_control.h create mode 100644 vkconfig_core/type_layer_type.cpp rename vkconfig_core/{layer_type.h => type_layer_type.h} (72%) create mode 100644 vkconfig_core/type_layers_mode.cpp rename vkconfig/dialog_about.h => vkconfig_core/type_layers_mode.h (56%) create mode 100644 vkconfig_core/type_log.cpp create mode 100644 vkconfig_core/type_log.h rename vkconfig_core/{platform.cpp => type_platform.cpp} (68%) rename vkconfig_core/{platform.h => type_platform.h} (85%) create mode 100644 vkconfig_core/type_status.cpp rename vkconfig3/vulkan_util.h => vkconfig_core/type_status.h (60%) create mode 100644 vkconfig_core/type_tab.cpp rename vkconfig3/combo_box.h => vkconfig_core/type_tab.h (61%) rename vkconfig_core/{test/test_layer_type.cpp => type_update.cpp} (84%) rename vkconfig/vulkan_util.h => vkconfig_core/type_update.h (70%) rename vkconfig/vulkan_util.cpp => vkconfig_core/vulkan_info.cpp (60%) create mode 100644 vkconfig_core/vulkan_info.h create mode 100644 vkconfig_core/vulkan_util.cpp rename vkconfig/main_layers.h => vkconfig_core/vulkan_util.h (78%) rename {vkconfig => vkconfig_gui}/CHANGELOG.md (95%) rename {vkconfig3 => vkconfig_gui}/CMakeLists.txt (81%) rename {vkconfig => vkconfig_gui}/CONTRIBUTING.md (100%) rename {vkconfig3 => vkconfig_gui}/README.md (100%) rename {vkconfig => vkconfig_gui}/combo_box.h (100%) create mode 100644 vkconfig_gui/configuration_layer_widget.cpp rename vkconfig3/widget_preset.h => vkconfig_gui/configuration_layer_widget.h (53%) rename {vkconfig3 => vkconfig_gui}/dialog_vulkan_analysis.cpp (98%) rename {vkconfig => vkconfig_gui}/dialog_vulkan_analysis.h (100%) rename {vkconfig => vkconfig_gui}/dialog_vulkan_analysis.ui (100%) rename {vkconfig => vkconfig_gui}/dialog_vulkan_info.cpp (98%) rename {vkconfig => vkconfig_gui}/dialog_vulkan_info.h (100%) rename {vkconfig => vkconfig_gui}/dialog_vulkan_info.ui (100%) rename {vkconfig => vkconfig_gui}/images/NewLunarGLogoBlack.png (100%) rename {vkconfig => vkconfig_gui}/images/presentation.gif (100%) rename {vkconfig => vkconfig_gui}/images/vkconfig_applications_collapsed.png (100%) rename {vkconfig => vkconfig_gui}/images/vkconfig_applications_dialog.png (100%) rename {vkconfig => vkconfig_gui}/images/vkconfig_applications_expanded.png (100%) rename {vkconfig => vkconfig_gui}/images/vulkan_configurator.png (100%) rename {vkconfig => vkconfig_gui}/images/vulkan_layers_order.png (100%) rename {vkconfig => vkconfig_gui}/images/vulkan_layers_order_small.png (100%) rename {vkconfig => vkconfig_gui}/images/vulkan_loader.png (100%) rename {vkconfig => vkconfig_gui}/images/vulkan_loader_640px.png (100%) rename {vkconfig3 => vkconfig_gui}/macOS/Info.plist (100%) rename {vkconfig3 => vkconfig_gui}/macOS/Resources/VulkanIcon.icns (100%) rename {vkconfig => vkconfig_gui}/macOS/vkconfig.cmake (59%) rename vkconfig3/main_gui.cpp => vkconfig_gui/main.cpp (55%) rename {vkconfig3 => vkconfig_gui}/mainwindow.cpp (82%) rename {vkconfig => vkconfig_gui}/mainwindow.h (74%) rename {vkconfig3 => vkconfig_gui}/mainwindow.ui (99%) rename {vkconfig => vkconfig_gui}/resourcefiles/lunarg_logo.png (100%) rename {vkconfig => vkconfig_gui}/resourcefiles/qt_logo.png (100%) rename {vkconfig => vkconfig_gui}/resourcefiles/vkconfig-off.png (100%) rename {vkconfig => vkconfig_gui}/resourcefiles/vkconfig-on.png (100%) rename {vkconfig => vkconfig_gui}/resourcefiles/vkconfig.aps (100%) rename {vkconfig => vkconfig_gui}/resourcefiles/vkconfig.rc (100%) rename {vkconfig => vkconfig_gui}/resourcefiles/vulkan.ico (100%) rename {vkconfig3/images => vkconfig_gui/resourcefiles}/vulkan_configurator.png (100%) create mode 100644 vkconfig_gui/resources.qrc rename {vkconfig3 => vkconfig_gui}/settings_tree.cpp (88%) rename {vkconfig3 => vkconfig_gui}/settings_tree.h (100%) rename {vkconfig => vkconfig_gui}/vkconfig.entitlements (100%) rename {vkconfig3 => vkconfig_gui}/vkconfig.pro (79%) rename {vkconfig => vkconfig_gui}/widget_preset.cpp (100%) rename {vkconfig => vkconfig_gui}/widget_preset.h (100%) rename {vkconfig3 => vkconfig_gui}/widget_setting.cpp (100%) rename {vkconfig => vkconfig_gui}/widget_setting.h (100%) rename {vkconfig => vkconfig_gui}/widget_setting_bool.cpp (100%) rename {vkconfig => vkconfig_gui}/widget_setting_bool.h (100%) rename {vkconfig => vkconfig_gui}/widget_setting_enum.cpp (84%) rename {vkconfig => vkconfig_gui}/widget_setting_enum.h (100%) rename {vkconfig => vkconfig_gui}/widget_setting_filesystem.cpp (70%) rename {vkconfig => vkconfig_gui}/widget_setting_filesystem.h (88%) rename {vkconfig => vkconfig_gui}/widget_setting_flags.cpp (100%) rename {vkconfig => vkconfig_gui}/widget_setting_flags.h (100%) rename {vkconfig3 => vkconfig_gui}/widget_setting_float.cpp (94%) rename {vkconfig => vkconfig_gui}/widget_setting_float.h (100%) rename {vkconfig3 => vkconfig_gui}/widget_setting_frames.cpp (92%) rename {vkconfig => vkconfig_gui}/widget_setting_frames.h (100%) rename {vkconfig3 => vkconfig_gui}/widget_setting_int.cpp (93%) rename {vkconfig => vkconfig_gui}/widget_setting_int.h (100%) rename {vkconfig => vkconfig_gui}/widget_setting_list.cpp (100%) rename {vkconfig => vkconfig_gui}/widget_setting_list.h (100%) rename {vkconfig => vkconfig_gui}/widget_setting_list_element.cpp (100%) rename {vkconfig => vkconfig_gui}/widget_setting_list_element.h (100%) rename {vkconfig => vkconfig_gui}/widget_setting_string.cpp (100%) rename {vkconfig => vkconfig_gui}/widget_setting_string.h (100%) rename {vkconfig3 => vkconfig_gui}/widget_tree_friendly_combobox.cpp (100%) rename {vkconfig3 => vkconfig_gui}/widget_tree_friendly_combobox.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bb7d207dd..b0352dd4c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,6 @@ find_package(valijson REQUIRED CONFIG) option(BUILD_TESTS "Build tests") option(RUN_ON_GITHUB "Build only tests that can run on Github" OFF) -option(BUILD_EXPERIMENTAL "Build tests for debugging layers" OFF) if(BUILD_TESTS) enable_testing() @@ -116,8 +115,6 @@ if(BUILD_LAYERMGR) endif() add_subdirectory(vkconfig_core) - add_subdirectory(vkconfig) - if(BUILD_EXPERIMENTAL) - add_subdirectory(vkconfig3) - endif() + add_subdirectory(vkconfig_cmd) + add_subdirectory(vkconfig_gui) endif() diff --git a/scripts/github_ci_linux.py b/scripts/github_ci_linux.py index a6ddb76461..79c92d8ca2 100644 --- a/scripts/github_ci_linux.py +++ b/scripts/github_ci_linux.py @@ -89,9 +89,9 @@ def BuildVT(args): RunShellCmd(test_cmd, VT_BUILD_DIR) print("Build Vulkan Configurator with QtCreator") - os.chdir('%s/../vkconfig' % VT_BUILD_DIR) - RunShellCmd('qmake vkconfig.pro', '%s/../vkconfig' % VT_BUILD_DIR) - RunShellCmd('make', '%s/../vkconfig' % VT_BUILD_DIR) + os.chdir('%s/../vkconfig_gui' % VT_BUILD_DIR) + RunShellCmd('qmake vkconfig.pro', '%s/../vkconfig_gui' % VT_BUILD_DIR) + RunShellCmd('make', '%s/../vkconfig_gui' % VT_BUILD_DIR) ret_code = 0 def RunATest(vt_cmd, vt_env): diff --git a/vkconfig/CMakeLists.txt b/vkconfig/CMakeLists.txt deleted file mode 100644 index 2c3588648e..0000000000 --- a/vkconfig/CMakeLists.txt +++ /dev/null @@ -1,56 +0,0 @@ -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_AUTOUIC ON) -find_package(Qt5 COMPONENTS Core Gui Widgets Network QUIET) - -if(NOT Qt5_FOUND) - message(WARNING "WARNING: vkconfig will be excluded because Qt5 was not found. Please add Qt5 into the PATH environment variable") -elseif(Qt5_VERSION VERSION_LESS 5.5) - message(WARNING "WARNING: vkconfig will be excluded because the found Qt version is too old. vkconfig requires version 5.5.") -else() - file(GLOB FILES_UI ./*.ui) - - source_group("UI Files" FILES ${FILES_UI}) - - file(GLOB FILES_SOURCE ./*.cpp) - file(GLOB FILES_HEADER ./*.h) - file(GLOB FILES_DOCS ./*.md) - - source_group("Docs Files" FILES ${FILES_DOCS}) - - set(FILES_ALL ${FILES_UI} ${FILES_SOURCE} ${FILES_HEADER} ${FILES_DOCS} resources.qrc) - - if(NOT APPLE) - if (NOT DEFINED CMAKE_INSTALL_BINDIR) - include(GNUInstallDirs) - endif() - - if(WIN32) - add_executable(vkconfig WIN32 ${FILES_ALL} ${CMAKE_CURRENT_SOURCE_DIR}/resourcefiles/vkconfig.rc) - target_compile_definitions(vkconfig PRIVATE _CRT_SECURE_NO_WARNINGS) - target_compile_options(vkconfig PRIVATE $<$:/MP>) - target_link_libraries(vkconfig Cfgmgr32) - else() - add_executable(vkconfig ${FILES_ALL} ${FILES_UI}) - endif() - - target_link_libraries(vkconfig Vulkan::Headers vkconfig_core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) - target_compile_definitions(vkconfig PRIVATE QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT) - set_target_properties(vkconfig PROPERTIES FOLDER "vkconfig") - - install(TARGETS vkconfig DESTINATION ${CMAKE_INSTALL_BINDIR}) - - if(WIN32) - get_target_property(QMAKE_EXE Qt5::qmake IMPORTED_LOCATION) - get_filename_component(QT_BIN_DIR "${QMAKE_EXE}" DIRECTORY) - find_program(WINDEPLOYQT_EXE windeployqt HINTS "${QT_BIN_DIR}") - - message(STATUS "Will run ${WINDEPLOYQT_EXE} at ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig.exe") - install(CODE "execute_process(COMMAND ${WINDEPLOYQT_EXE} ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig.exe)") - endif() - else() - include(macOS/vkconfig.cmake) - endif() -endif() diff --git a/vkconfig/README.md b/vkconfig/README.md deleted file mode 100644 index 1c574998fd..0000000000 --- a/vkconfig/README.md +++ /dev/null @@ -1,161 +0,0 @@ - -

LunarG

-

Copyright © 2015-2024 LunarG, Inc.

- -[![Creative Commons][3]][4] - -[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License" -[4]: https://creativecommons.org/licenses/by-nd/4.0/ - -

- -*Vulkan Configurator* allows overriding the [layers configuration](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderInterfaceArchitecture.md#layers) used by Vulkan applications at runtime. - -A Vulkan application may configure layers when creating a Vulkan Instance. This layers configuration may be overridden using *Vulkan Configurator* globally or for a selected list of Vulkan applications. - -Finally *Vulkan Configurator* allows using layers from user-defined directories. - -* **[Change Log](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/CHANGELOG.md)**: The history of *Vulkan Configurator* releases. -* **[Bug reports](https://github.com/LunarG/VulkanTools/issues)**: Open a GitHub issue when you encounter a bug. -* **[Roadmap](https://github.com/LunarG/VulkanTools/projects/2)**: Follow *Vulkan Configurator* future developments. -* **[Contributing](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/CONTRIBUTING.md)**: Submit a fix or a feature to *Vulkan Configurator*. - --------------- -## Platforms Support - -| OS | Windows | Linux | macOS | iOS | Android | -| --------| ------------------ | ------------------- | ------------------ | ------- | ------- | -| Support | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | - --------------- -## Downloads - -*Vulkan Configurator* is delivered with the [Vulkan SDK](https://vulkan.lunarg.com/sdk/home). - --------------- -## Using the Vulkan Configurator - -Vulkan Configurator is a graphical user interface (GUI) that may be launched from the console using `vkconfig`. - -The tool is distributed differently, depending on the platform: -- Ubuntu packages: Upon installing the `lunarg-vkconfig` package, the tools will be available from the command line as `vkconfig`. -- Linux tarball: The vkconfig executable comes pre-built; be sure Qt is installed to run it. Run vkconfig on the command line. - - On Ubuntu 20.04 Qt can be installed by running `sudo apt install qt5-default` -- Windows: The tool will be present on the start menu, in the Vulkan SDK menu. User can also invoke from a command line. -- macOS: The tool is provided as an application bundle. Run it by double-clicking the bundle from a Finder window. - -Vulkan Configurator may be used with command line arguments to override layers. Use `vkconfig --help` in the console for more information. - -On Windows 10, Vulkan Configurator can't output to 'Command Prompt' without a redirection to a file because it's a win32 application. -As a workaround, we can run Vulkan Configurator from 'MSYS'. - -![Vulkan Configurator Animated Presentation](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/presentation.gif) - - -### Selecting an Application - -The typical use-case for VkConfig is to make changes and run applications while the tool is still open so -that any changes made are not carried over when the tool exits. -Because of this, VkConfig has an application launcher built in which allows you to select which -application to run. - -![Application Selection](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/vkconfig_applications_collapsed.png) - -Select between any previously-defined applications by clicking the down-facing error on the right of -the application line. -The application selection can also be expanded so the application name, executable path, command-line -arguments, and even the log file can be edited. -To edit these fields in-place, expand the application area by simply expanding the arrow to the left of -the word "Application". - -![Application Selection Expanded](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/vkconfig_applications_expanded.png) - -To add or further edit an application in the launcher, click the 3 periods (`...`) to the far right -of the application field. -This will expand to an application dialog where applications can be added, edited, or removed. - -![Application Dialog](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/vkconfig_applications_dialog.png) - - -### Applications Listed by Name - -Applications are now listed by name so the same application can be added with different names and -different command-line arguments. - -For example, "Rise of the Tomb Raider" and "Half-Life 2" are both available through Valve's Steam -store. -In order to run both application's, the `steam` executable must first be run, but with different -arguments. -Because applications are now listed by name, it is now possible to add both to the Application list so -they can be triggered individually. -This removes the need to edit the command-line when switching between them previously. - -This may also prove useful if running the same application with one or more different command-line -arguments. - - --------------- -## Terminology - -***[Vulkan Layer](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderInterfaceArchitecture.md#layers)***: A layer is an optional library that can intercept Vulkan functions on their way from the Vulkan application down to the Vulkan drivers. Multiple layers can be chained together to use multiple layer functionalities simultaneously. - -***Vulkan Layers Configuration***: A collection of Vulkan Layers executed in [a specific order](#vulkan-layers-execution-order-overview) with specific settings for each layer. - -***[Vulkan Explicit Layers vs Implicit Layer](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderApplicationInterface.md#implicit-vs-explicit-layers)***: An explicit layer has to be explicitly activated by the user from source in `vkCreateInstance`, using Vulkan Configurator or `VK_INSTANCE_LAYERS` environment variable. Implicit layers are enabled by their existence on the system by default. - -***[Vulkan Meta-Layer](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderLayerInterface.md#override-meta-layer)***: Meta-layers are a special kind of layer which is only available through the desktop [Vulkan Loader](https://github.com/KhronosGroup/Vulkan-Loader). While usual layers are associated with one particular library, a meta-layer is actually a collection layer which contains an ordered list of other layers called *component layers*. - -***Vulkan Override Layer***: The Vulkan Override Layer is an implicit meta-layer found on the system with the name `VK_LAYER_LUNARG_override`. It is the mechanism used by *Vulkan Configurator* to override Vulkan applications layers. This layer contains: -- The ordered list of layers to activate -- The list of layers to exclude from execution -- The list of paths to executables that the layers override applies to. If this list is empty, the override is applied to every application upon startup. - -***Vulkan Layer settings***: Per-layer settings loaded by each layer library and stored in the `vk_layer_settings.txt` file. This file is located either next to the Vulkan application executable or set globally and applied to all Vulkan applications thanks to *Vulkan Configurator*. These settings are described [here for VK_LAYER_KHRONOS_validation](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/main/layers/vk_layer_settings.txt) and [here for other layers created by LunarG](https://github.com/LunarG/VulkanTools/blob/main/layersvt/vk_layer_settings.txt). - --------------- -## Vulkan Layers execution order overview - -[ ![Vulkan Loader](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/vulkan_layers_order_small.png) ](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/vulkan_layers_order.png) - --------------- -## Vulkan Loader and Layers implementation overview - -[ ![Vulkan Loader](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/vulkan_loader_640px.png) ](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/images/vulkan_loader.png) - -For detailed information, read the [Architecture of the Vulkan Loader Interfaces](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/loader/LoaderAndLayerInterface.md) document. - -## Vulkan Layers Settings - -### `vk_layer_settings.txt` - -The layer settings are stored into the `vk_layer_settings.txt` file and read directly by the layers. - -When *Vulkan Configurator is used to override layers, the Vulkan application local `vk_layer_settings.txt` file is ignored by layer ecosystem convention. - -*Vulkan Configurator* does not make any system-wide changes to a system, but it does make user-specific changes. -These changes are documented below: - -#### Linux and macOS - -Unix systems store files in the following paths: - -- `$HOME/.local/share/vulkan/implicit_layer.d/VkLayer_override.json` tells a Vulkan application which layers to use -- `$HOME/.local/share/vulkan/settings.d/vk_layer_settings.txt` tells Vulkan layers which settings to use - -#### Windows - -Windows systems store files in the following paths: - -- `%HOME%\AppData\Local\LunarG\vkconfig\override\VkLayerOverride.json` tells a Vulkan application which layers to use -- `%HOME%\AppData\Local\LunarG\vkconfig\override\vk_layer_settings.txt` tells Vulkan layers which settings to use - -In addition, Windows system create registry entries in the following locations: - -- `HKEY_CURRENT_USER\Software\Khronos\Vulkan\ImplicitLayers` will have an entry that points to the JSON file above -- `HKEY_CURRENT_USER\Software\Khronos\Vulkan\Settings` will have an entry that points to the text file above -- `HKEY_CURRENT_USER\Software\LunarG\vkconfig` stores the application settings for `vkconfig` - -### Environment Variables (Deprecated) - -OS Environment Variables are the legacy approach to configure layers however they should be considered deprecated in favor of using `vk_layer_settings.txt` either locally, next to the Vulkan Applications or globally, generated from *Vulkan Configurator*. - diff --git a/vkconfig/configurator.cpp b/vkconfig/configurator.cpp deleted file mode 100644 index ed757d51c6..0000000000 --- a/vkconfig/configurator.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Lenny Komow - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "configurator.h" -#include "vulkan_util.h" - -#include "dialog_layers.h" - -#include "../vkconfig_core/util.h" -#include "../vkconfig_core/path.h" -#include "../vkconfig_core/override.h" -#include "../vkconfig_core/alert.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -Configurator &Configurator::Get(const std::string &VULKAN_SDK) { - static Configurator configurator(VULKAN_SDK); - return configurator; -} - -Configurator::Configurator(const std::string &VULKAN_SDK) - : path(VULKAN_SDK, SUPPORTED_CONFIG_FILES), environment(path), layers(environment), configurations(environment) {} - -Configurator::~Configurator() { - configurations.SaveAllConfigurations(layers.selected_layers); - - SurrenderConfiguration(environment); -} - -bool Configurator::Init() { - std::string selected_configuration = this->environment.GetSelectedConfiguration(); - - this->ActivateConfiguration(""); - - this->UpdateDevices(); - - // Load simple app settings, the additional search paths, and the - // override app list. - this->layers.LoadAllInstalledLayers(); - - QSettings settings; - if (settings.value("crashed", QVariant(false)).toBool()) { - settings.setValue("crashed", false); - - if (Alert::ConfiguratorCrashed() == QMessageBox::No) { - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - } else { - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - - if (this->configurations.Empty()) { - this->configurations.ResetDefaultsConfigurations(layers.selected_layers); - } else { - this->configurations.FirstDefaultsConfigurations(layers.selected_layers); - } - - this->ActivateConfiguration(selected_configuration); - - return true; -} - -void Configurator::ActivateConfiguration(const std::string &configuration_name) { - Configuration *configuration = nullptr; - if (!configuration_name.empty()) { - configuration = FindByKey(this->configurations.available_configurations, configuration_name.c_str()); - } - - if (configuration_name.empty()) { - this->environment.SetSelectedConfiguration(""); - this->configurations.Configure(this->layers.selected_layers); - } else if (configuration == nullptr) { - QMessageBox alert; - alert.QDialog::setWindowTitle("Vulkan layers configuration is missing..."); - const std::string text = format("%s couldn't find '%s' layers configuration.", VKCONFIG_NAME, configuration_name.c_str()); - alert.setText(text.c_str()); - alert.setInformativeText("Vulkan Configurator is switching to Layers Controlled by Vulkan Application mode"); - alert.setIcon(QMessageBox::Critical); - alert.exec(); - - this->environment.SetSelectedConfiguration(""); - this->environment.SetMode(LAYERS_MODE_BY_APPLICATIONS); - this->configurations.Configure(this->layers.selected_layers); - } else { - // If the layers paths are differents, we need to reload the layers and the configurations - const std::vector paths = this->environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_GUI); - if (configuration->user_defined_paths != paths) { - this->configurations.SaveAllConfigurations(this->layers.selected_layers); - this->environment.SetPerConfigUserDefinedLayersPaths(configuration->user_defined_paths); - this->layers.LoadAllInstalledLayers(); - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - - this->environment.SetSelectedConfiguration(configuration_name.c_str()); - - std::string missing_layer; - if (::HasMissingLayer(configuration->parameters, layers.selected_layers, missing_layer)) { - QMessageBox alert; - alert.QDialog::setWindowTitle("Vulkan layer missing..."); - alert.setText(format("%s couldn't find '%s' layer required by '%s' configuration:", VKCONFIG_NAME, - missing_layer.c_str(), configuration->key.c_str()) - .c_str()); - alert.setInformativeText("Do you want to edit the configuration to locate the layer?"); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setIcon(QMessageBox::Warning); - if (alert.exec() == QMessageBox::Yes) { - LayersDialog dlg(nullptr, *configuration); - dlg.exec(); - - ActivateConfiguration(configuration->key); - } - } else { - this->configurations.Configure(this->layers.selected_layers); - } - } -} - -void Configurator::UpdateDevices() { - QLibrary library(GetVulkanLibrary()); - - VkInstance instance = VK_NULL_HANDLE; - VkResult err = CreateInstance(library, instance, false); - - if (err != VK_SUCCESS) { - err = CreateInstance(library, instance, true); - if (err != VK_SUCCESS) { - return; - } - } - - PFN_vkEnumeratePhysicalDevices pfnEnumeratePhysicalDevices = - (PFN_vkEnumeratePhysicalDevices)library.resolve("vkEnumeratePhysicalDevices"); - PFN_vkDestroyInstance pfnDestroyInstance = (PFN_vkDestroyInstance)library.resolve("vkDestroyInstance"); - PFN_vkGetPhysicalDeviceProperties pfnGetPhysicalDeviceProperties = - (PFN_vkGetPhysicalDeviceProperties)library.resolve("vkGetPhysicalDeviceProperties"); - - if (pfnEnumeratePhysicalDevices == nullptr || pfnDestroyInstance == nullptr || pfnGetPhysicalDeviceProperties == nullptr) { - return; - } - - uint32_t gpu_count = 0; - err = pfnEnumeratePhysicalDevices(instance, &gpu_count, NULL); - assert(!err); - - std::vector devices; - if (gpu_count > 0) { - devices.resize(gpu_count); - - err = pfnEnumeratePhysicalDevices(instance, &gpu_count, &devices[0]); - assert(!err); - } - - this->device_names.clear(); - for (std::size_t i = 0, n = devices.size(); i < n; ++i) { - VkPhysicalDeviceProperties properties; - pfnGetPhysicalDeviceProperties(devices[i], &properties); - - this->device_names.push_back(properties.deviceName); - } - - pfnDestroyInstance(instance, NULL); -} - -bool Configurator::SupportDifferentLayerVersions(Version *return_loader_version) const { - // Check loader version - const Version version = GetVulkanLoaderVersion(); - assert(version != Version::VERSION_NULL); - - if (return_loader_version) { - *return_loader_version = version; - } - - return version >= Version("1.3.212"); -} - -bool Configurator::SupportApplicationList(Version *return_loader_version) const { - // Check loader version - const Version version = GetVulkanLoaderVersion(); - assert(version != Version::VERSION_NULL); - - if (return_loader_version) { - *return_loader_version = version; - } - - return version >= Version("1.2.141"); -} - -void Configurator::ResetToDefault(bool hard) { - if (hard) { - this->environment.Reset(Environment::CLEAR); - this->layers.LoadAllInstalledLayers(); - this->configurations.ResetDefaultsConfigurations(this->layers.selected_layers); - - this->ActivateConfiguration(this->environment.GetSelectedConfiguration()); - } else { - this->configurations.ReloadDefaultsConfigurations(this->layers.selected_layers); - } -} - -std::vector Configurator::GetDeviceNames() const { return device_names; } diff --git a/vkconfig/dialog_about.cpp b/vkconfig/dialog_about.cpp deleted file mode 100644 index 982058e889..0000000000 --- a/vkconfig/dialog_about.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "dialog_about.h" - -AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::dialog_about) { - ui->setupUi(this); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - connect(ui->pbAboutQt, SIGNAL(clicked()), this, SLOT(aboutQt())); -} - -void AboutDialog::aboutQt() { qApp->aboutQt(); } diff --git a/vkconfig/dialog_about.ui b/vkconfig/dialog_about.ui deleted file mode 100644 index 399364cc8a..0000000000 --- a/vkconfig/dialog_about.ui +++ /dev/null @@ -1,220 +0,0 @@ - - - dialog_about - - - - 0 - 0 - 417 - 195 - - - - - 0 - 0 - - - - - 417 - 195 - - - - - 417 - 195 - - - - - Arial - 10 - - - - About Vulkan Configurator - - - - - 80 - 150 - 301 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - - - 180 - 20 - 241 - 41 - - - - - Arial - 10 - 50 - false - - - - Qt::LeftToRight - - - Copyright (c) 2020-2024 LunarG, Inc. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - 180 - 50 - 251 - 31 - - - - - Arial - 10 - 50 - false - - - - Licensed under Apache 2.0 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - 20 - 10 - 161 - 71 - - - - - - - :/resourcefiles/lunarg_logo.png - - - - - - 130 - 100 - 231 - 41 - - - - - Arial - 10 - 50 - false - - - - Qt licensed under LGPL 3.0 - - - true - - - - - - 130 - 150 - 81 - 32 - - - - About Qt - - - - - - 20 - 100 - 91 - 81 - - - - - - - :/resourcefiles/qt_logo.png - - - - - - - - - buttonBox - accepted() - dialog_about - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - dialog_about - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/vkconfig/dialog_applications.cpp b/vkconfig/dialog_applications.cpp deleted file mode 100644 index 07053cc16e..0000000000 --- a/vkconfig/dialog_applications.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "dialog_applications.h" -#include "configurator.h" - -#include "../vkconfig_core/alert.h" - -#include -#include -#include -#include - -#include - -ApplicationsDialog::ApplicationsDialog(QWidget *parent) - : QDialog(parent), ui(new Ui::dialog_applications()), _last_selected_application_index(-1) { - ui->setupUi(this); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - - Configurator &configurator = Configurator::Get(); - - // The header is hidden by default and stays hidden when no checkboxes are used. - if (!configurator.environment.GetUseApplicationList()) - setWindowTitle("Vulkan Applications Launcher Shortcuts"); - else { - ui->treeWidget->setHeaderHidden(false); - ui->treeWidget->setHeaderLabel("Check to override Vulkan layers"); - } - - // Show the current list - const std::vector &applications = configurator.environment.GetApplications(); - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - CreateApplicationItem(applications[i]); - } - - ui->treeWidget->installEventFilter(this); - - connect(ui->treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, - SLOT(selectedPathChanged(QTreeWidgetItem *, QTreeWidgetItem *))); - connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(itemChanged(QTreeWidgetItem *, int))); - connect(ui->lineEditAppName, SIGNAL(textEdited(const QString &)), this, SLOT(editAppName(const QString &))); - connect(ui->lineEditExecutable, SIGNAL(textEdited(const QString &)), this, SLOT(editExecutable(const QString &))); - connect(ui->lineEditCmdArgs, SIGNAL(textEdited(const QString &)), this, SLOT(editCommandLine(const QString &))); - connect(ui->lineEditWorkingFolder, SIGNAL(textEdited(const QString &)), this, SLOT(editWorkingFolder(const QString &))); - connect(ui->lineEditLogFile, SIGNAL(textEdited(const QString &)), this, SLOT(editLogFile(const QString &))); - - // If there is an item in the tree (nullptr is okay here), make it the currently selected item. - // This is a work around for macOS, where the currentItemChanged() signal is being emitted (by something) - // after this constructor, without actually selecting the first row. The effect there is, the remove button is - // enabled, and the first item is selected, but not visibly so. Repainting does not fix the issue either. This - // is a macOS only fix, but is put in for all platforms so that the GUI behavior is consistent across all - // platforms. - QTreeWidgetItem *item = ui->treeWidget->topLevelItem(0); - ui->treeWidget->setCurrentItem(item); -} - -bool ApplicationsDialog::eventFilter(QObject *target, QEvent *event) { - // Launch tree does some fancy resizing and since it's down in - // layouts and splitters, we can't just rely on the resize method - // of this window. - if (target == ui->treeWidget) { - if (event->type() == QEvent::Resize) { - ui->treeWidget->resizeColumnToContents(1); - int nLastColumnWidth = ui->treeWidget->columnWidth(1); - QRect rect = ui->treeWidget->geometry(); - ui->treeWidget->setColumnWidth(0, rect.width() - nLastColumnWidth); - } - } - return false; -} - -/// Make sure any changes are saved -void ApplicationsDialog::closeEvent(QCloseEvent *event) { - Environment &environment = Configurator::Get().environment; - - event->accept(); - - // When we don't use overridden list only, no need to alert the user about empty list cases. - if (!environment.GetUseApplicationList()) return; - - if (environment.GetApplications().empty() || !environment.HasOverriddenApplications()) { - environment.SetUseApplicationList(false); - - Alert::ApplicationListEmpty(); - } -} - -/// Browse for and select an executable file to add to the list. -void ApplicationsDialog::on_pushButtonAdd_clicked() // Pick the test application -{ - Configurator &configurator = Configurator::Get(); - - const std::string suggested_path(configurator.path.GetPath(PATH_EXECUTABLE).c_str()); - std::string executable_full_path = configurator.path.SelectPath(this, PATH_EXECUTABLE, suggested_path).c_str(); - - // If they have selected something! - if (!executable_full_path.empty()) { - // On macOS, they may have selected a binary, or they may have selected an app bundle. - // If the later, we need to drill down to the actuall applicaiton - if (executable_full_path.find(".app") != std::string::npos) { - // Start by drilling down - ExactExecutableFromAppBundle(executable_full_path); - } - - std::string app_name; - if (executable_full_path.find(GetNativeSeparator()) != std::string::npos) { - app_name = executable_full_path.substr(executable_full_path.rfind(GetNativeSeparator()) + 1); - } else { - app_name = executable_full_path; - } - - Application new_application(app_name, executable_full_path, ""); - configurator.environment.AppendApplication(new_application); - - QTreeWidgetItem *item = CreateApplicationItem(new_application); - - // To update the application list configuration - configurator.configurations.Configure(configurator.layers.selected_layers); - - ui->treeWidget->setCurrentItem(item); - configurator.environment.SelectActiveApplication(ui->treeWidget->indexOfTopLevelItem(item)); - } -} - -QTreeWidgetItem *ApplicationsDialog::CreateApplicationItem(const Application &application) const { - Configurator &configurator = Configurator::Get(); - - QTreeWidgetItem *item = new QTreeWidgetItem(); - ui->treeWidget->addTopLevelItem(item); - - if (configurator.environment.GetUseApplicationList()) { - QCheckBox *check_box = new QCheckBox(application.app_name.c_str()); - check_box->setChecked(application.layers_mode != LAYERS_MODE_BY_APPLICATIONS); - ui->treeWidget->setItemWidget(item, 0, check_box); - connect(check_box, SIGNAL(stateChanged(int)), this, SLOT(OnStateChanged(int))); - } else { - item->setText(0, application.app_name.c_str()); - } - - return item; -} - -/// Easy enough, just remove the selected program from the list -void ApplicationsDialog::on_pushButtonRemove_clicked() { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - int selection = ui->treeWidget->indexOfTopLevelItem(current); - assert(selection >= 0 && selection < ui->treeWidget->topLevelItemCount()); - - Configurator &configurator = Configurator::Get(); - - ui->treeWidget->takeTopLevelItem(selection); - ui->treeWidget->setCurrentItem(nullptr); - configurator.environment.RemoveApplication(selection); - - ui->groupLaunchInfo->setEnabled(false); - ui->pushButtonRemove->setEnabled(false); - ui->pushButtonSelect->setEnabled(false); - ui->lineEditAppName->setText(""); - ui->lineEditExecutable->setText(""); - ui->lineEditCmdArgs->setText(""); - ui->lineEditWorkingFolder->setText(""); - ui->lineEditLogFile->setText(""); - - // Update the application list configuration - configurator.configurations.Configure(configurator.layers.selected_layers); - - ui->treeWidget->update(); -} - -// Dismiss the dialog, and preserve app information so it can be set to -// the launcher. -void ApplicationsDialog::on_pushButtonSelect_clicked() { - Configurator &configurator = Configurator::Get(); - QTreeWidgetItem *item = ui->treeWidget->currentItem(); - if (item != nullptr) { - configurator.environment.SelectActiveApplication(ui->treeWidget->indexOfTopLevelItem(item)); - } - - close(); -} - -/// The remove button is disabled until/unless something is selected that can -/// be removed. Also the working folder and command line arguments are updated -void ApplicationsDialog::selectedPathChanged(QTreeWidgetItem *current_item, QTreeWidgetItem *previous_item) { - (void)previous_item; - int application_index = ui->treeWidget->indexOfTopLevelItem(current_item); - - ui->groupLaunchInfo->setEnabled(application_index >= 0); - ui->pushButtonRemove->setEnabled(application_index >= 0); - ui->pushButtonSelect->setEnabled(application_index >= 0); - - if (application_index < 0) { - ui->lineEditAppName->setText(""); - ui->lineEditExecutable->setText(""); - ui->lineEditCmdArgs->setText(""); - ui->lineEditWorkingFolder->setText(""); - ui->lineEditLogFile->setText(""); - return; - } - - const Application &application = Configurator::Get().environment.GetApplication(application_index); - - ui->lineEditAppName->setText(application.app_name.c_str()); - ui->lineEditExecutable->setText(application.executable_path.c_str()); - ui->lineEditExecutable->setToolTip(ReplaceBuiltInVariable(application.executable_path.c_str()).c_str()); - ui->lineEditWorkingFolder->setText(application.working_folder.c_str()); - ui->lineEditWorkingFolder->setToolTip(ReplaceBuiltInVariable(application.working_folder.c_str()).c_str()); - ui->lineEditCmdArgs->setText(application.arguments.c_str()); - ui->lineEditLogFile->setText(application.log_file.c_str()); - ui->lineEditLogFile->setToolTip(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); -} - -void ApplicationsDialog::itemChanged(QTreeWidgetItem *item, int column) { - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(item); - QCheckBox *check_box = dynamic_cast(ui->treeWidget->itemWidget(item, column)); - if (check_box != nullptr) { - Configurator::Get().environment.GetApplication(_last_selected_application_index).layers_mode = - check_box->isChecked() ? LAYERS_MODE_BY_CONFIGURATOR_RUNNING : LAYERS_MODE_BY_APPLICATIONS; - } -} - -/// Something was clicked. We don't know what, and short of setting up a new -/// signal/slot for each button, this seemed a reasonable approach. Just poll -/// all of them. There aren't that many, so KISS (keep it simple stupid) -/// If one of them had their state flipped, that's the one that was checked, make -/// it the currently selected one. -void ApplicationsDialog::OnStateChanged(int) { - Environment &environment = Configurator::Get().environment; - const bool need_checkbox = environment.GetUseApplicationList(); - if (!need_checkbox) return; - - // Loop through the whole list and reset the checkboxes - for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { - QTreeWidgetItem *item = ui->treeWidget->topLevelItem(i); - QCheckBox *check_box = dynamic_cast(ui->treeWidget->itemWidget(item, 0)); - assert(check_box != nullptr); - environment.GetApplication(i).layers_mode = - check_box->isChecked() ? LAYERS_MODE_BY_CONFIGURATOR_RUNNING : LAYERS_MODE_BY_APPLICATIONS; - } -} - -void ApplicationsDialog::editAppName(const QString &name) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).app_name = name.toStdString(); -} - -void ApplicationsDialog::editExecutable(const QString &executable) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).executable_path = executable.toStdString(); -} - -void ApplicationsDialog::editCommandLine(const QString &cmdLine) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).arguments = cmdLine.toStdString(); -} - -void ApplicationsDialog::editWorkingFolder(const QString &workingFolder) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).working_folder = workingFolder.toStdString(); -} - -void ApplicationsDialog::editLogFile(const QString &logFile) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).log_file = logFile.toStdString(); -} diff --git a/vkconfig/dialog_applications.h b/vkconfig/dialog_applications.h deleted file mode 100644 index e676324ce2..0000000000 --- a/vkconfig/dialog_applications.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "ui_dialog_applications.h" - -#include "../vkconfig_core/application.h" - -#include - -class ApplicationsDialog : public QDialog { - Q_OBJECT - - public: - explicit ApplicationsDialog(QWidget *parent = nullptr); - - int GetSelectedLaunchApplicationIndex() const { return _last_selected_application_index; } - - private: - QTreeWidgetItem *CreateApplicationItem(const Application &application) const; - - void closeEvent(QCloseEvent *) override; - bool eventFilter(QObject *target, QEvent *event) override; - - public Q_SLOTS: - void on_pushButtonAdd_clicked(); // Pick the application - void on_pushButtonRemove_clicked(); // Remove - void on_pushButtonSelect_clicked(); // Make this the current launcher app - void selectedPathChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); // Used to enable remove button - void itemChanged(QTreeWidgetItem *item, int column_index); - - void OnStateChanged(int); - - void editAppName(const QString &name); - void editExecutable(const QString &name); - void editCommandLine(const QString &cmd_line); - void editWorkingFolder(const QString &working_folder); - void editLogFile(const QString &log_file); - - private: - ApplicationsDialog(const ApplicationsDialog &) = delete; - ApplicationsDialog &operator=(const ApplicationsDialog &) = delete; - - std::unique_ptr ui; - int _last_selected_application_index; -}; diff --git a/vkconfig/dialog_applications.ui b/vkconfig/dialog_applications.ui deleted file mode 100644 index dd52a4b9d8..0000000000 --- a/vkconfig/dialog_applications.ui +++ /dev/null @@ -1,176 +0,0 @@ - - - dialog_applications - - - - 0 - 0 - 606 - 375 - - - - - Arial - 10 - - - - Vulkan Applications with overridden Vulkan Layers - - - - - - Add... - - - - - - - false - - - Remove - - - - - - - false - - - Ok - - - - - - - - Arial - 10 - - - - - - - Qt::ScrollBarAlwaysOff - - - 4 - - - true - - - 1 - - - false - - - false - - - - 1 - - - - - - - - false - - - - 0 - 60 - - - - This information is used only when the application is launched manually from vkconfig. - - - Monitored Launch Info - - - - - - Application: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Executable: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Working Folder: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Command Line Arguments: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Log File - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - diff --git a/vkconfig/dialog_layers.cpp b/vkconfig/dialog_layers.cpp deleted file mode 100644 index 9db37628b8..0000000000 --- a/vkconfig/dialog_layers.cpp +++ /dev/null @@ -1,746 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "dialog_layers.h" - -#include "configurator.h" - -#include "../vkconfig_core/alert.h" -#include "../vkconfig_core/platform.h" -#include "../vkconfig_core/util.h" -#include "../vkconfig_core/doc.h" - -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS -// From Stack Overflow. -#define MKPTR(p1, p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2)) - -typedef enum _pe_architecture { - PE_ARCHITECTURE_UNKNOWN = 0x0000, - PE_ARCHITECTURE_ANYCPU = 0x0001, - PE_ARCHITECTURE_X86 = 0x010B, - PE_ARCHITECTURE_x64 = 0x020B -} PE_ARCHITECTURE; - -static PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) { - // Parse and validate the DOS header - IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER *)pImageBase; - if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; - - // Parse and validate the NT header - IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS *)MKPTR(pDosHd, pDosHd->e_lfanew); - if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; - - // First, naive, check based on the 'Magic' number in the Optional Header. - PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic; - - return architecture; -} - -// End Stack Overflow -#endif - -/// Utility function to see if the file is 32-bit -static bool IsDLL32Bit(const std::string full_path) { -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS - if (full_path.empty()) return false; - - QFile file(full_path.c_str()); - if (!file.open(QIODevice::ReadOnly)) { - return false; // punt... - } - - // Not gonna lie, just guessed 1024 and it was enough. - // This is the minimum page size on any OS (I might be wrong, - // it could be 4096), so going lower is not really helpful. - // Changed to 4096 on a whim; looking for crashing bug I can't debug - void *header = file.map(0, 4096, QFileDevice::MapPrivateOption); - - // Another punt as we may not be able to map the file - if (header == nullptr) return false; - - PE_ARCHITECTURE arch = GetImageArchitecture(header); - - file.unmap((uchar *)header); - file.close(); - - return (PE_ARCHITECTURE_X86 == arch); -#else - (void)full_path; - return false; -#endif -} - -LayersDialog::LayersDialog(QWidget *parent, const Configuration &configuration) - : QDialog(parent), configuration(configuration), ui(new Ui::dialog_layers) { - ui->setupUi(this); - - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - - Configurator &configurator = Configurator::Get(); - configurator.configurations.SaveAllConfigurations(configurator.layers.selected_layers); - - ui->lineEditName->setText(configuration.key.c_str()); - ui->lineEditName->setFocus(); - ui->lineEditDescription->setText(configuration.description.c_str()); - ui->buttonBox->setEnabled(!configurator.layers.Empty()); - ui->pushButtonRemove->setEnabled(false); - - Environment &environment = configurator.environment; - restoreGeometry(environment.Get(LAYOUT_LAYER_GEOMETRY)); - - const QByteArray &restore_splitter_state = environment.Get(LAYOUT_LAYER_SPLITTER); - if (restore_splitter_state.isEmpty()) { - ui->splitter->setSizes(QList({300, 30})); - } else { - ui->splitter->restoreState(environment.Get(LAYOUT_LAYER_SPLITTER)); - } - - QTreeWidgetItem *header_item = ui->layerTree->headerItem(); - - header_item->setText(0, "Layers"); - header_item->setText(1, "Usage"); - - connect(ui->layerTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, - SLOT(currentLayerChanged(QTreeWidgetItem *, QTreeWidgetItem *))); - - connect(ui->layerTreeSorted, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, - SLOT(OnLayerTreeSortedClicked(QTreeWidgetItem *, int))); - - this->Reinit(); -} - -LayersDialog::~LayersDialog() { - Environment &environment = Configurator::Get().environment; - - environment.Set(LAYOUT_LAYER_SPLITTER, ui->splitter->saveState()); - environment.Set(LAYOUT_LAYER_GEOMETRY, saveGeometry()); -} - -void LayersDialog::Reinit() { - this->BuildParameters(); - - this->LoadAvailableLayersUI(); - this->LoadSortedLayersUI(); - this->LoadUserDefinedPaths(); - - this->UpdateUI(); -} - -struct ParameterState { - std::string key; - LayerState state; -}; - -static std::vector StoreParameterStates(const std::vector ¶meters) { - std::vector ParameterStates; - for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - ParameterState state; - state.key = parameters[i].key; - state.state = parameters[i].state; - ParameterStates.push_back(state); - } - return ParameterStates; -} - -static void RestoreParameterStates(std::vector &Parameters, const std::vector &states) { - for (std::size_t i = 0, n = states.size(); i < n; ++i) { - Parameter *saved_parameter = FindByKey(Parameters, states[i].key.c_str()); - if (saved_parameter == nullptr) continue; - - saved_parameter->state = states[i].state; - } -} - -void LayersDialog::Reload() { - std::string configuration_name = this->configuration.key; - const std::vector &ParameterStates = StoreParameterStates(this->configuration.parameters); - std::vector user_defined_paths = this->configuration.user_defined_paths; - - Configurator &configurator = Configurator::Get(); - configurator.configurations.SaveAllConfigurations(configurator.layers.selected_layers); - configurator.configurations.available_configurations.clear(); - configurator.environment.SetPerConfigUserDefinedLayersPaths(this->configuration.user_defined_paths); - - configurator.layers.LoadAllInstalledLayers(); - configurator.configurations.LoadAllConfigurations(configurator.layers.selected_layers); - - Configuration *saved_configuration = - FindByKey(configurator.configurations.available_configurations, configuration_name.c_str()); - if (saved_configuration != nullptr) { - this->configuration = *saved_configuration; - this->BuildParameters(); - } - - RestoreParameterStates(this->configuration.parameters, ParameterStates); - this->configuration.user_defined_paths = user_defined_paths; - - configurator.environment.SetSelectedConfiguration(configuration_name); - configurator.configurations.Configure(configurator.layers.selected_layers); -} - -void LayersDialog::UpdateUI() { - this->UpdateButtons(); - - if (!selected_available_layer_name.empty()) { - for (int i = 0, n = ui->layerTree->topLevelItemCount(); i < n; ++i) { - TreeWidgetItemParameter *layer_item = dynamic_cast(ui->layerTree->topLevelItem(i)); - if (layer_item->layer_name != selected_available_layer_name) continue; - - ui->layerTree->setCurrentItem(layer_item); - } - } else if (ui->layerTree->topLevelItemCount() > 0) { - ui->layerTree->setCurrentItem(ui->layerTree->topLevelItem(0)); - } - - if (!selected_sorted_layer_name.empty() && ui->layerTreeSorted->topLevelItemCount() > 1) { - for (int i = 0, n = ui->layerTreeSorted->topLevelItemCount(); i < n; ++i) { - TreeWidgetItemParameter *layer_item = dynamic_cast(ui->layerTreeSorted->topLevelItem(i)); - if (layer_item->layer_name != selected_sorted_layer_name) continue; - - ui->layerTreeSorted->setCurrentItem(layer_item); - } - } else if (ui->layerTreeSorted->topLevelItemCount() > 1) { - ui->layerTreeSorted->setCurrentItem(ui->layerTreeSorted->topLevelItem(0)); - } - - ui->layerTreeSorted->setEnabled(ui->layerTreeSorted->topLevelItemCount() > 1); - - QTreeWidgetItem *current_sorted_layers = ui->layerTreeSorted->currentItem(); - const bool has_selected_sorted_item = current_sorted_layers != nullptr; - - const bool has_above_sorted_item = ui->layerTreeSorted->itemAbove(current_sorted_layers) != nullptr; - ui->pushButtonUp->setEnabled(has_selected_sorted_item && has_above_sorted_item); - - const bool has_below_sorted_item = ui->layerTreeSorted->itemBelow(current_sorted_layers) != nullptr; - ui->pushButtonDown->setEnabled(has_selected_sorted_item && has_below_sorted_item); -} - -void LayersDialog::OnLayerTreeSortedClicked(QTreeWidgetItem *item, int column) { - (void)column; - - TreeWidgetItemParameter *selected_sorted_item = dynamic_cast(item); - assert(selected_sorted_item); - - this->selected_available_layer_name = this->selected_sorted_layer_name = selected_sorted_item->layer_name; - - UpdateUI(); -} - -void LayersDialog::AddLayerItem(const Parameter ¶meter) { - assert(!parameter.key.empty()); - - std::vector &available_layers = Configurator::Get().layers.selected_layers; - - const Layer *layer = FindByKey(available_layers, parameter.key.c_str()); - - std::string decorated_name(parameter.key); - - bool is_implicit_layer = false; - if (layer != nullptr) { - if (layer->status != STATUS_STABLE) { - decorated_name += format(" (%s)", GetToken(layer->status)); - } - - decorated_name += format(" - %s", layer->api_version.str().c_str()); - - if (IsDLL32Bit(layer->manifest_path)) { - decorated_name += " (32-bit)"; - } - - if (layer->type == LAYER_TYPE_IMPLICIT) { - is_implicit_layer = true; - decorated_name += format(" - %s layer", GetLayerTypeLabel(layer->type)); - } - } else { - // A layers configuration may have excluded layer that are misssing because they are not available on this platform - // We simply hide these layers to avoid confusing the Vulkan developers - if (parameter.state == LAYER_STATE_EXCLUDED) { - return; - } - - decorated_name += " (Missing)"; - } - - TreeWidgetItemParameter *item = new TreeWidgetItemParameter(parameter.key.c_str()); - - item->setText(0, decorated_name.c_str()); - if (layer != nullptr) { - item->setToolTip(0, layer->manifest_path.c_str()); - } - item->setFlags(item->flags() | Qt::ItemIsSelectable); - item->setDisabled(layer == nullptr); - - // Add the top level item - ui->layerTree->addTopLevelItem(item); - - // Add a combo box. Default has gray background which looks hidious - WidgetTreeFriendlyComboBox *widget = new WidgetTreeFriendlyComboBox(item); - ui->layerTree->setItemWidget(item, 1, widget); - - if (layer != nullptr) { - std::string tooltip; - - bool disable_value = false; - bool enable_value = false; - - if (!layer->disable_env.empty()) { - disable_value = !qgetenv(layer->disable_env.c_str()).isEmpty(); - - tooltip += layer->disable_env + format(": %s", disable_value ? "true" : "false"); - } - - if (!layer->enable_env.empty()) { - enable_value = qgetenv(layer->enable_env.c_str()).toStdString() == layer->enable_value; - - tooltip += "; " + layer->enable_env + format(": %s", enable_value ? "true" : "false"); - } - - const std::string implicit_string = !disable_value || (!layer->enable_env.empty() && enable_value) - ? "Env Variables Controlled: On" - : "Env Variables Controlled: Off"; - - widget->setToolTip(tooltip.c_str()); - widget->addItem(is_implicit_layer ? implicit_string.c_str() : "Application-Controlled"); - } else { - widget->addItem("Application-Controlled"); - widget->setCurrentIndex(LAYER_STATE_APPLICATION_CONTROLLED); - } - - widget->addItem("Overridden / Forced On"); - widget->addItem("Excluded / Forced Off"); - widget->setCurrentIndex(parameter.state); - - this->connect(widget, SIGNAL(selectionMade(QTreeWidgetItem *, int)), this, SLOT(layerUseChanged(QTreeWidgetItem *, int))); -} - -void LayersDialog::LoadAvailableLayersUI() { - ui->layerTree->clear(); - - for (std::size_t i = 0, n = this->configuration.parameters.size(); i < n; ++i) { - AddLayerItem(this->configuration.parameters[i]); - } - - resizeEvent(nullptr); - - ui->layerTree->update(); -} - -void LayersDialog::LoadSortedLayersUI() { - ui->layerTreeSorted->clear(); - - for (std::size_t i = 0, n = this->configuration.parameters.size(); i < n; ++i) { - if (this->configuration.parameters[i].state != LAYER_STATE_OVERRIDDEN) continue; - - TreeWidgetItemParameter *sorted_layer_item = new TreeWidgetItemParameter(this->configuration.parameters[i].key.c_str()); - sorted_layer_item->setText(0, this->configuration.parameters[i].key.c_str()); - sorted_layer_item->setFlags(sorted_layer_item->flags() | Qt::ItemIsSelectable); - - ui->layerTreeSorted->addTopLevelItem(sorted_layer_item); - } -} - -void LayersDialog::LoadUserDefinedPaths() { - Configurator &configurator = Configurator::Get(); - - // Populate the tree - ui->layerTreePath->clear(); - - // Building the list is not obvious. Each custom path may have multiple layers and there - // could be duplicates, which are not allowed. The layer paths are traversed in order, and - // layers are used on a first occurance basis. So we can't just show the layers that are - // present in the folder (because they may not be used). We have to list the custom layer paths - // and then look for layers that are already loaded that are from that path. - - for (std::size_t path_index = 0, count = this->configuration.user_defined_paths.size(); path_index < count; ++path_index) { - const std::string user_defined_path(ConvertNativeSeparators(this->configuration.user_defined_paths[path_index])); - - QTreeWidgetItem *item = new QTreeWidgetItem(); - ui->layerTreePath->addTopLevelItem(item); - item->setText(0, user_defined_path.c_str()); - item->setExpanded(true); - - // Look for layers that are loaded that are also from this folder - for (std::size_t i = 0, n = configurator.layers.selected_layers.size(); i < n; ++i) { - const Layer &layer = configurator.layers.selected_layers[i]; - - const QFileInfo file_info(layer.manifest_path.c_str()); - const std::string path(ConvertNativeSeparators(file_info.path().toStdString())); - if (path != user_defined_path) { - continue; - } - - std::string decorated_name(layer.key); - if (layer.status != STATUS_STABLE) { - decorated_name += format(" (%s)", GetToken(layer.status)); - } - decorated_name += format(" - %s", layer.api_version.str().c_str()); - - QTreeWidgetItem *child = new QTreeWidgetItem(); - child->setText(0, decorated_name.c_str()); - item->addChild(child); - } - } -} - -// The only way to catch the resize from the layouts -// (which is screwing up the spacing with the combo boxes) -void LayersDialog::showEvent(QShowEvent *event) { - (void)event; - - resizeEvent(nullptr); -} - -void LayersDialog::resizeEvent(QResizeEvent *event) { - (void)event; - - const QFontMetrics fm = ui->layerTree->fontMetrics(); - const int combo_width = (fm.size(Qt::TextSingleLine, "Env Variables Controlled: Off").width() * 1.5); - const int width = ui->layerTree->width() - combo_width; - ui->layerTree->setColumnWidth(0, width); -} - -void LayersDialog::on_button_properties_clicked() { - const std::vector &selected_layers = Configurator::Get().layers.selected_layers; - const Layer *layer = FindByKey(selected_layers, this->selected_available_layer_name.c_str()); - - Alert::LayerProperties(layer); -} - -void LayersDialog::on_button_doc_clicked() { - const std::vector &selected_layers = Configurator::Get().layers.selected_layers; - const Layer *layer = FindByKey(selected_layers, this->selected_available_layer_name.c_str()); - const std::string path = format("%s/%s.html", GetPath(BUILTIN_PATH_APPDATA).c_str(), layer->key.c_str()); - ExportHtmlDoc(*layer, path); - QDesktopServices::openUrl(QUrl(("file:///" + path).c_str())); -} - -void LayersDialog::on_button_website_clicked() { - const std::vector &selected_layers = Configurator::Get().layers.selected_layers; - const Layer *layer = FindByKey(selected_layers, this->selected_available_layer_name.c_str()); - QDesktopServices::openUrl(QUrl(layer->url.c_str())); -} - -void LayersDialog::on_button_reset_clicked() { - Configurator &configurator = Configurator::Get(); - - QMessageBox alert; - alert.QDialog::setWindowTitle(format("Resetting *%s* configuration...", this->configuration.key.c_str()).c_str()); - alert.setText(format("Are you sure you want to reset the *%s* configuration?", this->configuration.key.c_str()).c_str()); - if (this->configuration.IsBuiltIn()) - alert.setInformativeText( - format("The configuration layers and settings will be restored to default built-in *%s* configuration.", - configuration.key.c_str()) - .c_str()); - else if (configurator.configurations.HasFile(this->configuration)) - alert.setInformativeText( - format("The configuration layers and settings will be reloaded using the *%s* saved file from previous %s run.", - configuration.key.c_str(), VKCONFIG_NAME) - .c_str()); - else - alert.setInformativeText("The configuration layers and settings will be reset to zero."); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setIcon(QMessageBox::Warning); - if (alert.exec() == QMessageBox::No) return; - - selected_available_layer_name.clear(); - selected_sorted_layer_name.clear(); - - configuration.Reset(configurator.layers.selected_layers, configurator.path); - - this->Reinit(); - - ui->button_reset->setEnabled(false); -} - -void LayersDialog::OverrideOrder(const std::string layer_name, const TreeWidgetItemParameter *below, - const TreeWidgetItemParameter *above) { - assert(below != nullptr); - assert(below != above); - - Parameter *below_parameter = FindByKey(configuration.parameters, below->layer_name.c_str()); - assert(below_parameter != nullptr); - Parameter *above_parameter = FindByKey(configuration.parameters, above->layer_name.c_str()); - assert(above_parameter != nullptr); - - this->selected_sorted_layer_name = this->selected_available_layer_name = layer_name; - - std::swap(below_parameter->overridden_rank, above_parameter->overridden_rank); - - OrderParameter(configuration.parameters, Configurator::Get().layers.selected_layers); - LoadAvailableLayersUI(); - LoadSortedLayersUI(); - LoadUserDefinedPaths(); - - UpdateUI(); -} - -void LayersDialog::on_pushButtonUp_clicked() { - TreeWidgetItemParameter *selected_item = dynamic_cast(ui->layerTreeSorted->currentItem()); - assert(selected_item); - TreeWidgetItemParameter *above_item = dynamic_cast(ui->layerTreeSorted->itemAbove(selected_item)); - assert(above_item); - - OverrideOrder(selected_item->layer_name, selected_item, above_item); - - ui->button_reset->setEnabled(true); - this->UpdateButtons(); -} - -void LayersDialog::on_pushButtonDown_clicked() { - TreeWidgetItemParameter *selected_item = dynamic_cast(ui->layerTreeSorted->currentItem()); - assert(selected_item); - TreeWidgetItemParameter *below_item = dynamic_cast(ui->layerTreeSorted->itemBelow(selected_item)); - assert(below_item); - - OverrideOrder(selected_item->layer_name, below_item, selected_item); - - ui->button_reset->setEnabled(true); - this->UpdateButtons(); -} - -void LayersDialog::currentLayerChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { - (void)previous; - - TreeWidgetItemParameter *layer_item = dynamic_cast(current); - - if (layer_item == nullptr) { - this->selected_available_layer_name.clear(); - return; - } - - assert(!layer_item->layer_name.empty()); - - this->selected_available_layer_name = layer_item->layer_name.c_str(); - - ui->button_reset->setEnabled(true); - this->UpdateButtons(); -} - -void LayersDialog::UpdateButtons() { - const bool enabled = !selected_available_layer_name.empty(); - - bool enabled_url = false; - - if (enabled) { - std::vector &available_layers = Configurator::Get().layers.selected_layers; - const Layer *layer = FindByKey(available_layers, selected_available_layer_name.c_str()); - assert(layer != nullptr); - if (!layer->url.empty()) enabled_url = true; - } - - ui->button_properties->setEnabled(enabled); - ui->button_doc->setEnabled(enabled); - ui->button_website->setEnabled(enabled && enabled_url); -} - -void LayersDialog::OverrideAllExplicitLayers() { - for (auto it = this->configuration.parameters.begin(); it != this->configuration.parameters.end(); ++it) { - if (it->state != LAYER_STATE_APPLICATION_CONTROLLED) continue; - - Configurator &configurator = Configurator::Get(); - std::vector &available_layers = configurator.layers.selected_layers; - - const Layer *layer = FindByKey(available_layers, it->key.c_str()); - if (layer == nullptr) continue; - - if (layer->type == LAYER_TYPE_IMPLICIT) continue; - - if (it->key == "VK_LAYER_KHRONOS_validation") - it->state = LAYER_STATE_OVERRIDDEN; - else - it->state = LAYER_STATE_EXCLUDED; - } -} - -// Select the layer LayerState -void LayersDialog::layerUseChanged(QTreeWidgetItem *item, int selection) { - // Combo box changed. We first need to know which tree item was selected. - // Fortunatly, changing the combo box also changes the selected item. - assert(item); - assert(selection >= LAYER_STATE_FIRST && selection <= LAYER_STATE_LAST); - - TreeWidgetItemParameter *tree_layer_item = dynamic_cast(item); - assert(tree_layer_item != nullptr); - Parameter *current_parameter = FindByKey(configuration.parameters, tree_layer_item->layer_name.c_str()); - assert(current_parameter != nullptr); - - LayerState layer_state = static_cast(selection); - - if (layer_state == LAYER_STATE_OVERRIDDEN && current_parameter->key == "VK_LAYER_KHRONOS_profiles") { - if (Alert::LayerProfiles() == QMessageBox::Yes) { - OverrideAllExplicitLayers(); - } - } else if (layer_state != LAYER_STATE_APPLICATION_CONTROLLED) { - const std::vector &selected_layers = Configurator::Get().layers.selected_layers; - const Layer *layer = FindByKey(selected_layers, tree_layer_item->layer_name.c_str()); - - if (layer != nullptr) { - if (layer->type == LAYER_TYPE_IMPLICIT) { - if (Alert::LayerImplicit(tree_layer_item->layer_name.c_str()) == QMessageBox::No) { - layer_state = LAYER_STATE_APPLICATION_CONTROLLED; - } - } - } - } - - current_parameter->state = layer_state; - current_parameter->overridden_rank = Parameter::NO_RANK; - - OrderParameter(this->configuration.parameters, Configurator::Get().layers.selected_layers); - - ui->button_reset->setEnabled(true); - - LoadAvailableLayersUI(); - LoadSortedLayersUI(); - LoadUserDefinedPaths(); - - UpdateUI(); -} - -void LayersDialog::on_layerTreePath_itemSelectionChanged() { ui->pushButtonRemove->setEnabled(true); } - -void LayersDialog::on_pushButtonAdd_clicked() { - Configurator &configurator = Configurator::Get(); - const std::string custom_path = configurator.path.SelectPath(this, PATH_USER_DEFINED_LAYERS_GUI); - - if (!custom_path.empty()) { - std::vector &user_defined_paths = this->configuration.user_defined_paths; - - if (std::find(user_defined_paths.begin(), user_defined_paths.end(), custom_path) == user_defined_paths.end()) { - user_defined_paths.push_back(custom_path); - - this->Reload(); - this->Reinit(); - } - } - - ui->buttonBox->setEnabled(!configurator.layers.Empty()); -} - -void LayersDialog::on_pushButtonRemove_clicked() { - // Which one is selected? We need the top item too - QTreeWidgetItem *selected = ui->layerTreePath->currentItem(); - if (selected == nullptr) { - ui->pushButtonRemove->setEnabled(false); - return; - } - - while (selected->parent() != nullptr) selected = selected->parent(); - - RemoveString(this->configuration.user_defined_paths, selected->text(0).toStdString()); - - this->Reload(); - this->Reinit(); - - // Nothing is selected, so disable remove button - ui->pushButtonRemove->setEnabled(false); -} - -void LayersDialog::accept() { - if (ui->lineEditName->text().isEmpty()) { - Alert::ConfigurationNameEmpty(); - return; - } - - if (!IsPortableFilename(ui->lineEditName->text().toStdString())) { - Alert::ConfigurationNameInvalid(); - return; - } - - /* ANSI character are allowed - if (ui->lineEditName->text().contains(QRegularExpression(QStringLiteral("[^\\x{0000}-\\x{007F}]")))) { - Alert::ConfigurationNameASCII(); - return; - } - */ - - Configurator &configurator = Configurator::Get(); - if (this->configuration.key != ui->lineEditName->text().toStdString() && - IsFound(configurator.configurations.available_configurations, ui->lineEditName->text().toStdString().c_str())) { - Alert::ConfigurationRenamingFailed(); - return; - } - - Version loader_version; - if (!configurator.SupportDifferentLayerVersions(&loader_version)) { - std::string log_versions; - if (!configurator.configurations.CheckLayersVersions(configurator.layers.selected_layers, &this->configuration, - log_versions)) { - Alert::LayerIncompatibleVersions(log_versions.c_str(), loader_version); - return; - } - } - - FilterParameters(this->configuration.parameters, LAYER_STATE_APPLICATION_CONTROLLED); - - Configuration *saved_configuration = - FindByKey(configurator.configurations.available_configurations, this->configuration.key.c_str()); - assert(saved_configuration != nullptr); - - if (saved_configuration->key != ui->lineEditName->text().toStdString()) { - configurator.configurations.RemoveConfigurationFile(saved_configuration->key); - } - - const std::string active_configuration_name = ui->lineEditName->text().toStdString(); - - saved_configuration->key = active_configuration_name; - saved_configuration->description = ui->lineEditDescription->text().toStdString(); - saved_configuration->parameters = this->configuration.parameters; - saved_configuration->user_defined_paths = this->configuration.user_defined_paths; - saved_configuration->setting_tree_state.clear(); - configurator.configurations.SaveAllConfigurations(configurator.layers.selected_layers); - - QDialog::accept(); -} - -void LayersDialog::reject() { - Configurator &configurator = Configurator::Get(); - Configuration *saved_configuration = - FindByKey(configurator.configurations.available_configurations, this->configuration.key.c_str()); - assert(saved_configuration != nullptr); - - if (saved_configuration->user_defined_paths != this->configuration.user_defined_paths) { - configurator.environment.SetPerConfigUserDefinedLayersPaths(saved_configuration->user_defined_paths); - // Restore layers - this->Reload(); - } - - QDialog::reject(); -} - -void LayersDialog::BuildParameters() { - Configurator &configurator = Configurator::Get(); - this->configuration.parameters = GatherParameters(this->configuration.parameters, configurator.layers.selected_layers); -} diff --git a/vkconfig/dialog_layers.h b/vkconfig/dialog_layers.h deleted file mode 100644 index bbcc7941bd..0000000000 --- a/vkconfig/dialog_layers.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "widget_tree_friendly_combobox.h" - -#include "../vkconfig_core/configuration.h" - -#include "ui_dialog_layers.h" - -#include -#include - -class TreeWidgetItemParameter : public QTreeWidgetItem { - public: - TreeWidgetItemParameter(const char *layer_name) : layer_name(layer_name) { assert(layer_name != nullptr); } - - std::string layer_name; -}; - -class LayersDialog : public QDialog { - Q_OBJECT - - public: - explicit LayersDialog(QWidget *parent, const Configuration &configuration); - ~LayersDialog(); - - public Q_SLOTS: - void accept() override; - void reject() override; - - void currentLayerChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); - - void on_button_properties_clicked(); - void on_button_doc_clicked(); - void on_button_website_clicked(); - void on_button_reset_clicked(); - void on_pushButtonUp_clicked(); - void on_pushButtonDown_clicked(); - void on_pushButtonAdd_clicked(); - void on_pushButtonRemove_clicked(); - void on_layerTreePath_itemSelectionChanged(); - - void OnLayerTreeSortedClicked(QTreeWidgetItem *item, int column); - - void layerUseChanged(QTreeWidgetItem *item, int selection); - - private: - LayersDialog(const LayersDialog &) = delete; - LayersDialog &operator=(const LayersDialog &) = delete; - - virtual void resizeEvent(QResizeEvent *event) override; - virtual void showEvent(QShowEvent *) override; - - void UpdateUI(); - - void UpdateButtons(); - - void LoadAvailableLayersUI(); - void LoadSortedLayersUI(); - void LoadUserDefinedPaths(); - void Reload(); - void Reinit(); - void AddLayerItem(const Parameter ¶meter); - void BuildParameters(); - void OverrideAllExplicitLayers(); - void OverrideOrder(const std::string layer_name, const TreeWidgetItemParameter *below, const TreeWidgetItemParameter *above); - - Configuration configuration; - std::string selected_available_layer_name; - std::string selected_sorted_layer_name; - - std::unique_ptr ui; -}; diff --git a/vkconfig/dialog_layers.ui b/vkconfig/dialog_layers.ui deleted file mode 100644 index 8952d76e01..0000000000 --- a/vkconfig/dialog_layers.ui +++ /dev/null @@ -1,555 +0,0 @@ - - - dialog_layers - - - - 0 - 0 - 1024 - 640 - - - - - 1024 - 640 - - - - - 10000 - 10000 - - - - - 0 - 0 - - - - - Arial - 10 - - - - Edit Vulkan Layers - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 16777215 - 80 - - - - - 0 - 1 - - - - - - - - - - Description: - - - - - - - - 0 - 24 - - - - Description of your user-defined configuration - - - - - - - - 0 - 24 - - - - - - - Name of your new user-defined configuration - - - - - - - Name: - - - - - - - - - - 1 - - - Qt::Vertical - - - false - - - 10 - - - false - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 1 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Show Properties... - - - - - - - Show Documentation... - - - - - - - Visit Website... - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 120 - 0 - - - - - 1000 - 16777215 - - - - Reset - - - - - - - - - - 0 - 0 - - - - - 0 - 32 - - - - - 0 - 32 - - - - - Arial - 10 - - - - QFrame::Box - - - QFrame::Plain - - - false - - - false - - - QAbstractItemView::NoDragDrop - - - Qt::IgnoreAction - - - false - - - true - - - 0 - - - 0 - - - - 1 - - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 1 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 32 - - - - - 16777215 - 16777215 - - - - - 0 - 32 - - - - - Arial - 10 - - - - Overridden layers ordering requires multiple layers - - - QFrame::Box - - - QFrame::Plain - - - false - - - - 1 - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Execute Closer to the Vulkan Applications - - - - - - - Execute Closer to the Vulkan Drivers - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QFrame::Box - - - QFrame::Plain - - - 1 - - - false - - - 0 - - - 0 - - - - 1 - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Add User-Defined Path... - - - - - - - Remove User-Defined Path - - - - - - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - false - - - - - - - layerTree - - - - - buttonBox - accepted() - dialog_layers - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - dialog_layers - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/vkconfig/dialog_vulkan_analysis.cpp b/vkconfig/dialog_vulkan_analysis.cpp deleted file mode 100644 index a5b54c9aba..0000000000 --- a/vkconfig/dialog_vulkan_analysis.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "dialog_vulkan_analysis.h" - -#include "../vkconfig_core/platform.h" - -#include -#include -#include -#include -#include -#include -#include - -VulkanAnalysisDialog::VulkanAnalysisDialog(QWidget *parent) : QDialog(parent), ui(new Ui::dialog_vulkan_analysis) { - ui->setupUi(this); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - - // Hide the test widget as no test is actually run. - // This may be added back again later. - ui->tabWidget->removeTab(2); - - Run(); -} - -void VulkanAnalysisDialog::Run() { - ui->envTable->clear(); - ui->cleanupTable->clear(); - ui->hardwareTable->clear(); - ui->instanceTable->clear(); - ui->lunarGSDKTable->clear(); - ui->executableTable->clear(); - ui->vkRuntimesTable->clear(); - ui->externalTestsTable->clear(); - ui->layerSettingsTable->clear(); - ui->explicitLayersTable->clear(); - ui->implicitLayersTable->clear(); - ui->logicalDevicesTable->clear(); - ui->physicalDevicesTable->clear(); - - QProcess *via = new QProcess(this); -#if VKC_PLATFORM == VKC_PLATFORM_MACOS - via->setProgram("/usr/local/bin/vkvia"); -#else - via->setProgram("vkvia"); -#endif - - const QString &file_Path = QDir::temp().path() + "/vkvia.json"; - - // Remove the old one - remove(file_Path.toUtf8().constData()); - - QStringList args; - args << "--output_path" << QDir::temp().path(); - args << "--vkconfig_output"; - args << "--disable_cube_tests"; - via->setArguments(args); - via->start(); - via->waitForFinished(); - - QFile file(file_Path); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setText(tr("Error running vkvia. Is your SDK up to date and installed properly?")); - msgBox.exec(); - return; - } - - QString json_text = file.readAll(); - file.close(); - - ////////////////////////////////////////////////////// - // Convert the text to a JSON document & validate it - QJsonParseError parse_error; - QJsonDocument json_document = QJsonDocument::fromJson(json_text.toUtf8(), &parse_error); - - if (parse_error.error != QJsonParseError::NoError) { - QMessageBox msgBox; - msgBox.setWindowTitle("Cannot parse vkvia output."); - msgBox.setText(parse_error.errorString()); - msgBox.exec(); - return; - } - - if (json_document.isEmpty() || json_document.isNull()) return; - - ///////////////////////////////////////////////////////// - // Get the instance version and set that to the header - QString output; - const QJsonObject &json_object = json_document.object(); - - ///////////////////////////////////// System Info - // Get the extensions object and process it's members - QJsonValue environmentValue = json_object.value(QString(tr("Environment"))); - QJsonObject environmentObject = environmentValue.toObject(); - LoadTable(environmentObject, ui->envTable); - - QJsonValue hardwareValue = json_object.value(QString(tr("Hardware"))); - QJsonObject hardwareObject = hardwareValue.toObject(); - LoadTable(hardwareObject, ui->hardwareTable); - - QJsonValue executableValue = json_object.value(QString(tr("Executable Info"))); - QJsonObject executableObject = executableValue.toObject(); - LoadTable(executableObject, ui->executableTable); - - QJsonValue vkDriverInfo = json_object.value(QString(tr("Vulkan Driver Info"))); - QJsonObject vkDriverObject = vkDriverInfo.toObject(); - LoadTable(vkDriverObject, ui->vkDriverInfoTable); - - QJsonValue vkRunTimeValue = json_object.value(QString(tr("Vulkan Runtimes"))); - QJsonObject vkRunTimeObject = vkRunTimeValue.toObject(); - LoadTable(vkRunTimeObject, ui->vkRuntimesTable); - - QJsonValue lunarGSDKValue = json_object.value(QString(tr("Vulkan SDKs"))); - QJsonObject lunarGSDKObject = lunarGSDKValue.toObject(); - LoadTable(lunarGSDKObject, ui->lunarGSDKTable); - - QJsonValue vkImplicitValue = json_object.value(QString(tr("Vulkan Implicit Layers"))); - QJsonObject vkImplicitObject = vkImplicitValue.toObject(); - LoadTable(vkImplicitObject, ui->implicitLayersTable); - - QJsonValue vkExplicitValue = json_object.value(QString(tr("Vulkan Explicit Layers"))); - QJsonObject vkExplicitObject = vkExplicitValue.toObject(); - LoadTable(vkExplicitObject, ui->explicitLayersTable); - - QJsonValue vkLayerSettingsValue = json_object.value(QString(tr("Vulkan Layer Settings File"))); - QJsonObject vkLayerSettingsObject = vkLayerSettingsValue.toObject(); - LoadTable(vkLayerSettingsObject, ui->layerSettingsTable); - - /////////////////////////// Vulkan API Calls - QJsonValue instanceValue = json_object.value(QString(tr("Instance"))); - QJsonObject instanceObject = instanceValue.toObject(); - LoadTable(instanceObject, ui->instanceTable); - - QJsonObject devicesObject = json_object.value(QString(tr("Physical Devices"))).toObject(); - LoadTable(devicesObject, ui->physicalDevicesTable); - - QJsonObject logicalObject = json_object.value(QString(tr("Logical Devices"))).toObject(); - LoadTable(logicalObject, ui->logicalDevicesTable); - - QJsonObject cleanupObject = json_object.value(QString(tr("Cleanup"))).toObject(); - LoadTable(cleanupObject, ui->cleanupTable); - - /////////////////////////////////// External Tests - QJsonValue cubeValue = json_object.value(QString(tr("Cube"))).toObject(); - QJsonObject cubeObject = cubeValue.toObject(); - if (!cubeObject.isEmpty()) - LoadTable(cubeObject, ui->externalTestsTable); - else { - ui->externalTestsTable->setRowCount(1); - ui->externalTestsTable->setColumnCount(1); - ui->externalTestsTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui->externalTestsTable->setShowGrid(false); - QTableWidgetItem *item = new QTableWidgetItem(); - item->setText(tr("No SDK found by VIA, skipping test section")); - ui->externalTestsTable->setItem(0, 0, item); - } - - show(); -} - -void VulkanAnalysisDialog::LoadTable(QJsonObject &json_parent, QTableWidget *table) { - // How many items does this object contain? - int nHowManyRows = json_parent.size(); - table->setRowCount(nHowManyRows); - - // Get the first item in the table, and see how many items it has. This - // will be the number of columns - QJsonValue rowValue = json_parent.value("0"); - QJsonObject rowObject = rowValue.toObject(); - int nHowManyCols = rowObject.size(); - table->setColumnCount(nHowManyCols); - - table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - - // Now just iterate and fill in the cells - for (int row = 0; row < nHowManyRows; row++) { - rowValue = json_parent.value(QString().asprintf("%d", row)); - rowObject = rowValue.toObject(); - - for (int col = 0; col < nHowManyCols; col++) { - QJsonValue colValue = rowObject.value(QString().asprintf("%d", col)); - QString text = colValue.toString(); - QTableWidgetItem *item = new QTableWidgetItem; - item->setText(text); - table->setItem(row, col, item); - } - } -} diff --git a/vkconfig/main_doc.h b/vkconfig/main_doc.h deleted file mode 100644 index ce23885758..0000000000 --- a/vkconfig/main_doc.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2022 Valve Corporation - * Copyright (c) 2022 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. - * - * Authors: - * - David Pinedo - */ - -#pragma once - -#include "../vkconfig_core/command_line.h" - -int run_doc(const CommandLine& commandLine); diff --git a/vkconfig/main_gui.cpp b/vkconfig/main_gui.cpp deleted file mode 100644 index f614f40584..0000000000 --- a/vkconfig/main_gui.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "main_gui.h" - -#include "mainwindow.h" - -#include "../vkconfig_core/alert.h" -#include "../vkconfig_core/version.h" -#include "../vkconfig_core/application_singleton.h" - -#include -#include - -int run_gui(int argc, char* argv[], const CommandLine& command_line) { - QCoreApplication::setOrganizationName("LunarG"); - QCoreApplication::setOrganizationDomain("lunarg.com"); - - // This is used by QSettings for .ini, registry, and .plist files. - // It needs to not have spaces in it, and by default is the same as - // the executable name. If we rename the executable at a later date, - // keeping this as 'vkconfig' will ensure that it picks up the - // settings from the previous version (assuming that's ever an issue) - QCoreApplication::setApplicationName(VKCONFIG_SHORT_NAME); - - // Older Qt versions do not have this. Dynamically check the version - // of Qt since it's just an enumerant. Versions 5.6.0 and later have - // high dpi support. We really don't need to check the 5, but for - // the sake of completeness and mabye compatibility with qt 6. - // Also ignoring the trailing point releases - const char* version = qVersion(); - int version_major, version_minor; - sscanf(version, "%d.%d", &version_major, &version_minor); - if (version_major >= 5 && version_minor >= 6) { - // Qt::AA_EnableHighDpiScaling = 20 from qnamespace.h in Qt 5.6 or later - QCoreApplication::setAttribute((Qt::ApplicationAttribute)20); - } - - QApplication app(argc, argv); - - // This has to go after the construction of QApplication in - // order to use a QMessageBox and avoid some QThread warnings. - ApplicationSingleton singleton("vkconfig_single_instance"); - - while (!singleton.IsFirstInstance()) { - if (Alert::ConfiguratorSingleton() == QMessageBox::Cancel) { - return -1; - } - } - - // We simply cannot run without any layers - Configurator& configurator = Configurator::Get(command_line.command_vulkan_sdk); - - if (!configurator.Init()) return -1; - - // The main GUI is driven here - MainWindow main_window; - main_window.show(); - - return app.exec(); -} diff --git a/vkconfig/main_gui.h b/vkconfig/main_gui.h deleted file mode 100644 index 06c17e5aca..0000000000 --- a/vkconfig/main_gui.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/command_line.h" - -int run_gui(int argc, char* argv[], const CommandLine& command_line); diff --git a/vkconfig/main_layers.cpp b/vkconfig/main_layers.cpp deleted file mode 100644 index 1e5b041607..0000000000 --- a/vkconfig/main_layers.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "main_layers.h" -#include "configurator.h" - -#include "../vkconfig_core/configuration.h" -#include "../vkconfig_core/override.h" -#include "../vkconfig_core/layer_manager.h" - -#include - -static int RunLayersOverride(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); - - Configuration configuration; - const bool load_result = configuration.Load(layers.selected_layers, command_line.layers_configuration_path.c_str()); - if (!load_result) { - printf("\nFailed to load the layers configuration file...\n"); - return -1; - } - - // With command line, don't store the application list, it's always global, save and restore the setting - const bool use_application_list = environment.HasOverriddenApplications(); - environment.SetUseApplicationList(false); - - const bool override_result = OverrideConfiguration(environment, layers.selected_layers, configuration); - - environment.SetUseApplicationList(use_application_list); - - environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit - - if (override_result) { - printf("\nLayers configuration \"%s\" applied to all Vulkan Applications, including Vulkan layers:\n", - command_line.layers_configuration_path.c_str()); - for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { - const Parameter& parameter = configuration.parameters[i]; - if (parameter.state == LAYER_STATE_APPLICATION_CONTROLLED) continue; - - printf("\t%s (%s)\n", parameter.key.c_str(), parameter.state == LAYER_STATE_OVERRIDDEN ? "Overridden" : "Excluded"); - } - printf("\n (Use \"vkconfig layers --surrender\" to return Vulkan layers control to Vulkan applications.)\n"); - } else { - printf("\nFailed to override Vulkan applications layers...\n"); - } - - return override_result ? 0 : -1; -} - -static int RunLayersSurrender(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - const bool has_overridden_layers = HasOverride(); - const bool surrender_result = SurrenderConfiguration(environment); - - environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit - - if (has_overridden_layers) { - if (surrender_result) { - printf("\nFull Vulkan layers control returned to Vulkan applications.\n"); - printf("\n (Use \"vkconfig layers --override to take control of Vulkan layers.)\n"); - } else { - printf("\nFailed to surrender Vulkan applications layers...\n"); - } - } else { - printf("\nNo overridden Vulkan layers, nothing to surrender.\n"); - } - - return surrender_result ? 0 : -1; -} - -static int RunLayersList(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); - - if (layers.selected_layers.empty()) { - printf("No Vulkan layer found\n"); - } else { - for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { - const Layer& layer = layers.selected_layers[i]; - - printf("%s\n", layer.key.c_str()); - } - } - - return 0; -} - -static int RunLayersVerbose(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); - - for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { - const Layer& layer = layers.selected_layers[i]; - - printf("%s (%s) %s-%s\n", layer.key.c_str(), GetLayerTypeLabel(layer.type), layer.api_version.str().c_str(), - layer.implementation_version.c_str()); - printf("- %s\n", layer.description.c_str()); - printf("- %s\n", layer.manifest_path.c_str()); - printf("- %s\n", layer.binary_path.c_str()); - } - - return 0; -} - -int run_layers(const CommandLine& command_line) { - assert(command_line.command == COMMAND_LAYERS); - assert(command_line.error == ERROR_NONE); - - switch (command_line.command_layers_arg) { - case COMMAND_LAYERS_OVERRIDE: { - return RunLayersOverride(command_line); - } - case COMMAND_LAYERS_SURRENDER: { - return RunLayersSurrender(command_line); - } - case COMMAND_LAYERS_LIST: { - return RunLayersList(command_line); - } - case COMMAND_LAYERS_VERBOSE: { - return RunLayersVerbose(command_line); - } - default: { - assert(0); - return -1; - } - } -} diff --git a/vkconfig/main_reset.cpp b/vkconfig/main_reset.cpp deleted file mode 100644 index 3480bd9585..0000000000 --- a/vkconfig/main_reset.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "main_reset.h" - -#include "configurator.h" - -#include - -#include - -static int RunReset(int argc, char* argv[], bool hard) { - QCoreApplication::setOrganizationName("LunarG"); - QCoreApplication::setOrganizationDomain("lunarg.com"); - - // This is used by QSettings for .ini, registry, and .plist files. - // It needs to not have spaces in it, and by default is the same as - // the executable name. If we rename the executable at a later date, - // keeping this as 'vkconfig' will ensure that it picks up the - // settings from the previous version (assuming that's ever an issue) - QCoreApplication::setApplicationName(VKCONFIG_SHORT_NAME); - - // Older Qt versions do not have this. Dynamically check the version - // of Qt since it's just an enumerant. Versions 5.6.0 and later have - // high dpi support. We really don't need to check the 5, but for - // the sake of completeness and mabye compatibility with qt 6. - // Also ignoring the trailing point releases - const char* version = qVersion(); - int version_major, version_minor; - sscanf(version, "%d.%d", &version_major, &version_minor); - if (version_major >= 5 && version_minor >= 6) { - // Qt::AA_EnableHighDpiScaling = 20 from qnamespace.h in Qt 5.6 or later - QCoreApplication::setAttribute((Qt::ApplicationAttribute)20); - } - - QApplication app(argc, argv); - - Configurator::Get().ResetToDefault(hard); - - return 0; -} - -int run_reset(int argc, char* argv[], const CommandLine& command_line) { - assert(command_line.command == COMMAND_RESET); - assert(command_line.error == ERROR_NONE); - - switch (command_line.command_reset_arg) { - case COMMAND_RESET_SOFT: { - return RunReset(argc, argv, false); - } - case COMMAND_RESET_HARD: { - return RunReset(argc, argv, true); - } - default: { - assert(0); - return -1; - } - } -} diff --git a/vkconfig/mainwindow.ui b/vkconfig/mainwindow.ui deleted file mode 100644 index 330a4f750e..0000000000 --- a/vkconfig/mainwindow.ui +++ /dev/null @@ -1,820 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1200 - 720 - - - - - 1 - 1 - - - - - 1200 - 720 - - - - - 16777215 - 16777215 - - - - - Arial - 10 - - - - Vulkan Configurator - - - - - - - - - - Qt::Horizontal - - - true - - - 5 - - - false - - - - Qt::Vertical - - - - - 16 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 4 - 1 - - - - - 0 - 135 - - - - - 16777215 - 135 - - - - Vulkan Layers Management - - - false - - - - - - - Layers Controlled by the Vulkan Applications - - - - - Layers Controlled by the Vulkan Configurator - - - - - Layers Disabled by the Vulkan Configurator - - - - - - - - - - - 0 - 24 - - - - - Arial - 10 - - - - Keep Vulkan Configurator running in system tray - - - - - - - - 0 - 24 - - - - - Arial - 10 - - - - Apply only to the Vulkan Applications List - - - - - - - - 0 - 0 - - - - - 150 - 26 - - - - - 136 - 16777215 - - - - - Arial - 10 - - - - Edit Applications... - - - - - - - - - - - - - 1 - 0 - - - - Vulkan Layers Configurations - - - - 6 - - - - - - - - Arial - 10 - - - - QAbstractItemView::NoEditTriggers - - - false - - - 5 - - - 2 - - - false - - - 20 - - - - 1 - - - - - 2 - - - - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - New... - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - Arial - 10 - - - - Edit... - - - - - - - Duplicate - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Remove - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - - - - - - - - 0 - 1 - - - - Vulkan Application Launcher - - - - - - - 0 - 1 - - - - - 0 - 98 - - - - - 16777215 - 98 - - - - - Arial - 10 - - - - false - - - QAbstractItemView::NoEditTriggers - - - 3 - - - false - - - true - - - false - - - - - - - - - 2 - - - - - 3 - - - - - - - - - Consolas - 9 - - - - false - - - - - - - - Arial - 10 - - - - - - - - - - true - - - - - - - - Arial - 10 - - - - Clear - - - - - - - Status - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - Arial - 10 - - - - Launch - - - - - - - - 0 - 0 - - - - <html><head/><body><p>Vulkan loader debug messages level used by the VK_LOADER_DEBUG environment variable on launch. <br/><br/>Levels are:<br/>- error<br/>- warn (warnings)<br/>- info (information)<br/>- debug<br/>- layer (layer information)<br/>- implem (implementation/icd information)<br/>- all (report out all messages)</p></body></html> - - - - none - - - - - error - - - - - warn - - - - - info - - - - - debug - - - - - layer - - - - - implem - - - - - all - - - - - - - - Vulkan Loader: - - - - - - - - - Qt::Vertical - - - - - 0 - 1 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - 400 - 0 - - - - Configuration Settings - - - false - - - false - - - - 9 - - - - - - 300 - 0 - - - - - Arial - 10 - - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - - - QAbstractItemView::NoEditTriggers - - - true - - - false - - - false - - - 1 - - - false - - - 160 - - - 200 - - - - - - - - - - - - - - - - - - - 0 - 0 - 1200 - 25 - - - - - Tools - - - - - - - - - Help - - - - - - - - - - - - - - - - - - History... - - - - - Save Profile... - - - - - Exit and Keep - - - - - Exit - - - - - Vulkan Info - - - - - Vulkan Installation Analysis - - - - - About Vulkan Configurator - - - - - Vulkan Configurator Readme - - - - - Test Environment... - - - - - User-Defined Layers Paths... - - - - - API Dump... - - - - - Create Custom Profile.. - - - - - Reset To Default - - - - - Vulkan Specification - - - - - Vulkan Layer Specification - - - - - Vulkan GPU Info Reports - - - - - Vulkan Configurator Changelog - - - - - Find More Layers! - - - - - - diff --git a/vkconfig/resources.qrc b/vkconfig/resources.qrc deleted file mode 100644 index 08a828c071..0000000000 --- a/vkconfig/resources.qrc +++ /dev/null @@ -1,82 +0,0 @@ - - - resourcefiles/lunarg_logo.png - resourcefiles/qt_logo.png - resourcefiles/vulkan.ico - resourcefiles/vkconfig-off.png - resourcefiles/vkconfig-on.png - - - - ../vkconfig_core/configurations/2.2.2/API dump.json - ../vkconfig_core/configurations/2.2.2/Frame Capture.json - ../vkconfig_core/configurations/2.2.2/Portability.json - ../vkconfig_core/configurations/2.2.2/Synchronization.json - ../vkconfig_core/configurations/2.2.2/Validation.json - ../vkconfig_core/configurations/2.2.2/Crash Diagnostic.json - - - - ../vkconfig_core/layers/layers_schema.json - ../vkconfig_core/layers/validusage.json - - - - ../vkconfig_core/test/VK_LAYER_LUNARG_reference_1_2_1.json - - - - ../vkconfig_core/layers/130/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/130/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/130/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/130/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/135/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/135/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/135/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/135/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/141/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/148/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/154/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/162/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/170/VK_LAYER_KHRONOS_synchronization2.json - ../vkconfig_core/layers/170/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_screenshot.json - - diff --git a/vkconfig/settings_tree.cpp b/vkconfig/settings_tree.cpp deleted file mode 100644 index 2a6d7cd98c..0000000000 --- a/vkconfig/settings_tree.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "configurator.h" -#include "settings_tree.h" - -#include "widget_setting.h" -#include "widget_setting_int.h" -#include "widget_setting_float.h" -#include "widget_setting_frames.h" -#include "widget_setting_bool.h" -#include "widget_setting_enum.h" -#include "widget_setting_string.h" -#include "widget_setting_flags.h" -#include "widget_setting_filesystem.h" -#include "widget_setting_list_element.h" -#include "widget_setting_list.h" - -#include "../vkconfig_core/alert.h" -#include "../vkconfig_core/version.h" -#include "../vkconfig_core/platform.h" -#include "../vkconfig_core/util.h" - -#include -#include -#include -#include -#include - -#include - -static const char *TOOLTIP_ORDER = - "Layers are executed between the Vulkan application and driver in the specific order represented here"; - -SettingsTreeManager::SettingsTreeManager() : launched_application(false), tree(nullptr) {} - -void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { - assert(build_tree); - - // Do this first to make absolutely sure if these is an old configuration still active it's state gets saved. - CleanupGUI(); - - Configurator &configurator = Configurator::Get(); - - this->tree = build_tree; - - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); - if (configuration == nullptr) { - return; - } - - this->tree->blockSignals(true); - this->tree->clear(); - - QFont font_layer = this->tree->font(); - font_layer.setBold(true); - - QFont font_section = this->tree->font(); - font_section.setItalic(true); - - if (!configuration->HasOverride()) { - QTreeWidgetItem *item = new QTreeWidgetItem(); - item->setText(0, "No overridden or excluded layer"); - item->setFont(0, font_section); - item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->tree->addTopLevelItem(item); - } else { - const std::size_t overridden_layer_count = CountOverriddenLayers(configuration->parameters); - - if (overridden_layer_count > 1) { - QTreeWidgetItem *item = new QTreeWidgetItem(); - item->setText(0, "Vulkan Applications"); - item->setToolTip(0, TOOLTIP_ORDER); - item->setTextAlignment(0, Qt::AlignCenter); - item->setFont(0, font_section); - item->setDisabled(true); - this->tree->addTopLevelItem(item); - } - - // There will be one top level item for each layer - for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { - Parameter ¶meter = configuration->parameters[i]; - if (!IsPlatformSupported(parameter.platform_flags)) continue; - - if (parameter.state != LAYER_STATE_OVERRIDDEN) continue; - - const std::vector &selected_layers = configurator.layers.selected_layers; - const Layer *layer = FindByKey(selected_layers, parameter.key.c_str()); - - QTreeWidgetItem *layer_item = new QTreeWidgetItem(); - this->tree->addTopLevelItem(layer_item); - - std::string layer_text = parameter.key; - if (layer == nullptr) { - layer_text += " (Missing)"; - } else if (layer->status != STATUS_STABLE) { - layer_text += std::string(" (") + GetToken(layer->status) + ")"; - } - - layer_item->setToolTip(0, parameter.key.c_str()); // Hack for the context menu to find the layer - layer_item->setText(0, layer_text.c_str()); - layer_item->setFont(0, font_layer); - layer_item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - if (layer != nullptr) layer_item->setToolTip(0, layer->description.c_str()); - layer_item->setExpanded(true); - - if (layer == nullptr) continue; - - // Handle the case were we get off easy. No settings. - if (parameter.settings.empty()) { - QTreeWidgetItem *layer_child_item = new QTreeWidgetItem(); - layer_child_item->setText(0, "No User Settings"); - layer_item->addChild(layer_child_item); - continue; - } - - if (!layer->presets.empty()) { - QTreeWidgetItem *presets_item = new QTreeWidgetItem(); - layer_item->addChild(presets_item); - WidgetPreset *presets_combobox = new WidgetPreset(this->tree, presets_item, *layer, parameter); - this->connect(presets_combobox, SIGNAL(itemChanged()), this, SLOT(OnPresetChanged())); - } - - if (UseBuiltinValidationSettings(parameter)) { - BuildValidationTree(layer_item, parameter); - } else { - BuildGenericTree(layer_item, parameter); - } - } - - if (overridden_layer_count > 1) { - QTreeWidgetItem *item = new QTreeWidgetItem(); - item->setText(0, "Vulkan Drivers"); - item->setToolTip(0, TOOLTIP_ORDER); - item->setTextAlignment(0, Qt::AlignCenter); - item->setFont(0, font_section); - item->setDisabled(true); - this->tree->addTopLevelItem(item); - } - - const std::size_t excluded_layer_count = - CountExcludedLayers(configuration->parameters, configurator.layers.selected_layers); - - if (excluded_layer_count > 0) { - // The last item is just the excluded layers - QTreeWidgetItem *excluded_layers = new QTreeWidgetItem(); - this->tree->addTopLevelItem(excluded_layers); - excluded_layers->setText(0, "Excluded Layers:"); - excluded_layers->setToolTip(0, "The following layers won't be executed."); - excluded_layers->setFont(0, font_section); - excluded_layers->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - excluded_layers->setExpanded(true); - - for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { - Parameter ¶meter = configuration->parameters[i]; - if (!IsPlatformSupported(parameter.platform_flags)) continue; - - if (parameter.state != LAYER_STATE_EXCLUDED) continue; - - const Layer *layer = FindByKey(configurator.layers.selected_layers, parameter.key.c_str()); - if (layer == nullptr) continue; // Do not display missing excluded layers - - QTreeWidgetItem *layer_item = new QTreeWidgetItem(); - layer_item->setText(0, parameter.key.c_str()); - layer_item->setFont(0, font_layer); - layer_item->setToolTip(0, layer->description.c_str()); - excluded_layers->addChild(layer_item); - } - - // None excluded layer were found - if (excluded_layers->childCount() == 0) { - QTreeWidgetItem *child = new QTreeWidgetItem(); - child->setText(0, "None"); - excluded_layers->addChild(child); - } - } - } - - this->connect(this->tree, SIGNAL(expanded(const QModelIndex)), this, SLOT(OnExpandedChanged(const QModelIndex))); - this->connect(this->tree, SIGNAL(collapsed(const QModelIndex)), this, SLOT(OnCollapsedChanged(const QModelIndex))); - - this->tree->resizeColumnToContents(0); - - if (!configuration->setting_tree_state.isEmpty()) { - this->SetTreeState(configuration->setting_tree_state, 0, this->tree->invisibleRootItem()); - } - - this->tree->blockSignals(false); -} - -void SettingsTreeManager::CleanupGUI() { - if (this->tree == nullptr) // Was not initialized - return; - - Configurator &configurator = Configurator::Get(); - - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); - if (configuration != nullptr) { - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); - } - - this->validation.reset(); - - this->tree->clear(); - this->tree = nullptr; -} - -void SettingsTreeManager::OnExpandedChanged(const QModelIndex &index) { - (void)index; - - if (this->tree == nullptr) // Was not initialized - return; - - Configurator &configurator = Configurator::Get(); - - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); - - return; -} - -void SettingsTreeManager::OnCollapsedChanged(const QModelIndex &index) { - (void)index; - - if (this->tree == nullptr) // Was not initialized - return; - - Configurator &configurator = Configurator::Get(); - - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); - - return; -} - -void SettingsTreeManager::BuildValidationTree(QTreeWidgetItem *parent, Parameter ¶meter) { - Configurator &configurator = Configurator::Get(); - std::vector &selected_layers = configurator.layers.selected_layers; - Layer *validation_layer = FindByKey(selected_layers, "VK_LAYER_KHRONOS_validation"); - assert(validation_layer != nullptr); - - QTreeWidgetItem *validation_areas_item = new QTreeWidgetItem(); - parent->addChild(validation_areas_item); - - // This just finds the enables and disables - this->validation.reset( - new WidgetSettingValidation(this->tree, validation_areas_item, validation_layer->settings, parameter.settings)); - this->connect(this->validation.get(), SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - - SettingMetaSet &settings = validation_layer->settings; - for (std::size_t i = 0, n = settings.size(); i < n; ++i) { - this->BuildTreeItem(parent, parameter, *settings[i]); - } -} - -static bool IsBuiltinValidationSetting(const Parameter ¶meter, const std::string &key) { - if (parameter.key != "VK_LAYER_KHRONOS_validation") return false; - - std::vector keys; - keys.push_back("enables"); - keys.push_back("disables"); - - if (parameter.api_version.GetPatch() < 242) { - keys.push_back("printf_to_stdout"); - keys.push_back("printf_verbose"); - keys.push_back("printf_buffer_size"); - keys.push_back("gpuav_buffer_oob"); - keys.push_back("warn_on_robust_oob"); - keys.push_back("validate_draw_indirect"); - keys.push_back("vma_linear_output"); - keys.push_back("fine_grained_locking"); - } - - return IsStringFound(keys, key); -} - -void SettingsTreeManager::BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶meter, const SettingMeta &meta_object) { - if (IsBuiltinValidationSetting(parameter, meta_object.key)) return; - if (!IsPlatformSupported(meta_object.platform_flags)) return; - if (meta_object.view == SETTING_VIEW_HIDDEN) return; - if (meta_object.view == SETTING_VIEW_ADVANCED && - !Configurator::Get().configurations.FindActiveConfiguration()->view_advanced_settings) - return; - - QTreeWidgetItem *item = new QTreeWidgetItem(); - item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - parent->addChild(item); - - switch (meta_object.type) { - case SETTING_GROUP: { - item->setText(0, meta_object.label.c_str()); - item->setToolTip(0, meta_object.description.c_str()); - item->setFont(0, tree->font()); - item->setExpanded(meta_object.expanded); - } break; - case SETTING_BOOL: - case SETTING_BOOL_NUMERIC_DEPRECATED: { - const SettingMetaBool &meta = static_cast(meta_object); - - WidgetSettingBool *widget = new WidgetSettingBool(tree, item, meta, parameter.settings); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } break; - - case SETTING_INT: { - const SettingMetaInt &meta = static_cast(meta_object); - - WidgetSettingInt *widget = new WidgetSettingInt(tree, item, meta, parameter.settings); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } break; - - case SETTING_FLOAT: { - const SettingMetaFloat &meta = static_cast(meta_object); - - WidgetSettingFloat *widget = new WidgetSettingFloat(tree, item, meta, parameter.settings); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } break; - - case SETTING_FRAMES: { - const SettingMetaFrames &meta = static_cast(meta_object); - - WidgetSettingFrames *widget = new WidgetSettingFrames(tree, item, meta, parameter.settings); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } break; - - case SETTING_SAVE_FILE: - case SETTING_LOAD_FILE: - case SETTING_SAVE_FOLDER: - case SETTING_LOAD_FOLDER: { - const SettingMetaFilesystem &meta = static_cast(meta_object); - - WidgetSettingFilesystem *widget = new WidgetSettingFilesystem(tree, item, meta, parameter.settings); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } break; - - case SETTING_ENUM: { - const SettingMetaEnum &meta = static_cast(meta_object); - - WidgetSettingEnum *enum_widget = new WidgetSettingEnum(tree, item, meta, parameter.settings); - this->connect(enum_widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - - for (std::size_t i = 0, n = meta.enum_values.size(); i < n; ++i) { - const SettingEnumValue &value = meta.enum_values[i]; - - if (!IsPlatformSupported(value.platform_flags)) continue; - if (value.view == SETTING_VIEW_HIDDEN) continue; - - for (std::size_t i = 0, n = value.settings.size(); i < n; ++i) { - this->BuildTreeItem(item, parameter, *value.settings[i]); - } - } - } break; - - case SETTING_FLAGS: { - const SettingMetaFlags &meta = static_cast(meta_object); - - item->setText(0, meta.label.c_str()); - item->setToolTip(0, meta.description.c_str()); - item->setExpanded(meta.expanded); - - for (std::size_t i = 0, n = meta.enum_values.size(); i < n; ++i) { - const SettingEnumValue &value = meta.enum_values[i]; - - if (!IsPlatformSupported(value.platform_flags)) continue; - if (value.view == SETTING_VIEW_HIDDEN) continue; - - QTreeWidgetItem *child = new QTreeWidgetItem(); - item->addChild(child); - - WidgetSettingFlag *widget = new WidgetSettingFlag(tree, child, meta, parameter.settings, value.key.c_str()); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - - for (std::size_t j = 0, o = value.settings.size(); j < o; ++j) { - this->BuildTreeItem(child, parameter, *value.settings[j]); - } - } - } break; - - case SETTING_STRING: { - const SettingMetaString &meta = static_cast(meta_object); - - WidgetSettingString *widget = new WidgetSettingString(tree, item, meta, parameter.settings); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } break; - - case SETTING_LIST: { - const SettingMetaList &meta = static_cast(meta_object); - - WidgetSettingList *widget = new WidgetSettingList(tree, item, meta, parameter.settings); - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } break; - - default: { - item->setText(0, "Unknown setting"); - assert(0); // Unknown setting - } break; - } - - for (std::size_t i = 0, n = meta_object.children.size(); i < n; ++i) { - this->BuildTreeItem(item, parameter, *meta_object.children[i]); - } -} - -void SettingsTreeManager::BuildGenericTree(QTreeWidgetItem *parent, Parameter ¶meter) { - std::vector &selected_layers = Configurator::Get().layers.selected_layers; - - const SettingMetaSet &settings = FindByKey(selected_layers, parameter.key.c_str())->settings; - for (std::size_t i = 0, n = settings.size(); i < n; ++i) { - this->BuildTreeItem(parent, parameter, *settings[i]); - } -} - -void SettingsTreeManager::GetTreeState(QByteArray &byte_array, QTreeWidgetItem *top_item) { - byte_array.push_back(top_item->isExpanded() ? '1' : '0'); - - for (int i = 0, n = top_item->childCount(); i < n; ++i) { - GetTreeState(byte_array, top_item->child(i)); - } -} - -int SettingsTreeManager::SetTreeState(QByteArray &byte_array, int index, QTreeWidgetItem *top_item) { - // We very well could run out, on initial run, expand everything - if (index > byte_array.length()) - top_item->setExpanded(true); - else { - top_item->setExpanded(byte_array[index++] == '1'); - } - - // Walk the children - if (top_item->childCount() != 0) { - for (int i = 0, n = top_item->childCount(); i < n; ++i) { - index = SetTreeState(byte_array, index, top_item->child(i)); - } - } - - return index; -} - -void SettingsTreeManager::OnPresetChanged() { this->Refresh(REFRESH_ENABLE_AND_STATE); } - -void SettingsTreeManager::OnSettingChanged() { this->Refresh(REFRESH_ENABLE_ONLY); } - -void SettingsTreeManager::Refresh(RefreshAreas refresh_areas) { - this->tree->blockSignals(true); - - QTreeWidgetItem *root_item = this->tree->invisibleRootItem(); - for (int i = 0, n = root_item->childCount(); i < n; ++i) { - this->RefreshItem(refresh_areas, root_item->child(i)); - } - - this->tree->blockSignals(false); - - if (this->launched_application) { - QSettings settings; - if (!settings.value(VKCONFIG_KEY_MESSAGE_NEED_APPLICATION_RESTART, false).toBool()) { - settings.setValue(VKCONFIG_KEY_MESSAGE_NEED_APPLICATION_RESTART, true); - - Alert::ConfiguratorRestart(); - } - } - - // Refresh layer configuration - Configurator &configurator = Configurator::Get(); - configurator.configurations.Configure(configurator.layers.selected_layers); -} - -void SettingsTreeManager::RefreshItem(RefreshAreas refresh_areas, QTreeWidgetItem *parent) { - QWidget *widget = this->tree->itemWidget(parent, 0); - if (widget != nullptr) { - WidgetSettingBase *widget_base = dynamic_cast(widget); - if (widget_base != nullptr) widget_base->Refresh(refresh_areas); - } - - for (int i = 0, n = parent->childCount(); i < n; ++i) { - QTreeWidgetItem *child = parent->child(i); - if (child == nullptr) continue; - - this->RefreshItem(refresh_areas, child); - } -} diff --git a/vkconfig/settings_tree.h b/vkconfig/settings_tree.h deleted file mode 100644 index 9979d53134..0000000000 --- a/vkconfig/settings_tree.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "settings_validation_areas.h" -#include "widget_setting_flags.h" -#include "widget_setting_filesystem.h" -#include "widget_preset.h" - -#include "../vkconfig_core/configuration.h" - -#include -#include - -#include -#include - -class SettingsTreeManager : QObject { - Q_OBJECT - public: - SettingsTreeManager(); - - bool launched_application; - - void CreateGUI(QTreeWidget *build_tree); - void CleanupGUI(); - - void GetTreeState(QByteArray &byte_array, QTreeWidgetItem *top_item); - int SetTreeState(QByteArray &byte_array, int index, QTreeWidgetItem *top_item); - - void Refresh(RefreshAreas refresh_areas); - - public Q_SLOTS: - void OnSettingChanged(); - void OnPresetChanged(); - void OnExpandedChanged(const QModelIndex &index); - void OnCollapsedChanged(const QModelIndex &index); - - private: - SettingsTreeManager(const SettingsTreeManager &) = delete; - SettingsTreeManager &operator=(const SettingsTreeManager &) = delete; - - void BuildValidationTree(QTreeWidgetItem *parent, Parameter ¶meter); - void BuildGenericTree(QTreeWidgetItem *parent, Parameter ¶meter); - void BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶meter, const SettingMeta &meta); - - void RefreshItem(RefreshAreas refresh_areas, QTreeWidgetItem *parent); - - QTreeWidget *tree; - std::unique_ptr validation; -}; diff --git a/vkconfig/settings_validation_areas.cpp b/vkconfig/settings_validation_areas.cpp deleted file mode 100644 index f5e35a7799..0000000000 --- a/vkconfig/settings_validation_areas.cpp +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_setting.h" -#include "settings_validation_areas.h" -#include "configurator.h" - -#include "../vkconfig_core/version.h" -#include "../vkconfig_core/platform.h" -#include "../vkconfig_core/util.h" -#include "../vkconfig_core/setting_bool.h" - -#include -#include - -static const char *TOKEN_CORE = "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT"; -static const char *TOKEN_CORE_LAYOUT = "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION"; -static const char *TOKEN_CORE_CMD = "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE"; -static const char *TOKEN_CORE_OBJECT = "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE"; -static const char *TOKEN_CORE_QUERY = "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION"; -static const char *TOKEN_CORE_DESC = "VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET"; -static const char *TOKEN_CORE_SHADER = "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT"; -static const char *TOKEN_CORE_PUSH = "VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE"; -static const char *TOKEN_CORE_CACHING = "VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT"; - -static const char *TOKEN_MISC_THREAD = "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT"; -static const char *TOKEN_MISC_UNIQUE = "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT"; -static const char *TOKEN_MISC_LIFETIMES = "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT"; -static const char *TOKEN_MISC_PARAM = "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT"; - -static const char *TOKEN_SHADER_GPU = "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"; -static const char *TOKEN_SHADER_GPU_RESERVE = "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT"; -static const char *TOKEN_SHADER_PRINTF = "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT"; - -static const char *TOKEN_SYNC = "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT"; -static const char *TOKEN_SYNC_QUEUE_SUBMIT = "VALIDATION_CHECK_ENABLE_SYNCHRONIZATION_VALIDATION_QUEUE_SUBMIT"; - -static const char *TOKEN_BEST = "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT"; -static const char *TOKEN_BEST_ARM = "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM"; -static const char *TOKEN_BEST_AMD = "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD"; -static const char *TOKEN_BEST_IMG = "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_IMG"; -static const char *TOKEN_BEST_NVIDIA = "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA"; - -QCheckBox *WidgetSettingValidation::CreateWidget(QTreeWidgetItem *parent, QTreeWidgetItem **item, const char *key, - const char *flag) { - const SettingEnumValue *value = this->GetMetaFlag(key, flag); - - if (!IsSupported(value)) { - return nullptr; - } - - const std::string status = value->status == STATUS_STABLE ? "" : std::string(" (") + GetToken(value->status) + ")"; - - *item = new QTreeWidgetItem(); - (*item)->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - parent->addChild(*item); - (*item)->setExpanded(true); - - QCheckBox *widget = new QCheckBox(this); - widget->setText((value->label + status).c_str()); - widget->setToolTip(value->description.c_str()); - this->tree->setItemWidget(*item, 0, widget); - return widget; -} - -WidgetSettingValidation::WidgetSettingValidation(QTreeWidget *tree, QTreeWidgetItem *item, const SettingMetaSet &meta_set, - SettingDataSet &data_set) - : WidgetSettingBase(tree, item), - item_core(nullptr), - widget_core(nullptr), - item_core_layout(nullptr), - widget_core_layout(nullptr), - item_core_command(nullptr), - widget_core_cmd(nullptr), - item_core_object(nullptr), - widget_core_object(nullptr), - item_core_query(nullptr), - widget_core_query(nullptr), - item_core_desc(nullptr), - widget_core_desc(nullptr), - item_core_shader(nullptr), - widget_core_shader(nullptr), - item_core_push(nullptr), - widget_core_push(nullptr), - item_misc_thread(nullptr), - widget_misc_thread(nullptr), - item_misc_unique(nullptr), - widget_misc_unique(nullptr), - item_misc_lifetimes(nullptr), - widget_misc_lifetimes(nullptr), - item_misc_param(nullptr), - widget_misc_param(nullptr), - - item_shader(nullptr), - widget_shader(nullptr), - item_shader_gpu(nullptr), - widget_shader_gpu(nullptr), - item_shader_gpu_reserve(nullptr), - widget_shader_gpu_reserve(nullptr), - item_shader_gpu_oob(nullptr), - widget_shader_gpu_oob(nullptr), - item_shader_gpu_robust_oob(nullptr), - widget_shader_gpu_robust_oob(nullptr), - item_shader_gpu_desc_indexing(nullptr), - widget_shader_gpu_desc_indexing(nullptr), - item_shader_gpu_indirect(nullptr), - widget_shader_gpu_indirect(nullptr), - item_shader_dispatch_indirect(nullptr), - widget_shader_dispatch_indirect(nullptr), - item_shader_gpu_vma_linear_output(nullptr), - widget_shader_gpu_vma_linear_output(nullptr), - item_shader_printf(nullptr), - widget_shader_printf(nullptr), - - item_shader_printf_to_stdout(nullptr), - widget_shader_printf_to_stdout(nullptr), - item_shader_printf_verbose(nullptr), - widget_shader_printf_verbose(nullptr), - item_shader_printf_size(nullptr), - widget_debug_printf_size(nullptr), - - item_sync(nullptr), - widget_sync(nullptr), - item_sync_queue_submit(nullptr), - widget_sync_queue_submit(nullptr), - item_best(nullptr), - widget_best(nullptr), - item_best_arm(nullptr), - widget_best_arm(nullptr), - item_best_amd(nullptr), - widget_best_amd(nullptr), - item_best_img(nullptr), - widget_best_img(nullptr), - item_best_nvidia(nullptr), - widget_best_nvidia(nullptr), - - meta_set(meta_set), - data_set(data_set) { - assert(FindSetting(meta_set, "enables") != nullptr); - assert(FindSetting(meta_set, "disables") != nullptr); - assert(FindSetting(data_set, "enables") != nullptr); - assert(FindSetting(data_set, "disables") != nullptr); - - this->item->setText(0, "Validation Areas"); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(false); - - // Core - this->widget_core = this->CreateWidget(this->item, &this->item_core, "disables", TOKEN_CORE); - if (this->widget_core != nullptr) { - this->connect(this->widget_core, SIGNAL(clicked(bool)), this, SLOT(OnCoreChecked(bool))); - - Configurator &configurator = Configurator::Get(); - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); - - if (configuration->view_advanced_settings) { - this->widget_core_layout = this->CreateWidget(this->item_core, &this->item_core_layout, "disables", TOKEN_CORE_LAYOUT); - if (this->widget_core_layout != nullptr) - this->connect(this->widget_core_layout, SIGNAL(clicked(bool)), this, SLOT(OnCoreLayoutChecked(bool))); - - this->widget_core_cmd = this->CreateWidget(this->item_core, &this->item_core_command, "disables", TOKEN_CORE_CMD); - if (this->widget_core_cmd != nullptr) - this->connect(this->widget_core_cmd, SIGNAL(clicked(bool)), this, SLOT(OnCoreCommandChecked(bool))); - - this->widget_core_object = this->CreateWidget(this->item_core, &this->item_core_object, "disables", TOKEN_CORE_OBJECT); - if (this->widget_core_object != nullptr) - this->connect(this->widget_core_object, SIGNAL(clicked(bool)), this, SLOT(OnCoreObjectChecked(bool))); - - this->widget_core_query = this->CreateWidget(this->item_core, &this->item_core_query, "disables", TOKEN_CORE_QUERY); - if (this->widget_core_query != nullptr) - this->connect(this->widget_core_query, SIGNAL(clicked(bool)), this, SLOT(OnCoreQueryChecked(bool))); - - this->widget_core_desc = this->CreateWidget(this->item_core, &this->item_core_desc, "disables", TOKEN_CORE_DESC); - if (this->widget_core_desc != nullptr) - this->connect(this->widget_core_desc, SIGNAL(clicked(bool)), this, SLOT(OnCoreDescChecked(bool))); - - this->widget_core_shader = this->CreateWidget(this->item_core, &this->item_core_shader, "disables", TOKEN_CORE_SHADER); - if (this->widget_core_shader != nullptr) { - this->connect(this->widget_core_shader, SIGNAL(clicked(bool)), this, SLOT(OnCoreShaderChecked(bool))); - - this->widget_core_caching = - this->CreateWidget(this->item_core_shader, &this->item_core_caching, "disables", TOKEN_CORE_CACHING); - if (this->widget_core_caching != nullptr) - this->connect(this->widget_core_caching, SIGNAL(clicked(bool)), this, SLOT(OnCoreCachingChecked(bool))); - } - - this->widget_core_push = this->CreateWidget(this->item_core, &this->item_core_push, "disables", TOKEN_CORE_PUSH); - if (this->widget_core_push != nullptr) - this->connect(this->widget_core_push, SIGNAL(clicked(bool)), this, SLOT(OnCorePushChecked(bool))); - } - } - - // Misc: VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT - this->widget_misc_thread = this->CreateWidget(this->item, &this->item_misc_thread, "disables", TOKEN_MISC_THREAD); - if (this->widget_misc_thread != nullptr) - this->connect(this->widget_misc_thread, SIGNAL(clicked(bool)), this, SLOT(OnMiscThreadChecked(bool))); - - // Misc: VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT - this->widget_misc_unique = this->CreateWidget(this->item, &this->item_misc_unique, "disables", TOKEN_MISC_UNIQUE); - if (this->widget_misc_unique != nullptr) - this->connect(this->widget_misc_unique, SIGNAL(clicked(bool)), this, SLOT(OnMiscUniqueChecked(bool))); - - // Misc: VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT - this->widget_misc_lifetimes = this->CreateWidget(this->item, &this->item_misc_lifetimes, "disables", TOKEN_MISC_LIFETIMES); - if (this->widget_misc_lifetimes != nullptr) - this->connect(this->widget_misc_lifetimes, SIGNAL(clicked(bool)), this, SLOT(OnMiscLifetimesChecked(bool))); - - // Misc: VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT - this->widget_misc_param = this->CreateWidget(this->item, &this->item_misc_param, "disables", TOKEN_MISC_PARAM); - if (this->widget_misc_param != nullptr) - this->connect(this->widget_misc_param, SIGNAL(clicked(bool)), this, SLOT(OnMiscParamChecked(bool))); - - // Shader-based - { - const SettingEnumValue *value_gpu = GetMetaFlag("enables", TOKEN_SHADER_GPU); - const SettingEnumValue *value_printf = GetMetaFlag("enables", TOKEN_SHADER_PRINTF); - if (IsSupported(value_gpu) && IsSupported(value_printf)) { - this->item_shader = new QTreeWidgetItem(); - this->item_shader->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->addChild(this->item_shader); - - this->widget_shader = new QCheckBox(this); - this->widget_shader->setText("Shader-Based"); - this->tree->setItemWidget(this->item_shader, 0, this->widget_shader); - this->connect(this->widget_shader, SIGNAL(clicked(bool)), this, SLOT(OnShaderBasedChecked(bool))); - - this->item_shader_gpu = new QTreeWidgetItem(); - this->item_shader_gpu->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader->addChild(this->item_shader_gpu); - this->item_shader->setExpanded(true); - this->item_shader_gpu->setExpanded(true); - - this->widget_shader_gpu = new QRadioButton(this); - this->widget_shader_gpu->setText(value_gpu->label.c_str()); - this->widget_shader_gpu->setToolTip(value_gpu->description.c_str()); - this->tree->setItemWidget(this->item_shader_gpu, 0, this->widget_shader_gpu); - this->connect(this->widget_shader_gpu, SIGNAL(toggled(bool)), this, SLOT(OnShaderGPUChecked(bool))); - - this->widget_shader_gpu_reserve = - this->CreateWidget(this->item_shader_gpu, &this->item_shader_gpu_reserve, "enables", TOKEN_SHADER_GPU_RESERVE); - - if (this->widget_shader_gpu_reserve != nullptr) - this->connect(this->widget_shader_gpu_reserve, SIGNAL(clicked(bool)), this, SLOT(OnShaderGPUReserveChecked(bool))); - - { - const SettingMetaBool *value = FindSetting(meta_set, "gpuav_descriptor_indexing"); - if (IsSupported(value)) { - this->item_shader_gpu_desc_indexing = new QTreeWidgetItem(); - this->item_shader_gpu_desc_indexing->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_gpu->addChild(this->item_shader_gpu_desc_indexing); - this->item_shader_gpu->setExpanded(true); - - this->widget_shader_gpu_desc_indexing = new QCheckBox(this); - this->widget_shader_gpu_desc_indexing->setText(value->label.c_str()); - this->widget_shader_gpu_desc_indexing->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_gpu_desc_indexing, 0, this->widget_shader_gpu_desc_indexing); - this->connect(this->widget_shader_gpu_desc_indexing, SIGNAL(clicked(bool)), this, - SLOT(OnShaderGPUDescIndexingChecked(bool))); - } - } - - { - const SettingMetaBool *value = FindSetting(meta_set, "gpuav_buffer_oob"); - if (IsSupported(value)) { - this->item_shader_gpu_oob = new QTreeWidgetItem(); - this->item_shader_gpu_oob->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_gpu->addChild(this->item_shader_gpu_oob); - this->item_shader_gpu->setExpanded(true); - - this->widget_shader_gpu_oob = new QCheckBox(this); - this->widget_shader_gpu_oob->setText(value->label.c_str()); - this->widget_shader_gpu_oob->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_gpu_oob, 0, this->widget_shader_gpu_oob); - this->connect(this->widget_shader_gpu_oob, SIGNAL(clicked(bool)), this, SLOT(OnShaderGPUOOBChecked(bool))); - - { - const SettingMetaBool *value = FindSetting(meta_set, "warn_on_robust_oob"); - if (IsSupported(value)) { - this->item_shader_gpu_robust_oob = new QTreeWidgetItem(); - this->item_shader_gpu_robust_oob->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_gpu_oob->addChild(this->item_shader_gpu_robust_oob); - this->item_shader_gpu_oob->setExpanded(true); - - this->widget_shader_gpu_robust_oob = new QCheckBox(this); - this->widget_shader_gpu_robust_oob->setText(value->label.c_str()); - this->widget_shader_gpu_robust_oob->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_gpu_robust_oob, 0, this->widget_shader_gpu_robust_oob); - this->connect(this->widget_shader_gpu_robust_oob, SIGNAL(clicked(bool)), this, - SLOT(OnShaderGPURobustOOBChecked(bool))); - } - } - } - } - - { - const SettingMetaBool *value = FindSetting(meta_set, "validate_draw_indirect"); - if (IsSupported(value)) { - this->item_shader_gpu_indirect = new QTreeWidgetItem(); - this->item_shader_gpu_indirect->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_gpu->addChild(this->item_shader_gpu_indirect); - this->item_shader_gpu->setExpanded(true); - - this->widget_shader_gpu_indirect = new QCheckBox(this); - this->widget_shader_gpu_indirect->setText(value->label.c_str()); - this->widget_shader_gpu_indirect->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_gpu_indirect, 0, this->widget_shader_gpu_indirect); - this->connect(this->widget_shader_gpu_indirect, SIGNAL(clicked(bool)), this, - SLOT(OnShaderGPUIndirectChecked(bool))); - } - } - - { - const SettingMetaBool *value = FindSetting(meta_set, "validate_dispatch_indirect"); - if (IsSupported(value)) { - this->item_shader_dispatch_indirect = new QTreeWidgetItem(); - this->item_shader_dispatch_indirect->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_gpu->addChild(this->item_shader_dispatch_indirect); - this->item_shader_gpu->setExpanded(true); - - this->widget_shader_dispatch_indirect = new QCheckBox(this); - this->widget_shader_dispatch_indirect->setText(value->label.c_str()); - this->widget_shader_dispatch_indirect->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_dispatch_indirect, 0, this->widget_shader_dispatch_indirect); - this->connect(this->widget_shader_dispatch_indirect, SIGNAL(clicked(bool)), this, - SLOT(OnShaderDispatchIndirectChecked(bool))); - } - } - - { - const SettingMetaBool *value = FindSetting(meta_set, "vma_linear_output"); - if (IsSupported(value)) { - this->item_shader_gpu_vma_linear_output = new QTreeWidgetItem(); - this->item_shader_gpu_vma_linear_output->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_gpu->addChild(this->item_shader_gpu_vma_linear_output); - this->item_shader_gpu->setExpanded(true); - - this->widget_shader_gpu_vma_linear_output = new QCheckBox(this); - this->widget_shader_gpu_vma_linear_output->setText(value->label.c_str()); - this->widget_shader_gpu_vma_linear_output->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_gpu_vma_linear_output, 0, - this->widget_shader_gpu_vma_linear_output); - this->connect(this->widget_shader_gpu_vma_linear_output, SIGNAL(clicked(bool)), this, - SLOT(OnShaderGPUVMALinearOutput(bool))); - } - } - - this->item_shader_printf = new QTreeWidgetItem(); - this->item_shader_printf->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader->addChild(this->item_shader_printf); - this->item_shader->setExpanded(true); - this->item_shader_printf->setExpanded(true); - - this->widget_shader_printf = new QRadioButton(this); - this->widget_shader_printf->setText(value_printf->label.c_str()); - this->widget_shader_printf->setToolTip(value_printf->description.c_str()); - this->tree->setItemWidget(this->item_shader_printf, 0, this->widget_shader_printf); - this->connect(this->widget_shader_printf, SIGNAL(toggled(bool)), this, SLOT(OnShaderPrintfChecked(bool))); - - { - const SettingMetaBool *value = FindSetting(meta_set, "printf_to_stdout"); - if (IsSupported(value)) { - this->item_shader_printf_to_stdout = new QTreeWidgetItem(); - this->item_shader_printf_to_stdout->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_printf->addChild(this->item_shader_printf_to_stdout); - this->item_shader_printf->setExpanded(true); - - this->widget_shader_printf_to_stdout = new QCheckBox(this); - this->widget_shader_printf_to_stdout->setText(value->label.c_str()); - this->widget_shader_printf_to_stdout->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_printf_to_stdout, 0, this->widget_shader_printf_to_stdout); - this->connect(this->widget_shader_printf_to_stdout, SIGNAL(clicked(bool)), this, - SLOT(OnShaderPrintfStdoutChecked(bool))); - } - } - - { - const SettingMetaBool *value = FindSetting(meta_set, "printf_verbose"); - if (IsSupported(value)) { - this->item_shader_printf_verbose = new QTreeWidgetItem(); - this->item_shader_printf_verbose->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_shader_printf->addChild(this->item_shader_printf_verbose); - this->item_shader_printf->setExpanded(true); - - this->widget_shader_printf_verbose = new QCheckBox(this); - this->widget_shader_printf_verbose->setText(value->label.c_str()); - this->widget_shader_printf_verbose->setToolTip(value->description.c_str()); - this->tree->setItemWidget(this->item_shader_printf_verbose, 0, this->widget_shader_printf_verbose); - this->connect(this->widget_shader_printf_verbose, SIGNAL(clicked(bool)), this, - SLOT(OnShaderPrintfVerboseChecked(bool))); - } - } - - { - const SettingMetaInt *value = FindSetting(meta_set, "printf_buffer_size"); - if (IsSupported(value)) { - this->item_shader_printf_size = new QTreeWidgetItem(); - this->item_shader_printf->addChild(this->item_shader_printf_size); - this->item_shader_printf->setExpanded(true); - - this->widget_debug_printf_size = new WidgetSettingInt(tree, this->item_shader_printf_size, *value, data_set); - this->connect(this->widget_debug_printf_size, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - } - } - } else if (IsSupported(value_gpu)) { - this->widget_shader = this->CreateWidget(this->item, &this->item_shader, "enables", TOKEN_SHADER_GPU); - this->connect(this->widget_shader, SIGNAL(clicked(bool)), this, SLOT(OnShaderGPUChecked(bool))); - - this->widget_shader_gpu_reserve = - this->CreateWidget(this->item_shader, &this->item_shader_gpu_reserve, "enables", TOKEN_SHADER_GPU_RESERVE); - if (this->widget_shader_gpu_reserve != nullptr) - this->connect(this->widget_shader_gpu_reserve, SIGNAL(clicked(bool)), this, SLOT(OnShaderGPUReserveChecked(bool))); - } - } - - // Synchronization - this->widget_sync = this->CreateWidget(this->item, &this->item_sync, "enables", TOKEN_SYNC); - if (this->widget_sync != nullptr) { - this->connect(this->widget_sync, SIGNAL(clicked(bool)), this, SLOT(OnSyncChecked(bool))); - - this->widget_sync_queue_submit = - this->CreateWidget(this->item_sync, &this->item_sync_queue_submit, "enables", TOKEN_SYNC_QUEUE_SUBMIT); - if (this->widget_sync_queue_submit != nullptr) - this->connect(this->widget_sync_queue_submit, SIGNAL(clicked(bool)), this, SLOT(OnSyncQueueSubmitChecked(bool))); - } - - // Best Practices - this->widget_best = this->CreateWidget(this->item, &this->item_best, "enables", TOKEN_BEST); - if (this->widget_best != nullptr) { - this->connect(this->widget_best, SIGNAL(clicked(bool)), this, SLOT(OnBestChecked(bool))); - - this->widget_best_amd = this->CreateWidget(this->item_best, &this->item_best_amd, "enables", TOKEN_BEST_AMD); - if (this->widget_best_amd != nullptr) - this->connect(this->widget_best_amd, SIGNAL(clicked(bool)), this, SLOT(OnBestAmdChecked(bool))); - - this->widget_best_arm = this->CreateWidget(this->item_best, &this->item_best_arm, "enables", TOKEN_BEST_ARM); - if (this->widget_best_arm != nullptr) - this->connect(this->widget_best_arm, SIGNAL(clicked(bool)), this, SLOT(OnBestArmChecked(bool))); - - this->widget_best_img = this->CreateWidget(this->item_best, &this->item_best_img, "enables", TOKEN_BEST_IMG); - if (this->widget_best_img != nullptr) - this->connect(this->widget_best_img, SIGNAL(clicked(bool)), this, SLOT(OnBestImgChecked(bool))); - - this->widget_best_nvidia = this->CreateWidget(this->item_best, &this->item_best_nvidia, "enables", TOKEN_BEST_NVIDIA); - if (this->widget_best_nvidia != nullptr) - this->connect(this->widget_best_nvidia, SIGNAL(clicked(bool)), this, SLOT(OnBestNvidiaChecked(bool))); - } - - this->tree->setItemWidget(this->item, 0, this); - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -void WidgetSettingValidation::OnCoreChecked(bool checked) { - if (checked && !CheckOverhead(OVERHEAD_CORE)) { - this->widget_core->setChecked(false); - return; - } - - if (!checked) - this->UpdateFlag("disables", TOKEN_CORE, true); - else { - this->UpdateFlag("disables", TOKEN_CORE, false); - this->UpdateFlag("disables", TOKEN_CORE_LAYOUT, false); - this->UpdateFlag("disables", TOKEN_CORE_CMD, false); - this->UpdateFlag("disables", TOKEN_CORE_OBJECT, false); - this->UpdateFlag("disables", TOKEN_CORE_QUERY, false); - this->UpdateFlag("disables", TOKEN_CORE_DESC, false); - this->UpdateFlag("disables", TOKEN_CORE_SHADER, false); - this->UpdateFlag("disables", TOKEN_CORE_PUSH, false); - this->UpdateFlag("disables", TOKEN_CORE_CACHING, false); - } - - if (widget_core_layout != nullptr) { - widget_core_layout->setChecked(!HasDataFlag("disables", TOKEN_CORE_LAYOUT)); - } - if (widget_core_cmd != nullptr) { - widget_core_cmd->setChecked(!HasDataFlag("disables", TOKEN_CORE_CMD)); - } - if (widget_core_object != nullptr) { - widget_core_object->setChecked(!HasDataFlag("disables", TOKEN_CORE_OBJECT)); - } - if (widget_core_query != nullptr) { - widget_core_query->setChecked(!HasDataFlag("disables", TOKEN_CORE_QUERY)); - } - if (widget_core_desc != nullptr) { - widget_core_desc->setChecked(!HasDataFlag("disables", TOKEN_CORE_DESC)); - } - if (widget_core_shader != nullptr) { - widget_core_shader->setChecked(!HasDataFlag("disables", TOKEN_CORE_SHADER)); - if (widget_core_caching != nullptr) { - widget_core_caching->setChecked(!HasDataFlag("disables", TOKEN_CORE_CACHING)); - } - } - if (widget_core_push != nullptr) { - widget_core_push->setChecked(!HasDataFlag("disables", TOKEN_CORE_PUSH)); - } - - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCoreLayoutChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_LAYOUT, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCoreCommandChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_CMD, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCoreObjectChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_OBJECT, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCoreQueryChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_QUERY, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCoreDescChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_DESC, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCoreShaderChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_SHADER, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCorePushChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_PUSH, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnCoreCachingChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_CORE_CACHING, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnMiscThreadChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_MISC_THREAD, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnMiscUniqueChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_MISC_UNIQUE, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnMiscLifetimesChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_MISC_LIFETIMES, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnMiscParamChecked(bool checked) { - this->UpdateFlag("disables", TOKEN_MISC_PARAM, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderBasedChecked(bool checked) { - if (checked && !CheckOverhead(OVERHEAD_SHADER)) { - this->widget_shader->setChecked(false); - return; - } - - if (!checked) { - this->UpdateFlag("enables", TOKEN_SHADER_GPU, false); - this->UpdateFlag("enables", TOKEN_SHADER_PRINTF, false); - } else if (this->widget_shader_printf->isChecked()) { - this->UpdateFlag("enables", TOKEN_SHADER_GPU, false); - this->UpdateFlag("enables", TOKEN_SHADER_PRINTF, true); - } else { - if (!this->widget_shader_gpu->isChecked()) this->widget_shader_gpu->setChecked(true); - this->UpdateFlag("enables", TOKEN_SHADER_GPU, true); - this->UpdateFlag("enables", TOKEN_SHADER_PRINTF, false); - } - - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderGPUChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_SHADER_GPU, checked); - this->UpdateFlag("enables", TOKEN_SHADER_PRINTF, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderGPUReserveChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_SHADER_GPU_RESERVE, checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderGPUDescIndexingChecked(bool checked) { - static_cast(FindSetting(this->data_set, "gpuav_descriptor_indexing"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderGPUOOBChecked(bool checked) { - static_cast(FindSetting(this->data_set, "gpuav_buffer_oob"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderGPURobustOOBChecked(bool checked) { - static_cast(FindSetting(this->data_set, "warn_on_robust_oob"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderGPUIndirectChecked(bool checked) { - static_cast(FindSetting(this->data_set, "validate_draw_indirect"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderDispatchIndirectChecked(bool checked) { - static_cast(FindSetting(this->data_set, "validate_dispatch_indirect"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderGPUVMALinearOutput(bool checked) { - static_cast(FindSetting(this->data_set, "vma_linear_output"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderPrintfChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_SHADER_PRINTF, checked); - this->UpdateFlag("enables", TOKEN_SHADER_GPU, !checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderPrintfStdoutChecked(bool checked) { - static_cast(FindSetting(this->data_set, "printf_to_stdout"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnShaderPrintfVerboseChecked(bool checked) { - static_cast(FindSetting(this->data_set, "printf_verbose"))->value = checked; - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnSyncChecked(bool checked) { - if (checked && !CheckOverhead(OVERHEAD_SYNC)) { - this->widget_sync->setChecked(false); - return; - } - - this->UpdateFlag("enables", TOKEN_SYNC, checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnSyncQueueSubmitChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_SYNC_QUEUE_SUBMIT, checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnBestChecked(bool checked) { - if (checked && !CheckOverhead(OVERHEAD_BEST)) { - this->widget_best->setChecked(false); - return; - } - - this->UpdateFlag("enables", TOKEN_BEST, checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnBestArmChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_BEST_ARM, checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnBestAmdChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_BEST_AMD, checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnBestImgChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_BEST_IMG, checked); - this->OnSettingChanged(); -} - -void WidgetSettingValidation::OnBestNvidiaChecked(bool checked) { - this->UpdateFlag("enables", TOKEN_BEST_NVIDIA, checked); - this->OnSettingChanged(); -} - -bool WidgetSettingValidation::CheckOverhead(Overhead candidate) const { - QSettings settings; - if (settings.value("VKCONFIG_WARN_CORE_SHADER_IGNORE").toBool() == false) { - const bool features_to_run_alone[] = { - this->widget_core != nullptr ? this->widget_core->isChecked() || candidate == OVERHEAD_CORE : false, - this->widget_shader != nullptr ? this->widget_shader->isChecked() || candidate == OVERHEAD_SHADER : false, - this->widget_sync != nullptr ? this->widget_sync->isChecked() || candidate == OVERHEAD_SYNC : false, - this->widget_best != nullptr ? this->widget_best->isChecked() || candidate == OVERHEAD_BEST : false}; - - static const char *LABELS[]{ - "Core Validation", // OVERHEAD_CORE - "Shader Based Validation", // OVERHEAD_SHADER - "Synchronization Validation", // OVERHEAD_SYNC - "Best Practices Warnings" // OVERHEAD_BEST - }; - static_assert(countof(LABELS) == OVERHEAD_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - int count_enabled_features = 0; - for (std::size_t i = 0, n = countof(features_to_run_alone); i < n; ++i) - count_enabled_features += features_to_run_alone[i] ? 1 : 0; - - if (count_enabled_features > 1) { - QMessageBox alert(this->tree); - alert.setWindowTitle("High Validation Layer Overhead"); - alert.setText(format("Using %s, %s, %s and %s simultanously results in high performance degradation.", - LABELS[OVERHEAD_CORE], LABELS[OVERHEAD_SHADER], LABELS[OVERHEAD_SYNC], LABELS[OVERHEAD_BEST]) - .c_str()); - alert.setInformativeText(format("Do you want to add %s anyway?", LABELS[candidate]).c_str()); - alert.setIcon(QMessageBox::Warning); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setCheckBox(new QCheckBox("Do not show again.")); - const bool result = alert.exec() == QMessageBox::Yes; - if (alert.checkBox()->isChecked()) { - settings.setValue("VKCONFIG_WARN_CORE_SHADER_IGNORE", true); - } - return result; - } - } - - return true; -} - -void WidgetSettingValidation::OnSettingChanged() { emit itemChanged(); } - -void WidgetSettingValidation::UpdateFlag(const char *key, const char *flag, bool append) { - SettingDataFlags *data = static_cast(FindSetting(this->data_set, key)); - assert(data != nullptr); - - if (append) { - AppendString(data->value, flag); - } else { - RemoveString(data->value, flag); - } -} - -bool WidgetSettingValidation::HasDataBool(const char *key) const { - return static_cast(FindSetting(this->data_set, key))->value; -} - -bool WidgetSettingValidation::HasDataFlag(const char *key, const char *flag) const { - const SettingDataFlags *data = static_cast(FindSetting(this->data_set, key)); - - return IsStringFound(data->value, flag); -} - -const SettingEnumValue *WidgetSettingValidation::GetMetaFlag(const char *key, const char *flag) const { - return FindByKey(static_cast(FindSetting(this->meta_set, key))->enum_values, flag); -} - -void WidgetSettingValidation::Refresh(RefreshAreas refresh_areas) { - const bool core_enabled = !HasDataFlag("disables", TOKEN_CORE); - - if (this->widget_core != nullptr) { - this->widget_core->setChecked(core_enabled); - } - - if (this->widget_core_layout != nullptr) { - this->widget_core_layout->setEnabled(core_enabled); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_core_layout->setChecked(!HasDataFlag("disables", TOKEN_CORE_LAYOUT)); - } - - if (this->widget_core_cmd != nullptr) { - this->widget_core_cmd->setEnabled(core_enabled); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) this->widget_core_cmd->setChecked(!HasDataFlag("disables", TOKEN_CORE_CMD)); - } - - if (this->widget_core_object != nullptr) { - this->widget_core_object->setEnabled(core_enabled); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_core_object->setChecked(!HasDataFlag("disables", TOKEN_CORE_OBJECT)); - } - - if (this->widget_core_query != nullptr) { - this->widget_core_query->setEnabled(core_enabled); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_core_query->setChecked(!HasDataFlag("disables", TOKEN_CORE_QUERY)); - } - - if (this->widget_core_desc != nullptr) { - this->widget_core_desc->setEnabled(core_enabled); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_core_desc->setChecked(!HasDataFlag("disables", TOKEN_CORE_DESC)); - } - - if (this->widget_core_shader != nullptr) { - this->widget_core_shader->setEnabled(core_enabled); - - const bool shader_enabled = !HasDataFlag("disables", TOKEN_CORE_SHADER); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) this->widget_core_shader->setChecked(shader_enabled); - - if (this->widget_core_caching != nullptr) { - this->widget_core_caching->setEnabled(core_enabled && shader_enabled); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_core_caching->setChecked(!HasDataFlag("disables", TOKEN_CORE_CACHING)); - } - } - - if (this->widget_core_push != nullptr) { - this->widget_core_push->setEnabled(core_enabled); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_core_push->setChecked(!HasDataFlag("disables", TOKEN_CORE_PUSH)); - } - - if (this->widget_misc_thread != nullptr && refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_misc_thread->setChecked(!HasDataFlag("disables", TOKEN_MISC_THREAD)); - } - - if (this->widget_misc_unique != nullptr && refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_misc_unique->setChecked(!HasDataFlag("disables", TOKEN_MISC_UNIQUE)); - } - - if (this->widget_misc_lifetimes != nullptr && refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_misc_lifetimes->setChecked(!HasDataFlag("disables", TOKEN_MISC_LIFETIMES)); - } - - if (this->widget_misc_param != nullptr && refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_misc_param->setChecked(!HasDataFlag("disables", TOKEN_MISC_PARAM)); - } - - if (this->widget_shader != nullptr) { - const bool shader_gpu = HasDataFlag("enables", TOKEN_SHADER_GPU); - const bool shader_printf = HasDataFlag("enables", TOKEN_SHADER_PRINTF); - - if (GetMetaFlag("enables", TOKEN_SHADER_GPU) != nullptr && GetMetaFlag("enables", TOKEN_SHADER_PRINTF) != nullptr) { - const bool shader_enabled = this->widget_shader->isChecked() || shader_gpu || shader_printf; - if (shader_enabled && refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_shader->setChecked(shader_gpu || shader_printf); - } - - if (this->widget_shader_gpu != nullptr) { - this->widget_shader_gpu->setEnabled(this->widget_shader->isChecked()); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) this->widget_shader_gpu->setChecked(shader_gpu); - } - - if (this->widget_shader_gpu_reserve != nullptr) { - this->widget_shader_gpu_reserve->setEnabled(shader_gpu); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_gpu_reserve->setChecked(this->HasDataFlag("enables", TOKEN_SHADER_GPU_RESERVE)); - } - - if (this->widget_shader_gpu_desc_indexing != nullptr) { - this->widget_shader_gpu_desc_indexing->setEnabled(shader_gpu); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_gpu_desc_indexing->setChecked(this->HasDataBool("gpuav_descriptor_indexing")); - } - - if (this->widget_shader_gpu_oob != nullptr) { - this->widget_shader_gpu_oob->setEnabled(shader_gpu); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_gpu_oob->setChecked(this->HasDataBool("gpuav_buffer_oob")); - - if (this->widget_shader_gpu_robust_oob != nullptr) { - this->widget_shader_gpu_robust_oob->setEnabled(shader_gpu && this->HasDataBool("gpuav_buffer_oob")); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_gpu_robust_oob->setChecked(this->HasDataBool("warn_on_robust_oob")); - } - } - - if (this->widget_shader_gpu_indirect != nullptr) { - this->widget_shader_gpu_indirect->setEnabled(shader_gpu); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_gpu_indirect->setChecked(this->HasDataBool("validate_draw_indirect")); - } - - if (this->widget_shader_dispatch_indirect != nullptr) { - this->widget_shader_dispatch_indirect->setEnabled(shader_gpu); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_dispatch_indirect->setChecked(this->HasDataBool("validate_dispatch_indirect")); - } - - if (this->widget_shader_gpu_vma_linear_output != nullptr) { - this->widget_shader_gpu_vma_linear_output->setEnabled(shader_gpu); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_gpu_vma_linear_output->setChecked(this->HasDataBool("vma_linear_output")); - } - - if (this->widget_shader_printf != nullptr) { - this->widget_shader_printf->setEnabled(this->widget_shader->isChecked()); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) this->widget_shader_printf->setChecked(shader_printf); - } - - if (this->widget_shader_printf_to_stdout != nullptr) { - this->widget_shader_printf_to_stdout->setEnabled(shader_printf); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_printf_to_stdout->setChecked(this->HasDataBool("printf_to_stdout")); - } - - if (this->widget_shader_printf_verbose != nullptr) { - this->widget_shader_printf_verbose->setEnabled(shader_printf); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_printf_verbose->setChecked(this->HasDataBool("printf_verbose")); - } - - if (this->widget_debug_printf_size != nullptr) { - this->widget_debug_printf_size->setEnabled(shader_printf); - } - } else if (GetMetaFlag("enables", TOKEN_SHADER_GPU) != nullptr) { - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_shader->setChecked(HasDataFlag("enables", TOKEN_SHADER_GPU)); - } - - if (this->widget_shader_gpu_reserve != nullptr) { - this->widget_shader_gpu_reserve->setEnabled(shader_gpu); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) - this->widget_shader_gpu_reserve->setChecked(HasDataFlag("enables", TOKEN_SHADER_GPU)); - } - } - } - - if (this->widget_sync != nullptr && refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_sync->setChecked(HasDataFlag("enables", TOKEN_SYNC)); - } - - if (this->widget_sync_queue_submit != nullptr) { - this->widget_sync_queue_submit->setEnabled(HasDataFlag("enables", TOKEN_SYNC)); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_sync_queue_submit->setChecked(HasDataFlag("enables", TOKEN_SYNC_QUEUE_SUBMIT)); - } - } - - if (this->widget_best != nullptr && refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_best->setChecked(HasDataFlag("enables", TOKEN_BEST)); - } - - if (this->widget_best_arm != nullptr) { - this->widget_best_arm->setEnabled(HasDataFlag("enables", TOKEN_BEST)); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_best_arm->setChecked(HasDataFlag("enables", TOKEN_BEST_ARM)); - } - } - - if (this->widget_best_amd != nullptr) { - this->widget_best_amd->setEnabled(HasDataFlag("enables", TOKEN_BEST)); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_best_amd->setChecked(HasDataFlag("enables", TOKEN_BEST_AMD)); - } - } - - if (this->widget_best_img != nullptr) { - this->widget_best_img->setEnabled(HasDataFlag("enables", TOKEN_BEST)); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_best_img->setChecked(HasDataFlag("enables", TOKEN_BEST_IMG)); - } - } - - if (this->widget_best_nvidia != nullptr) { - this->widget_best_nvidia->setEnabled(HasDataFlag("enables", TOKEN_BEST)); - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - this->widget_best_nvidia->setChecked(HasDataFlag("enables", TOKEN_BEST_NVIDIA)); - } - } - - this->blockSignals(false); -} diff --git a/vkconfig/settings_validation_areas.h b/vkconfig/settings_validation_areas.h deleted file mode 100644 index c621e562ce..0000000000 --- a/vkconfig/settings_validation_areas.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/layer.h" - -#include "widget_setting_int.h" -#include "widget_setting_flags.h" - -#include "widget_setting.h" -#include -#include - -#include - -class WidgetSettingValidation : public WidgetSettingBase { - Q_OBJECT - - public: - explicit WidgetSettingValidation(QTreeWidget *tree, QTreeWidgetItem *item, const SettingMetaSet &meta_set, - SettingDataSet &data_set); - - void Refresh(RefreshAreas refresh_areas) override; - - private: - QTreeWidgetItem *item_core; - QCheckBox *widget_core; - - QTreeWidgetItem *item_core_layout; - QCheckBox *widget_core_layout; - - QTreeWidgetItem *item_core_command; - QCheckBox *widget_core_cmd; - - QTreeWidgetItem *item_core_object; - QCheckBox *widget_core_object; - - QTreeWidgetItem *item_core_query; - QCheckBox *widget_core_query; - - QTreeWidgetItem *item_core_desc; - QCheckBox *widget_core_desc; - - QTreeWidgetItem *item_core_shader; - QCheckBox *widget_core_shader; - - QTreeWidgetItem *item_core_push; - QCheckBox *widget_core_push; - - QTreeWidgetItem *item_core_caching; - QCheckBox *widget_core_caching; - - QTreeWidgetItem *item_misc_thread; - QCheckBox *widget_misc_thread; - - QTreeWidgetItem *item_misc_unique; - QCheckBox *widget_misc_unique; - - QTreeWidgetItem *item_misc_lifetimes; - QCheckBox *widget_misc_lifetimes; - - QTreeWidgetItem *item_misc_param; - QCheckBox *widget_misc_param; - - QTreeWidgetItem *item_shader; - QCheckBox *widget_shader; - - QTreeWidgetItem *item_shader_gpu; - QRadioButton *widget_shader_gpu; - - QTreeWidgetItem *item_shader_gpu_reserve; - QCheckBox *widget_shader_gpu_reserve; - - QTreeWidgetItem *item_shader_gpu_oob; - QCheckBox *widget_shader_gpu_oob; - - QTreeWidgetItem *item_shader_gpu_robust_oob; - QCheckBox *widget_shader_gpu_robust_oob; - - QTreeWidgetItem *item_shader_gpu_desc_indexing; - QCheckBox *widget_shader_gpu_desc_indexing; - - QTreeWidgetItem *item_shader_gpu_indirect; - QCheckBox *widget_shader_gpu_indirect; - - QTreeWidgetItem *item_shader_dispatch_indirect; - QCheckBox *widget_shader_dispatch_indirect; - - QTreeWidgetItem *item_shader_gpu_vma_linear_output; - QCheckBox *widget_shader_gpu_vma_linear_output; - - QTreeWidgetItem *item_shader_printf; - QRadioButton *widget_shader_printf; - - QTreeWidgetItem *item_shader_printf_to_stdout; - QCheckBox *widget_shader_printf_to_stdout; - - QTreeWidgetItem *item_shader_printf_verbose; - QCheckBox *widget_shader_printf_verbose; - - QTreeWidgetItem *item_shader_printf_size; - WidgetSettingInt *widget_debug_printf_size; - - QTreeWidgetItem *item_sync; - QCheckBox *widget_sync; - - QTreeWidgetItem *item_sync_queue_submit; - QCheckBox *widget_sync_queue_submit; - - QTreeWidgetItem *item_best; - QCheckBox *widget_best; - - QTreeWidgetItem *item_best_arm; - QCheckBox *widget_best_arm; - - QTreeWidgetItem *item_best_amd; - QCheckBox *widget_best_amd; - - QTreeWidgetItem *item_best_img; - QCheckBox *widget_best_img; - - QTreeWidgetItem *item_best_nvidia; - QCheckBox *widget_best_nvidia; - - QCheckBox *CreateWidget(QTreeWidgetItem *parent, QTreeWidgetItem **item, const char *key, const char *flag); - - public Q_SLOTS: - void OnCoreChecked(bool checked); - - void OnCoreLayoutChecked(bool checked); - void OnCoreCommandChecked(bool checked); - void OnCoreObjectChecked(bool checked); - void OnCoreQueryChecked(bool checked); - void OnCoreDescChecked(bool checked); - void OnCoreShaderChecked(bool checked); - void OnCorePushChecked(bool checked); - void OnCoreCachingChecked(bool checked); - - void OnMiscThreadChecked(bool checked); - void OnMiscUniqueChecked(bool checked); - void OnMiscLifetimesChecked(bool checked); - void OnMiscParamChecked(bool checked); - - void OnShaderBasedChecked(bool checked); - - void OnShaderGPUChecked(bool checked); - void OnShaderGPUReserveChecked(bool checked); - void OnShaderGPUDescIndexingChecked(bool checked); - void OnShaderGPUOOBChecked(bool checked); - void OnShaderGPURobustOOBChecked(bool checked); - void OnShaderGPUIndirectChecked(bool checked); - void OnShaderDispatchIndirectChecked(bool checked); - void OnShaderGPUVMALinearOutput(bool checked); - - void OnShaderPrintfChecked(bool checked); - void OnShaderPrintfStdoutChecked(bool checked); - void OnShaderPrintfVerboseChecked(bool checked); - - void OnSyncChecked(bool checked); - void OnSyncQueueSubmitChecked(bool checked); - - void OnBestChecked(bool checked); - void OnBestArmChecked(bool checked); - void OnBestAmdChecked(bool checked); - void OnBestImgChecked(bool checked); - void OnBestNvidiaChecked(bool checked); - - void OnSettingChanged(); - - Q_SIGNALS: - void itemChanged(); - - private: - WidgetSettingValidation(const WidgetSettingValidation &) = delete; - WidgetSettingValidation &operator=(const WidgetSettingValidation &) = delete; - - enum Overhead { - OVERHEAD_CORE = 0, - OVERHEAD_SHADER, - OVERHEAD_SYNC, - OVERHEAD_BEST, - - OVERHEAD_FIRST = OVERHEAD_CORE, - OVERHEAD_LAST = OVERHEAD_BEST, - }; - - enum { OVERHEAD_COUNT = OVERHEAD_LAST - OVERHEAD_FIRST + 1 }; - - bool CheckOverhead(Overhead candidate) const; - - void UpdateFlag(const char *key, const char *flag, bool append); - bool HasDataBool(const char *key) const; - bool HasDataFlag(const char *key, const char *flag) const; - const SettingEnumValue *GetMetaFlag(const char *key, const char *flag) const; - - const SettingMetaSet &meta_set; - SettingDataSet &data_set; -}; diff --git a/vkconfig/vkconfig.pro b/vkconfig/vkconfig.pro deleted file mode 100644 index d116c1d1f8..0000000000 --- a/vkconfig/vkconfig.pro +++ /dev/null @@ -1,203 +0,0 @@ -QT += core gui - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets network - -CONFIG += c++11 -CONFIG += sdk_no_version_check - -INCLUDEPATH += ../external/Vulkan-Headers/include -INCLUDEPATH += ../Vulkan-Headers/include - -# Ignore JSON validation -DEFINES += JSON_VALIDATION_OFF - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -DEFINES += WIN32_LEAN_AND_MEAN - -DEFINES += NOMINMAX - -Release: DEFINES += QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT - -linux: QMAKE_CXXFLAGS += -Wunused-variable - -SOURCES += \ - ../vkconfig_core/alert.cpp \ - ../vkconfig_core/application.cpp \ - ../vkconfig_core/application_singleton.cpp \ - ../vkconfig_core/command_line.cpp \ - ../vkconfig_core/configuration.cpp \ - ../vkconfig_core/configuration_manager.cpp \ - ../vkconfig_core/doc.cpp \ - ../vkconfig_core/date.cpp \ - ../vkconfig_core/environment.cpp \ - ../vkconfig_core/header.cpp \ - ../vkconfig_core/help.cpp \ - ../vkconfig_core/json.cpp \ - ../vkconfig_core/json_validator.cpp \ - ../vkconfig_core/layer.cpp \ - ../vkconfig_core/layer_manager.cpp \ - ../vkconfig_core/layer_preset.cpp \ - ../vkconfig_core/layer_state.cpp \ - ../vkconfig_core/layer_type.cpp \ - ../vkconfig_core/override.cpp \ - ../vkconfig_core/parameter.cpp \ - ../vkconfig_core/path.cpp \ - ../vkconfig_core/path_manager.cpp \ - ../vkconfig_core/platform.cpp \ - ../vkconfig_core/registry.cpp \ - ../vkconfig_core/setting.cpp \ - ../vkconfig_core/setting_bool.cpp \ - ../vkconfig_core/setting_filesystem.cpp \ - ../vkconfig_core/setting_flags.cpp \ - ../vkconfig_core/setting_float.cpp \ - ../vkconfig_core/setting_frames.cpp \ - ../vkconfig_core/setting_group.cpp \ - ../vkconfig_core/setting_int.cpp \ - ../vkconfig_core/setting_list.cpp \ - ../vkconfig_core/setting_string.cpp \ - ../vkconfig_core/util.cpp \ - ../vkconfig_core/version.cpp \ - vulkan_util.cpp \ - widget_preset.cpp \ - widget_setting.cpp \ - widget_setting_bool.cpp \ - widget_setting_enum.cpp \ - widget_setting_filesystem.cpp \ - widget_setting_flags.cpp \ - widget_setting_float.cpp \ - widget_setting_int.cpp \ - widget_setting_frames.cpp \ - widget_setting_string.cpp \ - widget_setting_list_element.cpp \ - widget_setting_list.cpp \ - widget_tree_friendly_combobox.cpp \ - dialog_about.cpp \ - dialog_applications.cpp \ - dialog_layers.cpp \ - dialog_vulkan_analysis.cpp \ - dialog_vulkan_info.cpp \ - main.cpp \ - main_gui.cpp \ - main_signal.cpp \ - main_reset.cpp \ - main_layers.cpp \ - main_doc.cpp \ - mainwindow.cpp \ - settings_tree.cpp \ - settings_validation_areas.cpp \ - configurator.cpp - -HEADERS += \ - ../vkconfig_core/alert.h \ - ../vkconfig_core/application.h \ - ../vkconfig_core/application_singleton.h \ - ../vkconfig_core/command_line.h \ - ../vkconfig_core/configuration.h \ - ../vkconfig_core/configuration_manager.h \ - ../vkconfig_core/doc.h \ - ../vkconfig_core/date.h \ - ../vkconfig_core/environment.h \ - ../vkconfig_core/header.h \ - ../vkconfig_core/help.h \ - ../vkconfig_core/json.h \ - ../vkconfig_core/json_validator.h \ - ../vkconfig_core/layer.h \ - ../vkconfig_core/layer_manager.h \ - ../vkconfig_core/layer_preset.h \ - ../vkconfig_core/layer_state.h \ - ../vkconfig_core/layer_type.h \ - ../vkconfig_core/override.h \ - ../vkconfig_core/parameter.h \ - ../vkconfig_core/path.h \ - ../vkconfig_core/path_manager.h \ - ../vkconfig_core/platform.h \ - ../vkconfig_core/registry.h \ - ../vkconfig_core/setting.h \ - ../vkconfig_core/setting_bool.h \ - ../vkconfig_core/setting_filesystem.h \ - ../vkconfig_core/setting_flags.h \ - ../vkconfig_core/setting_float.h \ - ../vkconfig_core/setting_frames.h \ - ../vkconfig_core/setting_group.h \ - ../vkconfig_core/setting_int.h \ - ../vkconfig_core/setting_list.h \ - ../vkconfig_core/setting_string.h \ - ../vkconfig_core/util.h \ - ../vkconfig_core/version.h \ - vulkan_util.h \ - widget_preset.h \ - widget_setting.h \ - widget_setting_bool.h \ - widget_setting_enum.h \ - widget_setting_filesystem.h \ - widget_setting_flags.h \ - widget_setting_float.h \ - widget_setting_int.h \ - widget_setting_frames.h \ - widget_setting_string.h \ - widget_setting_list_element.h \ - widget_setting_list.h \ - widget_tree_friendly_combobox.h \ - dialog_about.h \ - dialog_applications.h \ - dialog_layers.h \ - dialog_vulkan_analysis.h \ - dialog_vulkan_info.h \ - main_gui.h \ - main_signal.h \ - main_reset.h \ - main_layers.h \ - main_doc.h \ - mainwindow.h \ - settings_validation_areas.h \ - settings_tree.h \ - configurator.h - -FORMS += \ - dialog_about.ui \ - dialog_applications.ui \ - dialog_layers.ui \ - dialog_vulkan_analysis.ui \ - dialog_vulkan_info.ui \ - mainwindow.ui - -TRANSLATIONS += \ - vkconfig_en_US.ts - - -win32: { - LIBS += Advapi32.lib - LIBS += Cfgmgr32.lib - LIBS += User32.lib - RC_ICONS = resourcefiles/vulkan.ico -} - -macx: { -#CONFIG += file_copies -#COPIES += shellScript -#shellScript.files = $$files(macOS/vkconfig.sh) -#shellScript.path = $$OUT_PWD/VkConfig.app/Contents/MacOS - -QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.10 - -QMAKE_INFO_PLIST = macOS/Info.plist -RC_FILE = macOS/Resources/VulkanIcon.icns -} - -# Default rules for deployment. -qnx: target.path = /tmp/$${TARGET}/bin -else: unix:!android: target.path = /opt/$${TARGET}/bin -!isEmpty(target.path): INSTALLS += target - -RESOURCES += \ - resources.qrc diff --git a/vkconfig/widget_setting.cpp b/vkconfig/widget_setting.cpp deleted file mode 100644 index 4036caa5f1..0000000000 --- a/vkconfig/widget_setting.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "widget_setting.h" - -WidgetSettingBase::WidgetSettingBase(QTreeWidget* tree, QTreeWidgetItem* item) : tree(tree), item(item) { - assert(tree != nullptr); - assert(item != nullptr); -} - -void WidgetSettingBase::DisplayOverride(QWidget* widget, const SettingMeta& meta) const { - QCursor cursor = widget->cursor(); - cursor.setShape(Qt::WhatsThisCursor); - widget->setCursor(cursor); - - QPalette palette; - palette.setColor(QPalette::Active, QPalette::WindowText, QColor(255, 0, 0)); - palette.setColor(QPalette::Active, QPalette::Text, QColor(255, 0, 0)); - palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor(255, 0, 0)); - palette.setColor(QPalette::Inactive, QPalette::Text, QColor(255, 0, 0)); - palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(192, 128, 128)); - palette.setColor(QPalette::Disabled, QPalette::Text, QColor(192, 128, 128)); - - widget->setPalette(palette); - - const std::string tip = - format("Overridden by '%s' environment variable set to: '%s'", meta.env.c_str(), GetSettingOverride(meta).c_str()); - - widget->setToolTip(tip.c_str()); -} - -int HorizontalAdvance(const QFontMetrics& fm, const QString& string) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) - return fm.horizontalAdvance(string); -#else - return fm.width(string); -#endif -} - -std::string GetLabel(const SettingMeta& meta) { - if (meta.status == STATUS_STABLE) { - return meta.label; - } else { - return meta.label + " (" + GetToken(meta.status) + ")"; - } -} diff --git a/vkconfig/widget_setting_float.cpp b/vkconfig/widget_setting_float.cpp deleted file mode 100644 index 2cab7e00c1..0000000000 --- a/vkconfig/widget_setting_float.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "widget_setting_float.h" - -#include -#include -#include -#include - -#include - -static const int MIN_FIELD_WIDTH = 80; - -WidgetSettingFloat::WidgetSettingFloat(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFloat& meta, - SettingDataSet& data_set) - : WidgetSettingBase(tree, item), - meta(meta), - data_set(data_set), - field(new QLineEdit(this)), - timer_error(new QTimer(this)), - timer_valid(new QTimer(this)) { - const std::string unit = meta.unit.empty() ? "" : format(" (%s)", meta.unit.c_str()); - const std::string status = meta.status == STATUS_STABLE ? "" : std::string(" (") + GetToken(this->meta.status) + ")"; - - this->field->setFont(tree->font()); - this->field->setToolTip(format("[%f, %f]", meta.min_value, meta.max_value).c_str()); - this->field->setAlignment(Qt::AlignRight); - this->field->show(); - this->default_palette = this->field->palette(); - - this->connect(this->field, SIGNAL(textEdited(const QString&)), this, SLOT(OnTextEdited(const QString&))); - this->connect(this->timer_error, &QTimer::timeout, this, &WidgetSettingFloat::OnErrorValue); - this->connect(this->timer_valid, &QTimer::timeout, this, &WidgetSettingFloat::OnValidValue); - - this->item->setText(0, (this->meta.label + unit + status).c_str()); - this->item->setFont(0, this->tree->font()); - this->item->setToolTip(0, meta.description.c_str()); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -WidgetSettingFloat::~WidgetSettingFloat() { - this->timer_error->stop(); - this->timer_valid->stop(); -} - -void WidgetSettingFloat::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - const std::string float_format = meta.GetFloatFormat(); - - this->field->blockSignals(true); - this->field->setText(format(float_format.c_str(), this->data().value).c_str()); - this->field->blockSignals(false); - } -} - -void WidgetSettingFloat::resizeEvent(QResizeEvent* event) { - this->resize = event->size(); - this->Resize(); -} - -void WidgetSettingFloat::OnErrorValue() { - QPalette palette; - palette.setColor(QPalette::Base, QColor(255, 192, 192)); - this->field->setPalette(palette); - - QSettings settings; - if (settings.value("VKCONFIG_WIDGET_SETTING_FLOAT").toBool() == false) { - const std::string float_format = this->meta.GetFloatFormat(); - const std::string info = format("Do you want to reset to the setting default value? '%s'", float_format.c_str()); - const std::string range = this->meta.HasRange() - ? format("Enter a number in the range [%s, %s].", float_format.c_str(), float_format.c_str()) - : std::string("Enter a floating point number."); - - std::string text; - switch (this->ProcessInputValue()) { - default: - case SETTING_INPUT_NO_ERROR: { - assert(0); - break; - } - case SETTING_INPUT_ERROR_EMPTY: { - text = format(("'%s' value is empty. " + range).c_str(), this->meta.label.c_str(), this->meta.min_value, - this->meta.max_value); - break; - } - case SETTING_INPUT_ERROR_SYNTAX: { - text = format(("'%s' value has invalid characters. " + range).c_str(), this->meta.label.c_str(), - this->meta.min_value, this->meta.max_value); - break; - } - case SETTING_INPUT_ERROR_SEMENTICS: { - text = format(("'%s' value is out of range. " + range).c_str(), this->meta.label.c_str(), this->meta.min_value, - this->meta.max_value); - break; - } - } - - QMessageBox alert; - alert.setWindowTitle(format("Invalid '%s' setting value", meta.label.c_str()).c_str()); - alert.setText(text.c_str()); - alert.setInformativeText(format(info.c_str(), this->meta.default_value).c_str()); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setIcon(QMessageBox::Critical); - alert.setCheckBox(new QCheckBox("Do not show again.")); - if (alert.exec() == QMessageBox::Yes) { - const std::string field_value = format(this->meta.GetFloatFormat().c_str(), this->meta.default_value); - - this->data().value = this->meta.default_value; - this->field->setText(field_value.c_str()); - this->field->setPalette(default_palette); - this->Resize(); - } - if (alert.checkBox()->isChecked()) { - settings.setValue("VKCONFIG_WIDGET_SETTING_FLOAT", true); - } - } - - this->timer_error->stop(); -} - -void WidgetSettingFloat::OnValidValue() { - emit itemChanged(); - - this->timer_valid->stop(); -} - -void WidgetSettingFloat::Resize() { - const QFontMetrics fm = this->field->fontMetrics(); - const int width = std::max(HorizontalAdvance(fm, this->field->text() + "00"), MIN_FIELD_WIDTH); - - const QRect button_rect = QRect(this->resize.width() - width, 0, width, this->resize.height()); - this->field->setGeometry(button_rect); -} - -SettingInputError WidgetSettingFloat::ProcessInputValue() { return this->data().ProcessInput(this->value_buffer); } - -void WidgetSettingFloat::OnTextEdited(const QString& new_value) { - this->timer_error->stop(); - this->timer_valid->stop(); - - this->value_buffer = new_value.toStdString(); - this->Resize(); - - if (this->ProcessInputValue() == SETTING_INPUT_NO_ERROR) { - this->field->setPalette(default_palette); - this->timer_valid->start(500); - } else { - this->timer_error->start(2000); - } - - emit itemChanged(); -} - -SettingDataFloat& WidgetSettingFloat::data() { - SettingDataFloat* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig/widget_setting_frames.cpp b/vkconfig/widget_setting_frames.cpp deleted file mode 100644 index b9276dd73d..0000000000 --- a/vkconfig/widget_setting_frames.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "widget_setting_frames.h" -#include "widget_setting.h" - -#include "../vkconfig_core/util.h" - -#include -#include -#include -#include - -#include - -static const int MIN_FIELD_WIDTH = 80; - -WidgetSettingFrames::WidgetSettingFrames(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFrames& meta, - SettingDataSet& data_set) - : WidgetSettingBase(tree, item), - meta(meta), - data_set(data_set), - field(new QLineEdit(this)), - timer_error(new QTimer(this)), - timer_valid(new QTimer(this)) { - this->field->setFont(tree->font()); - this->field->setToolTip("Use list of comma separated integer ranges. Example: '0-2,16'."); - this->field->setAlignment(Qt::AlignRight); - this->field->show(); - this->default_palette = this->field->palette(); - - this->connect(this->field, SIGNAL(textEdited(const QString&)), this, SLOT(OnTextEdited(const QString&))); - this->connect(this->timer_error, &QTimer::timeout, this, &WidgetSettingFrames::OnErrorValue); - this->connect(this->timer_valid, &QTimer::timeout, this, &WidgetSettingFrames::OnValidValue); - - this->item->setText(0, GetLabel(this->meta).c_str()); - this->item->setFont(0, this->tree->font()); - this->item->setToolTip(0, meta.description.c_str()); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -WidgetSettingFrames::~WidgetSettingFrames() { - this->timer_error->stop(); - this->timer_valid->stop(); -} - -void WidgetSettingFrames::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->blockSignals(true); - this->field->setText(this->data().GetValue()); - this->field->blockSignals(false); - } -} - -void WidgetSettingFrames::resizeEvent(QResizeEvent* event) { - this->resize = event->size(); - this->Resize(); -} - -void WidgetSettingFrames::OnErrorValue() { - QPalette palette; - palette.setColor(QPalette::Base, QColor(255, 192, 192)); - this->field->setPalette(palette); - - QSettings settings; - if (settings.value("VKCONFIG_WIDGET_SETTING_FRAMES").toBool() == false) { - const std::string text = - format("The setting input '%s' is invalid. Use list of comma separated integer ranges. Example: '0-2,16'.", - this->data().GetValue()); - const std::string info = - format("Do you want to reset to the setting default value? '%s'", this->meta.default_value.c_str()); - - QMessageBox alert; - alert.setWindowTitle(format("Invalid '%s' setting value", meta.label.c_str()).c_str()); - alert.setText(text.c_str()); - alert.setInformativeText(info.c_str()); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setIcon(QMessageBox::Critical); - alert.setCheckBox(new QCheckBox("Do not show again.")); - if (alert.exec() == QMessageBox::Yes) { - this->data().SetValue(this->meta.default_value.c_str()); - this->field->setText(this->meta.default_value.c_str()); - this->field->setPalette(default_palette); - this->Resize(); - } - if (alert.checkBox()->isChecked()) { - settings.setValue("VKCONFIG_WIDGET_SETTING_FRAMES", true); - } - } - - this->timer_error->stop(); -} - -void WidgetSettingFrames::OnValidValue() { - emit itemChanged(); - - this->timer_valid->stop(); -} - -void WidgetSettingFrames::Resize() { - const QFontMetrics fm = this->field->fontMetrics(); - const int width = std::max(HorizontalAdvance(fm, this->field->text() + "00"), MIN_FIELD_WIDTH); - - const QRect button_rect = QRect(this->resize.width() - width, 0, width, this->resize.height()); - this->field->setGeometry(button_rect); -} - -SettingInputError WidgetSettingFrames::ProcessInputValue() { return this->data().ProcessInput(this->value_buffer); } - -void WidgetSettingFrames::OnTextEdited(const QString& new_value) { - this->timer_error->stop(); - this->timer_valid->stop(); - - this->value_buffer = new_value.toStdString(); - this->Resize(); - - if (this->ProcessInputValue() == SETTING_INPUT_NO_ERROR) { - this->field->setPalette(default_palette); - this->timer_valid->start(500); - } else { - this->timer_error->start(3000); - } - - emit itemChanged(); -} - -SettingDataFrames& WidgetSettingFrames::data() { - SettingDataFrames* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig/widget_setting_int.cpp b/vkconfig/widget_setting_int.cpp deleted file mode 100644 index 63603d1c02..0000000000 --- a/vkconfig/widget_setting_int.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "widget_setting_int.h" - -#include -#include -#include -#include - -#include - -static const int MIN_FIELD_WIDTH = 80; - -WidgetSettingInt::WidgetSettingInt(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaInt& meta, SettingDataSet& data_set) - : WidgetSettingBase(tree, item), - meta(meta), - data_set(data_set), - field(new QLineEdit(this)), - timer_error(new QTimer(this)), - timer_valid(new QTimer(this)) { - const std::string unit = meta.unit.empty() ? "" : format(" (%s)", meta.unit.c_str()); - const std::string status = meta.status == STATUS_STABLE ? "" : std::string(" (") + GetToken(this->meta.status) + ")"; - - this->field->setFont(tree->font()); - this->field->setToolTip(format("[%d, %d]", meta.min_value, meta.max_value).c_str()); - this->field->setAlignment(Qt::AlignRight); - this->field->show(); - this->default_palette = this->field->palette(); - - this->connect(this->field, SIGNAL(textEdited(const QString&)), this, SLOT(OnTextEdited(const QString&))); - this->connect(this->timer_error, &QTimer::timeout, this, &WidgetSettingInt::OnErrorValue); - this->connect(this->timer_valid, &QTimer::timeout, this, &WidgetSettingInt::OnValidValue); - - this->item->setText(0, (meta.label + unit + status).c_str()); - this->item->setFont(0, this->tree->font()); - this->item->setToolTip(0, meta.description.c_str()); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -WidgetSettingInt::~WidgetSettingInt() { - this->timer_error->stop(); - this->timer_valid->stop(); -} - -void WidgetSettingInt::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->blockSignals(true); - this->field->setText(format("%d", this->data().value).c_str()); - this->field->blockSignals(false); - } -} - -void WidgetSettingInt::resizeEvent(QResizeEvent* event) { - this->resize = event->size(); - this->Resize(); -} - -void WidgetSettingInt::OnErrorValue() { - QPalette palette; - palette.setColor(QPalette::Base, QColor(255, 192, 192)); - this->field->setPalette(palette); - - QSettings settings; - if (settings.value("VKCONFIG_WIDGET_SETTING_INT").toBool() == false) { - const std::string info = format("Do you want to reset to the setting default value? '%d'", this->meta.default_value); - const std::string range = format("Enter a number in the range [%d, %d].", this->meta.min_value, this->meta.max_value); - - std::string text; - switch (this->ProcessInputValue()) { - default: - case SETTING_INPUT_NO_ERROR: { - assert(0); - break; - } - case SETTING_INPUT_ERROR_EMPTY: { - text = format("'%s' value is empty. %s", meta.label.c_str(), range.c_str()); - break; - } - case SETTING_INPUT_ERROR_SYNTAX: { - text = format("'%s' value has invalid characters. %s", meta.label.c_str(), range.c_str()); - break; - } - case SETTING_INPUT_ERROR_SEMENTICS: { - text = format("'%s' value is out of range. %s", meta.label.c_str(), range.c_str()); - break; - } - } - - QMessageBox alert; - alert.setWindowTitle(format("Invalid '%s' setting value", meta.label.c_str()).c_str()); - alert.setText(text.c_str()); - alert.setInformativeText(info.c_str()); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setIcon(QMessageBox::Critical); - alert.setCheckBox(new QCheckBox("Do not show again.")); - if (alert.exec() == QMessageBox::Yes) { - this->data().value = this->meta.default_value; - this->field->setText(format("%d", this->meta.default_value).c_str()); - this->field->setPalette(default_palette); - this->Resize(); - } - if (alert.checkBox()->isChecked()) { - settings.setValue("VKCONFIG_WIDGET_SETTING_INT", true); - } - } - - this->timer_error->stop(); -} - -void WidgetSettingInt::OnValidValue() { - emit itemChanged(); - - this->timer_valid->stop(); -} - -void WidgetSettingInt::Resize() { - const QFontMetrics fm = this->field->fontMetrics(); - const int width = std::max(HorizontalAdvance(fm, this->field->text() + "00"), MIN_FIELD_WIDTH); - - const QRect button_rect = QRect(this->resize.width() - width, 0, width, this->resize.height()); - this->field->setGeometry(button_rect); -} - -SettingInputError WidgetSettingInt::ProcessInputValue() { return this->data().ProcessInput(this->value_buffer); } - -void WidgetSettingInt::OnTextEdited(const QString& new_value) { - this->timer_error->stop(); - this->timer_valid->stop(); - - this->value_buffer = new_value.toStdString(); - this->Resize(); - - if (this->ProcessInputValue() == SETTING_INPUT_NO_ERROR) { - this->field->setPalette(default_palette); - this->timer_valid->start(500); - } else { - this->timer_error->start(2000); - } - - emit itemChanged(); -} - -SettingDataInt& WidgetSettingInt::data() { - SettingDataInt* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig/widget_tree_friendly_combobox.cpp b/vkconfig/widget_tree_friendly_combobox.cpp deleted file mode 100644 index 6e9242158b..0000000000 --- a/vkconfig/widget_tree_friendly_combobox.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_tree_friendly_combobox.h" - -#include - -WidgetTreeFriendlyComboBox::WidgetTreeFriendlyComboBox(QTreeWidgetItem *item) : QComboBox(), item(item) { - assert(item); - - setFocusPolicy(Qt::StrongFocus); - - connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(indexChanged(int))); -} - -void WidgetTreeFriendlyComboBox::indexChanged(int index) { emit selectionMade(item, index); } diff --git a/vkconfig/widget_tree_friendly_combobox.h b/vkconfig/widget_tree_friendly_combobox.h deleted file mode 100644 index 2afd18c57d..0000000000 --- a/vkconfig/widget_tree_friendly_combobox.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include -#include -#include - -class WidgetTreeFriendlyComboBox : public QComboBox { - Q_OBJECT - public: - WidgetTreeFriendlyComboBox(QTreeWidgetItem *item); - - void wheelEvent(QWheelEvent *e) { - if (hasFocus()) QComboBox::wheelEvent(e); - } - - public Q_SLOTS: - void indexChanged(int nIndex); - - Q_SIGNALS: - void selectionMade(QTreeWidgetItem *tree_item, int index); - - private: - WidgetTreeFriendlyComboBox(const WidgetTreeFriendlyComboBox &) = delete; - WidgetTreeFriendlyComboBox &operator=(const WidgetTreeFriendlyComboBox &) = delete; - - QTreeWidgetItem *item; -}; diff --git a/vkconfig3/CHANGELOG.md b/vkconfig3/CHANGELOG.md deleted file mode 100644 index ba55cfc8f5..0000000000 --- a/vkconfig3/CHANGELOG.md +++ /dev/null @@ -1,290 +0,0 @@ - -

LunarG

-

Copyright � 2015-2022 LunarG, Inc.

- -[![Creative Commons][3]][4] - -[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License" -[4]: https://creativecommons.org/licenses/by-nd/4.0/ - -

- -# Release notes - -## [Vulkan Configurator 3.0.0](https://github.com/LunarG/VulkanTools/tree/main) - ??? 202? - -### Features: -- Redesign main window UI around tabs -- Add check box to disable all Vulkan Layers - -## [Vulkan Configurator 2.5.6](https://github.com/LunarG/VulkanTools/tree/main) - March 2024 - -### Fixes: -- Fix confusing synchronization built-in configuration - -## [Vulkan Configurator 2.5.5](https://github.com/LunarG/VulkanTools/tree/main) - January 2024 - -### Improvements: -- Add `LOAD_FOLDER` setting type - -### Fixes: -- Remove default settings values from built-in layer configurations -- Fix doc generator using default environment variable names - -## [Vulkan Configurator 2.5.4](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.250.0) - May 2023 - -### Improvements: -- Display `deviceUUID` and `driverUUID` in the "Development Status" when available for each physical device - -## [Vulkan Configurator 2.5.3](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.243.0) - March 2023 - -### Improvements: -- Enabling fully generic layer settings for the validation layer settings - -## [Vulkan Configurator 2.5.2](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.236.0) - December 2022 - -### Improvements: -- Add `warn_on_robust_oob` validation layer setting handling - -## [Vulkan Configurator 2.5.1](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.231.0) - October 2022 - -### Features: -- Add ENUM setting type children settings #1746 - -### Improvements: -- Allow disabling the validation layer settings built-in UI #1746 - -### Fixes: -- Fix override layer version when some layers are excluded or missing #1743 - -## [Vulkan Configurator 2.5.0](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.224.0) - August 2022 - -### Features: -- Add per layers-configuration user-defined layers paths #1711 - -### Improvements: -- Add reordering of configurations when renaming a configuration -- Improve handling of missing layers - -## [Vulkan Configurator 2.4.6](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.216.0) - June 2022 - -### Features: -- Add `VK_KHR_portability_enumeration` extension support - -### Improvements: -- Allow using multiple layers built with different Vulkan header version when Loader 212 or newer is installed on the system - -## [Vulkan Configurator 2.4.5](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.211.0) - April 2022 - -### Features: -- Add `VK_ADD_LAYER_PATH` Vulkan Loader variable handling -- Remove built-in support of `VK_LAYER_LUNARG_device_simulation` layer #1628 - - Use `VK_LAYER_KHRONOS_profiles` layer instead - -### Improvements: -- Improve the Portability built-in configuration to check only what's necessary, reducing validation overhead -- Refinement of the layers window UI design - -## [Vulkan Configurator 2.4.4](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.204.1) - March 2022 - -### Features: -- Add markdown documentation export -- Add `vk_layer_settings.txt` documentation export -- Add command line support of HTML, markdown and `vk_layer_settings.txt` documentation exports - -### Improvements: -- Add button to create a new layers configuration - -### Fixes: -- Fix layer presets that could be modified by accident #1653 -- Fix loading of profiles file from the UI #1653 - -## [Vulkan Configurator 2.4.3](https://github.com/LunarG/VulkanTools/tree/sdk-1.3.204.0) - February 2022 - -### Improvements: -- Upgrade the built-in "Portability" to use the Profiles layer -- Display the development status of a setting next to the setting label in the UI -- Display a warning when using multiple layers built with different Vulkan Header version - - It's a requirement by the Vulkan Loader - -### Fixes: -- Fix ANY dependence when using FLAGS setting type - -## [Vulkan Configurator 2.4.2](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.196.0) - November 2021 - -### Improvements: -- Discard applied layers configuration to ensure the layers never crash Vulkan Configurator - -### Fixes: -- Fix 'Edit Layers' button being enabled when there is no active configuration #1616 - -## [Vulkan Configurator 2.4.1](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.189.0) - September 2021 - -### Fixes: -- Fix user-defined layer settings not loaded, for older Vulkan API than 1.2.176 -- Fix settings written in 'vk_layer_settings.txt' even when the dependence is not met #1582 - -## [Vulkan Configurator 2.4.0](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.182.0) - July 2021 - -### Features: -- Add support for `VK_LAYER_SETTINGS_PATH` override for 'vk_layer_settings.txt' path -- Add 'vk_layer_settings.txt' path in the 'Vulkan Development Status' -- Add ${VK_LOCAL} and ${VK_APPDATA} built-in variables -- Add 'expanded' property to layer manifest settings and flags #1497 -- Add settings environment variables checking #1498 -- Add settings tree context menu #1501 -- Add layer generated user documentation #1510 -- Add build date in the title bar - -### Improvements: -- Add link to [Vulkan Guide layers](https://github.com/KhronosGroup/Vulkan-Guide/blob/main/chapters/development_tools.md#vulkan-layers) list within the help menu -- Update built-in VUIDs to the list included in SDK 1.2.176 #1511 -- Refactor the layer window to expose more layer documentation #1519 -- Add shader caching setting to validation built-in UI #1552 -- Add indirect parameter setting to validation built-in UI #1522 -- Improve user-defined paths dialog and workflow #1523 -- Improve UI labels #1551 - -### Fixes: -- Fix message box with no title displayed on macOS #1547 -- Hide excluded layers in configuration that are missing, these may not be supported on the platform #1551 -- Fix crash when renaming a configuration from the layers window #1551 -- Fix validation layer bool setting written in 'vk_layer-setting.txt' #1551 -- Fix upgrade of 'vkcube' path when the path is no longer valid - -## [Vulkan Configurator 2.3.0](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.176.0) - May 2021 - -### Features: -- Add Vulkan loader debug message to application launcher #1372 -- Redesigned of the full layer settings UI #1420 - -### Improvements: -- Add display of layer execution order in the setting tree #1390 -- Add layer settings UI inputs checking -- Add API dump presets #1414 -- Add validation layer VUIDs loading from Vulkan Header to keep it up to date #1434 -- Improve 'High Validation Layer Overhead' warning UI - -### Fixes: -- Hide 'Callback' from validation layer 'Debug Action' debug action that is NOOP -- Fix crash when SDK path is included in 'override_paths' of 'VkLayer_override.json' -- Fix default value of validation layer 'Check Out of Bounds #1435 -- Fix duplicate configurations #1445 -- Fix layer reordering crash #1449 -- Fix Vulkan application crash when updating the Vulkan loader -- Fix User-Defined layer path window 'Ok' button being disabled incorrectly -- Fix blank setting tree after using the user-defined layer path window #1377 -- Fix 'Reset To Default' than wasn't bringing back notification pop-ups -- Fix creating a new 'Configuration' can be cancelled - -## [Vulkan Configurator 2.2.0](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.170.0) - March 2021 - -### Features: -- Add *Synchronization* default configuration #1304 -- Add *Portability* default configuration on *macOS* #1307 -- Add per-configuration reset in layers configuration context menu -- Add per-configuration reset in layers window -- Expose `modify_extension_list` and `modify_memory_flags` settings from devsim - -### Improvements: -- Add display of `VK_LAYER_PATH` content in 'Vulkan Development Status' -- Rename 'Custom Path' by 'User-Defined Path' -- Add extension filters to load and save file layer settings #1317 -- Improve in application documentation of settings #1332 -- Display the layer status in the 'Vulkan Development Status' #1332 -- Refresh 'Vulkan Development Status' when the configuration changed #1366 -- Streamline 'configuration tree' UI usage #1370 -- Add 'Reload Default Configuration' to retrieve missing default configurations #1370 -- Add 'reset' command line argument to reset the platform layers configurations -- Add possible recovery by resetting to default when a crash happened during last run - -### Fixes: -- Fix export and import path being truncated when the path as '.' character -- Fix crash when loading a JSON file as if it's a JSON layer file but it's not #1330 -- Fix validation layer 'printf buffer size' setting exposed as a 'bool' instead of a 'int' #1338 -- Fix crash when using older `VK_LAYER_KHRONOS_validation` versions -- Fix *Vulkan Info* and *Vulkan Installation Analysis* dialog no longer running with overridden layers -- Fix preset changed causing the setting tree to be rebuild #1300 - -## [Vulkan Configurator 2.1.0](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.162.1) - January 2021 - -### Features: -- Refactor built-in configurations #1247 -- Add layer settings presets #1271 -- Add *Portability* default configuration on Linux and Windows #1279 - -### Improvements: -- In case of crash or user interruption, remove the layers override #1278 -- Improve layers support since version 1.1.130 -- Improve layer configurations compatibilities between versions -- Add more tool tips #1296 -- Display the 'Vulkan Development Status' each time the layers paths are changed - -### Fixes: -- Expose missing `VK_LAYER_LUNARG_gfxreconstruct` 'Log Detailed' setting - -## [Vulkan Configurator 2.0.3](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.162.0) - December 2020 - -### Features: -- Add command line arguments to manage layers override #1213 - -### Improvements: -- Test with *VS2015*, *VS2017* and *VS2019* -- Test with *Qt 5.9* and *Qt 5.15* including *QMake* build -- Test manually using a [use cases based template](https://docs.google.com/document/d/1z0WqfMp2IBko1fvDICkjDE_3JKnf8SrU5APQTqKRR-U/edit) - -### Fixes: -- Fix manual layers ordering #1214 -- Fix layers override update when changing layers management options #1225 -- Fix reset button in layers window #1227 -- Fix warning about old loader when trying to use application list #1230 -- Fix initialization of added applications on macOS #1249 - -## [Vulkan Configurator 2.0.2](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.154.0) - October 2020 - -### Features: -- Add multiple debug actions simultaneously #1119 -- Add better representation of the layers execution order #1181 - -### Improvements: -- Streamline and clean up GUI -- Add layers configuration description #1105 -- Add selected path from dialog window cache #1107 -- Add unit test framework #1100 -- Add button to browse working directory #1099 -- Add version in the title bar and show state #1109 -- Add default settings state in the layer configuration settings #1076 -- Make *Validation - Standard*, the default configuration #1076 -- Update `vkcube` to use the version from the same *Vulkan SDK* than *Vulkan Configurator* #1112 -- Expose `duplicate_message_limit` setting from `VK_LAYER_KHRONOS_validation` #1176 - -### Fixes: -- Fix disabled configurations that can't be reenabled or removed -- Fix display of custom layer paths #1101 -- Fix inconsistent display of separators in paths #1107 -- Fix display of empty entries in the custom path dialog when opening Json files that are not layer json files #1103 -- Fix log file default location to `HOME` to ensure write access #1083 -- Fix log file not written to #1109 -- Fix `debug_output` setting displayed on Linux and macOS but not available #1086 -- Fix `numeric_bool` setting display #1166 - -## [Vulkan Configurator 2.0.1](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.148.1) - August 2020 (revision 1) - -### Fixes: -- Fix *Shader Printf* built-in configuration that was setup for *GPU-Assisted* validation instead -- Fix layer configurations selection on Linux -- Fix debug output setting not working - -## [Vulkan Configurator 2.0.0](https://github.com/LunarG/VulkanTools/tree/sdk-1.2.148.0) - August 2020 - -### Features: -- Design GUI -- Add built-in Vulkan layers configurations -- Add user-defined Vulkan layers configurations -- Add import and export of Vulkan layers configuration -- Add `VK_LAYER_KHRONOS_validation` settings presets -- Add message filtering using VUID and message IDs -- Add an option to make layers overriding persistent on exit -- Add an option to override only a selected list of applications -- Add an application launcher -- Add startup Vulkan status diff --git a/vkconfig3/CONTRIBUTING.md b/vkconfig3/CONTRIBUTING.md deleted file mode 100644 index 4fbc92b651..0000000000 --- a/vkconfig3/CONTRIBUTING.md +++ /dev/null @@ -1,98 +0,0 @@ -# Contributing to Vulkan Configurator - -## Contributions Welcome - -The easiest method for contributing to *Vulkan Configurator* is to examine the [issues list](https://github.com/LunarG/VulkanTools/issues) and the [roadmap](https://github.com/LunarG/VulkanTools/projects/2) -and look for areas that are of interest. - -Furthermore: -- If you have your own work in mind, please open an issue to describe it and assign it to yourself. -- If you choose to work on an issue that is assigned, simply coordinate with the current assignee. - --------------- -## Building Vulkan Configurator - -It requires *[Qt 5](https://www.qt.io/download)* to be install and *Qt* `bin` directory to be added to the `PATH` environment variable. *Vulkan Configurator* is built as part of the [VulkanTools](https://github.com/LunarG/VulkanTools/blob/main/BUILD.md) using *CMake* build system or alternatively with `vkconfig.pro` using Qt Creator. - --------------- -## How to run Vulkan Configurator Unit Tests - -When submitting a PR, the unit tests will ran automatically. - -However, it's trivial and more effective to run the unit tests locally with the following commands: - -On Windows, from the build directory: -``` -ctest -C Debug --output-on-failure --parallel 16 -ctest -C Release --output-on-failure --parallel 16 -``` - -On Linux and macOS, from the build directory: -``` -ctest --output-on-failure --parallel 16 -``` - -`--parallel` runs the unit tests on the especified number of threads. - -`--output-on-failure` outputs unit tests details only on failed tests. - --------------- -## Submitting Fixes - -* **Ensure that the bug was not already reported or fixed** by searching on GitHub under [Issues](https://github.com/LunarG/VulkanTools/issues) and [Pull Requests](https://github.com/LunarG/VulkanTools/pulls). -* Use the existing GitHub forking and pull request process. - This will involve [forking the repository](https://help.github.com/articles/fork-a-repo/), - creating a branch with your commits, and then [submitting a pull request](https://help.github.com/articles/using-pull-requests/). -* Please read and adhere to the style and process [guidelines ](#coding-conventions-and-formatting) enumerated below. -* Please base your fixes on the `main` branch. SDK branches are generally not updated except for critical fixes needed to repair an SDK release. -* The resulting Pull Request will be assigned to a repository maintainer. Once the Pull Request has been approved and is passing internal CI, a repository maintainer - will merge the PR. - -### Coding Conventions and Formatting -* Use the **[Google style guide](https://google.github.io/styleguide/cppguide.html)** for source code with the following exceptions: - * The column limit is 132 (as opposed to the default value 80). The clang-format tool will handle this. See below. - * The indent is 4 spaces instead of the default 2 spaces. Again, the clang-format tool will handle this. - * If you can justify a reason for violating a rule in the guidelines, then you are free to do so. Be prepared to defend your -decision during code review. This should be used responsibly. An example of a bad reason is "I don't like that rule." An example of -a good reason is "This violates the style guide, but it improves type safety." - -* Run **clang-format** on your changes to maintain consistent formatting - * There are `.clang-format files` present in the repository to define clang-format settings - which are found and used automatically by clang-format. - * A sample git workflow may look like: - -> # Make changes to the source. -> $ git add -u . -> $ git clang-format --style=file -> # Check to see if clang-format made any changes and if they are OK. -> $ git add -u . -> $ git commit - -* **Commit Messages** - * Limit the subject line to 50 characters -- this allows the information to display correctly in git/Github logs - * Begin subject line with a one-word component description followed by a colon (e.g. layer/tool name, tests, etc.) - * Separate subject from body with a blank line - * Wrap the body at 72 characters - * Capitalize the subject line - * Do not end the subject line with a period - * Use the body to explain what and why vs. how - * Use the imperative mode in the subject line. This just means to write it as a command (e.g. Fix the sprocket) - -Strive for commits that implement a single or related set of functionality, using as many commits as is necessary (more is better). -That said, please ensure that the repository compiles and passes tests without error for each commit in your pull request. Note -that to be accepted into the repository, the pull request must [pass all tests](#testing your changes) on all supported platforms --- the automatic Github Travis and AppVeyor continuous integration features will assist in enforcing this requirement. - --------------- -## Contributor License Agreement (CLA) - -You will be prompted with a one-time "click-through" CLA dialog as part of submitting your pull request -or other contribution to GitHub. - --------------- -## License and Copyrights - -All contributions made to the LunarG repositories need to have the Apache 2.0 license. -Please see an existing file in this repository for an example. - -You can include your individual copyright after any existing copyrights. diff --git a/vkconfig3/configurator.cpp b/vkconfig3/configurator.cpp deleted file mode 100644 index c1fee594e9..0000000000 --- a/vkconfig3/configurator.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Lenny Komow - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "configurator.h" -#include "vulkan_util.h" - -#include "../vkconfig_core/util.h" -#include "../vkconfig_core/path.h" -#include "../vkconfig_core/override.h" -#include "../vkconfig_core/alert.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -Configurator &Configurator::Get(const std::string &VULKAN_SDK) { - static Configurator configurator(VULKAN_SDK); - return configurator; -} - -Configurator::Configurator(const std::string &VULKAN_SDK) - : path(VULKAN_SDK, SUPPORTED_CONFIG_FILES), environment(path), layers(environment), configurations(environment) {} - -Configurator::~Configurator() { - configurations.SaveAllConfigurations(layers.selected_layers); - - SurrenderConfiguration(environment); -} - -bool Configurator::Init() { - this->UpdateDevices(); - - // Load simple app settings, the additional search paths, and the - // override app list. - this->layers.LoadAllInstalledLayers(); - - QSettings settings; - if (settings.value("crashed", QVariant(false)).toBool()) { - settings.setValue("crashed", false); - - if (Alert::ConfiguratorCrashed() == QMessageBox::No) { - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - } else { - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - - if (this->configurations.Empty()) { - this->configurations.ResetDefaultsConfigurations(layers.selected_layers); - } else { - this->configurations.FirstDefaultsConfigurations(layers.selected_layers); - } - - this->ActivateConfiguration(this->environment.GetSelectedConfiguration()); - - return true; -} - -void Configurator::ActivateConfiguration(const std::string &configuration_name) { - Configuration *configuration = nullptr; - if (!configuration_name.empty()) { - configuration = FindByKey(this->configurations.available_configurations, configuration_name.c_str()); - } - - if (configuration_name.empty()) { - this->environment.SetSelectedConfiguration(""); - this->configurations.Configure(this->layers.selected_layers); - } else if (configuration == nullptr) { - QMessageBox alert; - alert.QDialog::setWindowTitle("Vulkan layers configuration is missing..."); - const std::string text = format("%s couldn't find '%s' layers configuration.", VKCONFIG_NAME, configuration_name.c_str()); - alert.setText(text.c_str()); - alert.setInformativeText("Vulkan Configurator is switching to Layers Controlled by Vulkan Application mode"); - alert.setIcon(QMessageBox::Critical); - alert.exec(); - - this->environment.SetSelectedConfiguration(""); - this->environment.SetMode(LAYERS_MODE_BY_APPLICATIONS); - this->configurations.Configure(this->layers.selected_layers); - } else { - // If the layers paths are differents, we need to reload the layers and the configurations - const std::vector paths = this->environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_GUI); - if (configuration->user_defined_paths != paths) { - this->configurations.SaveAllConfigurations(this->layers.selected_layers); - this->environment.SetPerConfigUserDefinedLayersPaths(configuration->user_defined_paths); - this->layers.LoadAllInstalledLayers(); - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - - std::string missing_layer; - if (::HasMissingLayer(configuration->parameters, layers.selected_layers, missing_layer)) { - QMessageBox alert; - alert.QDialog::setWindowTitle("Vulkan layer missing..."); - alert.setText(format("%s couldn't find '%s' layer required by '%s' configuration:", VKCONFIG_NAME, - missing_layer.c_str(), configuration->key.c_str()) - .c_str()); - alert.setIcon(QMessageBox::Critical); - alert.exec(); - } else { - this->configurations.Configure(this->layers.selected_layers); - } - - this->environment.SetSelectedConfiguration(configuration_name.c_str()); - } -} - -void Configurator::UpdateDevices() { - QLibrary library(GetVulkanLibrary()); - - VkInstance instance = VK_NULL_HANDLE; - VkResult err = CreateInstance(library, instance, false); - - if (err != VK_SUCCESS) { - err = CreateInstance(library, instance, true); - if (err != VK_SUCCESS) { - return; - } - } - - PFN_vkEnumeratePhysicalDevices pfnEnumeratePhysicalDevices = - (PFN_vkEnumeratePhysicalDevices)library.resolve("vkEnumeratePhysicalDevices"); - PFN_vkDestroyInstance pfnDestroyInstance = (PFN_vkDestroyInstance)library.resolve("vkDestroyInstance"); - PFN_vkGetPhysicalDeviceProperties pfnGetPhysicalDeviceProperties = - (PFN_vkGetPhysicalDeviceProperties)library.resolve("vkGetPhysicalDeviceProperties"); - - if (pfnEnumeratePhysicalDevices == nullptr || pfnDestroyInstance == nullptr || pfnGetPhysicalDeviceProperties == nullptr) { - return; - } - - uint32_t gpu_count = 0; - err = pfnEnumeratePhysicalDevices(instance, &gpu_count, NULL); - assert(!err); - - std::vector devices; - if (gpu_count > 0) { - devices.resize(gpu_count); - - err = pfnEnumeratePhysicalDevices(instance, &gpu_count, &devices[0]); - assert(!err); - } - - this->device_names.clear(); - for (std::size_t i = 0, n = devices.size(); i < n; ++i) { - VkPhysicalDeviceProperties properties; - pfnGetPhysicalDeviceProperties(devices[i], &properties); - - this->device_names.push_back(properties.deviceName); - } - - pfnDestroyInstance(instance, NULL); -} - -bool Configurator::SupportLoaderSettings(Version *return_loader_version) const { - // Check loader version - const Version version = GetVulkanLoaderVersion(); - assert(version != Version::VERSION_NULL); - - if (return_loader_version) { - *return_loader_version = version; - } - - return version >= Version("1.3.261"); -} - -void Configurator::ResetToDefault(bool hard) { - if (hard) { - this->environment.Reset(Environment::CLEAR); - this->layers.LoadAllInstalledLayers(); - this->configurations.ResetDefaultsConfigurations(this->layers.selected_layers); - - this->ActivateConfiguration(this->environment.GetSelectedConfiguration()); - } else { - this->configurations.ReloadDefaultsConfigurations(this->layers.selected_layers); - } -} - -std::vector Configurator::GetDeviceNames() const { return device_names; } diff --git a/vkconfig3/configurator.h b/vkconfig3/configurator.h deleted file mode 100644 index 6cdc5a62d6..0000000000 --- a/vkconfig3/configurator.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/version.h" -#include "../vkconfig_core/layer.h" -#include "../vkconfig_core/layer_manager.h" -#include "../vkconfig_core/path_manager.h" -#include "../vkconfig_core/environment.h" -#include "../vkconfig_core/configuration_manager.h" -#include "../vkconfig_core/platform.h" - -static const std::vector SUPPORTED_CONFIG_FILES = {"_2_2_3"}; - -class Configurator { - public: - static Configurator& Get(const std::string& VULKAN_SDK = ""); - bool Init(); - - // The list of applications affected - public: - bool SupportLoaderSettings(Version* return_loader_version = nullptr) const; - - void ActivateConfiguration(const std::string& configuration_name); - - void ResetToDefault(bool hard); - - std::vector GetDeviceNames() const; - - private: - Configurator(const std::string& VULKAN_SDK); - ~Configurator(); - - Configurator(const Configurator&) = delete; - Configurator& operator=(const Configurator&) = delete; - - void UpdateDevices(); - - public: - PathManager path; - Environment environment; - LayerManager layers; - ConfigurationManager configurations; - std::vector device_names; -}; diff --git a/vkconfig3/dialog_applications.cpp b/vkconfig3/dialog_applications.cpp deleted file mode 100644 index 7217f61939..0000000000 --- a/vkconfig3/dialog_applications.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "dialog_applications.h" -#include "configurator.h" - -#include "../vkconfig_core/alert.h" - -#include -#include -#include -#include - -#include - -ApplicationsDialog::ApplicationsDialog(QWidget *parent) - : QDialog(parent), ui(new Ui::dialog_applications()), _last_selected_application_index(-1) { - ui->setupUi(this); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - - Configurator &configurator = Configurator::Get(); - - // The header is hidden by default and stays hidden when no checkboxes are used. - if (!configurator.environment.GetUseApplicationList()) - setWindowTitle("Vulkan Applications Launcher Shortcuts"); - else { - ui->treeWidget->setHeaderHidden(false); - ui->treeWidget->setHeaderLabel("Check to override Vulkan layers"); - } - - // Show the current list - const std::vector &applications = configurator.environment.GetApplications(); - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - CreateApplicationItem(applications[i]); - } - - ui->treeWidget->installEventFilter(this); - - connect(ui->treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, - SLOT(selectedPathChanged(QTreeWidgetItem *, QTreeWidgetItem *))); - connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(itemChanged(QTreeWidgetItem *, int))); - connect(ui->lineEditAppName, SIGNAL(textEdited(const QString &)), this, SLOT(editAppName(const QString &))); - connect(ui->lineEditExecutable, SIGNAL(textEdited(const QString &)), this, SLOT(editExecutable(const QString &))); - connect(ui->lineEditCmdArgs, SIGNAL(textEdited(const QString &)), this, SLOT(editCommandLine(const QString &))); - connect(ui->lineEditWorkingFolder, SIGNAL(textEdited(const QString &)), this, SLOT(editWorkingFolder(const QString &))); - connect(ui->lineEditLogFile, SIGNAL(textEdited(const QString &)), this, SLOT(editLogFile(const QString &))); - - // If there is an item in the tree (nullptr is okay here), make it the currently selected item. - // This is a work around for macOS, where the currentItemChanged() signal is being emitted (by something) - // after this constructor, without actually selecting the first row. The effect there is, the remove button is - // enabled, and the first item is selected, but not visibly so. Repainting does not fix the issue either. This - // is a macOS only fix, but is put in for all platforms so that the GUI behavior is consistent across all - // platforms. - QTreeWidgetItem *item = ui->treeWidget->topLevelItem(0); - ui->treeWidget->setCurrentItem(item); -} - -bool ApplicationsDialog::eventFilter(QObject *target, QEvent *event) { - // Launch tree does some fancy resizing and since it's down in - // layouts and splitters, we can't just rely on the resize method - // of this window. - if (target == ui->treeWidget) { - if (event->type() == QEvent::Resize) { - ui->treeWidget->resizeColumnToContents(1); - int nLastColumnWidth = ui->treeWidget->columnWidth(1); - QRect rect = ui->treeWidget->geometry(); - ui->treeWidget->setColumnWidth(0, rect.width() - nLastColumnWidth); - } - } - return false; -} - -/// Make sure any changes are saved -void ApplicationsDialog::closeEvent(QCloseEvent *event) { - Environment &environment = Configurator::Get().environment; - - event->accept(); - - // When we don't use overridden list only, no need to alert the user about empty list cases. - if (!environment.GetUseApplicationList()) return; - - if (environment.GetApplications().empty() || !environment.HasOverriddenApplications()) { - environment.SetUseApplicationList(false); - - Alert::ApplicationListEmpty(); - } -} - -/// Browse for and select an executable file to add to the list. -void ApplicationsDialog::on_pushButtonAdd_clicked() // Pick the test application -{ - Configurator &configurator = Configurator::Get(); - - const std::string suggested_path(configurator.path.GetPath(PATH_EXECUTABLE).c_str()); - std::string executable_full_path = configurator.path.SelectPath(this, PATH_EXECUTABLE, suggested_path).c_str(); - - // If they have selected something! - if (!executable_full_path.empty()) { - // On macOS, they may have selected a binary, or they may have selected an app bundle. - // If the later, we need to drill down to the actuall applicaiton - if (executable_full_path.find(".app") != std::string::npos) { - // Start by drilling down - ExactExecutableFromAppBundle(executable_full_path); - } - - std::string app_name; - if (executable_full_path.find(GetNativeSeparator()) != std::string::npos) { - app_name = executable_full_path.substr(executable_full_path.rfind(GetNativeSeparator()) + 1); - } else { - app_name = executable_full_path; - } - - Application new_application(app_name, executable_full_path, ""); - configurator.environment.AppendApplication(new_application); - - QTreeWidgetItem *item = CreateApplicationItem(new_application); - - // To update the application list configuration - configurator.configurations.Configure(configurator.layers.selected_layers); - - ui->treeWidget->setCurrentItem(item); - configurator.environment.SelectActiveApplication(ui->treeWidget->indexOfTopLevelItem(item)); - } -} - -QTreeWidgetItem *ApplicationsDialog::CreateApplicationItem(const Application &application) const { - Configurator &configurator = Configurator::Get(); - - QTreeWidgetItem *item = new QTreeWidgetItem(); - ui->treeWidget->addTopLevelItem(item); - - if (configurator.environment.GetUseApplicationList()) { - QCheckBox *check_box = new QCheckBox(application.app_name.c_str()); - check_box->setChecked(application.layers_mode != LAYERS_MODE_BY_APPLICATIONS); - ui->treeWidget->setItemWidget(item, 0, check_box); - connect(check_box, SIGNAL(clicked(bool)), this, SLOT(itemClicked(bool))); - } else { - item->setText(0, application.app_name.c_str()); - } - - return item; -} - -/// Easy enough, just remove the selected program from the list -void ApplicationsDialog::on_pushButtonRemove_clicked() { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - int selection = ui->treeWidget->indexOfTopLevelItem(current); - assert(selection >= 0 && selection < ui->treeWidget->topLevelItemCount()); - - Configurator &configurator = Configurator::Get(); - - ui->treeWidget->takeTopLevelItem(selection); - ui->treeWidget->setCurrentItem(nullptr); - configurator.environment.RemoveApplication(selection); - - ui->groupLaunchInfo->setEnabled(false); - ui->pushButtonRemove->setEnabled(false); - ui->pushButtonSelect->setEnabled(false); - ui->lineEditAppName->setText(""); - ui->lineEditExecutable->setText(""); - ui->lineEditCmdArgs->setText(""); - ui->lineEditWorkingFolder->setText(""); - ui->lineEditLogFile->setText(""); - - // Update the application list configuration - configurator.configurations.Configure(configurator.layers.selected_layers); - - ui->treeWidget->update(); -} - -// Dismiss the dialog, and preserve app information so it can be set to -// the launcher. -void ApplicationsDialog::on_pushButtonSelect_clicked() { - Configurator &configurator = Configurator::Get(); - QTreeWidgetItem *item = ui->treeWidget->currentItem(); - if (item != nullptr) { - configurator.environment.SelectActiveApplication(ui->treeWidget->indexOfTopLevelItem(item)); - } - - close(); -} - -/// The remove button is disabled until/unless something is selected that can -/// be removed. Also the working folder and command line arguments are updated -void ApplicationsDialog::selectedPathChanged(QTreeWidgetItem *current_item, QTreeWidgetItem *previous_item) { - (void)previous_item; - int application_index = ui->treeWidget->indexOfTopLevelItem(current_item); - - ui->groupLaunchInfo->setEnabled(application_index >= 0); - ui->pushButtonRemove->setEnabled(application_index >= 0); - ui->pushButtonSelect->setEnabled(application_index >= 0); - - if (application_index < 0) { - ui->lineEditAppName->setText(""); - ui->lineEditExecutable->setText(""); - ui->lineEditCmdArgs->setText(""); - ui->lineEditWorkingFolder->setText(""); - ui->lineEditLogFile->setText(""); - return; - } - - const Application &application = Configurator::Get().environment.GetApplication(application_index); - - ui->lineEditAppName->setText(application.app_name.c_str()); - ui->lineEditExecutable->setText(application.executable_path.c_str()); - ui->lineEditExecutable->setToolTip(ReplaceBuiltInVariable(application.executable_path.c_str()).c_str()); - ui->lineEditWorkingFolder->setText(application.working_folder.c_str()); - ui->lineEditWorkingFolder->setToolTip(ReplaceBuiltInVariable(application.working_folder.c_str()).c_str()); - ui->lineEditCmdArgs->setText(application.arguments.c_str()); - ui->lineEditLogFile->setText(application.log_file.c_str()); - ui->lineEditLogFile->setToolTip(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); -} - -void ApplicationsDialog::itemChanged(QTreeWidgetItem *item, int column) { - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(item); - QCheckBox *check_box = dynamic_cast(ui->treeWidget->itemWidget(item, column)); - if (check_box != nullptr) { - Configurator::Get().environment.GetApplication(_last_selected_application_index).layers_mode = - check_box->isChecked() ? LAYERS_MODE_BY_CONFIGURATOR_RUNNING : LAYERS_MODE_BY_APPLICATIONS; - } -} - -/// Something was clicked. We don't know what, and short of setting up a new -/// signal/slot for each button, this seemed a reasonable approach. Just poll -/// all of them. There aren't that many, so KISS (keep it simple stupid) -/// If one of them had their state flipped, that's the one that was checked, make -/// it the currently selected one. -void ApplicationsDialog::itemClicked(bool clicked) { - (void)clicked; - - Environment &environment = Configurator::Get().environment; - const bool need_checkbox = environment.GetUseApplicationList(); - if (!need_checkbox) return; - - // Loop through the whole list and reset the checkboxes - for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { - QTreeWidgetItem *item = ui->treeWidget->topLevelItem(i); - QCheckBox *check_box = dynamic_cast(ui->treeWidget->itemWidget(item, 0)); - assert(check_box != nullptr); - environment.GetApplication(i).layers_mode = - check_box->isChecked() ? LAYERS_MODE_BY_CONFIGURATOR_RUNNING : LAYERS_MODE_BY_APPLICATIONS; - } -} - -void ApplicationsDialog::editAppName(const QString &name) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).app_name = name.toStdString(); -} - -void ApplicationsDialog::editExecutable(const QString &executable) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).executable_path = executable.toStdString(); -} - -void ApplicationsDialog::editCommandLine(const QString &cmdLine) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).arguments = cmdLine.toStdString(); -} - -void ApplicationsDialog::editWorkingFolder(const QString &workingFolder) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).working_folder = workingFolder.toStdString(); -} - -void ApplicationsDialog::editLogFile(const QString &logFile) { - QTreeWidgetItem *current = ui->treeWidget->currentItem(); - _last_selected_application_index = ui->treeWidget->indexOfTopLevelItem(current); - if (_last_selected_application_index < 0) return; - - Configurator::Get().environment.GetApplication(_last_selected_application_index).log_file = logFile.toStdString(); -} diff --git a/vkconfig3/dialog_applications.h b/vkconfig3/dialog_applications.h deleted file mode 100644 index 292180cf9e..0000000000 --- a/vkconfig3/dialog_applications.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "ui_dialog_applications.h" - -#include "../vkconfig_core/application.h" - -#include - -class ApplicationsDialog : public QDialog { - Q_OBJECT - - public: - explicit ApplicationsDialog(QWidget *parent = nullptr); - - int GetSelectedLaunchApplicationIndex() const { return _last_selected_application_index; } - - private: - QTreeWidgetItem *CreateApplicationItem(const Application &application) const; - - void closeEvent(QCloseEvent *) override; - bool eventFilter(QObject *target, QEvent *event) override; - - public Q_SLOTS: - void on_pushButtonAdd_clicked(); // Pick the application - void on_pushButtonRemove_clicked(); // Remove - void on_pushButtonSelect_clicked(); // Make this the current launcher app - void selectedPathChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); // Used to enable remove button - void itemChanged(QTreeWidgetItem *item, int column_index); - void itemClicked(bool clicked); - - void editAppName(const QString &name); - void editExecutable(const QString &name); - void editCommandLine(const QString &cmd_line); - void editWorkingFolder(const QString &working_folder); - void editLogFile(const QString &log_file); - - private: - ApplicationsDialog(const ApplicationsDialog &) = delete; - ApplicationsDialog &operator=(const ApplicationsDialog &) = delete; - - std::unique_ptr ui; - int _last_selected_application_index; -}; diff --git a/vkconfig3/dialog_applications.ui b/vkconfig3/dialog_applications.ui deleted file mode 100644 index dd52a4b9d8..0000000000 --- a/vkconfig3/dialog_applications.ui +++ /dev/null @@ -1,176 +0,0 @@ - - - dialog_applications - - - - 0 - 0 - 606 - 375 - - - - - Arial - 10 - - - - Vulkan Applications with overridden Vulkan Layers - - - - - - Add... - - - - - - - false - - - Remove - - - - - - - false - - - Ok - - - - - - - - Arial - 10 - - - - - - - Qt::ScrollBarAlwaysOff - - - 4 - - - true - - - 1 - - - false - - - false - - - - 1 - - - - - - - - false - - - - 0 - 60 - - - - This information is used only when the application is launched manually from vkconfig. - - - Monitored Launch Info - - - - - - Application: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Executable: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Working Folder: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Command Line Arguments: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Log File - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - diff --git a/vkconfig3/dialog_vulkan_analysis.h b/vkconfig3/dialog_vulkan_analysis.h deleted file mode 100644 index af1a432cf9..0000000000 --- a/vkconfig3/dialog_vulkan_analysis.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "ui_dialog_vulkan_analysis.h" - -#include - -#include - -class VulkanAnalysisDialog : public QDialog { - Q_OBJECT - - public: - explicit VulkanAnalysisDialog(QWidget* parent = nullptr); - - private: - VulkanAnalysisDialog(const VulkanAnalysisDialog&) = delete; - VulkanAnalysisDialog& operator=(const VulkanAnalysisDialog&) = delete; - - void Run(); - void LoadTable(QJsonObject& json_parent, QTableWidget* table); - - std::unique_ptr ui; -}; diff --git a/vkconfig3/dialog_vulkan_analysis.ui b/vkconfig3/dialog_vulkan_analysis.ui deleted file mode 100644 index a16b75ff9b..0000000000 --- a/vkconfig3/dialog_vulkan_analysis.ui +++ /dev/null @@ -1,420 +0,0 @@ - - - dialog_vulkan_analysis - - - - 0 - 0 - 752 - 772 - - - - - Arial - 10 - - - - Vulkan Installation Analysis - - - - - - 1 - - - QLayout::SetMaximumSize - - - - - 0 - - - - System Info - - - - - - 5 - - - - - 0 - 0 - 708 - 435 - - - - Environment - - - - - - true - - - true - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Hardware - - - - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Executable Info - - - - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Vulkan Driver Info - - - - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Vulkan Runtimes - - - - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Vulkan SDKs - - - - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Vulkan Implicit Layers - - - - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Vulkan Explicit Layers - - - - - - false - - - false - - - - - - - - - 0 - 0 - 708 - 435 - - - - Vulkan Layer Settings File - - - - - - false - - - false - - - - - - - - - - - - Vulkan API Calls - - - - - - 0 - - - - - 0 - 0 - 708 - 585 - - - - Instance - - - - - - false - - - false - - - - - - - - - 0 - 0 - 98 - 89 - - - - Physical Devices - - - - - - false - - - false - - - - - - - - - 0 - 0 - 98 - 89 - - - - Logical Devices - - - - - - false - - - false - - - - - - - - - 0 - 0 - 98 - 89 - - - - Cleanup - - - - - - false - - - false - - - - - - - - - - - - External Tests - - - - - - false - - - false - - - - - - - - - - - - - - diff --git a/vkconfig3/dialog_vulkan_info.cpp b/vkconfig3/dialog_vulkan_info.cpp deleted file mode 100644 index 1277cd80b4..0000000000 --- a/vkconfig3/dialog_vulkan_info.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "dialog_vulkan_info.h" - -#include "../vkconfig_core/util.h" -#include "../vkconfig_core/platform.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -VulkanInfoDialog::VulkanInfoDialog(QWidget *parent) : QDialog(parent), ui(new Ui::dialog_vulkan_info) { - ui->setupUi(this); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - - Run(); -} - -void VulkanInfoDialog::Run() { - static const char *VULKAN_INFO_PATH[] = { - "vulkaninfoSDK", // PLATFORM_WINDOWS - "vulkaninfo", // PLATFORM_LINUX - "/usr/local/bin/vulkaninfo", // PLATFORM_MACOS - "N/A", // PLATFORM_ANDROID - }; - static_assert(countof(VULKAN_INFO_PATH) == PLATFORM_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - ui->treeWidget->clear(); - - QProcess *vulkan_info = new QProcess(this); - vulkan_info->setProgram(VULKAN_INFO_PATH[VKC_PLATFORM]); - - QString filePath = QDir::temp().path(); - - QStringList args; - args << "--vkconfig_output"; - args << filePath; - - // Wait... make sure we don't pick up the old one! - filePath += "/vulkaninfo.json"; - remove(filePath.toUtf8().constData()); - - // Lock and load... - vulkan_info->setArguments(args); - vulkan_info->start(); - vulkan_info->waitForFinished(); - - // Check for the output file - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setText("Error running vulkaninfo. Is your SDK up to date and installed properly?"); - msgBox.exec(); - return; - } - - QString jsonText = file.readAll(); - file.close(); - - ////////////////////////////////////////////////////// - // Convert the text to a JSON document & validate it - QJsonParseError parseError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonText.toUtf8(), &parseError); - if (parseError.error != QJsonParseError::NoError) { - QMessageBox msgBox; - msgBox.setWindowTitle("Cannot parse vulkaninfo output."); - msgBox.setText(parseError.errorString()); - msgBox.exec(); - return; - } - - if (jsonDoc.isNull() || jsonDoc.isEmpty()) { - QMessageBox msgBox; - msgBox.setText(tr("Json document is empty!")); - msgBox.exec(); - return; - } - - ///////////////////////////////////////////////////////// - // Get the instance version and set that to the header - QJsonObject jsonTopObject = jsonDoc.object(); - QJsonValue instance = jsonTopObject.value("Vulkan Instance Version"); - QString output = "Vulkan Instance Version: " + instance.toString(); - - QTreeWidgetItem *header = ui->treeWidget->headerItem(); - header->setText(0, output); - - //////////////////////////////////////////////////////////// - // Setp through each major section and parse. - // All of these are the top layer nodes on the tree. - QJsonValue rootObject = jsonTopObject.value("Instance Extensions"); - QTreeWidgetItem *parent_node = new QTreeWidgetItem(); - parent_node->setText(0, "Instance Extensions"); - ui->treeWidget->addTopLevelItem(parent_node); - BuildExtensions(rootObject, parent_node); - - rootObject = jsonTopObject.value("Layer Properties"); - parent_node = new QTreeWidgetItem(); - BuildLayers(rootObject, parent_node); - - rootObject = jsonTopObject.value("Presentable Surfaces"); - parent_node = new QTreeWidgetItem(); - BuildSurfaces(rootObject, parent_node); - - rootObject = jsonTopObject.value("Device Groups"); - parent_node = new QTreeWidgetItem(); - BuildGroups(rootObject, parent_node); - - rootObject = jsonTopObject.value("Device Properties and Extensions"); - parent_node = new QTreeWidgetItem(); - parent_node->setText(0, "Device Properties and Extensions"); - BuildDevices(rootObject, parent_node); - - show(); -} - -/// Many large sections are generic enough to simply parse and construct a tree, -/// without the need for any special formatting or extra text that is not in the -/// json file. -void VulkanInfoDialog::TraverseGenericProperties(QJsonValue &parentJson, QTreeWidgetItem *pParentTreeItem) { - QJsonObject parentObject = parentJson.toObject(); - int listSize = parentObject.size(); - QStringList fields = parentObject.keys(); - - for (int field = 0; field < listSize; field++) { - QJsonValue fieldValue = parentObject.value(fields[field]); - - if (!fieldValue.isArray()) { - // Is it a single child or does it have children? If it has children, recurse - QJsonObject childObject = fieldValue.toObject(); - if (childObject.size() > 0) { - QTreeWidgetItem *pNewChild = new QTreeWidgetItem(); - pNewChild->setText(0, fields[field]); - pParentTreeItem->addChild(pNewChild); - TraverseGenericProperties(fieldValue, pNewChild); - continue; - } - - QTreeWidgetItem *pItem = new QTreeWidgetItem(); - pItem->setText(0, QString().asprintf("%s = %s", fields[field].toUtf8().constData(), - fieldValue.toVariant().toString().toUtf8().constData())); - pParentTreeItem->addChild(pItem); - } else { - // Add array list - QJsonArray jsonArray = fieldValue.toArray(); - QTreeWidgetItem *pArrayParent = new QTreeWidgetItem(); - pArrayParent->setText(0, QString().asprintf("%s: count = %d", fields[field].toUtf8().constData(), jsonArray.size())); - pParentTreeItem->addChild(pArrayParent); - - // The array is just a list of values. No children. - for (int i = 0; i < jsonArray.size(); i++) { - QTreeWidgetItem *pChild = new QTreeWidgetItem(); - // This looks weird... but integer fields will not conver to strings directly. However, if I - // make them a variant first, then they do. I'd call this a Qt bug, but the word around is - // a better choice than to wait for Qt to fix it and then have to require that version of Qt - // to build this tool... RSW - pChild->setText(0, jsonArray[i].toVariant().toString().toUtf8().constData()); - pArrayParent->addChild(pChild); - } - } - } -} - -/// Populate the a subtree with extension names. Extensions also report their -/// spec version, so some extra text is needed, and thus the need for a special -/// function as opposed to just calling TraverseGenericProperties() -void VulkanInfoDialog::BuildExtensions(QJsonValue &jsonValue, QTreeWidgetItem *pRoot) { - QString output; - QJsonObject extensionObject = jsonValue.toObject(); - int nObjectSize = extensionObject.size(); - - // Add all the extensions and thier version - QStringList keys = extensionObject.keys(); - - for (int i = 0; i < nObjectSize; i++) { - QJsonValue default_value = extensionObject.value(keys[i]); - QJsonObject object = default_value.toObject(); - QJsonValue specValue = object.value("specVersion"); - output = keys[i]; - output += " : extension revision "; - output += specValue.toVariant().toString(); - - QTreeWidgetItem *pSubItem = new QTreeWidgetItem(); - pSubItem->setText(0, output); - pRoot->addChild(pSubItem); - } -} - -/// This tree section has some different "kinds" of subtrees (the extensions) -/// and some extra text formatting requirements, so it had to be treated specially. -void VulkanInfoDialog::BuildLayers(QJsonValue &jsonValue, QTreeWidgetItem *root) { - QJsonObject layersObject = jsonValue.toObject(); - int layersCount = layersObject.size(); - - QString output = "Layers : count = "; - output += QString().asprintf("%d", layersCount); - - root->setText(0, output); - ui->treeWidget->addTopLevelItem(root); - - // Loop through all the layers - QStringList layers = layersObject.keys(); - for (int i = 0; i < layersCount; i++) { - QJsonValue layerTop = layersObject.value(layers[i]); - QJsonObject layerObject = layerTop.toObject(); - output = layers[i] + " ("; - output += layerObject.value("description").toString(); - output += ")"; - - QTreeWidgetItem *layer = new QTreeWidgetItem(); - layer->setText(0, output); - - QJsonValue apiVersion = layerObject.value("version"); - QTreeWidgetItem *api_version_item = new QTreeWidgetItem(); - output = "Vulkan Version : " + apiVersion.toString(); - api_version_item->setText(0, output); - layer->addChild(api_version_item); - - QVariant implementationVersion = layerObject.value("implementation version").toVariant(); - QTreeWidgetItem *implementation_version_item = new QTreeWidgetItem(); - output = "Implementation Version : " + implementationVersion.toString(); - implementation_version_item->setText(0, output); - layer->addChild(implementation_version_item); - - // Each layer has extensions - QJsonValue layerExtensions = layerObject.value("Layer Extensions"); - QJsonObject layerExtensionsObject = layerExtensions.toObject(); - int nExtCount = layerExtensionsObject.size(); - output = QString().asprintf("Layer Extensions: count = %d", nExtCount); - QTreeWidgetItem *ext_item = new QTreeWidgetItem(); - ext_item->setText(0, output); - layer->addChild(ext_item); - - BuildExtensions(layerExtensions, ext_item); // Generic enough - - // Each layer has devices too - QJsonValue devicesValue = layerObject.value("Devices"); - QJsonObject devicesObject = devicesValue.toObject(); - int devCount = devicesObject.size(); - QTreeWidgetItem *device_item = new QTreeWidgetItem(); - device_item->setText(0, QString().asprintf("Devices: count = %d", devCount)); - layer->addChild(device_item); - QStringList devicesList = devicesObject.keys(); - for (int dev = 0; dev < devCount; dev++) { - QJsonValue gpuVal = devicesObject.value(devicesList[dev]); - QJsonObject gpuObject = gpuVal.toObject(); - QJsonValue gpuIDValue = gpuObject.value("GPU id"); - output = "GPU id : "; - output += gpuIDValue.toVariant().toString(); - output += " ("; - output += devicesList[dev]; - output += ")"; - QTreeWidgetItem *no_child = new QTreeWidgetItem(); - no_child->setText(0, output); - device_item->addChild(no_child); - - QJsonValue devExtVal = gpuObject.value("Layer-Device Extensions"); - QJsonObject devExtObj = devExtVal.toObject(); - int extCount = devExtObj.size(); - output = QString().asprintf("Layer-Device Extensions: count = %d", extCount); - QTreeWidgetItem *pNext = new QTreeWidgetItem(); - pNext->setText(0, output); - device_item->addChild(pNext); - BuildExtensions(devExtVal, pNext); // Generic enough - } - root->addChild(layer); - } -} - -/// Nice and well behaved. TraverseGenericProperties will build the whole tree. -void VulkanInfoDialog::BuildSurfaces(QJsonValue &jsonValue, QTreeWidgetItem *pRoot) { - QJsonObject surfaces = jsonValue.toObject(); - - pRoot->setText(0, "Presentable Surfaces"); - ui->treeWidget->addTopLevelItem(pRoot); - - TraverseGenericProperties(jsonValue, pRoot); -} - -/// Nice and well behaved. TraverseGenericProperties will build the whole tree. -void VulkanInfoDialog::BuildGroups(QJsonValue &jsonValue, QTreeWidgetItem *pRoot) { - QJsonObject groupsObject = jsonValue.toObject(); - pRoot->setText(0, "Device Groups"); - ui->treeWidget->addTopLevelItem(pRoot); - - TraverseGenericProperties(jsonValue, pRoot); -} - -/// The Device Properties and Extensions tree is mostly pretty well behaved. -/// There is one section that can be handled by the TraverseGenericProperties() -/// function, and just one section that is specifially needing the -/// extensions list parser. -void VulkanInfoDialog::BuildDevices(QJsonValue &jsonValue, QTreeWidgetItem *root) { - QJsonObject gpuObject = jsonValue.toObject(); - - root->setText(0, "Device Properties and Extensions"); - ui->treeWidget->addTopLevelItem(root); - - // For each like GPU0 object - QStringList gpuList = gpuObject.keys(); - for (int i = 0; i < gpuObject.size(); i++) { - QTreeWidgetItem *pGPU = new QTreeWidgetItem(); - pGPU->setText(0, gpuList[i]); - root->addChild(pGPU); - - QJsonValue properties = gpuObject.value(gpuList[i]); - QJsonObject propertiesObject = properties.toObject(); - QStringList propertyParents = propertiesObject.keys(); - - for (int j = 0; j < propertiesObject.size(); j++) { - QTreeWidgetItem *parent = new QTreeWidgetItem(); - parent->setText(0, propertyParents[j]); - pGPU->addChild(parent); - QJsonValue default_value = propertiesObject.value(propertyParents[j]); - - if (propertyParents[j] == "Device Extensions") - BuildExtensions(default_value, parent); - else - TraverseGenericProperties(default_value, parent); - } - } -} diff --git a/vkconfig3/dialog_vulkan_info.h b/vkconfig3/dialog_vulkan_info.h deleted file mode 100644 index 5e82ebb38c..0000000000 --- a/vkconfig3/dialog_vulkan_info.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "ui_dialog_vulkan_info.h" - -#include - -class VulkanInfoDialog : public QDialog { - Q_OBJECT - - public: - explicit VulkanInfoDialog(QWidget *parent = nullptr); - - private: - VulkanInfoDialog(const VulkanInfoDialog &) = delete; - VulkanInfoDialog &operator=(const VulkanInfoDialog &) = delete; - - void BuildExtensions(QJsonValue &json_value, QTreeWidgetItem *root); - void BuildLayers(QJsonValue &json_value, QTreeWidgetItem *root); - void BuildSurfaces(QJsonValue &json_value, QTreeWidgetItem *root); - void BuildGroups(QJsonValue &json_value, QTreeWidgetItem *root); - void BuildDevices(QJsonValue &json_value, QTreeWidgetItem *root); - void TraverseGenericProperties(QJsonValue &parent_json, QTreeWidgetItem *parent_tree_item); - - void Run(); - - std::unique_ptr ui; -}; diff --git a/vkconfig3/dialog_vulkan_info.ui b/vkconfig3/dialog_vulkan_info.ui deleted file mode 100644 index 9ece47193d..0000000000 --- a/vkconfig3/dialog_vulkan_info.ui +++ /dev/null @@ -1,41 +0,0 @@ - - - dialog_vulkan_info - - - - 0 - 0 - 754 - 653 - - - - - Arial - - - - Vulkan Info - - - - - - - Arial - 10 - - - - - 1 - - - - - - - - - diff --git a/vkconfig3/images/NewLunarGLogoBlack.png b/vkconfig3/images/NewLunarGLogoBlack.png deleted file mode 100644 index 495acff39efaee6703f7912555aaae5345e5719a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4063 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 IZKEdt7rjom%K!iX diff --git a/vkconfig3/images/presentation.gif b/vkconfig3/images/presentation.gif deleted file mode 100644 index e314eb7f3fe50d0b80ae27378bee8abff9931a73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1803363 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≪SBuPfuphCl_Qd78FmuD*pI5eYDzpmUDJ$ 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�AlPq2W{+rU4man;MbGXIY2=A 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

sO_NZ72-M!|LoCe&Pv69>gIYv*M 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

s|de9m83z@9~KD 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 S^3g;wKQ`N4GbweYhD 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�AlD-o>bw3debAm=c6)(&5-l7v)cutFtfM2<0H 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

KR(E_A%M12! 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%0D649lgN|i$kzv2LC02eA=I9WhHk_qL9oiP^ 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

Cgsbo~9_9NABBDVvwVv+#Br!jUC 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 z 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

`P z3%2s#ALrkC2ORJ}nE9Xo)^}s8s$WaXVZb5lQ6P|(|FjWUBL>Wg^f)vH2)52$ zJ+8FyetYs`aq`cu9>9q-TQkX`@^K7oadNIs=E&Ij;$+OnqA+7CusFFt=O#sjQkv4E zb5{>GlDBrdE8`AN^Dh=_y(_mGZ}yp=nC}9MwF>po&KGMLm3R?Ylz*)Ri<1c$9-P}K zgT2kUb)}@Gz}TwFS5&2@e0@|-vv6=suzYjU!DNQp5(Twf%oJg44N!@WGO;aA@DUy?<#QI&~1Bl?$WFi&xnqi_tayAIWf^ox2No$ z&dnwIG{$GmM=}j&(wlso?a2YeTVO8~IF}xHSaWjOQ#;a_xwXCj6h_y6t zr*>`fQ!BgvU? zg9KwvmeWzgLhk!OeeGrRQ%eUs2UA0u-p@!No_L$PS}f3C&4y30HwhnWpGL^mUr1xl z*W?EnXI|j7l{QcpSSi{-T91ZZgUCIo0J({oB zteaiTO%(mQIb>5mwA~dfdUklYSzmtKKY0R`Yk+5Cc7dNugd=GeU!mo2#R9G#zPsY6 zs#|XOac)1mdOSp-330=Z-SS|3)quj;-t<+44nN1|XIGEc(+I*1&D1bg51gcF!aMTP zhbna5FjtS~N6pmwHg?>U`gob`wG3?AemaIJ1o6?*S2ec%2TJsb+oD^jb~t>D_r!6Z zF3E6IhrZOmluBu3+RB^pIFR3Rmg11~9shzFj&LjkJ`FCaaL!DSzPUNf!~ukxk3NOE@Z7=G&q9gE zY>Z&{ky5pODbE)4>2<>#1+!IFCn@p_O+}g%V(gY8_2(y%&!#?d+MsngmvY616B=PD zkbSTgw2J0sxq^kD4sVQ%A9=|Xo{dZbg@Rw-%U*s_&>%~N&VDyR4T`{s^?q3~o~0xv z0Fp&HhSvMktvJf0l#Xw^qt9}=Bq=;CUAV)nN3Q8p(%PjgOgKdasm@2qSXft6sjEM_ z=fJ~I{HAl1CoG`!hGs?r8xp$DvwA&Qp3f-RP=wHsgV_`4|?A`J$ z0I^0IC#D{KF|<0mh8-mS0O zcwdW|LXWC!Kl6Va{AO$+!KmuP^MYsb@Z(FWht=}g1<#ARbdwP)YNjq@n1AD(*ow8i zn$5cTa>(L!?}~KoS|GccU>Ctr=V6`Dw)c%S|4Hb9M?Dnlkt&2`3W{IZa3sRvHk&(z zR5DbX`h7+Bc{7I*Vg%QMUb=Uov`i(Bq4_U`_{o{>p*QH231Ftf|oFf;?4G4oThfuBNpV{zC} zh0Aok(_)j;db`_hug}rvfYag7vysr#k?^D8n7z@=rOED@>4|@A$o@B`mSa=1Z6oug z{mXHko8Ha)c6CPvg*$h%H|}Ju>*j76m+slOes%uv)uZogz~IsAvAx*o?S$F&#JSbv zh4s{x?Tq#Pg6-q-{nK|xXN^bD_9JNbF|_{}I(7`5I)Y9gLTC4&bGtvs{0{UtV`=+j zW&3b#Yj1sPXLD#g473SAm;mPaljpSIe}@G8x1h-X zz4!fp-~yBVJ}iTM=T|-6e_%EWTlXX7cP}gb@69YSy5I0$n2mOZ!d7(u7-M4O~vM9 zLtE=c+!OA{_HUruI{WLfH1G3kcsM{;g9N~eMF;)NaowMT{wI`+WO zlsE0dbzn9cX*wfKWd1n$@tsSgz#U%l#Y_OtppL#DNssoVL)-hM+29YuOmiX9k=_g@ zEH4g&-Ndgi&)t@hy*mGz2u*J&T*r8sG~(WiWg`iAo#BW`!$^gZDASDFhSB=gMhkBq zLDLuFp2fBszfpdly_jI}d3iArZo)TH;}x;F=}ng_Ii@e&uob71Lu9M_Q(oUXxtkh9 zet9_~uE!9#i{^NlWk^3aU&$8p%vs6t2~^BcgJ!k*G3S;J+DGLUj^wNsygN{&FQ__U zUVGa@JWBDlkvw;;_`~(PB*h(q=PSB}2unZSIbYG;g~)Hyf>-BCgE0eP?%W zHp=eEuWp0`%tl>Ep#1LwO~7_;+Xrk~bFaNsE2k4OyN;K$GB=(ri@UO&ta9u0*jMEY zS$|y@?PUvFee2CuvoSNncDfaVfP=qTdjndtJ%+z|y8E1a6K|&jrw%x=LY3WKAPF=c zQG#Nh2MyiMX72!r%$4VOLCRV1fKvT|ryEkq24fIN&nf0ew`OdQ?dLQw98W9%QUC{^P5IJWWP+EhYF+3wiavyYs zKQV9++iIh%G!fl9lX`{9LUTAEC+?~y?ghnmaS_+AtS3W9bYUN$MRqvCK_@M8nVWSH zKP8cDP4A<>{7Mh8P={sxu??-*UK@hbkqfE*TLk2!Cd|h=b(Dh1J`h|QxIjo9PeG`o ziLwFmsGK-s-bb3J(zFn#FKx_sLj4IkW=_j}^R~&QPkm$V_3hfRB{gc9g zB?EMK26Aj-eEk_|DuFB!x^-8YJlP1(d=xu$=#wnd*J5M zrtkJP!c&^*SZ7(~c`LW&k)gcEL)+c}uTFntv?hc-{$?7{k1p5u9$^kTQt zKcW|qHcsF%%@4SWWW3@+A-bDVxMwP<$S+$@^c-2Pj2hiDRwYTW%uiXSUG~Ay$1IJN zY@O$cH?g>Ge!TfS*S9lA#~0<6+q2KMO03tiS~~|vvv1Oxq>pJ&DrT0C@IHSQn7i{y zaVU3UzmWb_?)}SrLv0_8GV&>QkV8TUxWg-vBo_g9cqC|7pT5%Q$Q2p*%5GL`tFF;7- zLU|fp`=}AGhok+9niG)X_j!`K%VI2X_l~YdWNBiBFfL#7?OuPcZFz?L$s5`y zpR$OxGnC?u*@ehI`UP>O8c~@bgxGf_Pn5dA#jo5KviMv%@hnk$3&J-U^W`~oujm1# zg(7?OP+d@Yk&EuUn;HZOAx1nZpTHH#C3diw8Z|-X%+l=5*CAQe3isY_Ya{i$_S+^m?IGxIgEo>s`+49OInfCpqFU>q06&x~r z5hRlk5gr=>o(di5DiIbdDIF^rA2+c)51u+7rY;|`xiE{ZoJydYMWJrsN6W;4muVeA z=_N^7S?Sq1nYjhIunt{bVPQ^9S!#D(d?!eW7u;sCYrP=I-h0@vin(4Xb z$=ROqna|@hBNNl(=N?~w>ozj|>mNs_rweE2)8|*x=2ueZSCVGe(iS%|R(A4NcdFKR zo7eYy*AM$w4@Or&?2r9A4#rl_W8-ja;|K&Gzg#Tt_&-$m|KR_?kHNri{@ecLPyg^2 z!597^=%wb7Jl}Eon~lg0uGE(AjmU>xKY?E0OT#%x2?M>c65-6SMr3~`OE3)dn!D!e zl<0eY2fZ43isgB?eUXTXal2p+ZjVF~;=zXhhEnvQI|C3GJ@-HcWPY^{TfLx4u;Kr} zyrRe;+m2u*KMSt$Ap;HMw42n9qZ9L+uzOu{(awBu1_=!G&H%NMk*q9#jJ~;F(v7=o z0b#c9G0^P{-vy35S)Fa4Y`x#}ZhFnVED-mbn#(g|S8oJ%+#|lS!#WH^=q9gfRkbbR z^%H0fX9@(-6*G;ZFz!C>^4!s`lvPi?SmPqHjNCnwcW`Y|dW}X44KD?lOk0qWZ@-p! zM0~Yf&)oH_KgpOREOXME7Jh!xryEWu#D)4rB>D3-Uy~LHCI^4=BkWr|2A&WW{zN0v zYCDMlp#|}KKGMX)_`dQ@#xu?&Dkcf`2ge5t?#SfRZ>*^Gjqitu_+^NDSCd^`h-SEK zW^AB@{75^Tdf|GS4FV4>gD0=Xvw8PMSF`kBacbj{5JP0#uLyMt5cAX~|~2}MPs&2>?;UdeWJ zus-ZH#)XzNyqZe)OMO_6wr7D&CYVHJOSo@uS)3T(g{wt~8}A^&W}6M{({DB*tH{8? zEdX!rtrRj%97i*uHswGwDLY|N3$g85kt&(DaH#AOb=+nPO=jMc82Sp9zSb+L?{+@$ zV9dkd?>*q)M)7#J7rBFZuTKi$+`(;~>!UJ8{$9VD9BY}ginhr9XC0IL=jw1iQ_nxk z*s#JJ+|Gjg=v}DFhhYwG-KKmhA^kQ(R)^yQttvd{4sNz#j}uuf;LV{{N7Fw2MCE-R zj2lO@Aw$v?;_kb+$Mex92_bn%SQ8S{vEFRevq`=2;wX^Uq9-eP6x0pN*%hD>`3l8F zaIti;Kxi0li=$V#28CUC&;bWDBE?C9fxWPp@XOskIbbh5plx#o?1e!ia?ExU*b95J zLyzX7Y@o+WnT61kwTeyX*R3{K$8yN#+u0GY7lxi5Zi2E4GwCOLVN~U$KeiV>JE(y* zB7e_bSc=HH@K^T2^yto6Ems7$FYJXYrS{Z8Bl1HEaYg(4$=gN#dYGxCZSt+ePDLJ+ z;tkkZ{E!E%$pMc7QYjZro4KKEffmwq{!8s`q9>ujFXB+BHTm1c$ag|~TJ&kRqgxNx z{18?iLoTg{w=3S+2@|=OMou^E^3rsQMyMgxO&Cp4IdYXE)YQ zcoHquO!;2UBJvl^O#b9A*Qah;#4Rajat|-aK(lt^w*m|VMmyr{Ms^eKLE{)j4BUI2 zPPqL}#uhE03Vm+moJsJ{10+Z~`%zLs0nyKqC^~d&H^19xgEzO+MpTK44C5pu?Y05N^f-M~( ztCAz3dW4g~yq~R7YpRuw{y9zKc@A2>`34^{{}wF#7-3-gf{+p=H}Ph=52I z0YMRwoJ2&j3W$;?maN@SZR&PjMh4Q@@X?Y;UxQ_KUINE46T9K+S*0SpX%n+ICpEC};DvP@nHc`m z!_%xG4s9kG&p)zN&qrC7_8gCXdDDAz8R1{Vg=cK7%B9(F%U4`+YsKbsgeEi-?l3&F zZ09?y3GbjN-QqB|TC=O#X$h`64$IQVz<*dlwNq`!a0GgVc0LjNWxFr|(5t>vL)nq- z#@B`dy|omX4jvMBzLG}l)G^EDcq!ZK5VvMx?)pCSVVn5c_erIJf0e`6sJxVVZl^J3 z^s@i0xyQ8BB{^a=xj^$e%}B)CEZuPS9ktO%M&;c?1wV`F#I^x8>cQ5G_T1p}jZbTx zb{q8wH-|&7D9_eJh0&hW5)E3pPmGNfOiLJWC91Yum&KjD?HsOe)OoJCt!jx*KHL{k z3(IWcAC=l(UDt>>5iwhh9p1GhnlC~Vz3`?@D?7q6Kl~y=iIlV8mn0h8M6)gfr7MUp zP8>XG60(MkVS;_hmCzgfuMAZ8hQ1_OzRYAhxu6DL=_`$TnTwM#uXM3=Fd}#>&evq= zM!x{oF>QzFlNQGe)>Mb`6ALE;R-T-pP#>|pXjKBWGksAdJGx|QRyI1yYu%{c2t!6x zteqRSnJY79CoHbUky|G@EHeYc@(a6I7-)8v2=g4q2!DHJJ|zfny1WcFBz}7T~djXbZJtHnbApGF)4;weS$l+?Ra$W z1`O_oPa@*x5veOXS?lnE4S2-{ykQgG3Edrl?hZqDN1%vt=>8=1VCwe_Dik^MchmxO z9|qg{ivmhcaDZY1d<1(MfAQ>p|M`FS9e~21P}tfgY(hBshC>zjkC z8v{#ggL5k*Q%hr0i>UfKKlXKId~)jdDU08;7mpGcL6YOh2#CIFXs9nQE6vNz&ddOL z%&F;VDLH9zrKv$pDbBsg<|FAQ;~7TN*@iQDCUb@6^JSI`HTH`wZp)qCtKEJpy@4wO zL2F|X8&lDnvvHgAiJMDlo2%J>40PQ@=)ivcp8;Jp`zBNd1=oet-vSt$-|4iW0~iND z1_e5*INSnQq$-fGhDsN(K1fu_GX(6eQC+fDE#8A{1;>6gyIXcQeYl9dnUzQA^BBa5 zh>Q0a@nrm{Bh>(4cU9O%YCVWrWF?hjuN`-E+&LA{|8=aAVf>&ry`-kTF;KvX^G<2L zfv4wvCQbIBuk#+^H|5JU-WG~m5(ul-*chJU)Yk#7)l*0mwz9(*6AT@(R23x+&+YrrDR_DYQv0uM6FytIDgr9gq2$ztV z#H&;)KH4n$GC!RVV-4;Zv(vN5anh9AxbNMto;9g^ydj{c)8)Y~K2KaY%0wN=Ye;)h zkD%uigP)LY3WMZz%U#ld>$vpOmN}F9)DWV`&{zmIw}6iL-YwiwpR3s9aW3k!DRZ|p zw|9v{wf)WvKC$_Xt@egy;PfYl*=qyJj${T6gE!i9q@tZiZQSPH_~^8ZL`A!Kg@26i za19_z#B(RqbOd}k#qR(XEE%1&EUQsQLA$ODnNk=g33Y*)CYx#UkYU>Cj4Y?&+2UnWRnx+i2DUYWHC`0E zoB7~U-tP8NmiFFT#9B2L_37;D<4o!1vN(GsAgVZ|$NVFU;;*BM(>LlgOMi+gK2tlw z@FS}DMeB9Fi0bYWXIIcbcdO?#(@JOZJA0p+x<+RzCWDA$^XK*B=%`}8 z2AvRT-i9r92S;Rm_=>E>Fi9K7&V&_+G@N~ zKZncrMt4%#4vM}Qgd$C1 zRJqQMcjDe@&|8UN|XdG(N)x z37ZzB(#;@FsRY)GCtB5pHiM4`&aetJ$!LDv45{W}V7}bkqD2J_ji8^s@!qpdSMYhD zpE&)Mk5cW1tj_}CA``C`HMiG3;|hsgPULSqk*C9XC35;sk|0rH`^!@3hj>FK;W;V! zuT6PTJIJ;q_0<#rbWbtw?m~?`A@&78SNgM;8Z4F)0A0S8 z&wjSBI9h@fNeSuhx8bmOX4w>J<(BT?Qdk0)Z^|7#=`Z0!utfg$6gjJwFHs0sk_bVn zg1dB2EY()Bq-^TFkd~fA!L1Yp-&DmU>E2YetyGovRHdSp-b~xAG%bQOl}72l-0-b* zec3d%{+7PN(ya`0-!zRmX#jK|sLwTho48-ivO2dQfXwl&q1w*&kTur9p&kf`x|tK; zyR3a?c)2C*sZc$8|F95n_UGtd$=*lL)lmS4O z=0(}Zl}sxfRt?qDedWUoE<;z=4*4Ivs?<_vA49m!Rwc+{b%W8kjK~VbZ zL!nMc9=NPrUAH6A7_AcA`Q-4_T6Z==T)m5)~gx+^>ON~QSRcik`>#^CC{4i_{O@H zy0F1A`>)L&3thgmp99AGB1gv4M`o%<=9)(4JBJr~hZjbM7bb@n7KRr#h8MQ~pa7G& zu=S(5m$s``;6>{@>8m>l%ka3R?bwCwv=vy@##%3Qacz46zO}TywYIedw%MTol^xX) zQ2Q$nbTIHfsy}46{`=s+_8s^I3HXbrz|ZuHXMge3uU~ldtNwU7_~du6OiT0_hz7f( zpACG`P(sMRgk^X<#DVdsjGa^sbTk;(VVFJtmG49McaPiMZrFVrx)VFoh@<&O1yNQ8 z{;TL*?Co^Hd+4Ei>@@3rv=EY0HWkG`Dm1@!1^nZ~Ad59Hbmx0ARtXYDHM?U?{ zgi+YUtK_4hI}k!XZjC|Fmaf&lVjc?ZHL^I+)SQW#^0 zRWLyFid8cja`Iv~#RS1|B;{0qctdf_o8>d+&e+nt9#33O#bPJe6Y!``2dOYxPdi_; z7@!edf5k!^fW>U?=&qWW!f30Wh@B83$#`P?Jyf)0_Jg%$f1;<5MRKe&29km}6&u}kzt~WC&9D}AXpAYxcO=Wq8Z@RdUG$V?$m>fUGWSEkih&Ps!TDZvi z5}97fx|B|(E54LbY++~whVEYK>6O@Q>4w#WM#fo*C$Q?k(7nt!x65yKIluF^k%?Z< zJ-d~{u%~GpMH6zfD@BvR!vn?B;c2T{^ND4vWp=(N*UCKw_WUbgv%|`HEt_d;RaTc} zh$|r!%Sr{uNQ~EO^e{dL)Zj}*lGl+cvy<18>qVY!pt3r9x{=1+hpdS%IS=h6ZH2w(o=p*!Fow|W$nP0;+~_o2HxntwF;HgrevkHhAT9Pp!| zyY*ZK5JK9+SI|Ru0Lv&$0sn{|y7QsVM)N zH=yT#@Q*K|F)vDf!c$v!qSTncy3+KC(01LKW`q`3Lb8T5Jm3wTa15SuQ_X2P;$uAF zWCvX44%A)i*vFwtm1?f`vQ4S4{YAY0*UU{rnCm#lvcvo$MMyjcZ=Gv~gkvCP2(H*9swusDXOXYV|7oyAUk7@gD0-Ia zQ?slb)m`7Ra*WH(%~BlFd2V({tXWdmW=un>`%yC*K=!G6(4wJ!r^KqV!-VrSJfaG*35M>xA0a&aV-V_rYD~&?j03v~>?CCfL}A_bel4@ zEON?iIkfQ_W0Sw*+37dk6KKCMo8uY!Imv)S#CdD`#sH zT~P3O0eEU_t6^)aYiny{YioXMYaP(A;Gk&PZD3>dPXx>VbAb0Jq=@~eNKpctMAY`j z%8Vk*rgm%4x0RWe5Q1kzBd8GBj~8FkV4>xiH(W^-y-<^C1qSZZM@aFVTN`Rp9sVHg zHELz1Cqoy=GmW^|!KAvm)K{j+w8zz&Wavnq`R~Z0&olal6oEYR{1H<8lJ=;xvSJSo zR%SlRSD}z1bZNY^stWv_#%7*yz#`Y507x-;!U>;u9xczDbRknhAw}KfNw>2g-pHNS zjrl8Dp6SV)nEcg?y%2>I8CIf|=_JIQ+p=v?gLzz|D+w20Whu4TyC!X=+}?@JDSx<> zIJO%Ms?-AYUBDE!BZ=3 zC)w~hPYT}C~e7_!#CFCZTr@xpb7*u6F9aTgk$; z$dl#mKijFXjU1$KImdT(+9KVe;DkCpL623M{c1l2#Rx1@UczLhi`sdDH>b9{!Xlbb z9%+#qo@Z=PQR@UrpAMy#F&%uBOUPUjqbIwvXpO@P8(u`5+wS$d5oJ`{Ed7dq#0g5+ zJ^&)_0*uNh-GCH_W2 z%{ziiPDl~^7#Q~@c^ z&X66yhf#bv?a9!o$74Oo<&R>BoNn6Dk<8)NU+fNijx39#5oM^l#%=8G3XP+^+ADD* z%GcK!Mc_3z-4@&o4DgAkM-g~p_imFlJzkDXlacxgkOb2CnBkGK_(n=NlF8vAk<;kt1~p%YsRW zMjOx@P`QLRoYlQrAVqJ?E%h$KrTb%i57V_U=xqYYB*Ffa4*ILKbZg@GgsE$M-?V*^ zgiq6Za4~i{+LJbaJRF#-gRsV9Th~$}BCAPHP{m`v(8Byg>>+|vqdsV&mXq=e*2uiJOz_3g=~>OWap4ar1J4x&n&tFY59YzHi0Df0>8xd+}es%FlgO zfQL`;D!&k~z%@Rh>jJ_zgszJU-w?Yda`U>V_zkgJH*Ve%xp`YuTte)Yq}Xk#o1i45 z#X(8R+(OrFDVf_+cO<0mNXp1c%E(FGk&~8{2PGq?a7X^GtioM|dy4lTC@ZO`s;FtG zYiK@vr1eM}gu{YJM_pYI3Tt3!U}$7$WQ;0fVK@!rNH*fwhh~!6Vz~7ER3JMAi4h{(k`A-faX>af7 z?CSdbx%zh#MHXOc- zKTW3S2edkm!C=J8Vr8QHgBEHfh4+Hw)hC^? zCV(9qjisB^O|V6+q_8|p{k%w?Jz49)#>f#_ob$NRd+vJFon6yUt(a`TkB2SIU-(VC0f5Ej`)%t>4gF*2H_gb5s3m(;;{B)ib zVb*kBr7TT4&YSfVQ{E(nRspYg`uNZL2`E{g_rJypKOZ2v=%E?NHRKT=$i}%q9Vmw< z@c8|8Ua7x@d3YHhNhT+n1m=ui4%sjn+bovo8NEX6CK)>73C-!2K zlJx?m1s8OK)NEOvh8dQoJpN#dV9|;35@gj%2)8wSl#*I%_)s*X6v3*V(;{f37BuE% z@bM5U)#z#YHq~;L|4djwR-F?ob8a(ZB6D85g`jbMHw8ZEpFql2yqj8%XI8?Z|TaVx;Q5qPly zla(`P&H#HA;K)WxOAE4_fW695d=m=`3kc6U z9v%=|`6IbfKtKREwh9Xi-?(u@R8;gP`iP5*-$I|;-;cx}9ZB?&l9G~^mi}SzsGy*5 z@7_H{MMWhgB^4DFb#--3O-*fW&`5P2KL)+@$b!g68@e2s_aI6*O4TVL^)pJ$7Jl@Ozsb0gZMPq&NU`b)W{BnwnZ%Ts*RJ z`?Fx(A8qm<`sDBHsd0@SJhX26lBld)^u&R5M$!$W+!;&d9Zej{`LAg6GZ)*gq7~0^ zk|cNs@Grh?@keWZbOdiMlki?E&QC?H`Q^qto|G zUIZ)@cw|W@$`;SvDb8*Ww7|gOZ38_ugzh|8^9zgBDhs+|l&O)OSKS_c(;L0!_dn26 z|84h3ypRWe`P%i5{jVb_sg*?W7N`PmQI$}=m16azdM7KWO7;G(Gz(SG1GSPf!K#L; zXF?v@vYZLk_8O!Ndm64v8E%l8LJ?t7YC{qEtYwh=!^)Sn&`{#Qk zm^dshWmRLdEoa|8E|RW@L1|}v4?{S5Ik*1$1bhBxX=;(9Cd!Bb46nzIgYdK0YDa7$MzZ2A&7=P%Xw513&jCRmi^NRI ziU`e)3QLF#PyG;)7WpwFA~7c-JwGBNJ32o#qc%0aEv39CyJ4iDYrbM|y=G#&ej3rd zaL~SV(6M~bxpL6EygRnIK0P~aKkyL* z00Qg$wSD9k9Jvqjxz>@uP=9|Fxeq>WAP>MJ|EQhMk3scc{DJvL9|tf0vzPpXPyM#V z{)=z;yYKni*MlG7$8YiTYrj4I^Mk0b{p&~m&yE6U%KC?+09teU-BIA1%M%J}0LmKW z@`Q2}pv2hUQ#QZ!sQf!+?QM6Jc*J`md#W)2*h7{pILx$$O5tT|bvZ!-skZ6xyR@R+ zj^o@q8yy`kR!@q-&Ze@V;0!rViC3(2MqR|fnM(Im{>q*PUmd+XK_hFEU3Y-&!X;uBq@h4k_ekvS)A3U;2p}v0KAfex(O&Fg6j~=vbTv!@%377d zqM7a%!Uj=LPB|RljY)rDZ zzTOz_VnUOx6Zsm?fhr1f-o_#39v<#FQ5yCMQUBWrT#dM6Gm@VY@&`|xk70{vnG1ka z8q5I7nkp<9X;_U2)QfmF9YSTh@zO}_b}2>7TN6TQ$E>%xiK*CZyaSINw^Ak@O?zY9 zmK|NFygy)fDXBjUFlHTG&TGIP)C`DnG8{4^!xKMm(GuJeT@r^Wqn>4}#w3!9ImjEA zw!gh(rVx6ZJ?(Zj;Rs2_^apsqCL>qygmEvjWfsy+62g&PCg5%6yrY(EQZQ@Dmg7f$ zGA-vljh;Qd!SOREE(Px9rrm~=7Wk~jQlHA7jgP+VqYDu@WP^2yTRq5@(g0k0DC1Xa z2zJd1yYWkG+Q#^#dsfoyjm$S_3wkc#2;~|ndvh4JG{=Oq>SEmsP3hZVG#vDjY@ohi zA|N&zk8H{A)qssV;BfYSruQ6pdYfXxi{@tGLGWySM$Xw0ya`oYb#ypo9_{f(7 zYjp;boqx+PyPZ4&8qBAkWp3R!BG6FG)>5-2hDakGhKgT${ zw_m0t?|o}lJJUK?uDT(I+1e)Qp-kg^_lfddlHNn|rfO_KuA3MteaD#4;s%bE66JW# zBXI*Qe$0`$;n&MmM=nny__4(9l67=c8*EI{v7{kQzb#iu*0ZYpSgzu<-T1y-#T~xk zqkkuks=uj$w{*i7y<8>PC^)p?XWbS@14k`aZTLIj$J63S0nI5`uKH`r8Z1|Zw#74| zG^e(k@1pS&m?cn}Q?OihCxKPD8Lc_Z_DNvZlR|4wi`x=7t(sdk5kPZ_pUCAd)usb9 zr%iVfxxsRkt{^n5%O{a13208ia@9avA}`RKn%Y7mCctu4qg01QI25&9CD`BGVF@&+ z>pn?9bJ}SOma9;j)9dhNpgDzpgb*Z);7Ehzs{dTg=~kw7`%f-UI5I#)jMAK@>rjB@ zD#2}_IZc1UBs18eww)W=p03N+I@n>m4IBkB^d)3~qri54vMg{EXdUV+1&#u~$P8mW z;3zP(U0B?nVQK{&1rXas)dZR5?!Zxi3hd>}W?BG8fmuO#Nf&SwNRk;{RD+iev}alt zwT`aZ!pkNIvaB0r#x}#@<@2&XISS0lj3b8Nl{@V}ISSz1nZTspsm7K28_QL+ggHMg zSG9d5FWaf-^2_njyE8>Kywkwnk>h98Hbt|y(bor}9l60pZ8My9yRBM;d7+JWX1ODF+w|q~km3Dpv%F=y?dE=Yk#l$E z1c!G!tUL0e;B9l)_jWrS2=k+HWaq`G5nUc~`LPu3^S6Z%p9B2zRr`|W9-_aR zurS+Qc3FpdZ=gx8FgK)qSyyOpu*@05J>)7zK+n=H(DrrJW$Zfuj*q>&WFKJQk*bFY)pW*T^Y15N~ zh7a%0@^_YWSam?7_V(vQh)TQMJmCn+> zqK>UhyMrYyqOyTTx$WGDgJpgBvZ4Nt?ZUEy6?6ZxkvU*SF?_IU-B~sU?|@hC9jrMJ zl~3Tv@6=Eu*FEIRzfyGWGzcL#0{qLTndEm{)RCK^o#nH9ox2@&NN6-s#k_<(qB{Z! zOO~%#RPIFdl_9sX{VSIBAKfpO>#f^mih+%MK6L{j2up z+u4%pTXxSR>fSc)#n>nSs1;6_X6?aQ(ck57h+hTY70r%HC z?hce5PW&D&Djsgu9$Fru9$v*BJ_8Y~ATYH9vdWIK!MhFFVw}zPE^op(XO6*>>|Md{ zQznV2_$^->oxp_+xd>sxOvCsuA@Kl^xys7QfX`J`RaH|{1FWuwhQ`B(4*|FP=+PrB zEv;WLynx#Uq%L4_{~kgDP!WK-b#-+GiMRm)0q@_x2jeX;K97uy{P5vJR8-W*KRGcm zF|o0+@$vDAiHS)`Nhv8QX=z}^?T^nlzu)wqU4YZmGt<+v)6??PQi@ZPDpC?^QsU}U zVjEIono?t$(|%NJb6Q+;T6|M#LSt%TeM)j|O4_I7%&MfE^2Gd-_@cttvb>mzoam~Y z=<1`&j;==6CvaH-l@(Ky8CRPTUzeUxpPAZ}oz;?;-&R!8US8QzTi@By@p*KhYhkhr zI@1B4>)2iB*k5cvSm{Krbs^V3BR9Vwp}okhek6PVxig5|9YP|8k%$rG-UxDk6uCc! zJQzPXm^eU!n%qa#)IM@{A32XeF6|{vm4Ji2P-TvihgppAQVNXn`aN<5rpgMU%_$vm-6tve~3+(=W- zpIo)VdvM>*N=5Ke%)UpfgT7z2qJ#t(&v~ADT$dp6_KalEZCwnQB_jm25dQtMLzbf^TuW|E_> z>~#0qaBB%L)Q!Fg?HQnWw(!dB?g59*Hf*N1d)DhnM{ZTmiDWAIsMAofm-;YY@QG35 z!@D<@Kdkeuq98lY?AP&tCsY}Q`A-KDWkHolw@jVkh}d;O|2AuHO{v|d36k$#-99|_wI#Q zZ6r*(*pTXwc7!sBCQiH;Al1d}2)p2zI3B-C0-UnL&wWZ9%P%1@{n{Quijg#0*Gz2D z-5!Z2nl#e0OJrH&`(f2Sf)%XyDatX?LM|Xr%W6M)N^52CLZ9~jV~eLxO%=@~40Itv F{|D#z2#^2( diff --git a/vkconfig3/images/vkconfig_applications_collapsed.png b/vkconfig3/images/vkconfig_applications_collapsed.png deleted file mode 100644 index 3940fffbcd99252da710e1140d3a548dc581ae58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82424 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

Wa#{>&Nl3B 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 KC)1@by8l1V#uv!| diff --git a/vkconfig3/images/vkconfig_applications_dialog.png b/vkconfig3/images/vkconfig_applications_dialog.png deleted file mode 100644 index adf42da9bf6098d5762529e640204d8364121046..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170544 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 diff --git a/vkconfig3/images/vkconfig_applications_expanded.png b/vkconfig3/images/vkconfig_applications_expanded.png deleted file mode 100644 index feb1cf45d10a061e16fbd11573ce7837931080fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91459 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

DkEI!N>ct)$^#) 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 z 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 m`#Z9-Jw2n~7>@%;hGi)nrl|x4=1;2Qq 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 lO6T=*#v1MF}1;Ta6Ls8<38G>hqO` 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 diff --git a/vkconfig3/images/vulkan_loader.png b/vkconfig3/images/vulkan_loader.png deleted file mode 100644 index 8451a35125ebf346c2da49a349fe69af0b709967..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 283048 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 z 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
~tc$>6q6q!wUlMmu^W&%H`_S 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 z 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 diff --git a/vkconfig3/images/vulkan_loader_640px.png b/vkconfig3/images/vulkan_loader_640px.png deleted file mode 100644 index e79bf6d6df383a6325aca03f3d9512d549b63d02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100657 zcmd43WmHyc*e*(Uqoj0qcZWzfA|PFYbcb{|O1Fe`gLF62osyE$-JA!%IQz#p_Bp@y z*lUb6)>ynT=e(aguj{(sFlEJes7M4z5D*ZkGSZT&5D-wl5D+kP2vFcJrx$9F;6IR# zs_(=h%17Vqf&YOq7gG>}fT)T=elUau|Bq-Vt>p*-f!6)`QbNrxXP`L^Zm6nh(si!<_y?$u_ax~M< zqV>3OUbHgSpKvd{v+Ow9nl-l5Hu_ibX>w9k*q;=^pY(|d>fjkh31dv2d`s%^o2=&`A7o>!)alSxBK{2wK(tV$~?Dq>=k z?Ck7}jEr1dxDPptaa2@P`1tsoot>?%4_8_}c|Om|fB29*LSe~C*#RS_E~=vPwZ6VS zC@84CU8FW!vqF!6fZ*4!UszaJ4-XGkWI6N$V`EAR3aF^4m*?l6R|ojqXUmO_G)kF_ zOiUw*q?WWVU-Jcd_-OIxXJ}~XBt|WEo8^XJRKjZf9(`&7f%}QvcOmE`(Gd|#RmS~= zD!DK)yOM@cLEte$p9}KxdIkqAMpC&Va9OxHIVrLGUZ2o`?>E2PpW)}{-`?K-_U)S$ zoJ!3|sPzxh~d9jRsNBP=# zwuG`iE^d-k6hT!Hj3yl;2~&KP*zs<{rmS$!VSS)YMc}RROz3Mxvxis{4Rn>FqLK9-Q^n<%2 zO&%r=>NB3*AQtw>xc#gp6FF z-!5#u$jMFZmf-z(M@3B?92i*1rt(MzNgb-KU}a?`E-v05O|+1_ra?(X)$DS(zrNnt zCwUq2at$s!bzs`u9YJ+ue%GUivn@Gp(qa*ChAJh9$jF~(OYsRYT2O`QzUWzrs`~(E z%y}P|naNB;(+>w@OTogDm6+HE_g~+2dwZLclVc@%!hMr>;$8*$?;ieVZxupL1sBiH z&)?hIyT3X#HueuWy}l+9a5=~n@|;gj`m|JMoyKiF?|UQk@1hb=AESIBu8&uJ);j#G zhB@Nn!tC|+^%eHIW8EWVWv!G5K~u^S z{#jpdyHHK_@J6sIG;|-jwXK${g6wl z~f4;jl6i6IieNo;cdI~#&VByNa;sm$TA zRIV$aj>Ztff4thhn)@!M&U#5Pga7qUQ&UqWt!kLE+;e$b#EqSoY^BmGT7PzSw$kPm zaSOs3jYK$I21HxP`@_YbB_PV4o}O-o#>U1>5Rs68kITx*Nz{=Q^4P8{R~f_0=467S z$q;ZwBfGfl3PK)VgGVQBXl!)%^pxNt%ZU{ou#3Q9G8;`tq`Epe@l|C%8&*gA9t|9z z-gec+$!WRPLQPQ-ZTs|kFpkE2G~NB_f$uJ|jY+2tMFO%m2r{s_xj8Nldwasj-oC1$ zf@S~RR(N=Lfl`*DtnB36+-kio$rp|$Yh&XY$DL7sfB*g%5@RdBAHrX5I_eZKL|)=E zlwL|*-D$c|g~w)jU}OZOR3aXmH(2Wwh74qhz`dkCsH#FuY`uEM`Je>MBO@a-Q2FiK zD@qz)iIjo0l>6{Mx61_uQh5?jJs1bRvdRZe7QXM;=ug2FCqaBz?o8y|mgb^!8s zY+PJG&}$3~-*Sn{EFsT2%Ncrv^P}I*WI0`3U4^JVBO@ad8YrY|(^W`s-@g6OA`?f= zI?m3{ezJ;)h-h~Oyx&L_8~_TNnTO})zQzSk*e=-=v)BUymVrNMapvh}e{(}a$F?}{ zklvMni3v>qV9VG$Ik}RDUdhU2WL)OJqTUt|0&xhZ0TBv+SdDrRtgWrxR@sdE-tgLy zQc~uX;z7%bhpDNmD)UlMba!+>DAc&W`Bnbx4`IwXUZhrVe|-#2_F=xt7wSHFz?p*+kr5HuF4YGb9e2t< zHdcFF?(5XsWJ9m7uVa|0BM=2aEX~i0`Z_x~fware5?KO5!_UueSi_js%FOJ2TRoo6 z!&9%mWZA!JRt(Q=e=uLw*4Ac95R^YH@k_%R;p&YXohL^WXQBvn84_ zO#OyCqZvuey8hQhoS!f#anSIBs-^=Gv4MkYf!MscaeMW7Dj(J47}N|}5!a)Swa7Db zGc%93I+-3<2kwW9T%4#sXUE4sfy`F&zDzMw(Ea|(dfTHU44Wo3Ihpg*`1h{QH6XvC z3`Mtfe${Vr!^}mhjmFQfSJrpv=wZpef646U*GJI75<#?U3kBhn$0G}P2Ntn|+pd)ROICCJ%Sd;`7Hx%gU_X~ z3z=wXrKP0cHhtID4C1Y3OSMc)C@m%MFKSGO66G`OPKt|*cex!VbQnjSp3+vlwfyLV zj-bm8|CNB?%s`DOQpj?{ak5V@P173GOEZE2(+T@ObWx$&sLylo3K%U)GBRPl5Qnv& z(Jr*GB+H~^W$6V3(ohjr;IiWL@+b*0W=KGk6wc5xF!cBIR6=$x_4M^^oEt&s+)02Y z>}M(tlQs-IJT5M74O?e-i|2K@M#=mCu9j0Ejf0-0vXT`P=w#3*T^uaLp@!}&DYQM2 zlaY0oSmH1(4~d3|xB#-=<=;87)-6qp$t94ofzvCcu>UytZ33e*)aZ481!_)f zOG{u-&;q6Z_59Dzn##)KAOYR-*(Pn!N&7OqQxJgB{rJ(!*mw%OsH3x#mzQT7j0+13 z%c9>lJvBwhW&}gzNP!Ui^mxC?Vv>xANDSjy6Gx-OtWy^WKa*6*$tCNX-G(>7qT9sD z#g(8?jDRvlEc}HRxE?x*aHR~4N`#;5LZx9qSeT552Y;I62^K3>WxJ5))%5JFSzIWA zSQI~uwYhoyr-_`^_DnT7xuM^`b@lWzqY!iIRMpivKhH91X=%yH$$3meSJ>~25=lr% z%)@bUadC(Bf0r0f$lZRJ1h%TR`Q0Sal(sRF#sh-a6xzSA7XcBGh~H^oY3crCy_@T- zDRzITM6)81SvPzv$o$`}zw@oSmzI?^3Rvx%o#hr3Oh-k?!O6|bbK0Av;#~vDeA2p8 z&_63{6(leo&}=#FDszVwicMocDk>IJ|Kd&8khN_0l47r+D{W*y}eu0MQR{- z%FD?at0CGbgJN-au?O1UW6)Www75GRYDDD)BbhTM*p8y_CNa0lFIf|lpz{yv6)%kuf@5uA4>w>3eLt-=rR6(GAVG>Yu}ZgxF* z1Dew>Ah&{=2MS45b@k-rH0dQT!9UpqCgI1(rr@L&`5}K$NTT;1RSfO;rc#r8yRHz8!ky-+toH9hdQk&8wLi3S}}b9?!R9`A>v|Z2NRCb=4w9ZI=t>K45450$Bia9V7R8H zrl|rY^MF+eS=s##Kj@1;I^e~PRW--jcgo6k;4pyQ%{TSQ=;=LxT}LwnYS>;zu?Gpu z_}db-f>BWM;n0a6hW_3F zp%%Y}e3si42G%f!Z4d-gib5JUcs?Uze^N_+%8q9&U??%%|G(qpOM~$LkxBpO4*#WS zzs#fm$G$)r8kU!qc6X*k)9M7erKKe&H+R7o+&k$LAD6N(SvkY|Qd%Y^)6L_7fq`)_ z_@SVf0F!`I-kBDK%mhIJ2IjOhLPDPqFhG3!rrPfP_@Br0@_8_7%#~`rbc09=tOv&+ zjOWU9Xn@VBF@YcTh!mLV1#%hpMHUtof?l!4o-aK;-M|O53jgsP4Pqm&41jmLErSdX zBDqrL4Lb)%%p1OH??;d7_7_)lElPnxF&jy}yglEsl|KnW#@(MOd1vnP;sfPs#;_kg zd~oXyMg=nyXz}Ec7W7|k-nFm_3MHAN^XTYE-tFnZ{q^gFm!X2}pY6Y($Lo#EZsHmu*z`%K{e}_uUrRCdMYcT~ZB_t%oqSsPbT>LU6aR>n-elxS_B(#3&|rduOXDHcEjRzz|>pL6#G0snf$xS6~AYiG5PY?$jC@g?(lvk zCnpaN58K+*ZYdZU8?Sr)oh=*c6O4?FjjgS%EiSekN@M~Z2_qfdpc#l!noplT@$&Kg zv|dV#3Tv17H*>lDjD^nJaD{F7{=K8SdviF2!+T`~DkWv)^(%s31JV(p2q)(?RH4P+ z3-c&BL_`FIgcyZ%rNy!<%8$TV@w*&I&qZVQkcdG&u)O4vb{qpMHCNYbCTePn?ChGQ zI--@Fw`%V0hD`}qEODCZuae`P4!hwCIy$y9_^p@PbaiynvVsL*UM9?EIZ!0~Sw zBn<3WG|~OVEE7CDJa^d3H)g7ncG#}8@Od31&z!91I87#9$Kt#e;xZd<`uQ1jHS?4& z&qbi>2XVYm^RB}AZ$1(dfGY5Q6L23?FNm!Q&ZE>g#5p+Q&33c)vBkjXzLSo@X`rz#JvHTOOk6#1nQ%*GU-77 zyO_3OoKQq$+&?@2dOQ$XDrGk@vy;$hC72I4E%RD0R=5*0O9D2#fv&EpiHeN$eqsff zK|=zA=46_&H`>2scnTjH5%Eq+3N+{6q8PgR`l!js#MIT}qr$@f1J!$ifP{oJHr~Xh zQKY1ysgZexo%94P1E?Q4lmIq@u_gjn+8EmfO$dN-4h|0HZ`$7oxRjcYWr9**XuJWh z{sY2CTK=QmxtUBOL!*COT-3*pNNvrkJRBnW$9<^r=P^;gH}?kf-zRF?+kZY<&2qRs zYl24?S5=*#UWL&8>2(T)tS#(W*ZsRyw%pXI!)hXWEB!Loc z^7%7zg#6WYlKK{$B_+)@t>A-}6DQ&M=|a0l(3q&Ca%@yPluR4Zn_*3Df~15kB7AUF zq>#Ca0^Pljr#oshZjEAe{hW;J2 zB`s**e9?vNH(&^Twm`W9GbF|Ry#RPxIRs>-@#&VEBO+{^gm?pQ#b%dv3yURU5i=}Z zaS0*@_E6i6&Gm%r&?0wt_)OuTxRpQK!LVOpgMwp8PA_$x{?2Y)9}nG6|5^SR_bx^; z3ZFwkt^_!fT(i?cd2TmjLTVbaZInm!{r!$(=6lGPdtSjeWgWCWib`Wl^!|4^IJn&~ zxgF=pc+-(+$-?f{(+dlHlrUa>^ap1rzWGM>C!!2^sya$^BM_M;`IUO_TB+4sm zqeOEtBf*`x>Elg^5h)LS7zEBWW9xs*!kD)io*{`;tgzM%C5aA|BH@ ziW!Qi1nHiS1mOZw642)!JT{VfKTvIEOUna$+!RLY5fO8Vhzv&zE3(I3*KTfa%3FNU zE#5sk7#Zm|f#FESdSZ4KbjObF*eLfU;Gd$R!M+})A|pr}FftqS@m-(T4GXk*3+c)s zcMY06A`Beb!G~Oeq^GILLPt08cid2}-TSwO#=ANz{LIWzLBc%a05~~*SE*kR&d$=j zHKe|V30OE!PZ-w`^Yg?0{zA}jyWAE=TwiVu*Vg`|r*C}w#wFw-N*dMVe4m^eZe;y; z1{)J=f2A@T!n_i$0NK1nO%vDj3hm7R<@?b59CAS({snE7)0=^>k7=Cvh2_x`&^?4Y zqN)u?x40yB6^dl$ zQdVB=i`wF2dGG)Jbz=N0`|_aZ(cwSwcRtF)h7WF8g|wee3Z~UTkY1q@IJw?A@lKq1 zyeBJ5i0=ssnt1aP{mC9~f)UX+j0}YF=^qCy*w}@LWEn>qNgj4+sMJkNupAw#k&swP z5;8|W)m8e6qM1_*3#1iQ3I@9#Us+G@Zr569QY-jRCXwigdaY7XvYy)=qPC$SyktL= z;S_^pgM-J?va-1feI;`rpR8hB13r8EPy1#(^^J#199htRSnDh8nw#%!l*U5zd#h2% zAR+NpCWN5j%Nu<}Dhd&DJQ-+rhf6g75)1kovCSzxBH$_4hy_II>KaOn!N3f+c)V_N zd|Pj09iQ+sKHdyq&-+_)4;fQ!tzEWn&NPyej&pLVZ?3GDa9JWr1Vxp`pY<#)n*{|A z^jbdbZIDxuci}vS`v>-Ho}7I4^OHMX_H&b{$-b~pN%;WVibhlp50@(J?l9lK(=k=B z`??tg6gku!fDC|$=o|Khgy!VrOqSem#aM1~W)MJL!hP+0z0n&)Bv5Vt!}k+cLQ=?k z1)Hhh(=V(=&}rPLN^&JEOsE>cxK_pAA$}hg(wCb7nZzr+fYq?6_M)ZI(HatvhX{mF68HbH6(M+LJ z7w9jQR{-*QdO;Z~ZnUXDQ6VciJtgfx`rTU|kHTVdSh=4ns*~mVB#At9H0CA|IC@{d z-T|=q^E?KT^uVazbWvP!DWiDXq^dhxl}kE9yHhHspNQh%NJe21pR#UibOY~Q5j6v0 zVj_2``#H#SK|k_wUg6pvE!Be@KpP|M^j_ubgW>=~Ke5u-mXy@D^v!)3vH1SUNr#P| zFhGY{$vMl%Kt(+9X}DVN_A5|Aj)>4G)`}E+)Las+UU09#7G{hhmwZ}0+w7s#iGqxX@!h1-siqT#WwDM}*{VhExLQ-AqjC5rJg z4L|}#B_#ksPmFq&b91`^treJ7z=-A+U<>O8(AsNZpZwf$K}AWAyP@f6K%7*wiA~$w z+}`q7&D&knN#?cBA=p_zhv^jf!q5T0P=&>M*Dv>p0I2KfnsYtK zlX2dkHZ=AxyzGDh6u}KBRaOrPfGY&eZtNqKTdXbY2LQs&&)=M!@0@CBSz&b=!_d$O zz`&Mi{|sMgmccM(Wy$|pT@9EK<2c@{Yrqh0_CHzR!7CG6{hlgM7#eQr2cv#jRH_G2FraZ=~Tj%9F-DatKJx?airF0iG>QWB+~WUMQ5sT8mAmt?=9XYaJ4i(Oh$5 z`?QOemLH>|JX2Fu64{>kAgDTE2nh*ww6uN{6m&mD6ALwIFRgavkl(2Ac1;fti$^O3 zVGa+BGSkw_4h|2qFq(w>(KR(ey11B5t&L`+d@F<;+TPx&+2V!6HG027o)jOSXKJeP zDb?}pyxjt!SNUeA52f)_la<)KDPxyO=Nx%PiWq(#$Ly7yt)qjoyO|=IIGLE31Tylg zn`(K!HpYaw0D?+|8bNZFCi$uXz-OVG&59oT+c8Kce z+^+<{D+L9@Ei8$|gpn}}zYdp`J@R>&zaCB*-X1w_ZkjB61#{{M7>*f0V$RRc19nE; z_5S|POiA|VIW(-#x@JO61k6NfLs`u-xB@#eFLY~-&%n+E6JT@J2SzIzsKfRiw36zM6 zsuFwiQ8&f1abOGvZ_V@I%g(5}@g`fnjY5mtsotkg-YS@TCn69c38nu2L&vM=e6FKw zdsC<(Xnec?e4?#f0JtB-_IostHvvU8<6F~yEaD?v<#9QLO*0)IkEYiY7+=^UnHz@v z7(+s`)O;O`O_OXis+1M|u{|?|bj&VLI#OEtgNWB12Vq*aZd1C8y`Pq#$754ON=n7g zpQqDB7{+D`<*BJ{{n1(#+CNA8@`s(e-Z2Z?tv%!`jFpyYDyG&x3}Bj+0Ss8L@ocZk z81U$i+r#$w-hO^~RBpsVcayVqUNvT#%fAWdO6FP&C9X9qVm=>U7P(BQ%uUicx!Y_kk?t8NNh^H@zeU6lyC*c$T)mY>s0%I#>W#prY5Mf( zJ3VC%p@XVwq2*9IpAH~}n+>~>b#$KB)|Bk+@0mZwCd6OVRCSVHKRyt{!Wd9Q?k`OB z|Jt9NEjukLGObJ2Ie9ii2bh?WeJCpG;cTTLA=QsycJ@hfa{mkNOnO*v9tx3XNA1Ou zo12}gsxkqWbl|do2IF3+elR9Igl}vZ0c-~ley2CBX8>FJ4Cq&Pi^AIyW!;G?s6=^Khx`m zRqLI3a8c39$$BAcd*wKwUI_E^8KQ~3EKRBC8Bx>(hUae%_olA1L{>k2{%dYM!Z`wQ zdUbySnSYgD@^`#kw|*?m9H44KBJFB@eU zJs21%VXRl|wC^En1f``l5K1V0Mn3`Rwu_J5B7V)?k zAQr0hl2^=h68VDX>@qc14=gO=rrhfNm`_hH?S8S*+cBEa{MmAJv9;MejeB>d$NTa7 zvVPOOvEoYOIW2YH%1UNbN$TqBHFk1xasarAe7V8E#)j4?$FaqAzdidAAFqDCJ+hD- zf{BIoEiv)EhKBW2zCwjwD*!#`Q8v(l>IMZJJti`8_}8y4!8BQnmcWdR-@eoe-pn1d zJhpm^b*Set&`@;%ko_`}s+FIwEavU~G|`(;MU^ZYCe(U9UOcTeVEEMG&tnwdAbn+F_z*uHe8yWvw;h#S3BU{4Y!I;LfSD- z)1dc>Mu&(b%Od~|d3bn@t5;GI)TZxWY!x%^^nATm+OsSy`2m$T8%5aNF23kGoR*ZF zI6F6vLE-D%A0xu&&@-9%?VVdc^{s`m`<85i40x=K$k zaZYfGiw{$|6{Hnf|NixyTDrgNk2xMo_gmp;eBI>;^^u5;mG#qNEu9cj0e5VA`j@DH zn3x!VH;0EK_32$qO8N5u_P4BaJX-|UU|v~-FzwEHf0u-Jyg{!O5kMy&s{b6dd7U(X zphO6d6tu833 z;EQBjq4%@N9(t6JJ~JUrz-%fXZ6qyi@9(puFVXL1<+FjaExVIVZfk8p56;=DlyIb3 z9x965(|9^I&2s6-iy#Ne4hY4L!rTmETrB0~Z z9T7YRvn76=ompsUY47jPGHCYY=k1n%n2^#H5~hMJKaH_74 z#_F?*PYgs$a3;S!udG1E^t-y+Wi4e2hN^FAg}u2o{CYTBt}r-Us_ffY)a-hB zbr{j^!X(V)yckXNLGrz9u|)tJ-|cNQHMIz)L2cWg4nNl{5rAdpp2H_Hqeg_KG@Fkl zF{H@K?VyviSuOMChXKg^BWx_hoSV%`OCx9!0H<1}-`)l|_#4z3e3;JehiC{1t%|f% z92^|k@Cali1ekYkJBK^5abLae6c#5^VXXN6{h;m*oSQ5rS$2AhpamjgAZ$?3TPiB7 zoSdMyZ^xMo#l-AYRCv|@bWs=)Q@srg>gBEAVPc4MS5MPd_FYV7A7F_31UK2qVndkq%|^|krIlRti1RYEkcZME8A4a;^`k9f}t(LWpDK!N-@1a^XaaZCM~_%W|d5*6Bmf`U%#DO}T#j0^!Qw+%v-hK5SR8*3+&B-b2b z;}-&b4QUUeQ8520uBkHm_7G)VDXS>?fteQ0%{OwoFpuP4RaUny_>acFLXnUuaOspg zDKyJVtE<`Z1QONyamP8Uf6eB6u}%4r?Cz`2X({DCT*GDTL`I8n`4&l5+>1@kn@+vg ziuoboD-b>vvUDtF2d}EE`am2OhgzZp_W@wm(Z!_=XsW=7z(#Av0jSaO7Q^l!3Mtmb z?(eh=%^ttv_ql!rA{9@UHGl4eBC@vT4qF2fQgvfAV!_?*ZBRA2Jh)(0C{)zm6R*~@ z5Zc8iC1!G%NT+0#FdHzzx$LWZQ;I=g8RRr=Y;8G%i5Dou;7|zwtq+Dlc<^^^pth{E zTBru}R;}esxB@xg58eY+#>_V$Ss5A_kWb@|dcoX_2`M`yFLN6jZUB|~cdnx11d&im zN-9?>>TcrE85xK1L$wK_*$X#DBBBTAri={0`wjpl8wYILI+*vscpVlR>UMKtc)ZdI z*w8Vv2RL_kcfh=*@HtWg{8_i{OCtcpft=2C^V!J8M%bVOV%Xp?7>y|PUZkaxih@E`wlYkL_cn1ZPv+Z{4;=`it3JMBxva*tI-;$}1 zTjh7~^z`=L-rR`F{;aKaIa&sK1_|y>9?=m82M3_m%o6r8QdP_neguN5L?#{fbsiwN zxOLD|4mk7n_TD9o(?bL*vr0@LD0`s=R{~&?3%z*-1Y$r}mc&EUIW7KKDN``43kW@d zB1Ae6W^rk$xv^2V)q{(S%n%Ul78Vv@3~O^eCU!73GE#P!uQUW?L5usjnfvRIa$pfc z*gD%);lek7YP9>~;^M;E461SWny;>}W5FiC6TSykP9Ojf0B{iOCIc9-ut6ZE!MuqS z_Q~tv=5&|RJnY$bR)y(TZaqFeJ`iEP=svWo>gs~I0Ut_Grr+pbdIc0L)C%Gw2Sy@r zkG0j+{v1+5g{T3^07x=g00Z(LeqLTuB4{+H8{m!<@1lY1ij87@XDkaS5B7msDz#X7 zJMz0#fmDl!o7=38UJN4v2?^J&<5^+87N8KIiC4jXIQ-Qc8(p^(?uC$afs93>yAfci@ zs@}C5$U|g+9Ow>CmUY|C!NFfWcL`AH#Kgov{7{I&5QH<~KEO(Ep7a2y8%R7$pzgue z?KS9{oqeyXON13Y%4&>IS^*+m3eTV`5b=Xnd|*#kYOeDKcdG{gbpS8bm5?z06;D?W zQmoxNl#YNHh7STFtI7y1BV!=3D8&3t0Rl2|_b^abN@{5QY#AsjECg~c(T^WLYHHR$ zg#7{RzE~`2_;_Y|`Wv_R+_`T+1ioQ4fRHEKCesG`%bSw?{P#dZ#%;YQ3JYWuBk?ew zprWVx`)SC@p@i{%?_OS_vWmc88rY2k5eLYA*&(skkys|CrV~`5rcO?rYQqBq2wDJn z2;h1blF~!sm)ZUOvxSA&r}fc^9{|UlE73f@yZno%CmNhxRQM(r2ZRh8TNN4+|99<3 zj^y64biRPEFx(bmVx0gmqokx{#p?RxJ4l7Fp#%i6#rVnyZq?xPHK$5`(j5s#a6Ufn zvahdfKnGu$3~&>mn~{_a8bdV*7b{=$SQq~K4G_rRzCpzxlo>^{a!}#tE2IU#{jO(M z3vz&;vDxI;frqk6V?3De=RkO7cY<(ucu3X$MBu_li(|Y5@;_XJ_pJv!$?ZfndH6MvL*1ahL46{PwA3V zQoM>%Nkc_|h8nmnjltzFlY<@g!tW@nBE#sDHrCdtm`!e{8W7eifH1GV&nHbmm;jRf7tMa$2jbH2 z1qJ3n)h916zs74=4P?>#8yirqk~UiX-qrrA0mMKSpYwcoclRN-2u9aGYo*3q2^@GT z*Jo;4+R$JE9-A*fI1KVca%w6__jtXrXsl}L>Up`j&`kYn-@%asspajD6Cl}TyE&b9 z1HveewGK!i1m}xo05;?pYzt89m}0Geeiw=7hmTTIUJ zUQrSd5^~64CP0vs6joNoH}ER7@P&nku4xW>Yx_WY5Rs{j_&x?Lg7&%k)KxSNEF!$f zlf#gJ-W1I%3Bv(a&g7AMS)ht64sz)dV5i${PfODg7l(4x zVJ)Ru^lt*}JxDAh8lCz^cD~<0*40#1^|ut?CM&@c0+RV`#D;wUKpI4`zIQv_fMwhR zLJ87z`A61~*rl^1Q;^lf)T$UQkHBsSP*#Ay!B?@BSDb2o5lB&bEv}==O1})On+R7?f;J`f`AiHP7^&9N6EvE9Vu*5K) zk^T$G{@>_80rLI7*{1ow{|nYwfT+p*GxPr<^vdCni;JURV9@#SVW6)^1TsyCj*gCj zq2&Ab@7xERPgGzbWMg9k1k%^IxXqm%bG4G!py+)F`t}WrdmA6*3n2Gf1X@2}@0TNj zLp*7xBq#4$SXk)orP}R=f7&qen^ZkupBKytr`_7==VrpeC@d*0&CTTiaRZVXkVn@n z%s{>f%|MUIA?^E&+S%C&(iHmf@4toR!o}}mM$5G628ZOrBO(wGtEfWhbAY_O{yQlZ z#ioR0kC#Y0KxAfYCr!XAPyie%)~i=0$fw+t9SNXgy5YLf?d|KsdHuSIO>=N$WM*;_ z6l+uCBgmM^?_$v0g<`K>y#oFF{MpGmo!8xN4E~g~R>}zJ6JknZ<6NfT!p?5tL=}Z_ zsO2dU1yBW1cJx$)MMwAXd{7kkk3vM-YitCq&rEOb12u>SAox;1L$1;KDO+Q23^<;h zJaf}SUeBxi_Gf(0dmzEDDQZDNwA%s-4sQiXNl8uX!}$_Tux#_@HOBM|aL`x9Vj(7= z}J zs`20|Vu@k>>GNznlr)yY#Xw5xt3Ymv@#4=X35kg|OLYpg6q_g2rv6a1I%{N7PRDKb zXMccxJ^#m#Dj7)yKW_{0PSCOPW(s|7c45-}GaSGORA)iy%l{T_3h7>y)7Ax*m3E*} zBrH&}RW3k#(dL3}FHc++VV`YzX=wzo)r9b}hEuos_b(w40l)E@C}4eJ`Y!hs4t_69 zPJW9DBY=F_M{)uCBgmHt7}#K;hbD!?X;;_WoFDsR9Iy`9MSA}}F)5_KkXQ)NNgCQb z7UWE{(n%6?l>at-urV=Jk~4m*0v#x#-do?ScH3qb&}Lc5|Hs-9bq&~VnaP?2+fHLu zRqy92YLGDmBNLnMnq80QeG8w!V`y|d?u;GZ+*Nnl#${%-9(M()3bz6LtL6S8Oo6FC zH;IMh=H8f^nTm>)++W6|;rbwDsK(q%nW5_EPa&6s4?uQK`0P7AK2F48)^NOZojbU5 zVwfuv*R{F10E<8@r6EHHmaBkv8?0WbzzQNF*m<7%qk5+er>C>@mDH+#ke2?Q6C#3u zh{TQ_#Oml2h{q9z5(5QA{LJ&CF8jw1XV60dhtbi|DJUqYDSEA7LX+m0HpaG zuujFqoSBj`_#f+3g|f_oUv8KMm+!U}?(eT_936E5Ug&eWaercG@|K25*W=;FUbMq6 z0yhg5F3|^pPyM~`Iq}(pzyIIN%vhaQKq4+iUM-%J)3VwYwCZ&_l}4(vUNSxo22TT{ zhuX3GYtuGCPX4>-p&d$Px?QMnH{fS!ZOxSLh;J10;^H z+J)&!ikcEn`@?sLX_uo+q3ef-dDFIE+-5i=ymtGeL^5nuz?XMOgac`XPp)yX0q2OD z6!%S>U#(4?^vdz-Kx`|_!lHYwEFv@}#H~Wer8F@2VpmDsD92N@BacZ3DLj0|`;K#^ zhmwf_S;Fu3{_2OBsp-xZlaSNE;|zlZVi;F{v|(w7`p}Sp>vDy@$UtRK5bUxYKqaMv z5pxJ$k`xtd^j+>dfXx~3dJCG&f7JImFV)&0C!ZJ`97srruhsi$*&B$sv_1Os=IFO< z)!?A=7BV%pTwf%gg%!$g(@Bklc`seOFuKaHk&k8N>rUuz^L?d-hy5RAm$ zKa$F0Ma#q-jUOcy)n#nVrbaAnW^8K8HtOm2Jp=ph%5>5P`*3?CdljH(1hpQ{29hw5 z6_v3V^o<)wNB2)&ao~vO$_TMu|9sx)6&^~u)@^$*m6kR!BFB;Be-iJzV$s?F6S${P z>)ZS5{vUaEmSxhPSIhA+{op+cA0?tq0@TEe~Hfyu36W&v8%**>{o)E{=Tw`dJ*(KmGIw zaIV)|e;5;4e1Hrr-!Y9_VSf(YGGa}Bm#u$c{y6e&nEv???wM`%&k+Vj&bhhc&!0Z=`*^c3l{L4u z0jlWtc1!!)&qvF0OLad?P4`MaRDrQ~lz@QNmebxShTGZ$AMcBUQ+lm41B`>!@e1v@ zn%w6P^)}6;8HDpiYA!Z5-iGT}?&q`GI_5iD))^e|NWW?uj&4pXlkr*&yOS%6!o#zJ zf;=AY3gLz4mk0L%ktWgPQIxA)n_VcHTtz&OiN(`qN_=?ZZ|=mOIyySW$H8_2PY27(DT3C%bGTTe z1k8)GXhh)(oo1SWDY?c@s*_~U&>)Gw1_Vtb4$jS&g=F*ZxM!MZSOyz&530Ty%gaa+ z5#}gw8V)b^2Ai77rl+CACCCE%)C$OPZLk~&zs6Q}bwNSlpPX(c>$OT8v2fUr z56WK8mP_)evzU4-0Zs1p=U2k`?k6JaL#+U~&XyeQo9VT}LN8oql)sD4AG3tzBS6@< z?ClK>2LNc=*=FJFB!QtwOAA`SWq5E*vq;AktTYYqJKa|MD91hmQg@J0Pp`hEMKUnR z9G!SsL+!ltd}nuFFgmuMnues&gNvRl8xRg4l;!NB6Q2>Je36lngWUEWz2>>VvYm&U z+nNA6JR=PaJa!9QTQW?8lql3gK`ewL3D(;4SAC?Dg>N*3_4U{?S{2#Xp}Z@b}x)vJmkEclNf!QR{l+R?^=+pMo~ zNi_82U4n`wmg}(aD0@MFy#U@~ga#&gD=EG;-yjYSLVEgY`?oD<$bT2|N5mXD1kw4{ zM1nwL`~{N!CT0d#IyCGN^>PcAv=tPbzvJ1^CV1ub;+L@0)YQ2%pt6BIhgfLPy(I9i5x~t6*#Xq8wA3nt-+8{F8jOtj?Ox5cr$)e6@EkgPkoaCU z28o@WFQ0Y25dGK4|EJbk1z(mg<`qDeJ1^+CxrMnduUTki1_z{vei;Qkf74X%n8wE; zjJQL7{&VPwiHJB{qv#V73U=H8nJ&&?g%vWqy!=ZDQ4r+Kyjo5wj+!owq0tdQhnQ|V zo}Z`S=On%~{F0`$%*@0sW+SY|n}}cuiHB{k)oMYTFl}|Z9XMEegI5~rQ-r>O!CyW{ z9T4GouQ1t+9`DX1LQ23UJ138MfQXpq z(?jX-9WenNk&AXpE09UY+kOm1|8Ys9}?#m?rf`=nfBq%p4l)?(S%5mLK2H0CMgZCMSS! zNJ@!A?ftc~+8_AEOw5G@r~Y0Q&;%G^D8v=|EPQS!BSmV-{i@?P0MeBw;l(gi)YEhE zZVLq|+i>L;vj4W%CNc4sj0_?I0%r<)@8gLfm#HZw5)y*6<03r;1r1I6chQgP@$LhK z`#oWRItHZf@bb^UTVdFyESP+b$1AU0uhW`cvb#Z%vMaeMRS{_le`R5BU-}lTt!le) z?+*@)_NB64&ke@lo!)M|h4l88$4Z~+uZ}et&P7QbWnhfQ!d~)Rhe~g1Ya|8}|fUP_$b;=9`@N78VdKEPh{H797sA z4bL~sRht5KY{B&A#wAOj-)Zdra0#%E`bc340h-%=J<2X;H39xH!ygUweFP1l2)AJCb$W^hBE-sjsPPfv06*5`G# zfsMyQS`;HvQQ9M^Ta^}5CpNzUKfDP9QebzX5AxXAE;cd#qma9U5_ACQX`&8)6H1_h zQV0|>b0DmflSMPTjg2RC@*73`-<)KLqXC60!BGG1E)Q55P*M4<=bm)As`?r$yFMvZlJ)fVr zl$#b8KM`!}fu5ZD@-H$X68+GSxub`UzL+8H&THH_XD31Z_NTtV9%`CgJPriB*)qb5 zOc|QcGcbF=sA%2XqSDCwrf}%AxB-4}cq!G83ZJV>WShY3)8Ud@0rlVgE-F{umgEVM zWbFr7)7csnM7Ano>qP?su*21t!oec!0TV=A<^3r9?w#Ah3Wg@5sx}g8pT5~w*Y)+` zElqe-ljwEA4Iaa2#1_)E^zAZKAB!o!5DC&0qTe}f+uKlA>*i|dg*32TShO!0JSY5FSn zcfh#Wu;_JoNKsMe6dOxPG0-Rm;sL%;;_9yUv+GPZ^jV^&GAp2)V%XR|D z6d&|H3}25!&@r66SF_G50MET<@!QQ8v(@V`)J0(bVUb=oSd{E8bXKQ zm*=L<{-Iaev03d0PFyNO|9&8W9)Gpo)=5=$$^HDjwzeg=P2{VA6=!txvPMTwu)lA5 zWd&stLuRQvA1%dqwjT^rc_rZc~A=O z+Rn48$PP7C-p=+8@^?5)Ot()Dy@D?Kky(ituY-C`j&3_uKb3zk3~hWJ4k_fPf&=i7 z*Emx3KYDsq@L-iCY{bNFzkR?7nox>=S3&y2?%dRL96pcoM}h0q+_T*kqel=id%X(V z>zv=!8pg8(=ko}K*km<#AH*&aQ=Tby$xB6on7haka?GGwZ}q$&DffpC+x`7xW%427 zRH^xt#iVi|C~Lk@C5PykQp?!eOL?U@O?MzLEt;19G1_KhgLhMb*pI;H4C!Hs@PZ`> z`xr_kYXnDk6X8C6t{}rWbb%ej7L#&j8mr+l$F63sHK6{%dnWm3@SPEH@2~eHB_9zl z9|`k*{KydT@dj)1KnMH6HG>5)K*OwQ08}r~9ziGc=JQLKi9O)sy-6O<)Lmc8ZBhp7 zmw?Ly-PlMn+a}Ogf@P&JFpY+XdjMr55N`s8a=Ji?1pMkm9p|Yl03krH!(kA*gG$)f zaI%jOc^prt27W#RC|T$QkrD5asfY#LDjOU5(1|~kv;Di=^qcQVVCuC}#sr`YHnsfA z4+^j(aPjcW0nOa-a4Gjk`kvPSzW^F>C=7Ldef`kC+aqZUdB?u-;Ad}6*SkZk9vGBq zEFHmauW^p-i-Y?Yu82|t2`b!P2A`uDct+AHt3KD3FSlS*_ZzBrOjlPISh?#&tzlDf zez}KJc$4kzXdbrPZK9@+Cb?yY0LWNaW9a<)Rq9;~nr^epaJ~Wv;a6uXu&qE3pzrfA z0QU^t+uI8$M*#Y#^E=b$&Gq-c{DjVnAhqTh`QW%S0G`1fc@<#g85tR1c;^QYohAVA zTL25Ck}I{&V_C`uPdbq`tP0Dyv z4Sw6Ey4q+vi~!~8rb1le{QqI?t%JG_yLMkm=}+>;xl{fQaO zk1sDT$7k7g;P8!2&iiyJo}H6(4>TZMLh=)6!GUkx7k{sWk`u?pH@FcI60>phUGJQ7 z70bxH7^M(AIvUI_kBTCE7M9-isl>2EU}31_cx%(jGOpTe!q+RpDE#E7Ey9-KVw_r|2%P6ym0E$!WA(0!A|mPQ~!=$fcUnF>jV=5O5c2Icsd^P!oUQ0Pw;3Oo0!bUT5e4WNOQhFff^GuAhM)$_U~U`<AcJT8Wzo+C&UGF|u4lEF&NqE&lAJ_w|uQW$li-=)`P zZv6fm47`+-ltsm=NuWv}9~-+zoJ=L|Xc`0K^`1ll8<@4jo2hG3Pb7}<#m3T7`|;Bq z&J#QuUQkm`)mWx^g)}C13H3&sYGV z9;)3I)*wZExHjj95lXEY7k77tusV?1nl*)2mOHLCc)$Kz;c~RN_;+(?Q1Npld7YDu zCJbc@3u#pf$U-OuvmCZbv$CWE1H#(+5GXxQ?VS(M$TVK723UzpD-nG0JNxoyV%_LN znS!GFV*}Y>KkRYMD_$rNV3ncZF;N0fBFyixv9Ow(o9~6ziCbE-t9Pa#k=Jk71Tgs^ zm+ygX>1i)q*``)kS72hWHv`YfVlb;4R_elF(exib%wQthlOh7|^A)g-KEVaiy-P)< z3Clc;ORcP|9*BjceGC73gAnucYuuKSkVqvFvxG6=khg`1yB!QCc{n&4q=~lf9{T(E zJZz-XCPdtv|aTQMp2mk?6CRAm#WmLAMuK6!VG4s zfCeL}aB+6lJ*4S!c6NRd!z>C5KnHM(V6q$R3`5u7-mj);YZ1I3yr9h(_rA@iq~w$T z)M~doF+I;^uoH8@u5-c#`bQsAM8uV8UVuz0T)~h!#kS`Mr}W3?Enc#3RPlO-ZLeGp zQL$gYk$Qz4?dmPI7n*sty;0NNt{9>w8MdDeLV^lv5OxlVP`g%SWEh ztWTV6wcFvKXn;dDlqQKu+_Pc{!o?gX$1-zhJ%bGI>r}N9pPbwgmV@y(fovh4!R5hSdmF3YZ zWo4o(G28fX1VnVqoc#Q0(9}>l!Cgo zz^!19f>Cjz33OzuK!w0&GzT`O*=G@mRx)yOzNpaoS@1_TZVo3}Ei6&BT>Kru#Kd&+ z);cDi1UB;!Bc@)RHe_1+*t4SGu?MSU3+ z9jz}02Q&N?20t7?{>Wmur;~iPn5z5*YZpUGT-@&qqqJIB0Hsu-qoa!+3p*dwO9g!T z5|A-A*R zz>k0pQ~IMUeO7i8<(7~OQRLrWAD|{OprT?tpGm>JllBTp`Nx{R_N_4Wi^FJi{T3fz zpH!!v2s;5S$*6+knUdsU1qJKRpHn(7@i>c1_)>)8<0FyURnD9fmEUS63*>eUg*ev= z6~*tPJzvs^xkbj<>tx{*;v*p{FK=RCFn*U+(#Plh13G!GrRzEiFR!n3bkA2;RZ$G& zw&C0&`79msJ7mp$(1KdvKD2TTVjyG;;Wzxp{YFWm?g@K^kbslZBNmph0?o^=KhDDh7;(ey7-Q6PndrZp%}PA|RB@CM591tKcIYG;FqDuITIO|6SIKb*3U1x=``= zD6zJo`5K4*Dd=f+^6SiL#6-$(2KrkmUIbO(eA6(9{NR-|S3 z!Yct{njTdnDuRu*wJxh9sGm-uosimai|QcOV%c*KwBlc^ZiS$MN)jsz?+GCfg@85k zW3{8wof+h-JD(`T&f(g_Ig(=l&CdTHW73(9i77}q_1jK^k^XS*oA9Rw<0;xkMxgC; zgLS=2ypDt2f9m+?Xu8UQ%_b(6QJH28=e1jpa)lqZZ?fyv1?gwkjWLc8BzF6Tvtmi~ zWCVN58DGo~KYqlc6R|%O@mOCSY~|&xqNE6VArrUIy5M|Vy946;WMPgmlRv2qGbFz2` z5*0-0RUinGkhX@|g6`>Lwa7_CN>1(vEG|ILSy@>L2nZ-dke37u#jEe{s))2Y;8-JC z&n{w4;r@p{#Ax`N;_VqbqlY%nxvXiVcbq^AP?%QeoQUC$w${x5?$xW_u`!Z5?#!o& z;KvgLj*j#dFa(Me&;R1nV1?57V}*0SdGp4@!-GWepka8J(49>GbuZLL%*@O;>MFb? zk}VrJ>O;BkY+Z&hbhi#+VIFD$E|s9?($d;K?w}U>&P>!6@KNCPH7$%Ct&dYP@M?9W6wZYW2e z_%pBgSBrylM`YvEHS3;8{MqcI`N{9F(zh7+ zfP%`i$IjM<+nUUI;EwqELtRo*Lh5J*fl`vF6%VF;gv)4HShgwlo3%>KZ4R#8WKm^s z{d=h9{xB-e_6$cw%b#A+y(q*8=Fbj|Z!|bN`#e9dFh381_+*~K{Y`H4dcz!q-zPS8>fjEwk^zl1AV@(5Azks~Uw ziVE{SdT1l1ucZRirvPdn6iZkYH(-e1r0;gPM))2bCk&m`!oPr10;Mq~Apz5c&#;H$ zB0L=B+YNgws3C3MVIWQXHdp+w{G_w8qO9{^!V z4t8$XRzorr#?b{X9!8HcoPyL&RexwCT@usQ)7a}H0FZuNux%q< zp+}&jgGH&p#aZlL-6?V&3fpEK>&CHksv7v5!bmtM#DBS((bjs&~EJP?lD5-tx=PmRq-BBE3LtWF`s(O z8(jv_7`3aNoi0g8mHpRkXON`O`s@C5jc&E=g;wW4=1CyJr+vR^|ZWwej-%aL~C;>6O1pA?(ZzTHe)xucoqiZyLHpz0Kpk zC@UVKSZ=}$bCL1zl5V9WCT0Xq3JzP7?euS&1Mq2&wr8#r9@?f=L9KFGadsyfJiW@^ zS{u+_=uH+@x98vm6*d_{PYo)dkD#HklXqS5U3a;lujE0_cXy9Cvkr1y;)NpVrDe_1xvrk2Vq4(j4fjL<NVY%ixUv)J=T!Xy4 zyz=w&0oMh1ERee9W@nGWW7#j_Aw@5be$ziWdB%T!a`6IPXnF0iS=*=Zg0jhKbWB03 zb6&1jc-8;t#*+^?X&TzQH$gblrAVdacCm80gdIs38HG$79A6$q@Qjad#Q|sen@z>( zDRh~WQBXCH515%)-KnYEkD$lu?tVH`^R+zx`$ka4GkL#IfhgqN9PQ;a;dt$36 z30eU&dq>lj^UY8qYJWl!6BmXTePP~uqZM1p_sfji)g%~$j=H}zunL-udo>F$_iDNA zAy1VrFY~2YXf^FF^iy--;}dwl%#e)IQM;J9xOk$?3Y0OJ70;?69PNn}Xkr_WgoL6` z&(2plg!@W*_vZ%{{!W;Yz-sCnXWW~zU9SIPonG$G`s%x>TDMDZ zLJHcd@>@T!e-l}1o-|fg045@2{`wJRNqMX7(|wq>u&8{;BOq`kCmI2X#2#V@3eCV> zS=rR$oq~{CDU~i|(O=Y#M}Ba`eSn5RlH0k4s~c!#>OeZ7rmP&iI!I0VWD=GyJ6>K4 zPR@Nl?Daxz1SwP|yLG9Dbl93Dtxmnk5$mJWs+B)I;K8$Gw6c27!E$8=O%H-Q+FRm? zSO{Ar#Mv_yT!3kAuy;6~%zyWxyT$?8x5P z*`1dcYPizmCoK0La2F~*Od@{UlL1xB&s#Womc9RNm_Z zu;+o-fxWA%VU10fy1IZK7|Xo=cpMlgPfBW9Kc^?t(Ke*SdxBu>;lky}VLWXF>GPhmh4z-LLV65Y++Br=s}yx7psQ>6u{*ej@6f zuJYeTbY?M2(G!}TdDD&bejJ{ZML(Jge`2X9=3$SwJg zm$28s*SsR_Ps;T^(Tf5mg zd`5V&iPilhG4WI<=i6G9+)Rwd8A?h1ZFKAJZgV6!;h-<+9K z?g;OD;V7}JEI1}#7N{SC-~5o5_i$~9BVPFY1rqY^a-YDgTEh(g?dre%w9=!i9D13O zl5tR4`+CnGF%zLXEZdwRdA}cZ>p;T6O2I||F*i)uv zVOW%ZRA1s$0FW;HPI3$omH_mT_Q?nNj3VZXnwFaL*5Uf*`mp-+ue{Hh53(DWGD?$> zuH*_8zreV8Y`W%|&Gc8fDA8qDY5*)g^b`sh(`1pEfdc9wVj6C1+dSp9y*)l8q^YK+ z(7I&PiNA9QHt4IH4rd3NuX-iREDCBpsFit`gxyvuY}ot!-CPsJ#rzTlZ^y0z`QZs$ zfqFwj-$EcUTfU7QkF`|=Ia!c%(2EykPn@|oJEFZ`r5u6wO5c=O@tRM=aUT^k-_q)> z`|(y(XYBI3I`{gCs?qjH>N|IfeoH*eURBB8*gY5$wxQ>y^L^*1SLGn=} zwy!OFdv%aaSI_%%B=K}5;g>{;#KemSLe&@dn`dZ2z)_Q|DW>)Zj@^Ka%SnT&Ml`|* zZ&hI-V;c|WQ|}3;M;_8LWFyt5`(vskTKxT0G>FWzz>cbBRZrY%jmq8lD|wM@00d zXUJ1=x|%klB}CBrg793H?NxGhbUCI!)6iCeDs^&xGVb{cr*_ z!N6?e;c>q%-$$ae(vI3Xkxm?5z~$v$_TaIPFUg`W7jkya$2g3_N^dea zxfE?|=CZf_{M61*Iq0s@3Ifmye*ZrC{#~y(C2X)yTd^+vYbJ8!=GiW-a$8sDy7Bu5 z$cgQDi13~c_F2#`;wL60!Stj8swk2kd=!vSQQll&n3PmjR0IYE;gE5oaZ-?xo%OzV zlrAx7lM3OVUl$ykc8B>D)4;&dLTjK^&qRAb5RTc%_p01np=I3#v&WC;8ylM_DVE;V znGe;tw4q|BHt+O7KeXA`C+@>%1R{wsNy(NR^|JWU{O$_(cZ%}(=5OSbN32hFet=cx zM{H4%|JC_DBeeIFFU>wTHY!kj2rl4RGpwBi>O#nj*@K4;V{L{fr~54HL-BxaR9FiL z#>B)(m;4!w(hIe~XeXvzJx0O$@cN5i^YaY6)%u-^Y+8+j9^XD0s{S$=hB7s+7FwbA zNa+LC(5C#9#7{0x_aV!G6&TT=cmc>vZeCuj$gLM)>8=!1wfpUNN8`Eb1X#P@H0)mQb^uxEd2Ua z9~h@l5dlMcBsZszX5|Y4rPr0>ik;7-zah$4e}8{-b0&0EO*MwWDfLW3f*bmrAiAg- z7<}&OgpFpYkih$TW^wU7?>DA;_r8e}GNA(c&0Fz+w zf|_bb&T@f&7F-RhFyd3m*Z7v5UFLdf?M%&%tMIqiidiY0qep2r`&!GI!Y9zX1Luw2zN2>pi~8f+x4A4jabLbPm>%&wZT$TC zX21PevTn1t_$`(#!W!OemEB!T^J&+F@L6I?;iX1jDtr6OmnrT*b&3sgmvMHljR=0R z9r>^-k-unaO1Q4v@lW)ld}%RXc0*1Kaf!yIN&Tnxbi?e)Qg>+Ty>qLD4XLow-D3w_+?3p} z!)o$Y*Ru_93VS=hAylW=mY|sZa&W-Q#Mf~8<)DZW-WnDR&6pW>f&&Ev?V0!AcdSV&DGk9CZMR?C znNC3OO9y!JlHwzqAbZC9RnYo!^uM{HGnY}{J?Vn#Y9aFd2Y0!73aUM{)YR7QkUid5 z{~Iuhh{QuksMXq9`zcH%HnxtCg85TXji+Zw4#Sn0%&+y~VA)sxu33MVi3y0s*^t0? z;BL9+Xn%f0e|gq$+e7v_BO{A%@u&Vi&m2Qy0u5X&ivD!pobbNCxYT{=uauNjO-$aQ z2l`X!O^LrD6i2Qoz|F{)dg@RoGOK}3#%oF<8n%%`FY(~P?0+W)T-ZsKnV_utqWcl% zUmsG|$Df`Cj*njz6~&Qtw%f6lsWY;&O#PkXfD;Vx2B`^`Hm%U)BweBzkLW%d*#l5n5p)NSkMewkC{ zb>`mpJnwGk{!-!ZA2!^lO@&Y+_pEKJC73amwL#WH=EaA+?_J-%m(nsaj#pXCkS8Yt zV3?_}&Iu9mW_qUw=?||O=jlCGpR3L^{TRh}mwk>;fM>+~Fg7NZ_{-;kB6l~Vxxt(q zdkD{JY;=;8yaCZF|Kg|VFeD_X4hc1TQX(CMChdtJX%-$TLyDMn*~w5B^c^(xsmIr&hF!2qM=2j2!7U4kUEE*Z}+L zRHdD1y>KD*Sh0R^Y{@<#&?QYSqvxty=N_r_2)nHdmT3m0yI<%XU0ZMRR!~=95Kq*O(v5by%*dkF=7kpQlnU>Z- zj}NOZi0M_qY7e_;dv@lK;prYsej&yTTY-}k%u(9*3$2@i4wVkuJy~~nFmL|#6*Vv* zV6J!iNI7J@w0m}E4*V2fJR;D-B4VQT?Jk{T>0azD{uLGyUTvKr!@2=aUyDjhOKWM( zGbT^*0BHfuqI$sAm3I5}*?M`-V0f^;%Q)}=fY z!B7wMI#18=!omO_32`1CO3EaVZ9uq(SfQFQQ#AY_FkViAD&!8BFHkmg27#?4!Yjm4qzE^a;B%Jw|=68oUE&B zdGEo&LD=)hJ)0oo3eGjXs1%^1GX)tlY8`B%BXF1k2l{yV7o`3cRQQe>pk0mpP#;(F zy5|mEZTSp-`wfz=oV>hsP&moS%7Rbl6NLakRt~qO1RWe4vSdw7H)7l5c6RCL=wO_2 zBZPYW!3X{TVIyd0Xyvx6caRCAC*fEOR}BLL$DM?ZrU;H9v$hcoWqW!HGh;o{B)L^=QlHrf%l9{>(*A)gWY5p(?kQRMhDy6DQqUH)# z9#K&Q>rDvk8eUF~LHIo~_o1o_GBVP%Mh`_(Pk8izqu&Rjm25=Vr8?-uRZZI85Ofq-O-%J6Il9)mb7Y|e;E(bw;Jk+g6vBPa~Hxk@Ny+@ z_|f1b_Xf2qN`zj_CBBg@JSuoSV9~)PVZSFLLVejLjrbO(T(DDuL-ivTF1$XuP6sRU zIh4v2!Z+edCjV)!!&{3l6Z!G~Y|PHGn@{o|;9-8E7P$hsVO;<4upID8l0Xymwn!HR zvj4(qRG-;ScXVLTk_;6BtOaH_ac{em#JB7|L+`VScB=tT`49}}TGScIL)w5y?~2j>jKY8cM_ zkbU%`)G8f{s9$VOaT$9(u)_EjK4vu`$Pht>*jO~6^f)V{HLw0s6=+_sPj2vA-?WayUON@&2|+0|KTLT%PUZBlfwTjGC~Q27`v{^q?L9)f3rG6xZrSz z@xAMt4uMx@``{xXlRSZ`HHt8! z#}U~YP9%20HV~SC=LC6OA$K}HC4z!j7??}l2*qiz%G~5jCffXj;_oAVvyki}yxrk~ z&Id+Dh1Jy;P|~H+&B8j}g|AXyZ59~Mc&&uI!m;Qd4N z7e4N*(=2&`OyZ;&NQ8pal?@(+@K2ojEgiA35fLAepbVFM1c4-;%YMdw@sQ^Ss!-a} zWk^JeQ*41{0o7T^aYq|V2987M4t5}R9ai4-Ke}tcqyV@q8csq`ftng`G&(gih`r~d&V@^eei z7n(5SgfTEjwI_xcLHr+gbfy~&M+fN3@jkaF5?tels{?Fk0Ynr)5>^GilN321TcGT2 zEFLQ)F{@YS@|~-bCrR>AgJ3=eCZ^AU7cZVTG-ooiE`upt`xmpFLX! z6|VmMA^>_obER=uhl;EeVr2lc4xx69`3;q#F{#BNC{Zwv2REQ0&66m90?}%?ydcmq z71xKXr8)irkTsBz1-0D9BB`(D!b!(8miQGD6C?X;rvT8#vTt&-FFxwpV*N;caKQ?Q z2Xca4xU7Xes=%vP23%E_&Q04OeFqRiaVQa(9Mi@6oj=se`ff8&n;4Ab2|?zgw_F>R zaxOFn3VTXH1?$A^gN-8UYt>c?^LFx*5m54V9ZrKRbZ3&m17txyBqL9)IP5eFJU_JWV8`pU>_{$aw)<-!TbZN{}SK2ZbOE<^Pku z>PQI?2z`D1C2kf`JZOL1xE^mX8eL}EA~b+E;?>v_Q-b3Nx>wFoR|4NQ2q(ZK@OlRB zfAmy4#LC@_tS#@Jl!EyfxEe-HT8D<9VBOG=dk^|z0|Nv7S16}c0Of#zIIMVKz(%`$ zGk4FI2aXzurXfcN$kfnqx~_4_OWnO$Su(^-9so}3=18MyeJBhYE;Mxx+|j&7Z}18; zh+9mL9tHQaGtlkZi_j-IsS-jeCCj6xdghkIWC>?T!;JhSnOY0STWAL{++$(cTv!0o zjTiHYHbG}kkHJ=MvzAW|LJO0tC1I|Za=c>(R{gvz#!`g(6{?&q5~DtDuNcCR=U$wS zLM|=L^I?w!aX~>JGNiVC2awgj2okSZY`7-#qp&gN!m$820U&s=g>?@$mjs>?TsFb+jQWt=56f|sPm!czZ#EV~;fV;XvwI-?(f6OVGh>AlIum{NL1*Ny|bj%0O zrjhkJ7Z$jn7SQvWCB6A<#7_}nWyb!7iH5cUOGctH>^nO*4_pGDh2Kdih?b>B{`@%u ziv>dlgtF?j;jD1mpMi427ej2*)XZ#rt)mF!aZrncO`Q|h6M4Be#s5<+yu1)yh1T8G zwZq5EYzhF798#cX9vHuDU;}fEXf<%GQqQ4Z!_ z=zNMf!I2R_>fAmOW9v7uFt8TB_&Q7kT3(2)k|H??=}1Ne<|-0AoEL}|78Ve)2FbNg zm1${d(~6~i&crrTJD|ttJ1gw8C!wTt0GYOhrG*;MiuKVnF*16pbqbvYgC;+0Su>Gk z*eKxFyh}{%p9tMR@+?w%P>~UyeRRIJxw^V)D*xn(G>-y_F)0iK;6!Z`&4$HI^z1pm z-IC;U_ATg_#)&S^<@P^^NWZAvg98a&h?y<);+cK2u-%KS=Usm_02xd+&VC51GsEG$>1ed|ol=P#h!ra9h8aT`^nVtUPm21qdP zHF*NQ7n40bJ>6qp{#=J(9bC5(U0L~f@RjN!yk4|LjeElpoOdAkW(}4sE+S_5l!Q`N5>!?R)B8A{N5L2zdqn0xV zlm^I>jfseWelXCgI(m8_rS|FLj9+*yY~7YCgV|w_n5iZ@4~7>wVV~Ae#Uf;%UtPK^ zMSH-r^#+Vh3JSW#o{5PXKxF}$v9A-!hb79^9BRrqIB|BRCnZrB=5C4O{gpJB_&)#4qzr9n^IR(J6aq504!7_ zRIHWBihX$U-~s&s0TZC12Lq7KH~95|ca=e;j>r%|C#w$U zTMI}AB@z|xTTRh=jNAgfeug0eyG9#;em$3wDR!a|bcDB#;Heo5iGc%hwk@W>pI#l7a-QVdVBpt z;CePlG^TMHzKJJy*XEO_r=>;OXP{+b>R|rO>2A{37kv z)d=V#-HBHjyz6rAwiKcjr~XodmsMuxX2u5w3HQwDghOi_17>qp}>pQ)llFQvKQBdgerH7TtY zt;o=Di1?{QT2!1U=>xIF4)_Cegu)S-Xt_cTGi^+Wx}=WMBUpBIyZQ|R(xGV?B{qypBA^frwyb_qTc%wgy4BtUl#tvu68#N7 zVA6-el5RE#DgRf!96;7~Q%g<-*x$peLI#he`-!Q-p{S(fSJR(L@9y2!5Rmq)fH+_} zpcTXdDGQg1{pqjCU+Vb850Ac z7y39_wG>JkruzCVt;5JSe5d6b@7w>MeER<@M6KN9M=<%lI*Gu}{jyVDE*{JJ7g+nC ztoj&CY_qpFHoI+k)!?1_Tbg%v=ZVloRxB}jRL0Mr2k#smPq*+Td~bYp@`wE8l}~VS z47_vcxgR@!jUJxsj2({)vpA3E8uxhX`HEjq+-lrY++9Zptj6R~v|JAjTY>CPsE;q< z^iQ%zTu+SZjuk(87UlY43Jes&O3 zcKl9j=JS9;7Q0bSjuG&HfSS*H1#+`i@R^#KPwidqq-ACzmyWe}vpitxI65**Io_s; zS4j~Py`37tprN5K539tkdYO=B9kg7eFo;As))V-W++1JBDgMQcAh??cM*z^mMGdmD z8bS+JR{E*qF$`4dIU>>N{}V%Yjre=|!tESv0n|bsPaM0+r1fld)4$aS7pLZdg!(fl zXFjk&oz_Pd4{TTBr>AT1e!nUz0tipV@-i_#b#JdybDC9+Gbqhjg>7@fGX}B18UP^x zeh2hlzsil5VizYxMC!dau4w)9n3cy4NZ2_PUp7~k3~Ub=nx`k*jlus9fDiV*iQZ&M zY+`B=DP?=}d`J#>#LOIL;?W#Ds~y1lQ^T+&2yX1`Z)q_0gOh6S@=>H*PBzUd5(x)4aSP)OsAkx&DIgNl98(m@ak(<)*ta6QgvJS$AA!NOAD z;(8(TBKq&&3BC_YM|*#fJg%vJs6!;RZ%gYMwNQ?*hkF|eX8N7G-uLep-a}TEmGJqN zDFnoZwvdpcL=oycge{reit-VWpTCq@q~u3L{3zkV;=a=&A-VpDK^t`-Cp{;CR9;7C zOlt^tlcL6o_6vErGmjYB&Swt2owD(RRXtuaujMO+)q>XrT3Q|lD+qbYzXk`JFfgLX z>F}C+VP`>`FF<1P$$TCZy#4Oy@1{mEDTU8rHewEE^&eG)g+M9wvVWM6h`?uLdc5iw z8254J+v8k?Hil6jyDuZMjCswms;c`Y6Z_R%R8;cTM~Od?SlvW4%r(W+7n=GKO23fi zR#I{`(f2Jy+}JSRo}S8;rwze+`CXH8Yo*+AD92dPUdb_Zm`^*R;a#PKX0@aFApNnY zCp_(@sQ(&u&>+QN&q}tKW>*w5F|n5N15V=uv!=ki@#EuNbT8fhl=^mu%1W=~ehZxJ z7k0^qH31jnvCH;!GmCmqN7BqCejdGCM|-bf6ek@m5-(ZL31B~R=9X3Dc_6;VH+PL* zeF9pv=RGNW#Xo(tn;O@E#z96IiU`ueoeo(YKim|N*dO?|vCo^GLp92_l2f$6ASZ8S z+1u#6CytTwC_9c{(B9wHR_-5ZVPkiO)<=x&0+ADO8`}&;nw01gt{F@F~Xa| zfJ*+S#%{eKNsvpS3}pBpDFwF#Jg(Z;M~}O@q89)D{ra`a*u*;b!b3Z%s?@x@3&;hH zB{_c;FkwN`8_v@u_Fh)j9W`EFcG@jul1Z_vdf-^cpj zQ)$@?RIp>ganQG}Qqm{q4wZ;|b$@+5=GM-3IA8|4#>OB;ctq|?;qzY!O|fjZ35nr! zQDntKBO;=up;7H)bKf)DXtKO0FYm*@wv}^d`E19*?Z1^gn(A8tHJKE-A zh#H`bzNQ0mBD9vXeq8oK%K?1jrOC-uC1fnsds~D&G~v3r#7Zt8LC~|XpuT&zsrCA6dATEK-ESuBF);>_X#c5} z)Bg-YqXEiAN@3@y(Cbc29Pk%wL#1|8g?iB+NoH0}9}k_4UrqPOb{%2E~7$ z*~Sx{Rq*b{^78T7;RlHR?fnPl2-O8=6xiLNqYBLd2-MZ|yNUfHL$RUf=i&L4nyL-G zYEvfB9jbpno?AIzgYn@*kmGYgC35qraIXdi6zofvbhWknei|!6K?f{P$g8`&xY&S* zwYU>(V3fnC30#rmaVMP+#~~pl1etv%FXQ);8-m3ZqU14Z@06d&G&>yUC5wWor z1DSzYSq5<3^CVO1{`1Zy-lqOF17J9rF=drKr0~9b>N(0b0+XhjLDgab#ts-UB)GWLb90M18k$aS-{u<` zDJ?3}(cAi1Gkj5DqY_44=QzXw5dpl>v#5YC>V-~I*U(Mxm=GUdN73odKOSnA9E1(5 z+pY7)@W~SH+I-TiI-=)`T}QkC*PK&{!8ibqKrs(^ekO>}T9A`<2HrbVmNZmUxDoL2 zDzO9a1+clE>>x}Z$EDGHW83aaHJ|z*=rCPpkL_LZM?1y@2>UQD_`9^ks`m4@_Tulk zsmh|~$QG|(i8i=5`PF1)0jb>dj=bW(^=cd3Adsl+cb6W9?=OtLLOgnD=@$y21 zgnN8=VkOKTvaoc|@63U19Ssu$V!^_SjD~W`3)!Ll!%J@hgE(aQi3(^q(h5{;{ZKFA zXmAM#3?TVL4Mzz1|Dk_k+poaHDvs+t+SF#}LdeGW{=277B_xo^?+#PL3z;+g0N|P^ zw~x&s{}}+F&tK;M%FQh+gJ}2ve7zkR1x5IT5gONwU7fV&>MSeYz8-Fja{;DWJpGNW%yz`eAm3pXzy>8@=Uqz``fvJh>Sa^@P>z4 zy5u%M`}LmGE*>1%?=R71eLYmIJg`$Gi9CVO6ChGR7>r@#9sv;{PqL5z@Fn+YL5K!P zUVDeR;d*@Lrb|M@kC=JwVaS^Rg6P#%QcB^VMp6NRoWkL*c)9GCZ-7z56=&|~%!yfx zhAyAP-+y>&Lyx?`Yr*@okin(!(~pvUpx|(Lm*$sO;cAv-<<+`FC{?&-7bBNLFV#?& zQZV`l0y4_(w+HG{7LzM$+r6lN$K01fMkXtqv@G`Pomu|WrF^6CX=|}l`?&&9F%vIS z%sKUC-ipUn0}llfTLCkY?TcB(tQmr?ezNnoQ+63d`h8_=3A)qO`u@0jf?R}G+i?jA z$D0$!Kxr0<)mi+qx?V;7sNk-s#i3#zJlz2iSWc z{HCZu1i9{8l3{Oac2@Cjn0!>^P4fl`WEF@SRggY0qM%ZDv4{?d4pRq5=8y+P`F7mr zC%1vh)xlJi@6wXs!9k^o38#LCqM906!so^Sa|P$h?(T%wALt(m@)3&#*R&&Yas9OJ zoxJe-W-Mbs-z+O5yOA6Z5|OhJaktJr*kas&f zRRldeFR1hZFI%mDY^j-EZi}sMHyQ7?3I!+oN_tuY>UH?!g==Z$$n1c4#($*#c-r-0TZK>t0DVM%_ZO7xSIvY*AUq4EV8(+pi&R}6# z=yN#B)YiyMRlaTz#w0#68~qdp2VqUkx1yo|wo_6i;fiY(=#B0D-DB@`WZIi9iRaGz zTM5wso9w-*8FtNkcptkGDQuoS+n}4^`QR7fW3bSg9TLhz&ZBFs|9~#uq)v8kPt3#m z#d_pu!TRX865Fo0V$rAKk}aFg&g*8T+A|zdrv&6x=6|@C+*|?cbUhR91{1OTDb{~+ zeRWCGgkGeFT81uck{`7&t$- zTf6M)#uahgDR6OQXVhoc@^i+(AZZ%{nn0~Ikp04@%ZrYS^?mLL1^<6y=!JY#VD6k>oP zqg&D$sGesFZI|BO7A`K}FS6MA!UJ3`v6!Mz>_3#n2H1amXPdGte*W@R*{ZNz1@rSR zrk7FF&5E+sy;oFB72vAiWLstk^3 z^V|M~adB^}>~$o95k(O4q{?W90pk3Da*CU0m&={>j@RkV*jTTX6_TKxZt=9Qf7p1r zRZ#wxMJ`+1Sb^4yH*W@QmODZyyYe9;ZS1a&zpleFPU0YVA>H?61jjUnJdL4>fc}M^ z;^|2%I2iyYx@p)OGfWX37xyK4xJVL{9+{zUdEKSc!r4j3|F`T2pE-MA9nz7J;r5hw zUXwi=UK5=-p3Y zRCE3dg-%?4#3WIvG$Fn0#Y*8ZOWzUX)$bwX+dUQoZy^S|he z3I+sRn-jH{?Sc*%b;)Dm-BrY_&8&OjXAi0eN^N zDt0&yg8g_|L9kydpqVLYX(J;a=5-*%-sTjtS(5#|1C;@2bx?7sH2!iXMyBAhe3Whc z*)aTWvNW{lYNoH;{Svt2Pn|iwyydfFisUy0@9g2)s>z2YK0R@cK&-LfV}2w*8<1~H zN{WUTI$1!YLq-nU9xo_4G2&xE&t~?k*iV!bKShyTpYl0uevXck5WZV#y87d*Z^M1{ zQI#F+C_F-zb5DudS_vbQ>nmBl*JkFT4L=c(@|_*E9UV@07uqk+W2tH9_f67rG05FO zuC@?DY9b>;@&;>VY?rES>v($%f5xo4HI&2T{maRDu6IJtKZDYB4Y9ES)f;1C!hVn= z0B+m!O?4&TT~=q`hz86aI;G7oypkLNtbUBI-Hg%EMMXtXNJ*zXw%O!=^)0_6Z&;bw zYzdAE2~nS(9(z>u&DGU~h{a2UWctU%XQbPO{+pf%gL@EsIl2o6$8xg+4%)XOfunkJIS5q|!5s~{ld6Qm#K|$(Z=+-mqrifSi zrcUhA{<~R%o>=I7M<+6g@+dowdh%;0*w5n7o6xfAw=E%APCWeZ;Y(&%wvrqicTzVt z3=|0o4@ArKo^1%n6ZFX`mVBqlL9|bjjv^rTN2oM3SgJO}72+;sxl@NWobjyhGlbu1 zO;qgfrinu`VIz-q?kQ1-{QSZ~#`SH`blKV2!3h1v7Y&2UM(mji8~-1d9#S$I6y8i) zA3oq>Vgi&oP1v+mB@T%YD3uyKPJ8>QsdKHZd61~<_f9ot|2kH5m`}V2XxF-2x)I|4 zi?+9bs&Z}HcEv&o0YO5#Q&Q=W4gm@2k`ko5Te?e8Qa~E%20>c78>E!(ZuZ4`-|yWq zzJKif@4f#q)>vx|g*l)3%=@|TE6(dUyFQ_=PmZijz6kwUk-~>;J@a=CegDvh{KO3J z;lu8^50Np^O*(EX0HQ2#b`kq{&d>bP8Yk?j(h=TA)Z`sJ7B*>)voiA#?{~oSuJ;zM z*AD;bg@C|zhXbY9XbFzZQqE|E+P1{#ISRd>Q7Wn{!~~%!39c`1 zwIQwW4zlpSMRIEp3{<}d_IY=gP;wty1`r~|M$7zN95NezaPF7n;xfKV2x_!rM^t9a zTq!As#2LQ)jy-a5fJA?3osVI@G&V+aZ_<8P(<%-4NM7r6hf@a@W#ivPq_!s5*t&Ad zz2acu#yH`Z;#KKyrOVVttASTk+WVdSC8QSG6H}6G+@FHvKVaK^@^sB%XYN!cVUol2DC0UK1GbG_ zkK;!PEIb^JpNp-H-(ZQjLp_cS5mnvL@bFw`cn>hkjl)~kRxbnahjW@US=|UN8*^F7 zn_$Z<LQd*mpv435JMTOd%gb>5wP)eh|DSXS>DYmj>KCVOJ_pplw@Bup))iBgc_ZRq8 zM`brwGjOpy+jMv0L~5?3>Fi*+_flFx!AuItmh{Qpao`FA8#Xq{_x=_F0#s4>+uJ!5 z<#h{m?pX@BH@);`S&uxeoSz5qTx2B_N15*gf^);e>mRMywW~-OkK7qOdFzsWZXazY zsaHTa&HqPl#-7LSZ9W}}8vTp%lH|K$B9Jk%?4zK60C&)@>iH5At8Kr0?|yEo-<%Y@ zE>aP_PF;x)dz#7xrguPU+?25>2n$2SR|)?7`7I4FN}-GJvHNS z^oI0Eyw4v17!nKEB2$@!(+;vmG5yAx^&b~g;sUt;#j zDDJk--As7z^fVSd)Gq-Ubbca%omUQ`)}h;F&4qbSlaG)4RAsxk7gH#!(Ru9;w;=8T zCAWiQd{O90#F7~Bl zb}`~-TcWA%?%DbwcAYTHdV%Mm4&Sr_*Z;*}r}`nzy%Wcu7Po7;*yp@1R{@gSH5?cx zDIw#&GqX=z)YV25gX$D?E$_7mlTZYlR?xx+>Mksa2rk0$IlI-@hYw_SRmZ-(>=d`b8w5j{9&q zi!PqK|McQ6DKTTWOlM%amRV-Wp`$IH7)b%9CKTu(0;ghQ+n*>kiqt*~X2gh&iUJUK zQe?r_>r4PEbiZf=@$M@qx~8ey05P;mTVlIdzdioqSQ6`RHE=?pmbVlE!bc8p*eC*o zuLA;fYM%U4w}IRsy}bOzx8w8m@h);e4qYkAy_DENhJuaY1^quS3Htv7+f~X3KJEYX zpop#8$BxgZGOvjqp%Eq8+8f^CuLp26M9XF`(Ru%2g}{I&hvjD#@(cW}vol6Mr~d18 z{0-ss^ulYjK2GvLI#3FdfYwS~{fw99SNDK5%ORZz9hxaefq;8EUh2 z)m@GAyIpZFwturPr2Nx|7^~V|uKYEvDJzu=!}EYe*DWr7tfvRKtI)lqI$LUB>qCQT z2=K2@u)}4go>n^BN{NYqJv9{%4~~EUi~PXU>l6zg0CniPu{01)HYyZgAF-_ecs0>-ny6 zxIW6~d|c3xqu9R)NOKLfrDC^QO}U)P2D`l>|oB{w(t;uzgm2if3;& zkOqh-$Ky>6mz937$o@jj&cw_?Jn$XAiQRU&p35GI%w=WIuo8!<|N6fDI<%r+S4@72_v zmcHZTviSzxEqvKT@Gei}aysueP%9Qs9j4yU=bg0(v#4xqTX32&CJK6VL4vJCG2mfT0}D4 zAqfrvv~r!`SR&U57rGh&q2Sd+F|XxEgf(E?qM@w~J{VKAH9}qjt!-%oumi)P%H-p7 zF>iNy@wOff57%JnPub9rtA&0#2{{bZyoa%C?V;u#ri{^}r{7Es%1j0+mRir@fTIfz1}q5rTptb-m=^G&Aw@^U zzEM?_Y+sC+vR@#CHbiO`9t)xGpVcvGQ%9g6rz&$wlwA5&pgCpRU zXK)A)Ohg>t<`q?O%q}iYDSx5f(bE^8vNcqYG?u{8Tx%cl`W0KP6)8M87fU_TA)fg8 z`N#uu0ME#nRJ^hR*ht6)+s>#=^yj(s>gb9fd)JQwjalH^`3qqy+nCh`G zF}O^OSB?)+KY}bIXmvGJULGE0c=V*x1=1uh&(vk&an;moemHsWfyEV|I=0Iy0nph++wQAe!S+4kfYSXVG(VvXsY+K6&-Wr;^jzA$}f zXwXuZgN}r_x|y3p+g$B~KxB99a}VH54QD4XV0^biRr(Fq)km(eTC0}8d*oseGob~C z))kwMT^Bpzyp=a|$Njk~i~mFvqqw#fzqS_hPAyN72F4wp;yX_?if_pS7)Ug7t9RSp z=#Oxr{f}RaUFWVxja)|Wdb=5`wl6r|9k98rq~6RSAU%1U*@eRtjv^))x_YP7h?;_m zsKFjt>2ME&TrM__PQ9$=&zV;)3=oBnP{gsc`4?eVlo+*zN>NG?)VPe$I9hDHWYn5T z-(Mz2M$`T=ndWl1s#745bWezkeE0k@e(dEgrSbcPSN)z|OoB#?)YMtlAMRIM%raIO zzLYXCsdU~KbKDruH&H4Mq4-41yONa(sC}2>XKW{r4^njRNynytq>(2hV;Nwg5HWkD zVQlbCez_Oiz=g`C@VNL~l^3((95Ofj5a0*@_9Tpb6M0DO=ve&By!znaBAj@Z!&LdK zGDrfQ0An5qkuZDK%5Lb1@-~e?Mp7~dl$frJ+ObK;X>VdbeyP8x;IOubfxZu2L$cPJ$l^}8q5Z_F5CI6)al`QvC;t;*>2cNTpjkfqhw z7=moOGkRY?MsuP1Yevwr&($4X9J^1u`};t?+6KiYsGPfzaTpEF5(QKk%{|aLN-3!* z{lr9n93Hyw&I`k^-#WYbO)Up%rW>Ijew{aC=Jd|PSApC zZD|Q)Gnj(rJq%bSJ}V&nR#0H^_N^Q^MBNN@XUmcDXj?@hT>R%1-kuSHK$+j>&x1W_ zv!PjdRW>)Y&w+swNN{&VL==ABq9P-Uz76*jBMOVz3(T#*c_Dy#5XC*X6=Y6!|Au)r4KvJ+`|v?JK7dqKtIBG=CxJunJOrA`fQ*B2ESPc&(Gn@~hD+G{Dwish zZGFSDlfekx8=IYNfd7XJcn23CA*-scu3cl-(cCO-Mo$Bc!2;D{Jy5I0$H(j8M0LY0 ziArQwh5CG#2&{M{74KhHx`DxVPw=l5*k8=d%mDrY z`7mw8Do0CO+uHg%H6>+``B?(g9YU@-Cw2$g*b-o-aQv4tv>b*iEp>{cWIzIHY+{m` znHg;UMORO6VP(bm-8-rZLzFwJ@wh)dy$}*Vg24cb$xpApZZ zvAWC`pPm=RB`$kM&s^#*F9#H@VQ9%_bzZn5Tfh#&4_$hd%#4ir@He=;xQo)$bzHPu z&Pzv|mX{aYeP1x2;?Xin9q`?JVx(8c+m>%~24{K_`WQ9*^HIZsO>`=^PS1}QF)^)e zp}J|`6R(`Wk${gcFkWLnR`$MG-~=~Pd80(s$$2-?nDN^VR)`64;DP;-0yBu8)@Mw|x!1Jk_X!9S4pu?G%2(I-6E7 z^U|@BE4fRENEdZZIhkWjZ;4oxo6flOy6nrb* zJpiIsfp%D`Z!%JANQ!zLF2>5rg3lxeD?4_Qi@JKC1EGw}KAEWco5F&;48Ndp-@A89 zU%$K+ey6C~@#@Nhlr*`%Ug^~*5sBB8<)X2@TVt<53WIw}y@!WOLr;IKQFE{YM&)OR z^wCVjTRzcgY4N#h+xfCwcslWrBqKiWs9A^fwa*0*^LFl$6GZ1sI=4eZ^)oVw`H21)rU2 zdOJE=THU+SB#$t{Qm82|gE~4sKZ%Rn7hkDLnV$H``1p)qEEalACxr;2W(EcVNM41I^R5HqgOS=a-TyqGQ-2;YTc-wl zvas!Pnv>`!wPF4--sbVJfMpm|4^(%^+KDb6uXNXjOD?_TaaaRvkp} z9UTzV>I$bU^%QGOzZe@Uj5^@_e9QV_8ZqqZ13JYQKN05l6{}{PE~;!l-2agOou?<6 zudlb@Z89%{uC8iZnH=dI!lc{&{(gH)N=nMwEH-~8_1h<9Q+^M3=H>@U?)u#GOZ7;z z8%V>1JzCq(LcN?0so#O^on7J!g<&s>)h62zds#2R`61`O0p*G}F|Kd5BpwgNA^Rom#AH!S@3r zPkA>%;=nc~Vz@=})DTAVO-xJ-4Jj)O{lmh-z{wh9NUiLb{^R4SFpdESVX=(o5Xki2 zsi||D|7NK0oO1QNe$b&&#ZqDc2_S_?d zObmEW@YgZ1zU5^4x5`PiwY7U9p}x4}4oY8KKrdKL3X+s8bazAdrP009+~h+>28-7C zz41waFV-`;pF?9~)8n|pr}q&}vvWwFVn#+Oq6c`KZr6dlDq?Zah3pAYgq$b}x) z^@m4Cg^CIlW)ox;r9r;FcV%RHQX2k{Jb}5S@bGYuwCQQI72T#v>kjynCs*fmhWaoo z|J$1qD_w)snp`>`BtCv`Z+bN1qn%yBzjOsu&acX)2hv(YLw$FI!#!f^z3jTjgCgm5 z>Z*2J?D>U-V|$%ZQOb(-QiWC+l)eQrze(kFj;#Ou^AX8YKiPw~&fQY4)rGaR4&I`% zWiovw=yQrFN~uDY(CJoCl5f;%_V+#T>-&I3e`GlnXY&+77Ri9mj?59 zzEn}tx)7aSz)+Q~v~)K_{>+2~1a&Y32(Mgv^U4CxU%UWUrYZ=}u^M53lg1N95*d5R zqgigQn4ZQ55;WjVdqOA(F(nP{u3ESO*7frsiGl~B%vA9lmc5RilAmZHZU~Cm>lz#! zgs`TwQ_8Fh1%{`LjFw?B1)HCt(pUiK$JYq{lsP3&-n0HRln7v9B zL_}Jk9?Ym+cQOt`Dl|08(Tzx4bCTrrIWV$nYV!0?r=fb9NDP$>RB}UM4;-UkMwt_6 zzV!)KAMEi)VGwM?4!AX2J2w9FD`d*$U7udi%8|qs6lB)aRNXa<{sw@Nan;$cU)z(D z;}VlBd7Tw1<!I=c*G3F)?L;uJymaAlL zo86iLpRrtAZxSD5S&Y%-a3Km3uU=`Cn<&jCa6pYrQAr-dRr3D9``>N`U7rAK1H*5S z_iNuINb>+@nPN8=Ix~5HliTBCJ;9r z4sFghG`OaV-RI`kOE4HLa@dqj;q9=z--UUfSw0*aAK&$IvRw9XJ;Xd(>7!JvoTRiH z5az}+HzIB-C15zs*Uu(FrBLRZQgc+3b~Hq1L!X3 zeJByQd0~H~D&wmQy+sZRO6n;t&U^t6f=U^nA~@It2Swm4Uv`d&MXA+bOFE1nAhw0;3|Qxh zp1nIG8f<92Mb$X~nLD`Aw6<+G?&)*et1}z-r;!R1d}4Ck-*LK}zY~4f8n<=?!M{ZM zaM|-p4okUSuu;ddPi02NjMLKGu$(?I%Kh@EFM5pmr?x0Q zR3$R1tQ4$+S4%yLU<_d-@wBA_k2)($TU+lO`I|@FeN+g7iJYAt@Zt6^E{X>rqRGxw zlZSfM5Yz_i9YY|EtEnpeHj%>;j&tc2N-Ax)6ZF2>lkXacg_?rXX+hNh zQf{~W{YGA%R;w)Ain8(R&JGA~6YFiMA+DE6`T3J)YwI<16t-7Z<`?&!V?Bjc6ian8 zqy!pr+_o!&5D^D>-v0Db{;m!Mz6I!<*)DZAdIXnBO5Hr0%Vc``F^Y=i&!0z1kJW3k zy-iL^vb5Sk5O0?^9VJOz+L-1tJ$KL@4HgdQovn53?8xaUdtdzUp-|Q>@1)O(p|PT@ zx`$As{AxSxj~a5c)k=b^JGj)dvb(pRXY}5Aad&Y@R}s&A8qz zB|+z_0k8GCa$lxQ?Q^rL{ib`Vn6;D6M;oP%+hi8<_2eH4Yif?vtE@mGhFdXTWsRqE zOTgyx>kbS^ zsBP>o+w9NOp6R!9SJ$S%X^MOv;7{g)$f!|aFk5e=t&Q3q;kkF*w-dVJes$ptN>lX; zv!In5Vp5&+KKz@!mnugOLi2_XY0gb;VM)u~#hi$#uZxms-1eZ(*B9BdaZnMj1NOHFvFic z>Pf0~IarwhZ{7z-s7Ubw#*v3R^QQ0!Be4%xd$GjV``#wWmrzJnRAp}%r0BwcqxXuDcZ9GMsmPQWeVs;pv+`+S6ay+Q# zrFn|0Nj`LDudrRt;dA9LD^}xs7rJA!&e7($y0`Q9ReEm{B7@e`!@uQvrA>ajiZGY* zN{erGox{R3juz8t4a;JFxo`dbdzq;U8Bw)rOYjst+TP|gRo)g2;rBGAdA4~NfTkq% zsbz0GY~u3lVG4a~MT4Hh2ekn4O?heieLp2YPoN-Kq06%0qJlJXc6 zp$G$ta9lkf2x|084wc*c#H6k1WM8Qhf*nSul&g{|B&|6e`GkHgj4FmxPOxn z69TZVMRKw8<2sZ@SGq#JNE8}KJ|JCQpeTH%-{jHgqXH>wj#lkdopTdU)oj?BC5gDk zNd9Tl)VaQ#T!30>Cl0-TXk`LBYN;H;x~XY^+o{{9&56>!-#?mt0X%SuiaItmg?#A) zMeKwKVoO{O3zO~NL+1x-%*K(M)wWIf{Y;hz_x=4ITJB~Ze`UmRVI3SAmA#f5f1)zR zCM%2Vuw4%XQ#jIk8MK0VueRF1*sQK)HpGVo6Cbir)w|ri>TUnZZZ<9lXEGqy0A>ZW z7yvufU+b^~er9wO%5c&mUw)R!rIyOd-fTf`dlXIg`6Oz=_59bfKat+yy^aC|u^71q zabtzn!c8|1zv$r_1`7)$YkvEGkwb#jJyy_jrLh`k@Hr}gVgUsx2zgY9_!BjBh}X$T zR3eCeoDS#2;W4Vr?aU!`%7iMmcB53nVs$w`=V@^9Q&Zjhy}z8bHQmVh%yjrATJR#U zJUEC1_~%x}7rT&`R^wIj{7s0u^pD?dkEa%7F5wd-it7-I-+6Srt>b9h?2((33#nwo z;i1gs<2?6xj!J$f^n|LTm4RMh6R^K0JGeH7DkP+FpP8ANvmpd(ZYTuA1`d-pR)uWC zYZhv^$2Zn_o>9=^*VA|hasf^r9uW5^nhjY7hK056|K=#v9wgQ%F_3I2HKG>_$C_&J zS#xMv8_A}MGS`a}k#@U?c0Y&1oFhjQkBg(=6^<{X0_GDslc9%NwXi(hMxw|KgR#vO z^RPb=SD8(~85Y{$_O5evqI81CF;_x6VPv%br88fRzPJIq$+Ye9*5A>g^~vlgD7u)o zhYpMla9OWo??uZf->b!n1ugu;L+PM=7mH;xo-okGa}9VVV!r-8egBY^WjnAUIWF`TNJv@GxMH zNThV3`VL5Ac(0XNk5MiDxtA?amhSGBHtWLuPqJuxId$vPokeytW+nv#h*kA8z-8>B zcb0e+I%0zjNOQ2g>v7Z3t%1oNu#!4c1g;^+0c}d+ke+JWozF~ym>3<@T3R!Jl>=>K z7F5H*=h18=cLZP&&bJvRAP-7QG~Dt+a8KaC!GC;5y&`d>vTz(|QZ6n+C@^T{4%PEO z2&@WN{0$Lwd_Gat-@QaUd2F}T=?xt^#p7gwZEnY{oukdxBQ#ZF&Yk&1@p;M>PXIV@ z!+aAYz_7|{IX1-S`h6-AQAU?-l{6#~=6G%N(0D~+DmPER` zDVFo|DNMyXKNR^5Yg%SGe+IvnmKG@gM#9d2m5?m$%R@wf5#^!u@IgelYywAJ@hTp~9@S)VulI)!{pY7T>kbc~(z!NXA_lRCl^?mcs!ys=FvwOj-=h^*ot` z7O{8D!n(f;XZ;u3TPu8oQd&cprW=^p1F!fX9li_=&s>@??6QC{pR)Iu7VsFi$$SRw z0YO4!(BH(<^F3WoR zZEGmXrxx3&jDRKE5iy7K+gepBcf_I;C?*;&WEluX1()pY!T7po z^_m`czMtO^2ZAvYnvd17-;k|`ttZ=WKT9HnPSTrbsTMZKr5DWT1)oC}3fFe#%f-S> zxUCn!Ij4VdWkJDtyeK|h3{|bV1pLKTCY-M>e3>ZUUuV2}JzXCb^d#Vs(o^oTN#L^Q ze}|%#)%p)7YbdF5K9--uYG?dW zw;3Ba2r`K^wpjxwyQ;{Cc5NapGuyLi_d2&i3lT`ZiRWu;+5VB(P$~_=v_9~X&F6gHsaTID0I;FKvU8J7~< zEGYE}xG)_}ri@pTc}~7BAdT! z)k-ldEmGgKipd)-){{hFc)xbow5cero?lvmV@0_IY_L+tKgIJp+ZKassv#Vv0LK-^sH6Q)^ij`5g&a$s9RW5 zuTW)qtuqU)m#+#0Lpd?Y6%|$46yNQizc80g(RP@-b(;uTU)a9$W0$3Ic4pdO-g`ys zYGVB9%$@~OVYzrqPz{yS4*rnOkb>f4RcfhNjskS^8EdQN>hpQ+jFW!+2rgk=K&Mw` zlot|~+05Jc*bk=$03JJ=1NhwBe2IX=3zDqbs}+oJ6#lz+NnHG{*vn0H?V&G`_ay;; zWo0gWjyl+B8u>yK(z9^e<>5C<){*k5PP+Cah#ONbzT zAgd4hA%rT04xZ=OsUfo8N(w3}tn1yXzC2;9^Vm>DRT?>{Qh;IVPnybtg1gr`c3AuZ zi7;y{uA`$`Z2h-W(e;QSnrSwDb1IX*6CndsOAio{r~GM))57^JTmOAfz&*$7{nns{4c#-t)7F676s^yRxEZL-Ec7ZZ zIFo6Bo?-G=@Vh$S-cB~Kz}J}uuG*izFljNxG(`SKBmwg&fo(cM3XD*#^#8tj?sdyo z&Olmvv&8Vc(k#fw36lGFZEZAHn%WI*(Ky8Xq2UqjzTOq=xf&v}RwBN60f;VZpP06Z zpH8M~^NA!?HeB~)y?#Ai^FnvA4XP7UvdL!3*^$Rtucf4?dT6{{n*w(+mx>)x|jlha#JmIJN*`m zHJ$#*e%(UAk&%vSX=fyFsKUHi*LyRTwhd0=_Lhumgs6yF$nJ_oI>djr-0xt%DTHL^ z<>4Pr%_f=aWXXOAev>ENb|{CL7-E$lwuQT|FH=wC6q59I9c(jAV{guc zBx<;Bs9qN9BdTd6;L!S@w6Q`NC@>^KTr%wY*P!QN;URf1TGf21Ejh1sll=)syTh!=HAP2=F;m_2etXve%sZ_*D~XtLV^F~<7_MMKC^ zTj37n{BwsmczJmN75CtB4PkIH;jU09q50ng?#xC&`eiZLrIwy{K28`ZY}Lqm%?Tw3!;YpA;9TE@dr%J zA;&`_;4A`B45&jUq1*^|etAlHOB)-Z7$DE^N5%I?)%^oy)f z1l~qX(NxI~*U@&QRllr*lQ}*%qn&2Cl$j^$F5Y8|CxdH)1w(mj z+Qp?w*n8%sTEuy{E996TT*HLX5A?P2aj}TPQ|LN7o5sRG3cm+?s1+h+OiVMZFH#0_ zf*d!GyJ>06tS(pA(T4&XoSs)pS+C*C!kiM215y=K{m9AvsMu$Ky!oyto>T`w!2q^g z-`Uv#)ehL5f)!T?pc5t9fj34@3$hztn7IL8TiGwHe<9w3_7Z&Cj`sGg*Hs5|I?#dw z2&QZjx8EvgA;_v>D1pO#(r#x?(Ck5V2q%+z8BN+jOAsbFao}PWVfzp_h9va2eV#sa_I3*6<0jT4?_YCaFWSpPtUJcFk2sdaP#+HT}1|g z7^IA zF)HatHb#bnxzD#;qgmVqH57+v9JdbeA7hZe{nD40m!m5XRUg5}*KRo-xZ8zIPX!$@ zeNHBaxvpe=fd)yPpY^)l2LZQhy)&&Mm>G_g6}1RCbVa+HK7W20aq|^45w>_gAR6gY zV|2!y-zR@-9LRGRb8v6N?WX46*5K_W(gX;^8($O_78Xu7@cHNftyE+ZD4iJ9N+`B) z-a&LsdV3(qaGH{-C|&lMX4MXdp(C8)7-l~G{c%vJe z?BT6$@${x49Loq9k7VI|MDxy|%zV#)l%y0RcC|8vU$mUA!V`bN0ic6mUNQmXr^s*` zr5DeiLxTam61aCX!cifr49v_sunZo|dEY@?>WV{qW#X|-KCzkD`|6LTtwK|ko6bAGD0H%bN8R~ z>D8+|>!HjhT2|Iq7Vei(4K*goWmrtARzhP1G^(u*N4ub1z_LF?dO{btIqOem4^m?2 z?PMzgW;!xDn#@fEyg>Kk}*t@=^pA#*1PkVOhYxk z_X`^}Bcm+tg*bX!6|!MxY@9a4b6kDH-*}Sl$Icj zLPbTjCa5szcub);R-h%17xzqK^w%#5+_gCMGGlKqal9}a?8OHkt{((10VAbQqZ0P( zUeI-ojgGQ&aDW<_RN;n>a$~Fd!X$QDCxeqvz?V|y0)3QtE})2&P>PIqbF??b(*)FA zI31sjwtuU2C%JZYbU;gdRrlkiLe+c|;sCL>mcSnreA(_C<5PVz4c8|@m{79OW9q-QrdAocYQ=GXkZ($MueG$?fp595lD}eTJ_9B=5D6~D+LHYW zg&JE1;-fcD*%@@IZH~8QVkXeg2Rz%M22coiVxUQO0XaMRaNSX}=^8 z`23=&xw%lY+9wF8JiwvXT)Dt!gt4+ezc7kPw@+SByk8iLyt>ukANw&4hB}}swYwl% zDIRhA;xe5a;1-w|w-?MhQGoOvKRM~VxAcs*+Roe0&o3%U{!B8f!5W^4Z`*LJz-sq5 zs(?czgzc&XT5KdUDAQCG zD@T!u?hFrq6}&S)kicoZ0C5Wdq*pdK`AkRifnEa&fkhhN6Ys*F2hdiLUtkA-rU3^g z$SwW0W@>Tp@Zh}d+tbleVWFWh2C6}Qef`M@9Hc#=?{jIjw48Rrl`wPI`z`w=SfDeKV4LrV(YN^A|6rEw&z3KX**DRY6i0$aPp;32p5T`yN}KIikJXM-@tI0DZEJ)DbsoTQ`(9~N`Yp?m&J zqoRd@A>sTdT@!$AIWifF_uWxizSw;pmNVV3%ocF`|`FY4b z#b}|90C)t%R?`^l|LL#=^gM(pvBYq>VoURZ#Or!r@YvoB0|ehWsN@8$J5bsHUs+Iq zbuY#8nW>3M+EX#UunSBV^vz&{Pc2? zO`i1?bkN+0Aw(vcfyo@HO=BzHo7O4f&1pKyV4d6o5g5DWZ#b~fz750478$Yv%q;FE z+`m*pSjER6kOn;QgRZasV&-d$i;A#sGvwswhhDIO=L8CsPWmb*%De{0{ zo03ADiHt?#l>!MGNWp)N^@T{iO&|B&X>))jUnEZ|=ZEu?1t%ld3TfprrPLg?!$Z8; ztk=XF)I#dw;)t%v^>x!XQfWi9?b!zL+X$UH!})>p@M(kgDUfg&Z&nOeEHeaj^I?Oq z(9(QG>j?SXa4`ahMG)v1KDbmuf6x!<$==>xQ*>ZA_?y+aohpcmQp(x@ucTN=0crK~ zqo6=T-~QIyFhQ3c;ioq1=PM>k@4Etl)4{=k?<=B*&1BImDiSUzektRWB72~cD2f5> zHEdsQZ6QcqsIVE!AN5yRFMj>{6-LHEz3d8Mf-$Ul#JhI`OP^qYzcvT#8E~`H+C*=W zlSk!4UZDf(64*tSdlCXlaCP6ke;@QlyA0gy?;*?OJ|g7CiV8)DV^G^$8=*P z4iIDcUa|t9wJpxgc~M~AR_KS102`01lhaqan;;t0Nf6YBQ-EZUj0|iZ)Icu|+XJ)S zIc!FOMxkCTzy^N@`kbd&!lWd-whJvma32Jx$-YOe06keX6RxD7pa8byLU>H+hFV_*za-aHTgGot+xJ^_ISo#ceS5S((&*9pgl{i9sMhYb)UCm@QtkxS?{ z`{TV%kfyMQTiSUf7EVwNn+^m>#g{LzZoKr2C(ClIih0TKZffpkg@8YY8aqV3dgrDz zo;RF(&0Ag)4*!xwDJaB49|;Z;Ul@hahao%(V=y)X8;COF=#->Dkc9&4w<8F0Di6iG=@)!< zE9hN1(K2ww(U>$oumL0&KM*^GhA0~-of2-|OMn%-5f;C}>8p~^8_AWh6Se9I=K-wp z(=DbB)|;1m;#=VD?Hv&TIP4)fb6T{?CjJrHgBqUIeDe9l#y~nEyo+Hl*ZjsGup@x5 z=D%+J(R(4YnQ^`_`0tQ_C06U>btb{$h7 z#4}(&cHGXKn%t^(k~fA%pe2_x>tDe?ARm`LP6fVE%KlqL6IyJF^znU%@adPv4gh$r0Y(8sM;ZH@MZ=!NG)% z?m@4p>+#z93IPliEiCmsC|!n~o~k)5JtjJavN@10j$xwo{Sat$-fbN3?7rtQe=4Pm zGGaU51Y&egq=${1H0>}h?)prV)8N#`pziX!1{AZK=hDXtTJtqsTwVcR&FX?vOx1Y> zeF2lFdjG^@potw#sWq*Em)qf`z>M(+6d&Glh14N&5hW)a?0bw0=$P>)CihTK zS-eA~C1nml)f^mR%4bi<&e1=~&C1Ts$YSl#-~lriYoT}_1d}0~b?(>6QLC}5gaKv- zRXNiGV;)3AkE7r#Tv$h}I!<K^}-V7uXJv+?%H2v=2Gi0wyN8zMi({3A07>eFGDpKjgB6Ya=|4 z#}-8H?u%}xa;u}yRC-PJmq0(k1l3ItKXn#rH??xYkOPPl9!ImX1J074Xll}azNs|; z%}?e+;&h=ks!_4hy!P^7^&|}6QKv3&AY8K{d=->m^@4)gy-IK1v}8~wPR|T&NA0jM z{*30V;DmN?R%E2_H;Q~e1$;yTPAqi(G|_{bVn#?9?tQv-_?-DJi8Bi)nk z7(~od6qI=79G|~^3|jH8R2-L2_hBvl=5w!s&gj}eI!5=eZK$z=zJ<<^rXIXboln-3 z&iI5{J^^7ZnK#uq2}>tp0)Ed>ObAd^Y*M}x{w<#=X8M@!59 z-t$+6yC@19q*kuywLBru()a;oXCR!oYTtxsYPKT?@N{)aD}rp;;lwq>0OvRupGk51 z^@T}E zT6h9fBZi zY;2fqyv~G(Ykhv6y?Sh#|@iSUa6~M_tvZUdqS+U302mH=^-{c^^)2eqng^c?UGMnoE%v4%Io(<`1 z#46-G5P_ClP<{cS=|6Lk;3)(wn3A$G2=`b+VDZ_AI#F}7vO*4(0p%Gzrl^e@VSL>e z$ig8J*;R!48+;4 z{n8L>(nLf=5k!1VeUL%{hsJF8TU2D^SNHs_=y7VOu(AyaZ3VNfT1raG9z8_i zb-6rC?uwJ?`qWzZ)oh| z4-S6c=)-n);9O+*N?3n!v?sw5npH6Tktkym0Cza8tgH-5hjyFe)+Xmii0}H?=`}wW z`bhcJR~!v%|6pX$G6ByT$TtC5){6I!6rJLxCe>1`kJkNp0EYYiZh)=isWPNxujp0k zYdk$cvE$Y!%D8)ti{TCp687JNHpjy`hxBjIYb7T4R@R9V1g<+ar=Zr<@i1kq<2|gn zZ|F~+ys-K6Yjvg;#=j&t$R;9Ry|(NN#bd|k_}$*9 z430aA^(8|?XE~wK#{WiVeh(3G%3`L*=@EBdkuF8gNRF z$DxsHoz?`Uy1a@K;cNyxU>d+;Yh~=bf@|S=n%oanBi^ruuRLZY+RAg3)_eAsn=-;B z`EOpJ3`P%*Eob4#lLa|?=l3j?-z_a29g=2>M^MP@9Js+R78Y2<@>Gsf;rTCqg9=A5 z>c3ui63m^tLCto*qawPk?ZiFk-+!)dY;0`7$5*_ouPZN~`NIXzeoM2;RApY-b3@fy zo9au^d&RAzO%|Kf0sQQP!0f;~fxdG731!ZJg!6v1o>o7r04GKU!)8 z-RyBWIZlst!>rKtT|ERhrzWLAB1-(Ju;TVEoSjo|0xG(x9=qvz)bI;$df8;xFiWxWRf7?*T&b9GQQ zpu;prql$@v)2;Jpd*YSd-{0aQ;{F)u8uhJr;qX{cUBl?wjNRI}O-=b4T_?_yTwN7^~ zW%E_KzvSe6DfYA4GXg6vRutg3UtZ+q=i)wR|6picKR;CF{`Xgr)lZRA5@Mn-4_@~j za`yeOoX6<0hOz!Ii<6P;P?~2wDeW-ao+8@VfUe~bG+`P_DUYym@sA#{m4cL6!$4v4 zC!D61DtQlJ-^F(UvfA&xyK5G*92_<;#f7QZm@vFwUkbw2mlKP%QoXr3j!-)AxUh{5 zt=Bw`MYVc3OY6cN$ZoGtsQpx+L zJ~5<|Lwy_^#WU4v99ApCW2==pPPA7)!`7;E=@{K@M=jv;Y%LO7AATvgbX!m{seh)- zcz1sl5I%Qh(uM{KZ+>inGn^ zY$CgEACrCjcJB#av9-G4u^%^A_Y*`B`C6SqV8&~|-EZ;bwB$PliY)4TG2z7JMxr40 zb{|N3k|m$c$ijjUo=8qti$;J2*gapLA|v-KutHwEqoat=r^dQ1MB;_5tZaM&U2t4< zu0k-f0*|2YIX(`^pRMB=4rP(UZg+&sQ{R1fv;If2G4$^BAhsf4O5$~Rn6Gr3`!&&% zND_Q8ju;+tZ;sa1*40C6UFISNGc!V>f@MGOxk`&&J}P{@bhQP^z(s}NIq+qfq0uK| z9~{zjKCn0ziz;R2qy28FvOOWyyD_Hk;hlAbKc15k{?EtSb;ZDX^QUqSdiBv$b1_p7 zXV`__JjJ-@{Ud$e_Ua;Qyd-N%c;jKzlx+H(_2SF;=3IB@&GkMKwokn?wSW{@YqU^o zlS*)T#?f&|bEH!j6!%g7gNpkP!a{)xdwmx-@DW^Gp6mYZBWZNAwe$5gl%!r;Vb*5r zPf6ufk0ypql^@cud&{R6Y9Bcbk#Mt}Q89#mZ8y5y@qW!isOqZV!NpmWl>rhgl+nV7 zHyFuZJ)Mss$v`eW+6phB`Y;q5cmd)AgLsTVN*r0@Xx4S_}zI-S$srST&xp#!6uT3S#} zX=!SP0guAiczJ89!TGmbnQZeTPEIv_eL+d7`CD;t47lFG?B3rbpYp2o2^GBWQ z-rI<~EztM-d%7`DPC}7Hsrg=9UyzQ^=e*V#&@SIfOTqE>4m3AD`z9tb7+wmb^Zt8A zNByZE<78DEtC3yk}?Vy;!D1 zh>0+dtLhksac3dy8CTDbjoz>9hmx5OL`O#1YLqS2dLRFqn#>sKZ!sK7?09p$Tr7%Q_5<2vO3GXIEc^LCQ6$G!Q=?q^ zO^&*Ckv8+>myhD&0O(YxpK;TyGFPurzQSy}KkXjq!@>4mR3g}*TMvVw>nr+4VeDYV z3@t|j%>uX?#M;}poE)&co~fu}R|Dpu3f8{xo?Gh66)@`L5?X%Hc8azr%!M^sa&CaV zfZq(Dzh((|*(wKK9zz=dv+;ynlTSplLW(rgY1HJ|K}9gx-zdB5ckw2Gw^PL?%*Ey(!UhU4Z6BJ{?#Vc+3hyIx1=% zG}H^nH2+i6!fpx^{XPK+yCfL*;QDSQ`I>v3eXzw{VLzXF`d6J<)9E~(9{e>?fOq3E zmy56(Q&Lg}VQ5}SQ4~#YQqr>o9W*5FC?j=k;Vh4q*97W?LS}-H%KSIzPU^>Xo$yPr|={k4!WSJh=Sy5q?v>XoU|jx)A)Tikubz7NB1 z_y+PiFIxfT4<_T@>W$Sq2tzMG94G`0TO+rp-+9oYYgQf}tiLofgQeet>3{KFYz_-T zG{S8h;xXa2Z)xOVBILfm0x_{*5pQRC3rbr`rNPnBua%Xv8w(D<{=iJYqz%S$P|f{F z;jKnM0tmYA!l%$z4ct2Q{N9~5Gak`IOiu++kX@5F3UrVEfCy{3zIp$j_7fI4JCn`+ zKN6YY8CV4b*zbca%?inPS`ZB8u=o5H{1KAZIQw zkvDm9fQ-TmhxT@U!F+>nJ&aJKqMvaP=#*6MCxU&NbcmjRp1w{M?d=ZH{iJ;nQH?C^h@Wr3;! z0RU^Rd)KySB>@Y>17>)Y|Mv%MaPIzpL4?I`19y1=7O+Ok-k=MInH2Pj)Ue|Fhuzf( z+70+SArd`o+rNg|(87Z5zh44oD-RD(6Ub^oq`F#CS$PPm9K<}Ah4LR`qYW#_QGos{ z+T&M^Cbmri8_^=|=l@+Uf(XnReDWab3f*RXfP)jfuMS?E{|>HB_g6{4zyuFu6a8z& zD=~3#_w`}X|E?Bc0X+}H5LhRJR|(!cq&Pm%_=3XbzoV-a;1>;?d_!( zG?VS{@|*$(<~syM^8w^}gw9{RNDFA|CJ132%YTRrZ0zhC)77j_1fshT_YHWQjZw)I zacX0D-l)~ZA_*5)R#ujmVZW0N4=Z3?!k_+!1}4?=8u|QS9fyQO8|ZGZ-0VgCFZK$z z;fJ^arGW{7W4Kz`%5!S_U(y(IZGgt`?-WZG)Jo)>HX3d|U-y1wgOQxGJOKjC?okNn z*ucW}e~tPAK6xJwEduqmWj`kak~)}u0Mvs7rS#xQ02~lpjE@4$|HGA8XVtd1zviI{ zMoQ5%;R`q=|KEMu;_vv}yrmCS!M!k0e1TdI7Jrn+MnPAwPo%hcGf3`*fkskJ3D~@L z?_pkLKgK~03g+KCkhx|sQ*tT?M@Js_!pCH4D#XQfCpHgC;ZS)Q+-Y=lV7tuu1I6R} zx4sdCRXV8#Qpt9AGY09o;2qr$MC}M^2h%lpguGh=tux0$FV}9Y-q@!rUVlqv=?`rk!`KV|0q$x1;}L!Bl5M94(X|>+4x9tCg>79H#Z|%hA?8H#hygb;>R-4 z4XY@B{Awz#VpBMAb#tt=t1D*0+;F8PD9Alsz!1yk8DL#i%i92O^+kPP0_Vre7wL1$ z6vW|y4=#W}cMT6@rpza(*|Hp$+s2FU^wkfftqzYc>KAG#czD!<7SV2!-EXE;)ep_x=25uVD{Y2)=L?)tozsnXz^>$CeBapv?+g!QIu2QGE7(C#Qu(3C{x1U6_ zxr2Su&VCL6WYFtPgDpIRQ9TpYFw&~NW2M{pXHf+V8Z?v!zgmsKNV6cCwELv)>FX+3 zD?&f9s5URBJ&`%QT(+w`E?yQ3_(`=u)Dd`u7VsDC$FPIuRJB#%DC!O z=0k!0Je?04U+(wC#u!+XSm6`nv}Xj1r}jCD`ok5;cMPg>0KoM;v?7!3^JdjMu=|Pe z>diy(s0fc@<*F?pJN-Z>XsR*l=ty9Mx*r&K5zyq~_G@YnkZ>swihs(^EVmlXy%imO zU%v^r9v7Fq!ACROV#v8SQCF*W7)H9*G2|II;txnVW85{$ZjJ!P;xRs}9=ppL*t8V( zVPH~ZAAwIu`mrso#@q9e%NuPCQvDhS*g*RjMc@O%3GIZP(*&sRkMY08J)bM z7cDK#7?Um!14}<#fdV662dzZF>1E;3qAc%5IcDP+Cr z2r9SE_L>H-VB^=TsP{QjpWUffnVr!gOk6|gc6vymPq@^s@) zLuAD?EfBX2jjCv{Q@N_DwkNSgbp(Z_Pq-}I&LqHrY6>#nI&W`mrOAE(-rXi(8X6%K zU8qt@g3KZ6DW9$0-(gLt#-Fi8Fd%r06YUJ9tqARctN_5?dm|=>SzaaJzM}_E zb%?gcCt5kv8zcXyEk;&`#>Kk{aVYc~Rp>L!b>6eUAT#9P-(@9ymJ7L9K#mw49u>hyXGAakQCsici%Cj1lSszJR_1-&2&>P^uR4Ca z4`2U$&P5oJz@T)Su_{kfS!1?b`LT$7*52|*xfG4&m%(5=%9I$3wRuK`hnH~B4{n;3T((@OS<{Rs z9iQ~vVWFw_y)~4bvp?P1Y8>+!7+UK@i1xg|ZVR|7B)$7wjHd55k#e%XjFCP4^=)gi z<1RjKefeYff;0Rp5fT5PqQ~+8Ut@dD3EO_5Ey^BD4J2tC1_LnJKQZnMwbfLrwwv{7 z-b;-w>_Ug{7J<&i#y10voSABV?)9?hFPk@b4!_>+p(jB@oi5<}fzwticPo_brJMSiMBx(YMGx?b%LIBua#bkKHoCd`K-}r_(OA{&( zS4HN5bMc?$V0pnxd^|ui{G8LG@ZUZ5_PLLlBKZ$RHA!DW!pNz7B6fn? zb;G?m#${~muMdd^+l|L6*xdg4Gh7qgAeyzF`r08JLR#ZBrl4Le|MwSs=m?5`3Q^xheA_op>+7c| z$dhUOBO%?2-E`=ARfD+un9m36#BX$f0`IMRHDhLf`3yUI$+;2@a*G|1wId;f0n zoYuk%HsR$jgr?rYI4kSR>cvJvrcpH44wfl`LDbU^aGLFjA^YwJi@&Z{+l%2@gylIo zzpz?isI)|`dQ$^<5zYV1@w@(xF1-;qiokl-!&bgLmEANbSoF9vD)?h@;?L~8<+w`G zzrUO7J^y|Jyl%Cnv+?B_-`QDGz3Y<5K?Ea?BnhH3W`xc-TQy%}H1D0?$j?Cwjl2g& zgwD{tKdCnC2-kXRz0OF_zzO@j^1?LyB&Ub}dv&u@d!8W^tY~H7CM$&1VGmHTpbS1( zXt`C!ENx_LeE8pT40aH}#km5leO%wPx?m8`(Ps zH{Lx2Wi<#RVG(J>d;V?24n73CIY7L-4~~4DS|?ax+y7JcUx7|Ael~$c_Y4G=cnm67 z)A3Z@|4+Qthi{NbA$(+eo0-#Z0d$UWadAd4xuNUrHoO5cMF$XcLNULzv;?+z_vOxe zWnhMnUtM7f0LkV)h`M_w z@V;^GCRUqcTh`-0v_Tfa?RBqY#&w)Ue5 zdwO|^iHM+82>6}_UABv8Xb>j8P+sfGF8c{8>a47+VDfKnW!$jlKFG1hc3**ZYytrt zdj=&wD1YA!4F>X3&giqUmK+EpVT5YJ#$RHm#kcE4NGXX(yygmLzzdJZ6CE9*7MT}g zgM$XA((AEwC*DFoDPOU@+7eL%-m>>ZsbQ`KBpXvw?1O_VN$R!1|L1%_^{uEa#gp!E-PK_7Sq%f?fc=PDx2&VmgX?YTo~eORv=61xOy5 znVE+wpi4aHiz0f8;@<`xcE@*+sQ&@(54^8Kg2tT~Hl}crf%=pnF$g|hAjWrwKp5~Z zRh5LWtIoP&%B2hw9NqFlhnZ1O)GBfGh;0oN+C%+|PrI-SJ#S zVVm!SxDE^u|GHdVq+QJd&+}L_!YYu@b3i3B{nav%w7jhB1&-ke0DFM;1|&|>Z`|D6 z2@I;}tFW|S#Qyp=Zn(4|Fz{AuJs8_1MK`kE_uYnS#mn}o|!*(<` zZdd(Hk_ve2Go?FEFj`_vV|z}{MdY$j>py?_5{v}zqz3e#r1w7MfUJcO)xS}~oheWW z56V;Apa2mRX|c0rXhErHaUMKSxKaaVDk^&JA%vrZJVAYxX2f=RNwagnK&UcN7191n*g9ooQ zHL5|u-TIKoP?x$9WZIl>2s;;F!rkxS@dPF=pwPHmQn0LfNBsVTIUgFD$AQ7kyHvG% zXwaA-kr0D18QtR9`Qc_Ym_YcLKq?QyoN^N?_Q#+NS|&l74@T8InZ@o#;F{;0GT4lgo@t_Lxb#$A$^ zkCke{8HNz2`@_(0sQo*a2$mRp?w^-aL>M}B6Y96vq2Umsdq>O)1xFRRga2lao*F9= zoAWjysbDazA7w*aQ)>v;G?y2Mzt`c;fs4%H#}G(S^nazOU=Xt1K%Ime!C~}u8+}uh zEW2p`EkXpt9>C@>bIg*#uBQ`!=^$nnpmTeXY!E(#OG5X?9&hlqr=_Rs1O7ee4i4L+ z!U(DHzP@{kQR&|w9ef&W*P&KcQNewHO#}~pWchG!Zvk9tp{k1kC14iK{j4ZO4zD>E zmj)p-RlFTtykZ*VLvX%e+rLb42U|(l1AKghnG7T1!yz~X35o6+r27jZ+t1Vt<*OEe zFViR%JVTdjz7|Msa7uN;F~g``Wdm=T!tLc(h~W(S9$eBG#Lpx=?&#`hC4Q382PEfN z%ZQ*Y)Tdn($mqCO!0!~2yLkfF7_Z+Ac^^1<0KVM|&x?&-240K*`@veO$$Xdho ze~=rfxcewwK^9Idg1x|XPTQ%6VZ5#zL1*&X+7KlRcK|qWl&kG@t*xz@0)s2Rem&Zm zkBJv;rxa1lFrvF?1iC0nLgH>WQ#+?$T}{m=RR1?n&U*P;Z=xx}RkBsPi&P9I zh>VMl{=2;fFLRTE8;9PH8(HgFMQD$r(Z;A1AG;1l@YdQcu-t} zE1(nRBYlw+t*!n(q)TWc@magV8tk{-HBuet8)VubjZG&#F|LAa(yK6rGaBeBK)C@C2ro}Ywd>#jM)(Jw>r+$p zNI^-N3#1Jf&hc$Vd*rF&2091ILTrKXbo*F^v_E-)A)0GMab+pB;_S)j)J zUoQceeRq}VUf;TT6E2#kraidbq?E}BufSSA-U!|QM9+K^t5 z!tD%Rfr1Y}T7YTTw`A#O6;=1Ohrhwr)mT%Ji*62NkvYOh@!9f6K4UUbOHm247 zUnOWG?rZ^)yD$a2V{2nbWG12g6cEg`x-U)hsn&`92}hV^mMep zJQW6M&LZ^y-HhhC49p`)WS z#A-djcUu_DfHNYz@ql%YW)1$tD;Clh6#O1oUE_#dijvhvlH;;ki5_#+7iuP^LSvXf zQ&LuGYFOmuhlBIgJDo4t^Y~AOaTmCmSlx!2q31)#SlHPB)8u{ARr1xIFu;?3Bo}aD z)$xG3#7LVMG;w>V#w$Da)`l5B0y&c%;Y4wKZqLKT1Bx=Wt<3pOczGm#E(*bbphL1m z-ySlo*BO<05*auuomP=9&&46YN0*xQL@+887xEpB?PjgU%d&_C&1k$k!Cn1~rGIKl z%jR7JOv+YWy1TobfB#4ZNRc6k#Uf0?!0Q=~&kTa4y`yby0Jh#l?039Rb~CC!YWwR| z$cH2o6T2~}+59u({r9VoW@5kNwCV!89M0~~EeVYJT+UFWzx*HdnvoF*D;p+T5bC%> zhWCQaYBE2d>iQqn>NXgV!dhCs?5|)?Qy0YJ;gR4ndz~NImdPUYUUcH#muHoEuU_%U zU#63(d{4iI3gsUdt3wq+&`Lr=(nJ#f4(NO4U=xR?$mm@D^z4in2B%T;vGH%q_gVsx zpWA(&SDS~TKkxV7+QTc~&OJwOa$M^E^E?h$p%@YpSiV9~Hqs+9B5Qh;}<=z?ViMfNLrlr*c0Rg-GW_P>T zG54J-o&e#On6>p0Q53vq7pJ`o24$~qM90h{01?p4CqB@1J-qh&E?ORll)|hE`6R%F zKrkmX6ist|eJ1C*HY!CY`qhZEv|~ZP zua1r_8386q{zx%CUM?<^$VDIrIC8GuI3cl^EMEnSVIr&k z)jL8lFI85Rwa3qw{XMVl1u0wT=orXEIz-4w2>nhTFL{&7AK^#+CuI{5^^Fm7B4+c; zUDz*;`_sj58XAovT+dIep#Z8V(G^xHadFaeSndQtp-|+Pm>8S3a4{YpXYdFtr1~79 zd#XvOk3VKF-}^I5{^*fjMuzOsR!erU>t$x<&)NFN)N82#4Qcj^DmvhHTx$LJJjwKO zRahp%elErPk|%TgtUr|oAX%tyFt;&Dg{;Uu&JNOIVoE3EZG27~U|2hWMcL5z>K5I| z{kr;jziaXeNH)(h`l+Bcx3@Nw`}a3?qgxDxwq8v@a15U}=h94VZcq?f_p%toLvVR3 zD=GC5wt->#CB}6NxA9&>!0+f7{ol{iYUhH37tK5OZ^{SfQol4Z2I_m+@4e-q5@}Ri zlXdw?L8p_+r<4APKM32P|7^*afVCrh)Y~WhkzQKwg3!Tz`+;3=lZY0{(~5N{?>Ra9 zONtsRgi(8mIn=5w7Wdb27(`Vj?#aras2BS*$){^|cD^Vp%hhqOvKP$va@D>YvCOLP zcXk$YbP_?ZzFa*~%}OaSr=jovV!6|pRVT@Rxw8{=2V-N$f}X>zqoZ}26{dY3q6#$s zK5p*IK|<0qG_2=!YyWfaozB$#+UWAJV&ks3v3x_+Xg>dF!F^j67U6uA-Pe{ z50c>19!cFK4DNld$b3!?!sout6gn>-f7j2i&Bsn`_QTV$5Phv~trJcDBHX2vA=g`0 zgUvxoJ8*uNbVcLYeHYB2P^I@{U}WHAQNuvCs}Dr2C+818P*qdXnro%A1=(E2wwFP(#L9|y) zz5caEPn^Dr6zjCQh-r}X2@97cI>d#cpZ;AgA@l#1>%vRQ6GT?Z<$}hGMGDaiJ->S2 zm^u*jNYeVf1Q3X1nUS`x4x7Zg+4{ZlUsVeeVJe(*A+~mQbIPKt&soJiHZRYi zL*pmokgD-x+X(ziPA*>W-i3pjX1GaAB6xE0(p-kVloeXK7b@D9HTx(HY)9x6fD6g{9(FX}qUhPaQz!*o;>BMrWS57JHD z;l4s&B21XgEC_LNj6WA_l4B{9NMO(K-gSmF(AE3c*!@jS9O!sf{%eDC5U2XPm*8EJ zhw^^8Ar;O$dzRPUzW|&}OUtvdL3o>LnZC*C)lH9I9ZY!pTKw~^Wd@}WUw?u-5?~1;c+k48_EbRKQ^^hZ{@z9t3E8FB_x#U& zlEm{~dl=T|_4lW?6{y+TnuUbx+rt!s=&1t%51Bw@9jWW?7r#qNoCh1*Q?6h9uUoym zzC+Kh8Wl;a(-3+qUXXV$ryza)llO6&pXZy8ev+N6;z<=v7daUju=kI-UF)~m(c8NT z*nqmaIx-#?kHd|GiF1-zTaP-CFQE=Eov%l7-dT;yUAt_qR@*;@sYJQCeA#8?>2te> zvLqjpbPo3!l6jA_t88=hnj#;IP~*S7BmW__H(nEfuuVDgakqPSW{7lZ_t!SY2WCoO++4238}MRz@#2V|<`)9-Ga zj8O62uanKqS}m`o!o%UFs%JL{$e><8R%X!`n9mtlG#_xQt<9Kup|B`nWOjLG4&s2F zg~3W2&1(7d(%nbSx{za17978p>1iVgyr zKTLe|jHO}m^J~p1xLtXd06zy8_kofU)^H6k*Uy#`a>I}`&+!t$-NTL@p^3tb0z(lDR(hbMKRtwZ>Ja=Vo6(+%#Z4g9zmOAgc3a?ih%`f+<) z{lY))-hCKQhJVFbXf@u+?)mkr!;LrBT<~HXLHQJu?Sn|esFzhqmqTz>Ri@mFB)n9l`!p{&YXV#^%pGvhc_He5}>n z4madK<>Fx_UpA?u`-F$**IN@Lw(KW$3UD3m#2C33MD*6qHImIY>3UyZrA3o5PEGKU zbF-&calWo<%MhM0tnZ3Z>@zrKljv%Dvv=_31ICD_dZ7mg478|L+>gsmu~+b_>|EET zj~7OA=q)W7KRoYZS9{NbH#(H8RQ=~Sf9yAY(HqP3^)hn}HLRheTRzZGDUKCc&l11E ztl3GbvYWfeuCBH>`K;R&y_RQZUEkN5S+~OV>v_h_{`kB5%|OGLEH{PAj|_MbFpF{e z-9HNm1$yMWW=6;9U z(~AMZ0p>%CKWITX>905U9d9d-elvJkq=ihws(;sE;jr&{a9tujPI^it7MXShZAh#A zXRnsm_;1I(-Ro)%kw^y~g`uVkG-jJhlb-1uAI)w5N>tY-=`ws&Rt7c03!7z!d(FpU zw6rHwU5Y9yFIzj|X9Q^c7{sbK`J5H#$l~es$9w;CKru^nfkS(upTVnhYu7!avvcgw zqoVC8?(?&$x;n~0?*vx=j^4ZeKThsHpgkR_%UWG|&AXJJ}iSq?-+)qcY9Z02ME zDO&bP4clmQEBeX&zpKUjfEiRP*71b#3(UV{lh`u8y|=iiM!FE7%EaHh#dSPOSc+!@H&9ksq@oC3ykHFs-19k}>p>ro{ce!+NVvy#^7U~0W6I3# zG=8&M=d3}I#(f^H3Dfq_IP(D`oO|K;c;ej)86`UtcL_@CcD+3Mwx{>nwK9ZWX-!w_ zld;|S!jLAm*AUhy`sfQC(O*@E((|<;kGg9t@+P&nG-w8+&s!N6U)~rmt!x}EN#8Xy zTn10pSIeh=dlJlFy{fJJIvA*gB6=|=m&(SBb(3&llr9oV*k#F)e6^xs&%gM9+G}eM zn|k|RMp2t8Z7-!bFOyw*-zj%D)0fQHxSOzfwHb96mH<%IgL)w&ar}devP})QQHnDYz!zWcy44oXahV6k&$nel(+R8gvboiRUTRDkZ*M3r3#Q7$!rl#>} z6~(%nx=nnEtjUk%^_Yvci;L4Uv$khuvh{2C|GwAz0bDSR;zsxTB&|sy#Kf)Ug=g`s z%`@G3YKyHB^X#7c4+Y$%El417hVLJ_ti|_e6#1?(o&|T zbm$x`;vRW9o&>M;9TyDz8P>0?k;JKvqq4sG=uScR71i-*Z^IK@T(L(juC7VNE)D57szl`R zpSop6-~d6+JO(&Rq#n_$<_(HVNt{cZ`CI*o4Gj&T=0!I@SzC9%oIVbCIt~Mn0WXiO zjlmZ-=FhoC*``Yurvi}H!>*1mTD-r3VHTXa%|2ZjplqzYbu;|(fQ9eiu;WF-ZYOs) zdlTw~{T{zTj}MG{u1(LRursYElAl7a{ZS_;dg9QSj^#}{|Mb;hMr5_>TO1-OMHwZf z-&EoXQ@`ST1f)?CfIQ?rx0B9h_%b++-&MQvY-l?!+f2&JO1_&HStLF|1F82Zz1lYl zDk{~4_FKerCN)(N|F!vz_MT^LSW=hl`TJN3ZiYfKD5sjwlq~u0Q*u>)vfX+Kf$3aZS&_ zaQT7g#giwJ^z^TuJi&g8<0?u+eOp94D+K=+C?8Jmhtp{^# zIRQesQOBpH709Tb=CQ8SX>I&ac6`2h9!%Z9of)&W9cc24>c>Any2t05AF;xI-+E_u z)9b+E9SEyoN}w5PSRnnrG@zp;5bDKnIT?`$?y)*gGAHL6n=h=YRpc}PT%?gy z4<`XZSJhO$tj^AMVD`;qf;oDojgYdct8Rgs z_0GIM9x2nonzh9Y;WM=4y7iV@LDpW5Gb&Dc@tG(n2~m+>$3|VKt3A5$>J*my!N63P zWh~_K>;p7hPWRC)>dXh!%zyWr_B>1o#ttnm(Jub*omyw$KX2t4M zL=#~a&VsD5&;DYPN1AYeBqVuUFN@3Yo}cCwHbIOVcw6 zVLb2QVpbiySEPMcA5CoRqquahObmX}jg1<(+t{4>@P!xHQ@*y$A zk10m8b;F~)O@R;#o25Z0%5*Srb%<(pC+#`}hA!^Tt5X%`F%#MPi(y=$5^nHO9p>fX zp{19!=_UW1Rs~fPZK5my$NwF{Q7M& zn5SnhE_?re&TtCCE9DbL)_KAtbD}`kUB1k!*RGcPFae!QK%fZ>C!COc_V$#(z?p0G zEWy^+9l|jn4WKN-PqdTK0Hu@?Ox@=4(~Xuu@B8Ey-5ba+O|U@T%ogAr4Q>et(xfKx>wY%vd3Io#W7bEG zK}=oo-j8z4eJRMZ+79Xy{OJRd6OcT2e+3A@n8lO}OjBWv5Ci?^Y-uT!EuppuGel;J zoTQ{B?5*p8EP2*gKo&dN@%S-R3!XEdCB?+Vzzp$EtU53P`ArNLD z0cAx+*trD0sI(%(B-@XP#`l)=g6amk(#pw^k*oGQkO24}=Y&XZncL2sZl&~lFE=-W zxdzF&h!P1CWq7<{l-U#?>o7S~=CVEvs87UcbeaC)!xV@a#<%DAuUc;14gguuLmlHmiP>Z3 zK^a{b|Mo3{5Q?D3fm&x|yVNA0RpXGN<5cA)dYeKu6TpCI@EzAdryagr{ z6XuQ#yx)v_5Bgr6Fv8;h|Mw*I{}BZ8gHi{=5g|_<98n-aN{s1Ee}_O0Dpox=Yz+eW zO+?hr>B*ik>@eYP?BI;U_~(n}rlyskeE^#HKQuQ$C#(Zk10v=iOY&b&MG5TWp#0%+ zSO}Q7ngS&km{#D$fvnhnm~HXfU|Z{hWh8iSfShSGPC)0cNSbxQtX7x=RFQwNZiuyK zsR7gr_rteY0lVN2kaJl2hui*}SLqo*3DfL#5Qc?EM&i~}ukL`343r-FfMxuzyW$z} z(1l*ze1l2$00jGUb91nO`HDbth?EC`SCQc`>)LVqg-YRz^q?1>uLs z>mitMt{bDED+tmQDTh-UfNv0NMfW-@GgILT*11(8VGovoVF#BDW$kOqiSOUPkB^U! zjU}x94-75?4G_ocpab{^`L^%qwh#Ile$Raon~MoJDq(>}#YyKK9u)<&HvsuRm_B&E zIMn2K=~d;joc3^}yf3P*_D_8ayifcx+3S1% z97xwf8X8IU_4O0q1z@2FIwP>ZaFnIW0upzrL`5A^kj-&07MMB_D_g|o_Uaa_l5}{S zv%_A!0*cSNti@U<885*8XsRmi{6~ulzn#I2>sN4=Ht;%`7=PphlSj7R(NR&3%sON- zPW02lZx)G^Qj6%WIH>>MI5^#z(1|XSLH_Ev9grf{e#ye}ZKOoU@elwvA|mBrhA`=={fbG{a*w?gHCq8r4ct=Gfh z4i-)eP+vtx#_oq3(IZn=Y7S2DyfXnh@R6z=V?x0j!KEm&e@p-8X?Lglst8rfQQ9GzA@c zVY7C2f8jaRDb)Bq{N-G=&|`O9*`*gQ-GZlT|Wg(b^OD8_-O(=kT zAt+me|L6NBuT@gD6ii=T4UGhjmmN-62^*cjqFfiePi7-N;z>MCt8%PS|9 zrg8r5b{`EZd*tzLI;&ag^v>2f<4liYog_aZQl=TA=l=e%LU4yTOmYf;;{~BEze^b3 zJ`K3e2SC-Sn;Vr{iCi;Tty|y7xcgxoRrBe0kS^E!T2m~0w79WYb~N#%EN&89zmfAb zPbhh`Y#8Y@Y^Q+bPsMo^4atLP&HjSa>`s4*b?HIkYL5cYhX%jhC&E4OX>jWO_U*=# zNc0-9C}MtCMg1(AhLy7E(-bka62HM&UwGqTT~xEVoJHs6&spZS4NG5U;8_8W2X=>~ zDz)r9^Fcw8eBSuIJO2A7GEv0A2M4k3oGdIb+2Z!{6s4g>-yEI~;Nk}M2^hgYs^wA6 zND-4*TU!8WT|s9_T_89prQTiMM#AItR2MLU055D_SO7T3Kt%-(99iD1y5X`CSS0>$ z0O$Z&JYIVW zcdF3_`fUX`)QU=26E#b{kDcx9pUtD*o=D@bhpf15sJ#n$A@Viog`I#OQ&qFjB7!pn zK5X$4eR&xjMa_w3~PK(CkJ zdC+-}x{n3*4L7el-)P?L9IyVH!hPzz z$_}w;OWCsTQ&SV-epPfNr){oXCtnE$VhO~DH>zR454*}_gyxOo$P+zY#Z9=yp z^xA@#RYz!27kncCAz^C*?R~9_D`Ntk;mP4+a=M&u&GB1lY=$?jTCln^yrKbqO-xE! z2r5)7jpJ2m%^GqC8>L}bb;D5{szg{e)ufWQ(`5C&sJrhlKygcrM1ZvR3nMrAODsKD zjm%Y;SGfIYsB*KdeRZo^Lz4rfsp}I~8>8drM~?^;|7M_Cj=Fch1=TxVcRFwr@bOV@ zkH+Qdkg1p8!^e+YKmaI;TH}R~Qy*c&Xm7=n>$(XZiZtyi3~ig|zI9L;L6GJBnCLV? zhlh#tP8%u`CMG*(eIdm<>o&$&dBrS|x6tHBab|Ryn}9$8>F;Whq{-8*OQ&i4xl)eL z2J>D7PMmmb-S0VDr4rKshE;}MBSax)PNkJPF276V#lGMWi=N?eq?FqBTJ1fyog*Dc zddF#B4C$BobK>@MKS^*Tcs@IZzeC# zmxXSBeA<&*zZy@k?0smZ^(DNfm7sy#;nx!KX+^6&$}ZFxUPoKWOrAybsI74|_4Np8 z9SFgnfl`2P`L=$|x4Zl1_dL-JZVyM(D?@xHvl~4fS8aU`>Tb7aghG`c8k&WG7 zqS}jv7wz&oMw!36Vx&Xv38P)I2Po#V@H*VUbF+Eb>h15}E0+q{&QGlRK1i9FF-S>4 zd8g0s^$dOF4Xb`;UB~{Oq@=2JqKJh2RQc*rXB1Jd{-b~$n<+$g&d*%Mqq_uEshszC zv%xAaMeH5Db#V8NrGE9Fo;WJ(Z&bW47TN{)XXbw<9F1prE}rLETh{guKS1VZ*Oqsh zc%|yaX~_-=EP$%gb8=HtR3o=De3ES}&ctMM@bLyf8FXvR2f#n3YPuS?JstCBA`U5q z!{db?(d+96KznC+{}*0Bl=XVJ<6vc_rJ(_Anf`P^{r9Z?L-VnZE^c7s;SrdFO8iR# zBRta?yWZj#o6%(6peiz&0{aK>8SiW!SWO*7z8eAd17yoa(lW@6W=W{cRB34*S`Xb! zoj8io6QECdzVkLiIBuzRy73&!z`c__9+k15KT|ixr02^Hur5(Jp96Qr(3vi4`e*Uw z#E7#@j$BNYeOKehDqHRL7(va;lfI7tcQBCr7>1KGF|mMjIwYqQ-Fh6bs-p!H*Ev`! zxq(3e>}4R5d~rYw`4SajSL~)VG%9W2vlkUTUs&y>@Vz)uwpe?`s2()k*A?SfxJB|{ z>CbBA)x;BVg7;kAT4T})`}gnN!?;^ONpFEtW!E@ArL)R*>+0^jsV>m zk-4>V+qeseyJcZ;oRfiv=6!mEm}!H{wO>1D6_?lc)C$B&hhaaQ?)Y5?ry1`9#?9LK4HP5 z$22rwRHKL?OiD#v)z$A1J&q4d1VNuafA}Ju6<%av6&}~&9h8BKTY5bv{a)-sosGlQ z$zA-C$9_R*hHNV=yN-ulRan+`HCK^{A~q@LHimYC!Hb!@Tg+meRe$*XqgU0VN%Kmw z0?$|X&nn??MsB_;yn@U1ZiV}T&Bmcq$ z$LTM5>DSMnvqMD0+#tAQ{HrCHyCNE$-s~X#V}aAWC;tJ2+pKDZgqTvl2GXx*4=!)r z_x1JnOue)z1X)*+S{AuF}vvLYd2V`C&GHJ&Bzo0SQ0=|8>~q3KHx{25s2^FRfI z=318eLPIA7W}A-Ohwpqff0gB!Ll)!IXg*EXx-|DaDA-{sG%!2s3+{T)tF~l1m@Zsj zNyj&#p?gu*{vWKpWmr{Vw=OKw-O{DBAl)UPh)60*N=PXwAf3_;N{4hQ-AK1cr?hlP zcgHt)_ul7x*LBX%^IL(n=9=r7W88`Lg;rGj8dMIQ^d(nfopl#95|cn$s+Xp#sgDEn z;iG|%jvgy2h99WjF)?-mZ3!t2buJFaM;iikbR=S8gb;nSN&p!GWf!bIYS*_oL>n{Cq$`ua?|4Q)#LN5KAr zjOgvrzLcuS*=Z_jcgo3b_3nzo(%24~`0mkBa8S+ZN^hj+9e)8UA4QP%O(Whdba6p# zZ`0o0mHk>WoY)!vgW-j{sJ*#Niuk+4+XTOEy4SBqffM#GOPQ7X{o4-`18(`6`R<&j z>4bz+G@_(>=C44Wm0x5#;J?M)>^JVO3G}K)v*$#9(7*R$~9s zDHyy9(~aT2W)QM>D0a2}I@)5&i-E))Pj92e6GmrJr1($-YZ`1`z7lq#={N=vCVskf zbLhpK9V<~~8OaAMDHo@{wS}Dcp`W5^y;vBPnTe%%p|OH~$xe$V@~2OVhifHuPPQAy zy?AOy`zw4SBTuLewg*@HU1B-H(LU`R)DBebtjDldm0O5xtiSGQIW^O&)Smhgt>Z_? zf)-J<&dORw&Re`OZVmFW++SbOgYC{a?4|bWUuO-fn&#n z@Ho&VUHQw&r;xAzldp)0C zT$-8}iv1Uaz?$&UlLbm6jO44=mwx%O`}_MOL|1+=eIGzysBfkPwe}_w68iHVpj$$+ z5ny01xQLB3BEY{wK;d*tN%xZ4!5|K6bhL)t6Cx)m6WdqAm~Q864Nk)xta58-g}-3% zhtTL0j@bo91!JgA{$$Vmdc80lSH?`Ut~%z&kHQ+~0x91|M;rcAAcp8a+-7Hs*`t&p zOA}1iEczSFWw2{I0}VK$q8}*-GR!sfeR%4f)7b8jTp_d<^%tk+q|s@=C2gVC#R^rF zr+ibf-d$oqB4FVRn`X+=!p)730dmwL0F$|!0HmdRKzpVHIHeCE#9IHW*XuQ|fq~oz zi5pM3Xwc_f{w5j6>;EAqx4gd^t{^x0ZzU!wA?PXQ#y?^{&SE<|;zuz9fC4zo&*MO- zLVFwAPd69;yu9M=a8XRGO?blA7IQ|ebXvhisF?L4GOE5zZWIvk{JlNBmIFldz5HM2v~vKeEV zKOsNQt*)RkA*z&|rI45|G{4Y(yt0Dk$QH5!&ol+%Xvye@9F4Z9sCY*EOaIeTh?W4WlMUd}lTX>_6 zkR$tdqE}YM#>=H-4;Q4xP8Ai{998kbk}xlVqNm+i*R5 zO@RMU@0=>%lZWJ?-dCkg&FCU435i*o-_t)mnA{M!E_yqwjhxTD5=yy`F$5r6Dxj1a z$bkS^3~0#is{o{_j6wiI7bCsVA~tbK&};(~D1lq%UeKJ))qwQvr{N{TS`u+n@ICef zF_+5m&OK^yj=Nphmwa)9)aV_6%D}q_eeCoM3_zB-x>bf3$tMYx$omD)8DpZ&rMX?~ z6QF6V1O*4D{S-nJEaUVnYXRy2>|6l;VN;7%s{rrlT?(@>5H4<+-^OFeu*rD^0i!Ni z%8#*G1n39am?D~=UBte8`I0_`vhy+==h6bqGTY-N8RMxpw>(|EA-^Yny@1tUHl4ca zamMeaQL$PXLae&?AFw=>KKDce?p) zZ|7~O_J1zoGbV1VXW4rtyGaq_YdqF~T|+U~zu}0MGkQoZw~zziqwS#T#=E zNLV$rumD`!@Rk$`mgR?Z3t4JX3X0p#bch<8C2D5&fQzm|6a3%sy$}~HA3(J@Iy(nh zJU^>_*Ny>6@?fm_U)VhnG>-!M31#aFx5-H7XJ;k?iFyv2aeoZ9J=qpS1!2tUmt?kw*J$ z1qMEc;!bE@!>m#0%-BN%=S!Dh@nT%I?Tfaqh93l=~1#lS?tW(9y~{DlS@-(GSs3CZS+i1Xzs z2ru9(7{F5+4!73TB}T7C>t9$IgYR+g|7b`^Ag7M;LdFcTK;bk3dsicBKMME~6CqL} z#(ELLL0W&P)%+`^)4<~uJmW$BHkd8ZW?jx!?rLWClXuu~~WZr&v# z$WP!Pp6&>JoNIzAuq_g{-1~VP6U)3RB_(e6IR5Z)O#s+@TocE2cid@F<~E6kpM_bK zLfmz6dxi`#PFMPVdOz4D1#G*bpzna&&B!0Z96nE!UFkGvLnxf7>5uUj`(E%R#h9O; z&yWez7JaWA`Z5dR<*+;FW`=WU%FAF|%^rXHU;hbG=9vqNW^*)nN)$>n-(O!IoS&o! z8OWGJveHu<7?Gle&n_-@D$2Atp(v9e1T6`=|Kxsa%E<*m2l16=IUbmspc!NPYNZ#xk8S+mCell% zWT&N_%cycF;5Gv96e}Xtx32bJ5h0<#|B2?y$uW7vUH~@@(8THmrABYHwcBouNbsZB z2 z!3|lKQ5jJEX9h(**kAQ;ga6zP-y=VGa8aP;VY4yx)7H_kx>^w>;4j>)yk>vQ=bAnP zLhE2}->0)$+4EkmKe^ivn~;L6JXhxmBAkOTFaTvbLB}F;F}f{1VRm5-JA7NcyDGqL zcVyMK3p}&))w$i19f+@o2yWO&Fy(W9cc_f0)mcEYzNrswPkb?4sQ3M#S|+RwRXD0&YM>`D3CsOe3&o#>3!0Y?`Np%0sK$? z`EzIoD*kkHU9C`6p`iHO8utDxJ9hTk%cA-N&+hM6H;yhp=m}mLiaJS288SG97(xPO zh!0BXS2=IyhuB)i-2pEHqBgtO7@`K!nYV6!xrJS)os)gP=sUTp(f!#lCOqc0z35ul zA8$66?oMN1Q1NfLw(pzE*9NxSxA z>klkZe4W34w@yzF&A53LZd2igU$(ULJHOF9Kc1-#E6|)dI81_fP?Gm>DdL0g&Qbi( z5W`d@He{|C_a`6m7{}HAbQ2fTemSJ7XbE8)51dab6U4uL*QJZifTURbTQkngLsqs; zhh@2o820ujPb`16ryVXWcl%9F=0L5ShsDLQ*7kOIii89yWyn*}7YZ{~@7llI%IwY* z)@E-C{r#^%dKXU3HFHfw--INIXNUd%HRN7ojEEBy`Y@;7B{njaiJnFMMUUn)p%sHB%#p1E`eVH$0_n*1NUR6bl?6b%n%7=!bah?t$9Q?KTVMb;DDi*}tT zVhYmrLP@#OA)^5JZzu~04hw5|<4w=VSSo#nF#ZDX^o%ZHRut>Cx~#0aG9J1tOa7`r ztaZ{Lj;m)H5D;`|YDl)n-$xT# zihr)==OEkJRQUF!K>NeH_W{UU`{-s<`TEko9z5&VScl);y125u+7ActV6I9L#1HG% zznkPHt*vQrJTN|rV)1`dP;+v~GLpc4s{h}Y3Y^dpk726d;wpi02qcIzxf(rr|NLk= zzt>k)CHwjwHMk|-W7F%gB>R|tY`bbH>grhh^NbA@mFdBQH|}SrlgzAAKULZ~DB*_t zz^>lp8nZRdm2aYSv%A|2WP#Zq*%xvReVvb~5ZtdzuFju|JErDj`F`w5m1G{$D9xN5 z%9`imGO+t3C{_}(K5WvPEau(Q%QP__7e;Y{=|H%96J^2_pvfd4pe7@ey}Qbk=#c>Z zbOuT}EoMc$#T6B99ybjcU+^gir!iEU$J>`0Qo2Wv`re!$Ff%iQi?ZNnohXGzuYX-#&!%}+N9b&W3#x_%EyHVd)u^PH?EKU_ z=<>ZiFzXW&;VDxKY=5tEfPEs=$cWD8ecbLkvF5VtC7SnCuDjck;p$4m@1CgWucpio z4)%s~@{=grWkMtRr~Op$jK44}JKpNg{DbS(@XwW}p z#S>XykCa-Dt|SG77=}hH0+u~d#w$yPbsoA(Qc`J>-rQ$JA<)EZ2_ZRAjr~8bdteeTu-bRX#9PxL5pM!xe?MJ5SvHlPJfA6*6 zo@5E5CLt!-5%KuzeB+)m-x~jB?m#rv8d^#cxKKzux<^R#cGnOPuT$2w=>F>nxd-Bv z&fDxwx?8Fn?D7!Kx=27)NG`j7AJO|qkzt`uF&n8-dtYzt;$LpT@nX*BRx>xY>UP6?d3o7^f|7A@Y!u>%{TRMw64=Mu zw?B4nef;z1PY_#o_w*PVc%51Vy^!O!wfS+aYON6tSqFxv0CazBg{Y1!hl?>`c%^&8 zXlQ6e_wGRsYN_?p(~FB|GBRBs6&3K?c3vrIUrua{h025|Lsnf-xKBB+PmIMYe5lHW zD3wXz&SOPG_pSWk3E+eVo~uOW^sDYOygcnn_rqo0hpsrYt@IIOH`eSM~;rb4g3 zLZtdlH?ka3tTepnMk%o7fe2+~Zccd~Ut(N$JQ&1k#axnjZ4ME42-`T`Sz6w<^X~K` zwO(8Pts^^Dla&qVy^rQ~ibJ61b@~*B=xneaEiD~}q8~$n5edoI@UVe_7i~ZgEdpbJ zuF1cltn2IRWg0Qui(2@KL+nxH6$4tj>6%IuQh2jPcsk^iw?@FS0WKrB2KUIw{;jOs zBPZ{A7#lZ~!R!<;Wo^v^Oz3=Fif8u+NOb8)6yUR$W><>PQvS$(KOJ@)bNRdSyOh(6 zO`w<99L*bp4;&&|fHnCE(!bk*2SSU?xyGdL_DJtW+yQme^6F}tK!3w;4Qv%;= z^B$uCA-D{0A>a|hw7@7`Y48gtfJ}^-DRMi|leagh7K=(SuhvRgi>J$`pfa?EINMxjAt#MswE4#jio?CM=_=C&0 zpQhFP_IBa@2Rx}}YMId#0?9(}BPuHRVjI_!XwfV^w-Ff~u?lN&1;xbbBWuoC9_IB~ zOmPco2nmUWhB`Pp{aat>7ODt_-b~mzCsOZ&{3zJQW^<*7EF+`U7=IdL2KBORz^$px z1SV`F!G%Rk$eZ^l4`f`YLdVo(# z3a|ee<3TK_qg%#U9zBvdhr}$nc_bPNe_*->gY*%8z`)8%BKH+jsLf5iQC22fN2nGg zaHS;Q_wn-s0cEM=a*~9HPQClphlGS^H*-eC&9rR$t!uYR1W7zTWb}{NC6JawLsSRJ zQ*62oN!Y9=;NK!|l3ZnjSKujxO$E z{X5#*19cooI)XlbmV^jDY?_vKEWNe>{J7fUy>KXp`lz?_*KRoHz~icEYOkiIT|)yh zdGr<~S^*(pl8;Nx$?+e3ePo@lLnTaVYNodLFEzd84SXd~=nx7~=IlTchp_yRqXcSq zAdz_1MZ>WcN@!)CK8<#e4X2T4_&9%;)#LmS{bCs6hak|n%!snItZZH*<)f^kqOq+| z>e~KtH>}=1LB$%buDO0a`$GYgZ1))%v$-w2zx!T)=6(>cg0?q0z{5*`2nj`)xVZi{ zz*;rCL(-2Wd?5f_=>$^+GCkQtghdv!FuZtXx9dwG8@-7^bQC{7c`6h-x-^i^w!8#i zY7HFv;0FYCr$G?JFQ)~=4M&PD(`k73lOqVzjP*WVuJJH2`Ljq#s6X;kJ7%8D&u7aQ z%YP}8t4x@OIg8Br75{C%N4~9VMGALwTpKAi)em}({tjI{5@KK0smbw6udHk9)CTpc z^YimpkcP!=h=$T{n-i&1=jI|Ho{a5|Zr&p)U{#9XKYe)#$`p+5D_vT&LSLj)htGH9 zVf+Hy5a zWPZ=Jv=UYF!TGSSHY8;|2u(&}jEsz&rUNRKp5eG&LB89*xNx?NDEzjWE;+VV_FMQ=EQ`y@5YNYiVS8#MnRG}x%P)IF3Z9l|MaJ3w9$CpFt`uDmSN z4d5Ec*t+6h-h)b7=%Dvmf?r+>PxZfl|H6YytImn-N!V$x+E z+T117EgU+$R03h4jVq0h-fI5tdS_I+mm(=8^$wcIqcrMT-UoO%!|uKfOeL2N7uYepcXrcJiIf;pD>YY#61e6fBt9L+U* zD=UvH@W-}-2nbwJxM%2SXmhKpCO9sv%*?5bF+*_NzQ03{O0d1LQ48m^fIt=G@nu^$ zDI;7{q$B@pF}(X$pA!WIMV*;k3WqDS=}`kr@OY|dT99WK17h~{rjD#3-PKkk`A+OvhiQFj=rsY3! zt$@5KN)V?BG27YOchs~yx6-4`Ql;bIhVB^*LfWEwe=d4EI~yCsU@@#vp4#oU)0Lc- z3?ORi`>g5rB?%SJ0CNjrKl}m$zkV#T9e8+>-KlxY=TsV!NuPMcC*|e!W;n;n*1CDq zr}y08w$$AWtL)yXo_v`f4wdtA7cuqMc`IgS)*3<*hl}5lmp1+Z$&F5g);HISBph80 zYBrjhBN@+rrigRtkLn@1@9#4>JH{jg?b;cyNcYi^c~Tb(%AY7Ri3^>bxBBli$hTOE zI!7gZ`8<@qu)roSMk8K#vq?52&mws#PT$lRoS(l5f($*AGi2Pf&sg z9TPJH$JUAdl3@uu{$tZ_l=2g1JSZ0F>>L>(N>E+l==O|yr;67I`&aXmcPZ{5Waz<- z_@0x4y3@V(h8X&b&@nLHkwP${f65~Yo|rHs*2mB0jrQ90zmzB%8XCs=-4KpEt6EDs z6Yj*v!)wC2gC4RDz-rt#y`;E@dOa|Hm_ac%g)YeXNq&0tMcRqAZD&MHLb2r zG^0W`>PlDw$C&sZhfdGPu)$)`+DLZq9Xq=ogYi?`2kh+FWPTj}SOyPUVzDtX7lp_a zJ#O4#qp5*|fl_e5W1_Sw=@oHe81=Vmeea8Z!v+w-cDyC6_}H;J*|*(ZS2u13hS52y zuRlB6jo=8d%u&2DF?Bv|@r^n>ME~U9!?-)sUJq1m; zrN5S@VpY|w>!n}|LU#7l)#bg~nm%hA)|H9h*v%GbB{u|(7>8KN#4;Ez9;8JfAy^%> zEjCrNrGRl-CHWV zWEtQ2%v{QXv;3#4Kn+8Q2ms%tq>@D(_8P7nH z$J%5?@A9&~lZlXEeiHBRVc>o27ga|pUT@0W1t z|7JE({=GI{Lq%oqCxt-j+WWp^MZ87?3zJ^!-phwPqNGA*ysnX;T_?jX8{{5d4yQS8f-|6aivtROI9!R0NJ}{Q* zke&_+@-QPU z1WT3jKE_l34>GuGu2MJGOf4;XzI*@DvQZHFI{T9U&2gF@nV#@~e89P_+#)B_rxCHn z-YqhI!f1QiNW`9*_dV^)vSF5V9BHkgo%p?xX}xJfP`Eg1vHz;NIxcA7#GW(@KPdMh>p%yr(E4_R0s zVwUU58=jN#iHQb^o^N&GK@TqpQ^Cu;b>e}(q2UM^Hv+679CHxY=OaAD)R8jDXE7JQ zL`FU&G-X`JGxyDGn$AlMf403;*L1aKbx$=5(U8w0U~guI)lFGSE`c$BQ`RZL8C z=$XGqqrlDy_KPc`jg0qAHF0rqiMn3~jrOqFoxW5yb97*{o-F^c>lKIFT-F;hjcL`HZCfKO zg6@~q=6_O9%P7Gk0|hDh9+#=7^>MB2b$8|0{W(xIZES4YImvo|lfBdDs#D{5iyhjq zzMd`OfPs#t*WLe+If97fm)vy&8NvWp%hh9d4B2q2oNrBtC<8t1Hw|LGS+8t=nDdAO!|9w zioX_fLrJPn$Hv;4Ib`<0rf*JGWdmtnvfMs2$@`5r*IJMrcwK5FfoRNMJomB6yoXAu zr6s8Y3SG1^WMY;Jqc8kkKm^QG$%FL{Y*K6f4J9up;z~kCH*9Qd8RvKdtT>@~TwqMK z1hO@K1*ya^9#q>6-sdl5v4>|SKlji~PY8PZ(|AzW?NVL zxmaSzxarwx??m1?8P3sfeoMm9*WLe1kG8`!iHDpIR}6i_1TGnVBc>}g5fo4F0W0CV z=R0bESxp+^1e56QHcb8d`};jVmxK|^u^R*OQfNK}_nwn)ejnSKsT~?BMHvwg6PxMl z!?ER7_W*(5?bv+Cv);Wd8x+`1Pk*RY>T_m(cuYN9wL?lpTj_r0 z&2^%lh1h6cp;06w9PVXM7G!EpnHZ7U=z0bxwaVwMFhtS3;)sFV(Y$zZ?6JbF(KP8C zehWV~UCVN(vWA#HIbL^HCd*5Ng#ixgk(SkDW;WL?HEjKiIG`qIyo!t&G4Vt(OlW|6 zuki+8+1uwYjDf$`24~s6(7Kb^G}TGM((39enlvkMbJX0BMt8bv(Y^wuRNK{$>CCr_1xv$=T0Us`Iec!JF<7rPUI zP!#1vP;YL1-5H*uJP^2?lxIi!XKUs{kOMbeJ?;J*5+M3u+y`a3`DNbt0oqZR;5~Kfs zC0w7@l-nyUW)#0kotv7QkAUPgJ6j$f{+;+g|K8l+5666!7%eTt0EWiK{`7qcnA|uw zU^QL;!D^mLOG|q|x^&(f;(%bK1m3`21~ji+0sxqDQ5cnyFW1^ZlGG7Z@8}Iks_7a( zJpfNXrXspH`T1dLf9b#m@XAC{NH9JEKnNO8-9~qICZ^T(b<_9nJMZn@rEd~N!bLBJYg?YG zH(IoLITfJv{HNntX?8XvMI`(vDhUSXCLE}9FpYl!RI=J}?>=t49)TXUmp_uaq~ttf zehy&Pgs!e{A-|>4N;jNZY&@(}TfS-9I0y8q`}S(-GO@7y9vg#trYtZfQwo1#zJ_PMA3889 ztlqak+BbN}g_H5fJbxY-dUo2@-X6=YwX(FNs;t~(jE^L#iUi>8<$Z{FynQx6bfdt| zTRnM*Jk5!ZfY%^(`x;0-_kQEl_exK{PvL>UI1WQ>bMxmZ%QuW@UU~mPE9r!UCZ?vQ zrl;###&BAYFwxMG7V6SI)BeC*DO9;EAkXG*zPkPFi|%-fK<^evW=i(P0s;di69p`% z)uFV?7%*G>tHTdPzL;RC<*LfN`{BbsKs+k3n`dr+Pzg+fx8s4nesc#g0%3kpQA%WF zYX{Pv%hJkfm6{3*7Iwk;17%Ikqw=ES;$2v2;g(9@Kr*AcMO#12@xZfp82Wkm3(;Ue zggvIatE-et@{<43)fHC1*B-2b5B7cGFoKg5(97Sgtp)&twp5%XbvA8`nFtF;-8>O@ zY>IjPd}w2g9~Jk$zRRxOJ5$z3jb!iUX8n`x=%|?F;GpxvBdpfNp7?>OstHdKxHNFz zE<(E`dZ8M8bfDPz{hNiCS5--=sHL04)Nj14ZK=FGP0TsUjmTq@ee%Q3-*15d%*%_f zpr2XiDXyzUS}HBa!^G%s_2$3AE{lr1u!6(fPcMZiKBE2?QV$^$qOwJ>7Utxvf&)@o zO3Dw5>}BxZst}+JNZ*^qx+QdX>jsC;e1eke=g;+3zAS!u;IOy|3{{wq-!?jy_V&s> zY6`9Eb?)(5(XeI(kDI^COV1D9*3SLF&jzS*Wyuj4rJ=8rTdf9{ zlSwg`VnH^N4q*l{s;9uIi(FnpgjEC@s193tExH2<$tEV4g(=9KxY^7@W5=>;9drRJ z+1u3*hD>@Tn7DGrQas`QL`%o{nwW_B5AsTLVq;?q3buSPNuYwOyAiX<{&Q^o*(uk- zPbw1BJz#L#0VN#9$M*+aHVN^lq6Qgj?fB@?2RS(x;%JSqFy;4^Tr{(R-LbQV#w#nU z;Tl!jXNdv{TayL*hlhaHF^fAM=R=a=QCoY(=%}x+5A@KKT#T@&>CRG{ni9NwmoZl8 z2CQhzn!^!mQ0j)r)s=qsNwP@QWcQ0#ulXJ_{rcET&g{I@>Ypbj1|b*z!7X~#>_ufJXY>`cW*CQdz; z>-x}qH}37}9My}M0Be*>Xg8`XGf^TF{P-`9OJ}xzh5r2CFs_r6;=yY8=-{4aL)~8N zi$}s0me>kgGilxtskD)==n4|~Y{9G#9R4sW?jvSauRBVcv$ITW`I+UsYb(9tP(YrZ zKIQ7BrVu}rWAF?4!LxK69(2;_`io2i#1YL(AJ!KEK~l;6B0@*t3Hf*Y3(gd{XA z!z*m`73~VSNXDM#`F;AFEa1b~n0GZgg{wXwa&#}<&?->ymxJp$_4_|VEiG9vXn#2I zxasZd4OLP+hQ+R~(9+tP>t4y;?tICcH>XY44Hu{Q*vlJZzjOuXwip@ds;qE%c_`{F zsWh#fuh7@rnt%=Q-9a>d59t8l@C^#WfG6CcxSkH(elwy0Ni4AE=Gy2`BI0)UE~H>n zlamWW4HX=3-M@dA81X#?R0xD{+U*yfRCV=)uU_B1-SI0>X%ZFs|14Up%tq(QU0iWaL)AJF$ea z!8r%t_J@0WfY@~P^+8$VHGH9N6Pcbgu#78s*c5;c&7T`>0@V-|LY3 z?A`tQAM={QD(LR^;xP1Ccvnn7dmskpGYL0mKE{smQ9jgHE`7vWi=XUfl)jx8y&#Fg zz(ki!BQc+GhCClEM0<_$=`XJ82X7G&NY|s|;^KUK9$8G4BL6p)_*NRg1w~BmI`{_d z?(PCQY&lsT=#m^Ux}4%MqE+Fg&wi1ane&U0vGAMl>jI+}1s*qiR059}x$yZeKD>vu z5-&E%_5G1)r^O-)Hf;o)@&*@2(wb7Lht<)q4`f1t^%f#0`)9XPIQ7#OlouO;!B!g8 zc=0{aLs;Ite9M_x-7#_3*H@slAn)p=6*E~=KK-!bSp4JbO9PFGL1AI}hq>2&8fDvU z?ahWM4mMvQX23roVMXF56;1p!E}Gamz;#zIJ2|-|jc$19SDN$yQn;jlY95I&Qt!jd zQ@XWVnmf9-;GW1C6peu955${LOmmyryqeTK-mG2tPIrEP6XUs83gN zpM{&_QVH*@btY*R%BO5!0Y-EZo@;bkyNjn^2Zacr!HNO}MPg=VCJ2-QfPVWqs!$;~C){y@6NeNx$0h5T z7Yl@lj-czfOD{S6rZ~^tk5#+7z&DocS;5+5_MV>N5<%9p(H}>W5NVGXz{^0Fv#;1_ z+bh4jV^8bH=T2ZwesM{A%kZiVgQU^n?Cg7dyt({GE_?_XF*PkkXuh}|3Uot(0xJ!Y zYrDFDe|#7}F~J3*oAuG)Q1rk4@MyU<1qQ7njKYDIIUp3>l7W-;$5G=A>%)g-T>te8 zX2a6b=37TbK==Z`fCkyu_mQ|bRKgT3>>GQn-cB}+-+&nGgE<)l4(;vj=J%S7DA924 zS&hglDTRjy3M0(;J=rDwL@|^CEND(+;dXw5TcgMHBbALdCMI0XhReAU1JO@+VFJ`Q zFVcBQKwvJvySF9g(6@T{p$0c@4)h#1c)+-l@wuK#Vq#j@+3^R@-38j)uTY)Kd?*vj z3S18Y9$G^4%>xDoUu@HGfHD;0xwBSgQD4(RnL4aN%c$_g*(IfK^1#v6oi*y{@K-C` z98E(^d^*Ak58=gv0xi?`=CcjorvB#k6PCXpT!4gzQM-dr71FD4VCa$YnT{}$#O~SK z`*UbBKVs3h4b)uFe>tRw8T{sL4fp`Rp8t6cW1yGb{OT%=nDZgJuCA8u?00+nz#^SN z{8CLiCIN?o5(95YxiB{@2Z8`<2`W8vwcs;?&sS4Z6CWSHxAxPZPGwK$gwXzct7ufJlNkHvw3=razg{%N*wtV^zXnuP#Y=j`M}C1jJy%TbgO zgmI8=^PG!|x`rr#sgr}Pr|Y*%Raii_;@A+)3?_zT7*J< z2QlixoJ^xuf5r>B!LRZ`m79f6?u#Xy0`C@PG_ zs!a4vZQ%nD1qu>daFBlq4QwQ+!APJ*gI&eyKTk^90L}kQF;GZhu<79Vt= zk$wz-fT00GC_&6%E{`{ja4Yq&LjVCVFv0Zn^u>E57?_w_TU)(7J+NEAraFgn`~Gt= znORt%kf;L=6$(PEi^QZPQ3y)mXGAN!rS}7bTfoH#;VXc(h+elaKIu zAxVxAUP=uJ+qI+H3UexqLSUGZY-y0h;4kE*uodv~^7`}VkM_mQjfV}y>o~p2ne0hu?`Wf8+&#Ag z`2`#szdPD?;9Y&>gBmY?hs`(}e_HDNZZ;NCd~zJ7AaBSG-<4`Y0=3vb7`HwWg{aYCp+j)Ch44X+x#Sr#GJuXMgaxG%?w8Y;drVG|(MQ)Oe{6N!uk#K+@#j*SE6&m! zFhdQU%gG}yK4On<%abNXpRLg6YABWJ=1k_hJbIGlZ}BB?&^h-^ep1lP0^#J8D6mna z&NcP>dvR{(*2wogNV3qVvOJuu=sZ(Z_WWjUWw7|1pTCTX>Vi$jm5r`6)Qw9i=2+@rPjYd|j zNF@gUTts|inO=9yd`!&2w{J&mY%yEYfn?PCBK`5LJ>x&-G|e|*n;V}qDF*Y?FWm7F z1kM5{P`1P5FD5FQ^zGZ;34quzsef|Vzy+brr3Q|_4;vRRmW>UDt+fydadh8a(Kupq zN!2r)p5A`}XiH53@??UXZ4(og$D7Nw4$?V71sZd@>|&xZp;Ru`-S?C*gT+?+o{GCN zvoQLdt7*T5ZL06t(+>`tg0im&?XEY5d_OEZ9h*z)&l8i7jC|){`3V)YhS`}pwd52T zG!}M8gs~hve1Qp>skvy1_y=jFGrR;TxIuo#3m2D0#NHgbub{W^i=v!d4ICnnlEur%2Qn2r z@SE#?E>KXtdwZ*tq==|#NH&8qhEGRF=;zO#v^jk-7rDUT;NT#fkrAJYr(rN!7gLKx z3~c17`?u}w{hy_-fdA+m0S`q)qA7i=skY@!tp+?9){tvL~+^NJU0Bf1) zd=DI8r{oO}6=lRgl7LlZBq8gAX2H$P>1nd#W5nKG)VKuA>Yw^9ekI9ZYPrM16SBo2 zl>Ie6{)3?*bR~uSt#{D{i4u^I7biOoc6MSP=N?1lRU7FKQRu1zPlo<_OC=pEh`3L^ zo0QmWtTh^~XzX8t#M;lq=pf$X^mOjiQy-r=-bf8~Z8myl=G`NnL;TdJcx3|*>|s|% zZs^w}4*dRoy+F%Mbw7?`?UA#=(8srM>aL-B#P>Pvab4Nn0U(6)OVDJ+!%yA!dQxa3 zpE()@dp^28WW0J$Cy7hH9(WT9wj=SH34g?`5o29;Q+s4Lg z^cRc25G5tY-7UBNx=c6|Y|imYekFO;t|xC2uV( zA|lUhuU6R&rtexzg%xV8wg}0;L|L-e8!OB;7cjwLHFz*Rzv{oIJ^Pc#_2T#^J;_Gs-g01z~ z6-J#sR5)YB?6wj{LACWPq^W@bhjc&CwJ}ev%*LiT1-sfFn~_v#eE7`ASKrE!S+E-T zkgp31NjU23FP?wr{jfko9fmQk(JGHRTPO77g;{%BpxEfhJ3>M-18nQ|WsE;oS3Hglo$MkE^eJsvP=Sy)&Ae+H|; zebfRtA9Lj6x!<(~AY6(c-%nCCP+@;={iV23*_75K~`+8=NhVc{5SDp2vtzIt5&?TK3^Jxw?x zfHwSQGQ~&JnGjEQGMI~uLM*BVrPe@FZ`+#ea}yEu;=tmOk{Q<{yC}O|ZFsZ$H{TgT(u}^CQppye4hY$3vI8?&7C4$i)atFG7V>Hji#N-z* zQ^V~gEo0;6lofK~Htwh9zzj~Tb>Oj?f?0ivntIP4H!+l^e{-@Jai-B`8N$OkEM|V> zr+Oxt0MmsSA5LQ>;qXX``F(ELL8P?*K%h(_Kb2O6bGe6vl%aE6{FZhNksagVPKxV3 z{c+$b6&0%e7RIXuPOHDKtagyBtN`=D*Vo^iEwY&H+hm9hp|1aM?MfezkeT9#QjQmN z#QzZURjxRdFr*ER{m|e6ZS7twLuO`Ej{U3GZs6N7AmtVp@2Lq23I;)`U#~Ap`1&xa zRtu|=lHmfAI03;+W!1y&R(}AWCy+lXe~qOXDVUPO#a;QESslv(NR|J|=I^K&CL#7M z$(KWY3@>8B$PVZPsz_D;-L>Q6P0q>&>juCZ+r*@#krBI2q-klzeG@bi$)O>J8++tH zBEX(h=;zlFK_}f2LT0=3SFAFX5|p9<9DSbkEtPTu*PyAHS@-G8K1}&oRKkZ4g(w>w z5MVx2a|FP`-rk-(iwgDapngrealENQDVA{N=0PV9EB%G-wFRp$;cQlcSQpg422)v@OD7M zhyC2RThP(bv1yLq>M!L7D9K$+!u-RUnVPBx5s;uNmCeh|O|24Z{G_G!&0pu)Y1ONP zq6Z<0vYu}LhAP=9Y%Lju?Dy^;=hV3%6>(qhkKwzsGV3Y!^E`g$D`aBwg#&ajqy)Eph3Dhav89J>gJD=;7Xn@G(kC;Y*X_0AhzXlCZzzuVQ@nLN?a(GungL zt~G?LTt6h%;%A+WSc?aOr)S+X3)dReOLjhR`h(-{F9=~^h)L}NC-5UyR?rjpBEC^m zQ&Lj;H48eDl8T4=z=5nG1?J}Ff}Zc`vu6g6+KEO<4~3; zxuMGv$?H$}t1vQWWyYz;pWj`2fJ%;zU@$@w5EMWgYT>P-dxz?21@{rMvdD;}TIZ#V z8-kol+hLFK-X7g$etgnFMM&!X&x#Q;ZkJC33ghP83VXhcmv*HLs{=qL9&+wgs;?*6 zn9(rpou9u6)7G5lydSXopfXZ1vE6`tZP%muP%ENThi|roE;npDb3$dfvW<%W3Nw*7rfH% zyIAc^?@&LJ#}mcY<}h9bY-e|G58{5oD$Ldv=aeY}YpfB-`%GWo8MGKkMIhij1ZVc? zb-V_!hI<)cp2@x}B57sF%3c}$`!jF)(sczH3-2iiemDu}Bqd?YFU@&-&7HD;Al8>` zROoi)cS0k+iH_wXRmLT`D;RQkygs_o7DyQJ7vMqA$+z^iDEQeXCxci<)Oz7bwvAB} z7l%fv&rhE%aJ&QbW!x6WjEl~x!etNINU^fQce2F#skXbjD>}}%?=9-@($bOhr6VPmN+#1btaaLwlug#~+>u;h@?7k#?(T9VswrG}EK~)4U z*7gj=P_5m@ZELl(bN4n?0=H2R_+eF4@C`@dS!%o7Z%>Se$H~L9F`R=t1P@Fd9i8{x zMEJ`9Rk6y{+ihG)N-|_+IUyrIla|KkJ|nT5@mf;vkE7dLE)3cE%#vhjC1E$$^sPH4 zFgR!uWR)ea^WX`jYhsi}RP*xYR{Sk}YzYj(1ef`#dFcFdk|>yHC79ICf>TG7DZ zXmT>x+9rFFLz76Bsqae|%{>Mq*x)=&nOstETLX9v*k{c*5e{;`AJ*O|?_b&{VyJAv z>D$4`7*nt5oof%qyKe0rkZse}UtOHstW?gF82o}-0X zo0)CEW#@VdE$SeQpb)a5e?CTK@S>H;C1#73D!ic{k}2+uV44v;hik!;^KXR9Fmh-jCa*U zgDNCcVLs&Z0d1hHI08?Yi1=Oy{oHALu$E%dxP@sD$GEZ#ibu&nX{}UX0-Z3O{&u!P zD;qnB`NTe}m{?<~UQdnP_&7YcRe7z3vw_GyT{6t*O?*~(Yp)aJRw;+{WQAwpL29-i9cm`;dU=o2N zeR*j~*nacF4;HC*5M%^Q(Z+g-$8yI}DG4k&+lmZlp z9mgBLaxq0y(khQ}JZ^q)By&7snb=;F@xdY#LB67FI6;EOl30ws-o5v5mzUw`1^_@m zqG?$eJJy5`2^N*W&G@;T_Z1Sp(KU+I-;kNZOLi^c{`iC4Gu!M#3fhk1Iy}dp9KC@F zkZ$6TA5F|p@yqFeGf%6^DusDfh&1QHeP!pHiLz%LI%~s~Ub^_k?6(z4v&;_Z##(j7djCKJ!7dD%NE_os#sh^Wpe7x*NS`O!$Xm4rYaK>PW_``dZ%6MqL94$wr*f? zHEKpcaVzBm2sxu`8Nbt)v}-j}s+mtrBIJ9R9exI5tx{#WO^lz-4kJ4|HoQz9x42?t z5}A=mBGtLDjN1zo;e(?bsf#F!F`*@Yu~FH!4J6{@$fcO8FP3|S8!RnFG_`Edr$|R* z$lBrBlLOHw*VmReqU2p=c|PAI2{}anxTCYIUc%A$c2g-<@yN9&r)2^wv;a#!oKQiy7J}PhUPVsOj{#u;m zW2wEHNB?*zERadBNF;evqD`Vp(H#$R{xj41!1mkHV9kl|EcF~)Msn=B z*!GsYCtlrrnX1q@ZdvIq?Ly8G;v{`NTD_!b-f-4#oRB6ZBO%}U06`Zwh)x?T&-o^0m3ybr!vwtn$d;WwA*?Qc|*H=HW?fK|Y#u4kVMP6OBAMZ~eQ`@<@Pk!ys zemmf6_b*+#nyBb}$}V2iXzV)I?9Tbm)3c%P8WIvXFi?H7p8A(}knZK3U&ctC6X2UAWI`xQ(*s|>?oK^S&e!)Ah{k=sEuPU-7;endDcrR{Twl~9!rRhHe={q&$^Z(H^w|2Mns^#8Lzyg{7Z zoffgId#BQgQ{}R}ei!TO3>PeXT2fN~n4~#uU%=XFqrV+l; z2y>lGzMA@EQ-oCSNV|@?sD`PboOOn{aSMqQ%Km6Y^*J}YAhHDvVgLfZRW-z1H&H}j zd^lg)0$hLjHpXUrjox7vyFa)`-N@0A9&!8+UrMv(g@N+POZoB6TJ>-Kt##bHxU|hZ zGA+CxHvhs+o#uEo9dpH8VN0MY~ zl(>m)s=}60_ij~X&DxQ!u9FQycEb?!jI#8^bBO*D6_O`MWqI#(EnK!f{Q}ImFrcqv z>PmqKLjxU^P{i#uW*zgIP9)6Wr{Cv2YNI6Lp7F!oySHnDe^fIF?JM`C%CWi0o3nFw zitvde>D!E?Y6V5k=}9NpY}5Q~GiJC83l|;WGjR`KZQ0w}j{eey!FESr;$l^#P^PU995?{H{f3{S zwEYJ6#&iJ}9e8dIdEQM*Dk_cxD)gku1flB7h-7;5lr{N&s8U@5L6=KO7i5uGo==I? zmUN`5sdlSAp7)ra6t>sY)Rga;jeNb+Kdu6k^JuC8AG-E1WM zIjc~9$oJV6OTKH3H(r+ezZ$OZ%;FOg{`B1hMA9BRY^+@u1eRVBMDbnTanP4=0Tfe5 z6SBv$*Rrxy0cTKrY~_SD{t6K38l@9w<(}8 zCG6WCwpRf^QNG&-w=cp8NAgVvN*q-UlUI~P>}GbLphZM6ghun@AA}9T#sLXcM@I^U z6^|2=fk-6{0dKg77v(GX8EQgsaB##t?>&!ae5yslFj)gt16>wWN?hCqhysCi9cfBQ zIn7;NbAViNJZUMZlNHrcgXbk{8F_ibsR~Amp9cNQRFeJv!4_v@!Rv#51o(z%CC)(Z&CFJ@W`K m**X5Kwl#PJV-y0tyq@caeo6jzbudd diff --git a/vkconfig3/main.cpp b/vkconfig3/main.cpp deleted file mode 100644 index bf02185e8a..0000000000 --- a/vkconfig3/main.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "main_gui.h" -#include "main_reset.h" -#include "main_layers.h" -#include "main_doc.h" -#include "main_signal.h" - -#include "../vkconfig_core/path.h" - -#include - -#ifdef _WIN32 -#include -#endif - -#include -#include - -int main(int argc, char* argv[]) { -#ifdef _WIN32 - DWORD procId; - DWORD count = GetConsoleProcessList(&procId, 1); - if (count < 2) { - ::ShowWindow(::GetConsoleWindow(), SW_HIDE); // hide console window - } -#endif - - ::vkconfig_version = "vkconfig"; - - const CommandLine command_line(argc, argv); - - if (command_line.error != ERROR_NONE) { - command_line.log(); - command_line.usage(); - return -1; - } - - InitSignals(); - - switch (command_line.command) { - case COMMAND_SHOW_USAGE: { - command_line.usage(); - return 0; - } - case COMMAND_VERSION: { - command_line.version(); - return 0; - } - case COMMAND_LAYERS: { - return run_layers(command_line); - } - case COMMAND_RESET: { - return run_reset(argc, argv, command_line); - } - case COMMAND_VULKAN_SDK: - case COMMAND_GUI: { - return run_gui(argc, argv, command_line); - } - case COMMAND_DOC: { - return run_doc(command_line); - } - default: { - assert(0); - return -1; - } - } -} diff --git a/vkconfig3/main_doc.cpp b/vkconfig3/main_doc.cpp deleted file mode 100644 index 4a8c007e70..0000000000 --- a/vkconfig3/main_doc.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2022-2024 Valve Corporation - * Copyright (c) 2022-2024 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. - * - * Authors: - * - David Pinedo - * - Christophe Riccio - */ - -#include "main_doc.h" -#include "configurator.h" - -#include "../vkconfig_core/layer_manager.h" -#include "../vkconfig_core/doc.h" -#include "../vkconfig_core/configuration_manager.h" - -#include - -int run_doc_html(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); - - for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { - const Layer& layer = layers.selected_layers[i]; - if (layer.key == command_line.doc_layer_name) { - const std::string path = format("%s/%s.html", command_line.doc_out_dir.c_str(), layer.key.c_str()); - ExportHtmlDoc(layer, path); - return 0; - } - } - fprintf(stderr, "vkconfig: Could not load layer %s\n", command_line.doc_layer_name.c_str()); - fprintf(stderr, "Run \"vkconfig layers --list\" to get list of available layers\n"); - return -1; -} - -int run_doc_markdown(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); - - for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { - const Layer& layer = layers.selected_layers[i]; - if (layer.key == command_line.doc_layer_name) { - const std::string path = format("%s/%s.md", command_line.doc_out_dir.c_str(), layer.key.c_str()); - ExportMarkdownDoc(layer, path); - return 0; - } - } - fprintf(stderr, "vkconfig: Could not load layer %s\n", command_line.doc_layer_name.c_str()); - fprintf(stderr, "Run \"vkconfig layers --list\" to get list of available layers\n"); - return -1; -} - -int run_doc_settings(const CommandLine& command_line) { - int rval = 0; - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - ConfigurationManager configuration_manager(environment); - Configuration config; - LayerManager layers(environment); - Layer* layer; - - layers.LoadLayer(command_line.doc_layer_name); - layer = FindByKey(layers.selected_layers, command_line.doc_layer_name.c_str()); - if (!layer) { - fprintf(stderr, "vkconfig: Could not load layer %s\n", command_line.doc_layer_name.c_str()); - fprintf(stderr, "Run \"vkconfig layers --list\" to get list of available layers\n"); - return -1; - } - config = configuration_manager.CreateConfiguration(layers.selected_layers, "Config"); - config.parameters = GatherParameters(config.parameters, layers.selected_layers); - config.parameters[0].state = LAYER_STATE_OVERRIDDEN; - ExportSettingsDoc(layers.selected_layers, config, command_line.doc_out_dir + "/vk_layer_settings.txt"); - - return rval; -} - -int run_doc(const CommandLine& command_line) { - assert(command_line.command == COMMAND_DOC); - assert(command_line.error == ERROR_NONE); - - switch (command_line.command_doc_arg) { - case COMMAND_DOC_HTML: { - return run_doc_html(command_line); - } - case COMMAND_DOC_MARKDOWN: { - return run_doc_markdown(command_line); - } - case COMMAND_DOC_SETTINGS: { - return run_doc_settings(command_line); - } - default: { - assert(0); - return -1; - } - } -} diff --git a/vkconfig3/main_gui.h b/vkconfig3/main_gui.h deleted file mode 100644 index 06c17e5aca..0000000000 --- a/vkconfig3/main_gui.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/command_line.h" - -int run_gui(int argc, char* argv[], const CommandLine& command_line); diff --git a/vkconfig3/main_reset.h b/vkconfig3/main_reset.h deleted file mode 100644 index d777edf378..0000000000 --- a/vkconfig3/main_reset.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/command_line.h" - -int run_reset(int argc, char* argv[], const CommandLine& command_line); diff --git a/vkconfig3/main_signal.cpp b/vkconfig3/main_signal.cpp deleted file mode 100644 index 1e057852f0..0000000000 --- a/vkconfig3/main_signal.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "../vkconfig_core/override.h" -#include "../vkconfig_core/layer_manager.h" - -#include "main_signal.h" -#include "configurator.h" - -#include - -#include - -void SurrenderConfiguration(int signal) { - (void)signal; - - // Indicate that Vulkan Configurator crashed to handle it on next run - { - QSettings settings; - settings.setValue("crashed", true); - } - - PathManager paths("", SUPPORTED_CONFIG_FILES); - Environment environment(paths); - - SurrenderConfiguration(environment); -} - -void InitSignals() { - std::signal(SIGINT, SurrenderConfiguration); - std::signal(SIGTERM, SurrenderConfiguration); - std::signal(SIGSEGV, SurrenderConfiguration); - std::signal(SIGABRT, SurrenderConfiguration); - std::signal(SIGILL, SurrenderConfiguration); - std::signal(SIGFPE, SurrenderConfiguration); -} diff --git a/vkconfig3/mainwindow.h b/vkconfig3/mainwindow.h deleted file mode 100644 index e6bad7ea9d..0000000000 --- a/vkconfig3/mainwindow.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "configurator.h" -#include "settings_tree.h" - -#include "ui_mainwindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/// This just allows me to associate a specific profile definition -/// with a list widget item. -class ConfigurationListItem : public QTreeWidgetItem { - public: - ConfigurationListItem(const std::string &configuration_name) : configuration_name(configuration_name) {} - std::string configuration_name; - QRadioButton *radio_button; - QPushButton *push_button_reset; - QPushButton *push_button_duplicate; - QPushButton *push_button_remove; - - private: - ConfigurationListItem(const ConfigurationListItem &) = delete; - ConfigurationListItem &operator=(const ConfigurationListItem &) = delete; -}; - -class LayerWidget : public QLabel { - Q_OBJECT - - public: - LayerWidget(const std::vector layers, const Parameter ¶meter, QListWidget *list, QListWidgetItem *item) - : item(item), layer_version(nullptr), layer_state(nullptr) { - const bool is_implicit_layer = layers.empty() ? false : layers[0]->type == LAYER_TYPE_IMPLICIT; - - if (parameter.control != LAYER_CONTROL_APPLICATIONS && parameter.control != LAYER_CONTROL_UNORDERED) { - this->layer_version = new QComboBox(this); - this->layer_version->addItem(layers.empty() ? "0.0.000" : layers[0]->api_version.str().c_str()); - if (!layers.empty()) { - this->layer_version->setToolTip(layers[0]->manifest_path.c_str()); - } - // this->layer_version->setEnabled(layers.size() > 1); - this->layer_version->installEventFilter(this); - - this->layer_state = new QComboBox(this); - this->layer_state->addItem("Auto"); - this->layer_state->addItem("On"); - this->layer_state->addItem("Off"); - this->layer_state->setEnabled(!layers.empty()); - this->layer_state->setCurrentIndex(parameter.state); - this->layer_state->installEventFilter(this); - } - - std::string decorated_name(layers.empty() ? parameter.key : layers[0]->key); - - if (layers.empty()) { - // A layers configuration may have excluded layer that are misssing because they are not available on this platform - // We simply hide these layers to avoid confusing the Vulkan developers - if (parameter.state == LAYER_STATE_EXCLUDED) return; - - if (parameter.control != LAYER_CONTROL_APPLICATIONS && parameter.control != LAYER_CONTROL_UNORDERED) { - decorated_name += " (Missing)"; - } - } else { - if (layers[0]->status != STATUS_STABLE) { - decorated_name += format(" (%s)", GetToken(layers[0]->status)); - } - - // if (IsDLL32Bit(layer->manifest_path)) { - // decorated_name += " (32-bit)"; - //} - } - this->setText(decorated_name.c_str()); - - item->setSizeHint(QSize(0, ITEM_HEIGHT)); - - // list->addItem(item); - // list->setItemWidget(item, this); - } - - protected: - bool eventFilter(QObject *target, QEvent *event) { - if (event->type() == QEvent::Wheel) { - return true; - } - - return false; - } - - void resizeEvent(QResizeEvent *event) override { - QSize size = event->size(); - - if (this->layer_state != nullptr) { - const QFontMetrics fm = this->layer_state->fontMetrics(); - const int width_state = std::max(HorizontalAdvance(fm, "Auto 000"), 80); - const int width_version = std::max(HorizontalAdvance(fm, "1.2.199 000"), 80); - - const QRect state_button_rect = QRect(size.width() - width_state, 0, width_state, size.height()); - this->layer_state->setGeometry(state_button_rect); - - const QRect version_button_rect = QRect(size.width() - width_state - width_version, 0, width_version, size.height()); - this->layer_version->setGeometry(version_button_rect); - } - } - - public: - QListWidgetItem *item; - - private: - QComboBox *layer_version; - QComboBox *layer_state; -}; - -class LayerPathWidget : public QLabel { - Q_OBJECT - - public: - LayerPathWidget(const std::string &layer_path, QListWidget *list, QListWidgetItem *item) : item(item) { - this->button_edit = new QPushButton(this); - this->button_edit->setText("..."); - this->button_edit->show(); - this->buttom_remove = new QPushButton(this); - this->buttom_remove->setText("x"); - this->buttom_remove->show(); - - this->setText(layer_path.c_str()); - - item->setSizeHint(QSize(0, ITEM_HEIGHT)); - } - - QPushButton *button_edit; - QPushButton *buttom_remove; - - protected: - void resizeEvent(QResizeEvent *event) override { - QSize size = event->size(); - - const QFontMetrics fm = this->button_edit->fontMetrics(); - const int button_width_state = 30; - - const QRect edit_button_rect = - QRect(size.width() - button_width_state - button_width_state, 0, button_width_state, size.height()); - this->button_edit->setGeometry(edit_button_rect); - - const QRect remove_button_rect = QRect(size.width() - button_width_state, 0, button_width_state, size.height()); - this->buttom_remove->setGeometry(remove_button_rect); - } - - public: - QListWidgetItem *item; -}; - -class TreeWidgetItemParameter : public QListWidgetItem { - public: - TreeWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } - - QWidget *widget; - std::string layer_name; -}; - -enum Tool { TOOL_VULKAN_INFO, TOOL_VULKAN_INSTALL }; - -class MainWindow : public QMainWindow { - Q_OBJECT - - public: - MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - - void InitUI(); - void UpdateUI(); - - private: - SettingsTreeManager _settings_tree_manager; - - std::unique_ptr _launch_application; // Keeps track of the monitored app - QFile _log_file; // Log file for layer output - - void LoadConfigurationList(); - void SetupLauncherTree(); - - void closeEvent(QCloseEvent *event) override; - void showEvent(QShowEvent *event) override; - void resizeEvent(QResizeEvent *event) override; - bool eventFilter(QObject *target, QEvent *event) override; - - std::unique_ptr vk_info_dialog; - std::unique_ptr vk_installation_dialog; - - void Log(const std::string &log); - - ConfigurationListItem *GetCheckedItem(); - - QComboBox *_launcher_apps_combo; - QLineEdit *_launcher_executable; - QLineEdit *_launcher_arguments; - QLineEdit *_launcher_working; - QLineEdit *_launcher_log_file_edit; - QPushButton *_launcher_apps_browse_button; - QPushButton *_launcher_executable_browse_button; - QPushButton *_launcher_working_browse_button; - QPushButton *_launcher_log_file_browse_button; - QSystemTrayIcon *_tray_icon; - QMenu *_tray_icon_menu; - QAction *_tray_restore_action; - QAction *_tray_layers_controlled_by_applications; - QAction *_tray_layers_controlled_by_configurator; - QAction *_tray_layers_disabled_by_configurator; - QAction *_tray_quit_action; - - void RemoveClicked(ConfigurationListItem *item); - void ResetClicked(ConfigurationListItem *item); - void RenameClicked(ConfigurationListItem *item); - void NewClicked(); - void DuplicateClicked(ConfigurationListItem *item); - void ExportClicked(ConfigurationListItem *item); - void ImportClicked(ConfigurationListItem *item); - void ReloadDefaultClicked(ConfigurationListItem *item); - - void AddLayerPathItem(const std::string &layer_path); - void AddLayerItem(const Parameter ¶meter); - - private slots: - void trayActionRestore(); - void trayActionControlledByApplications(bool checked); - void trayActionControlledByConfigurator(bool checked); - void trayActionDisabledByApplications(bool checked); - void iconActivated(QSystemTrayIcon::ActivationReason reason); - - public Q_SLOTS: - void toolsVulkanInfo(bool checked); - void toolsVulkanInstallation(bool checked); - void toolsResetToDefault(bool checked); - - void OnHelpFindLayers(bool checked); - void OnHelpReadme(bool checked); - void OnHelpChangelog(bool checked); - void OnHelpVulkanSpec(bool checked); - void OnHelpLayerSpec(bool checked); - void OnHelpGPUInfo(bool checked); - - void editorExpanded(QTreeWidgetItem *item); - - void launchItemExpanded(QTreeWidgetItem *item); - void launchItemCollapsed(QTreeWidgetItem *item); - void launchItemChanged(int index); - void launchSetLogFile(); - void launchSetExecutable(); - void launchSetWorkingFolder(); - void launchChangeLogFile(const QString &new_text); - void launchChangeExecutable(const QString &new_text); - void launchChangeWorkingFolder(const QString &new_text); - void launchArgsEdited(const QString &new_text); - - void on_tab_widget_currentChanged(int index); - - void on_push_button_launcher_clicked(); - void on_push_button_clear_log_clicked(); - // void on_check_box_apply_list_clicked(); - void on_check_box_clear_on_launch_clicked(); - void on_push_button_applications_clicked(); - void on_push_button_new_clicked(); - void on_push_button_rename_clicked(); - void on_push_button_remove_clicked(); - void on_push_button_duplicate_clicked(); - - void on_check_box_per_application_toggled(bool checked); - void on_combo_box_mode_currentIndexChanged(int index); - void on_combo_box_applications_currentIndexChanged(int index); - - void OnConfigurationItemExpanded(QTreeWidgetItem *item); - void OnConfigurationItemClicked(bool checked); - void OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); - void OnConfigurationItemChanged(QTreeWidgetItem *item, int column); - void OnConfigurationTreeClicked(QTreeWidgetItem *item, int column); - void OnSettingsTreeClicked(QTreeWidgetItem *item, int column); - void OnLauncherLoaderMessageChanged(int level); - - void standardOutputAvailable(); // stdout output is available - void errorOutputAvailable(); // Layeroutput is available - void processClosed(int exitCode, QProcess::ExitStatus status); // app died - - private: - MainWindow(const MainWindow &) = delete; - MainWindow &operator=(const MainWindow &) = delete; - - void InitTray(); - void UpdateTray(); - - void RemoveConfiguration(const std::string &configuration_name); - void ResetLaunchApplication(); - void StartTool(Tool tool); - QStringList BuildEnvVariables() const; - - std::unique_ptr ui; - bool been_warned_about_old_loader; -}; - -int run_gui(int argc, char *argv[]); diff --git a/vkconfig3/resourcefiles/lunarg_logo.png b/vkconfig3/resourcefiles/lunarg_logo.png deleted file mode 100644 index 0d63479821d1d2ebaeae73ee798f00c1c5f5fa8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6909 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 TYJO<%4=OWb3!_H{ZZZD_>O?VH diff --git a/vkconfig3/resourcefiles/qt_logo.png b/vkconfig3/resourcefiles/qt_logo.png deleted file mode 100644 index bd5250e30b37649cc41c39280f7228f043c6f125..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2770 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 V;Ed}TQ^NW*asO`|XIvlU{0rI(eZK$z diff --git a/vkconfig3/resourcefiles/vkconfig.rc b/vkconfig3/resourcefiles/vkconfig.rc deleted file mode 100644 index a0110cb778..0000000000 --- a/vkconfig3/resourcefiles/vkconfig.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "vulkan.ico" \ No newline at end of file diff --git a/vkconfig3/resourcefiles/vulkan.ico b/vkconfig3/resourcefiles/vulkan.ico deleted file mode 100644 index 802593c65c1618ead776f8d6f81fc0a249727000..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9662 zcmeHJF>c#16lIVhqdaA`mI56*_y+M2d;}gLH?TTo^bx#vDBvU5MGoL2$UqNZXLA4} z?0b@az%rCb#gc2FQtaFr_rW`QaHlFmzz( z!2i&JZ}&enkOeTh)?PsO9xwsuYt#?Tvw&_n*Xm03FC+Ey99QQdXo~TU+`(0O2-;)4 zBl@q(L(t#GJ937Ldk8wyN^53+1~J#hJEH$$9Rg03l$H)*f*+cB}aB~CL(*AF!Fe*mc={OHy}%)}EX@#Jk_y>kzt z-qKSuceQhjINMvcZh6;;37w%c57lU=mPL*J9BZQ0$Nc;}24b`?ciXu@otc{t@geUN z-auR$(0{gvsv7)m@%4~%KJN#;BWK3`UOj~TAuVgsB8)vbPwYYjSVebhS$Q~Jj)cICL;C3@D99MB^K+9SpYd; z>sVo2yBBL*x8pDvH`Rc}qT}0#z)$C%OJ;~~HHqHOzGZea^q1NY3+GP#<>4O~TqL(o_ zSc|?oOSkA3Mm`PDgE1P~#<15*;KO$S=DI#dik$Kt!Ctl1%6RsHdYNY;J+c||{Cuwg z@82jp_S|>WpvMT_QRaYiTqDw^T3iP*AP0C(L8o`nq~SAb(8*rAnngQVeHOsM71!u*b_ft-g8WV?XTuzW2^Ngj(#ouZGOcd^(%v zB68}c{jqDP(@U?A_aYwZt4?2iaqk6nLf-lGJ@=X0J;yK}Ixuu#=)ll{vIC}gl#1um ztuc&03g49DgUg6v+^*zP#Ve`x&98!uxgoz8 b!+qv}Xfmr;oXyK|!J7wDaO*yDgHnG0RY?*p diff --git a/vkconfig3/resourcefiles/vulkan_configurator.png b/vkconfig3/resourcefiles/vulkan_configurator.png deleted file mode 100644 index 0b665ad3388c43619070c4062b94c9e5c46ff883..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37072 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 diff --git a/vkconfig3/resources.qrc b/vkconfig3/resources.qrc deleted file mode 100644 index 6a6d611d1a..0000000000 --- a/vkconfig3/resources.qrc +++ /dev/null @@ -1,81 +0,0 @@ - - - resourcefiles/vulkan_configurator.png - resourcefiles/lunarg_logo.png - resourcefiles/qt_logo.png - resourcefiles/vkconfig-off.png - resourcefiles/vkconfig-on.png - - - - ../vkconfig_core/configurations/2.2.2/API dump.json - ../vkconfig_core/configurations/2.2.2/Frame Capture.json - ../vkconfig_core/configurations/2.2.2/Portability.json - ../vkconfig_core/configurations/2.2.2/Synchronization.json - ../vkconfig_core/configurations/2.2.2/Validation.json - - - - ../vkconfig_core/layers/layers_schema.json - ../vkconfig_core/layers/validusage.json - - - - ../vkconfig_core/test/VK_LAYER_LUNARG_reference_1_2_1.json - - - - ../vkconfig_core/layers/130/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/130/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/130/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/130/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/135/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/135/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/135/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/135/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/141/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/141/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/148/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/148/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/154/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/154/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/162/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/162/VK_LAYER_LUNARG_screenshot.json - - - - ../vkconfig_core/layers/170/VK_LAYER_KHRONOS_synchronization2.json - ../vkconfig_core/layers/170/VK_LAYER_KHRONOS_validation.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_api_dump.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_gfxreconstruct.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_monitor.json - ../vkconfig_core/layers/170/VK_LAYER_LUNARG_screenshot.json - - diff --git a/vkconfig3/vkconfig.entitlements b/vkconfig3/vkconfig.entitlements deleted file mode 100644 index 6883e4a27b..0000000000 --- a/vkconfig3/vkconfig.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.disable-library-validation - - - diff --git a/vkconfig3/vulkan_util.cpp b/vkconfig3/vulkan_util.cpp deleted file mode 100644 index d91acffd30..0000000000 --- a/vkconfig3/vulkan_util.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "vulkan_util.h" -#include "configurator.h" - -#include "../vkconfig_core/alert.h" -#include "../vkconfig_core/util.h" -#include "../vkconfig_core/platform.h" -#include "../vkconfig_core/override.h" - -#include - -#include -#include - -#include - -const char *GetVulkanLibrary() { - static const char *TABLE[] = { - "vulkan-1.dll", // PLATFORM_WINDOWS - "libvulkan", // PLATFORM_LINUX - "/usr/local/lib/libvulkan", // PLATFORM_MACOS - "N/A", // PLATFORM_ANDROID - }; - static_assert(countof(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return TABLE[VKC_PLATFORM]; -} - -std::string GetUUIDString(const uint8_t deviceUUID[VK_UUID_SIZE]) { - std::string result; - - for (std::size_t i = 0, n = VK_UUID_SIZE; i < n; ++i) { - result += format("%02X", deviceUUID[i]); - } - - return result; -} - -Version GetVulkanLoaderVersion() { - // Check loader version - QLibrary library(GetVulkanLibrary()); - - if (!library.load()) return Version::VERSION_NULL; - - PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; - vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)library.resolve("vkEnumerateInstanceVersion"); - assert(vkEnumerateInstanceVersion); - - uint32_t version = 0; - const VkResult result = vkEnumerateInstanceVersion(&version); - assert(result == VK_SUCCESS); - - return Version(version); -} - -static std::string GetUserDefinedLayersPathsLog(const char *label, UserDefinedLayersPaths custom_layer_path) { - std::string log; - - const std::vector &user_defined_layer_paths = - Configurator::Get().environment.GetUserDefinedLayersPaths(custom_layer_path); - if (!user_defined_layer_paths.empty()) { - log += format(" - %s:\n", label); - for (std::size_t i = 0, n = user_defined_layer_paths.size(); i < n; ++i) - log += format(" - %s\n", user_defined_layer_paths[i].c_str()); - } else - log += format(" - %s: None\n", label); - - return log; -} - -VkResult CreateInstance(QLibrary &library, VkInstance &instance, bool enumerate_portability) { - if (!enumerate_portability) return VK_ERROR_INCOMPATIBLE_DRIVER; - - PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = - (PFN_vkEnumerateInstanceExtensionProperties)library.resolve("vkEnumerateInstanceExtensionProperties"); - assert(vkEnumerateInstanceExtensionProperties); - - uint32_t property_count = 0; - VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &property_count, nullptr); - assert(err == VK_SUCCESS); - - std::vector instance_properties(property_count); - err = vkEnumerateInstanceExtensionProperties(nullptr, &property_count, &instance_properties[0]); - assert(err == VK_SUCCESS); - - // Handle Portability Enumeration requirements - std::vector instance_extensions; - - for (std::size_t i = 0, n = instance_properties.size(); i < n && enumerate_portability; ++i) { - if (instance_properties[i].extensionName == std::string(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) { - instance_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME); - } -#if VK_KHR_portability_enumeration - else if (instance_properties[i].extensionName == std::string(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) { - instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); - } -#endif - } - - // Check Vulkan Devices - - VkApplicationInfo app = {}; - app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app.pNext = nullptr; - app.pApplicationName = VKCONFIG_SHORT_NAME; - app.applicationVersion = 0; - app.pEngineName = VKCONFIG_SHORT_NAME; - app.engineVersion = 0; - app.apiVersion = VK_API_VERSION_1_1; - - VkInstanceCreateInfo inst_info = {}; - inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; -#if VK_KHR_portability_enumeration - if (!instance_extensions.empty()) { - inst_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; - } -#endif - inst_info.pNext = nullptr; - inst_info.pApplicationInfo = &app; - inst_info.enabledLayerCount = 0; - inst_info.ppEnabledLayerNames = nullptr; - inst_info.enabledExtensionCount = static_cast(instance_extensions.size()); - inst_info.ppEnabledExtensionNames = instance_extensions.empty() ? nullptr : &instance_extensions[0]; - - PFN_vkCreateInstance vkCreateInstance = (PFN_vkCreateInstance)library.resolve("vkCreateInstance"); - assert(vkCreateInstance); - - return vkCreateInstance(&inst_info, nullptr, &instance); -} - -std::string GenerateVulkanStatus() { - std::string log; - - Configurator &configurator = Configurator::Get(); - - // Layers override configuration - switch (configurator.environment.GetMode()) { - default: - case LAYERS_MODE_BY_APPLICATIONS: - log += "- Vulkan Layers Controlled by Vulkan Applications\n"; - break; - case LAYERS_MODE_BY_CONFIGURATOR_RUNNING: - if (configurator.configurations.HasActiveConfiguration(configurator.layers.selected_layers)) { - log += format("- Vulkan Layers Controlled by \"%s\" configuration\n", - configurator.environment.GetSelectedConfiguration().c_str()); - } else { - log += format("- Vulkan Layers Controlled by Vulkan Configurator but no configuration selected\n", - configurator.environment.GetSelectedConfiguration().c_str()); - } - break; - case LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED: - log += "- Vulkan Layers Disabled by Vulkan Configurator\n"; - break; - } - - log += "- Environment variables:\n"; - - // Check Vulkan SDK path - const std::string vk_sdk_path(qgetenv("VULKAN_SDK")); - if (!vk_sdk_path.empty()) - log += format(" - VULKAN_SDK: %s\n", vk_sdk_path.c_str()); - else - log += " - VULKAN_SDK not set\n"; - - // Check VK_LOCAL path - const std::string vk_local_path(GetPath(BUILTIN_PATH_LOCAL)); - if (!vk_local_path.empty()) { - log += format(" - VK_LOCAL: %s\n", vk_local_path.c_str()); - } - - const Version loader_version = GetVulkanLoaderVersion(); - - if (loader_version == Version::VERSION_NULL) { - Alert::LoaderFailure(); - - log += "- Could not find a Vulkan Loader.\n"; - return log; - } else { - log += format("- Vulkan Loader version: %s\n", loader_version.str().c_str()); - const int loader_message_types = configurator.environment.GetLoaderMessageTypes(); - if (loader_message_types != LOADER_MESSAGE_NONE) { - log += format(" - VK_LOADER_DEBUG=%s\n", GetLoaderMessageTokens(loader_message_types).c_str()); - } - } - - log += "- User-Defined Layers locations:\n"; - log += GetUserDefinedLayersPathsLog("VK_LAYER_PATH variable", USER_DEFINED_LAYERS_PATHS_ENV_SET); - log += GetUserDefinedLayersPathsLog("Per-configuration paths", USER_DEFINED_LAYERS_PATHS_GUI); - log += GetUserDefinedLayersPathsLog("VK_ADD_LAYER_PATH variable", USER_DEFINED_LAYERS_PATHS_ENV_ADD); - - const std::string layer_settings_path(qgetenv("VK_LAYER_SETTINGS_PATH")); - if (!layer_settings_path.empty()) { - log += "- `vk_layer_settings.txt` location overridden by VK_LAYER_SETTINGS_PATH:\n"; - if (layer_settings_path.find("vk_layer_settings.txt") == std::string::npos) { - log += format(" %s\n", layer_settings_path.c_str()); - } else { - log += format(" %s\n", ExtractAbsoluteDir(layer_settings_path).c_str()); - } - } else { - const std::string path = GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS); - log += "- `vk_layer_settings.txt` uses the default platform path:\n"; - log += format(" %s\n", ExtractAbsoluteDir(path).c_str()); - } - - // If there is no Vulkan loader installed, we can't call any Vulkan API. - if (loader_version == Version::VERSION_NULL) { - return log; - } - - LayersMode saved_mode = configurator.environment.GetMode(); - configurator.environment.SetMode(LAYERS_MODE_BY_APPLICATIONS); - configurator.configurations.Configure(configurator.layers.selected_layers); - - QLibrary library(GetVulkanLibrary()); - PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = - (PFN_vkEnumerateInstanceLayerProperties)library.resolve("vkEnumerateInstanceLayerProperties"); - assert(vkEnumerateInstanceLayerProperties); - - std::uint32_t instance_layer_count = 0; - VkResult err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); - assert(!err); - - std::vector layers_properties; - layers_properties.resize(instance_layer_count); - - err = vkEnumerateInstanceLayerProperties(&instance_layer_count, &layers_properties[0]); - assert(!err); - - log += "- Available Layers:\n"; - for (std::size_t i = 0, n = layers_properties.size(); i < n; ++i) { - const Layer *layer = FindByKey(configurator.layers.selected_layers, layers_properties[i].layerName); - - std::string status; - if (layer != nullptr) { - if (layer->status != STATUS_STABLE) { - status = GetToken(layer->status); - } - } - - if (status.empty()) { - log += format(" - %s\n", layers_properties[i].layerName); - } else { - log += format(" - %s (%s)\n", layers_properties[i].layerName, status.c_str()); - } - } - - VkInstance inst = VK_NULL_HANDLE; - err = CreateInstance(library, inst, false); - if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { - // If no compatible driver were found, trying with portability enumeration - err = CreateInstance(library, inst, true); - if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { - Alert::InstanceFailure(); - - log += "- Cannot find a compatible Vulkan installable client driver (ICD).\n"; - return log; - } - } - assert(err == VK_SUCCESS); - - PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = - (PFN_vkEnumeratePhysicalDevices)library.resolve("vkEnumeratePhysicalDevices"); - assert(vkEnumeratePhysicalDevices); - - PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = - (PFN_vkEnumerateInstanceExtensionProperties)library.resolve("vkEnumerateInstanceExtensionProperties"); - assert(vkEnumerateInstanceExtensionProperties); - - VkResult result = VK_SUCCESS; - - uint32_t instance_extension_count = 0; - result = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr); - - std::vector instance_extensions; - if (instance_extension_count > 0) { - instance_extensions.resize(instance_extension_count); - } - result = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions.data()); - - bool has_device_id = false; - if (result == VK_SUCCESS) { - for (std::size_t i = 0, n = instance_extensions.size(); i < n; ++i) { - if (instance_extensions[i].extensionName == std::string(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) { - has_device_id = true; - break; - } - } - } - - uint32_t gpu_count = 0; - err = vkEnumeratePhysicalDevices(inst, &gpu_count, NULL); - - PFN_vkDestroyInstance vkDestroyInstance = (PFN_vkDestroyInstance)library.resolve("vkDestroyInstance"); - assert(vkDestroyInstance); - - // This can fail on a new Linux setup. Check and fail gracefully rather than crash. - if (err != VK_SUCCESS) { - Alert::PhysicalDeviceFailure(); - vkDestroyInstance(inst, NULL); - - log += "- Cannot find a compatible Vulkan installable client driver (ICD).\n"; - return log; - } - - std::vector devices; - devices.resize(gpu_count); - - err = vkEnumeratePhysicalDevices(inst, &gpu_count, &devices[0]); - assert(!err); - - PFN_vkGetPhysicalDeviceProperties pfnGetPhysicalDeviceProperties = - (PFN_vkGetPhysicalDeviceProperties)library.resolve("vkGetPhysicalDeviceProperties"); - assert(pfnGetPhysicalDeviceProperties); - - Configurator &configurator_edit = Configurator::Get(); - configurator_edit.device_names.clear(); - - log += "- Physical Devices:\n"; - for (std::size_t i = 0, n = devices.size(); i < n; ++i) { - VkPhysicalDeviceProperties properties; - pfnGetPhysicalDeviceProperties(devices[i], &properties); - - const std::string vk_version = format("%d.%d.%d", VK_VERSION_MAJOR(properties.apiVersion), - VK_VERSION_MINOR(properties.apiVersion), VK_VERSION_PATCH(properties.apiVersion)); - - log += format(" - %s with Vulkan %s\n", properties.deviceName, vk_version.c_str()); - - if (has_device_id) { - PFN_vkGetPhysicalDeviceProperties2 pfnGetPhysicalDeviceProperties2 = - (PFN_vkGetPhysicalDeviceProperties2)library.resolve("vkGetPhysicalDeviceProperties2"); - assert(pfnGetPhysicalDeviceProperties2); - - VkPhysicalDeviceIDPropertiesKHR properties_deviceid{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR, nullptr}; - VkPhysicalDeviceProperties2 properties2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &properties_deviceid}; - - pfnGetPhysicalDeviceProperties2(devices[i], &properties2); - - const std::string deviceUUID = GetUUIDString(properties_deviceid.deviceUUID); - log += format(" - deviceUUID: %s\n", deviceUUID.c_str()); - - const std::string driverUUID = GetUUIDString(properties_deviceid.driverUUID); - log += format(" - driverUUID: %s\n", driverUUID.c_str()); - } - - configurator_edit.device_names.push_back(properties.deviceName); - } - - vkDestroyInstance(inst, NULL); - - configurator.environment.SetMode(saved_mode); - configurator.configurations.Configure(configurator.layers.selected_layers); - - return log; -} diff --git a/vkconfig3/widget_preset.cpp b/vkconfig3/widget_preset.cpp deleted file mode 100644 index 3bf4bfdc23..0000000000 --- a/vkconfig3/widget_preset.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "widget_preset.h" - -#include - -WidgetPreset::WidgetPreset(QTreeWidget* tree, QTreeWidgetItem* item, const Layer& layer, Parameter& parameter) - : WidgetSettingBase(tree, item), layer(layer), parameter(parameter), field(new ComboBox(this)) { - this->field->setFocusPolicy(Qt::StrongFocus); - this->field->addItem(Layer::NO_PRESET); - - preset_labels.push_back(Layer::NO_PRESET); - - for (std::size_t i = 0, n = layer.presets.size(); i < n; ++i) { - const LayerPreset& layer_preset = layer.presets[i]; - - if (!IsPlatformSupported(layer_preset.platform_flags)) continue; - if (layer_preset.view == SETTING_VIEW_HIDDEN) continue; - - this->field->addItem((layer_preset.label + " Preset").c_str()); - preset_labels.push_back(layer_preset.label); - } - - // 'Refresh' need to be called before 'connect' to avoid triggering 'currentIndexChanged' in an infinite loop - this->Refresh(REFRESH_ENABLE_AND_STATE); - this->connect(this->field, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPresetChanged(int))); - - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->tree->setItemWidget(this->item, 0, this); -} - -void WidgetPreset::Refresh(RefreshAreas refresh_areas) { - (void)refresh_areas; - - const std::string& preset_label = layer.FindPresetLabel(parameter.settings); - - this->field->blockSignals(true); - this->field->setCurrentIndex(GetComboBoxIndex(preset_label.c_str())); - this->field->blockSignals(false); - - if (preset_label != Layer::NO_PRESET) { - const LayerPreset* preset = GetPreset(layer.presets, preset_label.c_str()); - assert(preset != nullptr); - this->setToolTip(preset->description.c_str()); - } -} - -void WidgetPreset::resizeEvent(QResizeEvent* event) { - const QRect button_rect = QRect(0, 0, event->size().width(), event->size().height()); - this->field->setGeometry(button_rect); -} - -int WidgetPreset::GetComboBoxIndex(const char* preset_label) const { - for (std::size_t i = 0, n = preset_labels.size(); i < n; ++i) { - if (preset_labels[i] == preset_label) return static_cast(i); - } - - assert(0); - return -1; -} - -void WidgetPreset::OnPresetChanged(int combox_preset_index) { - assert(combox_preset_index >= 0 && static_cast(combox_preset_index) < preset_labels.size()); - const std::string& preset_label = preset_labels[combox_preset_index]; - - if (preset_label == Layer::NO_PRESET) return; - - const LayerPreset* preset = GetPreset(layer.presets, preset_label.c_str()); - assert(preset != nullptr); - parameter.ApplyPresetSettings(*preset); - - emit itemChanged(); -} diff --git a/vkconfig3/widget_setting.h b/vkconfig3/widget_setting.h deleted file mode 100644 index 66517648e1..0000000000 --- a/vkconfig3/widget_setting.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting.h" - -#include -#include -#include -#include - -#include - -static const int MIN_BUTTON_SIZE = 24; -static const int ITEM_HEIGHT = 24; - -enum RefreshAreas { REFRESH_ENABLE_AND_STATE = 0, REFRESH_ENABLE_ONLY }; - -class WidgetSettingBase : public QWidget { - Q_OBJECT - - public: - WidgetSettingBase(QTreeWidget* tree, QTreeWidgetItem* item); - - virtual void Refresh(RefreshAreas refresh_areas) = 0; - - private: - WidgetSettingBase(const WidgetSettingBase&) = delete; - WidgetSettingBase& operator=(const WidgetSettingBase&) = delete; - - protected: - void DisplayOverride(QWidget* widget, const SettingMeta& meta) const; - - QTreeWidget* tree; - QTreeWidgetItem* item; -}; - -int HorizontalAdvance(const QFontMetrics& fm, const QString& string); - -std::string GetLabel(const SettingMeta& meta); diff --git a/vkconfig3/widget_setting_bool.cpp b/vkconfig3/widget_setting_bool.cpp deleted file mode 100644 index 52ebb201d2..0000000000 --- a/vkconfig3/widget_setting_bool.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_setting_bool.h" - -#include - -WidgetSettingBool::WidgetSettingBool(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaBool& meta, - SettingDataSet& data_set) - : WidgetSettingBase(tree, item), meta(meta), data_set(data_set), field(new QCheckBox(this)) { - this->field->setText(GetLabel(this->meta).c_str()); - this->field->setFont(this->tree->font()); - this->field->setToolTip(this->meta.description.c_str()); - this->field->show(); - this->connect(this->field, SIGNAL(clicked()), this, SLOT(OnClicked())); - - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -void WidgetSettingBool::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, this->data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->blockSignals(true); - this->field->setChecked(this->data().value); - this->field->blockSignals(false); - } -} - -void WidgetSettingBool::OnClicked() { - this->data().value = this->field->isChecked(); - - emit itemChanged(); -} - -SettingDataBool& WidgetSettingBool::data() { - SettingDataBool* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig3/widget_setting_bool.h b/vkconfig3/widget_setting_bool.h deleted file mode 100644 index 3b0d56c72e..0000000000 --- a/vkconfig3/widget_setting_bool.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_bool.h" - -#include "widget_setting.h" - -#include - -class WidgetSettingBool : public WidgetSettingBase { - Q_OBJECT - - public: - explicit WidgetSettingBool(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaBool& meta, SettingDataSet& data_set); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnClicked(); - - Q_SIGNALS: - void itemChanged(); - - private: - SettingDataBool& data(); - - const SettingMetaBool& meta; - SettingDataSet& data_set; - - QCheckBox* field; -}; diff --git a/vkconfig3/widget_setting_enum.cpp b/vkconfig3/widget_setting_enum.cpp deleted file mode 100644 index ff838de327..0000000000 --- a/vkconfig3/widget_setting_enum.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_setting_enum.h" -#include "widget_setting.h" -#include "configurator.h" - -#include "../vkconfig_core/setting_filesystem.h" - -#include - -static const int MIN_FIELD_WIDTH = 80; - -static std::vector GetProfileNames(SettingDataSet& data_set) { - std::vector profiles_name; - - SettingDataFileLoad* data_file_load = static_cast(FindSetting(data_set, "profile_file")); - if (data_file_load != nullptr) { - profiles_name = data_file_load->profile_names; - } - - SettingDataFolderLoad* data_folder_load = static_cast(FindSetting(data_set, "profile_dirs")); - if (data_folder_load != nullptr) { - profiles_name = data_folder_load->profile_names; - } - - return profiles_name; -} - -WidgetSettingEnum::WidgetSettingEnum(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaEnum& meta, - SettingDataSet& data_set) - : WidgetSettingBase(tree, item), meta(meta), data_set(data_set), field(new ComboBox(this)), last_resize(0, 0) { - this->field->setFocusPolicy(Qt::StrongFocus); - this->field->show(); - - this->item->setText(0, GetLabel(this->meta).c_str()); - this->item->setFont(0, this->tree->font()); - this->item->setToolTip(0, this->meta.description.c_str()); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); - - this->connect(this->field, SIGNAL(currentIndexChanged(int)), this, SLOT(OnIndexChanged(int))); -} - -void WidgetSettingEnum::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->blockSignals(true); - this->field->blockSignals(true); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (meta.default_value == "${VP_DEFAULT}") { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->clear(); - this->enum_indexes.clear(); - - const std::vector& profiles = GetProfileNames(data_set); - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - - int selection = 0; - const std::string value = this->data().GetValue(); - for (std::size_t i = 0, n = profiles.size(); i < n; ++i) { - this->field->addItem(profiles[i].c_str()); - if (profiles[i] == value) { - selection = static_cast(this->enum_indexes.size()); - } - this->enum_indexes.push_back(i); - } - this->field->setCurrentIndex(selection); - if (!profiles.empty()) { - OnIndexChanged(selection); - } - - // Ensure this->field size match the profiles names size - this->Resize(); - } else if (meta.default_value == "${VP_PHYSICAL_DEVICES}") { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->clear(); - this->enum_indexes.clear(); - - const std::vector& devices = Configurator::Get().GetDeviceNames(); - - int selection = 0; - const std::string value = this->data().GetValue(); - for (std::size_t i = 0, n = devices.size(); i < n; ++i) { - this->field->addItem(devices[i].c_str()); - if (devices[i] == value || "${VP_PHYSICAL_DEVICES}" == value) { - this->data().SetValue(devices[i].c_str()); - selection = static_cast(this->enum_indexes.size()); - } - this->enum_indexes.push_back(i); - } - this->field->setCurrentIndex(selection); - if (!devices.empty()) { - OnIndexChanged(selection); - } - } else if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->clear(); - this->enum_indexes.clear(); - - int selection = 0; - const std::string value = this->data().GetValue(); - - for (std::size_t i = 0, n = this->meta.enum_values.size(); i < n; ++i) { - if (!IsSupported(&this->meta.enum_values[i])) continue; - - this->field->addItem(this->meta.enum_values[i].label.c_str()); - if (this->meta.enum_values[i].key == value) { - selection = static_cast(this->enum_indexes.size()); - } - this->enum_indexes.push_back(i); - } - this->field->setCurrentIndex(selection); - } - - this->blockSignals(false); - this->field->blockSignals(false); -} - -void WidgetSettingEnum::Resize() { - // resizeEvent was never call yet - if (this->last_resize.width() == 0 || this->last_resize.height() == 0) { - return; - } - - int width = MIN_FIELD_WIDTH; - - const QFontMetrics fm = this->field->fontMetrics(); - - if (meta.default_value == "${VP_DEFAULT}") { - const std::vector& profiles = GetProfileNames(data_set); - for (std::size_t i = 0, n = profiles.size(); i < n; ++i) { - width = std::max(width, HorizontalAdvance(fm, (profiles[i] + "0000").c_str())); - } - } else if (meta.default_value == "${VP_PHYSICAL_DEVICES}") { - const std::vector& devices = Configurator::Get().GetDeviceNames(); - for (std::size_t i = 0, n = devices.size(); i < n; ++i) { - width = std::max(width, HorizontalAdvance(fm, (devices[i] + "000").c_str())); - } - } else { - for (std::size_t i = 0, n = this->meta.enum_values.size(); i < n; ++i) { - width = std::max(width, HorizontalAdvance(fm, (this->meta.enum_values[i].label + "0000").c_str())); - } - } - - const int prefix_width = HorizontalAdvance(fm, this->item->text(0) + "0"); - - width = std::min(width, this->last_resize.width() - prefix_width); - - const QRect button_rect(this->last_resize.width() - width, 0, width, this->last_resize.height()); - this->field->setGeometry(button_rect); -} - -void WidgetSettingEnum::resizeEvent(QResizeEvent* event) { - this->last_resize = event->size(); - - this->Resize(); -} - -void WidgetSettingEnum::OnIndexChanged(int index) { - if (meta.default_value == "${VP_DEFAULT}") { - const std::vector& profiles = GetProfileNames(data_set); - assert(index >= 0 && index < static_cast(profiles.size())); - - this->data().SetValue(profiles[index].c_str()); - this->setToolTip(profiles[index].c_str()); - } else if (meta.default_value == "${VP_PHYSICAL_DEVICES}") { - const std::vector& devices = Configurator::Get().GetDeviceNames(); - assert(index >= 0 && index < static_cast(devices.size())); - - this->data().SetValue(devices[index].c_str()); - this->setToolTip(devices[index].c_str()); - } else { - assert(index >= 0 && index < static_cast(this->meta.enum_values.size())); - - const std::size_t value_index = enum_indexes[static_cast(index)]; - this->data().SetValue(this->meta.enum_values[value_index].key.c_str()); - this->setToolTip(this->meta.enum_values[value_index].description.c_str()); - } - - emit itemChanged(); -} - -SettingDataEnum& WidgetSettingEnum::data() { - SettingDataEnum* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig3/widget_setting_enum.h b/vkconfig3/widget_setting_enum.h deleted file mode 100644 index 5f707cfbd3..0000000000 --- a/vkconfig3/widget_setting_enum.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "widget_setting.h" -#include "combo_box.h" - -#include "../vkconfig_core/setting_flags.h" - -#include - -class WidgetSettingEnum : public WidgetSettingBase { - Q_OBJECT - - public: - explicit WidgetSettingEnum(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaEnum& meta, SettingDataSet& data_set); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnIndexChanged(int index); - - Q_SIGNALS: - void itemChanged(); - - private: - void resizeEvent(QResizeEvent* event) override; - - void Resize(); - - SettingDataEnum& data(); - - const SettingMetaEnum& meta; - SettingDataSet& data_set; - - ComboBox* field; - std::vector enum_indexes; - QSize last_resize; -}; diff --git a/vkconfig3/widget_setting_filesystem.cpp b/vkconfig3/widget_setting_filesystem.cpp deleted file mode 100644 index 3c35154e80..0000000000 --- a/vkconfig3/widget_setting_filesystem.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_setting_filesystem.h" -#include "widget_setting.h" - -#include "../vkconfig_core/path.h" -#include "../vkconfig_core/alert.h" -#include "../vkconfig/configurator.h" - -#include - -#include - -WidgetSettingFilesystem::WidgetSettingFilesystem(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFilesystem& meta, - SettingDataSet& data_set) - : WidgetSettingBase(tree, item), - meta(meta), - data_set(data_set), - item_child(new QTreeWidgetItem()), - field(new QLineEdit(this)), - button(new QPushButton(this)) { - this->field->show(); - this->connect(this->field, SIGNAL(textEdited(const QString&)), this, SLOT(textFieldChanged(const QString&))); - - this->button->setText("..."); - this->button->show(); - this->connect(this->button, SIGNAL(clicked()), this, SLOT(browseButtonClicked())); - - this->item->setText(0, GetLabel(this->meta).c_str()); - this->item->setToolTip(0, meta.description.c_str()); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->item->addChild(item_child); - tree->setItemWidget(this->item, 0, this); - - this->item_child->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item_child->setExpanded(true); - tree->setItemWidget(this->item_child, 0, this->field); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -void WidgetSettingFilesystem::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->item_child->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->button->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - LoadPath(this->data().GetValue()); - - this->field->blockSignals(true); - this->field->setText(this->data().GetValue()); - this->field->setToolTip(ReplaceBuiltInVariable(this->data().GetValue()).c_str()); - - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } else { - this->field->setToolTip(ReplaceBuiltInVariable(this->field->text().toStdString()).c_str()); - } - - this->field->blockSignals(false); - } -} - -void WidgetSettingFilesystem::resizeEvent(QResizeEvent* event) { - const QSize parent_size = event->size(); - - const QRect button_rect = QRect(parent_size.width() - MIN_BUTTON_SIZE, 0, MIN_BUTTON_SIZE, parent_size.height()); - this->button->setGeometry(button_rect); -} - -void WidgetSettingFilesystem::LoadPath(const std::string& path) { - switch (this->meta.type) { - case SETTING_LOAD_FILE: { - const SettingMetaFileLoad& setting_meta = static_cast(this->meta); - if (setting_meta.format == "PROFILE") { - if (path.empty()) return; - - SettingDataFileLoad& file_setting_data = static_cast(this->data()); - file_setting_data.profile_names = GetProfileNamesFromFile(path); - - SettingDataString* enum_setting_data = FindSetting(this->data_set, "profile_name"); - if (!file_setting_data.profile_names.empty() && enum_setting_data != nullptr) { - enum_setting_data->SetValue(file_setting_data.profile_names[0].c_str()); - } else { - enum_setting_data->SetValue(""); - } - } - break; - } - case SETTING_LOAD_FOLDER: { - const SettingMetaFolderLoad& setting_meta = static_cast(this->meta); - if (setting_meta.format == "PROFILE") { - if (path.empty()) return; - - SettingDataFolderLoad& setting_data = static_cast(this->data()); - setting_data.profile_names = GetProfileNamesFromDir(path); - - SettingDataString* enum_setting_data = FindSetting(this->data_set, "profile_name"); - if (enum_setting_data != nullptr) { - if (std::find(setting_data.profile_names.begin(), setting_data.profile_names.end(), - enum_setting_data->GetValue()) == setting_data.profile_names.end()) { - enum_setting_data->SetValue("${VP_DEFAULT}"); - } - } - } - break; - } - default: - break; - } -} - -void WidgetSettingFilesystem::browseButtonClicked() { - std::string path = field->text().toStdString(); - if (path.empty()) { - path = "${VK_LOCAL}"; - } - if (!QFileInfo(ReplaceBuiltInVariable(path).c_str()).exists()) { - path = this->data().GetValue(); - } - if (!QFileInfo(ReplaceBuiltInVariable(path).c_str()).exists()) { - path.clear(); - } - - const std::string replaced_path = ReplaceBuiltInVariable(path); - - const char* filter = this->meta.filter.c_str(); - std::string new_path; - - switch (this->meta.type) { - case SETTING_LOAD_FILE: - new_path = QFileDialog::getOpenFileName(this->button, "Select file", replaced_path.c_str(), filter).toStdString(); - break; - case SETTING_SAVE_FILE: - new_path = QFileDialog::getSaveFileName(this->button, "Select File", replaced_path.c_str(), filter).toStdString(); - break; - case SETTING_LOAD_FOLDER: - case SETTING_SAVE_FOLDER: - new_path = QFileDialog::getExistingDirectory(this->button, "Select Folder", replaced_path.c_str()).toStdString(); - break; - default: - assert(0); - break; - } - - // The user has cancel the operation - if (new_path.empty()) { - return; - } - - new_path = ConvertNativeSeparators(new_path); - - // The path didn't change, preserve the built-in variables - if (replaced_path == new_path) { - return; - } - - this->data().SetValue(new_path.c_str()); - - this->field->setText(this->data().GetValue()); - this->field->setToolTip(ReplaceBuiltInVariable(this->field->text().toStdString()).c_str()); - - LoadPath(new_path); - - emit itemChanged(); -} - -void WidgetSettingFilesystem::textFieldChanged(const QString& value) { - std::string file = value.toStdString(); - - if (!file.empty()) { - LoadPath(file); - - if (VKC_ENV == VKC_ENV_WIN32) { - file = ConvertNativeSeparators(file); - } - } - - if (QFileInfo(ReplaceBuiltInVariable(file).c_str()).exists()) { - this->data().SetValue(file.c_str()); - this->field->setToolTip(ReplaceBuiltInVariable(file.c_str()).c_str()); - } - - emit itemChanged(); -} - -SettingDataString& WidgetSettingFilesystem::data() { - SettingDataString* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig3/widget_setting_filesystem.h b/vkconfig3/widget_setting_filesystem.h deleted file mode 100644 index 6d82e368da..0000000000 --- a/vkconfig3/widget_setting_filesystem.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_filesystem.h" - -#include "widget_setting.h" - -#include -#include -#include - -class WidgetSettingFilesystem : public WidgetSettingBase { - Q_OBJECT - - public: - explicit WidgetSettingFilesystem(QTreeWidget *tree, QTreeWidgetItem *item, const SettingMetaFilesystem &meta, - SettingDataSet &data_set); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void browseButtonClicked(); - void textFieldChanged(const QString &value); - - Q_SIGNALS: - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent *event) override; - - private: - SettingDataString &data(); - void LoadPath(const std::string &path); - - const SettingMetaFilesystem &meta; - SettingDataSet &data_set; - - QTreeWidgetItem *item_child; - QLineEdit *field; - QPushButton *button; -}; diff --git a/vkconfig3/widget_setting_flags.cpp b/vkconfig3/widget_setting_flags.cpp deleted file mode 100644 index e47396b57b..0000000000 --- a/vkconfig3/widget_setting_flags.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_setting_flags.h" -#include "widget_setting.h" - -#include "../vkconfig_core/layer.h" -#include "../vkconfig_core/util.h" - -#include - -#include - -WidgetSettingFlag::WidgetSettingFlag(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFlags& meta, - SettingDataSet& data_set, const std::string& flag) - : WidgetSettingBase(tree, item), meta(meta), data_set(data_set), flag(flag), field(new QCheckBox(this)) { - assert(!flag.empty()); - - const SettingEnumValue* enum_value = FindByKey(meta.enum_values, flag.c_str()); - assert(enum_value); - - const std::string status = meta.status == STATUS_STABLE ? "" : std::string(" (") + GetToken(enum_value->status) + ")"; - - this->field->setText((enum_value->label + status).c_str()); - this->field->setToolTip(enum_value->description.c_str()); - this->field->setFont(tree->font()); - this->field->show(); - this->connect(this->field, SIGNAL(clicked(bool)), this, SLOT(OnClicked(bool))); - - this->item->setExpanded(enum_value->expanded); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -void WidgetSettingFlag::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - const std::vector& value = this->data().value; - - this->field->blockSignals(true); - this->field->setChecked(std::find(value.begin(), value.end(), flag) != value.end()); - this->field->blockSignals(false); - } -} - -void WidgetSettingFlag::OnClicked(bool checked) { - if (checked) { - AppendString(this->data().value, flag); - } else { - RemoveString(this->data().value, flag); - } - - emit itemChanged(); -} - -SettingDataFlags& WidgetSettingFlag::data() { - SettingDataFlags* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig3/widget_setting_flags.h b/vkconfig3/widget_setting_flags.h deleted file mode 100644 index 393ca38209..0000000000 --- a/vkconfig3/widget_setting_flags.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_flags.h" - -#include "widget_setting.h" - -#include - -class WidgetSettingFlag : public WidgetSettingBase { - Q_OBJECT - - public: - explicit WidgetSettingFlag(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFlags& meta, SettingDataSet& data_set, - const std::string& flag); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnClicked(bool checked); - - Q_SIGNALS: - void itemChanged(); - - private: - SettingDataFlags& data(); - - const SettingMetaFlags& meta; - SettingDataSet& data_set; - - std::string flag; - QCheckBox* field; -}; diff --git a/vkconfig3/widget_setting_float.h b/vkconfig3/widget_setting_float.h deleted file mode 100644 index 66c76a1db1..0000000000 --- a/vkconfig3/widget_setting_float.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "widget_setting.h" - -#include "../vkconfig_core/setting_float.h" - -#include -#include -#include -#include - -class WidgetSettingFloat : public WidgetSettingBase { - Q_OBJECT - - public: - WidgetSettingFloat(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFloat& meta, SettingDataSet& data_set); - virtual ~WidgetSettingFloat(); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnTextEdited(const QString& value); - void OnErrorValue(); - void OnValidValue(); - - Q_SIGNALS: - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent* event) override; - - private: - void Resize(); - SettingInputError ProcessInputValue(); - SettingDataFloat& data(); - - const SettingMetaFloat& meta; - SettingDataSet& data_set; - - std::string value_buffer; - QLineEdit* field; - QTimer* timer_error; - QTimer* timer_valid; - QSize resize; - QPalette default_palette; -}; diff --git a/vkconfig3/widget_setting_frames.h b/vkconfig3/widget_setting_frames.h deleted file mode 100644 index 64312ebdfc..0000000000 --- a/vkconfig3/widget_setting_frames.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_frames.h" - -#include "widget_setting.h" - -#include -#include -#include -#include -#include - -class WidgetSettingFrames : public WidgetSettingBase { - Q_OBJECT - - public: - WidgetSettingFrames(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFrames& meta, SettingDataSet& data_set); - virtual ~WidgetSettingFrames(); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnTextEdited(const QString& value); - void OnErrorValue(); - void OnValidValue(); - - Q_SIGNALS: - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent* event) override; - - private: - void Resize(); - SettingInputError ProcessInputValue(); - SettingDataFrames& data(); - - const SettingMetaFrames& meta; - SettingDataSet& data_set; - - std::string value_buffer; - QLineEdit* field; - QTimer* timer_error; - QTimer* timer_valid; - QSize resize; - QPalette default_palette; -}; diff --git a/vkconfig3/widget_setting_int.h b/vkconfig3/widget_setting_int.h deleted file mode 100644 index 7174af51a9..0000000000 --- a/vkconfig3/widget_setting_int.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_int.h" - -#include "widget_setting.h" - -#include -#include -#include - -class WidgetSettingInt : public WidgetSettingBase { - Q_OBJECT - - public: - WidgetSettingInt(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaInt& meta, SettingDataSet& data_set); - virtual ~WidgetSettingInt(); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnTextEdited(const QString& value); - void OnErrorValue(); - void OnValidValue(); - - Q_SIGNALS: - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent* event) override; - - private: - void Resize(); - SettingInputError ProcessInputValue(); - SettingDataInt& data(); - - const SettingMetaInt& meta; - SettingDataSet& data_set; - - std::string value_buffer; - QLineEdit* field; - QTimer* timer_error; - QTimer* timer_valid; - QSize resize; - QPalette default_palette; -}; diff --git a/vkconfig3/widget_setting_list.cpp b/vkconfig3/widget_setting_list.cpp deleted file mode 100644 index f33af7f398..0000000000 --- a/vkconfig3/widget_setting_list.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_setting_list.h" -#include "widget_setting_list_element.h" -#include "widget_setting.h" - -#include "../vkconfig_core/util.h" - -#include - -#include - -const char *GetFieldToolTip(const SettingMetaList &meta, bool current_list_empty) { - if (meta.list.empty()) { - return "Start tapping to add a new value"; - } else if (meta.list_only && current_list_empty) { - return "All the accepted values are already listed"; - } else { - return "Start tapping to search for available values"; - } -} - -WidgetSettingList::WidgetSettingList(QTreeWidget *tree, QTreeWidgetItem *item, const SettingMetaList &meta, - SettingDataSet &data_set) - : WidgetSettingBase(tree, item), - meta(meta), - data_set(data_set), - search(nullptr), - field(new QLineEdit(this)), - add_button(new QPushButton(this)), - list(meta.list) { - std::vector value = this->data().value; - for (std::size_t i = 0, n = value.size(); i < n; ++i) { - ::RemoveValue(this->list, value[i]); - } - - const char *tooltip = GetFieldToolTip(this->meta, this->list.empty()); - - this->field->show(); - this->field->setText(""); - this->field->setToolTip(tooltip); - this->field->setFont(this->tree->font()); - this->field->setFocusPolicy(Qt::StrongFocus); - this->field->installEventFilter(this); - this->ResetCompleter(); - - this->connect(this->field, SIGNAL(textChanged(const QString &)), this, SLOT(OnTextEdited(const QString &))); - this->connect(this->field, SIGNAL(returnPressed()), this, SLOT(OnElementAppended()), Qt::QueuedConnection); - - this->add_button->show(); - this->add_button->setText("+"); - this->add_button->setFont(this->tree->font()); - - this->connect(this->add_button, SIGNAL(pressed()), this, SLOT(OnElementAppended()), Qt::QueuedConnection); - - std::sort(value.begin(), value.end()); - this->data().value = value; - - this->item->setText(0, (this->meta.label + " ").c_str()); - this->item->setFont(0, this->tree->font()); - this->item->setToolTip(0, this->meta.description.c_str()); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -void WidgetSettingList::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE && (!this->meta.list_only || !this->list.empty())); - this->add_button->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE && !this->field->text().isEmpty()); - - if (this->meta.list_only && this->list.empty()) { - this->field->hide(); - this->add_button->hide(); - } else { - this->field->show(); - this->add_button->show(); - } - - std::vector &value = this->data().value; - - if (value != this->value_cached) { - this->value_cached = value; - - this->tree->blockSignals(true); - - while (this->item->childCount() > 0) { - this->item->removeChild(this->item->child(0)); - } - - for (std::size_t i = 0, n = value.size(); i < n; ++i) { - this->AddElement(value[i]); - } - - this->tree->blockSignals(false); - } - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - } -} - -void WidgetSettingList::Resize() { - const int button_size = MIN_BUTTON_SIZE; - - const QFontMetrics fm = this->fontMetrics(); - const int text_width = HorizontalAdvance(fm, item->text(0)); - - this->field->setGeometry(text_width, 0, this->size.width() - button_size - text_width, this->size.height()); - this->add_button->setGeometry(this->size.width() - button_size, 0, button_size, this->size.height()); -} - -void WidgetSettingList::resizeEvent(QResizeEvent *event) { - this->size = event->size(); - this->Resize(); -} - -bool WidgetSettingList::eventFilter(QObject *target, QEvent *event) { - (void)target; - if (event->type() == QEvent::Wheel) { - event->ignore(); - return true; - } - - return this->field->eventFilter(target, event); -} - -void WidgetSettingList::ResetCompleter() { - if (this->search != nullptr) this->search->deleteLater(); - - this->search = new QCompleter(ConvertValues(this->list), this); - this->search->setCompletionMode(QCompleter::PopupCompletion); - this->search->setModelSorting(QCompleter::CaseSensitivelySortedModel); - this->search->setFilterMode(Qt::MatchContains); - this->search->setCaseSensitivity(Qt::CaseSensitive); - this->search->setMaxVisibleItems(20); - - this->field->setCompleter(this->search); - - this->connect(this->search, SIGNAL(activated(const QString &)), this, SLOT(OnCompleted(const QString &)), Qt::QueuedConnection); -} - -void WidgetSettingList::AddElement(EnabledNumberOrString &element) { - QTreeWidgetItem *child = new QTreeWidgetItem(); - child->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->addChild(child); - - WidgetSettingListElement *widget = new WidgetSettingListElement(this->tree, child, this->meta, this->data_set, element); - this->tree->setItemWidget(child, 0, widget); - - this->connect(widget, SIGNAL(itemChanged()), this, SLOT(OnSettingChanged())); - this->connect(widget, SIGNAL(itemSelected(const QString &)), this, SLOT(OnElementRemoved(const QString &))); -} - -void WidgetSettingList::OnCompleted(const QString &value) { - (void)value; - // We can't do this right away, the completer emits it's signal - // before it's really "complete". If we clear the control too soon - // it clears the completers value too. This might be a Qt bug, but this - // works really well as a work-a-round - OnElementAppended(); -} - -void WidgetSettingList::OnElementAppended() { - const std::string entry = this->field->text().toStdString(); - if (entry.empty()) return; - - if (this->meta.list_only && !IsValueFound(this->meta.list, entry)) { - QMessageBox alert; - alert.setWindowTitle("Invalid value"); - alert.setText(format("'%s' setting doesn't accept '%s' as a value", this->meta.label.c_str(), entry.c_str()).c_str()); - alert.setInformativeText("Please select a value from the list."); - alert.setIcon(QMessageBox::Warning); - alert.exec(); - return; - } - - std::vector &value = this->data().value; - - // Add the value if it's not in the list already - if (IsValueFound(value, entry)) { - QMessageBox alert; - alert.setWindowTitle("Duplicated value"); - alert.setText(format("'%s' setting already has the value '%s' listed", this->meta.label.c_str(), entry.c_str()).c_str()); - alert.setIcon(QMessageBox::Warning); - alert.exec(); - return; - } - - this->field->setText(""); - - value.push_back(entry); - std::sort(value.begin(), value.end()); - ::RemoveValue(this->list, entry); - - emit itemChanged(); -} - -void WidgetSettingList::OnTextEdited(const QString &value) { - assert(this->add_button); - assert(this->field); - - if (value.isEmpty()) { - this->item->setText(0, (this->meta.label + " ").c_str()); - } else if (value.size() >= 1 && !this->item->text(0).isEmpty()) { - this->item->setText(0, ""); - } - - this->Resize(); - - this->add_button->setEnabled(!value.isEmpty()); -} - -void WidgetSettingList::OnElementRemoved(const QString &element) { - NumberOrString list_value(element.toStdString()); - this->list.push_back(list_value); - - RemoveValue(this->data().value, EnabledNumberOrString(list_value)); -} - -void WidgetSettingList::OnSettingChanged() { emit itemChanged(); } - -SettingDataList &WidgetSettingList::data() { - SettingDataList *data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig3/widget_setting_list.h b/vkconfig3/widget_setting_list.h deleted file mode 100644 index 6fcdb0f34b..0000000000 --- a/vkconfig3/widget_setting_list.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_list.h" - -#include "widget_setting.h" - -#include -#include -#include -#include -#include - -class WidgetSettingList : public WidgetSettingBase { - Q_OBJECT - - public: - explicit WidgetSettingList(QTreeWidget *tree, QTreeWidgetItem *item, const SettingMetaList &meta, SettingDataSet &data_set); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnCompleted(const QString &value); - void OnElementAppended(); - void OnTextEdited(const QString &value); - void OnSettingChanged(); - void OnElementRemoved(const QString &value); - - Q_SIGNALS: - void itemSelected(const QString &value); - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent *event) override; - bool eventFilter(QObject *target, QEvent *event) override; - - private: - void Resize(); - void AddElement(EnabledNumberOrString &element); - void ResetCompleter(); - - SettingDataList &data(); - - const SettingMetaList &meta; - SettingDataSet &data_set; - - QCompleter *search; - QLineEdit *field; - QPushButton *add_button; - QSize size; - - std::vector list; - std::vector value_cached; -}; diff --git a/vkconfig3/widget_setting_list_element.cpp b/vkconfig3/widget_setting_list_element.cpp deleted file mode 100644 index 50ab9672c4..0000000000 --- a/vkconfig3/widget_setting_list_element.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "widget_setting_list_element.h" -#include "widget_setting.h" - -#include "../vkconfig_core/layer.h" -#include "../vkconfig_core/util.h" - -#include - -WidgetSettingListElement::WidgetSettingListElement(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaList& meta, - SettingDataSet& data_set, EnabledNumberOrString& element) - : WidgetSettingBase(tree, item), - meta(meta), - data_set(data_set), - element(element), - button(new QPushButton(this)), - field(new QCheckBox(this)) { - const std::string text = element.key.empty() ? format("%d", element.number) : element.key; - const std::string status = meta.status == STATUS_STABLE ? "" : std::string(" (") + GetToken(this->meta.status) + ")"; - - this->field->setText((text + status).c_str()); - this->field->setFont(this->tree->font()); - this->field->setToolTip(text.c_str()); - this->field->setCheckable(true); - this->connect(this->field, SIGNAL(clicked(bool)), this, SLOT(OnElementChecked(bool))); - - this->button->setText("-"); - this->button->setFont(tree->font()); - this->button->show(); - this->connect(this->button, SIGNAL(clicked()), this, SLOT(OnElementRemoved())); - - this->item->setExpanded(true); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -void WidgetSettingListElement::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->button->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->blockSignals(true); - std::vector& value = this->data().value; - this->field->setChecked(std::find(value.begin(), value.end(), this->element)->enabled); - this->field->blockSignals(false); - } -} - -void WidgetSettingListElement::resizeEvent(QResizeEvent* event) { - const QSize parent_size = event->size(); - - const QRect field_rect = QRect(0, 0, parent_size.width() - MIN_BUTTON_SIZE, parent_size.height()); - this->field->setGeometry(field_rect); - - const QRect button_rect = QRect(parent_size.width() - MIN_BUTTON_SIZE, 0, MIN_BUTTON_SIZE, parent_size.height()); - this->button->setGeometry(button_rect); -} - -void WidgetSettingListElement::OnElementChecked(bool checked) { - this->element.enabled = checked; - - emit itemChanged(); -} - -void WidgetSettingListElement::OnElementRemoved() { - std::vector& value = this->data().value; - - auto it = std::find(value.begin(), value.end(), this->element); - assert(it != value.end()); - - value.erase(it); - - emit itemSelected(this->field->text()); // Remove the element from the parent WidgetSettingList - emit itemChanged(); // Notify the setting tree that settings have changed -} - -SettingDataList& WidgetSettingListElement::data() { - SettingDataList* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig3/widget_setting_list_element.h b/vkconfig3/widget_setting_list_element.h deleted file mode 100644 index f7f501497f..0000000000 --- a/vkconfig3/widget_setting_list_element.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_list.h" - -#include "widget_setting.h" - -#include -#include -#include - -class WidgetSettingListElement : public WidgetSettingBase { - Q_OBJECT - public: - explicit WidgetSettingListElement(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaList& meta, - SettingDataSet& data_set, EnabledNumberOrString& element); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnElementRemoved(); - void OnElementChecked(bool checked); - - Q_SIGNALS: - void itemSelected(const QString& value); - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent* event) override; - - private: - SettingDataList& data(); - - const SettingMetaList& meta; - SettingDataSet& data_set; - - EnabledNumberOrString& element; - QPushButton* button; - QCheckBox* field; -}; diff --git a/vkconfig3/widget_setting_string.cpp b/vkconfig3/widget_setting_string.cpp deleted file mode 100644 index 4876d69029..0000000000 --- a/vkconfig3/widget_setting_string.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "widget_setting_string.h" -#include "widget_setting.h" - -#include - -static const int MIN_FIELD_WIDTH = 120; - -WidgetSettingString::WidgetSettingString(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaString& meta, - SettingDataSet& data_set) - : WidgetSettingBase(tree, item), meta(meta), data_set(data_set), field(new QLineEdit(this)) { - this->field->setText(this->data().GetValue()); - QFont font = tree->font(); - if (meta.key == "force_device_uuid") { - font.setFamily("Consolas"); - font.setPointSize(10); - } - this->field->setFont(font); - this->field->setToolTip(this->field->text()); - this->field->show(); - - this->connect(this->field, SIGNAL(textEdited(const QString&)), this, SLOT(OnTextEdited(const QString&))); - - this->item->setText(0, GetLabel(this->meta).c_str()); - this->item->setFont(0, this->tree->font()); - this->item->setToolTip(0, meta.description.c_str()); - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->item->setExpanded(this->meta.expanded); - this->tree->setItemWidget(this->item, 0, this); - - this->Refresh(REFRESH_ENABLE_AND_STATE); -} - -void WidgetSettingString::Refresh(RefreshAreas refresh_areas) { - const SettingDependenceMode enabled = ::CheckDependence(this->meta, data_set); - - this->item->setHidden(enabled == SETTING_DEPENDENCE_HIDE); - this->item->setDisabled(enabled != SETTING_DEPENDENCE_ENABLE); - this->field->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - this->setEnabled(enabled == SETTING_DEPENDENCE_ENABLE); - - if (refresh_areas == REFRESH_ENABLE_AND_STATE) { - if (::CheckSettingOverridden(this->meta)) { - this->DisplayOverride(this->field, this->meta); - } - - this->field->setText(this->data().GetValue()); - } -} - -void WidgetSettingString::Resize() { - const QFontMetrics fm = this->field->fontMetrics(); - const int width = std::max(HorizontalAdvance(fm, this->field->text() + "00"), MIN_FIELD_WIDTH); - - const QRect field_rect = QRect(this->resize.width() - width, 0, width, this->resize.height()); - this->field->setGeometry(field_rect); -} - -void WidgetSettingString::resizeEvent(QResizeEvent* event) { - this->resize = event->size(); - this->Resize(); -} - -void WidgetSettingString::OnTextEdited(const QString& value) { - this->data().SetValue(value.toStdString().c_str()); - this->field->setToolTip(this->field->text()); - - emit itemChanged(); -} - -SettingDataString& WidgetSettingString::data() { - SettingDataString* data = FindSetting(this->data_set, this->meta.key.c_str()); - assert(data != nullptr); - return *data; -} diff --git a/vkconfig3/widget_setting_string.h b/vkconfig3/widget_setting_string.h deleted file mode 100644 index 82a9c2bda2..0000000000 --- a/vkconfig3/widget_setting_string.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/setting_string.h" - -#include "widget_setting.h" - -#include -#include - -class WidgetSettingString : public WidgetSettingBase { - Q_OBJECT - - public: - WidgetSettingString(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaString& meta, SettingDataSet& data_set); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnTextEdited(const QString& value); - - Q_SIGNALS: - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent* event) override; - - private: - void Resize(); - SettingDataString& data(); - - const SettingMetaString& meta; - SettingDataSet& data_set; - - QLineEdit* field; - QSize resize; -}; diff --git a/vkconfig_cmd/CMakeLists.txt b/vkconfig_cmd/CMakeLists.txt new file mode 100644 index 0000000000..7e381602bf --- /dev/null +++ b/vkconfig_cmd/CMakeLists.txt @@ -0,0 +1,57 @@ +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) +find_package(Qt5 COMPONENTS Core Gui Widgets Network QUIET) + +if(NOT Qt5_FOUND) + message("WARNING: vkconfig will be excluded because Qt5 was not found. Please add Qt5 into the PATH environment variable") +elseif(Qt5_VERSION VERSION_LESS 5.5) + message("WARNING: vkconfig will be excluded because the found Qt version is too old. vkconfig requires version 5.5.") +else() + file(GLOB FILES_UI ./*.ui) + + source_group("UI Files" FILES ${FILES_UI}) + + file(GLOB FILES_SOURCE ./*.cpp) + file(GLOB FILES_HEADER ./*.h) + file(GLOB FILES_DOCS ./*.md) + + source_group("Docs Files" FILES ${FILES_DOCS}) + + set(FILES_ALL ${FILES_UI} ${FILES_SOURCE} ${FILES_HEADER} ${FILES_DOCS}) + + if(NOT APPLE) + if (NOT DEFINED CMAKE_INSTALL_BINDIR) + include(GNUInstallDirs) + endif() + + if(WIN32) + add_executable(vkconfig-cmd ${FILES_ALL}) + target_compile_definitions(vkconfig-cmd PRIVATE _CRT_SECURE_NO_WARNINGS) + target_compile_options(vkconfig-cmd PRIVATE $<$:/MP>) + target_link_libraries(vkconfig-cmd Cfgmgr32) + else() + add_executable(vkconfig-cmd ${FILES_ALL} ${FILES_UI}) + endif() + + target_link_libraries(vkconfig-cmd Vulkan::Headers vkconfig-core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) + target_compile_definitions(vkconfig-cmd PRIVATE QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT) + set_target_properties(vkconfig-cmd PROPERTIES FOLDER "vkconfig") + set_target_properties(vkconfig-cmd PROPERTIES OUTPUT_NAME "vkconfig") + + install(TARGETS vkconfig-cmd DESTINATION ${CMAKE_INSTALL_BINDIR}) + + if(WIN32) + get_target_property(QMAKE_EXE Qt5::qmake IMPORTED_LOCATION) + get_filename_component(QT_BIN_DIR "${QMAKE_EXE}" DIRECTORY) + find_program(WINDEPLOYQT_EXE windeployqt HINTS "${QT_BIN_DIR}") + + message("Will run ${WINDEPLOYQT_EXE} at ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig.exe") + install(CODE "execute_process(COMMAND ${WINDEPLOYQT_EXE} ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig.exe)") + endif() + else() + include(macOS/vkconfig.cmake) + endif() +endif() diff --git a/vkconfig/macOS/Info.plist b/vkconfig_cmd/macOS/Info.plist similarity index 100% rename from vkconfig/macOS/Info.plist rename to vkconfig_cmd/macOS/Info.plist diff --git a/vkconfig/macOS/Resources/VulkanIcon.icns b/vkconfig_cmd/macOS/Resources/VulkanIcon.icns similarity index 100% rename from vkconfig/macOS/Resources/VulkanIcon.icns rename to vkconfig_cmd/macOS/Resources/VulkanIcon.icns diff --git a/vkconfig3/macOS/vkconfig.cmake b/vkconfig_cmd/macOS/vkconfig.cmake similarity index 71% rename from vkconfig3/macOS/vkconfig.cmake rename to vkconfig_cmd/macOS/vkconfig.cmake index e64ce1eb80..ade4372653 100644 --- a/vkconfig3/macOS/vkconfig.cmake +++ b/vkconfig_cmd/macOS/vkconfig.cmake @@ -17,7 +17,7 @@ -add_executable(vkconfig +add_executable(vkconfig-cmd MACOSX_BUNDLE ${FILES_ALL} ${CMAKE_CURRENT_SOURCE_DIR}/macOS/Resources/VulkanIcon.icns @@ -28,14 +28,14 @@ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/macOS/Resources/VulkanIc PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") -target_link_libraries(vkconfig vkconfig_core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) -target_link_libraries(vkconfig "-framework Cocoa -framework QuartzCore") +target_link_libraries(vkconfig-cmd vkconfig-core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) +target_link_libraries(vkconfig-cmd "-framework Cocoa -framework QuartzCore") get_target_property(QMAKE_EXE Qt5::qmake IMPORTED_LOCATION) get_filename_component(QT_BIN_DIR "${QMAKE_EXE}" DIRECTORY) find_program(MACDEPLOYQT_EXE macdeployqt HINTS "${QT_BIN_DIR}") -add_custom_command(TARGET vkconfig POST_BUILD +add_custom_command(TARGET vkconfig-cmd POST_BUILD COMMAND "${MACDEPLOYQT_EXE}" "${CMAKE_CURRENT_BINARY_DIR}/vkconfig.app/" -always-overwrite @@ -44,15 +44,16 @@ add_custom_command(TARGET vkconfig POST_BUILD COMMENT "Running macdeployqt..." ) -add_custom_command(TARGET vkconfig POST_BUILD +add_custom_command(TARGET vkconfig-cmd POST_BUILD COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/macOS/Info.plist" "${CMAKE_CURRENT_BINARY_DIR}/vkconfig.app/Contents/" COMMENT "Copying Info.plist to vkconfig.app..." ) -set_target_properties(vkconfig PROPERTIES SKIP_BUILD_RPATH FALSE) -set_target_properties(vkconfig PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) -set_target_properties(vkconfig PROPERTIES INSTALL_RPATH "") -set_target_properties(vkconfig PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) -install(TARGETS vkconfig BUNDLE DESTINATION "bin") +set_target_properties(vkconfig-cmd PROPERTIES OUTPUT_NAME "vkconfig") +set_target_properties(vkconfig-cmd PROPERTIES SKIP_BUILD_RPATH FALSE) +set_target_properties(vkconfig-cmd PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) +set_target_properties(vkconfig-cmd PROPERTIES INSTALL_RPATH "") +set_target_properties(vkconfig-cmd PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) +install(TARGETS vkconfig-cmd BUNDLE DESTINATION "bin") diff --git a/vkconfig/main.cpp b/vkconfig_cmd/main.cpp similarity index 87% rename from vkconfig/main.cpp rename to vkconfig_cmd/main.cpp index 1335279ac0..204d496771 100644 --- a/vkconfig/main.cpp +++ b/vkconfig_cmd/main.cpp @@ -18,21 +18,14 @@ * - Christophe Riccio */ -#include "main_gui.h" #include "main_reset.h" #include "main_layers.h" #include "main_doc.h" -#include "main_signal.h" #include "../vkconfig_core/path.h" - -#include +#include "../vkconfig_core/configurator_signal.h" int main(int argc, char* argv[]) { - ::vkconfig_version = "vkconfig"; - - InitSignals(); - const CommandLine command_line(argc, argv); if (command_line.error != ERROR_NONE) { @@ -41,6 +34,8 @@ int main(int argc, char* argv[]) { return -1; } + InitSignals(); + switch (command_line.command) { case COMMAND_SHOW_USAGE: { command_line.usage(); @@ -56,10 +51,6 @@ int main(int argc, char* argv[]) { case COMMAND_RESET: { return run_reset(argc, argv, command_line); } - case COMMAND_VULKAN_SDK: - case COMMAND_GUI: { - return run_gui(argc, argv, command_line); - } case COMMAND_DOC: { return run_doc(command_line); } diff --git a/vkconfig/main_doc.cpp b/vkconfig_cmd/main_doc.cpp similarity index 75% rename from vkconfig/main_doc.cpp rename to vkconfig_cmd/main_doc.cpp index 4a8c007e70..29e145db3f 100644 --- a/vkconfig/main_doc.cpp +++ b/vkconfig_cmd/main_doc.cpp @@ -20,8 +20,8 @@ */ #include "main_doc.h" -#include "configurator.h" +#include "../vkconfig_core/configurator.h" #include "../vkconfig_core/layer_manager.h" #include "../vkconfig_core/doc.h" #include "../vkconfig_core/configuration_manager.h" @@ -29,12 +29,7 @@ #include int run_doc_html(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); + LayerManager layers; for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { const Layer& layer = layers.selected_layers[i]; @@ -50,12 +45,7 @@ int run_doc_html(const CommandLine& command_line) { } int run_doc_markdown(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); + LayerManager layers; for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { const Layer& layer = layers.selected_layers[i]; @@ -72,24 +62,20 @@ int run_doc_markdown(const CommandLine& command_line) { int run_doc_settings(const CommandLine& command_line) { int rval = 0; - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - ConfigurationManager configuration_manager(environment); - Configuration config; - LayerManager layers(environment); - Layer* layer; - layers.LoadLayer(command_line.doc_layer_name); - layer = FindByKey(layers.selected_layers, command_line.doc_layer_name.c_str()); + LayerManager layers; + + Layer* layer = layers.Find(command_line.doc_layer_name.c_str()); if (!layer) { fprintf(stderr, "vkconfig: Could not load layer %s\n", command_line.doc_layer_name.c_str()); fprintf(stderr, "Run \"vkconfig layers --list\" to get list of available layers\n"); return -1; } - config = configuration_manager.CreateConfiguration(layers.selected_layers, "Config"); + + ConfigurationManager configuration_manager; + Configuration config = configuration_manager.CreateConfiguration(layers.selected_layers, "Config"); config.parameters = GatherParameters(config.parameters, layers.selected_layers); - config.parameters[0].state = LAYER_STATE_OVERRIDDEN; + config.parameters[0].control = LAYER_CONTROL_ON; ExportSettingsDoc(layers.selected_layers, config, command_line.doc_out_dir + "/vk_layer_settings.txt"); return rval; diff --git a/vkconfig3/main_doc.h b/vkconfig_cmd/main_doc.h similarity index 84% rename from vkconfig3/main_doc.h rename to vkconfig_cmd/main_doc.h index ce23885758..75f5548bfc 100644 --- a/vkconfig3/main_doc.h +++ b/vkconfig_cmd/main_doc.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2022 Valve Corporation - * Copyright (c) 2022 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ * * Authors: * - David Pinedo + * - Christophe Riccio */ #pragma once diff --git a/vkconfig3/main_layers.cpp b/vkconfig_cmd/main_layers.cpp similarity index 63% rename from vkconfig3/main_layers.cpp rename to vkconfig_cmd/main_layers.cpp index 1e5b041607..50cbae543b 100644 --- a/vkconfig3/main_layers.cpp +++ b/vkconfig_cmd/main_layers.cpp @@ -19,47 +19,38 @@ */ #include "main_layers.h" -#include "configurator.h" +#include "../vkconfig_core/configurator.h" #include "../vkconfig_core/configuration.h" -#include "../vkconfig_core/override.h" #include "../vkconfig_core/layer_manager.h" #include static int RunLayersOverride(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); + Configurator& configurator = Configurator::Get(); Configuration configuration; - const bool load_result = configuration.Load(layers.selected_layers, command_line.layers_configuration_path.c_str()); + const bool load_result = + configuration.Load(command_line.layers_configuration_path.c_str(), configurator.layers.selected_layers); if (!load_result) { printf("\nFailed to load the layers configuration file...\n"); return -1; } - // With command line, don't store the application list, it's always global, save and restore the setting - const bool use_application_list = environment.HasOverriddenApplications(); - environment.SetUseApplicationList(false); - - const bool override_result = OverrideConfiguration(environment, layers.selected_layers, configuration); - - environment.SetUseApplicationList(use_application_list); + const bool override_result = configurator.Override(); - environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit + configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit if (override_result) { printf("\nLayers configuration \"%s\" applied to all Vulkan Applications, including Vulkan layers:\n", command_line.layers_configuration_path.c_str()); for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { const Parameter& parameter = configuration.parameters[i]; - if (parameter.state == LAYER_STATE_APPLICATION_CONTROLLED) continue; + if (parameter.control == LAYER_CONTROL_AUTO) { + continue; + } - printf("\t%s (%s)\n", parameter.key.c_str(), parameter.state == LAYER_STATE_OVERRIDDEN ? "Overridden" : "Excluded"); + printf("\t%s (%s)\n", parameter.key.c_str(), parameter.control == LAYER_CONTROL_ON ? "Overridden" : "Excluded"); } printf("\n (Use \"vkconfig layers --surrender\" to return Vulkan layers control to Vulkan applications.)\n"); } else { @@ -70,14 +61,12 @@ static int RunLayersOverride(const CommandLine& command_line) { } static int RunLayersSurrender(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); + Configurator& configurator = Configurator::Get(); - const bool has_overridden_layers = HasOverride(); - const bool surrender_result = SurrenderConfiguration(environment); + const bool has_overridden_layers = configurator.HasOverride(); + const bool surrender_result = configurator.Surrender(); - environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit + configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit if (has_overridden_layers) { if (surrender_result) { @@ -94,12 +83,7 @@ static int RunLayersSurrender(const CommandLine& command_line) { } static int RunLayersList(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); + LayerManager layers; if (layers.selected_layers.empty()) { printf("No Vulkan layer found\n"); @@ -115,21 +99,16 @@ static int RunLayersList(const CommandLine& command_line) { } static int RunLayersVerbose(const CommandLine& command_line) { - PathManager paths(command_line.command_vulkan_sdk, SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); - - LayerManager layers(environment); - layers.LoadAllInstalledLayers(); + LayerManager layers; for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { const Layer& layer = layers.selected_layers[i]; - printf("%s (%s) %s-%s\n", layer.key.c_str(), GetLayerTypeLabel(layer.type), layer.api_version.str().c_str(), + printf("%s (%s) %s-%s\n", layer.key.c_str(), GetToken(layer.type), layer.api_version.str().c_str(), layer.implementation_version.c_str()); printf("- %s\n", layer.description.c_str()); - printf("- %s\n", layer.manifest_path.c_str()); - printf("- %s\n", layer.binary_path.c_str()); + printf("- %s\n", layer.manifest_path.AbsolutePath().c_str()); + printf("- %s\n", layer.binary_path.AbsolutePath().c_str()); } return 0; diff --git a/vkconfig3/main_layers.h b/vkconfig_cmd/main_layers.h similarity index 89% rename from vkconfig3/main_layers.h rename to vkconfig_cmd/main_layers.h index a4528437b6..81de0eac62 100644 --- a/vkconfig3/main_layers.h +++ b/vkconfig_cmd/main_layers.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vkconfig3/main_reset.cpp b/vkconfig_cmd/main_reset.cpp similarity index 95% rename from vkconfig3/main_reset.cpp rename to vkconfig_cmd/main_reset.cpp index 3480bd9585..e3f342a84d 100644 --- a/vkconfig3/main_reset.cpp +++ b/vkconfig_cmd/main_reset.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,12 @@ #include "main_reset.h" -#include "configurator.h" - -#include +#include "../vkconfig_core/configurator.h" #include +#include + static int RunReset(int argc, char* argv[], bool hard) { QCoreApplication::setOrganizationName("LunarG"); QCoreApplication::setOrganizationDomain("lunarg.com"); diff --git a/vkconfig/main_reset.h b/vkconfig_cmd/main_reset.h similarity index 89% rename from vkconfig/main_reset.h rename to vkconfig_cmd/main_reset.h index d777edf378..4f29de61b9 100644 --- a/vkconfig/main_reset.h +++ b/vkconfig_cmd/main_reset.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vkconfig_core/CMakeLists.txt b/vkconfig_core/CMakeLists.txt index 165ad94c8c..890ad70a15 100644 --- a/vkconfig_core/CMakeLists.txt +++ b/vkconfig_core/CMakeLists.txt @@ -1,4 +1,4 @@ -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5 COMPONENTS Core Gui Widgets Network QUIET) @@ -6,59 +6,31 @@ if(Qt5_FOUND) file(GLOB FILES_SOURCE ./*.cpp) file(GLOB FILES_HEADER ./*.h) - file(GLOB FILES_CONFIGURATIONS_2_2_2 ./configurations/2.2.2/*.json) - source_group("Configurations 2.2.2 Files" FILES ${FILES_CONFIGURATIONS_2_2_2}) - - file(GLOB FILES_LAYERS_130 ./layers/130/*.json) - source_group("130 Files" FILES ${FILES_LAYERS_130}) - - file(GLOB FILES_LAYERS_135 ./layers/135/*.json) - source_group("135 Files" FILES ${FILES_LAYERS_135}) - - file(GLOB FILES_LAYERS_141 ./layers/141/*.json) - source_group("141 Files" FILES ${FILES_LAYERS_141}) - - file(GLOB FILES_LAYERS_148 ./layers/148/*.json) - source_group("148 Files" FILES ${FILES_LAYERS_148}) - - file(GLOB FILES_LAYERS_154 ./layers/154/*.json) - source_group("154 Files" FILES ${FILES_LAYERS_154}) - - file(GLOB FILES_LAYERS_162 ./layers/162/*.json) - source_group("162 Files" FILES ${FILES_LAYERS_162}) - - file(GLOB FILES_LAYERS_170 ./layers/170/*.json) - source_group("170 Files" FILES ${FILES_LAYERS_170}) + file(GLOB FILES_CONFIGURATIONS ./configurations/3.0.0/*.json) + source_group("Configurations Files" FILES ${FILES_CONFIGURATIONS}) file(GLOB FILES_LAYERS_SCHEMA ./layers/layers_schema.json) source_group("Schema Files" FILES ${FILES_LAYERS_SCHEMA}) set(FILES_RESOURCES - ${FILES_CONFIGURATIONS_2_2_2} - ${FILES_LAYERS_130} - ${FILES_LAYERS_135} - ${FILES_LAYERS_141} - ${FILES_LAYERS_148} - ${FILES_LAYERS_154} - ${FILES_LAYERS_162} - ${FILES_LAYERS_170} + ${FILES_CONFIGURATIONS} ${FILES_LAYERS_SCHEMA}) set(FILES_ALL ${FILES_SOURCE} ${FILES_HEADER} ${FILES_RESOURCES}) - add_library(vkconfig_core STATIC ${FILES_ALL}) - target_compile_options(vkconfig_core PRIVATE $<$:/MP>) - target_compile_definitions(vkconfig_core PRIVATE QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT) - target_compile_definitions(vkconfig_core PRIVATE INSTALL_FULL_SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") - target_compile_definitions(vkconfig_core PRIVATE INSTALL_FULL_DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") - set_target_properties(vkconfig_core PROPERTIES FOLDER "vkconfig_core") + add_library(vkconfig-core STATIC ${FILES_ALL}) + target_compile_options(vkconfig-core PRIVATE $<$:/MP>) + target_compile_definitions(vkconfig-core PRIVATE QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT) + target_compile_definitions(vkconfig-core PRIVATE INSTALL_FULL_SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") + target_compile_definitions(vkconfig-core PRIVATE INSTALL_FULL_DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") + set_target_properties(vkconfig-core PROPERTIES FOLDER "vkconfig") if(WIN32) - target_compile_definitions(vkconfig_core PRIVATE _CRT_SECURE_NO_WARNINGS) - target_link_libraries(vkconfig_core Cfgmgr32) + target_compile_definitions(vkconfig-core PRIVATE _CRT_SECURE_NO_WARNINGS) + target_link_libraries(vkconfig-core Cfgmgr32) endif() - target_link_libraries(vkconfig_core Vulkan::Headers valijson Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) + target_link_libraries(vkconfig-core Vulkan::Headers valijson Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) if(BUILD_TESTS) add_subdirectory(test) diff --git a/vkconfig_core/alert.cpp b/vkconfig_core/alert.cpp index da9721bc62..b9c19b29ac 100644 --- a/vkconfig_core/alert.cpp +++ b/vkconfig_core/alert.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,53 +21,51 @@ #include "alert.h" #include -void Alert::LoaderFailure() { +QMessageBox::Button Alert::StartSingleton() { QMessageBox alert; - alert.QDialog::setWindowTitle("Vulkan Development Status failure..."); - alert.setText("Could not find a Vulkan Loader."); + alert.QDialog::setWindowTitle(format("Cannot start a new instance of %s", VKCONFIG_NAME).c_str()); alert.setIcon(QMessageBox::Critical); - alert.exec(); -} + alert.setDefaultButton(QMessageBox::Cancel); + alert.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + alert.setText(format("Another instance of %s is currently running. Please close it to continue.", VKCONFIG_NAME).c_str()); + alert.setInformativeText(format("Press OK to continue launching the new instance of %s when the other instance is " + "stopped.\nPress CANCEL to stop the launch of a new %s instance.", + VKCONFIG_NAME, VKCONFIG_NAME) + .c_str()); -void Alert::InstanceFailure() { - QMessageBox alert; - alert.QDialog::setWindowTitle("Vulkan Development Status failure..."); - alert.setText("Cannot find a compatible Vulkan installable client driver (ICD)."); - alert.setIcon(QMessageBox::Critical); - alert.exec(); + return static_cast(alert.exec()); } -void Alert::PhysicalDeviceFailure() { +void Alert::StartLoaderFailure() { QMessageBox alert; - alert.setWindowTitle("Vulkan Development Status failure..."); - alert.setText("Cannot find any Vulkan Physical Devices."); + alert.QDialog::setWindowTitle("Vulkan Configurator failed to start..."); + alert.setText("Could not find a Vulkan Loader."); alert.setIcon(QMessageBox::Critical); alert.exec(); } -void Alert::ApplicationListUnsupported(const char* message) { +void Alert::StartLoaderIncompatibleVersions(const Version& system_loader_version, const Version& required_loader_version) { QMessageBox alert; - alert.QDialog::setWindowTitle("Layers override of a selected list of Vulkan Applications is not available"); - alert.setTextFormat(Qt::RichText); - alert.setText(message); - alert.setInformativeText( - "In order to apply layers override to only a selected list of Vulkan applications, get the latest Vulkan Runtime from " - "
HERE. to use this feature or update your Vulkan drivers"); - alert.setIcon(QMessageBox::Warning); + alert.setWindowTitle("Vulkan Configurator failed to start..."); + alert.setText(format("The system has Vulkan Loader %s. The Vulkan Loader %s and older requires that the layers use the " + "same Vulkan Headers minor version.", + system_loader_version.str().c_str(), required_loader_version.str().c_str()) + .c_str()); + alert.setInformativeText("Please update the Vulkan Runtime at https://vulkan.lunarg.com/sdk/home"); + alert.setIcon(QMessageBox::Critical); alert.exec(); } -void Alert::ApplicationListEmpty() { +void Alert::StartPhysicalDeviceFailure() { QMessageBox alert; - alert.setIcon(QMessageBox::Warning); - alert.QDialog::setWindowTitle("Vulkan Layers overriding will apply globally."); - alert.setText("The application list to override is empty. Restricting layers overriding to the selected list is disabled."); - alert.setInformativeText("As a result, Vulkan Layers overriding will apply globally, to all Vulkan applications."); + alert.setWindowTitle("Vulkan Configurator failed to start..."); + alert.setText("Cannot find any Vulkan Physical Devices."); + alert.setIcon(QMessageBox::Critical); alert.exec(); } -void Alert::LayerInvalid(const char* path, const char* message) { - const std::string text = format("%s is not a valid layer manifest. \n\n", path) + message; +void Alert::LayerInvalid(const Path& path, const char* message) { + const std::string text = format("%s is not a valid layer manifest. \n\n", path.AbsolutePath().c_str()) + message; QMessageBox alert; alert.QDialog::setWindowTitle("Failed to load a layer manifest..."); @@ -77,8 +75,8 @@ void Alert::LayerInvalid(const char* path, const char* message) { alert.exec(); } -void Alert::PathInvalid(const char* path, const char* message) { - const std::string text = format("'%s' is not a valid path.", path); +void Alert::PathInvalid(const Path& path, const char* message) { + const std::string text = format("'%s' is not a valid path.", path.AbsolutePath().c_str()); QMessageBox alert; alert.QDialog::setWindowTitle("The select path doesn't exist..."); @@ -112,21 +110,6 @@ QMessageBox::Button Alert::LayerProfiles() { return static_cast(alert.exec()); } -QMessageBox::Button Alert::ConfiguratorSingleton() { - QMessageBox alert; - alert.QDialog::setWindowTitle(format("Cannot start a new instance of %s", VKCONFIG_NAME).c_str()); - alert.setIcon(QMessageBox::Critical); - alert.setDefaultButton(QMessageBox::Cancel); - alert.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - alert.setText(format("Another instance of %s is currently running. Please close it to continue.", VKCONFIG_NAME).c_str()); - alert.setInformativeText(format("Press OK to continue launching the new instance of %s when the other instance is " - "stopped.\nPress CANCEL to stop the launch of a new %s instance.", - VKCONFIG_NAME, VKCONFIG_NAME) - .c_str()); - - return static_cast(alert.exec()); -} - void Alert::ConfiguratorRestart() { const char* text = "Vulkan Layers are fully configured when creating a Vulkan Instance which typically happens at Vulkan Application start."; @@ -241,10 +224,10 @@ static std::string BuildPropertiesLog(const Layer& layer) { } description += "\n"; - description += layer.manifest_path + "\n"; - description += format("- %s Layers Path \n", GetLayerTypeLabel(layer.type)); + description += layer.manifest_path.AbsolutePath() + "\n"; + description += format("- %s Layers Path \n", GetToken(layer.type)); description += "- File Format: " + layer.file_format_version.str() + "\n"; - description += "- Layer Binary Path:\n " + layer.binary_path + "\n"; + description += "- Layer Binary Path:\n " + layer.binary_path.AbsolutePath() + "\n"; description += "\n"; description += format("Total Settings Count: %d - Total Presets Count: %d", CountSettings(layer.settings), layer.presets.size()); @@ -274,18 +257,6 @@ void Alert::LayerProperties(const Layer* layer) { alert.exec(); } -QMessageBox::Button Alert::LayerIncompatibleVersions(const char* message, const Version& loader_version) { - QMessageBox alert; - alert.setWindowTitle("Incompatible layers versions"); - alert.setText(format("The system has Vulkan Loader %s. The Vulkan Loader 1.3.211 and older requires that the layers use the " - "same Vulkan Headers minor version.", - loader_version.str().c_str()) - .c_str()); - alert.setInformativeText(message); - alert.setIcon(QMessageBox::Critical); - return static_cast(alert.exec()); -} - void Alert::LogFileFailed() { QMessageBox alert; alert.setText("Cannot open log file"); diff --git a/vkconfig_core/alert.h b/vkconfig_core/alert.h index bc071eeefd..38e030dfae 100644 --- a/vkconfig_core/alert.h +++ b/vkconfig_core/alert.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,24 +21,22 @@ #pragma once #include "../vkconfig_core/layer.h" +#include "../vkconfig_core/path.h" #include struct Alert { - static void LoaderFailure(); - static void InstanceFailure(); - static void PhysicalDeviceFailure(); + static QMessageBox::Button StartSingleton(); + static void StartLoaderFailure(); + static void StartLoaderIncompatibleVersions(const Version& system_loader_version, const Version& required_loader_version); + static void StartPhysicalDeviceFailure(); - static void ApplicationListUnsupported(const char* message); - static void ApplicationListEmpty(); - - static void LayerInvalid(const char* path, const char* message); + static void LayerInvalid(const Path& path, const char* message); static QMessageBox::Button LayerImplicit(const char* layer_name); static QMessageBox::Button LayerProfiles(); - static void PathInvalid(const char* path, const char* message); + static void PathInvalid(const Path& path, const char* message); - static QMessageBox::Button ConfiguratorSingleton(); static void ConfiguratorRestart(); static QMessageBox::Button ConfiguratorResetAll(); static QMessageBox::Button ConfiguratorReloadDefault(); @@ -50,7 +48,6 @@ struct Alert { static void ConfigurationNameASCII(); static void LayerProperties(const Layer* layer); - static QMessageBox::Button LayerIncompatibleVersions(const char* message, const Version& loader_version); static void LogFileFailed(); diff --git a/vkconfig_core/application.cpp b/vkconfig_core/application.cpp index 1189886a21..3122339e57 100644 --- a/vkconfig_core/application.cpp +++ b/vkconfig_core/application.cpp @@ -22,7 +22,7 @@ #include #include - +/* Application::Application(const std::string& name, const std::string& executable_full_path, const std::string& arguments) : app_name(name), executable_path(executable_full_path), @@ -33,3 +33,4 @@ Application::Application(const std::string& name, const std::string& executable_ .toStdString() .c_str()), layers_mode(LAYERS_MODE_BY_CONFIGURATOR_RUNNING) {} +*/ diff --git a/vkconfig_core/application.h b/vkconfig_core/application.h index ce44266d8f..3486813625 100644 --- a/vkconfig_core/application.h +++ b/vkconfig_core/application.h @@ -20,22 +20,28 @@ #pragma once +#include "type_layers_mode.h" #include "path.h" +#include "configuration_info.h" #include +#include -enum LayersMode { LAYERS_MODE_BY_APPLICATIONS = 0, LAYERS_MODE_BY_CONFIGURATOR_RUNNING, LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED }; +struct ApplicationOptions { + std::string label; + Path working_folder; + std::vector arguments; + std::vector environment_variables; + Path log_file; +}; struct Application { - Application() {} - Application(const std::string& name, const std::string& executable_full_path, const std::string& arguments); - - std::string app_name; Path executable_path; - Path working_folder; - std::string arguments; - std::string env; - Path log_file; - LayersMode layers_mode; - std::string layers_configuration; + ConfigurationInfo configuration; + int active_option_index = 0; + std::vector options; + + ApplicationOptions& GetActiveOptions() { return this->options[active_option_index]; } + + const ApplicationOptions& GetActiveOptions() const { return this->options[active_option_index]; } }; diff --git a/vkconfig_core/bitfield.cpp b/vkconfig_core/bitfield.cpp new file mode 100644 index 0000000000..acd008ba19 --- /dev/null +++ b/vkconfig_core/bitfield.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "bitfield.h" + +std::size_t PopCount(int bitfield) { + std::size_t count = 0; + + for (std::size_t i = 0, n = sizeof(bitfield) * 8; i < n; ++i) { + if (bitfield & (1 << i)) { + ++count; + } + } + + return count; +} + +int FindPosition(int bit) { + assert(PopCount(bit) == 1); + + for (int i = 0, n = sizeof(bit) * 8; i < n; ++i) { + if (bit & (1 << i)) { + return i; + } + } + + return -1; +} diff --git a/vkconfig_core/bitfield.h b/vkconfig_core/bitfield.h new file mode 100644 index 0000000000..5be6315937 --- /dev/null +++ b/vkconfig_core/bitfield.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include +#include + +std::size_t PopCount(int bitfield); + +int FindPosition(int bit); + +template +inline int GetBit(T value, T first) { + return 1 << (value - first); +} + +template +inline VALUE GetValue(BIT bit, VALUE first) { + return static_cast(FindPosition(bit) + first); +} diff --git a/vkconfig_core/command_line.cpp b/vkconfig_core/command_line.cpp index 9dac1745c5..8efa3ccb43 100644 --- a/vkconfig_core/command_line.cpp +++ b/vkconfig_core/command_line.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2022 Valve Corporation - * Copyright (c) 2020-2022 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -44,7 +45,7 @@ static const CommandHelpDesc command_help_desc[] = { static HelpType GetCommandHelpId(const char* token) { assert(token != nullptr); - for (std::size_t i = 0, n = countof(command_help_desc); i < n; ++i) { + for (std::size_t i = 0, n = std::size(command_help_desc); i < n; ++i) { if (std::strcmp(command_help_desc[i].token, token) == 0) return command_help_desc[i].arguments; } @@ -58,24 +59,22 @@ struct ModeDesc { }; static const ModeDesc mode_desc[] = { - {COMMAND_NONE, "", HELP_DEFAULT}, // COMMAND_NONE - {COMMAND_SHOW_USAGE, "-h", HELP_HELP}, // COMMAND_SHOW_USAGE - {COMMAND_SHOW_USAGE, "--help", HELP_HELP}, // COMMAND_SHOW_USAGE - {COMMAND_SHOW_USAGE, "help", HELP_HELP}, // COMMAND_SHOW_USAGE - {COMMAND_VERSION, "-v", HELP_VERSION}, // COMMAND_VERSION - {COMMAND_VERSION, "--version", HELP_VERSION}, // COMMAND_VERSION - {COMMAND_VERSION, "version", HELP_VERSION}, // COMMAND_VERSION - {COMMAND_GUI, "gui", HELP_GUI}, // COMMAND_GUI - {COMMAND_LAYERS, "layers", HELP_LAYERS}, // COMMAND_LAYERS - {COMMAND_DOC, "doc", HELP_DOC}, // COMMAND_DOC - {COMMAND_RESET, "reset", HELP_RESET}, // COMMAND_RESET - {COMMAND_VULKAN_SDK, "VULKAN_SDK", HELP_RESET} // COMMAND_VULKAN_SDK + {COMMAND_NONE, "", HELP_DEFAULT}, // COMMAND_NONE + {COMMAND_SHOW_USAGE, "-h", HELP_HELP}, // COMMAND_SHOW_USAGE + {COMMAND_SHOW_USAGE, "--help", HELP_HELP}, // COMMAND_SHOW_USAGE + {COMMAND_SHOW_USAGE, "help", HELP_HELP}, // COMMAND_SHOW_USAGE + {COMMAND_VERSION, "-v", HELP_VERSION}, // COMMAND_VERSION + {COMMAND_VERSION, "--version", HELP_VERSION}, // COMMAND_VERSION + {COMMAND_VERSION, "version", HELP_VERSION}, // COMMAND_VERSION + {COMMAND_LAYERS, "layers", HELP_LAYERS}, // COMMAND_LAYERS + {COMMAND_DOC, "doc", HELP_DOC}, // COMMAND_DOC + {COMMAND_RESET, "reset", HELP_RESET} // COMMAND_RESET }; static CommandType GetModeId(const char* token) { assert(token != nullptr); - for (std::size_t i = 0, n = countof(mode_desc); i < n; ++i) { + for (std::size_t i = 0, n = std::size(mode_desc); i < n; ++i) { if (std::strcmp(mode_desc[i].token, token) == 0) return mode_desc[i].mode; } @@ -83,7 +82,7 @@ static CommandType GetModeId(const char* token) { } static const ModeDesc& GetModeDesc(CommandType command_type) { - for (std::size_t i = 0, n = countof(mode_desc); i < n; ++i) { + for (std::size_t i = 0, n = std::size(mode_desc); i < n; ++i) { if (mode_desc[i].mode == command_type) return mode_desc[i]; } @@ -105,7 +104,7 @@ static const CommandResetDesc command_reset_desc[] = {{COMMAND_RESET_SOFT, "--so static CommandResetArg GetCommandResetId(const char* token) { assert(token != nullptr); - for (std::size_t i = 0, n = countof(command_reset_desc); i < n; ++i) { + for (std::size_t i = 0, n = std::size(command_reset_desc); i < n; ++i) { if (std::strcmp(command_reset_desc[i].token, token) == 0) return command_reset_desc[i].arguments; } @@ -144,7 +143,7 @@ static const CommandDocDesc command_doc_desc[] = { static CommandLayersArg GetCommandLayersId(const char* token) { assert(token != nullptr); - for (std::size_t i = 0, n = countof(command_layers_desc); i < n; ++i) { + for (std::size_t i = 0, n = std::size(command_layers_desc); i < n; ++i) { if (std::strcmp(command_layers_desc[i].token, token) == 0) return command_layers_desc[i].arguments; } @@ -154,7 +153,7 @@ static CommandLayersArg GetCommandLayersId(const char* token) { static const CommandLayersDesc& GetCommandLayers(CommandLayersArg layers_arg) { assert(layers_arg != COMMAND_LAYERS_NONE); - for (std::size_t i = 0, n = countof(command_layers_desc); i < n; ++i) { + for (std::size_t i = 0, n = std::size(command_layers_desc); i < n; ++i) { if (command_layers_desc[i].arguments == layers_arg) return command_layers_desc[i]; } @@ -165,7 +164,7 @@ static const CommandLayersDesc& GetCommandLayers(CommandLayersArg layers_arg) { static CommandDocArg GetCommandDocId(const char* token) { assert(token != nullptr); - for (std::size_t i = 0, n = countof(command_doc_desc); i < n; ++i) { + for (std::size_t i = 0, n = std::size(command_doc_desc); i < n; ++i) { if (std::strcmp(command_doc_desc[i].token, token) == 0) return command_doc_desc[i].arguments; } @@ -178,12 +177,10 @@ CommandLine::CommandLine(int argc, char* argv[]) command_layers_arg(_command_layers_arg), layers_configuration_path(_layers_configuration_path), command_doc_arg(_command_doc_arg), - command_vulkan_sdk(_command_vulkan_sdk), doc_layer_name(_doc_layer_name), doc_out_dir(_doc_out_dir), error(_error), error_args(_error_args), - _command(COMMAND_GUI), _command_reset_arg(COMMAND_RESET_NONE), _command_layers_arg(COMMAND_LAYERS_NONE), _command_doc_arg(COMMAND_DOC_NONE), @@ -195,9 +192,6 @@ CommandLine::CommandLine(int argc, char* argv[]) int arg_offset = 1; switch (_command = GetModeId(argv[arg_offset + 0])) { - case COMMAND_VULKAN_SDK: { - _command_vulkan_sdk = argv[arg_offset + 1]; - } break; case COMMAND_LAYERS: { if (argc <= arg_offset + 1) { _error = ERROR_MISSING_COMMAND_ARGUMENT; @@ -297,7 +291,6 @@ CommandLine::CommandLine(int argc, char* argv[]) _error_args.push_back(argv[arg_offset + 0]); break; } - case COMMAND_GUI: case COMMAND_VERSION: { break; } diff --git a/vkconfig_core/command_line.h b/vkconfig_core/command_line.h index 8597e2befd..e2e766eb93 100644 --- a/vkconfig_core/command_line.h +++ b/vkconfig_core/command_line.h @@ -24,16 +24,7 @@ #include #include -enum CommandType { - COMMAND_NONE = 0, - COMMAND_SHOW_USAGE, - COMMAND_VERSION, - COMMAND_GUI, - COMMAND_RESET, - COMMAND_LAYERS, - COMMAND_DOC, - COMMAND_VULKAN_SDK -}; +enum CommandType { COMMAND_NONE = 0, COMMAND_SHOW_USAGE, COMMAND_VERSION, COMMAND_RESET, COMMAND_LAYERS, COMMAND_DOC }; enum CommandLayersArg { COMMAND_LAYERS_NONE = 0, @@ -71,7 +62,6 @@ class CommandLine { const CommandLayersArg& command_layers_arg; const std::string& layers_configuration_path; const CommandDocArg& command_doc_arg; - const std::string& command_vulkan_sdk; const std::string& doc_layer_name; const std::string& doc_out_dir; @@ -87,7 +77,6 @@ class CommandLine { CommandLayersArg _command_layers_arg; std::string _layers_configuration_path; CommandDocArg _command_doc_arg; - std::string _command_vulkan_sdk; std::string _doc_layer_name; std::string _doc_out_dir; diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index 949c4a308d..94d5c0542d 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -23,7 +23,7 @@ #include "util.h" #include "path.h" #include "json.h" -#include "platform.h" +#include "type_platform.h" #include "version.h" #include @@ -39,11 +39,49 @@ #include #include -Configuration::Configuration() : key("New Configuration"), platform_flags(PLATFORM_DESKTOP_BIT), view_advanced_settings(false) {} +Configuration::Configuration() + : key("New Configuration"), version(1), platform_flags(PLATFORM_DESKTOP_BIT), view_advanced_settings(false) {} -bool Configuration::Load2_2(const std::vector& available_layers, const QJsonObject& json_root_object) { +Configuration Configuration::CreateDisabled(const std::vector& available_layers) { + Configuration result; + result.key = "_DisablingConfiguration"; + result.parameters = GatherParameters(result.parameters, available_layers); + + for (std::size_t i = 0, n = result.parameters.size(); i < n; ++i) { + result.parameters[i].control = LAYER_CONTROL_OFF; + } + + return result; +} + +bool Configuration::Load(const Path& full_path, const std::vector& available_layers) { + assert(!full_path.Empty()); + + this->parameters.clear(); + + QFile file(full_path.AbsolutePath().c_str()); + const bool result = file.open(QIODevice::ReadOnly | QIODevice::Text); + assert(result); + std::string json_text = file.readAll().toStdString(); + file.close(); + + QJsonParseError parse_error; + QJsonDocument json_doc = QJsonDocument::fromJson(json_text.c_str(), &parse_error); + + if (parse_error.error != QJsonParseError::NoError) { + return false; + } + + Version version(json_doc.object().value("file_format_version").toString().toStdString()); + if (version < (Version(3, 0, 0))) { + return false; // Unsupported version + } + + const QJsonObject& json_root_object = json_doc.object(); const QJsonValue& json_configuration_value = json_root_object.value("configuration"); - if (json_configuration_value == QJsonValue::Undefined) return false; // Not a configuration file + if (json_configuration_value == QJsonValue::Undefined) { + return false; // Not a configuration file + } const QJsonObject& json_configuration_object = json_configuration_value.toObject(); @@ -52,6 +90,10 @@ bool Configuration::Load2_2(const std::vector& available_layers, const QJ this->description = ReadString(json_configuration_object, "description").c_str(); // Optional configuration values + if (json_configuration_object.value("version") != QJsonValue::Undefined) { + this->version = json_configuration_object.value("version").toVariant().toInt(); + } + if (json_configuration_object.value("expanded_states") != QJsonValue::Undefined) { this->setting_tree_state = json_configuration_object.value("expanded_states").toVariant().toByteArray(); } @@ -70,7 +112,7 @@ bool Configuration::Load2_2(const std::vector& available_layers, const QJ for (std::size_t i = 0, n = paths.size(); i < n; ++i) { const QFileInfo info(paths[i].c_str()); if (info.exists()) { - this->user_defined_paths.push_back(paths[i]); + this->user_defined_paths.push_back(Path(paths[i])); } else { QMessageBox alert; alert.QDialog::setWindowTitle("User-defined layer path doesn't exist"); @@ -94,16 +136,34 @@ bool Configuration::Load2_2(const std::vector& available_layers, const QJ Parameter parameter; parameter.key = ReadStringValue(json_layer_object, "name").c_str(); parameter.overridden_rank = ReadIntValue(json_layer_object, "rank"); - parameter.state = GetLayerState(ReadStringValue(json_layer_object, "state").c_str()); + parameter.control = GetLayerControl(ReadStringValue(json_layer_object, "control").c_str()); + const std::string& version = ReadStringValue(json_layer_object, "version"); + parameter.api_version = version == "latest" ? Version::VERSION_NULL : Version(version.c_str()); const QJsonValue& json_platform_value = json_layer_object.value("platforms"); if (json_platform_value != QJsonValue::Undefined) { parameter.platform_flags = GetPlatformFlags(ReadStringArray(json_layer_object, "platforms")); } - const Layer* layer = FindByKey(available_layers, parameter.key.c_str()); + const Layer* layer = nullptr; + for (std::size_t i = 0, n = available_layers.size(); i < n; ++i) { + const Layer& current_layer = available_layers[i]; + if (current_layer.key != parameter.key) { + continue; + } + + if (parameter.api_version == Version::VERSION_NULL) { + if (layer == nullptr) { + layer = ¤t_layer; + } else if (layer->api_version < current_layer.api_version) { + layer = ¤t_layer; + } + } else if (parameter.api_version == current_layer.api_version) { + layer = ¤t_layer; + } + } + if (layer != nullptr) { - parameter.api_version = layer->api_version; CollectDefaultSettingData(layer->settings, parameter.settings); } @@ -115,10 +175,14 @@ bool Configuration::Load2_2(const std::vector& available_layers, const QJ const SettingType setting_type = GetSettingType(ReadStringValue(json_setting_object, "type").c_str()); SettingData* setting_data = FindSetting(parameter.settings, setting_key.c_str()); - if (setting_data == nullptr) continue; + if (setting_data == nullptr) { + continue; + } // Configuration type and layer type are differents, use layer default value - if (setting_data->type != setting_type) continue; + if (setting_data->type != setting_type) { + continue; + } const bool result = setting_data->Load(json_setting_object); assert(result); @@ -130,37 +194,16 @@ bool Configuration::Load2_2(const std::vector& available_layers, const QJ return true; } -bool Configuration::Load(const std::vector& available_layers, const std::string& full_path) { - assert(!full_path.empty()); - - this->parameters.clear(); - - QFile file(full_path.c_str()); - const bool result = file.open(QIODevice::ReadOnly | QIODevice::Text); - assert(result); - QString json_text = file.readAll(); - file.close(); - - QJsonParseError parse_error; - QJsonDocument json_doc = QJsonDocument::fromJson(json_text.toUtf8(), &parse_error); - - if (parse_error.error != QJsonParseError::NoError) { - return false; - } - - return Load2_2(available_layers, json_doc.object()); -} - -bool Configuration::Save(const std::vector& available_layers, const std::string& full_path, bool exporter) const { - assert(!full_path.empty()); +bool Configuration::Save(const Path& full_path, bool exporter) const { + assert(!full_path.Empty()); QJsonObject root; - root.insert("file_format_version", Version::LAYER_CONFIG.str().c_str()); + root.insert("file_format_version", Version::VKCONFIG.str().c_str()); // Build the json document QJsonArray excluded_list; for (std::size_t i = 0, n = this->parameters.size(); i < n; ++i) { - if (this->parameters[i].state != LAYER_STATE_EXCLUDED) { + if (this->parameters[i].control != LAYER_CONTROL_OFF) { continue; } excluded_list.append(this->parameters[i].key.c_str()); @@ -170,14 +213,16 @@ bool Configuration::Save(const std::vector& available_layers, const std:: for (std::size_t i = 0, n = this->parameters.size(); i < n; ++i) { const Parameter& parameter = this->parameters[i]; - if (parameter.state == LAYER_STATE_APPLICATION_CONTROLLED) { + if (parameter.control == LAYER_CONTROL_AUTO) { continue; } QJsonObject json_layer; json_layer.insert("name", parameter.key.c_str()); json_layer.insert("rank", parameter.overridden_rank); - json_layer.insert("state", GetToken(parameter.state)); + json_layer.insert("control", GetToken(parameter.control)); + json_layer.insert("version", + parameter.api_version == Version::VERSION_NULL ? "latest" : parameter.api_version.str().c_str()); SaveStringArray(json_layer, "platforms", GetPlatformTokens(parameter.platform_flags)); QJsonArray json_settings; @@ -204,6 +249,7 @@ bool Configuration::Save(const std::vector& available_layers, const std:: QJsonObject json_configuration; json_configuration.insert("name", this->key.c_str()); + json_configuration.insert("version", this->version); json_configuration.insert("description", this->description.c_str()); SaveStringArray(json_configuration, "platforms", GetPlatformTokens(this->platform_flags)); if (!exporter && !this->setting_tree_state.isEmpty()) { @@ -214,7 +260,7 @@ bool Configuration::Save(const std::vector& available_layers, const std:: QJsonArray json_paths; for (std::size_t i = 0, n = this->user_defined_paths.size(); i < n; ++i) { - json_paths.append(this->user_defined_paths[i].c_str()); + json_paths.append(this->user_defined_paths[i].AbsolutePath().c_str()); } json_configuration.insert("layers_paths", json_paths); @@ -222,7 +268,7 @@ bool Configuration::Save(const std::vector& available_layers, const std:: QJsonDocument doc(root); - QFile json_file(full_path.c_str()); + QFile json_file(full_path.AbsolutePath().c_str()); const bool result = json_file.open(QIODevice::WriteOnly | QIODevice::Text); assert(result); @@ -240,16 +286,24 @@ bool Configuration::Save(const std::vector& available_layers, const std:: } } -void Configuration::Reset(const std::vector& available_layers, const PathManager& path_manager) { - (void)path_manager; +Parameter* Configuration::Find(std::string parameter_key) { + for (std::size_t i = 0, n = this->parameters.size(); i < n; ++i) { + if (this->parameters[i].key == parameter_key) { + return &this->parameters[i]; + } + } + + return nullptr; +} +void Configuration::Reset(const std::vector& available_layers) { // Case 1: reset using built-in configuration files - const QFileInfoList& builtin_configuration_files = GetJSONFiles(":/configurations/"); + const std::vector& builtin_configuration_files = CollectFilePaths(":/configurations/"); for (int i = 0, n = builtin_configuration_files.size(); i < n; ++i) { - const std::string& basename = builtin_configuration_files[i].baseName().toStdString(); + const std::string& basename = builtin_configuration_files[i].Basename(); if (this->key == basename) { - const bool result = this->Load(available_layers, builtin_configuration_files[i].absoluteFilePath().toStdString()); + const bool result = this->Load(builtin_configuration_files[i], available_layers); assert(result); OrderParameter(this->parameters, available_layers); @@ -258,28 +312,22 @@ void Configuration::Reset(const std::vector& available_layers, const Path } // Case 2: reset using configuration files using saved configurations - const std::string base_config_path = GetPath(BUILTIN_PATH_CONFIG_REF); + const Path full_path(Get(Path::CONFIGS) + "/" + this->key + ".json"); - const std::vector& SUPPORTED_CONFIG_FILES = path_manager.SUPPORTED_CONFIG_FILES; + std::FILE* file = std::fopen(full_path.AbsolutePath().c_str(), "r"); + if (file) { + std::fclose(file); + const bool result = this->Load(full_path, available_layers); + assert(result); - for (std::size_t i = 0, n = SUPPORTED_CONFIG_FILES.size(); i < n; ++i) { - const std::string path = base_config_path + SUPPORTED_CONFIG_FILES[i] + "/" + this->key + ".json"; - - std::FILE* file = std::fopen(path.c_str(), "r"); - if (file) { - std::fclose(file); - const bool result = this->Load(available_layers, path); - assert(result); - - OrderParameter(this->parameters, available_layers); - return; - } + OrderParameter(this->parameters, available_layers); + return; } // Case 3: reset to default values { for (auto it = this->parameters.begin(); it != this->parameters.end(); ++it) { - it->state = LAYER_STATE_APPLICATION_CONTROLLED; + it->control = LAYER_CONTROL_AUTO; it->overridden_rank = Parameter::NO_RANK; for (std::size_t i = 0, n = it->settings.size(); i < n; ++i) { it->settings[i]->Reset(); @@ -296,7 +344,7 @@ bool Configuration::HasOverride() const { continue; } - if (this->parameters[i].state != LAYER_STATE_APPLICATION_CONTROLLED) { + if (this->parameters[i].control != LAYER_CONTROL_AUTO) { return true; } } @@ -305,9 +353,9 @@ bool Configuration::HasOverride() const { } bool Configuration::IsBuiltIn() const { - const QFileInfoList& builtin_configuration_files = GetJSONFiles(":/configurations/"); + const std::vector& builtin_configuration_files = CollectFilePaths(":/configurations/"); for (int i = 0, n = builtin_configuration_files.size(); i < n; ++i) { - const std::string& basename = builtin_configuration_files[i].baseName().toStdString(); + const std::string& basename = builtin_configuration_files[i].Basename(); if (basename == this->key) { return true; diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index 02260ce0be..fe89c3c0e3 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -22,7 +22,6 @@ #pragma once #include "parameter.h" -#include "path_manager.h" #include @@ -33,27 +32,28 @@ class Configuration { public: Configuration(); - bool Load(const std::vector& available_layers, const std::string& full_path); - bool Save(const std::vector& available_layers, const std::string& full_path, bool exporter = false) const; + static Configuration CreateDisabled(const std::vector& available_layers); + + bool Load(const Path& full_path, const std::vector& available_layers); + bool Save(const Path& full_path, bool exporter = false) const; bool HasOverride() const; + Parameter* Find(std::string parameter_key); - void Reset(const std::vector& available_layers, const PathManager& path_manager); + void Reset(const std::vector& available_layers); std::size_t Size() const { return this->parameters.size(); }; std::string key; // User readable display of the configuration name (may contain spaces) + int version; int platform_flags; std::string description; // A friendly description of what this profile does QByteArray setting_tree_state; // Recall editor tree state bool view_advanced_settings; std::vector parameters; - std::vector user_defined_paths; + std::vector user_defined_paths; bool IsBuiltIn() const; - - private: - bool Load2_2(const std::vector& available_layers, const QJsonObject& json_root_object); }; std::string MakeConfigurationName(const std::vector& configurations, const std::string& configuration_name); diff --git a/vkconfig3/main_signal.h b/vkconfig_core/configuration_info.cpp similarity index 84% rename from vkconfig3/main_signal.h rename to vkconfig_core/configuration_info.cpp index d9ff6e1a7d..7c42cde38d 100644 --- a/vkconfig3/main_signal.h +++ b/vkconfig_core/configuration_info.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,4 @@ * - Christophe Riccio */ -#pragma once - -void InitSignals(); +#include "configuration_info.h" diff --git a/vkconfig_core/configuration_info.h b/vkconfig_core/configuration_info.h new file mode 100644 index 0000000000..21f05cf7de --- /dev/null +++ b/vkconfig_core/configuration_info.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "type_update.h" +#include "type_layers_mode.h" + +#include + +class ConfigurationInfo { + private: + std::string name = "Validation"; + LayersMode mode = LAYERS_CONTROLLED_BY_APPLICATIONS; + UpdateBits area = UPDATE_NONE; + + public: + const char* GetName() const { return this->name.c_str(); } + + void SetName(const std::string& new_configuration_name) { + if (this->name != new_configuration_name) { + this->name = new_configuration_name; + this->area = UPDATE_ALL; + } + } + + LayersMode GetMode() const { return this->mode; } + + void SetMode(LayersMode new_configuration_mode) { + if (this->mode != new_configuration_mode) { + this->mode = new_configuration_mode; + this->area = UPDATE_ALL; + } + } + + void ForceUpdate(UpdateBits area_bits) { + if (area_bits == UPDATE_NONE) { + this->area = area_bits; + } else { + this->area = static_cast(this->area | area_bits); + } + } +}; diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index 3391c42ff8..a9e22509e3 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -19,48 +19,31 @@ */ #include "util.h" -#include "path_manager.h" #include "configuration_manager.h" -#include "override.h" +#include "configurator.h" #include "alert.h" -#include -#include - -ConfigurationManager::ConfigurationManager(Environment &environment) : environment(environment) {} +ConfigurationManager::ConfigurationManager() {} ConfigurationManager::~ConfigurationManager() {} void ConfigurationManager::LoadAllConfigurations(const std::vector &available_layers) { this->available_configurations.clear(); - // If this is the first time, we need to create the initial set of - // configuration files. - if (this->environment.first_run) { - this->RemoveConfigurationFiles(); - this->LoadDefaultConfigurations(available_layers); - - this->environment.first_run = false; - } - - const std::string base_config_path = GetPath(BUILTIN_PATH_CONFIG_REF); - - const std::vector &SUPPORTED_CONFIG_FILES = this->environment.paths.SUPPORTED_CONFIG_FILES; + this->LoadConfigurationsPath(available_layers); - for (std::size_t i = 0, n = SUPPORTED_CONFIG_FILES.size(); i < n; ++i) { - const std::string path = base_config_path + SUPPORTED_CONFIG_FILES[i]; - this->LoadConfigurationsPath(available_layers, path.c_str()); - } + // If built-in configurations were updated, replace the stored configuration + this->LoadDefaultConfigurations(available_layers); this->SortConfigurations(); } void ConfigurationManager::LoadDefaultConfigurations(const std::vector &available_layers) { - const QFileInfoList &configuration_files = GetJSONFiles(":/configurations/"); + const std::vector &configuration_files = CollectFilePaths(":/configurations/"); for (int i = 0, n = configuration_files.size(); i < n; ++i) { Configuration configuration; - const bool result = configuration.Load(available_layers, configuration_files[i].absoluteFilePath().toStdString()); + const bool result = configuration.Load(configuration_files[i], available_layers); assert(result); if (!IsPlatformSupported(configuration.platform_flags)) { @@ -77,13 +60,21 @@ void ConfigurationManager::LoadDefaultConfigurations(const std::vector &a OrderParameter(configuration.parameters, available_layers); - Configuration *found_configuration = FindByKey(this->available_configurations, configuration.key.c_str()); + Configuration *found_configuration = this->FindConfiguration(configuration.key); if (found_configuration == nullptr) { + auto iter = this->removed_built_in_configuration.find(configuration.key); + // If the removed built-in configuration is a version older than the current built-in configuration, we are it back. + if (iter == this->removed_built_in_configuration.end()) { + this->available_configurations.push_back(configuration); + } else if (iter->second < configuration.version) { + this->available_configurations.push_back(configuration); + } + } else if (found_configuration->version < configuration.version) { + // Replaced the old configuration by the new one + this->RemoveConfiguration(available_layers, found_configuration->key); this->available_configurations.push_back(configuration); } } - - this->SortConfigurations(); } void ConfigurationManager::SortConfigurations() { @@ -97,19 +88,11 @@ void ConfigurationManager::SortConfigurations() { std::sort(this->available_configurations.begin(), this->available_configurations.end(), Compare()); } -void ConfigurationManager::LoadConfigurationsPath(const std::vector &available_layers, const char *path) { - const QFileInfoList &configuration_files = GetJSONFiles(path); +void ConfigurationManager::LoadConfigurationsPath(const std::vector &available_layers) { + const std::vector &configuration_files = CollectFilePaths(Get(Path::CONFIGS)); for (int i = 0, n = configuration_files.size(); i < n; ++i) { - const QFileInfo &info = configuration_files[i]; - Configuration configuration; - std::string path = info.absoluteFilePath().toStdString(); - - // Skip "2_2_1/Portability.json" because we replaced the devsim layer by the profiles layer - if (path.find("2_2_1/Portability.json") != std::string::npos) { - path = ":/configurations/Portability.json"; - } - const bool result = configuration.Load(available_layers, path); + const bool result = configuration.Load(configuration_files[i], available_layers); if (!result) { continue; } @@ -127,10 +110,15 @@ void ConfigurationManager::LoadConfigurationsPath(const std::vector &avai } } -void ConfigurationManager::SaveAllConfigurations(const std::vector &available_layers) { +static Path MakeConfigurationPath(const std::string &key) { + const Path &path = Get(Path::CONFIGS) + "/" + key + ".json"; + return path.AbsolutePath(); +} + +void ConfigurationManager::SaveAllConfigurations() { for (std::size_t i = 0, n = available_configurations.size(); i < n; ++i) { - const std::string path = GetPath(BUILTIN_PATH_CONFIG_LAST) + "/" + available_configurations[i].key + ".json"; - available_configurations[i].Save(available_layers, path.c_str()); + const Path &path(MakeConfigurationPath(available_configurations[i].key)); + available_configurations[i].Save(path); } } @@ -141,12 +129,12 @@ Configuration &ConfigurationManager::CreateConfiguration(const std::vectoravailable_configurations.push_back(configuration); @@ -156,51 +144,31 @@ Configuration &ConfigurationManager::CreateConfiguration(const std::vector &SUPPORTED_CONFIG_FILES = environment.paths.SUPPORTED_CONFIG_FILES; + const std::string base_path = AbsolutePath(Path::CONFIGS); - for (std::size_t i = 0, n = SUPPORTED_CONFIG_FILES.size(); i < n; ++i) { - const std::string path = base_path + SUPPORTED_CONFIG_FILES[i] + "/" + configuration.key + ".json"; + const std::string path = base_path + "/" + configuration.key + ".json"; - std::FILE *file = std::fopen(path.c_str(), "r"); - if (file) { - std::fclose(file); - return true; - } + std::FILE *file = std::fopen(path.c_str(), "r"); + if (file) { + std::fclose(file); + return true; } + return false; } void ConfigurationManager::RemoveConfigurationFiles() { - const std::string base_path = GetPath(BUILTIN_PATH_CONFIG_REF); - - const std::vector &SUPPORTED_CONFIG_FILES = environment.paths.SUPPORTED_CONFIG_FILES; - - for (std::size_t i = 0, n = SUPPORTED_CONFIG_FILES.size(); i < n; ++i) { - const std::string path = base_path + SUPPORTED_CONFIG_FILES[i]; - - const QFileInfoList &configuration_files = GetJSONFiles(path.c_str()); - for (int i = 0, n = configuration_files.size(); i < n; ++i) { - QFile::remove(configuration_files[i].filePath()); - } + const std::vector &configuration_files = CollectFilePaths(Get(Path::CONFIGS)); + for (int i = 0, n = configuration_files.size(); i < n; ++i) { + configuration_files[i].Remove(); } } void ConfigurationManager::RemoveConfigurationFile(const std::string &key) { - const std::string base_path = GetPath(BUILTIN_PATH_CONFIG_REF); - - const std::vector &SUPPORTED_CONFIG_FILES = environment.paths.SUPPORTED_CONFIG_FILES; - - for (std::size_t i = 0, n = SUPPORTED_CONFIG_FILES.size(); i < n; ++i) { - const std::string path = base_path + SUPPORTED_CONFIG_FILES[i]; - - const QFileInfoList &configuration_files = GetJSONFiles(path.c_str()); - for (int j = 0, o = configuration_files.size(); j < o; ++j) { - const QString filename = configuration_files[j].fileName(); - if (filename.toStdString() == key + ".json") { - QFile::remove(configuration_files[j].filePath()); - } + const std::vector &configuration_files = CollectFilePaths(Get(Path::CONFIGS)); + for (int j = 0, o = configuration_files.size(); j < o; ++j) { + if (configuration_files[j].Basename() == key) { + configuration_files[j].Remove(); } } } @@ -208,10 +176,6 @@ void ConfigurationManager::RemoveConfigurationFile(const std::string &key) { void ConfigurationManager::RemoveConfiguration(const std::vector &available_layers, const std::string &configuration_name) { assert(!configuration_name.empty()); - LayersMode saved_mode = this->environment.GetMode(); - this->environment.SetMode(LAYERS_MODE_BY_APPLICATIONS); - this->Configure(available_layers); - RemoveConfigurationFile(configuration_name.c_str()); // Update the configuration in the list @@ -219,6 +183,12 @@ void ConfigurationManager::RemoveConfiguration(const std::vector &availab for (std::size_t i = 0, n = this->available_configurations.size(); i < n; ++i) { if (this->available_configurations[i].key == configuration_name) { + int version = this->available_configurations[i].version; + + auto result = this->removed_built_in_configuration.insert(std::make_pair(configuration_name, version)); + if (!result.second) { + this->removed_built_in_configuration[configuration_name] = version; + } continue; } updated_configurations.push_back(this->available_configurations[i]); @@ -226,104 +196,42 @@ void ConfigurationManager::RemoveConfiguration(const std::vector &availab std::swap(updated_configurations, this->available_configurations); this->SortConfigurations(); - - this->environment.SetSelectedConfiguration(""); - this->environment.SetMode(saved_mode); - this->Configure(available_layers); } -void ConfigurationManager::Configure(const std::vector &available_layers) { - const std::string active_configuration_name = this->environment.GetSelectedConfiguration(); - - if (active_configuration_name.empty()) { - this->environment.SetSelectedConfiguration(""); - this->Configure(available_layers, ""); - } else { - Configuration *selected_configuration = FindByKey(this->available_configurations, active_configuration_name.c_str()); - if (selected_configuration == nullptr) { - environment.SetSelectedConfiguration(""); - } - this->Configure(available_layers, this->environment.GetSelectedConfiguration()); +Configuration *ConfigurationManager::FindConfiguration(const std::string &configuration_name) { + if (configuration_name.empty()) { + return nullptr; } -} - -void ConfigurationManager::Configure(const std::vector &available_layers, const std::string &configuration_name) { - switch (this->environment.GetMode()) { - default: - case LAYERS_MODE_BY_APPLICATIONS: { - SurrenderConfiguration(this->environment); - } break; - case LAYERS_MODE_BY_CONFIGURATOR_RUNNING: { - if (configuration_name.empty()) { - ::SurrenderConfiguration(this->environment); - } else { - Configuration *selected_configuration = FindByKey(this->available_configurations, configuration_name.c_str()); - std::string missing_layer; - if (::HasMissingLayer(selected_configuration->parameters, available_layers, missing_layer)) { - ::SurrenderConfiguration(this->environment); - } else { - ::OverrideConfiguration(this->environment, available_layers, *selected_configuration); - } - } - } break; - case LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED: { - Configuration temp_configuration; - temp_configuration.key = "_TempConfiguration"; - temp_configuration.parameters = GatherParameters(temp_configuration.parameters, available_layers); - - for (std::size_t i = 0, n = temp_configuration.parameters.size(); i < n; ++i) { - temp_configuration.parameters[i].state = LAYER_STATE_EXCLUDED; - } - ::OverrideConfiguration(environment, available_layers, temp_configuration); - } break; + if (this->available_configurations.empty()) { + return nullptr; } + + return FindByKey(this->available_configurations, configuration_name.c_str()); } -Configuration *ConfigurationManager::FindActiveConfiguration() { - if (this->environment.GetSelectedConfiguration().empty()) { +const Configuration *ConfigurationManager::FindConfiguration(const std::string &configuration_name) const { + if (configuration_name.empty()) { return nullptr; } - return FindByKey(this->available_configurations, this->environment.GetSelectedConfiguration().c_str()); -} - -bool ConfigurationManager::HasActiveConfiguration(const std::vector &available_layers) const { - switch (environment.GetMode()) { - case LAYERS_MODE_BY_APPLICATIONS: - return false; - case LAYERS_MODE_BY_CONFIGURATOR_RUNNING: { - const std::string configuration_name = this->environment.GetSelectedConfiguration(); - if (configuration_name.empty()) { - return false; - } else { - const Configuration *selected_configuration = FindByKey(this->available_configurations, configuration_name.c_str()); - if (selected_configuration != nullptr) { - std::string missing_layer; - return !::HasMissingLayer(selected_configuration->parameters, available_layers, missing_layer); - } else { - return false; - } - } - } - case LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED: - return true; + if (this->available_configurations.empty()) { + return nullptr; } - return false; + return FindByKey(this->available_configurations, configuration_name.c_str()); } -std::string ConfigurationManager::ImportConfiguration(const std::vector &available_layers, - const std::string &full_import_path) { - assert(!full_import_path.empty()); +std::string ConfigurationManager::ImportConfiguration(const std::vector &available_layers, const Path &full_import_path) { + assert(!full_import_path.Empty()); Configuration configuration; - if (!configuration.Load(available_layers, full_import_path)) { + if (!configuration.Load(full_import_path, available_layers)) { QMessageBox msg; msg.setIcon(QMessageBox::Critical); msg.setWindowTitle("Import of Layers Configuration error"); msg.setText("Cannot access the source configuration file."); - msg.setInformativeText(full_import_path.c_str()); + msg.setInformativeText(full_import_path.AbsolutePath().c_str()); msg.exec(); return ""; } @@ -335,74 +243,39 @@ std::string ConfigurationManager::ImportConfiguration(const std::vector & return configuration.key; } -void ConfigurationManager::ExportConfiguration(const std::vector &available_layers, const std::string &full_export_path, +void ConfigurationManager::ExportConfiguration(const std::vector &available_layers, const Path &full_export_path, const std::string &configuration_name) { assert(!configuration_name.empty()); - assert(!full_export_path.empty()); + assert(!full_export_path.Empty()); Configuration *configuration = FindByKey(available_configurations, configuration_name.c_str()); assert(configuration); - if (!configuration->Save(available_layers, full_export_path, true)) { + if (!configuration->Save(full_export_path, true)) { QMessageBox msg; msg.setIcon(QMessageBox::Critical); msg.setWindowTitle("Export of Layers Configuration error"); msg.setText("Cannot create the destination configuration file."); - msg.setInformativeText(full_export_path.c_str()); + msg.setInformativeText(full_export_path.AbsolutePath().c_str()); msg.exec(); } } -void ConfigurationManager::ResetDefaultsConfigurations(const std::vector &available_layers) { - this->environment.Reset(Environment::DEFAULT); - +void ConfigurationManager::Reset(const std::vector &available_layers) { // Now we need to kind of restart everything - this->LoadAllConfigurations(available_layers); - this->SaveAllConfigurations(available_layers); -} - -void ConfigurationManager::ReloadDefaultsConfigurations(const std::vector &available_layers) { - // Now we need to kind of restart everything - LoadDefaultConfigurations(available_layers); - - this->Configure(available_layers); -} - -void ConfigurationManager::FirstDefaultsConfigurations(const std::vector &available_layers) { - const QFileInfoList &configuration_files = GetJSONFiles(":/configurations/"); + this->LoadDefaultConfigurations(available_layers); - for (int i = 0, n = configuration_files.size(); i < n; ++i) { - if (environment.IsDefaultConfigurationInit(configuration_files[i].baseName().toStdString())) { - continue; - } - - environment.InitDefaultConfiguration(configuration_files[i].baseName().toStdString()); - - Configuration configuration; - const bool result = configuration.Load(available_layers, configuration_files[i].absoluteFilePath().toStdString()); - assert(result); - - if (!IsPlatformSupported(configuration.platform_flags)) { - continue; - } - - if (FindByKey(available_configurations, configuration.key.c_str()) != nullptr) { - continue; - } - - OrderParameter(configuration.parameters, available_layers); - available_configurations.push_back(configuration); - } + this->SortConfigurations(); } bool ConfigurationManager::CheckApiVersions(const std::vector &available_layers, Configuration *selected_configuration, std::string &log_versions) const { - return CompareLayersVersions(available_layers, selected_configuration, environment.api_version, log_versions, true); + return this->CompareLayersVersions(available_layers, selected_configuration, Version::VKCONFIG, log_versions, true); } bool ConfigurationManager::CheckLayersVersions(const std::vector &available_layers, Configuration *selected_configuration, std::string &log_versions) const { - return CompareLayersVersions(available_layers, selected_configuration, Version::VERSION_NULL, log_versions, false); + return this->CompareLayersVersions(available_layers, selected_configuration, Version::VERSION_NULL, log_versions, false); } bool ConfigurationManager::CompareLayersVersions(const std::vector &available_layers, Configuration *selected_configuration, @@ -417,7 +290,9 @@ bool ConfigurationManager::CompareLayersVersions(const std::vector &avail ++param_index) { const Parameter ¶meter = selected_configuration->parameters[param_index]; - if (parameter.state != LAYER_STATE_OVERRIDDEN) continue; + if (parameter.control != LAYER_CONTROL_ON) { + continue; + } for (std::size_t layer_index = 0, layer_count = available_layers.size(); layer_index < layer_count; ++layer_index) { const Layer &layer = available_layers[layer_index]; diff --git a/vkconfig_core/configuration_manager.h b/vkconfig_core/configuration_manager.h index 99c1a03aaa..4ed37c4de8 100644 --- a/vkconfig_core/configuration_manager.h +++ b/vkconfig_core/configuration_manager.h @@ -21,43 +21,33 @@ #pragma once #include "configuration.h" -#include "environment.h" -#include "path_manager.h" +#include "path.h" #include #include class ConfigurationManager { public: - ConfigurationManager(Environment& environment); + ConfigurationManager(); ~ConfigurationManager(); void LoadAllConfigurations(const std::vector& available_layers); - void SaveAllConfigurations(const std::vector& available_layers); + void SaveAllConfigurations(); Configuration& CreateConfiguration(const std::vector& available_layers, const std::string& configuration_name, bool duplicate = false); void RemoveConfiguration(const std::vector& available_layers, const std::string& configuration_name); - std::string ImportConfiguration(const std::vector& available_layers, const std::string& full_import_path); - void ExportConfiguration(const std::vector& available_layers, const std::string& full_export_path, + std::string ImportConfiguration(const std::vector& available_layers, const Path& full_import_path); + void ExportConfiguration(const std::vector& available_layers, const Path& full_export_path, const std::string& configuration_name); - Configuration* FindActiveConfiguration(); - bool HasActiveConfiguration(const std::vector& available_layers) const; + const Configuration* FindConfiguration(const std::string& configuration_name) const; + Configuration* FindConfiguration(const std::string& configuration_name); - // The only function that actually configure the system, the Vulkan Loader, the Vulkan layer settings, creating and deleting - // system files - void Configure(const std::vector& available_layers, const std::string& configuration_name); - void Configure(const std::vector& available_layers); - - void ResetDefaultsConfigurations(const std::vector& available_layers); - - void ReloadDefaultsConfigurations(const std::vector& available_layers); - - void FirstDefaultsConfigurations(const std::vector& available_layers); + void Reset(const std::vector& available_layers); void SortConfigurations(); @@ -79,8 +69,9 @@ class ConfigurationManager { void RemoveConfigurationFiles(); - void LoadConfigurationsPath(const std::vector& available_layers, const char* path); + void LoadConfigurationsPath(const std::vector& available_layers); void LoadDefaultConfigurations(const std::vector& available_layers); - Environment& environment; + std::vector default_configuration_filenames; + std::map removed_built_in_configuration; }; diff --git a/vkconfig_core/configurations/2.2.2/Portability.json b/vkconfig_core/configurations/2.2.2/Portability.json deleted file mode 100644 index 0a1cec7425..0000000000 --- a/vkconfig_core/configurations/2.2.2/Portability.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "file_format_version": "2.2.1", - "configuration": { - "name": "Portability", - "platforms": [ - "WINDOWS", - "LINUX", - "MACOS" - ], - "description": "Check the Vulkan application is portable to Apple platforms", - "layers": [ - { - "name": "VK_LAYER_LUNARG_api_dump", - "rank": -1, - "settings": [ - ], - "state": "EXCLUDED" - }, - { - "name": "VK_LAYER_LUNARG_gfxreconstruct", - "rank": -1, - "settings": [ - ], - "state": "EXCLUDED", - "platforms": [ - "WINDOWS", - "LINUX" - ] - }, - { - "name": "VK_LAYER_LUNARG_monitor", - "rank": -1, - "settings": [ - ], - "state": "EXCLUDED", - "platforms": [ - "WINDOWS", - "LINUX" - ] - }, - { - "name": "VK_LAYER_LUNARG_screenshot", - "rank": -1, - "settings": [ - ], - "state": "EXCLUDED", - "platforms": [ - "WINDOWS", - "LINUX" - ] - }, - { - "name": "VK_LAYER_KHRONOS_synchronization2", - "rank": -1, - "settings": [ - ], - "state": "EXCLUDED" - }, - { - "name": "VK_LAYER_KHRONOS_validation", - "rank": 4, - "settings": [ - ], - "state": "OVERRIDDEN" - }, - { - "name": "VK_LAYER_KHRONOS_profiles", - "rank": 5, - "settings": [ - { - "key": "profile_dirs", - "type": "LOAD_FOLDER", - "value": "${VULKAN_CONTENT}/VK_LAYER_KHRONOS_profiles" - }, - { - "key": "profile_name", - "type": "ENUM", - "value": "VP_LUNARG_desktop_baseline_2023" - } - ], - "state": "OVERRIDDEN" - } - ] - } -} diff --git a/vkconfig_core/configurations/2.2.2/API dump.json b/vkconfig_core/configurations/3.0.0/API dump.json similarity index 76% rename from vkconfig_core/configurations/2.2.2/API dump.json rename to vkconfig_core/configurations/3.0.0/API dump.json index 4dbfa1f2d6..12d674bb9f 100644 --- a/vkconfig_core/configurations/2.2.2/API dump.json +++ b/vkconfig_core/configurations/3.0.0/API dump.json @@ -1,7 +1,8 @@ { - "file_format_version": "2.2.1", + "file_format_version": "3.0.0", "configuration": { "name": "API dump", + "version": 1, "platforms": [ "WINDOWS", "LINUX", @@ -14,7 +15,8 @@ "rank": 0, "settings": [ ], - "state": "OVERRIDDEN" + "control": "on", + "version": "latest" } ] } diff --git a/vkconfig_core/configurations/2.2.2/Crash Diagnostic.json b/vkconfig_core/configurations/3.0.0/Crash Diagnostic.json similarity index 95% rename from vkconfig_core/configurations/2.2.2/Crash Diagnostic.json rename to vkconfig_core/configurations/3.0.0/Crash Diagnostic.json index 19e738261f..adb61b5d6f 100644 --- a/vkconfig_core/configurations/2.2.2/Crash Diagnostic.json +++ b/vkconfig_core/configurations/3.0.0/Crash Diagnostic.json @@ -1,5 +1,12 @@ { + "file_format_version": "3.0.0", "configuration": { + "name": "Crash Diagnostic", + "version": 1, + "platforms": [ + "WINDOWS", + "LINUX" + ], "description": "Crash Diagnostic Layer is a crash/hang debugging tool that helps determines GPU progress in a Vulkan application.", "layers": [ { @@ -74,15 +81,9 @@ "value": true } ], - "state": "OVERRIDDEN" + "control": "on", + "version": "latest" } - ], - "name": "Crash Diagnostic", - "platforms": [ - "WINDOWS", - "LINUX" - ], - "view_advanced_settings": false - }, - "file_format_version": "2.2.2" + ] + } } diff --git a/vkconfig_core/configurations/2.2.2/Frame Capture.json b/vkconfig_core/configurations/3.0.0/Frame Capture.json similarity index 82% rename from vkconfig_core/configurations/2.2.2/Frame Capture.json rename to vkconfig_core/configurations/3.0.0/Frame Capture.json index fc176e5e5d..f0503f0b5b 100644 --- a/vkconfig_core/configurations/2.2.2/Frame Capture.json +++ b/vkconfig_core/configurations/3.0.0/Frame Capture.json @@ -1,7 +1,8 @@ { - "file_format_version": "2.2.2", + "file_format_version": "3.0.0", "configuration": { "name": "Frame Capture", + "version": 1, "platforms": [ "WINDOWS", "LINUX" @@ -18,7 +19,8 @@ "value": "${VK_LOCAL}/gfxrecon_capture.gfxr" } ], - "state": "OVERRIDDEN" + "control": "on", + "version": "latest" } ] } diff --git a/vkconfig_core/configurations/3.0.0/Portability.json b/vkconfig_core/configurations/3.0.0/Portability.json new file mode 100644 index 0000000000..7c33d6a4e6 --- /dev/null +++ b/vkconfig_core/configurations/3.0.0/Portability.json @@ -0,0 +1,41 @@ +{ + "file_format_version": "3.0.0", + "configuration": { + "name": "Portability", + "version": 1, + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS" + ], + "description": "Check the Vulkan application is portable to Apple platforms", + "layers": [ + { + "name": "VK_LAYER_KHRONOS_validation", + "rank": 4, + "settings": [ + ], + "control": "on", + "version": "latest" + }, + { + "name": "VK_LAYER_KHRONOS_profiles", + "rank": 5, + "settings": [ + { + "key": "profile_dirs", + "type": "LOAD_FOLDER", + "value": "${VULKAN_CONTENT}/VK_LAYER_KHRONOS_profiles" + }, + { + "key": "profile_name", + "type": "ENUM", + "value": "VP_LUNARG_desktop_baseline_2023" + } + ], + "control": "on", + "version": "latest" + } + ] + } +} diff --git a/vkconfig_core/configurations/2.2.2/Synchronization.json b/vkconfig_core/configurations/3.0.0/Synchronization.json similarity index 94% rename from vkconfig_core/configurations/2.2.2/Synchronization.json rename to vkconfig_core/configurations/3.0.0/Synchronization.json index b8450842a0..4e1795292e 100644 --- a/vkconfig_core/configurations/2.2.2/Synchronization.json +++ b/vkconfig_core/configurations/3.0.0/Synchronization.json @@ -1,7 +1,8 @@ { - "file_format_version": "2.2.1", + "file_format_version": "3.0.0", "configuration": { "name": "Synchronization", + "version": 1, "platforms": [ "WINDOWS", "LINUX", @@ -89,7 +90,8 @@ "value": false } ], - "state": "OVERRIDDEN" + "control": "on", + "version": "latest" }, { "name": "VK_LAYER_KHRONOS_synchronization2", @@ -101,7 +103,8 @@ "value": false } ], - "state": "OVERRIDDEN" + "control": "on", + "version": "latest" } ] } diff --git a/vkconfig_core/configurations/2.2.2/Validation.json b/vkconfig_core/configurations/3.0.0/Validation.json similarity index 79% rename from vkconfig_core/configurations/2.2.2/Validation.json rename to vkconfig_core/configurations/3.0.0/Validation.json index 0cf968746e..62d14c31ac 100644 --- a/vkconfig_core/configurations/2.2.2/Validation.json +++ b/vkconfig_core/configurations/3.0.0/Validation.json @@ -1,7 +1,8 @@ { - "file_format_version": "2.2.1", + "file_format_version": "3.0.0", "configuration": { "name": "Validation", + "version": 1, "platforms": [ "WINDOWS", "LINUX", @@ -14,7 +15,8 @@ "rank": 0, "settings": [ ], - "state": "OVERRIDDEN" + "control": "on", + "version": "latest" } ] } diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp new file mode 100644 index 0000000000..9e39aeff1c --- /dev/null +++ b/vkconfig_core/configurator.cpp @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Lenny Komow + * - Richard S. Wright Jr. + * - Christophe Riccio + */ + +#include "configurator.h" +#include "registry.h" +#include "vulkan_info.h" +#include "util.h" +#include "path.h" +#include "alert.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +static QJsonObject CreateJsonSettingObject(const Configurator::LoaderSettings& loader_settings) { + QJsonArray json_layers; + for (std::size_t j = 0, o = loader_settings.layers.size(); j < o; ++j) { + const Configurator::LoaderLayerSettings& layer = loader_settings.layers[j]; + + QJsonObject json_layer; + json_layer.insert("name", layer.key.c_str()); + json_layer.insert("path", layer.path.c_str()); + json_layer.insert("control", ToLowerCase(::GetToken(layer.control)).c_str()); + json_layer.insert("treat_as_implicit_manifest", layer.implicit); + json_layers.append(json_layer); + } + + QJsonArray json_stderr_log; + const std::vector& stderr_log = GetLogTokens(loader_settings.stderr_log_flags); + for (std::size_t i = 0, n = stderr_log.size(); i < n; ++i) { + json_stderr_log.append(stderr_log[i].c_str()); + } + + QJsonObject json_settings; + + if (!loader_settings.executable_path.empty()) { + QJsonArray json_app_keys; + json_app_keys.append(loader_settings.executable_path.c_str()); + json_settings.insert("app_keys", json_app_keys); + } + + json_settings.insert("layers", json_layers); + json_settings.insert("stderr_log", json_stderr_log); + return json_settings; +} + +void Configurator::BuildLoaderSettings(const ConfigurationInfo& info, const std::string& executable_path, + std::vector& loader_settings_array) const { + LoaderSettings result; + result.executable_path = executable_path; + + static Configuration disbled_configuration = Configuration::CreateDisabled(this->layers.selected_layers); + const Configuration* configuration = nullptr; + + switch (info.GetMode()) { + case LAYERS_CONTROLLED_BY_APPLICATIONS: + return; + case LAYERS_CONTROLLED_BY_CONFIGURATOR: { + configuration = this->configurations.FindConfiguration(info.GetName()); + if (configuration == nullptr) { + return; + } + } break; + case LAYERS_DISABLED_BY_CONFIGURATOR: { + configuration = &disbled_configuration; + } break; + } + assert(configuration != nullptr); + + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + LoaderLayerSettings loader_layer_settings; + + const Parameter& parameter = configuration->parameters[i]; + if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { + continue; + } + + const Layer* layer = FindByKey(this->layers.selected_layers, parameter.key.c_str()); + if (layer == nullptr) { + continue; + } + + // Extract just the path + loader_layer_settings.key = parameter.key; + if (layer != nullptr) { + loader_layer_settings.path = layer->manifest_path.AbsolutePath(); + } + loader_layer_settings.control = parameter.control; + loader_layer_settings.implicit = layer != nullptr ? layer->type == LAYER_TYPE_IMPLICIT : false; + + result.layers.push_back(loader_layer_settings); + } + + loader_settings_array.push_back(result); +} + +// Create and write vk_loader_settings.json file +bool Configurator::WriteLoaderSettings(const Path& loader_settings_path) { + assert(!loader_settings_path.Empty()); + + std::vector loader_settings_array; + + if (this->environment.GetPerApplicationConfig()) { + for (std::size_t i = 0, n = this->environment.GetApplications().size(); i < n; ++i) { + const Application& application = this->environment.GetApplication(i); + + this->BuildLoaderSettings(application.configuration, application.executable_path.AbsolutePath(), loader_settings_array); + } + } else { + BuildLoaderSettings(this->environment.global_configuration, "", loader_settings_array); + } + + if (loader_settings_array.empty()) { + return this->Surrender(); + } else { + QJsonObject root; + root.insert("file_format_version", "1.0.0"); + if (loader_settings_array.size() > 1) { + QJsonArray json_settings_array; + for (std::size_t i = 0, n = loader_settings_array.size(); i < n; ++i) { + json_settings_array.append(CreateJsonSettingObject(loader_settings_array[i])); + } + root.insert("settings_array", json_settings_array); + } else if (!loader_settings_array.empty()) { + root.insert("settings", CreateJsonSettingObject(loader_settings_array[0])); + } + QJsonDocument doc(root); + + QFile json_file(loader_settings_path.AbsolutePath().c_str()); + const bool result_layers_file = json_file.open(QIODevice::WriteOnly | QIODevice::Text); + assert(result_layers_file); + json_file.write(doc.toJson()); + json_file.close(); + + return result_layers_file; + } +} + +// Create and write vk_layer_settings.txt file +bool Configurator::WriteLayersSettings(const Path& layers_settings_path) { + std::vector layers_settings_array; + + if (this->environment.GetPerApplicationConfig()) { + const std::vector& applications = this->environment.GetApplications(); + + for (std::size_t i = 0, n = applications.size(); i < n; ++i) { + LayersSettings settings; + settings.configuration_name = applications[i].configuration.GetName(); + settings.executable_path = applications[i].executable_path; + settings.settings_path = applications[i].GetActiveOptions().working_folder; + layers_settings_array.push_back(settings); + } + } else { + LayersSettings settings; + settings.configuration_name = this->environment.global_configuration.GetName(); + settings.settings_path = layers_settings_path; + layers_settings_array.push_back(settings); + } + + bool has_missing_layers = false; + bool result_settings_file = true; + + for (std::size_t i = 0, n = layers_settings_array.size(); i < n; ++i) { + const LayersSettings& layers_settings = layers_settings_array[i]; + + Configuration* configuration = this->configurations.FindConfiguration(layers_settings.configuration_name); + if (configuration == nullptr) { + if (layers_settings.executable_path.Empty()) { + fprintf(stderr, "Fail to apply unknown '%s' global configuration\n", layers_settings.configuration_name.c_str()); + } else { + fprintf(stderr, "Fail to apply unknown '%s' configuration to '%s'\n", layers_settings.configuration_name.c_str(), + layers_settings.executable_path.AbsolutePath().c_str()); + } + + result_settings_file = false; + continue; + } + + QFile file(layers_settings.settings_path.AbsolutePath().c_str()); + result_settings_file = result_settings_file && file.open(QIODevice::WriteOnly | QIODevice::Text); + if (!result_settings_file) { + fprintf(stderr, "Cannot open file %s\n", layers_settings.settings_path.AbsolutePath().c_str()); + continue; + } + QTextStream stream(&file); + + // Loop through all the layers + for (std::size_t j = 0, n = configuration->parameters.size(); j < n; ++j) { + const Parameter& parameter = configuration->parameters[j]; + if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { + continue; + } + + const Layer* layer = FindByKey(this->layers.selected_layers, parameter.key.c_str()); + if (layer == nullptr) { + has_missing_layers = true; + continue; + } + + if (parameter.control != LAYER_CONTROL_ON) { + continue; + } + + stream << "\n"; + stream << "# " << layer->key.c_str() << "\n\n"; + + std::string lc_layer_name = GetLayerSettingPrefix(layer->key); + + for (std::size_t i = 0, m = parameter.settings.size(); i < m; ++i) { + const SettingData* setting_data = parameter.settings[i]; + + // Skip groups - they aren't settings, so not relevant in this output + if (setting_data->type == SETTING_GROUP) { + continue; + } + + // Skip missing settings + const SettingMeta* meta = FindSetting(layer->settings, setting_data->key.c_str()); + if (meta == nullptr) { + continue; + } + + // Skip overriden settings + if (::CheckSettingOverridden(*meta)) { + continue; + } + + stream << "# "; + stream << meta->label.c_str(); + stream << "\n# =====================\n# ."; + stream << meta->key.c_str() << "\n"; + + // Break up description into smaller words + std::string description = meta->description; + std::vector words; + std::size_t pos; + while ((pos = description.find(" ")) != std::string::npos) { + words.push_back(description.substr(0, pos)); + description.erase(0, pos + 1); + } + if (description.size() > 0) words.push_back(description); + if (words.size() > 0) { + stream << "#"; + std::size_t nchars = 2; + for (auto word : words) { + if (word.size() + nchars > 80) { + stream << "\n#"; + nchars = 2; + } + stream << " " << word.c_str(); + nchars += (word.size() + 1); + } + } + stream << "\n"; + + // If feature has unmet dependency, output it but comment it out + if (::CheckDependence(*meta, parameter.settings) != SETTING_DEPENDENCE_ENABLE) { + stream << "#"; + } + + stream << lc_layer_name.c_str() << setting_data->key.c_str() << " = "; + stream << setting_data->Export(EXPORT_MODE_OVERRIDE).c_str(); + stream << "\n\n"; + } + } + file.close(); + } + + return result_settings_file && !has_missing_layers; +} + +Configurator& Configurator::Get() { + static Configurator configurator; + return configurator; +} + +Configurator::Configurator() : environment(), layers(), configurations() {} + +Configurator::~Configurator() { + this->configurations.SaveAllConfigurations(); + + this->Surrender(); +} + +bool Configurator::Init() { + // Load simple app settings, the additional search paths, and the + // override app list. + this->layers.LoadAllInstalledLayers(); + + if (this->environment.has_crashed) { + this->environment.has_crashed = false; + + if (Alert::ConfiguratorCrashed() == QMessageBox::No) { + this->configurations.LoadAllConfigurations(this->layers.selected_layers); + } + } else { + this->configurations.LoadAllConfigurations(this->layers.selected_layers); + } + + this->Override(); + + return true; +} + +bool Configurator::Override() { + const Path& loader_settings_path = ::Get(Path::LOADER_SETTINGS); + const Path& layers_settings_path = ::Get(Path::LAYERS_SETTINGS); + + // Clean up + this->Surrender(); + + // vk_loader_settings.json + const bool result_layers = this->WriteLoaderSettings(loader_settings_path); + + // vk_layer_settings.txt + const bool result_settings = this->WriteLayersSettings(layers_settings_path); + + // On Windows only, we need to write these values to the registry +#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS + AppendRegistryEntriesForLayers(loader_settings_path.AbsolutePath().c_str(), layers_settings_path.AbsolutePath().c_str()); +#endif + + return result_settings && result_layers; +} + +bool Configurator::Surrender() { + const Path& loader_settings_path = ::Get(Path::LOADER_SETTINGS); + const Path& layers_settings_path = ::Get(Path::LAYERS_SETTINGS); + + const bool result_loader_settings = loader_settings_path.Remove(); + const bool result_layers_settings = layers_settings_path.Remove(); + +#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS + RemoveRegistryEntriesForLayers(loader_settings_path.AbsolutePath().c_str(), layers_settings_path.AbsolutePath().c_str()); +#endif + + this->environment.global_configuration.ForceUpdate(UPDATE_ALL); + + return result_loader_settings && result_layers_settings; +} + +bool Configurator::HasOverride() const { + const Path& loader_settings_path = ::Get(Path::LOADER_SETTINGS); + const Path& layers_settings_path = ::Get(Path::LAYERS_SETTINGS); + + return loader_settings_path.Exists() || layers_settings_path.Exists(); +} + +void Configurator::ResetToDefault(bool hard) { + this->environment.Reset(Environment::CLEAR); + this->layers.LoadAllInstalledLayers(); + this->configurations.Reset(this->layers.selected_layers); +} + +Configuration* Configurator::GetActiveConfiguration() { + const ConfigurationInfo& info = this->environment.GetActiveConfigurationInfo(); + return this->configurations.FindConfiguration(info.GetName()); +} + +const Configuration* Configurator::GetActiveConfiguration() const { + const ConfigurationInfo& info = this->environment.GetActiveConfigurationInfo(); + return this->configurations.FindConfiguration(info.GetName()); +} + +bool Configurator::HasActiveConfiguration() const { return true; } diff --git a/vkconfig/configurator.h b/vkconfig_core/configurator.h similarity index 53% rename from vkconfig/configurator.h rename to vkconfig_core/configurator.h index 5aab5c54fd..0e50464f6d 100644 --- a/vkconfig/configurator.h +++ b/vkconfig_core/configurator.h @@ -24,52 +24,62 @@ #include "../vkconfig_core/version.h" #include "../vkconfig_core/layer.h" #include "../vkconfig_core/layer_manager.h" -#include "../vkconfig_core/path_manager.h" #include "../vkconfig_core/environment.h" #include "../vkconfig_core/configuration_manager.h" -#include "../vkconfig_core/platform.h" - -static const std::vector SUPPORTED_CONFIG_FILES = {"_2_2_3", "_2_2_2", "_2_2_1"}; +#include "../vkconfig_core/type_platform.h" +#include "../vkconfig_core/vulkan_info.h" class Configurator { public: - static Configurator& Get(const std::string& VULKAN_SDK = ""); - bool Init(); + struct LayersSettings { + std::string configuration_name; + Path executable_path; + Path settings_path; + }; - // The list of applications affected - public: - bool SupportDifferentLayerVersions(Version* return_loader_version = nullptr) const; + struct LoaderLayerSettings { + std::string key; + std::string path; + LayerControl control = LAYER_CONTROL_AUTO; + bool implicit = false; + }; - // If return_loader_version is not null, the function will return the loader version - // If quiet is false, message box will be generate - bool SupportApplicationList(Version* return_loader_version = nullptr) const; + struct LoaderSettings { + std::string executable_path; + std::vector layers; + LogFlags stderr_log_flags = LOG_ERROR; + }; - bool HasActiveOverrideOnApplicationListOnly() const { - return SupportApplicationList() && environment.HasOverriddenApplications(); - } + static Configurator& Get(); + bool Init(); - void ActivateConfiguration(const std::string& configuration_name); + public: + bool Surrender(); + bool Override(); + bool HasOverride() const; void ResetToDefault(bool hard); - std::string profile_file; - - std::vector GetDeviceNames() const; + Configuration* GetActiveConfiguration(); + const Configuration* GetActiveConfiguration() const; + bool HasActiveConfiguration() const; private: - Configurator(const std::string& VULKAN_SDK); + Configurator(); ~Configurator(); Configurator(const Configurator&) = delete; Configurator& operator=(const Configurator&) = delete; - void UpdateDevices(); - void CopyResourceFiles(); + bool WriteLayersSettings(const Path& layers_settings_path); + bool WriteLoaderSettings(const Path& loader_settings_path); + + void BuildLoaderSettings(const ConfigurationInfo& info, const std::string& executable_path, + std::vector& loader_settings_array) const; public: - PathManager path; Environment environment; LayerManager layers; ConfigurationManager configurations; - std::vector device_names; + VulkanSystemInfo vulkan_system_info; }; diff --git a/vkconfig/main_signal.cpp b/vkconfig_core/configurator_signal.cpp similarity index 78% rename from vkconfig/main_signal.cpp rename to vkconfig_core/configurator_signal.cpp index 1e057852f0..21cf767614 100644 --- a/vkconfig/main_signal.cpp +++ b/vkconfig_core/configurator_signal.cpp @@ -18,29 +18,22 @@ * - Christophe Riccio */ -#include "../vkconfig_core/override.h" -#include "../vkconfig_core/layer_manager.h" - -#include "main_signal.h" #include "configurator.h" -#include +#include "signal.h" #include void SurrenderConfiguration(int signal) { (void)signal; - // Indicate that Vulkan Configurator crashed to handle it on next run - { - QSettings settings; - settings.setValue("crashed", true); - } + Configurator& configurator = Configurator::Get(); - PathManager paths("", SUPPORTED_CONFIG_FILES); - Environment environment(paths); + // Indicate that Vulkan Configurator crashed to handle it on next run + configurator.environment.has_crashed = true; - SurrenderConfiguration(environment); + // Delete the layers configurations files + configurator.Surrender(); } void InitSignals() { diff --git a/vkconfig/main_signal.h b/vkconfig_core/configurator_signal.h similarity index 88% rename from vkconfig/main_signal.h rename to vkconfig_core/configurator_signal.h index d9ff6e1a7d..44abac55b4 100644 --- a/vkconfig/main_signal.h +++ b/vkconfig_core/configurator_signal.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vkconfig_core/doc.cpp b/vkconfig_core/doc.cpp index 1f36e15cb4..20786e2743 100644 --- a/vkconfig_core/doc.cpp +++ b/vkconfig_core/doc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2022 Valve Corporation - * Copyright (c) 2020-2022 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ #include "doc.h" #include "setting_flags.h" -#include "override.h" +#include "configurator.h" #include @@ -322,9 +322,10 @@ void ExportHtmlDoc(const Layer& layer, const std::string& path) { text += "

    \n"; text += format("\t
  • API Version: %s
  • \n", layer.api_version.str().c_str()); text += format("\t
  • Implementation Version: %s
  • \n", layer.implementation_version.c_str()); - text += format("\t
  • Layer Manifest: %s
      \n", QFileInfo(layer.manifest_path.c_str()).fileName().toStdString().c_str()); + text += format("\t
    • Layer Manifest: %s
        \n", + QFileInfo(layer.manifest_path.RelativePath().c_str()).fileName().toStdString().c_str()); text += format("\t\t
      • File Format: %s
      • \n", layer.file_format_version.str().c_str()); - text += format("\t\t
      • Layer Binary Path: %s
      • \n", layer.binary_path.c_str()); + text += format("\t\t
      • Layer Binary Path: %s
      • \n", layer.binary_path.RelativePath().c_str()); text += "\t
    • \n"; if (layer.platforms != 0) { text += format("\t
    • Platforms: %s
    • \n", BuildPlatformsHtml(layer.platforms).c_str()); @@ -407,10 +408,12 @@ void ExportMarkdownDoc(const Layer& layer, const std::string& path) { text += "### Layer Properties\n\n"; text += "- API Version: " + layer.api_version.str() + "\n"; text += "- Implementation Version: " + layer.implementation_version + "\n"; - text += "- Layer Manifest: " + QFileInfo(layer.manifest_path.c_str()).fileName().toStdString() + "\n"; + text += "- Layer Manifest: " + QFileInfo(layer.manifest_path.RelativePath().c_str()).fileName().toStdString() + "\n"; text += " - File Format: " + layer.file_format_version.str() + "\n"; text += " - Layer Binary: "; - text += (layer.binary_path.rfind("./", 0) == 0 ? layer.binary_path.substr(2) : layer.binary_path) + "\n"; + text += (layer.binary_path.RelativePath().rfind("./", 0) == 0 ? layer.binary_path.RelativePath().substr(2) + : layer.binary_path.RelativePath()) + + "\n"; if (layer.platforms != 0) { text += "- Platforms: " + BuildPlatformsMarkdown(layer.platforms) + "\n"; @@ -464,8 +467,10 @@ void ExportMarkdownDoc(const Layer& layer, const std::string& path) { } void ExportSettingsDoc(const std::vector& available_layers, const Configuration& configuration, const std::string& path) { + /* TODO if (WriteLayersSettings(available_layers, configuration, path)) printf("vkconfig: settings written to %s\n", path.c_str()); else printf("vkconfig: could not write %s\n", path.c_str()); + */ } diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index 7acd45322d..244db47449 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -19,11 +19,13 @@ */ #include "environment.h" -#include "platform.h" #include "setting.h" #include "util.h" -#include +#include "type_platform.h" +#include "type_layers_mode.h" +#include "type_log.h" + #include #include #include @@ -43,7 +45,7 @@ static const char* GetApplicationSuffix() { ".app", // PLATFORM_MACOS "N/A" // PLATFORM_ANDROID }; - static_assert(countof(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); + static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); return TABLE[VKC_PLATFORM]; } @@ -67,129 +69,49 @@ static const char* GetLayoutStateToken(LayoutState state) { "launcherCollapsed", // LAYOUT_LAUNCHER_COLLAPSED "launcherOnClear" // LAYOUT_LAUNCHER_CLEAR_ON }; - static_assert(countof(table) == LAYOUT_COUNT, "The tranlation table size doesn't match the enum number of elements"); + static_assert(std::size(table) == LAYOUT_COUNT, "The tranlation table size doesn't match the enum number of elements"); return table[state]; } -std::string GetLoaderMessageToken(LoaderMessageType message_type) { - static const char* LOADER_MESSAGE_TOKENS[]{ - "error", // LOADER_MESSAGE_ERROR - "warn", // LOADER_MESSAGE_WARN - "info", // LOADER_MESSAGE_INFO - "debug", // LOADER_MESSAGE_DEBUG - "layer", // LOADER_MESSAGE_LAYER - "implem" // LOADER_MESSAGE_IMPLEMENTATION - }; - - static_assert(countof(LOADER_MESSAGE_TOKENS) == LOADER_MESSAGE_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - return LOADER_MESSAGE_TOKENS[message_type - LOADER_MESSAGE_FIRST]; -} - -std::string GetLoaderMessageTokens(int mesage_types) { - std::vector results; - - for (int i = LOADER_MESSAGE_FIRST, l = LOADER_MESSAGE_LAST; i <= l; ++i) { - if (mesage_types & (1 << i)) { - results.push_back(GetLoaderMessageToken(static_cast(i))); - } - } - - return Merge(results, ","); -} - -int GetLoaderMessageTypes(const std::string& values) { - std::vector split_values = Split(values, ","); - - int result = 0; - - for (std::size_t i = 0, n = split_values.size(); i < n; ++i) { - const LoaderMessageType message_type = GetLoaderMessageType(split_values[i]); - if (message_type == LOADER_MESSAGE_NONE) { - continue; - } - result |= (1 << message_type); +Environment::Environment(Mode mode) + : mode(mode), loader_message_types_flags(::GetLogFlags(qgetenv("VK_LOADER_DEBUG").toStdString())) { + if (mode == MODE_AUTO_LOAD_SAVE) { + const bool result = Load(); + assert(result); } - return result; -} - -LoaderMessageType GetLoaderMessageType(const std::string& value) { - for (int i = LOADER_MESSAGE_FIRST, n = LOADER_MESSAGE_LAST; i <= n; ++i) { - const LoaderMessageType message_type = static_cast(i); - if (::GetLoaderMessageToken(message_type) == value) return message_type; + if (this->applications.empty()) { + this->applications = CreateDefaultApplications(); } - - return LOADER_MESSAGE_NONE; -} - -Environment::Environment(PathManager& paths, const Version& api_version) - : api_version(api_version), - use_system_tray(false), - use_per_application_configuration(false), - loader_message_types(::GetLoaderMessageTypes(qgetenv("VK_LOADER_DEBUG").toStdString())), - paths_manager(paths), - paths(paths_manager) { - const bool result = Load(); - assert(result); } Environment::~Environment() { - const bool result = Save(); - assert(result); + if (mode == MODE_AUTO_LOAD_SAVE) { + const bool result = Save(); + assert(result); + } } void Environment::Reset(ResetMode mode) { switch (mode) { case DEFAULT: { - this->first_run = true; - this->vkconfig2_version = Version::VKCONFIG; - this->vkconfig3_version = Version::VKCONFIG3; - this->layers_mode = LAYERS_MODE_BY_CONFIGURATOR_RUNNING; + this->global_configuration = ConfigurationInfo(); this->use_per_application_configuration = false; - this->use_application_list = false; this->use_system_tray = false; - this->selected_configuration = "Validation"; - this->active_application.clear(); - this->user_defined_layers_paths[USER_DEFINED_LAYERS_PATHS_GUI].clear(); + this->active_executable_index = 0; - applications = CreateDefaultApplications(); + this->applications = CreateDefaultApplications(); break; } case CLEAR: { this->Reset(DEFAULT); - QSettings settings; - settings.setValue("VKCONFIG_WIDGET_SETTING_INT", false); - settings.setValue("VKCONFIG_WIDGET_SETTING_FLOAT", false); - settings.setValue("VKCONFIG_WIDGET_SETTING_FRAMES", false); - settings.setValue("VKCONFIG_WARN_MISSING_LAYERS_IGNORE", false); - settings.setValue("VKCONFIG_WARN_CORE_SHADER_IGNORE", false); - - settings.setValue(VKCONFIG_KEY_MESSAGE_NEED_APPLICATION_RESTART, false); - settings.setValue("overrideActive", false); - settings.setValue("applyPerApplication", false); - settings.setValue("keepActiveOnExit", false); - - settings.setValue("restartWarning", false); - settings.setValue("warnAboutShutdownState", false); - - const std::string loader_debug_message(qgetenv("VK_LOADER_DEBUG")); - if (loader_debug_message.empty()) { - this->loader_message_types = 0; - } else { - this->loader_message_types = ::GetLoaderMessageTypes(loader_debug_message); - } - settings.setValue(VKCONFIG_KEY_LOADER_MESSAGE, static_cast(this->loader_message_types)); break; } case SYSTEM: { const bool result_env = Load(); assert(result_env); - const bool result_path = paths_manager.Load(); - assert(result_path); break; } default: { @@ -199,199 +121,222 @@ void Environment::Reset(ResetMode mode) { } } +std::string GetPath() { + static const char* TABLE[] = { + "/AppData/Local/LunarG", // ENVIRONMENT_WIN32 + "/.local/share/vulkan" // ENVIRONMENT_UNIX + }; + static_assert(std::size(TABLE) == ENVIRONMENT_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + const std::string home = QDir().homePath().toStdString(); + return home + TABLE[VKC_ENV]; +} + bool Environment::Load() { Reset(DEFAULT); - QSettings settings; - - // Load "first_run" - this->first_run = settings.value(VKCONFIG_KEY_INITIALIZE_FILES, first_run).toBool(); + const Path& vkconfig_init_path = ::Get(Path::INIT); + QFile file(vkconfig_init_path.AbsolutePath().c_str()); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QString data = file.readAll(); + file.close(); - // Load "version": If the version doesn't exist of it's an old version of vkconfig - this->vkconfig2_version = - Version(settings.value(VKCONFIG_KEY_VKCONFIG_VERSION, Version::VKCONFIG.str().c_str()).toString().toStdString()); + const QJsonDocument& json_doc = QJsonDocument::fromJson(data.toLocal8Bit()); + const QJsonObject& json_root_object = json_doc.object(); - // Load "version": If the version doesn't exist of it's an old version of vkconfig - this->vkconfig3_version = - Version(settings.value(VKCONFIG_KEY_VKCONFIG3_VERSION, Version::VKCONFIG3.str().c_str()).toString().toStdString()); + const Version file_format_version = Version(json_root_object.value("file_format_version").toString().toStdString()); + if (file_format_version > Version::VKCONFIG) { + return false; // Vulkan Configurator needs to be updated + } - // Load 'override_mode" - this->layers_mode = static_cast(settings.value(VKCONFIG_KEY_LAYERS_MODE, QVariant(layers_mode)).toInt()); + // interface json object + const QJsonObject& json_interface_object = json_root_object.value("interface").toObject(); + this->active_tab = GetTabType(json_interface_object.value("active_tab").toString().toStdString().c_str()); + this->has_crashed = json_interface_object.value("has_crashed").toBool(); + + // diagnostic json object + const QJsonObject& json_diagnostic_object = json_root_object.value("diagnostic").toObject(); + const QJsonArray& json_loader_messages_array = json_diagnostic_object.value("loader_messages").toArray(); + this->loader_message_types_flags = 0; + for (int i = 0, n = json_loader_messages_array.size(); i < n; ++i) { + const std::string& token = json_loader_messages_array[i].toString().toStdString(); + this->loader_message_types_flags |= GetLogBit(token.c_str()); + } - this->use_per_application_configuration = - static_cast(settings.value(VKCONFIG_KEY_STATE_PER_APPLICATION, this->use_application_list).toBool()); - this->use_application_list = - static_cast(settings.value(VKCONFIG_KEY_STATE_APPLICATION_LIST, this->use_application_list).toBool()); - this->use_system_tray = static_cast(settings.value(VKCONFIG_KEY_STATE_SYSTEM_TRAY, this->use_system_tray).toBool()); + // applications json object + const QJsonObject& json_applications_object = json_root_object.value("applications").toObject(); - // Load loader debug message state - this->loader_message_types = settings.value(VKCONFIG_KEY_LOADER_MESSAGE, static_cast(this->loader_message_types)).toInt(); + this->active_executable_index = json_applications_object.value("active_executable_index").toInt(); - // Load active configuration - this->selected_configuration = - settings.value(VKCONFIG_KEY_ACTIVE_CONFIGURATION, this->selected_configuration.c_str()).toString().toStdString(); + const QJsonObject& json_list_object = json_applications_object.value("list").toObject(); - this->active_application = - settings.value(VKCONFIG_KEY_ACTIVE_APPLICATION, this->active_application.c_str()).toString().toStdString(); + const QStringList& json_list_keys = json_list_object.keys(); - // Load layout state - for (std::size_t i = 0; i < LAYOUT_COUNT; ++i) { - this->layout_states[i] = settings.value(GetLayoutStateToken(static_cast(i))).toByteArray(); - } + this->applications.clear(); + for (int i = 0, n = json_list_keys.length(); i < n; ++i) { + Application application; - // Load default configuration already init - this->default_configuration_filenames = ConvertString(settings.value("default_configuration_files").toStringList()); + const QJsonObject& json_application_object = json_list_object.value(json_list_keys[i]).toObject(); + application.executable_path = json_list_keys[i].toStdString(); + application.configuration.SetName(json_application_object.value("configuration").toString().toStdString()); + application.configuration.SetMode( + ::GetLayersMode(json_application_object.value("mode").toString().toStdString().c_str())); + application.active_option_index = json_application_object.value("active_option_index").toInt(); - const char* SEPARATOR = GetToken(PARSE_ENV_VAR); + const QJsonArray& json_options_array = json_application_object.value("options").toArray(); + for (int j = 0, o = json_options_array.size(); j < o; ++j) { + const QJsonObject& json_options_object = json_options_array[j].toObject(); - // See if the VK_LAYER_PATH environment variable is set. If so, parse it and - // assemble a list of paths that take precidence for layer discovery. - const QString VK_LAYER_PATH(qgetenv("VK_LAYER_PATH")); - if (!VK_LAYER_PATH.isEmpty()) { - std::vector paths = ConvertString(QString(qgetenv("VK_LAYER_PATH")).split(SEPARATOR)); - paths = UniqueStrings(paths); - this->user_defined_layers_paths[USER_DEFINED_LAYERS_PATHS_ENV_SET] = paths; - } else { - this->user_defined_layers_paths[USER_DEFINED_LAYERS_PATHS_ENV_SET].clear(); - } + ApplicationOptions application_options; - // See if the VK_ADD_LAYER_PATH environment variable is set. If so, parse it and - // assemble a list of paths that take precidence for layer discovery. - const QString VK_ADD_LAYER_PATH(qgetenv("VK_ADD_LAYER_PATH")); - if (!VK_ADD_LAYER_PATH.isEmpty()) { - std::vector paths = ConvertString(QString(qgetenv("VK_ADD_LAYER_PATH")).split(SEPARATOR)); - paths = UniqueStrings(paths); - this->user_defined_layers_paths[USER_DEFINED_LAYERS_PATHS_ENV_ADD] = paths; - } else { - this->user_defined_layers_paths[USER_DEFINED_LAYERS_PATHS_ENV_ADD].clear(); - } + application_options.label = json_options_object.value("label").toString().toStdString(); + application_options.working_folder = json_options_object.value("working_folder").toString().toStdString(); - // Load application list - const bool result = LoadApplications(); - assert(result); + const QJsonArray& json_command_lines_array = json_options_object.value("arguments").toArray(); + for (int k = 0, p = json_command_lines_array.size(); k < p; ++k) { + application_options.arguments.push_back(json_command_lines_array[k].toString().toStdString()); + } - return result; -} + const QJsonArray& json_environment_variables_array = json_options_object.value("environment_variables").toArray(); + for (int k = 0, p = json_environment_variables_array.size(); k < p; ++k) { + application_options.environment_variables.push_back( + json_environment_variables_array[k].toString().toStdString()); + } -bool Environment::LoadApplications() { - const std::string& application_list_json = GetPath(BUILTIN_PATH_APPLIST); - QFile file(application_list_json.c_str()); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { // if applist.json exist, load saved applications - QString data = file.readAll(); - file.close(); + application_options.log_file = json_options_array[j].toObject().value("log_file").toString().toStdString(); - applications.clear(); - - if (!data.isEmpty()) { - const QJsonDocument& json_doc = QJsonDocument::fromJson(data.toLocal8Bit()); - assert(json_doc.isObject()); - if (!json_doc.isEmpty()) { - // Get the list of apps - const QJsonObject& json_doc_object = json_doc.object(); - const QStringList& app_keys = json_doc_object.keys(); - - for (int i = 0, n = app_keys.length(); i < n; ++i) { - const QJsonValue& app_value = json_doc_object.value(app_keys[i]); - const QJsonObject& app_object = app_value.toObject(); - - Application application; - application.app_name = app_object.value("app_name").toString().toStdString(); - application.executable_path = app_object.value("app_path").toString().toStdString(); - application.working_folder = app_object.value("app_folder").toString().toStdString(); - application.layers_mode = app_object.value("exclude_override").toBool() ? LAYERS_MODE_BY_APPLICATIONS - : LAYERS_MODE_BY_CONFIGURATOR_RUNNING; - application.log_file = app_object.value("log_file").toString().toStdString(); - if (application.app_name.length() == 0) { - std::string path = application.executable_path.c_str(); - if (path.find(GetNativeSeparator()) != std::string::npos) { - application.app_name = path.substr(path.rfind(GetNativeSeparator()) + 1); - } else { - application.app_name = path; - } - } - - // Arguments are in an array to make room for adding more in a future version - const QJsonArray& args = app_object.value("command_lines").toArray(); - application.arguments = args[0].toString().toStdString(); - - applications.push_back(application); - } + application.options.push_back(application_options); } + + this->applications.push_back(application); + } + + // configurations json object + const QJsonObject& json_configurations_object = json_root_object.value("configurations").toObject(); + this->use_per_application_configuration = json_configurations_object.value("use_per_application").toBool(); + this->global_configuration.SetName(json_configurations_object.value("configuration").toString().toStdString()); + this->global_configuration.SetMode( + ::GetLayersMode(json_configurations_object.value("mode").toString().toStdString().c_str())); + + // preferences json object + const QJsonObject& json_preferences_object = json_root_object.value("preferences").toObject(); + this->use_system_tray = json_preferences_object.value("use_system_tray").toBool(); + this->home_sdk_path = json_preferences_object.value("VK_HOME").toString().toStdString(); + if (this->home_sdk_path.Empty()) { + this->home_sdk_path = ::Get(Path::HOME); } - applications = RemoveMissingApplications(applications); - applications = UpdateDefaultApplications(applications); - if (applications.empty()) applications = CreateDefaultApplications(); + const QJsonArray& json_hide_message_boxes_array = json_preferences_object.value("hide_message_boxes").toArray(); + this->hide_message_boxes_flags = 0; + for (int i = 0, n = json_hide_message_boxes_array.size(); i < n; ++i) { + const std::string& token = json_hide_message_boxes_array[i].toString().toStdString(); + this->hide_message_boxes_flags |= GetLogBit(token.c_str()); + } } return true; } bool Environment::Save() const { - QSettings settings; + const Path& vkconfig_init_path = ::Get(Path::INIT); - // Save 'first_run' - settings.setValue(VKCONFIG_KEY_INITIALIZE_FILES, this->first_run); + QFile file(vkconfig_init_path.AbsolutePath().c_str()); + const bool result = file.open(QIODevice::WriteOnly | QIODevice::Text); + assert(result); - // Save 'version' - settings.setValue(VKCONFIG_KEY_VKCONFIG_VERSION, Version::LAYER_CONFIG.str().c_str()); + QJsonObject json_root_object; + json_root_object.insert("file_format_version", Version::VKCONFIG.str().c_str()); - settings.setValue(VKCONFIG_KEY_LAYERS_MODE, this->layers_mode); - settings.setValue(VKCONFIG_KEY_STATE_PER_APPLICATION, this->use_per_application_configuration); - settings.setValue(VKCONFIG_KEY_STATE_APPLICATION_LIST, this->use_application_list); - settings.setValue(VKCONFIG_KEY_STATE_SYSTEM_TRAY, this->use_system_tray); + QJsonObject json_interface_object; + json_interface_object.insert("active_tab", GetToken(this->active_tab)); + json_interface_object.insert("has_crashed", this->has_crashed); + json_root_object.insert("interface", json_interface_object); - // Save 'loader_message' - settings.setValue(VKCONFIG_KEY_LOADER_MESSAGE, static_cast(this->loader_message_types)); + QJsonObject json_diagnostic_object; - // Save active configuration - settings.setValue(VKCONFIG_KEY_ACTIVE_CONFIGURATION, this->selected_configuration.c_str()); + QJsonArray json_loader_messages_array; + for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { + LogType type = static_cast(i); + if (this->loader_message_types_flags & (1 << i)) { + json_loader_messages_array.append(GetToken(type)); + } + } + json_diagnostic_object.insert("loader_messages", json_loader_messages_array); - // Save active application - settings.setValue(VKCONFIG_KEY_ACTIVE_APPLICATION, this->active_application.c_str()); + json_root_object.insert("diagnostic", json_diagnostic_object); + + QJsonObject json_applications_object; + json_applications_object.insert("active_executable", this->active_executable_index); + QJsonObject json_applications_list_object; + + for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { + const Application& application = this->applications[i]; - // Save layout state - for (std::size_t i = 0; i < LAYOUT_COUNT; ++i) { - settings.setValue(GetLayoutStateToken(static_cast(i)), this->layout_states[i]); + QJsonObject json_application_object; + json_application_object.insert("configuration", application.configuration.GetName()); + json_application_object.insert("mode", ::GetToken(application.configuration.GetMode())); + json_application_object.insert("active_option", application.active_option_index); + + QJsonArray json_options_array; + for (std::size_t j = 0, o = application.options.size(); j < o; ++j) { + const ApplicationOptions& options = application.options[j]; + + QJsonArray json_arg_array; + for (std::size_t k = 0, p = options.arguments.size(); k < p; ++k) { + json_arg_array.append(options.arguments[k].c_str()); + } + + QJsonArray json_env_array; + for (std::size_t k = 0, p = options.environment_variables.size(); k < p; ++k) { + json_env_array.append(options.environment_variables[k].c_str()); + } + + QJsonObject json_option_object; + json_option_object.insert("label", options.label.c_str()); + json_option_object.insert("working_folder", options.working_folder.AbsolutePath().c_str()); + json_option_object.insert("arguments", json_arg_array); + json_option_object.insert("environment_variables", json_env_array); + json_option_object.insert("log_file", options.log_file.AbsolutePath().c_str()); + + json_options_array.append(json_option_object); + } + json_application_object.insert("options", json_options_array); + + json_applications_list_object.insert(application.executable_path.AbsolutePath().c_str(), json_application_object); } - // Save default configuration initizalized - settings.setValue("default_configuration_files", ConvertString(this->default_configuration_filenames)); + json_applications_object.insert("list", json_applications_list_object); - const bool result = SaveApplications(); - assert(result); + json_root_object.insert("applications", json_applications_object); - return true; -} + QJsonObject json_layers_object; -bool Environment::SaveApplications() const { - QJsonObject root; + json_root_object.insert("layers", json_layers_object); - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - // Build an array of appnames with associated data - QJsonObject application_object; - application_object.insert("app_name", applications[i].app_name.c_str()); - application_object.insert("app_path", applications[i].executable_path.c_str()); - application_object.insert("app_folder", applications[i].working_folder.c_str()); - application_object.insert("exclude_override", applications[i].layers_mode == LAYERS_MODE_BY_APPLICATIONS); - application_object.insert("log_file", applications[i].log_file.c_str()); - - // Ground work for mulitiple sets of command line arguments - QJsonArray argsArray; - argsArray.append(QJsonValue(applications[i].arguments.c_str())); - - application_object.insert("command_lines", argsArray); - root.insert(QFileInfo(applications[i].app_name.c_str()).fileName(), application_object); + QJsonObject json_configurations_object; + json_configurations_object.insert("use_per_application", this->use_per_application_configuration); + json_configurations_object.insert("configuration", this->global_configuration.GetName()); + json_configurations_object.insert("mode", ::GetToken(this->global_configuration.GetMode())); + + json_root_object.insert("configurations", json_configurations_object); + + QJsonObject json_preferences_object; + json_preferences_object.insert("use_system_tray", this->use_system_tray); + json_preferences_object.insert("VK_HOME", this->home_sdk_path.RelativePath().c_str()); + + QJsonArray json_hide_message_boxes_array; + for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { + LogType type = static_cast(i); + if (this->hide_message_boxes_flags & (1 << i)) { + json_hide_message_boxes_array.append(GetToken(type)); + } } + json_preferences_object.insert("hide_message_boxes", json_hide_message_boxes_array); - const std::string& app_list_json = GetPath(BUILTIN_PATH_APPLIST); - assert(QFileInfo(app_list_json.c_str()).absoluteDir().exists()); + json_root_object.insert("preferences", json_preferences_object); - QFile file(app_list_json.c_str()); - const bool result = file.open(QIODevice::WriteOnly | QIODevice::Text); - assert(result); - QJsonDocument doc(root); - file.write(doc.toJson()); + QJsonDocument json_doc(json_root_object); + file.write(json_doc.toJson()); file.close(); return true; @@ -399,23 +344,16 @@ bool Environment::SaveApplications() const { void Environment::SelectActiveApplication(std::size_t application_index) { assert(application_index < this->applications.size()); - - this->SetActiveApplication(this->applications[application_index].app_name); + this->active_executable_index = application_index; } int Environment::GetActiveApplicationIndex() const { - for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { - if (this->applications[i].app_name == this->active_application) { - return static_cast(i); - } - } - - return 0; // Not found, but the list is present, so return the first item. + return this->active_executable_index; // Not found, but the list is present, so return the first item. } bool Environment::HasOverriddenApplications() const { for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { - if (this->applications[i].layers_mode != LAYERS_MODE_BY_APPLICATIONS) { + if (this->applications[i].configuration.GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { return true; } } @@ -441,7 +379,9 @@ bool Environment::RemoveApplication(std::size_t application_index) { new_applications.reserve(this->applications.size() - 1); for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { - if (i == application_index) continue; + if (i == application_index) { + continue; + } new_applications.push_back(this->applications[i]); } @@ -449,16 +389,32 @@ bool Environment::RemoveApplication(std::size_t application_index) { return true; } +const ConfigurationInfo& Environment::GetActiveConfigurationInfo() const { + if (this->GetPerApplicationConfig()) { + return this->GetActiveApplication().configuration; + } else { + return this->global_configuration; + } +} + +ConfigurationInfo& Environment::GetActiveConfigurationInfo() { + if (this->GetPerApplicationConfig()) { + return this->GetActiveApplication().configuration; + } else { + return this->global_configuration; + } +} + const Application& Environment::GetActiveApplication() const { assert(!this->applications.empty()); - for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { - if (this->applications[i].app_name == this->active_application) { - return this->applications[i]; - } - } + return this->applications[this->active_executable_index]; // Not found, but the list is present, so return the first item. +} + +Application& Environment::GetActiveApplication() { + assert(!this->applications.empty()); - return this->applications[0]; // Not found, but the list is present, so return the first item. + return this->applications[this->active_executable_index]; // Not found, but the list is present, so return the first item. } const Application& Environment::GetApplication(std::size_t application_index) const { @@ -477,16 +433,6 @@ bool Environment::GetPerApplicationConfig() const { return this->use_per_applica void Environment::SetPerApplicationConfig(bool enable) { this->use_per_application_configuration = enable; } -bool Environment::GetUseApplicationList() const { - return this->use_application_list && this->layers_mode != LAYERS_MODE_BY_APPLICATIONS; -} - -void Environment::SetUseApplicationList(bool enable) { this->use_application_list = enable; } - -LayersMode Environment::GetMode() const { return this->layers_mode; } - -void Environment::SetMode(LayersMode mode) { this->layers_mode = mode; } - void Environment::Set(LayoutState state, const QByteArray& data) { assert(state >= LAYOUT_FIRST && state <= LAYOUT_LAST); this->layout_states[state] = data; @@ -497,20 +443,6 @@ const QByteArray& Environment::Get(LayoutState state) const { return this->layout_states[state]; } -bool Environment::IsDefaultConfigurationInit(const std::string& default_configuration_filename) const { - for (std::size_t i = 0, n = this->default_configuration_filenames.size(); i < n; ++i) { - if (this->default_configuration_filenames[i] == default_configuration_filename) { - return true; - } - } - - return false; -} - -void Environment::InitDefaultConfiguration(const std::string& configuration_filename) { - AppendString(this->default_configuration_filenames, configuration_filename); -} - /////////////////////////////////////////////////////////////////////////// /// This is only used on macOS to extract the executable from the bundle. /// You have to look at the plist.info file, you can't just assume whatever @@ -520,8 +452,8 @@ void Environment::InitDefaultConfiguration(const std::string& configuration_file /// Note, not ALL macOS executables are in a bundle, so if a non-bundled /// executable is fed in here, it will silently just return without /// modifying the path (which will be the correct behavior) -bool ExactExecutableFromAppBundle(std::string& app_path) { - std::string path = app_path; +bool ExactExecutableFromAppBundle(Path& app_path) { + std::string path = app_path.AbsolutePath(); path += "/Contents/"; std::string list_file = path + "Info.plist"; QFile file(list_file.c_str()); @@ -556,7 +488,7 @@ bool ExactExecutableFromAppBundle(std::string& app_path) { path += cExeName; // Return original if not found, but root if found - app_path = path; + app_path = Path(path); delete[] cExeName; break; @@ -568,75 +500,82 @@ bool ExactExecutableFromAppBundle(std::string& app_path) { return true; } -std::string Environment::GetDefaultExecutablePath(const std::string& executable_name) const { +DefaultPath Environment::GetDefaultExecutablePath(const std::string& executable_name) const { static const char* DEFAULT_PATH = VKC_PLATFORM == VKC_PLATFORM_MACOS ? "/../.." : ""; + DefaultPath default_path{"." + executable_name, "."}; + // Using VULKAN_SDK environement variable - const std::string env("${VULKAN_SDK}"); - if (!env.empty()) { - static const char* TABLE[] = { - "/Bin", // ENVIRONMENT_WIN32 - "/bin", // ENVIRONMENT_UNIX - }; - static_assert(countof(TABLE) == ENVIRONMENT_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - const std::string search_path = env + TABLE[VKC_ENV] + DEFAULT_PATH + executable_name.c_str(); - const QFileInfo file_info(ReplaceBuiltInVariable(search_path).c_str()); - if (file_info.exists()) { - return search_path; + const Path env = ::Get(Path::SDK_BIN); + if (!env.Empty()) { + const Path search_path(env + DEFAULT_PATH + executable_name.c_str()); + if (search_path.Exists()) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; } } - // Such the default applications from package installation (Linux) + // Search the default applications from package installation (Linux) if (VKC_PLATFORM == VKC_PLATFORM_LINUX) { - const std::string search_path = std::string("/usr/bin") + DEFAULT_PATH + executable_name.c_str(); - const QFileInfo file_info(ReplaceBuiltInVariable(search_path).c_str()); - if (file_info.exists()) { - return search_path; + const Path search_path(std::string("/usr/bin") + DEFAULT_PATH + executable_name); + if (search_path.Exists()) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; } } else if (VKC_PLATFORM == VKC_PLATFORM_MACOS) { - const std::string search_path = std::string("/Applications") + executable_name.c_str(); - std::string replaced_string = ReplaceBuiltInVariable(search_path); - const QFileInfo file_info(search_path.c_str()); - if (file_info.exists() && ExactExecutableFromAppBundle(replaced_string)) { - return replaced_string; + Path search_path(std::string("/Applications") + executable_name); + if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; } } // Using relative path to vkconfig in case SDK is not "installed" if (VKC_PLATFORM == VKC_PLATFORM_MACOS) { - const std::string search_path = std::string("..") + DEFAULT_PATH + executable_name.c_str(); - std::string replaced_string = ReplaceBuiltInVariable(search_path); - const QFileInfo file_info(replaced_string.c_str()); - if (file_info.exists() && ExactExecutableFromAppBundle(replaced_string)) { - return replaced_string; + Path search_path(std::string("..") + DEFAULT_PATH + executable_name); + if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; } } else { - const std::string search_path = std::string(".") + DEFAULT_PATH + executable_name.c_str(); - const QFileInfo file_info(ReplaceBuiltInVariable(search_path).c_str()); - if (file_info.exists()) { - return search_path; + Path search_path(std::string(".") + DEFAULT_PATH + executable_name); + if (search_path.Exists()) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; } } - return "./" + executable_name; + return default_path; } -static const DefaultApplication defaults_applications[] = {{"vkcube", ConvertNativeSeparators("/vkcube"), "--suppress_popups"}, - {"vkcubepp", ConvertNativeSeparators("/vkcubepp"), "--suppress_popups"}}; +static const DefaultApplication defaults_applications[] = {{"vkcube", "/vkcube", "--suppress_popups"}, + {"vkcubepp", "/vkcubepp", "--suppress_popups"}}; Application Environment::CreateDefaultApplication(const DefaultApplication& default_application) const { - const std::string executable_path = GetDefaultExecutablePath((default_application.key + GetApplicationSuffix()).c_str()); - if (executable_path.empty()) Application(); // application could not be found.. - - Application application(default_application.name, executable_path, default_application.arguments); + const DefaultPath& default_paths = GetDefaultExecutablePath((default_application.key + GetApplicationSuffix()).c_str()); + if (default_paths.executable_path.Empty()) { + Application(); // application could not be found.. + } + ApplicationOptions options; + options.label = "Default"; + options.working_folder = default_paths.working_folder; // On all operating systems, but Windows we keep running into problems with this ending up // somewhere the user isn't allowed to create and write files. For consistncy sake, the log // initially will be set to the users home folder across all OS's. This is highly visible // in the application launcher and should not present a usability issue. The developer can // easily change this later to anywhere they like. - application.log_file = std::string("${VK_LOCAL}") + default_application.key + ".txt"; + options.log_file = std::string("${VK_LOCAL}") + default_application.key + ".txt"; + + Application application; + application.executable_path = Path(default_paths.executable_path.AbsolutePath(), true); + application.options.push_back(options); + application.active_option_index = 0; return application; } @@ -644,10 +583,12 @@ Application Environment::CreateDefaultApplication(const DefaultApplication& defa std::vector Environment::CreateDefaultApplications() const { std::vector new_applications; - for (std::size_t name_index = 0, name_count = countof(defaults_applications); name_index < name_count; ++name_index) { + for (std::size_t name_index = 0, name_count = std::size(defaults_applications); name_index < name_count; ++name_index) { const Application& application = CreateDefaultApplication(defaults_applications[name_index]); - if (application.executable_path.empty()) continue; + if (application.executable_path.Empty()) { + continue; + } new_applications.push_back(application); } @@ -662,8 +603,10 @@ std::vector Environment::RemoveMissingApplications(const std::vecto for (std::size_t i = 0, n = applications.size(); i < n; ++i) { const Application& application = applications[i]; - const QFileInfo file_info(application.executable_path.c_str()); - if (!file_info.exists()) continue; + const QFileInfo file_info(application.executable_path.AbsolutePath().c_str()); + if (!file_info.exists()) { + continue; + } valid_applications.push_back(application); } @@ -675,7 +618,7 @@ std::vector Environment::UpdateDefaultApplications(const std::vecto std::vector search_applications; std::vector updated_applications = applications; - for (std::size_t default_index = 0, default_count = countof(defaults_applications); default_index < default_count; + for (std::size_t default_index = 0, default_count = std::size(defaults_applications); default_index < default_count; ++default_index) { const std::string defaults_name = defaults_applications[default_index].key + GetApplicationSuffix(); @@ -686,7 +629,7 @@ std::vector Environment::UpdateDefaultApplications(const std::vecto application_index < application_count; ++application_index) { const Application& application = search_applications[application_index]; - if (QString(application.executable_path.c_str()).endsWith(defaults_name.c_str())) { + if (QString(application.executable_path.AbsolutePath().c_str()).endsWith(defaults_name.c_str())) { updated_applications.push_back(CreateDefaultApplication(defaults_applications[default_index])); } else { updated_applications.push_back(application); diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index 44101fe310..e5856060d9 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -21,9 +21,9 @@ #pragma once #include "version.h" -#include "environment_key.h" #include "application.h" -#include "path_manager.h" +#include "type_tab.h" +#include "type_log.h" #include @@ -53,98 +53,22 @@ enum LayoutState { enum { LAYOUT_COUNT = LAYOUT_LAST - LAYOUT_FIRST + 1 }; -enum UserDefinedLayersPaths { - USER_DEFINED_LAYERS_PATHS_ENV_SET = 0, // VK_LAYER_PATH - USER_DEFINED_LAYERS_PATHS_ENV_ADD, // VK_ADD_LAYER_PATH - USER_DEFINED_LAYERS_PATHS_GUI, - - USER_DEFINED_LAYERS_PATHS_FIRST = USER_DEFINED_LAYERS_PATHS_ENV_SET, - USER_DEFINED_LAYERS_PATHS_LAST = USER_DEFINED_LAYERS_PATHS_GUI, -}; - -enum { USER_DEFINED_LAYERS_PATHS_COUNT = USER_DEFINED_LAYERS_PATHS_LAST - USER_DEFINED_LAYERS_PATHS_FIRST + 1 }; - -enum LoaderMessageType { - LOADER_MESSAGE_NONE = 0, - LOADER_MESSAGE_ERROR, - LOADER_MESSAGE_WARN, - LOADER_MESSAGE_INFO, - LOADER_MESSAGE_DEBUG, - LOADER_MESSAGE_LAYER, - LOADER_MESSAGE_IMPLEMENTATION, - LOADER_MESSAGE_ALL, - - LOADER_MESSAGE_FIRST = LOADER_MESSAGE_ERROR, - LOADER_MESSAGE_LAST = LOADER_MESSAGE_IMPLEMENTATION, -}; - -enum { LOADER_MESSAGE_COUNT = LOADER_MESSAGE_LAST - LOADER_MESSAGE_FIRST + 1 }; - -enum { - LOADER_MESSAGE_ERROR_BIT = (1 << LOADER_MESSAGE_ERROR), - LOADER_MESSAGE_WARN_BIT = (1 << LOADER_MESSAGE_WARN), - LOADER_MESSAGE_INFO_BIT = (1 << LOADER_MESSAGE_INFO), - LOADER_MESSAGE_DEBUG_BIT = (1 << LOADER_MESSAGE_DEBUG), - LOADER_MESSAGE_LAYER_BIT = (1 << LOADER_MESSAGE_LAYER), - LOADER_MESSAGE_IMPLEMENTATION_BIT = (1 << LOADER_MESSAGE_IMPLEMENTATION), - LOADER_MESSAGE_ALL_BIT = LOADER_MESSAGE_ERROR_BIT | LOADER_MESSAGE_WARN_BIT | LOADER_MESSAGE_INFO_BIT | - LOADER_MESSAGE_DEBUG_BIT | LOADER_MESSAGE_LAYER_BIT | LOADER_MESSAGE_IMPLEMENTATION_BIT -}; - -inline int GetLoaderMessageFlags(LoaderMessageType level) { - int flags = 0; - - switch (level) { - default: - case LOADER_MESSAGE_ALL: - case LOADER_MESSAGE_IMPLEMENTATION: - flags |= LOADER_MESSAGE_IMPLEMENTATION_BIT; - case LOADER_MESSAGE_LAYER: - flags |= LOADER_MESSAGE_LAYER_BIT; - case LOADER_MESSAGE_DEBUG: - flags |= LOADER_MESSAGE_DEBUG_BIT; - case LOADER_MESSAGE_INFO: - flags |= LOADER_MESSAGE_INFO_BIT; - case LOADER_MESSAGE_WARN: - flags |= LOADER_MESSAGE_WARN_BIT; - case LOADER_MESSAGE_ERROR: - flags |= LOADER_MESSAGE_ERROR_BIT; - case LOADER_MESSAGE_NONE: - flags |= 0; - } - - return flags; -} - -inline LoaderMessageType GetLoaderMessageType(int flags) { - if (flags == LOADER_MESSAGE_ALL_BIT) { - return LOADER_MESSAGE_ALL; - } else if (flags & LOADER_MESSAGE_IMPLEMENTATION_BIT) { - return LOADER_MESSAGE_IMPLEMENTATION; - } else if (flags & LOADER_MESSAGE_LAYER_BIT) { - return LOADER_MESSAGE_LAYER; - } else if (flags & LOADER_MESSAGE_DEBUG_BIT) { - return LOADER_MESSAGE_DEBUG; - } else if (flags & LOADER_MESSAGE_INFO_BIT) { - return LOADER_MESSAGE_INFO; - } else if (flags & LOADER_MESSAGE_WARN_BIT) { - return LOADER_MESSAGE_WARN; - } else if (flags & LOADER_MESSAGE_ERROR_BIT) { - return LOADER_MESSAGE_ERROR; - } else { - return LOADER_MESSAGE_NONE; - } -} - struct DefaultApplication { std::string name; std::string key; std::string arguments; }; +struct DefaultPath { + Path executable_path; + Path working_folder; +}; + class Environment { public: - Environment(PathManager& paths, const Version& api_version = Version::VKHEADER); + enum Mode { MODE_AUTO_LOAD_SAVE = 0, MODE_UNINITIALIZED }; + + Environment(Mode mode = MODE_AUTO_LOAD_SAVE); ~Environment(); enum ResetMode { DEFAULT = 0, CLEAR, SYSTEM }; @@ -152,9 +76,7 @@ class Environment { void Reset(ResetMode mode); bool Load(); - bool LoadApplications(); bool Save() const; - bool SaveApplications() const; void SelectActiveApplication(std::size_t application_index); int GetActiveApplicationIndex() const; @@ -162,91 +84,61 @@ class Environment { bool AppendApplication(const Application& application); bool RemoveApplication(std::size_t application_index); - void SetActiveApplication(const std::string& name) { this->active_application = name; } + const ConfigurationInfo& GetActiveConfigurationInfo() const; + ConfigurationInfo& GetActiveConfigurationInfo(); + const std::vector& GetApplications() const { return applications; } const Application& GetActiveApplication() const; + Application& GetActiveApplication(); const Application& GetApplication(std::size_t application_index) const; Application& GetApplication(std::size_t application_index); - const std::string& GetSelectedConfiguration() const { return this->selected_configuration; } - void SetSelectedConfiguration(const std::string& name) { this->selected_configuration = name; } - const QByteArray& Get(LayoutState state) const; void Set(LayoutState state, const QByteArray& data); bool GetPerApplicationConfig() const; void SetPerApplicationConfig(bool enable); - bool GetUseApplicationList() const; - void SetUseApplicationList(bool enable); - bool GetUseSystemTray() const { return this->use_system_tray; } void SetUseSystemTray(bool enable) { this->use_system_tray = enable; } - LayersMode GetMode() const; - void SetMode(LayersMode mode); - - int GetLoaderMessageTypes() const { return this->loader_message_types; } - void SetLoaderMessageTypes(int types) { this->loader_message_types = types; } - - bool first_run; - const Version api_version; + LogFlags GetLoaderMessageFlags() const { return this->loader_message_types_flags; } + void SetLoaderMessageFlags(LogFlags flags) { this->loader_message_types_flags = flags; } - void SetPerConfigUserDefinedLayersPaths(const std::vector& paths) { - std::vector& custom_layer_paths_gui = user_defined_layers_paths[USER_DEFINED_LAYERS_PATHS_GUI]; - custom_layer_paths_gui.clear(); - for (std::size_t i = 0, n = paths.size(); i < n; ++i) { - custom_layer_paths_gui.push_back(ConvertNativeSeparators(paths[i]).c_str()); - } - } + // Search for all the applications in the list, an remove the application which executable can't be found + std::vector RemoveMissingApplications(const std::vector& applications) const; - const std::vector& GetUserDefinedLayersPaths(UserDefinedLayersPaths user_defined_layers_paths_id) const { - return user_defined_layers_paths[user_defined_layers_paths_id]; - } + bool has_crashed = false; + int hide_message_boxes_flags = 0; - bool IsDefaultConfigurationInit(const std::string& configuration_filename) const; - void InitDefaultConfiguration(const std::string& configuration_filename); + Path path_export; + Path path_import; - // Search for all the applications in the list, an remove the application which executable can't be found - std::vector RemoveMissingApplications(const std::vector& applications) const; + ConfigurationInfo global_configuration; private: Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; - Version vkconfig2_version; - Version vkconfig3_version; - LayersMode layers_mode; - bool use_application_list; - bool use_system_tray; - bool use_per_application_configuration; - int loader_message_types; + const Mode mode; + + TabType active_tab = TAB_DIAGNOSTIC; + bool use_system_tray = false; + bool use_per_application_configuration = false; + LogFlags loader_message_types_flags; + Path home_sdk_path; - std::string selected_configuration; - std::string active_application; + int active_executable_index; std::array layout_states; - std::array, USER_DEFINED_LAYERS_PATHS_COUNT> user_defined_layers_paths; std::vector applications; - PathManager& paths_manager; - - std::vector default_configuration_filenames; - // Update default applications path to use relative path (really useful only on Windows) std::vector UpdateDefaultApplications(const std::vector& applications) const; // Create a list of default applications, eg vkcube std::vector CreateDefaultApplications() const; Application CreateDefaultApplication(const DefaultApplication& default_application) const; - std::string GetDefaultExecutablePath(const std::string& executable_name) const; - - public: - const PathManager& paths; + DefaultPath GetDefaultExecutablePath(const std::string& executable_name) const; }; -bool ExactExecutableFromAppBundle(std::string& path); - -LoaderMessageType GetLoaderMessageType(const std::string& value); -int GetLoaderMessageTypes(const std::string& values); -std::string GetLoaderMessageToken(LoaderMessageType mesage_type); -std::string GetLoaderMessageTokens(int mesage_types); +bool ExactExecutableFromAppBundle(Path& path); diff --git a/vkconfig_core/environment_key.h b/vkconfig_core/environment_key.h deleted file mode 100644 index ab5f7a1cd3..0000000000 --- a/vkconfig_core/environment_key.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2024-2024 Valve Corporation - * Copyright (c) 2024-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -// Saved settings for the application -#define VKCONFIG_KEY_STATE_PER_APPLICATION "STATE_PerApplication" -#define VKCONFIG_KEY_STATE_APPLICATION_LIST "STATE_Applicationlist" -#define VKCONFIG_KEY_STATE_SYSTEM_TRAY "STATE_SystemTray" - -#define VKCONFIG_KEY_MESSAGE_SYSTEM_TRAY "MESSAGE_SystemTray" -#define VKCONFIG_KEY_MESSAGE_NEED_APPLICATION_RESTART "MESSAGE_NeedApplicationRestart" - -#define VKCONFIG_KEY_INITIALIZE_FILES "FirstTimeRun" -#define VKCONFIG_KEY_LAYERS_MODE "LayersMode" -#define VKCONFIG_KEY_LOADER_MESSAGE "LoaderMessage" - -#define VKCONFIG_KEY_ACTIVE_CONFIGURATION "ActiveConfiguration" -#define VKCONFIG_KEY_ACTIVE_APPLICATION "ActiveApplication" - -#define VKCONFIG_KEY_VKCONFIG_VERSION "vkConfigVersion" -#define VKCONFIG_KEY_VKCONFIG3_VERSION "vkConfig3Version" -#define VKCONFIG_KEY_CUSTOM_PATHS "customPaths" diff --git a/vkconfig_core/header.cpp b/vkconfig_core/header.cpp index 8aa22be48b..014371fa78 100644 --- a/vkconfig_core/header.cpp +++ b/vkconfig_core/header.cpp @@ -45,7 +45,7 @@ const char* GetToken(SettingView state) { "ADVANCED", // SETTING_VIEW_ADVANCED "HIDDEN", // SETTING_VIEW_HIDDEN }; - static_assert(countof(table) == SETTING_VIEW_COUNT, "The tranlation table size doesn't match the enum number of elements"); + static_assert(std::size(table) == SETTING_VIEW_COUNT, "The tranlation table size doesn't match the enum number of elements"); return table[state]; } diff --git a/vkconfig_core/header.h b/vkconfig_core/header.h index 1a23636187..38fcec5160 100644 --- a/vkconfig_core/header.h +++ b/vkconfig_core/header.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,8 @@ #pragma once -#include "platform.h" +#include "type_platform.h" +#include "type_status.h" #include "json.h" #include diff --git a/vkconfig_core/help.cpp b/vkconfig_core/help.cpp index cbeddea984..41933a8925 100644 --- a/vkconfig_core/help.cpp +++ b/vkconfig_core/help.cpp @@ -20,7 +20,7 @@ #include "help.h" #include "util.h" -#include "platform.h" +#include "type_platform.h" #include diff --git a/vkconfig_core/json.h b/vkconfig_core/json.h index 383a2240f2..822cb8e6dd 100644 --- a/vkconfig_core/json.h +++ b/vkconfig_core/json.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vkconfig_core/json_validator.cpp b/vkconfig_core/json_validator.cpp index 95c9fd5eec..fc16d67cca 100644 --- a/vkconfig_core/json_validator.cpp +++ b/vkconfig_core/json_validator.cpp @@ -49,7 +49,7 @@ bool JsonValidator::Check(const QString &json_data) { assert(!json_data.isEmpty()); if (!schema) { - const QJsonDocument schema_document = ParseJsonFile(":/layers/schema.json"); + const QJsonDocument schema_document = ParseJsonFile(":/vkconfig/schema.json"); schema.reset(new Schema); diff --git a/vkconfig_core/json_validator.h b/vkconfig_core/json_validator.h index c354bc8770..70f8a09538 100644 --- a/vkconfig_core/json_validator.h +++ b/vkconfig_core/json_validator.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vkconfig_core/layer.cpp b/vkconfig_core/layer.cpp index 4d08c04343..f0790aaaf2 100644 --- a/vkconfig_core/layer.cpp +++ b/vkconfig_core/layer.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2022 Valve Corporation - * Copyright (c) 2020-2022 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ #include "setting_int.h" #include "setting_list.h" #include "setting_string.h" -#include "platform.h" +#include "type_platform.h" #include "util.h" #include "path.h" #include "json.h" @@ -47,42 +47,13 @@ #include #include -static std::string GetBuiltinFolder(const Version& version) { - QDir dir(":/layers"); - dir.setFilter(QDir::Dirs); - QFileInfoList list = dir.entryInfoList(); - - std::vector version_supported; - - for (int i = 0, n = list.size(); i < n; ++i) { - const std::string value = list[i].baseName().toStdString(); - if (!IsNumber(value)) continue; - version_supported.push_back(std::atoi(value.c_str())); - } - - std::sort(version_supported.begin(), version_supported.end()); - - const int searched_version = version.GetPatch(); - - for (int i = static_cast(version_supported.size()) - 1; i >= 0; --i) { - const int current_version = version_supported[i]; - - if (searched_version < current_version) continue; - - return format(":/layers/%d", current_version); - } - - return ":/layers/170"; -} - const char* Layer::NO_PRESET = "User-Defined Settings"; -Layer::Layer() : status(STATUS_STABLE), platforms(PLATFORM_DESKTOP_BIT), type(LAYER_TYPE_EXPLICIT) {} +Layer::Layer() : status(STATUS_STABLE), platforms(PLATFORM_DESKTOP_BIT) {} -Layer::Layer(const std::string& key, const LayerType layer_type) - : key(key), status(STATUS_STABLE), platforms(PLATFORM_DESKTOP_BIT), type(layer_type) {} +Layer::Layer(const std::string& key) : key(key), status(STATUS_STABLE), platforms(PLATFORM_DESKTOP_BIT) {} -Layer::Layer(const std::string& key, const LayerType layer_type, const Version& file_format_version, const Version& api_version, +Layer::Layer(const std::string& key, const Version& file_format_version, const Version& api_version, const std::string& implementation_version, const std::string& library_path) : key(key), file_format_version(file_format_version), @@ -90,12 +61,11 @@ Layer::Layer(const std::string& key, const LayerType layer_type, const Version& api_version(api_version), implementation_version(implementation_version), status(STATUS_STABLE), - platforms(PLATFORM_DESKTOP_BIT), - type(layer_type) {} + platforms(PLATFORM_DESKTOP_BIT) {} // Todo: Load the layer with Vulkan API bool Layer::IsValid() const { - return file_format_version != Version::VERSION_NULL && !key.empty() && !binary_path.empty() && + return file_format_version != Version::VERSION_NULL && !key.empty() && !binary_path.Empty() && api_version != Version::VERSION_NULL && !implementation_version.empty(); } @@ -164,181 +134,14 @@ SettingMeta* Layer::Instantiate(SettingMetaSet& meta_set, const std::string& key return setting_meta; } -bool Layer::Load(const std::vector& available_layers, const std::string& full_path_to_file, LayerType layer_type) { - this->type = layer_type; // Set layer type, no way to know this from the json file - - if (full_path_to_file.empty()) return false; - - QFile file(full_path_to_file.c_str()); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return false; - } - - QString json_text = file.readAll(); - file.close(); - - this->manifest_path = full_path_to_file; - - // Convert the text to a JSON document & validate it. - // It does need to be a valid json formatted file. - QJsonParseError json_parse_error; - const QJsonDocument& json_document = QJsonDocument::fromJson(json_text.toUtf8(), &json_parse_error); - if (json_parse_error.error != QJsonParseError::NoError) { - return false; - } - - // Make sure it's not empty - if (json_document.isNull() || json_document.isEmpty()) { - return false; - } - - // First check it's a layer manifest, ignore otherwise. - const QJsonObject& json_root_object = json_document.object(); - if (json_root_object.value("file_format_version") == QJsonValue::Undefined) { - return false; // Not a layer JSON file - } - if (json_root_object.value("layer") == QJsonValue::Undefined) { - return false; // Not a layer JSON file - } - - this->file_format_version = ReadVersionValue(json_root_object, "file_format_version"); - if (this->file_format_version.GetMajor() > 1) { - Alert::LayerInvalid(full_path_to_file.c_str(), - format("Unsupported layer file format: %s", this->file_format_version.str().c_str()).c_str()); - return false; - } - - const QJsonObject& json_layer_object = ReadObject(json_root_object, "layer"); - - std::string current_last_modified = QFileInfo(full_path_to_file.c_str()).lastModified().toString(Qt::ISODate).toStdString(); - - QSettings settings; - std::string cached_last_modified = settings.value(full_path_to_file.c_str()).toString().toStdString(); - - this->key = ReadStringValue(json_layer_object, "name"); +bool Layer::Load(const Path& full_path_to_file, LayerType type) { + this->type = type; // Set layer type, no way to know this from the json file - if (this->key == "VK_LAYER_LUNARG_override") { + if (full_path_to_file.Empty()) { return false; } - // Check if a layer with the same name is already in the list - if (FindByKey(available_layers, this->key.c_str()) != nullptr) { - return false; - } - - this->api_version = ReadVersionValue(json_layer_object, "api_version"); - - const bool is_builtin_layer_file = - full_path_to_file.rfind(":/") == 0; // Check whether the path start with ":/" for resource file paths. - - JsonValidator validator; - - const bool should_validate = current_last_modified != cached_last_modified; - const bool is_valid = should_validate ? validator.Check(json_text) : true; - - if (should_validate && is_valid) { - settings.setValue(full_path_to_file.c_str(), current_last_modified.c_str()); - } - - const QJsonValue& json_library_path_value = json_layer_object.value("library_path"); - if (json_library_path_value != QJsonValue::Undefined) { - this->binary_path = json_library_path_value.toString().toStdString(); - } - - this->implementation_version = ReadStringValue(json_layer_object, "implementation_version"); - if (json_layer_object.value("status") != QJsonValue::Undefined) { - this->status = GetStatusType(ReadStringValue(json_layer_object, "status").c_str()); - } - if (json_layer_object.value("platforms") != QJsonValue::Undefined) { - this->platforms = GetPlatformFlags(ReadStringArray(json_layer_object, "platforms")); - } - this->description = ReadStringValue(json_layer_object, "description"); - if (json_layer_object.value("introduction") != QJsonValue::Undefined) { - this->introduction = ReadStringValue(json_layer_object, "introduction"); - } - if (json_layer_object.value("url") != QJsonValue::Undefined) { - this->url = ReadStringValue(json_layer_object, "url"); - } - - if (json_layer_object.value("disable_environment") != QJsonValue::Undefined) { - const QJsonObject& json_env_object = json_layer_object.value("disable_environment").toObject(); - const QStringList keys = json_env_object.keys(); - this->disable_env = keys[0].toStdString(); - this->disable_value = ReadStringValue(json_env_object, this->disable_env.c_str()) == "1"; - } - if (json_layer_object.value("enable_environment") != QJsonValue::Undefined) { - const QJsonObject& json_env_object = json_layer_object.value("enable_environment").toObject(); - const QStringList keys = json_env_object.keys(); - this->enable_env = keys[0].toStdString(); - this->enable_value = ReadStringValue(json_env_object, this->enable_env.c_str()) == "1"; - } - - if (!is_valid && this->key != "VK_LAYER_LUNARG_override") { - if (!is_builtin_layer_file || (is_builtin_layer_file && this->api_version >= Version(1, 2, 170))) { - Alert::LayerInvalid(full_path_to_file.c_str(), validator.message.toStdString().c_str()); - return false; - } - } - - const QJsonValue& json_features_value = json_layer_object.value("features"); - if (json_features_value != QJsonValue::Undefined) { - const QJsonObject& json_features_object = json_features_value.toObject(); - - // Load layer settings - const QJsonValue& json_settings_value = json_features_object.value("settings"); - if (json_settings_value != QJsonValue::Undefined) { - AddSettingsSet(this->settings, nullptr, json_settings_value); - } - - // Load layer presets - const QJsonValue& json_presets_value = json_features_object.value("presets"); - if (json_presets_value != QJsonValue::Undefined) { - assert(json_presets_value.isArray()); - const QJsonArray& json_preset_array = json_presets_value.toArray(); - for (int preset_index = 0, preset_count = json_preset_array.size(); preset_index < preset_count; ++preset_index) { - const QJsonObject& json_preset_object = json_preset_array[preset_index].toObject(); - - LayerPreset preset; - preset.platform_flags = this->platforms; - preset.status = this->status; - LoadMetaHeader(preset, json_preset_object); - - const QJsonArray& json_setting_array = ReadArray(json_preset_object, "settings"); - for (int setting_index = 0, setting_count = json_setting_array.size(); setting_index < setting_count; - ++setting_index) { - AddSettingData((SettingDataSet&)preset.settings, json_setting_array[setting_index]); - } - - this->presets.push_back(preset); - } - } - } - - // Override old built-in layer settings - if (!is_builtin_layer_file && this->api_version <= Version(1, 2, 176)) { - const std::string path = GetBuiltinFolder(this->api_version) + "/" + this->key + ".json"; - - Layer default_layer; - if (default_layer.Load(available_layers, path, this->type)) { - this->introduction = default_layer.introduction; - this->url = default_layer.url; - this->platforms = default_layer.platforms; - this->status = default_layer.status; - std::swap(this->settings, default_layer.settings); - std::swap(this->presets, default_layer.presets); - this->memory = default_layer.memory; - } - } - - return this->IsValid(); // Not all JSON file are layer JSON valid -} - -bool Layer::Load(const std::string& full_path_to_file, LayerType layer_type) { - this->type = layer_type; // Set layer type, no way to know this from the json file - - if (full_path_to_file.empty()) return false; - - QFile file(full_path_to_file.c_str()); + QFile file(full_path_to_file.AbsolutePath().c_str()); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } @@ -372,17 +175,17 @@ bool Layer::Load(const std::string& full_path_to_file, LayerType layer_type) { this->file_format_version = ReadVersionValue(json_root_object, "file_format_version"); if (this->file_format_version.GetMajor() > 1) { - Alert::LayerInvalid(full_path_to_file.c_str(), - format("Unsupported layer file format: %s", this->file_format_version.str().c_str()).c_str()); + const std::string message = format("Unsupported layer file format: %s", this->file_format_version.str().c_str()); + Alert::LayerInvalid(full_path_to_file, message.c_str()); return false; } const QJsonObject& json_layer_object = ReadObject(json_root_object, "layer"); - std::string current_last_modified = QFileInfo(full_path_to_file.c_str()).lastModified().toString(Qt::ISODate).toStdString(); + std::string current_last_modified = full_path_to_file.LastModified(); QSettings settings; - std::string cached_last_modified = settings.value(full_path_to_file.c_str()).toString().toStdString(); + std::string cached_last_modified = settings.value(full_path_to_file.AbsolutePath().c_str()).toString().toStdString(); this->key = ReadStringValue(json_layer_object, "name"); @@ -392,16 +195,13 @@ bool Layer::Load(const std::string& full_path_to_file, LayerType layer_type) { this->api_version = ReadVersionValue(json_layer_object, "api_version"); - const bool is_builtin_layer_file = - full_path_to_file.rfind(":/") == 0; // Check whether the path start with ":/" for resource file paths. - JsonValidator validator; const bool should_validate = current_last_modified != cached_last_modified; const bool is_valid = should_validate ? validator.Check(json_text) : true; if (should_validate && is_valid) { - settings.setValue(full_path_to_file.c_str(), current_last_modified.c_str()); + settings.setValue(full_path_to_file.AbsolutePath().c_str(), current_last_modified.c_str()); } const QJsonValue& json_library_path_value = json_layer_object.value("library_path"); @@ -437,11 +237,9 @@ bool Layer::Load(const std::string& full_path_to_file, LayerType layer_type) { this->enable_value = ReadStringValue(json_env_object, this->enable_env.c_str()) == "1"; } - if (!is_valid && this->key != "VK_LAYER_LUNARG_override") { - if (!is_builtin_layer_file || (is_builtin_layer_file && this->api_version >= Version(1, 2, 170))) { - Alert::LayerInvalid(full_path_to_file.c_str(), validator.message.toStdString().c_str()); - return false; - } + if (!is_valid) { + Alert::LayerInvalid(full_path_to_file, validator.message.toStdString().c_str()); + return false; } const QJsonValue& json_features_value = json_layer_object.value("features"); @@ -478,22 +276,6 @@ bool Layer::Load(const std::string& full_path_to_file, LayerType layer_type) { } } - // Override old built-in layer settings - if (!is_builtin_layer_file && this->api_version <= Version(1, 2, 176)) { - const std::string path = GetBuiltinFolder(this->api_version) + "/" + this->key + ".json"; - - Layer default_layer; - if (default_layer.Load(path, this->type)) { - this->introduction = default_layer.introduction; - this->url = default_layer.url; - this->platforms = default_layer.platforms; - this->status = default_layer.status; - std::swap(this->settings, default_layer.settings); - std::swap(this->presets, default_layer.presets); - this->memory = default_layer.memory; - } - } - return this->IsValid(); // Not all JSON file are layer JSON valid } @@ -539,7 +321,7 @@ void Layer::AddSettingsSet(SettingMetaSet& settings, const SettingMeta* parent, if (setting_meta->type == SETTING_LOAD_FILE) { const SettingMetaFileLoad& setting_file = static_cast(*setting_meta); if (setting_file.format == "PROFILE") { - const std::string& value = ReplaceBuiltInVariable(setting_file.default_value); + const std::string& value = setting_file.default_value.AbsolutePath(); const QJsonDocument& doc = ParseJsonFile(value.c_str()); if (!doc.isNull() && !doc.isEmpty()) { diff --git a/vkconfig_core/layer.h b/vkconfig_core/layer.h index dad1e5b6d8..9d049dbb75 100644 --- a/vkconfig_core/layer.h +++ b/vkconfig_core/layer.h @@ -23,8 +23,9 @@ #include "setting.h" #include "layer_preset.h" -#include "layer_type.h" #include "version.h" +#include "path.h" +#include "type_layer_type.h" #include #include @@ -38,8 +39,8 @@ class Layer { static const char* NO_PRESET; Layer(); - Layer(const std::string& key, const LayerType layer_type); - Layer(const std::string& key, const LayerType layer_type, const Version& file_format_version, const Version& api_version, + Layer(const std::string& key); + Layer(const std::string& key, const Version& file_format_version, const Version& api_version, const std::string& implementation_version, const std::string& library_path); bool IsValid() const; @@ -55,7 +56,7 @@ class Layer { public: std::string key; Version file_format_version; - std::string binary_path; + Path binary_path; Version api_version; std::string implementation_version; StatusType status; @@ -63,8 +64,8 @@ class Layer { std::string introduction; std::string url; int platforms; - std::string manifest_path; - LayerType type; + Path manifest_path; + LayerType type = LAYER_TYPE_EXPLICIT; QJsonDocument profile; std::string disable_env; std::string enable_env; @@ -74,9 +75,7 @@ class Layer { std::vector settings; std::vector presets; - bool Load(const std::vector& available_layers, const std::string& full_path_to_file, LayerType layer_type); - - bool Load(const std::string& full_path_to_file, LayerType layer_type); + bool Load(const Path& full_path_to_file, LayerType type = LAYER_TYPE_EXPLICIT); private: Layer& operator=(const Layer&) = delete; diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 3e53b4a8d9..80776777fa 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2022 Valve Corporation - * Copyright (c) 2020-2022 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,272 +20,167 @@ #include "layer_manager.h" #include "util.h" -#include "platform.h" +#include "type_platform.h" #include "registry.h" -#include -#include -#include - -/// Going back and forth between the Windows registry and looking for files -/// in specific folders is just a mess. This class consolidates all that into -/// one single abstraction that knows whether to look in the registry or in -/// a folder with QDir. -/// This is a little weird because generally QSettings is for going back -/// and forth between the Registry or .ini files. Here, I'm going from -/// the registry to directory entries. -class PathFinder { - private: - QStringList files; - - public: - PathFinder() {} - - // Constructor does all the work. Abstracts away instances where we might - // be searching a disk path, or a registry path. - // TBD, does this really need it's own file/module? - PathFinder(const std::string &path, bool force_file_system = (VKC_PLATFORM != VKC_PLATFORM_WINDOWS)) { - if (!force_file_system) { - QSettings settings(path.c_str(), QSettings::NativeFormat); - files = settings.allKeys(); - } else { - QDir dir(path.c_str()); - QFileInfoList file_info_list = dir.entryInfoList(QStringList() << "*.json", QDir::Files); - - for (int file_index = 0; file_index < file_info_list.size(); ++file_index) { - files << file_info_list[file_index].filePath(); - } - } +LayerType GetLayerType(LayersPaths Layers_paths_type) { + if (Layers_paths_type == LAYERS_PATHS_IMPLICIT) { + return LAYER_TYPE_IMPLICIT; + } else { + return LAYER_TYPE_EXPLICIT; } +} - int FileCount() const { return files.size(); } - std::string GetFileName(int i) const { return files[i].toStdString(); } -}; +std::vector GetImplicitLayerPaths() { + std::vector result; #if VKC_PLATFORM == VKC_PLATFORM_WINDOWS -static const char *SEARCH_PATHS[] = {"HKEY_LOCAL_MACHINE\\Software\\Khronos\\Vulkan\\ExplicitLayers", - "HKEY_LOCAL_MACHINE\\Software\\Khronos\\Vulkan\\ImplicitLayers", - "HKEY_CURRENT_USER\\Software\\Khronos\\Vulkan\\ExplicitLayers", - "HKEY_CURRENT_USER\\Software\\Khronos\\Vulkan\\ImplicitLayers", - "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Class\\...\\VulkanExplicitLayers", - "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Class\\...\\VulkanImplicitLayers"}; + static const char *REGISTRY_PATHS[] = { + "HKEY_LOCAL_MACHINE\\Software\\Khronos\\Vulkan\\ImplicitLayers", + "HKEY_CURRENT_USER\\Software\\Khronos\\Vulkan\\ImplicitLayers", + "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Class\\...\\VulkanImplicitLayers"}; + + for (std::size_t i = 0, n = std::size(REGISTRY_PATHS); i < n; ++i) { + const std::vector ®istry_paths = LoadRegistryLayers(REGISTRY_PATHS[i]); + result.insert(result.begin(), registry_paths.begin(), registry_paths.end()); + } #else -static const char *SEARCH_PATHS[] = { - "/usr/local/etc/vulkan/explicit_layer.d", // Not used on macOS, okay to just ignore - "/usr/local/etc/vulkan/implicit_layer.d", // Not used on macOS, okay to just ignore - "/usr/local/share/vulkan/explicit_layer.d", - "/usr/local/share/vulkan/implicit_layer.d", - "/etc/vulkan/explicit_layer.d", - "/etc/vulkan/implicit_layer.d", - "/usr/share/vulkan/explicit_layer.d", - "/usr/share/vulkan/implicit_layer.d", - ".local/share/vulkan/explicit_layer.d", - ".local/share/vulkan/implicit_layer.d", + static const char *LAYERS_PATHS[] = { + "/usr/local/etc/vulkan/implicit_layer.d", // Not used on macOS, okay to just ignore + "/usr/local/share/vulkan/implicit_layer.d", + "/etc/vulkan/implicit_layer.d", + "/usr/share/vulkan/implicit_layer.d", + ".local/share/vulkan/implicit_layer.d", #ifdef INSTALL_FULL_DATAROOTDIR - INSTALL_FULL_DATAROOTDIR "/vulkan/explicit_layer.d", - INSTALL_FULL_DATAROOTDIR "/vulkan/implicit_layer.d", + INSTALL_FULL_DATAROOTDIR "/vulkan/implicit_layer.d", #endif #ifdef INSTALL_FULL_SYSCONFDIR - INSTALL_FULL_SYSCONFDIR "/vulkan/explicit_layer.d", - INSTALL_FULL_SYSCONFDIR "/vulkan/implicit_layer.d", + INSTALL_FULL_SYSCONFDIR "/vulkan/implicit_layer.d", #endif -}; -#endif - -LayerManager::LayerManager(const Environment &environment) : environment(environment) { this->selected_layers.reserve(10); } + }; -void LayerManager::Clear() { this->selected_layers.clear(); } + for (std::size_t i = 0, n = std::size(LAYERS_PATHS); i < n; ++i) { + result.push_back(LAYERS_PATHS[i]); + } +#endif -bool LayerManager::Empty() const { return this->selected_layers.empty(); } + return result; +} -std::vector LayerManager::BuildPathList() const { - std::vector list; +std::vector GetExplicitLayerPaths() { + std::vector result; - // FIRST: If VK_LAYER_PATH is set it has precedence over other layers. - { - const std::vector &paths = environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_SET); - for (std::size_t i = 0, n = paths.size(); i < n; ++i) { - list.push_back(paths[i]); - } - } +#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS + static const char *REGISTRY_PATHS[] = { + "HKEY_LOCAL_MACHINE\\Software\\Khronos\\Vulkan\\ExplicitLayers", + "HKEY_CURRENT_USER\\Software\\Khronos\\Vulkan\\ExplicitLayers", + "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Class\\...\\VulkanExplicitLayers"}; - // SECOND: Any per layers configuration user-defined path from Vulkan Configurator? Search for those too - { - const std::vector &paths = environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_GUI); - for (std::size_t i = 0, n = paths.size(); i < n; ++i) { - list.push_back(paths[i]); - } + for (std::size_t i = 0, n = std::size(REGISTRY_PATHS); i < n; ++i) { + const std::vector ®istry_paths = LoadRegistryLayers(REGISTRY_PATHS[i]); + result.insert(result.begin(), registry_paths.begin(), registry_paths.end()); } +#else + static const char *LAYERS_PATHS[] = { + "/usr/local/etc/vulkan/explicit_layer.d", // Not used on macOS, okay to just ignore + "/usr/local/share/vulkan/explicit_layer.d", + "/etc/vulkan/explicit_layer.d", + "/usr/share/vulkan/explicit_layer.d", + ".local/share/vulkan/explicit_layer.d", +#ifdef INSTALL_FULL_DATAROOTDIR + INSTALL_FULL_DATAROOTDIR "/vulkan/explicit_layer.d", +#endif +#ifdef INSTALL_FULL_SYSCONFDIR + INSTALL_FULL_SYSCONFDIR "/vulkan/explicit_layer.d", +#endif + }; - // THIRD: Add VK_ADD_LAYER_PATH layers - { - const std::vector &paths = environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_ADD); - for (std::size_t i = 0, n = paths.size(); i < n; ++i) { - list.push_back(paths[i]); - } + for (std::size_t i = 0, n = std::size(LAYERS_PATHS); i < n; ++i) { + result.push_back(LAYERS_PATHS[i]); } +#endif - // FOURTH: Standard layer paths, in standard locations. The above has always taken precedence - { - for (std::size_t i = 0, n = countof(SEARCH_PATHS); i < n; i++) { - list.push_back(SEARCH_PATHS[i]); - } - } + return result; +} - // FIFTH: Standard layer paths, in standard locations. The above has always taken precedence - if (!qgetenv("VULKAN_SDK").isEmpty()) { - list.push_back(GetPath(BUILTIN_PATH_EXPLICIT_LAYERS)); - } +LayerManager::LayerManager(const std::vector &user_defined_paths) { + this->paths[LAYERS_PATHS_IMPLICIT] = GetImplicitLayerPaths(); - return list; -} + this->paths[LAYERS_PATHS_EXPLICIT] = GetExplicitLayerPaths(); -// Find all installed layers on the system. -void LayerManager::LoadAllInstalledLayers() { - this->selected_layers.clear(); + const char *SEPARATOR = GetToken(PARSE_ENV_VAR); - // FIRST: If VK_LAYER_PATH is set it has precedence over other layers. - const std::vector &env_user_defined_layers_paths_set = - environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_SET); - for (std::size_t i = 0, n = env_user_defined_layers_paths_set.size(); i < n; ++i) { - LoadLayersFromPath(env_user_defined_layers_paths_set[i]); + const std::vector &VK_LAYER_PATH = UniqueStrings(Split(qgetenv("VK_LAYER_PATH").toStdString(), SEPARATOR)); + for (std::size_t i = 0, n = VK_LAYER_PATH.size(); i < n; ++i) { + this->paths[LAYERS_PATHS_ENV_SET].push_back(VK_LAYER_PATH[i]); } - // SECOND: Any per layers configuration user-defined path from Vulkan Configurator? Search for those too - const std::vector &gui_config_user_defined_layers_paths = - environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_GUI); - for (std::size_t i = 0, n = gui_config_user_defined_layers_paths.size(); i < n; ++i) { - LoadLayersFromPath(gui_config_user_defined_layers_paths[i]); + const std::vector &VK_ADD_LAYER_PATH = UniqueStrings(Split(qgetenv("VK_ADD_LAYER_PATH").toStdString(), SEPARATOR)); + for (std::size_t i = 0, n = VK_ADD_LAYER_PATH.size(); i < n; ++i) { + this->paths[LAYERS_PATHS_ENV_SET].push_back(VK_ADD_LAYER_PATH[i]); } - // THIRD: Add VK_ADD_LAYER_PATH layers - const std::vector &env_user_defined_layers_paths_add = - environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_ADD); - for (std::size_t i = 0, n = env_user_defined_layers_paths_add.size(); i < n; ++i) { - LoadLayersFromPath(env_user_defined_layers_paths_add[i]); - } + this->paths[LAYERS_PATHS_GUI].insert(this->paths[LAYERS_PATHS_GUI].begin(), user_defined_paths.begin(), + user_defined_paths.end()); - // FOURTH: Standard layer paths, in standard locations. The above has always taken precedence - for (std::size_t i = 0, n = countof(SEARCH_PATHS); i < n; i++) { - LoadLayersFromPath(SEARCH_PATHS[i]); - } + this->paths[LAYERS_PATHS_SDK].push_back(::Get(Path::SDK_BIN)); - // FIFTH: See if thee is anyting in the VULKAN_SDK path that wasn't already found elsewhere - if (!qgetenv("VULKAN_SDK").isEmpty()) { - LoadLayersFromPath(GetPath(BUILTIN_PATH_EXPLICIT_LAYERS)); - } + this->LoadAllInstalledLayers(); } -// Load a single layer -void LayerManager::LoadLayer(const std::string &layer_name) { - this->selected_layers.clear(); - - // FIRST: If VK_LAYER_PATH is set it has precedence over other layers. - const std::vector &env_user_defined_layers_paths_set = - environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_SET); - for (std::size_t i = 0, n = env_user_defined_layers_paths_set.size(); i < n; ++i) { - if (LoadLayerFromPath(layer_name, env_user_defined_layers_paths_set[i])) return; - } +void LayerManager::Clear() { this->selected_layers.clear(); } - // SECOND: Any per layers configuration user-defined path from Vulkan Configurator? Search for those too - const std::vector &gui_config_user_defined_layers_paths = - environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_GUI); - for (std::size_t i = 0, n = gui_config_user_defined_layers_paths.size(); i < n; ++i) { - if (LoadLayerFromPath(layer_name, gui_config_user_defined_layers_paths[i])) return; - } +bool LayerManager::Empty() const { return this->selected_layers.empty(); } - // THIRD: Add VK_ADD_LAYER_PATH layers - const std::vector &env_user_defined_layers_paths_add = - environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_ADD); - for (std::size_t i = 0, n = env_user_defined_layers_paths_add.size(); i < n; ++i) { - if (LoadLayerFromPath(layer_name, env_user_defined_layers_paths_add[i])) return; - } +std::size_t LayerManager::Size() const { return this->selected_layers.size(); } - // FOURTH: Standard layer paths, in standard locations. The above has always taken precedence - for (std::size_t i = 0, n = countof(SEARCH_PATHS); i < n; i++) { - if (LoadLayerFromPath(layer_name, SEARCH_PATHS[i])) return; - } +Layer *LayerManager::Find(const std::string &layer_name) { + assert(!layer_name.empty()); - // FIFTH: See if thee is anyting in the VULKAN_SDK path that wasn't already found elsewhere - if (!qgetenv("VULKAN_SDK").isEmpty()) { - if (LoadLayerFromPath(layer_name, GetPath(BUILTIN_PATH_EXPLICIT_LAYERS))) return; - } + return FindByKey(this->selected_layers, layer_name.c_str()); } -/// Search a folder and load up all the layers found there. This does NOT -/// load the default settings for each layer. This is just a master list of -/// layers found. Do NOT load duplicate layer names. The type of layer (explicit or implicit) is -/// determined from the path name. -void LayerManager::LoadLayersFromPath(const std::string &path) { - // On Windows custom files are in the file system. On non Windows all layers are - // searched this way - LayerType type = LAYER_TYPE_USER_DEFINED; - if (QString(path.c_str()).contains("explicit", Qt::CaseInsensitive)) type = LAYER_TYPE_EXPLICIT; - if (QString(path.c_str()).contains("implicit", Qt::CaseInsensitive)) type = LAYER_TYPE_IMPLICIT; - - PathFinder file_list; - - if (VKC_PLATFORM == VKC_PLATFORM_WINDOWS) { - if (QString(path.c_str()).contains("...")) { -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS - LoadRegistryLayers(path.c_str(), this->selected_layers, type); -#endif - return; - } +const Layer *LayerManager::Find(const std::string &layer_name) const { + assert(!layer_name.empty()); - file_list = PathFinder(path, (type == LAYER_TYPE_USER_DEFINED)); - } else if (VKC_PLATFORM == VKC_PLATFORM_LINUX || VKC_PLATFORM == VKC_PLATFORM_MACOS) { - // On Linux/Mac, we also need the home folder - std::string search_path = path; - if (path[0] == '.') { - search_path = QDir().homePath().toStdString() + "/" + path; - } + return FindByKey(this->selected_layers, layer_name.c_str()); +} - file_list = PathFinder(search_path, true); - } else { - assert(0); // Platform unknown - } +// Find all installed layers on the system. +void LayerManager::LoadAllInstalledLayers() { + this->selected_layers.clear(); - for (int i = 0, n = file_list.FileCount(); i < n; ++i) { - Layer layer; - if (layer.Load(this->selected_layers, file_list.GetFileName(i).c_str(), type)) { - // Make sure this layer name has not already been added - if (FindByKey(this->selected_layers, layer.key.c_str()) != nullptr) continue; + for (std::size_t group_index = 0, group_count = this->paths.size(); group_index < group_count; ++group_index) { + const LayerType layer_type = ::GetLayerType(static_cast(group_index)); - // Good to go, add the layer - this->selected_layers.push_back(layer); + const std::vector &paths_group = this->paths[group_index]; + for (std::size_t i = 0, n = paths_group.size(); i < n; ++i) { + this->LoadLayersFromPath(paths_group[i], layer_type); } } } -// Attempt to load the named layer from the given path -bool LayerManager::LoadLayerFromPath(const std::string &layer_name, const std::string &path) { - LayerType type = LAYER_TYPE_USER_DEFINED; - if (QString(path.c_str()).contains("explicit", Qt::CaseInsensitive)) type = LAYER_TYPE_EXPLICIT; - if (QString(path.c_str()).contains("implicit", Qt::CaseInsensitive)) type = LAYER_TYPE_IMPLICIT; +void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { + const std::vector &layers_paths = layers_path.IsDir() ? CollectFilePaths(layers_path) : GetVector(layers_path); - PathFinder file_list; + for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { + Layer layer; + if (layer.Load(layers_paths[i], type)) { + if (this->IsAvailable(layer)) { + continue; + } - if (VKC_PLATFORM == VKC_PLATFORM_LINUX || VKC_PLATFORM == VKC_PLATFORM_MACOS) { - // On Linux/Mac, we also need the home folder - std::string search_path = path; - if (path[0] == '.') { - search_path = QDir().homePath().toStdString() + "/" + path; + this->selected_layers.push_back(layer); } - file_list = PathFinder(search_path, true); - } else { - file_list = PathFinder(path, true); } +} - for (int i = 0, n = file_list.FileCount(); i < n; ++i) { - Layer layer; - if (layer.Load(this->selected_layers, file_list.GetFileName(i).c_str(), type)) { - // Add this layer if the layer name matches, then return - if (layer_name == layer.key) { - this->selected_layers.push_back(layer); - return true; - } +bool LayerManager::IsAvailable(const Layer &layer) const { + for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (this->selected_layers[i].key == layer.key && this->selected_layers[i].api_version == layer.api_version) { + return true; } } + return false; } diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index 572a29c32a..339a286a65 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2022 Valve Corporation - * Copyright (c) 2020-2022 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,31 +21,46 @@ #pragma once #include "layer.h" -#include "environment.h" - -#include +#include "path.h" #include #include #include +enum LayersPaths { + LAYERS_PATHS_IMPLICIT = 0, + LAYERS_PATHS_EXPLICIT, + LAYERS_PATHS_ENV_SET, // From $VK_LAYER_PATH + LAYERS_PATHS_ENV_ADD, // from $VK_ADD_LAYER_PATH + LAYERS_PATHS_GUI, + LAYERS_PATHS_SDK, + + LAYERS_PATHS_FIRST = LAYERS_PATHS_IMPLICIT, + LAYERS_PATHS_LAST = LAYERS_PATHS_SDK, +}; + +enum { LAYERS_PATHS_COUNT = LAYERS_PATHS_LAST - LAYERS_PATHS_FIRST + 1 }; + +LayerType GetLayerType(LayersPaths Layers_paths_type); + class LayerManager { public: - LayerManager(const Environment& environment); + LayerManager(const std::vector& user_defined_paths = std::vector()); void Clear(); bool Empty() const; + std::size_t Size() const; - void LoadAllInstalledLayers(); - void LoadLayer(const std::string& layer_name); - void LoadLayersFromPath(const std::string& path); + Layer* Find(const std::string& layer_name); + const Layer* Find(const std::string& layer_name) const; - std::vector BuildPathList() const; + void LoadAllInstalledLayers(); + void LoadLayersFromPath(const Path& layers_path, LayerType type = LAYER_TYPE_EXPLICIT); std::vector selected_layers; - const Environment& environment; - private: - bool LoadLayerFromPath(const std::string& layer_name, const std::string& path); + bool IsAvailable(const Layer& layer) const; + + std::array, LAYERS_PATHS_COUNT> paths; }; diff --git a/vkconfig_core/layer_state.cpp b/vkconfig_core/layer_state.cpp deleted file mode 100644 index 403ff2e301..0000000000 --- a/vkconfig_core/layer_state.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "layer_state.h" - -#include "util.h" - -#include -#include - -const char* GetToken(LayerState state) { - static const char* table[] = { - "APPLICATION_CONTROLLED", // LAYER_STATE_APPLICATION_CONTROLLED - "OVERRIDDEN", // LAYER_STATE_OVERRIDDEN - "EXCLUDED" // LAYER_STATE_EXCLUDED - }; - static_assert(countof(table) == LAYER_STATE_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return table[state]; -} - -LayerState GetLayerState(const char* token) { - for (std::size_t i = 0, n = LAYER_STATE_COUNT; i < n; ++i) { - const LayerState layer_state = static_cast(i); - if (std::strcmp(GetToken(layer_state), token) == 0) return layer_state; - } - - assert(0); - return static_cast(-1); -} diff --git a/vkconfig_core/layer_state.h b/vkconfig_core/layer_state.h deleted file mode 100644 index 7913faa909..0000000000 --- a/vkconfig_core/layer_state.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -enum LayerState { - LAYER_STATE_APPLICATION_CONTROLLED = 0, // The Vulkan application configured this layer at will - LAYER_STATE_OVERRIDDEN = 1, // Force on/override this layer and configure it regarless of the Vulkan application - LAYER_STATE_EXCLUDED = 2, // Force off/exclude this layer regarless of the Vulkan application - - LAYER_STATE_FIRST = LAYER_STATE_APPLICATION_CONTROLLED, - LAYER_STATE_LAST = LAYER_STATE_EXCLUDED -}; - -enum { LAYER_STATE_COUNT = LAYER_STATE_LAST - LAYER_STATE_FIRST + 1 }; - -const char* GetToken(LayerState state); -LayerState GetLayerState(const char* token); diff --git a/vkconfig_core/layer_type.cpp b/vkconfig_core/layer_type.cpp deleted file mode 100644 index 342e9f4567..0000000000 --- a/vkconfig_core/layer_type.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "layer_type.h" - -#include "util.h" - -#include - -const char* GetLayerTypeLabel(LayerType type) { - assert(type >= LAYER_TYPE_FIRST && type <= LAYER_TYPE_LAST); - - static const char* table[] = { - "Explicit", // LAYER_TYPE_EXPLICIT - "Implicit", // LAYER_TYPE_IMPLICIT - "User-Defined" // LAYER_TYPE_USER_DEFINED - }; - static_assert(countof(table) == LAYER_TYPE_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return table[type]; -} diff --git a/vkconfig_core/layers/130/VK_LAYER_KHRONOS_validation.json b/vkconfig_core/layers/130/VK_LAYER_KHRONOS_validation.json deleted file mode 100644 index ea1a9eff2c..0000000000 --- a/vkconfig_core/layers/130/VK_LAYER_KHRONOS_validation.json +++ /dev/null @@ -1,328 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_KHRONOS_validation", - "library_path": ".\\VkLayer_khronos_validation.dll", - "api_version": "1.1.130", - "implementation_version": "1", - "description": "Khronos Validation Layer", - "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "9" - }, - { - "name": "VK_EXT_debug_utils", - "spec_version": "1" - }, - { - "name": "VK_EXT_validation_features", - "spec_version": "2" - } - ], - "device_extensions": [ - { - "name": "VK_EXT_debug_marker", - "spec_version": "4", - "entrypoints": [ - "vkDebugMarkerSetObjectTagEXT", - "vkDebugMarkerSetObjectNameEXT", - "vkCmdDebugMarkerBeginEXT", - "vkCmdDebugMarkerEndEXT", - "vkCmdDebugMarkerInsertEXT" - ] - }, - { - "name": "VK_EXT_validation_cache", - "spec_version": "1", - "entrypoints": [ - "vkCreateValidationCacheEXT", - "vkDestroyValidationCacheEXT", - "vkGetValidationCacheDataEXT", - "vkMergeValidationCachesEXT" - ] - }, - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Standard", - "description": "Good default validation setup that balance validation coverage and performance.", - "settings": [ - { - "key": "enables", - "value": [] - }, - { - "key": "disables", - "value": [] - } - ] - }, - { - "label": "Reduced-Overhead", - "description": "Disables some checks in the interest of better performance.", - "settings": [ - { - "key": "enables", - "value": [ - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET", - "VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE" - ] - } - ] - }, - { - "label": "Best Practices", - "description": "Provides warnings about potential API misuse but valid usages of the API.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time.", - "platforms": [ "WINDOWS", "LINUX" ], - "status": "BETA", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - } - ], - "settings": [ - { - "key": "debug_action", - "label": "Debug Action", - "description": "This indicates what action is to be taken when a layer wants to report information", - "type": "FLAGS", - "flags": [ - { - "key": "VK_DBG_LAYER_ACTION_LOG_MSG", - "label": "Log Message", - "description": "Log a txt message to stdout or to a log filename.", - "settings": [ - { - "key": "log_filename", - "label": "Log Filename", - "description": "Specifies the output filename", - "type": "SAVE_FILE", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "debug_action", - "value": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - } - ] - } - } - ] - }, - { - "key": "VK_DBG_LAYER_ACTION_CALLBACK", - "label": "Callback", - "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", - "view": "HIDDEN" - }, - { - "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", - "label": "Debug Output", - "description": "Log a txt message using the Windows OutputDebugString function.", - "platforms": [ "WINDOWS" ] - }, - { - "key": "VK_DBG_LAYER_ACTION_BREAK", - "label": "Break", - "description": "Trigger a breakpoint if a debugger is in use." - } - ], - "default": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - }, - { - "key": "report_flags", - "label": "Message Severity", - "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", - "type": "FLAGS", - "flags": [ - { - "key": "info", - "label": "Info", - "description": "Report informational messages." - }, - { - "key": "warn", - "label": "Warning", - "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." - }, - { - "key": "perf", - "label": "performance", - "description": "Report using the API in a way that may cause suboptimal performance." - }, - { - "key": "error", - "label": "Error", - "description": "Report errors in API usage." - }, - { - "key": "debug", - "label": "Debug", - "description": "For layer development. Report messages for debugging layer behavior.", - "view": "ADVANCED" - } - ], - "default": [ - "error", - "warn", - "perf" - ] - }, - { - "key": "disables", - "env": "VK_LAYER_DISABLES", - "label": "Disables", - "description": "Setting an option here will disable areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "label": "Thread Safety", - "description": "Thread checks. It may help with performance to run with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check, or when debugging difficult application behaviors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "label": "Stateless Parameter", - "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "label": "Object Lifetime", - "description": "Object tracking checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", - "label": "Core", - "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "label": "Handle Wrapping", - "description": "Handle wrapping checks. Disable this feature if you are running into crashes when authoring new extensions or developing new Vulkan objects/structures" - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", - "label": "Shaders", - "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "label": "Command Buffer State", - "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "label": "Image Layout", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "label": "Query", - "description": "Checks for commands that use VkQueryPool objects.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "label": "Object in Use", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - } - ], - "default": [] - }, - { - "key": "enables", - "env": "VK_LAYER_ENABLES", - "label": "Enables", - "description": "Setting an option here will enable specialized areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "label": "GPU-Assisted", - "description": "Activating this feature instruments shader programs to generate additional diagnostic data.", - "url": "${LUNARG_SDK}/gpu_validation.html", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", - "label": "Reserve a descriptorSet binding slot", - "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", - "label": "Best Practices", - "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", - "url": "${LUNARG_SDK}/best_practices.html" - } - ], - "default": [] - } - ] - } - } -} diff --git a/vkconfig_core/layers/130/VK_LAYER_LUNARG_api_dump.json b/vkconfig_core/layers/130/VK_LAYER_LUNARG_api_dump.json deleted file mode 100644 index 0762910f38..0000000000 --- a/vkconfig_core/layers/130/VK_LAYER_LUNARG_api_dump.json +++ /dev/null @@ -1,277 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_api_dump", - "library_path": ".\\VkLayer_api_dump.dll", - "api_version": "1.1.130", - "implementation_version": "2", - "description": "LunarG API dump layer", - "introduction": "The API Dump utility layer prints API calls, parameters, and values to the identified output stream.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/api_dump_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "presets": [ - { - "label": "Console Output", - "description": "Output API dump to stdout", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "stdout" - }, - { - "key": "file", - "value": false - } - ] - }, - { - "label": "Text Output", - "description": "Output API dump to a text file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.txt" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "HTML Output", - "description": "Output API dump to a HTML file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "html" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.html" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "JSON Output", - "description": "Output API dump to a JSON file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "json" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.json" - }, - { - "key": "file", - "value": true - } - ] - } - ], - "settings": [ - { - "key": "output_range", - "env": "VK_APIDUMP_OUTPUT_RANGE", - "label": "Output Range", - "description": "Comma separated list of frames to output or a range of frames with a start, count, and optional interval separated by a dash. A count of 0 will output every frame after the start of the range. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "0-0" - }, - { - "key": "output_format", - "env": "VK_APIDUMP_OUTPUT_FORMAT", - "label": "Output Format", - "description": "Specifies the format used for output; can be HTML, JSON, or Text (default -- outputs plain text)", - "type": "ENUM", - "flags": [ - { - "key": "text", - "label": "Text", - "description": "Plain text" - }, - { - "key": "html", - "label": "HTML", - "description": "HTML" - }, - { - "key": "json", - "label": "JSON", - "description": "Json" - } - ], - "default": "text" - }, - { - "key": "file", - "label": "Output to File", - "description": "Setting this to true indicates that output should be written to file instead of stdout", - "type": "BOOL", - "default": false, - "settings": [ - { - "key": "log_filename", - "env": "VK_APIDUMP_LOG_FILENAME", - "label": "Log Filename", - "description": "Specifies the file to dump to when output files are enabled", - "type": "SAVE_FILE", - "filter": "*.txt,*.html,*.json", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "file", - "value": true - } - ] - } - } - ] - }, - { - "key": "flush", - "env": "VK_APIDUMP_FLUSH", - "label": "Log Flush After Write", - "description": "Setting this to true causes IO to be flushed after each API call that is written", - "type": "BOOL", - "default": true - }, - { - "key": "name_size", - "label": "Name Size", - "description": "The number of characters the name of a variable should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 1 - }, - "unit": "chars" - }, - { - "key": "show_types", - "label": "Show Types", - "description": "Dump types in addition to values", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "type_size", - "label": "Type Size", - "description": "The number of characters the name of a type should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 0 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "show_types", - "value": true - } - ] - } - } - ] - }, - { - "key": "show_timestamp", - "env": "VK_APIDUMP_TIMESTAMP", - "label": "Show Timestamp", - "description": "Show the timestamp of function calls since start in microseconds", - "type": "BOOL", - "default": false - }, - { - "key": "show_shader", - "label": "Show Shader", - "description": "Dump the shader binary code in pCode", - "type": "BOOL", - "default": false - }, - { - "key": "detailed", - "env": "VK_APIDUMP_DETAILED", - "label": "Show Parameter Details", - "description": "Dump parameter details in addition to API calls", - "type": "BOOL", - "default": true - }, - { - "key": "no_addr", - "env": "VK_APIDUMP_NO_ADDR", - "label": "Hide Addresses", - "description": "Dump \"address\" in place of hex addresses", - "type": "BOOL", - "default": false - }, - { - "key": "use_spaces", - "label": "Use Spaces", - "description": "Setting this to true causes all tab characters to be replaced with spaces", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "indent_size", - "label": "Indent Size", - "description": "Specifies the number of spaces that a tab is equal to", - "type": "INT", - "default": 4, - "range": { - "min": 1, - "max": 16 - }, - "unit": "chars", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "use_spaces", - "value": true - } - ] - } - } - ] - } - ] - } - } -} - diff --git a/vkconfig_core/layers/130/VK_LAYER_LUNARG_monitor.json b/vkconfig_core/layers/130/VK_LAYER_LUNARG_monitor.json deleted file mode 100644 index 53021b0e20..0000000000 --- a/vkconfig_core/layers/130/VK_LAYER_LUNARG_monitor.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "file_format_version": "1.0.0", - "layer": { - "name": "VK_LAYER_LUNARG_monitor", - "library_path": ".\\VkLayer_monitor.dll", - "api_version": "1.1.130", - "implementation_version": "1", - "description": "Execution Monitoring Layer", - "introduction": "The monitor utility layer prints the real-time frames-per-second value to the application's title bar.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/monitor_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ] - } -} diff --git a/vkconfig_core/layers/135/VK_LAYER_KHRONOS_validation.json b/vkconfig_core/layers/135/VK_LAYER_KHRONOS_validation.json deleted file mode 100644 index 8184fc52a2..0000000000 --- a/vkconfig_core/layers/135/VK_LAYER_KHRONOS_validation.json +++ /dev/null @@ -1,329 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_KHRONOS_validation", - "library_path": ".\\VkLayer_khronos_validation.dll", - "api_version": "1.2.135", - "implementation_version": "1", - "description": "Khronos Validation Layer", - "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "9" - }, - { - "name": "VK_EXT_debug_utils", - "spec_version": "1" - }, - { - "name": "VK_EXT_validation_features", - "spec_version": "2" - } - ], - "device_extensions": [ - { - "name": "VK_EXT_debug_marker", - "spec_version": "4", - "entrypoints": [ - "vkDebugMarkerSetObjectTagEXT", - "vkDebugMarkerSetObjectNameEXT", - "vkCmdDebugMarkerBeginEXT", - "vkCmdDebugMarkerEndEXT", - "vkCmdDebugMarkerInsertEXT" - ] - }, - { - "name": "VK_EXT_validation_cache", - "spec_version": "1", - "entrypoints": [ - "vkCreateValidationCacheEXT", - "vkDestroyValidationCacheEXT", - "vkGetValidationCacheDataEXT", - "vkMergeValidationCachesEXT" - ] - }, - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Standard", - "description": "Good default validation setup that balance validation coverage and performance.", - "settings": [ - { - "key": "enables", - "value": [] - }, - { - "key": "disables", - "value": [] - } - ] - }, - { - "label": "Reduced-Overhead", - "description": "Disables some checks in the interest of better performance.", - "editor_state": "01110111111111111111111001111111111110", - "settings": [ - { - "key": "enables", - "value": [ - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET", - "VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE" - ] - } - ] - }, - { - "label": "Best Practices", - "description": "Provides warnings about potential API misuse but valid usages of the API.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time.", - "platforms": [ "WINDOWS", "LINUX" ], - "status": "BETA", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - } - ], - "settings": [ - { - "key": "debug_action", - "label": "Debug Action", - "description": "This indicates what action is to be taken when a layer wants to report information", - "type": "FLAGS", - "flags": [ - { - "key": "VK_DBG_LAYER_ACTION_LOG_MSG", - "label": "Log Message", - "description": "Log a txt message to stdout or to a log filename.", - "settings": [ - { - "key": "log_filename", - "label": "Log Filename", - "description": "Specifies the output filename", - "type": "SAVE_FILE", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "debug_action", - "value": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - } - ] - } - } - ] - }, - { - "key": "VK_DBG_LAYER_ACTION_CALLBACK", - "label": "Callback", - "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", - "view": "HIDDEN" - }, - { - "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", - "label": "Debug Output", - "description": "Log a txt message using the Windows OutputDebugString function.", - "platforms": [ "WINDOWS" ] - }, - { - "key": "VK_DBG_LAYER_ACTION_BREAK", - "label": "Break", - "description": "Trigger a breakpoint if a debugger is in use." - } - ], - "default": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - }, - { - "key": "report_flags", - "label": "Message Severity", - "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", - "type": "FLAGS", - "flags": [ - { - "key": "info", - "label": "Info", - "description": "Report informational messages." - }, - { - "key": "warn", - "label": "Warning", - "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." - }, - { - "key": "perf", - "label": "performance", - "description": "Report using the API in a way that may cause suboptimal performance." - }, - { - "key": "error", - "label": "Error", - "description": "Report errors in API usage." - }, - { - "key": "debug", - "label": "Debug", - "description": "For layer development. Report messages for debugging layer behavior.", - "view": "ADVANCED" - } - ], - "default": [ - "error", - "warn", - "perf" - ] - }, - { - "key": "disables", - "env": "VK_LAYER_DISABLES", - "label": "Disables", - "description": "Setting an option here will disable areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "label": "Thread Safety", - "description": "Thread checks. It may help with performance to run with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check, or when debugging difficult application behaviors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "label": "Stateless Parameter", - "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "label": "Object Lifetime", - "description": "Object tracking checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", - "label": "Core", - "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "label": "Handle Wrapping", - "description": "Handle wrapping checks. Disable this feature if you are running into crashes when authoring new extensions or developing new Vulkan objects/structures" - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", - "label": "Shaders", - "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "label": "Command Buffer State", - "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "label": "Image Layout", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "label": "Query", - "description": "Checks for commands that use VkQueryPool objects.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "label": "Object in Use", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - } - ], - "default": [] - }, - { - "key": "enables", - "env": "VK_LAYER_ENABLES", - "label": "Enables", - "description": "Setting an option here will enable specialized areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "label": "GPU-Assisted", - "description": "Activating this feature instruments shader programs to generate additional diagnostic data.", - "url": "${LUNARG_SDK}/gpu_validation.html", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", - "label": "Reserve a descriptorSet binding slot", - "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", - "label": "Best Practices", - "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", - "url": "${LUNARG_SDK}/best_practices.html" - } - ], - "default": [] - } - ] - } - } -} diff --git a/vkconfig_core/layers/135/VK_LAYER_LUNARG_api_dump.json b/vkconfig_core/layers/135/VK_LAYER_LUNARG_api_dump.json deleted file mode 100644 index f25e549148..0000000000 --- a/vkconfig_core/layers/135/VK_LAYER_LUNARG_api_dump.json +++ /dev/null @@ -1,277 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_api_dump", - "library_path": ".\\VkLayer_api_dump.dll", - "api_version": "1.2.135", - "implementation_version": "2", - "description": "LunarG API dump layer", - "introduction": "The API Dump utility layer prints API calls, parameters, and values to the identified output stream.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/api_dump_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "presets": [ - { - "label": "Console Output", - "description": "Output API dump to stdout", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "stdout" - }, - { - "key": "file", - "value": false - } - ] - }, - { - "label": "Text Output", - "description": "Output API dump to a text file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.txt" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "HTML Output", - "description": "Output API dump to a HTML file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "html" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.html" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "JSON Output", - "description": "Output API dump to a JSON file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "json" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.json" - }, - { - "key": "file", - "value": true - } - ] - } - ], - "settings": [ - { - "key": "output_range", - "env": "VK_APIDUMP_OUTPUT_RANGE", - "label": "Output Range", - "description": "Comma separated list of frames to output or a range of frames with a start, count, and optional interval separated by a dash. A count of 0 will output every frame after the start of the range. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "0-0" - }, - { - "key": "output_format", - "env": "VK_APIDUMP_OUTPUT_FORMAT", - "label": "Output Format", - "description": "Specifies the format used for output; can be HTML, JSON, or Text (default -- outputs plain text)", - "type": "ENUM", - "flags": [ - { - "key": "text", - "label": "Text", - "description": "Plain text" - }, - { - "key": "html", - "label": "HTML", - "description": "HTML" - }, - { - "key": "json", - "label": "JSON", - "description": "Json" - } - ], - "default": "text" - }, - { - "key": "file", - "label": "Output to File", - "description": "Setting this to true indicates that output should be written to file instead of stdout", - "type": "BOOL", - "default": false, - "settings": [ - { - "key": "log_filename", - "env": "VK_APIDUMP_LOG_FILENAME", - "label": "Log Filename", - "description": "Specifies the file to dump to when output files are enabled", - "type": "SAVE_FILE", - "filter": "*.txt,*.html,*.json", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "file", - "value": true - } - ] - } - } - ] - }, - { - "key": "flush", - "env": "VK_APIDUMP_FLUSH", - "label": "Log Flush After Write", - "description": "Setting this to true causes IO to be flushed after each API call that is written", - "type": "BOOL", - "default": true - }, - { - "key": "name_size", - "label": "Name Size", - "description": "The number of characters the name of a variable should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 1 - }, - "unit": "chars" - }, - { - "key": "show_types", - "label": "Show Types", - "description": "Dump types in addition to values", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "type_size", - "label": "Type Size", - "description": "The number of characters the name of a type should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 0 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "show_types", - "value": true - } - ] - } - } - ] - }, - { - "key": "show_timestamp", - "env": "VK_APIDUMP_TIMESTAMP", - "label": "Show Timestamp", - "description": "Show the timestamp of function calls since start in microseconds", - "type": "BOOL", - "default": false - }, - { - "key": "show_shader", - "label": "Show Shader", - "description": "Dump the shader binary code in pCode", - "type": "BOOL", - "default": false - }, - { - "key": "detailed", - "env": "VK_APIDUMP_DETAILED", - "label": "Show Parameter Details", - "description": "Dump parameter details in addition to API calls", - "type": "BOOL", - "default": true - }, - { - "key": "no_addr", - "env": "VK_APIDUMP_NO_ADDR", - "label": "Hide Addresses", - "description": "Dump \"address\" in place of hex addresses", - "type": "BOOL", - "default": false - }, - { - "key": "use_spaces", - "label": "Use Spaces", - "description": "Setting this to true causes all tab characters to be replaced with spaces", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "indent_size", - "label": "Indent Size", - "description": "Specifies the number of spaces that a tab is equal to", - "type": "INT", - "default": 4, - "range": { - "min": 1, - "max": 16 - }, - "unit": "chars", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "use_spaces", - "value": true - } - ] - } - } - ] - } - ] - } - - } -} diff --git a/vkconfig_core/layers/135/VK_LAYER_LUNARG_monitor.json b/vkconfig_core/layers/135/VK_LAYER_LUNARG_monitor.json deleted file mode 100644 index 8461bbbed6..0000000000 --- a/vkconfig_core/layers/135/VK_LAYER_LUNARG_monitor.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "file_format_version": "1.0.0", - "layer": { - "name": "VK_LAYER_LUNARG_monitor", - "library_path": ".\\VkLayer_monitor.dll", - "api_version": "1.2.135", - "implementation_version": "1", - "description": "Execution Monitoring Layer", - "introduction": "The monitor utility layer prints the real-time frames-per-second value to the application's title bar.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/monitor_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ] - } -} diff --git a/vkconfig_core/layers/135/VK_LAYER_LUNARG_screenshot.json b/vkconfig_core/layers/135/VK_LAYER_LUNARG_screenshot.json deleted file mode 100644 index 9509790d02..0000000000 --- a/vkconfig_core/layers/135/VK_LAYER_LUNARG_screenshot.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_screenshot", - "type": "GLOBAL", - "library_path": ".\\VkLayer_screenshot.dll", - "api_version": "1.2.135", - "implementation_version": "1", - "description": "LunarG image capture layer", - "introduction": "The screenshot layer records frames to image files.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/screenshot_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "settings": [ - { - "key": "frames", - "env": "VK_SCREENSHOT_FRAMES", - "label": "Frames", - "description": "Comma separated list of frames to output as screen shots or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "" - }, - { - "key": "dir", - "env": "VK_SCREENSHOT_DIR", - "label": "Directory", - "description": "This can be set to specify the directory in which to create the screenshot files.", - "type": "SAVE_FOLDER", - "default": "" - }, - { - "key": "format", - "env": "VK_SCREENSHOT_FORMAT", - "label": "Format", - "description": "This can be set to a color space for the output.", - "type": "ENUM", - "flags": [ - { - "key": "UNORM", - "label": "UNORM", - "description": "" - }, - { - "key": "SNORM", - "label": "SNORM", - "description": "" - }, - { - "key": "USCALED", - "label": "USCALED", - "description": "" - }, - { - "key": "SSCALED", - "label": "SSCALED", - "description": "" - }, - { - "key": "UINT", - "label": "UINT", - "description": "" - }, - { - "key": "SINT", - "label": "SINT", - "description": "" - }, - { - "key": "SRGB", - "label": "SRGB", - "description": "" - }, - { - "key": "USE_SWAPCHAIN_COLORSPACE", - "label": "USE_SWAPCHAIN_COLORSPACE", - "description": "" - } - ], - "default": "USE_SWAPCHAIN_COLORSPACE" - } - ] - } - } -} diff --git a/vkconfig_core/layers/141/VK_LAYER_KHRONOS_validation.json b/vkconfig_core/layers/141/VK_LAYER_KHRONOS_validation.json deleted file mode 100644 index 77afb7965c..0000000000 --- a/vkconfig_core/layers/141/VK_LAYER_KHRONOS_validation.json +++ /dev/null @@ -1,358 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_KHRONOS_validation", - "library_path": ".\\VkLayer_khronos_validation.dll", - "api_version": "1.2.148", - "implementation_version": "1", - "description": "Khronos Validation Layer", - "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "9" - }, - { - "name": "VK_EXT_debug_utils", - "spec_version": "1" - }, - { - "name": "VK_EXT_validation_features", - "spec_version": "2" - } - ], - "device_extensions": [ - { - "name": "VK_EXT_debug_marker", - "spec_version": "4", - "entrypoints": [ - "vkDebugMarkerSetObjectTagEXT", - "vkDebugMarkerSetObjectNameEXT", - "vkCmdDebugMarkerBeginEXT", - "vkCmdDebugMarkerEndEXT", - "vkCmdDebugMarkerInsertEXT" - ] - }, - { - "name": "VK_EXT_validation_cache", - "spec_version": "1", - "entrypoints": [ - "vkCreateValidationCacheEXT", - "vkDestroyValidationCacheEXT", - "vkGetValidationCacheDataEXT", - "vkMergeValidationCachesEXT" - ] - }, - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Standard", - "description": "Good default validation setup that balance validation coverage and performance.", - "settings": [ - { - "key": "enables", - "value": [] - }, - { - "key": "disables", - "value": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - } - ] - }, - { - "label": "Reduced-Overhead", - "description": "Disables some checks in the interest of better performance.", - "settings": [ - { - "key": "enables", - "value": [ - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET", - "VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE" - ] - } - ] - }, - { - "label": "Best Practices", - "description": "Provides warnings about potential API misuse but valid usages of the API.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Shader Printf", - "description": "Debug shader code by \"printing\" any values of interest to the debug callback or stdout.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - } - ], - "settings": [ - { - "key": "debug_action", - "label": "Debug Action", - "description": "This indicates what action is to be taken when a layer wants to report information", - "type": "FLAGS", - "flags": [ - { - "key": "VK_DBG_LAYER_ACTION_LOG_MSG", - "label": "Log Message", - "description": "Log a txt message to stdout or to a log filename.", - "settings": [ - { - "key": "log_filename", - "label": "Log Filename", - "description": "Specifies the output filename", - "type": "SAVE_FILE", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "debug_action", - "value": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - } - ] - } - } - ] - }, - { - "key": "VK_DBG_LAYER_ACTION_CALLBACK", - "label": "Callback", - "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", - "view": "HIDDEN" - }, - { - "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", - "label": "Debug Output", - "description": "Log a txt message using the Windows OutputDebugString function.", - "platforms": [ "WINDOWS" ] - }, - { - "key": "VK_DBG_LAYER_ACTION_BREAK", - "label": "Break", - "description": "Trigger a breakpoint if a debugger is in use." - } - ], - "default": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - }, - { - "key": "report_flags", - "label": "Message Severity", - "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", - "type": "FLAGS", - "flags": [ - { - "key": "info", - "label": "Info", - "description": "Report informational messages." - }, - { - "key": "warn", - "label": "Warning", - "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." - }, - { - "key": "perf", - "label": "performance", - "description": "Report using the API in a way that may cause suboptimal performance." - }, - { - "key": "error", - "label": "Error", - "description": "Report errors in API usage." - }, - { - "key": "debug", - "label": "Debug", - "description": "For layer development. Report messages for debugging layer behavior.", - "view": "ADVANCED" - } - ], - "default": [ - "error", - "warn", - "perf" - ] - }, - { - "key": "disables", - "env": "VK_LAYER_DISABLES", - "label": "Disables", - "description": "Setting an option here will disable areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "label": "Thread Safety", - "description": "Thread checks. It may help with performance to run with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check, or when debugging difficult application behaviors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "label": "Stateless Parameter", - "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "label": "Object Lifetime", - "description": "Object tracking checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", - "label": "Core", - "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "label": "Handle Wrapping", - "description": "Handle wrapping checks. Disable this feature if you are running into crashes when authoring new extensions or developing new Vulkan objects/structures" - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", - "label": "Shaders", - "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "label": "Command Buffer State", - "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "label": "Image Layout", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "label": "Query", - "description": "Checks for commands that use VkQueryPool objects.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "label": "Object in Use", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - } - ], - "default": [] - }, - { - "key": "enables", - "env": "VK_LAYER_ENABLES", - "label": "Enables", - "description": "Setting an option here will enable specialized areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT", - "label": "Debug Printf", - "description": "Enables processing of debug printf instructions in shaders and sending debug strings to the debug callback", - "url": "${LUNARG_SDK}/debug_printf.html", - "status": "STABLE", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "label": "GPU-Assisted", - "description": "Activating this feature instruments shader programs to generate additional diagnostic data.", - "url": "${LUNARG_SDK}/gpu_validation.html", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", - "label": "Reserve a descriptorSet binding slot", - "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", - "label": "Best Practices", - "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", - "url": "${LUNARG_SDK}/best_practices.html" - } - ], - "default": [] - } - ] - } - } -} diff --git a/vkconfig_core/layers/141/VK_LAYER_LUNARG_api_dump.json b/vkconfig_core/layers/141/VK_LAYER_LUNARG_api_dump.json deleted file mode 100644 index 4a011ea5a4..0000000000 --- a/vkconfig_core/layers/141/VK_LAYER_LUNARG_api_dump.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_api_dump", - "library_path": ".\\VkLayer_api_dump.dll", - "api_version": "1.2.141", - "implementation_version": "2", - "description": "LunarG API dump layer", - "introduction": "The API Dump utility layer prints API calls, parameters, and values to the identified output stream.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/api_dump_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "presets": [ - { - "label": "Console Output", - "description": "Output API dump to stdout", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "stdout" - }, - { - "key": "file", - "value": false - } - ] - }, - { - "label": "Text Output", - "description": "Output API dump to a text file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.txt" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "HTML Output", - "description": "Output API dump to a HTML file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "html" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.html" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "JSON Output", - "description": "Output API dump to a JSON file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "json" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.json" - }, - { - "key": "file", - "value": true - } - ] - } - ], - "settings": [ - { - "key": "output_range", - "env": "VK_APIDUMP_OUTPUT_RANGE", - "label": "Output Range", - "description": "Comma separated list of frames to output or a range of frames with a start, count, and optional interval separated by a dash. A count of 0 will output every frame after the start of the range. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "0-0" - }, - { - "key": "output_format", - "env": "VK_APIDUMP_OUTPUT_FORMAT", - "label": "Output Format", - "description": "Specifies the format used for output; can be HTML, JSON, or Text (default -- outputs plain text)", - "type": "ENUM", - "flags": [ - { - "key": "text", - "label": "Text", - "description": "Plain text" - }, - { - "key": "html", - "label": "HTML", - "description": "HTML" - }, - { - "key": "json", - "label": "JSON", - "description": "Json" - } - ], - "default": "text" - }, - { - "key": "file", - "label": "Output to File", - "description": "Setting this to true indicates that output should be written to file instead of stdout", - "type": "BOOL", - "default": false, - "settings": [ - { - "key": "log_filename", - "env": "VK_APIDUMP_LOG_FILENAME", - "label": "Log Filename", - "description": "Specifies the file to dump to when output files are enabled", - "type": "SAVE_FILE", - "filter": "*.txt,*.html,*.json", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "file", - "value": true - } - ] - } - } - ] - }, - { - "key": "flush", - "env": "VK_APIDUMP_FLUSH", - "label": "Log Flush After Write", - "description": "Setting this to true causes IO to be flushed after each API call that is written", - "type": "BOOL", - "default": true - }, - { - "key": "name_size", - "label": "Name Size", - "description": "The number of characters the name of a variable should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 1 - }, - "unit": "chars" - }, - { - "key": "show_types", - "label": "Show Types", - "description": "Dump types in addition to values", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "type_size", - "label": "Type Size", - "description": "The number of characters the name of a type should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 0 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "show_types", - "value": true - } - ] - } - } - ] - }, - { - "key": "show_timestamp", - "env": "VK_APIDUMP_TIMESTAMP", - "label": "Show Timestamp", - "description": "Show the timestamp of function calls since start in microseconds", - "type": "BOOL", - "default": false - }, - { - "key": "show_shader", - "label": "Show Shader", - "description": "Dump the shader binary code in pCode", - "type": "BOOL", - "default": false - }, - { - "key": "detailed", - "env": "VK_APIDUMP_DETAILED", - "label": "Show Parameter Details", - "description": "Dump parameter details in addition to API calls", - "type": "BOOL", - "default": true - }, - { - "key": "no_addr", - "env": "VK_APIDUMP_NO_ADDR", - "label": "Hide Addresses", - "description": "Dump \"address\" in place of hex addresses", - "type": "BOOL", - "default": false - }, - { - "key": "use_spaces", - "label": "Use Spaces", - "description": "Setting this to true causes all tab characters to be replaced with spaces", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "indent_size", - "label": "Indent Size", - "description": "Specifies the number of spaces that a tab is equal to", - "type": "INT", - "default": 4, - "range": { - "min": 1, - "max": 16 - }, - "unit": "chars", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "use_spaces", - "value": true - } - ] - } - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/141/VK_LAYER_LUNARG_gfxreconstruct.json b/vkconfig_core/layers/141/VK_LAYER_LUNARG_gfxreconstruct.json deleted file mode 100644 index 660fc71589..0000000000 --- a/vkconfig_core/layers/141/VK_LAYER_LUNARG_gfxreconstruct.json +++ /dev/null @@ -1,409 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_gfxreconstruct", - "type": "GLOBAL", - "library_path": ".\\VkLayer_gfxreconstruct.dll", - "api_version": "1.2.141", - "status": "BETA", - "implementation_version": "36865", - "description": "GFXReconstruct Capture Layer Version 0.9.1", - "introduction": "The GFXReconstruct Capture Layer intercepts Vulkan API calls and logs them to a capture file. Other tools in the GFXReconstruct suite can inspect, modify, or replay capture files generated by this component.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/capture_tools.html", - "platforms": [ "WINDOWS", "LINUX", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Initialization", - "description": "Capture the first two frames.", - "settings": [ - { - "key": "capture_trigger", - "value": "" - }, - { - "key": "capture_frames", - "value": "1-2" - }, - { - "key": "memory_tracking_mode", - "value": "unassisted" - } - ] - }, - { - "label": "Range", - "description": "Capture a range of frames between presses of the F5 key.", - "settings": [ - { - "key": "capture_trigger", - "value": "F5" - }, - { - "key": "capture_frames", - "value": "" - }, - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - ], - "settings": [ - { - "key": "capture_trigger", - "env": "GFXRECON_CAPTURE_TRIGGER", - "label": "Hotkey Capture Trigger", - "description": "Specify a hotkey (any one of F1-F12, TAB, CONTROL) that will be used to start/stop capture. Example: F3 will set the capture trigger to F3 hotkey. One capture file will be generated for each pair of start/stop hotkey presses. Default is: Empty string (hotkey capture trigger is disabled).", - "type": "ENUM", - "flags": [ - { - "key": "", - "label": "None", - "description": "" - }, - { - "key": "F1", - "label": "F1", - "description": "" - }, - { - "key": "F2", - "label": "F2", - "description": "" - }, - { - "key": "F3", - "label": "F3", - "description": "" - }, - { - "key": "F4", - "label": "F4", - "description": "" - }, - { - "key": "F5", - "label": "F5", - "description": "" - }, - { - "key": "F6", - "label": "F6", - "description": "" - }, - { - "key": "F7", - "label": "F7", - "description": "" - }, - { - "key": "F8", - "label": "F8", - "description": "" - }, - { - "key": "F9", - "label": "F9", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F11", - "label": "F11", - "description": "" - }, - { - "key": "F12", - "label": "F12", - "description": "" - }, - { - "key": "TAB", - "label": "TAB", - "description": "" - }, - { - "key": "CONTROL", - "label": "CONTROL", - "description": "" - } - ], - "default": "" - }, - { - "key": "capture_frames", - "env": "GFXRECON_CAPTURE_FRAMES", - "label": "Capture Specific Frames", - "description": "Specify one or more comma-separated frame ranges to capture. Each range will be written to its own file. A frame range can be specified as a single value, to specify a single frame to capture, or as two hyphenated values, to specify the first and last frame to capture. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: 200,301-305 will create two capture files, one containing a single frame and one containing five frames. Default is: Empty string (all frames are captured).", - "type": "STRING", - "default": "" - }, - { - "key": "capture_file", - "env": "GFXRECON_CAPTURE_FILE", - "label": "Capture File Name", - "description": "Path to use when creating the capture file. Default is: gfxrecon_capture.gfxr", - "type": "SAVE_FILE", - "filter": "*.gfxr", - "default": "${VK_LOCAL}/gfxrecon_capture.gfxr", - "settings": [ - { - "key": "capture_file_timestamp", - "env": "GFXRECON_CAPTURE_FILE_TIMESTAMP", - "label": "Capture File Name with Timestamp", - "description": "Add a timestamp (yyyymmddThhmmss) postfix to the capture file name.", - "type": "BOOL", - "default": true - }, - { - "key": "capture_file_flush", - "env": "GFXRECON_CAPTURE_FILE_FLUSH", - "label": "Capture File Flush After Write", - "description": "Flush output stream after each packet is written to the capture file. Default is: false.", - "type": "BOOL", - "default": true - } - ] - }, - { - "key": "capture_compression_type", - "env": "GFXRECON_CAPTURE_COMPRESSION_TYPE", - "label": "Compression Format", - "description": "Compression format to use with the capture file. Valid values are: LZ4, ZLIB, ZSTD, and NONE. Default is: LZ4", - "type": "ENUM", - "flags": [ - { - "key": "LZ4", - "label": "LZ4", - "description": "Fastest compression algorithm that favors performance over compression ratio." - }, - { - "key": "ZLIB", - "label": "ZLIB", - "description": "Widely used compression algorithm with better compression ratio than LZ4 but worse performance." - }, - { - "key": "ZSTD", - "label": "ZSTD", - "description": "Newer compression algorithm with better compression ratio and performance than ZLIB, though not as fast as LZ4." - }, - { - "key": "NONE", - "label": "NONE", - "description": "No compression" - } - ], - "default": "LZ4" - }, - { - "key": "memory_tracking_mode", - "env": "GFXRECON_MEMORY_TRACKING_MODE", - "label": "Memory Tracking Mode", - "description": "Specifies the memory tracking mode to use for detecting modifications to mapped Vulkan memory objects. Available options are: page_guard, assisted, and unassisted.", - "type": "ENUM", - "flags": [ - { - "key": "page_guard", - "label": "page_guard", - "description": "Tracks modifications to individual memory pages, which are written to the capture file on calls to vkFlushMappedMemoryRanges, vkUnmapMemory, and vkQueueSubmit. Tracking modifications requires allocating shadow memory for all mapped memory." - }, - { - "key": "assisted", - "label": "assisted", - "description": "Expects the application to call vkFlushMappedMemoryRanges after memory is modified; the memory ranges specified to the vkFlushMappedMemoryRanges call will be written to the capture file during the call." - }, - { - "key": "unassisted", - "label": "unassisted", - "description": "Writes the full content of mapped memory to the capture file on calls to vkUnmapMemory and vkQueueSubmit. It is very inefficient and may be unusable with real-world applications that map large amounts of memory." - } - ], - "default": "page_guard", - "settings": [ - { - "key": "page_guard_copy_on_map", - "env": "GFXRECON_PAGE_GUARD_COPY_ON_MAP", - "label": "Page Guard Copy on Map", - "description": "When the page_guard memory tracking mode is enabled, copies the content of the mapped memory to the shadow memory immediately after the memory is mapped.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_separate_read", - "env": "GFXRECON_PAGE_GUARD_SEPARATE_READ", - "label": "Page Guard Separate Read Tracking", - "description": "When the page_guard memory tracking mode is enabled, copies the content of pages accessed for read from mapped memory to shadow memory on each read. Can overwrite unprocessed shadow memory content when an application is reading from and writing to the same page.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_external_memory", - "env": "GFXRECON_PAGE_GUARD_EXTERNAL_MEMORY", - "label": "Page Guard External Memory", - "description": "When the page_guard memory tracking mode is enabled, use the VK_EXT_external_memory_host extension to eliminate the need for shadow memory allocations. For each memory allocation from a host visible memory type, the capture layer will create an allocation from system memory, which it can monitor for write access, and provide that allocation to vkAllocateMemory as external memory. Only available on Windows.", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - } - ] - }, - { - "key": "log", - "label": "Log", - "description": "Control log messages.", - "type": "GROUP", - "settings": [ - { - "key": "log_level", - "env": "GFXRECON_LOG_LEVEL", - "label": "Level", - "description": "Specify the highest level message to log. Options are: debug, info, warning, error, and fatal. The specified level and all levels listed after it will be enabled for logging. For example, choosing the warning level will also enable the error and fatal levels.", - "type": "ENUM", - "flags": [ - { - "key": "debug", - "label": "debug, info, warning, error, fatal", - "description": "" - }, - { - "key": "info", - "label": "info, warning, error, fatal", - "description": "" - }, - { - "key": "warning", - "label": "warning, error, fatal", - "description": "" - }, - { - "key": "error", - "label": "error, fatal", - "description": "" - }, - { - "key": "fatal", - "label": "fatal", - "description": "" - } - ], - "default": "info" - }, - { - "key": "log_detailed", - "env": "GFXRECON_LOG_DETAILED", - "label": "Log Name and Line Number", - "description": "Include name and line number from the file responsible.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_console", - "env": "GFXRECON_LOG_OUTPUT_TO_CONSOLE", - "label": "Log Output to Console / stdout", - "description": "Log messages will be written to stdout.", - "type": "BOOL", - "default": true - }, - { - "key": "log_break_on_error", - "env": "GFXRECON_LOG_BREAK_ON_ERROR", - "label": "Trigger Debug Break on Error", - "description": "Trigger a debug break when logging an error.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_os_debug_string", - "env": "GFXRECON_LOG_OUTPUT_TO_OS_DEBUG_STRING", - "label": "Log Output to Debug Console", - "description": "Windows only option. Log messages will be written to the Debug Console with OutputDebugStringA", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false - }, - { - "key": "log_file", - "env": "GFXRECON_LOG_FILE", - "label": "Log File", - "description": "When set, log messages will be written to a file at the specified path. Default is: Empty string (file logging disabled).", - "type": "SAVE_FILE", - "filter": "*.txt", - "default": "", - "settings": [ - { - "key": "log_file_flush_after_write", - "env": "GFXRECON_LOG_FILE_FLUSH_AFTER_WRITE", - "label": "Log File Flush After Write", - "description": "Flush the log file to disk after each write when true.", - "type": "BOOL", - "default": false - }, - { - "key": "log_file_keep_open", - "env": "GFXRECON_LOG_FILE_KEEP_OPEN", - "label": "Log File Keep Open", - "description": "Keep the log file open between log messages when true, or close and reopen the log file for each message when false.", - "type": "BOOL", - "default": true - }, - { - "key": "log_file_create_new", - "env": "GFXRECON_LOG_FILE_CREATE_NEW", - "label": "Log File Overwrite", - "description": "Specifies that log file initialization should overwrite an existing file when true, or append to an existing file when false.", - "type": "BOOL", - "default": true - } - ] - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/141/VK_LAYER_LUNARG_monitor.json b/vkconfig_core/layers/141/VK_LAYER_LUNARG_monitor.json deleted file mode 100644 index b102ca9e07..0000000000 --- a/vkconfig_core/layers/141/VK_LAYER_LUNARG_monitor.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "file_format_version": "1.0.0", - "layer": { - "name": "VK_LAYER_LUNARG_monitor", - "library_path": ".\\VkLayer_monitor.dll", - "api_version": "1.2.141", - "implementation_version": "1", - "description": "Execution Monitoring Layer", - "introduction": "The monitor utility layer prints the real-time frames-per-second value to the application's title bar.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/monitor_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ] - } -} diff --git a/vkconfig_core/layers/141/VK_LAYER_LUNARG_screenshot.json b/vkconfig_core/layers/141/VK_LAYER_LUNARG_screenshot.json deleted file mode 100644 index 3448019103..0000000000 --- a/vkconfig_core/layers/141/VK_LAYER_LUNARG_screenshot.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_screenshot", - "type": "GLOBAL", - "library_path": ".\\VkLayer_screenshot.dll", - "api_version": "1.2.148", - "implementation_version": "1", - "description": "LunarG image capture layer", - "introduction": "The screenshot layer records frames to image files.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/screenshot_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "settings": [ - { - "key": "frames", - "env": "VK_SCREENSHOT_FRAMES", - "label": "Frames", - "description": "Comma separated list of frames to output as screen shots or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "" - }, - { - "key": "dir", - "env": "VK_SCREENSHOT_DIR", - "label": "Directory", - "description": "This can be set to specify the directory in which to create the screenshot files.", - "type": "SAVE_FOLDER", - "default": "" - }, - { - "key": "format", - "env": "VK_SCREENSHOT_FORMAT", - "label": "Format", - "description": "This can be set to a color space for the output.", - "type": "ENUM", - "flags": [ - { - "key": "UNORM", - "label": "UNORM", - "description": "" - }, - { - "key": "SNORM", - "label": "SNORM", - "description": "" - }, - { - "key": "USCALED", - "label": "USCALED", - "description": "" - }, - { - "key": "SSCALED", - "label": "SSCALED", - "description": "" - }, - { - "key": "UINT", - "label": "UINT", - "description": "" - }, - { - "key": "SINT", - "label": "SINT", - "description": "" - }, - { - "key": "SRGB", - "label": "SRGB", - "description": "" - }, - { - "key": "USE_SWAPCHAIN_COLORSPACE", - "label": "USE_SWAPCHAIN_COLORSPACE", - "description": "" - } - ], - "default": "USE_SWAPCHAIN_COLORSPACE" - } - ] - } - } -} diff --git a/vkconfig_core/layers/148/VK_LAYER_KHRONOS_validation.json b/vkconfig_core/layers/148/VK_LAYER_KHRONOS_validation.json deleted file mode 100644 index f0681faaf0..0000000000 --- a/vkconfig_core/layers/148/VK_LAYER_KHRONOS_validation.json +++ /dev/null @@ -1,404 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_KHRONOS_validation", - "library_path": ".\\VkLayer_khronos_validation.dll", - "api_version": "1.2.148", - "implementation_version": "1", - "description": "Khronos Validation Layer", - "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "9" - }, - { - "name": "VK_EXT_debug_utils", - "spec_version": "1" - }, - { - "name": "VK_EXT_validation_features", - "spec_version": "2" - } - ], - "device_extensions": [ - { - "name": "VK_EXT_debug_marker", - "spec_version": "4", - "entrypoints": [ - "vkDebugMarkerSetObjectTagEXT", - "vkDebugMarkerSetObjectNameEXT", - "vkCmdDebugMarkerBeginEXT", - "vkCmdDebugMarkerEndEXT", - "vkCmdDebugMarkerInsertEXT" - ] - }, - { - "name": "VK_EXT_validation_cache", - "spec_version": "1", - "entrypoints": [ - "vkCreateValidationCacheEXT", - "vkDestroyValidationCacheEXT", - "vkGetValidationCacheDataEXT", - "vkMergeValidationCachesEXT" - ] - }, - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Standard", - "description": "Good default validation setup that balance validation coverage and performance.", - "settings": [ - { - "key": "enables", - "value": [] - }, - { - "key": "disables", - "value": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - } - ] - }, - { - "label": "Reduced-Overhead", - "description": "Disables some checks in the interest of better performance.", - "settings": [ - { - "key": "enables", - "value": [ - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET", - "VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE" - ] - } - ] - }, - { - "label": "Best Practices", - "description": "Provides warnings about potential API misuse but valid usages of the API.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Shader Printf", - "description": "Debug shader code by \"printing\" any values of interest to the debug callback or stdout.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - }, - { - "key": "enable_message_limit", - "value": false - } - ] - } - ], - "settings": [ - { - "key": "debug_action", - "label": "Debug Action", - "description": "This indicates what action is to be taken when a layer wants to report information", - "type": "FLAGS", - "flags": [ - { - "key": "VK_DBG_LAYER_ACTION_LOG_MSG", - "label": "Log Message", - "description": "Log a txt message to stdout or to a log filename.", - "settings": [ - { - "key": "log_filename", - "label": "Log Filename", - "description": "Specifies the output filename", - "type": "SAVE_FILE", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "debug_action", - "value": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - } - ] - } - } - ] - }, - { - "key": "VK_DBG_LAYER_ACTION_CALLBACK", - "label": "Callback", - "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", - "view": "HIDDEN" - }, - { - "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", - "label": "Debug Output", - "description": "Log a txt message using the Windows OutputDebugString function.", - "platforms": [ "WINDOWS" ] - }, - { - "key": "VK_DBG_LAYER_ACTION_BREAK", - "label": "Break", - "description": "Trigger a breakpoint if a debugger is in use." - } - ], - "default": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - }, - { - "key": "report_flags", - "label": "Message Severity", - "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", - "type": "FLAGS", - "flags": [ - { - "key": "info", - "label": "Info", - "description": "Report informational messages." - }, - { - "key": "warn", - "label": "Warning", - "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." - }, - { - "key": "perf", - "label": "performance", - "description": "Report using the API in a way that may cause suboptimal performance." - }, - { - "key": "error", - "label": "Error", - "description": "Report errors in API usage." - }, - { - "key": "debug", - "label": "Debug", - "description": "For layer development. Report messages for debugging layer behavior.", - "view": "ADVANCED" - } - ], - "default": [ - "error", - "warn", - "perf" - ] - }, - { - "key": "enable_message_limit", - "label": "Limit Duplicated Messages", - "description": "Enable limitation of duplicate messages.", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "duplicate_message_limit", - "env": "VK_LAYER_DUPLICATE_MESSAGE_LIMIT", - "label": "Max Duplicated Messages", - "description": "Maximum number of times any single validation message would be reported.", - "type": "INT", - "default": 10, - "range": { - "min": 1 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "enable_message_limit", - "value": true - } - ] - } - } - ] - }, - { - "key": "message_id_filter", - "env": "VK_LAYER_MESSAGE_ID_FILTER", - "label": "Mute Message VUIDs", - "description": "List of VUIDs and VUID identifers which are to be IGNORED by the validation layer", - "type": "LIST", - "default": [] - }, - { - "key": "disables", - "env": "VK_LAYER_DISABLES", - "label": "Disables", - "description": "Setting an option here will disable areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "label": "Thread Safety", - "description": "Thread checks. It may help with performance to run with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check, or when debugging difficult application behaviors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "label": "Stateless Parameter", - "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "label": "Object Lifetime", - "description": "Object tracking checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", - "label": "Core", - "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "label": "Handle Wrapping", - "description": "Handle wrapping checks. Disable this feature if you are running into crashes when authoring new extensions or developing new Vulkan objects/structures" - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", - "label": "Shaders", - "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "label": "Command Buffer State", - "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "label": "Image Layout", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "label": "Query", - "description": "Checks for commands that use VkQueryPool objects.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "label": "Object in Use", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - } - ], - "default": [] - }, - { - "key": "enables", - "env": "VK_LAYER_ENABLES", - "label": "Enables", - "description": "Setting an option here will enable specialized areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT", - "label": "Debug Printf", - "description": "Enables processing of debug printf instructions in shaders and sending debug strings to the debug callback", - "url": "${LUNARG_SDK}/debug_printf.html", - "status": "STABLE", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "label": "GPU-Assisted", - "description": "Activating this feature instruments shader programs to generate additional diagnostic data.", - "url": "${LUNARG_SDK}/gpu_validation.html", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", - "label": "Reserve a descriptorSet binding slot", - "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", - "label": "Best Practices", - "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", - "url": "${LUNARG_SDK}/best_practices.html" - }, - { - "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM", - "label": "ARM-specific best practices", - "description": "Activating this feature enables the output of warnings related to ARM-specific misuse of the API, but which are not explicitly prohibited by the specification." - } - ], - "default": [] - } - ] - } - } -} diff --git a/vkconfig_core/layers/148/VK_LAYER_LUNARG_api_dump.json b/vkconfig_core/layers/148/VK_LAYER_LUNARG_api_dump.json deleted file mode 100644 index d3c4f5f62e..0000000000 --- a/vkconfig_core/layers/148/VK_LAYER_LUNARG_api_dump.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_api_dump", - "library_path": ".\\VkLayer_api_dump.dll", - "api_version": "1.2.148", - "implementation_version": "2", - "description": "LunarG API dump layer", - "introduction": "The API Dump utility layer prints API calls, parameters, and values to the identified output stream.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/api_dump_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "presets": [ - { - "label": "Console Output", - "description": "Output API dump to stdout", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "stdout" - }, - { - "key": "file", - "value": false - } - ] - }, - { - "label": "Text Output", - "description": "Output API dump to a text file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.txt" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "HTML Output", - "description": "Output API dump to a HTML file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "html" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.html" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "JSON Output", - "description": "Output API dump to a JSON file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "json" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.json" - }, - { - "key": "file", - "value": true - } - ] - } - ], - "settings": [ - { - "key": "output_range", - "env": "VK_APIDUMP_OUTPUT_RANGE", - "label": "Output Range", - "description": "Comma separated list of frames to output or a range of frames with a start, count, and optional interval separated by a dash. A count of 0 will output every frame after the start of the range. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "0-0" - }, - { - "key": "output_format", - "env": "VK_APIDUMP_OUTPUT_FORMAT", - "label": "Output Format", - "description": "Specifies the format used for output; can be HTML, JSON, or Text (default -- outputs plain text)", - "type": "ENUM", - "flags": [ - { - "key": "text", - "label": "Text", - "description": "Plain text" - }, - { - "key": "html", - "label": "HTML", - "description": "HTML" - }, - { - "key": "json", - "label": "JSON", - "description": "Json" - } - ], - "default": "text" - }, - { - "key": "file", - "label": "Output to File", - "description": "Setting this to true indicates that output should be written to file instead of stdout", - "type": "BOOL", - "default": false, - "settings": [ - { - "key": "log_filename", - "env": "VK_APIDUMP_LOG_FILENAME", - "label": "Log Filename", - "description": "Specifies the file to dump to when output files are enabled", - "type": "SAVE_FILE", - "filter": "*.txt,*.html,*.json", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "file", - "value": true - } - ] - } - } - ] - }, - { - "key": "flush", - "env": "VK_APIDUMP_FLUSH", - "label": "Log Flush After Write", - "description": "Setting this to true causes IO to be flushed after each API call that is written", - "type": "BOOL", - "default": true - }, - { - "key": "name_size", - "label": "Name Size", - "description": "The number of characters the name of a variable should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 1 - }, - "unit": "chars" - }, - { - "key": "show_types", - "label": "Show Types", - "description": "Dump types in addition to values", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "type_size", - "label": "Type Size", - "description": "The number of characters the name of a type should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 0 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "show_types", - "value": true - } - ] - } - } - ] - }, - { - "key": "show_timestamp", - "env": "VK_APIDUMP_TIMESTAMP", - "label": "Show Timestamp", - "description": "Show the timestamp of function calls since start in microseconds", - "type": "BOOL", - "default": false - }, - { - "key": "show_shader", - "label": "Show Shader", - "description": "Dump the shader binary code in pCode", - "type": "BOOL", - "default": false - }, - { - "key": "detailed", - "env": "VK_APIDUMP_DETAILED", - "label": "Show Parameter Details", - "description": "Dump parameter details in addition to API calls", - "type": "BOOL", - "default": true - }, - { - "key": "no_addr", - "env": "VK_APIDUMP_NO_ADDR", - "label": "Hide Addresses", - "description": "Dump \"address\" in place of hex addresses", - "type": "BOOL", - "default": false - }, - { - "key": "use_spaces", - "label": "Use Spaces", - "description": "Setting this to true causes all tab characters to be replaced with spaces", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "indent_size", - "label": "Indent Size", - "description": "Specifies the number of spaces that a tab is equal to", - "type": "INT", - "default": 4, - "range": { - "min": 1, - "max": 16 - }, - "unit": "chars", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "use_spaces", - "value": true - } - ] - } - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/148/VK_LAYER_LUNARG_gfxreconstruct.json b/vkconfig_core/layers/148/VK_LAYER_LUNARG_gfxreconstruct.json deleted file mode 100644 index ec324fcda4..0000000000 --- a/vkconfig_core/layers/148/VK_LAYER_LUNARG_gfxreconstruct.json +++ /dev/null @@ -1,409 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_gfxreconstruct", - "type": "GLOBAL", - "library_path": ".\\VkLayer_gfxreconstruct.dll", - "api_version": "1.2.148", - "status": "BETA", - "implementation_version": "36866", - "description": "GFXReconstruct Capture Layer Version 0.9.2", - "introduction": "The GFXReconstruct Capture Layer intercepts Vulkan API calls and logs them to a capture file. Other tools in the GFXReconstruct suite can inspect, modify, or replay capture files generated by this component.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/capture_tools.html", - "platforms": [ "WINDOWS", "LINUX", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Initialization", - "description": "Capture the first two frames.", - "settings": [ - { - "key": "capture_trigger", - "value": "" - }, - { - "key": "capture_frames", - "value": "1-2" - }, - { - "key": "memory_tracking_mode", - "value": "unassisted" - } - ] - }, - { - "label": "Range", - "description": "Capture a range of frames between presses of the F5 key.", - "settings": [ - { - "key": "capture_trigger", - "value": "F5" - }, - { - "key": "capture_frames", - "value": "" - }, - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - ], - "settings": [ - { - "key": "capture_trigger", - "env": "GFXRECON_CAPTURE_TRIGGER", - "label": "Hotkey Capture Trigger", - "description": "Specify a hotkey (any one of F1-F12, TAB, CONTROL) that will be used to start/stop capture. Example: F3 will set the capture trigger to F3 hotkey. One capture file will be generated for each pair of start/stop hotkey presses. Default is: Empty string (hotkey capture trigger is disabled).", - "type": "ENUM", - "flags": [ - { - "key": "", - "label": "None", - "description": "" - }, - { - "key": "F1", - "label": "F1", - "description": "" - }, - { - "key": "F2", - "label": "F2", - "description": "" - }, - { - "key": "F3", - "label": "F3", - "description": "" - }, - { - "key": "F4", - "label": "F4", - "description": "" - }, - { - "key": "F5", - "label": "F5", - "description": "" - }, - { - "key": "F6", - "label": "F6", - "description": "" - }, - { - "key": "F7", - "label": "F7", - "description": "" - }, - { - "key": "F8", - "label": "F8", - "description": "" - }, - { - "key": "F9", - "label": "F9", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F11", - "label": "F11", - "description": "" - }, - { - "key": "F12", - "label": "F12", - "description": "" - }, - { - "key": "TAB", - "label": "TAB", - "description": "" - }, - { - "key": "CONTROL", - "label": "CONTROL", - "description": "" - } - ], - "default": "" - }, - { - "key": "capture_frames", - "env": "GFXRECON_CAPTURE_FRAMES", - "label": "Capture Specific Frames", - "description": "Specify one or more comma-separated frame ranges to capture. Each range will be written to its own file. A frame range can be specified as a single value, to specify a single frame to capture, or as two hyphenated values, to specify the first and last frame to capture. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: 200,301-305 will create two capture files, one containing a single frame and one containing five frames. Default is: Empty string (all frames are captured).", - "type": "STRING", - "default": "" - }, - { - "key": "capture_file", - "env": "GFXRECON_CAPTURE_FILE", - "label": "Capture File Name", - "description": "Path to use when creating the capture file. Default is: gfxrecon_capture.gfxr", - "type": "SAVE_FILE", - "filter": "*.gfxr", - "default": "${VK_LOCAL}/gfxrecon_capture.gfxr", - "settings": [ - { - "key": "capture_file_timestamp", - "env": "GFXRECON_CAPTURE_FILE_TIMESTAMP", - "label": "Capture File Name with Timestamp", - "description": "Add a timestamp (yyyymmddThhmmss) postfix to the capture file name.", - "type": "BOOL", - "default": true - }, - { - "key": "capture_file_flush", - "env": "GFXRECON_CAPTURE_FILE_FLUSH", - "label": "Capture File Flush After Write", - "description": "Flush output stream after each packet is written to the capture file. Default is: false.", - "type": "BOOL", - "default": true - } - ] - }, - { - "key": "capture_compression_type", - "env": "GFXRECON_CAPTURE_COMPRESSION_TYPE", - "label": "Compression Format", - "description": "Compression format to use with the capture file. Valid values are: LZ4, ZLIB, ZSTD, and NONE. Default is: LZ4", - "type": "ENUM", - "flags": [ - { - "key": "LZ4", - "label": "LZ4", - "description": "Fastest compression algorithm that favors performance over compression ratio." - }, - { - "key": "ZLIB", - "label": "ZLIB", - "description": "Widely used compression algorithm with better compression ratio than LZ4 but worse performance." - }, - { - "key": "ZSTD", - "label": "ZSTD", - "description": "Newer compression algorithm with better compression ratio and performance than ZLIB, though not as fast as LZ4." - }, - { - "key": "NONE", - "label": "NONE", - "description": "No compression" - } - ], - "default": "LZ4" - }, - { - "key": "memory_tracking_mode", - "env": "GFXRECON_MEMORY_TRACKING_MODE", - "label": "Memory Tracking Mode", - "description": "Specifies the memory tracking mode to use for detecting modifications to mapped Vulkan memory objects. Available options are: page_guard, assisted, and unassisted.", - "type": "ENUM", - "flags": [ - { - "key": "page_guard", - "label": "page_guard", - "description": "Tracks modifications to individual memory pages, which are written to the capture file on calls to vkFlushMappedMemoryRanges, vkUnmapMemory, and vkQueueSubmit. Tracking modifications requires allocating shadow memory for all mapped memory." - }, - { - "key": "assisted", - "label": "assisted", - "description": "Expects the application to call vkFlushMappedMemoryRanges after memory is modified; the memory ranges specified to the vkFlushMappedMemoryRanges call will be written to the capture file during the call." - }, - { - "key": "unassisted", - "label": "unassisted", - "description": "Writes the full content of mapped memory to the capture file on calls to vkUnmapMemory and vkQueueSubmit. It is very inefficient and may be unusable with real-world applications that map large amounts of memory." - } - ], - "default": "page_guard", - "settings": [ - { - "key": "page_guard_copy_on_map", - "env": "GFXRECON_PAGE_GUARD_COPY_ON_MAP", - "label": "Page Guard Copy on Map", - "description": "When the page_guard memory tracking mode is enabled, copies the content of the mapped memory to the shadow memory immediately after the memory is mapped.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_separate_read", - "env": "GFXRECON_PAGE_GUARD_SEPARATE_READ", - "label": "Page Guard Separate Read Tracking", - "description": "When the page_guard memory tracking mode is enabled, copies the content of pages accessed for read from mapped memory to shadow memory on each read. Can overwrite unprocessed shadow memory content when an application is reading from and writing to the same page.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_external_memory", - "env": "GFXRECON_PAGE_GUARD_EXTERNAL_MEMORY", - "label": "Page Guard External Memory", - "description": "When the page_guard memory tracking mode is enabled, use the VK_EXT_external_memory_host extension to eliminate the need for shadow memory allocations. For each memory allocation from a host visible memory type, the capture layer will create an allocation from system memory, which it can monitor for write access, and provide that allocation to vkAllocateMemory as external memory. Only available on Windows.", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - } - ] - }, - { - "key": "log", - "label": "Log", - "description": "Control log messages.", - "type": "GROUP", - "settings": [ - { - "key": "log_level", - "env": "GFXRECON_LOG_LEVEL", - "label": "Level", - "description": "Specify the highest level message to log. Options are: debug, info, warning, error, and fatal. The specified level and all levels listed after it will be enabled for logging. For example, choosing the warning level will also enable the error and fatal levels.", - "type": "ENUM", - "flags": [ - { - "key": "debug", - "label": "debug, info, warning, error, fatal", - "description": "" - }, - { - "key": "info", - "label": "info, warning, error, fatal", - "description": "" - }, - { - "key": "warning", - "label": "warning, error, fatal", - "description": "" - }, - { - "key": "error", - "label": "error, fatal", - "description": "" - }, - { - "key": "fatal", - "label": "fatal", - "description": "" - } - ], - "default": "info" - }, - { - "key": "log_detailed", - "env": "GFXRECON_LOG_DETAILED", - "label": "Log Name and Line Number", - "description": "Include name and line number from the file responsible.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_console", - "env": "GFXRECON_LOG_OUTPUT_TO_CONSOLE", - "label": "Log Output to Console / stdout", - "description": "Log messages will be written to stdout.", - "type": "BOOL", - "default": true - }, - { - "key": "log_break_on_error", - "env": "GFXRECON_LOG_BREAK_ON_ERROR", - "label": "Trigger Debug Break on Error", - "description": "Trigger a debug break when logging an error.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_os_debug_string", - "env": "GFXRECON_LOG_OUTPUT_TO_OS_DEBUG_STRING", - "label": "Log Output to Debug Console", - "description": "Windows only option. Log messages will be written to the Debug Console with OutputDebugStringA", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false - }, - { - "key": "log_file", - "env": "GFXRECON_LOG_FILE", - "label": "Log File", - "description": "When set, log messages will be written to a file at the specified path. Default is: Empty string (file logging disabled).", - "type": "SAVE_FILE", - "filter": "*.txt", - "default": "", - "settings": [ - { - "key": "log_file_flush_after_write", - "env": "GFXRECON_LOG_FILE_FLUSH_AFTER_WRITE", - "label": "Log File Flush After Write", - "description": "Flush the log file to disk after each write when true.", - "type": "BOOL", - "default": false - }, - { - "key": "log_file_keep_open", - "env": "GFXRECON_LOG_FILE_KEEP_OPEN", - "label": "Log File Keep Open", - "description": "Keep the log file open between log messages when true, or close and reopen the log file for each message when false.", - "type": "BOOL", - "default": true - }, - { - "key": "log_file_create_new", - "env": "GFXRECON_LOG_FILE_CREATE_NEW", - "label": "Log File Overwrite", - "description": "Specifies that log file initialization should overwrite an existing file when true, or append to an existing file when false.", - "type": "BOOL", - "default": true - } - ] - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/148/VK_LAYER_LUNARG_monitor.json b/vkconfig_core/layers/148/VK_LAYER_LUNARG_monitor.json deleted file mode 100644 index 0f1e412a99..0000000000 --- a/vkconfig_core/layers/148/VK_LAYER_LUNARG_monitor.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "file_format_version": "1.0.0", - "layer": { - "name": "VK_LAYER_LUNARG_monitor", - "library_path": ".\\VkLayer_monitor.dll", - "api_version": "1.2.148", - "implementation_version": "1", - "description": "Execution Monitoring Layer", - "introduction": "The monitor utility layer prints the real-time frames-per-second value to the application's title bar.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/monitor_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ] - } -} diff --git a/vkconfig_core/layers/148/VK_LAYER_LUNARG_screenshot.json b/vkconfig_core/layers/148/VK_LAYER_LUNARG_screenshot.json deleted file mode 100644 index 3448019103..0000000000 --- a/vkconfig_core/layers/148/VK_LAYER_LUNARG_screenshot.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_screenshot", - "type": "GLOBAL", - "library_path": ".\\VkLayer_screenshot.dll", - "api_version": "1.2.148", - "implementation_version": "1", - "description": "LunarG image capture layer", - "introduction": "The screenshot layer records frames to image files.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/screenshot_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "settings": [ - { - "key": "frames", - "env": "VK_SCREENSHOT_FRAMES", - "label": "Frames", - "description": "Comma separated list of frames to output as screen shots or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "" - }, - { - "key": "dir", - "env": "VK_SCREENSHOT_DIR", - "label": "Directory", - "description": "This can be set to specify the directory in which to create the screenshot files.", - "type": "SAVE_FOLDER", - "default": "" - }, - { - "key": "format", - "env": "VK_SCREENSHOT_FORMAT", - "label": "Format", - "description": "This can be set to a color space for the output.", - "type": "ENUM", - "flags": [ - { - "key": "UNORM", - "label": "UNORM", - "description": "" - }, - { - "key": "SNORM", - "label": "SNORM", - "description": "" - }, - { - "key": "USCALED", - "label": "USCALED", - "description": "" - }, - { - "key": "SSCALED", - "label": "SSCALED", - "description": "" - }, - { - "key": "UINT", - "label": "UINT", - "description": "" - }, - { - "key": "SINT", - "label": "SINT", - "description": "" - }, - { - "key": "SRGB", - "label": "SRGB", - "description": "" - }, - { - "key": "USE_SWAPCHAIN_COLORSPACE", - "label": "USE_SWAPCHAIN_COLORSPACE", - "description": "" - } - ], - "default": "USE_SWAPCHAIN_COLORSPACE" - } - ] - } - } -} diff --git a/vkconfig_core/layers/154/VK_LAYER_KHRONOS_validation.json b/vkconfig_core/layers/154/VK_LAYER_KHRONOS_validation.json deleted file mode 100644 index 8b60336c98..0000000000 --- a/vkconfig_core/layers/154/VK_LAYER_KHRONOS_validation.json +++ /dev/null @@ -1,432 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_KHRONOS_validation", - "library_path": ".\\VkLayer_khronos_validation.dll", - "api_version": "1.2.154", - "implementation_version": "1", - "description": "Khronos Validation Layer", - "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "9" - }, - { - "name": "VK_EXT_debug_utils", - "spec_version": "1" - }, - { - "name": "VK_EXT_validation_features", - "spec_version": "2" - } - ], - "device_extensions": [ - { - "name": "VK_EXT_debug_marker", - "spec_version": "4", - "entrypoints": [ - "vkDebugMarkerSetObjectTagEXT", - "vkDebugMarkerSetObjectNameEXT", - "vkCmdDebugMarkerBeginEXT", - "vkCmdDebugMarkerEndEXT", - "vkCmdDebugMarkerInsertEXT" - ] - }, - { - "name": "VK_EXT_validation_cache", - "spec_version": "1", - "entrypoints": [ - "vkCreateValidationCacheEXT", - "vkDestroyValidationCacheEXT", - "vkGetValidationCacheDataEXT", - "vkMergeValidationCachesEXT" - ] - }, - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Standard", - "description": "Good default validation setup that balance validation coverage and performance.", - "settings": [ - { - "key": "enables", - "value": [] - }, - { - "key": "disables", - "value": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - } - ] - }, - { - "label": "Reduced-Overhead", - "description": "Disables some checks in the interest of better performance.", - "settings": [ - { - "key": "enables", - "value": [ - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET", - "VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE" - ] - } - ] - }, - { - "label": "Best Practices", - "description": "Provides warnings about potential API misuse but valid usages of the API.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Synchronization", - "description": "Identify resource access conflicts due to missing or incorrect synchronization operations between actions reading or writing the same regions of memory.", - "status": "ALPHA", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Shader Printf", - "description": "Debug shader code by \"printing\" any values of interest to the debug callback or stdout.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - }, - { - "key": "enable_message_limit", - "value": false - } - ] - } - ], - "settings": [ - { - "key": "debug_action", - "label": "Debug Action", - "description": "This indicates what action is to be taken when a layer wants to report information", - "type": "FLAGS", - "flags": [ - { - "key": "VK_DBG_LAYER_ACTION_LOG_MSG", - "label": "Log Message", - "description": "Log a txt message to stdout or to a log filename.", - "settings": [ - { - "key": "log_filename", - "label": "Log Filename", - "description": "Specifies the output filename", - "type": "SAVE_FILE", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "debug_action", - "value": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - } - ] - } - } - ] - }, - { - "key": "VK_DBG_LAYER_ACTION_CALLBACK", - "label": "Callback", - "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", - "view": "HIDDEN" - }, - { - "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", - "label": "Debug Output", - "description": "Log a txt message using the Windows OutputDebugString function.", - "platforms": [ "WINDOWS" ] - }, - { - "key": "VK_DBG_LAYER_ACTION_BREAK", - "label": "Break", - "description": "Trigger a breakpoint if a debugger is in use." - } - ], - "default": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - }, - { - "key": "report_flags", - "label": "Message Severity", - "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", - "type": "FLAGS", - "flags": [ - { - "key": "info", - "label": "Info", - "description": "Report informational messages." - }, - { - "key": "warn", - "label": "Warning", - "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." - }, - { - "key": "perf", - "label": "performance", - "description": "Report using the API in a way that may cause suboptimal performance." - }, - { - "key": "error", - "label": "Error", - "description": "Report errors in API usage." - }, - { - "key": "debug", - "label": "Debug", - "description": "For layer development. Report messages for debugging layer behavior.", - "view": "ADVANCED" - } - ], - "default": [ - "error", - "warn", - "perf" - ] - }, - { - "key": "enable_message_limit", - "label": "Limit Duplicated Messages", - "description": "Enable limitation of duplicate messages.", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "duplicate_message_limit", - "env": "VK_LAYER_DUPLICATE_MESSAGE_LIMIT", - "label": "Max Duplicated Messages", - "description": "Maximum number of times any single validation message would be reported.", - "type": "INT", - "default": 10, - "range": { - "min": 1 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "enable_message_limit", - "value": true - } - ] - } - } - ] - }, - { - "key": "message_id_filter", - "env": "VK_LAYER_MESSAGE_ID_FILTER", - "label": "Mute Message VUIDs", - "description": "List of VUIDs and VUID identifers which are to be IGNORED by the validation layer", - "type": "LIST", - "default": [] - }, - { - "key": "disables", - "env": "VK_LAYER_DISABLES", - "label": "Disables", - "description": "Setting an option here will disable areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "label": "Thread Safety", - "description": "Thread checks. It may help with performance to run with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check, or when debugging difficult application behaviors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "label": "Stateless Parameter", - "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "label": "Object Lifetime", - "description": "Object tracking checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", - "label": "Core", - "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "label": "Handle Wrapping", - "description": "Handle wrapping checks. Disable this feature if you are running into crashes when authoring new extensions or developing new Vulkan objects/structures" - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", - "label": "Shaders", - "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "label": "Command Buffer State", - "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "label": "Image Layout", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "label": "Query", - "description": "Checks for commands that use VkQueryPool objects.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "label": "Object in Use", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - } - ], - "default": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - }, - { - "key": "enables", - "env": "VK_LAYER_ENABLES", - "label": "Enables", - "description": "Setting an option here will enable specialized areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", - "label": "Synchronization", - "description": "This feature reports resource access conflicts due to missing or incorrect synchronization operations between actions (Draw, Copy, Dispatch, Blit) reading or writing the same regions of memory.", - "url": "${LUNARG_SDK}/synchronization_usage.html", - "status": "ALPHA" - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT", - "label": "Debug Printf", - "description": "Enables processing of debug printf instructions in shaders and sending debug strings to the debug callback", - "url": "${LUNARG_SDK}/debug_printf.html", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "label": "GPU-Assisted", - "description": "Activating this feature instruments shader programs to generate additional diagnostic data.", - "url": "${LUNARG_SDK}/gpu_validation.html", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", - "label": "Reserve a descriptorSet binding slot", - "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", - "label": "Best Practices", - "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", - "url": "${LUNARG_SDK}/best_practices.html" - }, - { - "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM", - "label": "ARM-specific best practices", - "description": "Activating this feature enables the output of warnings related to ARM-specific misuse of the API, but which are not explicitly prohibited by the specification." - } - ], - "default": [] - } - ] - } - } -} diff --git a/vkconfig_core/layers/154/VK_LAYER_LUNARG_api_dump.json b/vkconfig_core/layers/154/VK_LAYER_LUNARG_api_dump.json deleted file mode 100644 index b0e109149b..0000000000 --- a/vkconfig_core/layers/154/VK_LAYER_LUNARG_api_dump.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_api_dump", - "library_path": ".\\VkLayer_api_dump.dll", - "api_version": "1.2.154", - "implementation_version": "2", - "description": "LunarG API dump layer", - "introduction": "The API Dump utility layer prints API calls, parameters, and values to the identified output stream.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/api_dump_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "presets": [ - { - "label": "Console Output", - "description": "Output API dump to stdout", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "stdout" - }, - { - "key": "file", - "value": false - } - ] - }, - { - "label": "Text Output", - "description": "Output API dump to a text file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.txt" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "HTML Output", - "description": "Output API dump to a HTML file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "html" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.html" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "JSON Output", - "description": "Output API dump to a JSON file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "json" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.json" - }, - { - "key": "file", - "value": true - } - ] - } - ], - "settings": [ - { - "key": "output_range", - "env": "VK_APIDUMP_OUTPUT_RANGE", - "label": "Output Range", - "description": "Comma separated list of frames to output or a range of frames with a start, count, and optional interval separated by a dash. A count of 0 will output every frame after the start of the range. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "0-0" - }, - { - "key": "output_format", - "env": "VK_APIDUMP_OUTPUT_FORMAT", - "label": "Output Format", - "description": "Specifies the format used for output; can be HTML, JSON, or Text (default -- outputs plain text)", - "type": "ENUM", - "flags": [ - { - "key": "text", - "label": "Text", - "description": "Plain text" - }, - { - "key": "html", - "label": "HTML", - "description": "HTML" - }, - { - "key": "json", - "label": "JSON", - "description": "Json" - } - ], - "default": "text" - }, - { - "key": "file", - "label": "Output to File", - "description": "Setting this to true indicates that output should be written to file instead of stdout", - "type": "BOOL", - "default": false, - "settings": [ - { - "key": "log_filename", - "env": "VK_APIDUMP_LOG_FILENAME", - "label": "Log Filename", - "description": "Specifies the file to dump to when output files are enabled", - "type": "SAVE_FILE", - "filter": "*.txt,*.html,*.json", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "file", - "value": true - } - ] - } - } - ] - }, - { - "key": "flush", - "env": "VK_APIDUMP_FLUSH", - "label": "Log Flush After Write", - "description": "Setting this to true causes IO to be flushed after each API call that is written", - "type": "BOOL", - "default": true - }, - { - "key": "name_size", - "label": "Name Size", - "description": "The number of characters the name of a variable should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 1 - }, - "unit": "chars" - }, - { - "key": "show_types", - "label": "Show Types", - "description": "Dump types in addition to values", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "type_size", - "label": "Type Size", - "description": "The number of characters the name of a type should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 0 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "show_types", - "value": true - } - ] - } - } - ] - }, - { - "key": "show_timestamp", - "env": "VK_APIDUMP_TIMESTAMP", - "label": "Show Timestamp", - "description": "Show the timestamp of function calls since start in microseconds", - "type": "BOOL", - "default": false - }, - { - "key": "show_shader", - "label": "Show Shader", - "description": "Dump the shader binary code in pCode", - "type": "BOOL", - "default": false - }, - { - "key": "detailed", - "env": "VK_APIDUMP_DETAILED", - "label": "Show Parameter Details", - "description": "Dump parameter details in addition to API calls", - "type": "BOOL", - "default": true - }, - { - "key": "no_addr", - "env": "VK_APIDUMP_NO_ADDR", - "label": "Hide Addresses", - "description": "Dump \"address\" in place of hex addresses", - "type": "BOOL", - "default": false - }, - { - "key": "use_spaces", - "label": "Use Spaces", - "description": "Setting this to true causes all tab characters to be replaced with spaces", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "indent_size", - "label": "Indent Size", - "description": "Specifies the number of spaces that a tab is equal to", - "type": "INT", - "default": 4, - "range": { - "min": 1, - "max": 16 - }, - "unit": "chars", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "use_spaces", - "value": true - } - ] - } - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/154/VK_LAYER_LUNARG_gfxreconstruct.json b/vkconfig_core/layers/154/VK_LAYER_LUNARG_gfxreconstruct.json deleted file mode 100644 index 027be30c70..0000000000 --- a/vkconfig_core/layers/154/VK_LAYER_LUNARG_gfxreconstruct.json +++ /dev/null @@ -1,408 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_gfxreconstruct", - "type": "GLOBAL", - "library_path": ".\\VkLayer_gfxreconstruct.dll", - "api_version": "1.2.154", - "implementation_version": "36867", - "description": "GFXReconstruct Capture Layer Version 0.9.3", - "introduction": "The GFXReconstruct Capture Layer intercepts Vulkan API calls and logs them to a capture file. Other tools in the GFXReconstruct suite can inspect, modify, or replay capture files generated by this component.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/capture_tools.html", - "platforms": [ "WINDOWS", "LINUX", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Initialization", - "description": "Capture the first two frames.", - "settings": [ - { - "key": "capture_trigger", - "value": "" - }, - { - "key": "capture_frames", - "value": "1-2" - }, - { - "key": "memory_tracking_mode", - "value": "unassisted" - } - ] - }, - { - "label": "Range", - "description": "Capture a range of frames between presses of the F5 key.", - "settings": [ - { - "key": "capture_trigger", - "value": "F5" - }, - { - "key": "capture_frames", - "value": "" - }, - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - ], - "settings": [ - { - "key": "capture_trigger", - "env": "GFXRECON_CAPTURE_TRIGGER", - "label": "Hotkey Capture Trigger", - "description": "Specify a hotkey (any one of F1-F12, TAB, CONTROL) that will be used to start/stop capture. Example: F3 will set the capture trigger to F3 hotkey. One capture file will be generated for each pair of start/stop hotkey presses. Default is: Empty string (hotkey capture trigger is disabled).", - "type": "ENUM", - "flags": [ - { - "key": "", - "label": "None", - "description": "" - }, - { - "key": "F1", - "label": "F1", - "description": "" - }, - { - "key": "F2", - "label": "F2", - "description": "" - }, - { - "key": "F3", - "label": "F3", - "description": "" - }, - { - "key": "F4", - "label": "F4", - "description": "" - }, - { - "key": "F5", - "label": "F5", - "description": "" - }, - { - "key": "F6", - "label": "F6", - "description": "" - }, - { - "key": "F7", - "label": "F7", - "description": "" - }, - { - "key": "F8", - "label": "F8", - "description": "" - }, - { - "key": "F9", - "label": "F9", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F11", - "label": "F11", - "description": "" - }, - { - "key": "F12", - "label": "F12", - "description": "" - }, - { - "key": "TAB", - "label": "TAB", - "description": "" - }, - { - "key": "CONTROL", - "label": "CONTROL", - "description": "" - } - ], - "default": "" - }, - { - "key": "capture_frames", - "env": "GFXRECON_CAPTURE_FRAMES", - "label": "Capture Specific Frames", - "description": "Specify one or more comma-separated frame ranges to capture. Each range will be written to its own file. A frame range can be specified as a single value, to specify a single frame to capture, or as two hyphenated values, to specify the first and last frame to capture. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: 200,301-305 will create two capture files, one containing a single frame and one containing five frames. Default is: Empty string (all frames are captured).", - "type": "STRING", - "default": "" - }, - { - "key": "capture_file", - "env": "GFXRECON_CAPTURE_FILE", - "label": "Capture File Name", - "description": "Path to use when creating the capture file. Default is: gfxrecon_capture.gfxr", - "type": "SAVE_FILE", - "filter": "*.gfxr", - "default": "${VK_LOCAL}/gfxrecon_capture.gfxr", - "settings": [ - { - "key": "capture_file_timestamp", - "env": "GFXRECON_CAPTURE_FILE_TIMESTAMP", - "label": "Capture File Name with Timestamp", - "description": "Add a timestamp (yyyymmddThhmmss) postfix to the capture file name.", - "type": "BOOL", - "default": true - }, - { - "key": "capture_file_flush", - "env": "GFXRECON_CAPTURE_FILE_FLUSH", - "label": "Capture File Flush After Write", - "description": "Flush output stream after each packet is written to the capture file. Default is: false.", - "type": "BOOL", - "default": true - } - ] - }, - { - "key": "capture_compression_type", - "env": "GFXRECON_CAPTURE_COMPRESSION_TYPE", - "label": "Compression Format", - "description": "Compression format to use with the capture file. Valid values are: LZ4, ZLIB, ZSTD, and NONE. Default is: LZ4", - "type": "ENUM", - "flags": [ - { - "key": "LZ4", - "label": "LZ4", - "description": "Fastest compression algorithm that favors performance over compression ratio." - }, - { - "key": "ZLIB", - "label": "ZLIB", - "description": "Widely used compression algorithm with better compression ratio than LZ4 but worse performance." - }, - { - "key": "ZSTD", - "label": "ZSTD", - "description": "Newer compression algorithm with better compression ratio and performance than ZLIB, though not as fast as LZ4." - }, - { - "key": "NONE", - "label": "NONE", - "description": "No compression" - } - ], - "default": "LZ4" - }, - { - "key": "memory_tracking_mode", - "env": "GFXRECON_MEMORY_TRACKING_MODE", - "label": "Memory Tracking Mode", - "description": "Specifies the memory tracking mode to use for detecting modifications to mapped Vulkan memory objects. Available options are: page_guard, assisted, and unassisted.", - "type": "ENUM", - "flags": [ - { - "key": "page_guard", - "label": "page_guard", - "description": "Tracks modifications to individual memory pages, which are written to the capture file on calls to vkFlushMappedMemoryRanges, vkUnmapMemory, and vkQueueSubmit. Tracking modifications requires allocating shadow memory for all mapped memory." - }, - { - "key": "assisted", - "label": "assisted", - "description": "Expects the application to call vkFlushMappedMemoryRanges after memory is modified; the memory ranges specified to the vkFlushMappedMemoryRanges call will be written to the capture file during the call." - }, - { - "key": "unassisted", - "label": "unassisted", - "description": "Writes the full content of mapped memory to the capture file on calls to vkUnmapMemory and vkQueueSubmit. It is very inefficient and may be unusable with real-world applications that map large amounts of memory." - } - ], - "default": "page_guard", - "settings": [ - { - "key": "page_guard_copy_on_map", - "env": "GFXRECON_PAGE_GUARD_COPY_ON_MAP", - "label": "Page Guard Copy on Map", - "description": "When the page_guard memory tracking mode is enabled, copies the content of the mapped memory to the shadow memory immediately after the memory is mapped.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_separate_read", - "env": "GFXRECON_PAGE_GUARD_SEPARATE_READ", - "label": "Page Guard Separate Read Tracking", - "description": "When the page_guard memory tracking mode is enabled, copies the content of pages accessed for read from mapped memory to shadow memory on each read. Can overwrite unprocessed shadow memory content when an application is reading from and writing to the same page.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_external_memory", - "env": "GFXRECON_PAGE_GUARD_EXTERNAL_MEMORY", - "label": "Page Guard External Memory", - "description": "When the page_guard memory tracking mode is enabled, use the VK_EXT_external_memory_host extension to eliminate the need for shadow memory allocations. For each memory allocation from a host visible memory type, the capture layer will create an allocation from system memory, which it can monitor for write access, and provide that allocation to vkAllocateMemory as external memory. Only available on Windows.", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - } - ] - }, - { - "key": "log", - "label": "Log", - "description": "Control log messages.", - "type": "GROUP", - "settings": [ - { - "key": "log_level", - "env": "GFXRECON_LOG_LEVEL", - "label": "Level", - "description": "Specify the highest level message to log. Options are: debug, info, warning, error, and fatal. The specified level and all levels listed after it will be enabled for logging. For example, choosing the warning level will also enable the error and fatal levels.", - "type": "ENUM", - "flags": [ - { - "key": "debug", - "label": "debug, info, warning, error, fatal", - "description": "" - }, - { - "key": "info", - "label": "info, warning, error, fatal", - "description": "" - }, - { - "key": "warning", - "label": "warning, error, fatal", - "description": "" - }, - { - "key": "error", - "label": "error, fatal", - "description": "" - }, - { - "key": "fatal", - "label": "fatal", - "description": "" - } - ], - "default": "info" - }, - { - "key": "log_detailed", - "env": "GFXRECON_LOG_DETAILED", - "label": "Log Name and Line Number", - "description": "Include name and line number from the file responsible.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_console", - "env": "GFXRECON_LOG_OUTPUT_TO_CONSOLE", - "label": "Log Output to Console / stdout", - "description": "Log messages will be written to stdout.", - "type": "BOOL", - "default": true - }, - { - "key": "log_break_on_error", - "env": "GFXRECON_LOG_BREAK_ON_ERROR", - "label": "Trigger Debug Break on Error", - "description": "Trigger a debug break when logging an error.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_os_debug_string", - "env": "GFXRECON_LOG_OUTPUT_TO_OS_DEBUG_STRING", - "label": "Log Output to Debug Console", - "description": "Windows only option. Log messages will be written to the Debug Console with OutputDebugStringA", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false - }, - { - "key": "log_file", - "env": "GFXRECON_LOG_FILE", - "label": "Log File", - "description": "When set, log messages will be written to a file at the specified path. Default is: Empty string (file logging disabled).", - "type": "SAVE_FILE", - "filter": "*.txt", - "default": "", - "settings": [ - { - "key": "log_file_flush_after_write", - "env": "GFXRECON_LOG_FILE_FLUSH_AFTER_WRITE", - "label": "Log File Flush After Write", - "description": "Flush the log file to disk after each write when true.", - "type": "BOOL", - "default": false - }, - { - "key": "log_file_keep_open", - "env": "GFXRECON_LOG_FILE_KEEP_OPEN", - "label": "Log File Keep Open", - "description": "Keep the log file open between log messages when true, or close and reopen the log file for each message when false.", - "type": "BOOL", - "default": true - }, - { - "key": "log_file_create_new", - "env": "GFXRECON_LOG_FILE_CREATE_NEW", - "label": "Log File Overwrite", - "description": "Specifies that log file initialization should overwrite an existing file when true, or append to an existing file when false.", - "type": "BOOL", - "default": true - } - ] - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/154/VK_LAYER_LUNARG_monitor.json b/vkconfig_core/layers/154/VK_LAYER_LUNARG_monitor.json deleted file mode 100644 index d27037c416..0000000000 --- a/vkconfig_core/layers/154/VK_LAYER_LUNARG_monitor.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "file_format_version": "1.0.0", - "layer": { - "name": "VK_LAYER_LUNARG_monitor", - "library_path": ".\\VkLayer_monitor.dll", - "api_version": "1.2.154", - "implementation_version": "1", - "description": "Execution Monitoring Layer", - "introduction": "The monitor utility layer prints the real-time frames-per-second value to the application's title bar.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/monitor_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ] - } -} diff --git a/vkconfig_core/layers/154/VK_LAYER_LUNARG_screenshot.json b/vkconfig_core/layers/154/VK_LAYER_LUNARG_screenshot.json deleted file mode 100644 index 42c77c9654..0000000000 --- a/vkconfig_core/layers/154/VK_LAYER_LUNARG_screenshot.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_screenshot", - "type": "GLOBAL", - "library_path": ".\\VkLayer_screenshot.dll", - "api_version": "1.2.154", - "implementation_version": "1", - "description": "LunarG image capture layer", - "introduction": "The screenshot layer records frames to image files.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/screenshot_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "settings": [ - { - "key": "frames", - "env": "VK_SCREENSHOT_FRAMES", - "label": "Frames", - "description": "Comma separated list of frames to output as screen shots or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "" - }, - { - "key": "dir", - "env": "VK_SCREENSHOT_DIR", - "label": "Directory", - "description": "This can be set to specify the directory in which to create the screenshot files.", - "type": "SAVE_FOLDER", - "default": "" - }, - { - "key": "format", - "env": "VK_SCREENSHOT_FORMAT", - "label": "Format", - "description": "This can be set to a color space for the output.", - "type": "ENUM", - "flags": [ - { - "key": "UNORM", - "label": "UNORM", - "description": "" - }, - { - "key": "SNORM", - "label": "SNORM", - "description": "" - }, - { - "key": "USCALED", - "label": "USCALED", - "description": "" - }, - { - "key": "SSCALED", - "label": "SSCALED", - "description": "" - }, - { - "key": "UINT", - "label": "UINT", - "description": "" - }, - { - "key": "SINT", - "label": "SINT", - "description": "" - }, - { - "key": "SRGB", - "label": "SRGB", - "description": "" - }, - { - "key": "USE_SWAPCHAIN_COLORSPACE", - "label": "USE_SWAPCHAIN_COLORSPACE", - "description": "" - } - ], - "default": "USE_SWAPCHAIN_COLORSPACE" - } - ] - } - } -} diff --git a/vkconfig_core/layers/162/VK_LAYER_KHRONOS_validation.json b/vkconfig_core/layers/162/VK_LAYER_KHRONOS_validation.json deleted file mode 100644 index d1296b55fa..0000000000 --- a/vkconfig_core/layers/162/VK_LAYER_KHRONOS_validation.json +++ /dev/null @@ -1,510 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_KHRONOS_validation", - "library_path": ".\\VkLayer_khronos_validation.dll", - "api_version": "1.2.162", - "implementation_version": "1", - "description": "Khronos Validation Layer", - "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "9" - }, - { - "name": "VK_EXT_debug_utils", - "spec_version": "1" - }, - { - "name": "VK_EXT_validation_features", - "spec_version": "2" - } - ], - "device_extensions": [ - { - "name": "VK_EXT_debug_marker", - "spec_version": "4", - "entrypoints": [ - "vkDebugMarkerSetObjectTagEXT", - "vkDebugMarkerSetObjectNameEXT", - "vkCmdDebugMarkerBeginEXT", - "vkCmdDebugMarkerEndEXT", - "vkCmdDebugMarkerInsertEXT" - ] - }, - { - "name": "VK_EXT_validation_cache", - "spec_version": "1", - "entrypoints": [ - "vkCreateValidationCacheEXT", - "vkDestroyValidationCacheEXT", - "vkGetValidationCacheDataEXT", - "vkMergeValidationCachesEXT" - ] - }, - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Standard", - "description": "Good default validation setup that balance validation coverage and performance.", - "settings": [ - { - "key": "enables", - "value": [] - }, - { - "key": "disables", - "value": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - } - ] - }, - { - "label": "Reduced-Overhead", - "description": "Disables some checks in the interest of better performance.", - "settings": [ - { - "key": "enables", - "value": [ - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET", - "VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE" - ] - } - ] - }, - { - "label": "Best Practices", - "description": "Provides warnings about potential API misuse but valid usages of the API.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Synchronization", - "description": "Identify resource access conflicts due to missing or incorrect synchronization operations between actions reading or writing the same regions of memory.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Shader Printf", - "description": "Debug shader code by \"printing\" any values of interest to the debug callback or stdout.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - }, - { - "key": "enable_message_limit", - "value": false - } - ] - } - ], - "settings": [ - { - "key": "debug_action", - "label": "Debug Action", - "description": "This indicates what action is to be taken when a layer wants to report information", - "type": "FLAGS", - "flags": [ - { - "key": "VK_DBG_LAYER_ACTION_LOG_MSG", - "label": "Log Message", - "description": "Log a txt message to stdout or to a log filename.", - "settings": [ - { - "key": "log_filename", - "label": "Log Filename", - "description": "Specifies the output filename", - "type": "SAVE_FILE", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "debug_action", - "value": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - } - ] - } - } - ] - }, - { - "key": "VK_DBG_LAYER_ACTION_CALLBACK", - "label": "Callback", - "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", - "view": "HIDDEN" - }, - { - "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", - "label": "Debug Output", - "description": "Log a txt message using the Windows OutputDebugString function.", - "platforms": [ "WINDOWS" ] - }, - { - "key": "VK_DBG_LAYER_ACTION_BREAK", - "label": "Break", - "description": "Trigger a breakpoint if a debugger is in use." - } - ], - "default": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - }, - { - "key": "report_flags", - "label": "Message Severity", - "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", - "type": "FLAGS", - "flags": [ - { - "key": "info", - "label": "Info", - "description": "Report informational messages." - }, - { - "key": "warn", - "label": "Warning", - "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." - }, - { - "key": "perf", - "label": "performance", - "description": "Report using the API in a way that may cause suboptimal performance." - }, - { - "key": "error", - "label": "Error", - "description": "Report errors in API usage." - }, - { - "key": "debug", - "label": "Debug", - "description": "For layer development. Report messages for debugging layer behavior.", - "view": "ADVANCED" - } - ], - "default": [ - "error", - "warn", - "perf" - ] - }, - { - "key": "enable_message_limit", - "label": "Limit Duplicated Messages", - "description": "Enable limitation of duplicate messages.", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "duplicate_message_limit", - "env": "VK_LAYER_DUPLICATE_MESSAGE_LIMIT", - "label": "Max Duplicated Messages", - "description": "Maximum number of times any single validation message would be reported.", - "type": "INT", - "default": 10, - "range": { - "min": 1 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "enable_message_limit", - "value": true - } - ] - } - } - ] - }, - { - "key": "message_id_filter", - "env": "VK_LAYER_MESSAGE_ID_FILTER", - "label": "Mute Message VUIDs", - "description": "List of VUIDs and VUID identifers which are to be IGNORED by the validation layer", - "type": "LIST", - "default": [] - }, - { - "key": "disables", - "env": "VK_LAYER_DISABLES", - "label": "Disables", - "description": "Setting an option here will disable areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "label": "Thread Safety", - "description": "Thread checks. It may help with performance to run with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check, or when debugging difficult application behaviors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "label": "Stateless Parameter", - "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "label": "Object Lifetime", - "description": "Object tracking checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", - "label": "Core", - "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "label": "Handle Wrapping", - "description": "Handle wrapping checks. Disable this feature if you are running into crashes when authoring new extensions or developing new Vulkan objects/structures" - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", - "label": "Shaders", - "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "label": "Command Buffer State", - "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "label": "Image Layout", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "label": "Query", - "description": "Checks for commands that use VkQueryPool objects.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "label": "Object in Use", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - } - ], - "default": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - }, - { - "key": "enables", - "env": "VK_LAYER_ENABLES", - "label": "Enables", - "description": "Setting an option here will enable specialized areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", - "label": "Synchronization", - "description": "This feature reports resource access conflicts due to missing or incorrect synchronization operations between actions (Draw, Copy, Dispatch, Blit) reading or writing the same regions of memory.", - "url": "${LUNARG_SDK}/synchronization_usage.html", - "status": "STABLE" - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT", - "label": "Debug Printf", - "description": "Enables processing of debug printf instructions in shaders and sending debug strings to the debug callback", - "url": "${LUNARG_SDK}/debug_printf.html", - "status": "STABLE", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "printf_to_stdout", - "label": "Printf to stdout", - "description": "To redirect Debug Printf messages from the debug callback to stdout", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" ] - } - ] - } - }, - { - "key": "printf_verbose", - "label": "Verbose", - "description": "Verbosity of debug printf messages", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "BOOL", - "default": false, - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" ] - } - ] - } - }, - { - "key": "printf_buffer_size", - "label": "Printf buffer size", - "description": "The size in bytes of the buffer used by debug printf", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "INT", - "default": 1024, - "range": { - "min": 128, - "max": 1048576 - }, - "unit": "bytes", - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" ] - } - ] - } - } - ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time", - "url": "${LUNARG_SDK}/gpu_validation.html", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "gpuav_buffer_oob", - "label": "Check Out of Bounds ", - "description": "Enable buffer out of bounds checking", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT" ] - } - ] - } - } - ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", - "label": "Reserve Descriptor Set Binding Slot", - "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", - "label": "Best Practices", - "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", - "url": "${LUNARG_SDK}/best_practices.html" - }, - { - "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM", - "label": "ARM-specific best practices", - "description": "Activating this feature enables the output of warnings related to ARM-specific misuse of the API, but which are not explicitly prohibited by the specification." - } - ], - "default": [] - } - ] - } - - } -} diff --git a/vkconfig_core/layers/162/VK_LAYER_LUNARG_api_dump.json b/vkconfig_core/layers/162/VK_LAYER_LUNARG_api_dump.json deleted file mode 100644 index 1b6b7c0ce2..0000000000 --- a/vkconfig_core/layers/162/VK_LAYER_LUNARG_api_dump.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_api_dump", - "library_path": ".\\VkLayer_api_dump.dll", - "api_version": "1.2.162", - "implementation_version": "2", - "description": "LunarG API dump layer", - "introduction": "The API Dump utility layer prints API calls, parameters, and values to the identified output stream.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/api_dump_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "presets": [ - { - "label": "Console Output", - "description": "Output API dump to stdout", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "stdout" - }, - { - "key": "file", - "value": false - } - ] - }, - { - "label": "Text Output", - "description": "Output API dump to a text file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "text" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.txt" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "HTML Output", - "description": "Output API dump to a HTML file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "html" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.html" - }, - { - "key": "file", - "value": true - } - ] - }, - { - "label": "JSON Output", - "description": "Output API dump to a JSON file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], - "status": "STABLE", - "settings": [ - { - "key": "output_format", - "value": "json" - }, - { - "key": "log_filename", - "value": "${VK_LOCAL}/vk_apidump.json" - }, - { - "key": "file", - "value": true - } - ] - } - ], - "settings": [ - { - "key": "output_range", - "env": "VK_APIDUMP_OUTPUT_RANGE", - "label": "Output Range", - "description": "Comma separated list of frames to output or a range of frames with a start, count, and optional interval separated by a dash. A count of 0 will output every frame after the start of the range. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "0-0" - }, - { - "key": "output_format", - "env": "VK_APIDUMP_OUTPUT_FORMAT", - "label": "Output Format", - "description": "Specifies the format used for output; can be HTML, JSON, or Text (default -- outputs plain text)", - "type": "ENUM", - "flags": [ - { - "key": "text", - "label": "Text", - "description": "Plain text" - }, - { - "key": "html", - "label": "HTML", - "description": "HTML" - }, - { - "key": "json", - "label": "JSON", - "description": "Json" - } - ], - "default": "text" - }, - { - "key": "file", - "label": "Output to File", - "description": "Setting this to true indicates that output should be written to file instead of stdout", - "type": "BOOL", - "default": false, - "settings": [ - { - "key": "log_filename", - "env": "VK_APIDUMP_LOG_FILENAME", - "label": "Log Filename", - "description": "Specifies the file to dump to when output files are enabled", - "type": "SAVE_FILE", - "filter": "*.txt,*.html,*.json", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "file", - "value": true - } - ] - } - } - ] - }, - { - "key": "flush", - "env": "VK_APIDUMP_FLUSH", - "label": "Log Flush After Write", - "description": "Setting this to true causes IO to be flushed after each API call that is written", - "type": "BOOL", - "default": true - }, - { - "key": "name_size", - "label": "Name Size", - "description": "The number of characters the name of a variable should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 1 - }, - "unit": "chars" - }, - { - "key": "show_types", - "label": "Show Types", - "description": "Dump types in addition to values", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "type_size", - "label": "Type Size", - "description": "The number of characters the name of a type should consume, assuming more are not required", - "type": "INT", - "default": 32, - "range": { - "min": 0 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "show_types", - "value": true - } - ] - } - } - ] - }, - { - "key": "show_timestamp", - "env": "VK_APIDUMP_TIMESTAMP", - "label": "Show Timestamp", - "description": "Show the timestamp of function calls since start in microseconds", - "type": "BOOL", - "default": false - }, - { - "key": "show_shader", - "label": "Show Shader", - "description": "Dump the shader binary code in pCode", - "type": "BOOL", - "default": false - }, - { - "key": "detailed", - "env": "VK_APIDUMP_DETAILED", - "label": "Show Parameter Details", - "description": "Dump parameter details in addition to API calls", - "type": "BOOL", - "default": true - }, - { - "key": "no_addr", - "env": "VK_APIDUMP_NO_ADDR", - "label": "Hide Addresses", - "description": "Dump \"address\" in place of hex addresses", - "type": "BOOL", - "default": false - }, - { - "key": "use_spaces", - "label": "Use Spaces", - "description": "Setting this to true causes all tab characters to be replaced with spaces", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "indent_size", - "label": "Indent Size", - "description": "Specifies the number of spaces that a tab is equal to", - "type": "INT", - "default": 4, - "range": { - "min": 1, - "max": 16 - }, - "unit": "chars", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "use_spaces", - "value": true - } - ] - } - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/162/VK_LAYER_LUNARG_gfxreconstruct.json b/vkconfig_core/layers/162/VK_LAYER_LUNARG_gfxreconstruct.json deleted file mode 100644 index f24c92b568..0000000000 --- a/vkconfig_core/layers/162/VK_LAYER_LUNARG_gfxreconstruct.json +++ /dev/null @@ -1,429 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_gfxreconstruct", - "type": "GLOBAL", - "library_path": ".\\VkLayer_gfxreconstruct.dll", - "api_version": "1.2.162", - "implementation_version": "36868", - "description": "GFXReconstruct Capture Layer Version 0.9.4", - "introduction": "The GFXReconstruct Capture Layer intercepts Vulkan API calls and logs them to a capture file. Other tools in the GFXReconstruct suite can inspect, modify, or replay capture files generated by this component.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/capture_tools.html", - "platforms": [ "WINDOWS", "LINUX", "ANDROID" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Initialization", - "description": "Capture the first two frames.", - "settings": [ - { - "key": "capture_trigger", - "value": "" - }, - { - "key": "capture_frames", - "value": "1-2" - }, - { - "key": "memory_tracking_mode", - "value": "unassisted" - } - ] - }, - { - "label": "Range", - "description": "Capture a range of frames between presses of the F5 key.", - "settings": [ - { - "key": "capture_trigger", - "value": "F5" - }, - { - "key": "capture_frames", - "value": "" - }, - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - ], - "settings": [ - { - "key": "capture_trigger", - "env": "GFXRECON_CAPTURE_TRIGGER", - "label": "Hotkey Capture Trigger", - "description": "Specify a hotkey (any one of F1-F12, TAB, CONTROL) that will be used to start/stop capture. Example: F3 will set the capture trigger to F3 hotkey. One capture file will be generated for each pair of start/stop hotkey presses. Default is: Empty string (hotkey capture trigger is disabled).", - "type": "ENUM", - "flags": [ - { - "key": "", - "label": "None", - "description": "" - }, - { - "key": "F1", - "label": "F1", - "description": "" - }, - { - "key": "F2", - "label": "F2", - "description": "" - }, - { - "key": "F3", - "label": "F3", - "description": "" - }, - { - "key": "F4", - "label": "F4", - "description": "" - }, - { - "key": "F5", - "label": "F5", - "description": "" - }, - { - "key": "F6", - "label": "F6", - "description": "" - }, - { - "key": "F7", - "label": "F7", - "description": "" - }, - { - "key": "F8", - "label": "F8", - "description": "" - }, - { - "key": "F9", - "label": "F9", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" - }, - { - "key": "F11", - "label": "F11", - "description": "" - }, - { - "key": "F12", - "label": "F12", - "description": "" - }, - { - "key": "TAB", - "label": "TAB", - "description": "" - }, - { - "key": "CONTROL", - "label": "CONTROL", - "description": "" - } - ], - "default": "" - }, - { - "key": "capture_frames", - "env": "GFXRECON_CAPTURE_FRAMES", - "label": "Capture Specific Frames", - "description": "Specify one or more comma-separated frame ranges to capture. Each range will be written to its own file. A frame range can be specified as a single value, to specify a single frame to capture, or as two hyphenated values, to specify the first and last frame to capture. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: 200,301-305 will create two capture files, one containing a single frame and one containing five frames. Default is: Empty string (all frames are captured).", - "type": "STRING", - "default": "" - }, - { - "key": "capture_file", - "env": "GFXRECON_CAPTURE_FILE", - "label": "Capture File Name", - "description": "Path to use when creating the capture file. Default is: gfxrecon_capture.gfxr", - "type": "SAVE_FILE", - "filter": "*.gfxr", - "default": "${VK_LOCAL}/gfxrecon_capture.gfxr", - "settings": [ - { - "key": "capture_file_timestamp", - "env": "GFXRECON_CAPTURE_FILE_TIMESTAMP", - "label": "Capture File Name with Timestamp", - "description": "Add a timestamp (yyyymmddThhmmss) postfix to the capture file name.", - "type": "BOOL", - "default": true - }, - { - "key": "capture_file_flush", - "env": "GFXRECON_CAPTURE_FILE_FLUSH", - "label": "Capture File Flush After Write", - "description": "Flush output stream after each packet is written to the capture file. Default is: false.", - "type": "BOOL", - "default": true - } - ] - }, - { - "key": "capture_compression_type", - "env": "GFXRECON_CAPTURE_COMPRESSION_TYPE", - "label": "Compression Format", - "description": "Compression format to use with the capture file. Valid values are: LZ4, ZLIB, ZSTD, and NONE. Default is: LZ4", - "type": "ENUM", - "flags": [ - { - "key": "LZ4", - "label": "LZ4", - "description": "Fastest compression algorithm that favors performance over compression ratio." - }, - { - "key": "ZLIB", - "label": "ZLIB", - "description": "Widely used compression algorithm with better compression ratio than LZ4 but worse performance." - }, - { - "key": "ZSTD", - "label": "ZSTD", - "description": "Newer compression algorithm with better compression ratio and performance than ZLIB, though not as fast as LZ4." - }, - { - "key": "NONE", - "label": "NONE", - "description": "No compression" - } - ], - "default": "LZ4" - }, - { - "key": "memory_tracking_mode", - "env": "GFXRECON_MEMORY_TRACKING_MODE", - "label": "Memory Tracking Mode", - "description": "Specifies the memory tracking mode to use for detecting modifications to mapped Vulkan memory objects. Available options are: page_guard, assisted, and unassisted.", - "type": "ENUM", - "flags": [ - { - "key": "page_guard", - "label": "page_guard", - "description": "tracks modifications to individual memory pages, which are written to the capture file on calls to vkFlushMappedMemoryRanges, vkUnmapMemory, and vkQueueSubmit. Tracking modifications requires allocating shadow memory for all mapped memory." - }, - { - "key": "assisted", - "label": "assisted", - "description": "Expects the application to call vkFlushMappedMemoryRanges after memory is modified; the memory ranges specified to the vkFlushMappedMemoryRanges call will be written to the capture file during the call." - }, - { - "key": "unassisted", - "label": "unassisted", - "description": "writes the full content of mapped memory to the capture file on calls to vkUnmapMemory and vkQueueSubmit. It is very inefficient and may be unusable with real-world applications that map large amounts of memory." - } - ], - "default": "page_guard", - "settings": [ - { - "key": "page_guard_copy_on_map", - "env": "GFXRECON_PAGE_GUARD_COPY_ON_MAP", - "label": "Page Guard Copy on Map", - "description": "When the page_guard memory tracking mode is enabled, copies the content of the mapped memory to the shadow memory immediately after the memory is mapped.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_separate_read", - "env": "GFXRECON_PAGE_GUARD_SEPARATE_READ", - "label": "Page Guard Separate Read Tracking", - "description": "When the page_guard memory tracking mode is enabled, copies the content of pages accessed for read from mapped memory to shadow memory on each read. Can overwrite unprocessed shadow memory content when an application is reading from and writing to the same page.", - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_external_memory", - "env": "GFXRECON_PAGE_GUARD_EXTERNAL_MEMORY", - "label": "Page Guard External Memory", - "description": "When the page_guard memory tracking mode is enabled, use the VK_EXT_external_memory_host extension to eliminate the need for shadow memory allocations. For each memory allocation from a host visible memory type, the capture layer will create an allocation from system memory, which it can monitor for write access, and provide that allocation to vkAllocateMemory as external memory. Only available on Windows.", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - } - ] - } - }, - { - "key": "page_guard_persistent_memory", - "env": "GFXRECON_PAGE_GUARD_PERSISTENT_MEMORY", - "label": "Page Guard Persisent Memory", - "description": "When the page_guard memory tracking mode is enabled, this option changes the way that the shadow memory used to detect modifications to mapped memory is allocated. The default behavior is to allocate and copy the mapped memory range on map and free the allocation on unmap. When this option is enabled, an allocation with a size equal to that of the object being mapped is made once on the first map and is not freed until the object is destroyed. This option is intended to be used with applications that frequently map and unmap large memory ranges, to avoid frequent allocation and copy operations that can have a negative impact on performance. This option is ignored when GFXRECON_PAGE_GUARD_EXTERNAL_MEMORY is enabled.", - "type": "BOOL", - "default": false, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "memory_tracking_mode", - "value": "page_guard" - }, - { - "key": "page_guard_external_memory", - "value": false - } - ] - } - } - ] - }, - { - "key": "log", - "label": "Log", - "description": "Control log messages.", - "type": "GROUP", - "settings": [ - { - "key": "log_level", - "env": "GFXRECON_LOG_LEVEL", - "label": "Level", - "description": "Specify the highest level message to log. Options are: debug, info, warning, error, and fatal. The specified level and all levels listed after it will be enabled for logging. For example, choosing the warning level will also enable the error and fatal levels.", - "type": "ENUM", - "flags": [ - { - "key": "debug", - "label": "debug, info, warning, error, fatal", - "description": "" - }, - { - "key": "info", - "label": "info, warning, error, fatal", - "description": "" - }, - { - "key": "warning", - "label": "warning, error, fatal", - "description": "" - }, - { - "key": "error", - "label": "error, fatal", - "description": "" - }, - { - "key": "fatal", - "label": "fatal", - "description": "" - } - ], - "default": "info" - }, - { - "key": "log_detailed", - "env": "GFXRECON_LOG_DETAILED", - "label": "Log Name and Line Number", - "description": "Include name and line number from the file responsible.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_console", - "env": "GFXRECON_LOG_OUTPUT_TO_CONSOLE", - "label": "Log Output to Console / stdout", - "description": "Log messages will be written to stdout.", - "type": "BOOL", - "default": true - }, - { - "key": "log_break_on_error", - "env": "GFXRECON_LOG_BREAK_ON_ERROR", - "label": "Trigger Debug Break on Error", - "description": "Trigger a debug break when logging an error.", - "type": "BOOL", - "default": false - }, - { - "key": "log_output_to_os_debug_string", - "env": "GFXRECON_LOG_OUTPUT_TO_OS_DEBUG_STRING", - "label": "Log Output to Debug Console", - "description": "Windows only option. Log messages will be written to the Debug Console with OutputDebugStringA", - "platforms": [ "WINDOWS" ], - "type": "BOOL", - "default": false - }, - { - "key": "log_file", - "env": "GFXRECON_LOG_FILE", - "label": "Log File", - "description": "When set, log messages will be written to a file at the specified path. Default is: Empty string (file logging disabled).", - "type": "SAVE_FILE", - "filter": "*.txt", - "default": "", - "settings": [ - { - "key": "log_file_flush_after_write", - "env": "GFXRECON_LOG_FILE_FLUSH_AFTER_WRITE", - "label": "Log File Flush After Write", - "description": "Flush the log file to disk after each write when true.", - "type": "BOOL", - "default": false - }, - { - "key": "log_file_keep_open", - "env": "GFXRECON_LOG_FILE_KEEP_OPEN", - "label": "Log File Keep Open", - "description": "Keep the log file open between log messages when true, or close and reopen the log file for each message when false.", - "type": "BOOL", - "default": true - }, - { - "key": "log_file_create_new", - "env": "GFXRECON_LOG_FILE_CREATE_NEW", - "label": "Log File Overwrite", - "description": "Specifies that log file initialization should overwrite an existing file when true, or append to an existing file when false.", - "type": "BOOL", - "default": true - } - ] - } - ] - } - ] - } - } -} diff --git a/vkconfig_core/layers/162/VK_LAYER_LUNARG_monitor.json b/vkconfig_core/layers/162/VK_LAYER_LUNARG_monitor.json deleted file mode 100644 index 1ae5891915..0000000000 --- a/vkconfig_core/layers/162/VK_LAYER_LUNARG_monitor.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "file_format_version": "1.0.0", - "layer": { - "name": "VK_LAYER_LUNARG_monitor", - "library_path": ".\\VkLayer_monitor.dll", - "api_version": "1.2.162", - "implementation_version": "1", - "description": "Execution Monitoring Layer", - "introduction": "The monitor utility layer prints the real-time frames-per-second value to the application's title bar.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/monitor_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ] - } -} diff --git a/vkconfig_core/layers/162/VK_LAYER_LUNARG_screenshot.json b/vkconfig_core/layers/162/VK_LAYER_LUNARG_screenshot.json deleted file mode 100644 index 0a0c8693b3..0000000000 --- a/vkconfig_core/layers/162/VK_LAYER_LUNARG_screenshot.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_screenshot", - "type": "GLOBAL", - "library_path": ".\\VkLayer_screenshot.dll", - "api_version": "1.2.162", - "implementation_version": "1", - "description": "LunarG image capture layer", - "introduction": "The screenshot layer records frames to image files.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/screenshot_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "settings": [ - { - "key": "frames", - "env": "VK_SCREENSHOT_FRAMES", - "label": "Frames", - "description": "Comma separated list of frames to output as screen shots or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "" - }, - { - "key": "dir", - "env": "VK_SCREENSHOT_DIR", - "label": "Directory", - "description": "This can be set to specify the directory in which to create the screenshot files.", - "type": "SAVE_FOLDER", - "default": "" - }, - { - "key": "format", - "env": "VK_SCREENSHOT_FORMAT", - "label": "Format", - "description": "This can be set to a color space for the output.", - "type": "ENUM", - "flags": [ - { - "key": "UNORM", - "label": "UNORM", - "description": "" - }, - { - "key": "SNORM", - "label": "SNORM", - "description": "" - }, - { - "key": "USCALED", - "label": "USCALED", - "description": "" - }, - { - "key": "SSCALED", - "label": "SSCALED", - "description": "" - }, - { - "key": "UINT", - "label": "UINT", - "description": "" - }, - { - "key": "SINT", - "label": "SINT", - "description": "" - }, - { - "key": "SRGB", - "label": "SRGB", - "description": "" - }, - { - "key": "USE_SWAPCHAIN_COLORSPACE", - "label": "USE_SWAPCHAIN_COLORSPACE", - "description": "" - } - ], - "default": "USE_SWAPCHAIN_COLORSPACE" - } - ] - } - } -} diff --git a/vkconfig_core/layers/170/VK_LAYER_KHRONOS_validation.json b/vkconfig_core/layers/170/VK_LAYER_KHRONOS_validation.json deleted file mode 100644 index e789dbd454..0000000000 --- a/vkconfig_core/layers/170/VK_LAYER_KHRONOS_validation.json +++ /dev/null @@ -1,507 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_KHRONOS_validation", - "type": "GLOBAL", - "library_path": ".\\VkLayer_khronos_validation.dll", - "api_version": "1.2.170", - "implementation_version": "1", - "description": "Khronos Validation Layer", - "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "instance_extensions": [ - { - "name": "VK_EXT_debug_report", - "spec_version": "9" - }, - { - "name": "VK_EXT_debug_utils", - "spec_version": "1" - }, - { - "name": "VK_EXT_validation_features", - "spec_version": "2" - } - ], - "device_extensions": [ - { - "name": "VK_EXT_debug_marker", - "spec_version": "4", - "entrypoints": [ - "vkDebugMarkerSetObjectTagEXT", - "vkDebugMarkerSetObjectNameEXT", - "vkCmdDebugMarkerBeginEXT", - "vkCmdDebugMarkerEndEXT", - "vkCmdDebugMarkerInsertEXT" - ] - }, - { - "name": "VK_EXT_validation_cache", - "spec_version": "1", - "entrypoints": [ - "vkCreateValidationCacheEXT", - "vkDestroyValidationCacheEXT", - "vkGetValidationCacheDataEXT", - "vkMergeValidationCachesEXT" - ] - }, - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ "vkGetPhysicalDeviceToolPropertiesEXT" ] - } - ], - "features": { - "presets": [ - { - "label": "Standard", - "description": "Good default validation setup that balance validation coverage and performance.", - "settings": [ - { - "key": "enables", - "value": [] - }, - { - "key": "disables", - "value": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - } - ] - }, - { - "label": "Reduced-Overhead", - "description": "Disables some checks in the interest of better performance.", - "settings": [ - { - "key": "enables", - "value": [ - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION" - ] - } - ] - }, - { - "label": "Best Practices", - "description": "Provides warnings about potential API misuse but valid usages of the API.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Synchronization", - "description": "Identify resource access conflicts due to missing or incorrect synchronization operations between actions reading or writing the same regions of memory.", - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - } - ] - }, - { - "label": "Shader Printf", - "description": "Debug shader code by \"printing\" any values of interest to the debug callback or stdout.", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "enables", - "value": [ - "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" - ] - }, - { - "key": "disables", - "value": [ - "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT" - ] - }, - { - "key": "enable_message_limit", - "value": false - } - ] - } - ], - "settings": [ - { - "key": "debug_action", - "label": "Debug Action", - "description": "This indicates what action is to be taken when a layer wants to report information", - "type": "FLAGS", - "flags": [ - { - "key": "VK_DBG_LAYER_ACTION_LOG_MSG", - "label": "Log Message", - "description": "Log a txt message to stdout or to a log filename.", - "settings": [ - { - "key": "log_filename", - "label": "Log Filename", - "description": "Specifies the output filename", - "type": "SAVE_FILE", - "default": "stdout", - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "debug_action", - "value": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - } - ] - } - } - ] - }, - { - "key": "VK_DBG_LAYER_ACTION_CALLBACK", - "label": "Callback", - "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", - "view": "HIDDEN" - }, - { - "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", - "label": "Debug Output", - "description": "Log a txt message using the Windows OutputDebugString function.", - "platforms": [ "WINDOWS" ] - }, - { - "key": "VK_DBG_LAYER_ACTION_BREAK", - "label": "Break", - "description": "Trigger a breakpoint if a debugger is in use." - } - ], - "default": [ "VK_DBG_LAYER_ACTION_LOG_MSG" ] - }, - { - "key": "report_flags", - "label": "Message Severity", - "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", - "type": "FLAGS", - "flags": [ - { - "key": "info", - "label": "Info", - "description": "Report informational messages." - }, - { - "key": "warn", - "label": "Warning", - "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." - }, - { - "key": "perf", - "label": "performance", - "description": "Report using the API in a way that may cause suboptimal performance." - }, - { - "key": "error", - "label": "Error", - "description": "Report errors in API usage." - }, - { - "key": "debug", - "label": "Debug", - "description": "For layer development. Report messages for debugging layer behavior.", - "view": "ADVANCED" - } - ], - "default": [ - "error", - "warn", - "perf" - ] - }, - { - "key": "enable_message_limit", - "label": "Limit Duplicated Messages", - "description": "Enable limitation of duplicate messages.", - "type": "BOOL", - "default": true, - "settings": [ - { - "key": "duplicate_message_limit", - "env": "VK_LAYER_DUPLICATE_MESSAGE_LIMIT", - "label": "Max Duplicated Messages", - "description": "Maximum number of times any single validation message would be reported.", - "type": "INT", - "default": 10, - "range": { - "min": 1 - }, - "dependence": { - "mode": "ALL", - "settings": [ - { - "key": "enable_message_limit", - "value": true - } - ] - } - } - ] - }, - { - "key": "message_id_filter", - "env": "VK_LAYER_MESSAGE_ID_FILTER", - "label": "Mute Message VUIDs", - "description": "List of VUIDs and VUID identifers which are to be IGNORED by the validation layer", - "type": "LIST", - "default": [] - }, - { - "key": "disables", - "env": "VK_LAYER_DISABLES", - "label": "Disables", - "description": "Setting an option here will disable areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", - "label": "Thread Safety", - "description": "Thread checks. It may help with performance to run with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check, or when debugging difficult application behaviors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", - "label": "Stateless Parameter", - "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", - "label": "Object Lifetime", - "description": "Object tracking checks. This may not always be necessary late in a development cycle." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", - "label": "Core", - "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", - "label": "Handle Wrapping", - "description": "Handle wrapping checks. Disable this feature if you are running into crashes when authoring new extensions or developing new Vulkan objects/structures" - }, - { - "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", - "label": "Shaders", - "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", - "label": "Command Buffer State", - "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", - "label": "Image Layout", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", - "label": "Query", - "description": "Checks for commands that use VkQueryPool objects.", - "view": "ADVANCED" - }, - { - "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", - "label": "Object in Use", - "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", - "view": "ADVANCED" - } - ], - "default": [ "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" ] - }, - { - "key": "enables", - "env": "VK_LAYER_ENABLES", - "label": "Enables", - "description": "Setting an option here will enable specialized areas of validation", - "type": "FLAGS", - "flags": [ - { - "key": "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", - "label": "Synchronization", - "description": "This feature reports resource access conflicts due to missing or incorrect synchronization operations between actions (Draw, Copy, Dispatch, Blit) reading or writing the same regions of memory.", - "url": "${LUNARG_SDK}/synchronization_usage.html" - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT", - "label": "Debug Printf", - "description": "Enables processing of debug printf instructions in shaders and sending debug strings to the debug callback", - "url": "${LUNARG_SDK}/debug_printf.html", - "status": "STABLE", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "printf_to_stdout", - "label": "Printf to stdout", - "description": "To redirect Debug Printf messages from the debug callback to stdout", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" ] - } - ] - } - }, - { - "key": "printf_verbose", - "label": "Verbose", - "description": "Verbosity of debug printf messages", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "BOOL", - "default": false, - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" ] - } - ] - } - }, - { - "key": "printf_buffer_size", - "label": "Printf buffer size", - "description": "The size in bytes of the buffer used by debug printf", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "INT", - "default": 1024, - "range": { - "min": 128, - "max": 1048576 - }, - "unit": "bytes", - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT" ] - } - ] - } - } - ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", - "label": "GPU-Assisted", - "description": "Check for API usage errors at shader execution time", - "url": "${LUNARG_SDK}/gpu_validation.html", - "platforms": [ "WINDOWS", "LINUX" ], - "settings": [ - { - "key": "gpuav_buffer_oob", - "label": "Check Out of Bounds ", - "description": "Enable buffer out of bounds checking", - "platforms": [ "WINDOWS", "LINUX" ], - "type": "BOOL", - "default": true, - "dependence": { - "mode": "ANY", - "settings": [ - { - "key": "enables", - "value": [ "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT" ] - } - ] - } - } - ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", - "label": "Reserve Descriptor Set Binding Slot", - "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", - "platforms": [ "WINDOWS", "LINUX" ] - }, - { - "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", - "label": "Best Practices", - "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", - "url": "${LUNARG_SDK}/best_practices.html" - }, - { - "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM", - "label": "ARM-specific best practices", - "description": "Activating this feature enables the output of warnings related to ARM-specific misuse of the API, but which are not explicitly prohibited by the specification." - } - ], - "default": [] - } - ] - } - } -} diff --git a/vkconfig_core/layers/170/VK_LAYER_LUNARG_screenshot.json b/vkconfig_core/layers/170/VK_LAYER_LUNARG_screenshot.json deleted file mode 100644 index 7188012c08..0000000000 --- a/vkconfig_core/layers/170/VK_LAYER_LUNARG_screenshot.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "file_format_version": "1.2.0", - "layer": { - "name": "VK_LAYER_LUNARG_screenshot", - "type": "GLOBAL", - "library_path": ".\\VkLayer_screenshot.dll", - "api_version": "1.2.170", - "implementation_version": "1", - "description": "LunarG image capture layer", - "introduction": "The screenshot layer records frames to image files.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/screenshot_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], - "device_extensions": [ - { - "name": "VK_EXT_tooling_info", - "spec_version": "1", - "entrypoints": [ - "vkGetPhysicalDeviceToolPropertiesEXT" - ] - } - ], - "features": { - "settings": [ - { - "key": "frames", - "env": "VK_SCREENSHOT_FRAMES", - "label": "Frames", - "description": "Comma separated list of frames to output as screen shots or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", - "type": "STRING", - "default": "" - }, - { - "key": "dir", - "env": "VK_SCREENSHOT_DIR", - "label": "Directory", - "description": "This can be set to specify the directory in which to create the screenshot files.", - "type": "SAVE_FOLDER", - "default": "" - }, - { - "key": "format", - "env": "VK_SCREENSHOT_FORMAT", - "label": "Format", - "description": "This can be set to a color space for the output.", - "type": "ENUM", - "flags": [ - { - "key": "UNORM", - "label": "UNORM", - "description": "" - }, - { - "key": "SNORM", - "label": "SNORM", - "description": "" - }, - { - "key": "USCALED", - "label": "USCALED", - "description": "" - }, - { - "key": "SSCALED", - "label": "SSCALED", - "description": "" - }, - { - "key": "UINT", - "label": "UINT", - "description": "" - }, - { - "key": "SINT", - "label": "SINT", - "description": "" - }, - { - "key": "SRGB", - "label": "SRGB", - "description": "" - }, - { - "key": "USE_SWAPCHAIN_COLORSPACE", - "label": "USE_SWAPCHAIN_COLORSPACE", - "description": "" - } - ], - "default": "USE_SWAPCHAIN_COLORSPACE" - } - ] - } - } -} diff --git a/vkconfig_core/override.cpp b/vkconfig_core/override.cpp deleted file mode 100644 index c1c2ebe23b..0000000000 --- a/vkconfig_core/override.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "override.h" -#include "util.h" -#include "platform.h" -#include "registry.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -// Create and write VkLayer_override.json file -bool WriteLayersOverride(const Environment& environment, const std::vector& available_layers, - const Configuration& configuration, const std::string& layers_path) { - assert(!layers_path.empty()); - assert(QFileInfo(layers_path.c_str()).absoluteDir().exists()); - - const QStringList& path_gui = ConvertString(environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_GUI)); - const QStringList& path_env_set = ConvertString(environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_SET)); - const QStringList& path_env_add = ConvertString(environment.GetUserDefinedLayersPaths(USER_DEFINED_LAYERS_PATHS_ENV_ADD)); - - QStringList layer_system_paths; - QStringList layer_override_paths = path_gui; - - for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { - const Parameter& parameter = configuration.parameters[i]; - if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { - continue; - } - - if (parameter.state != LAYER_STATE_OVERRIDDEN) { - continue; - } - - const Layer* layer = FindByKey(available_layers, parameter.key.c_str()); - if (layer == nullptr) { - continue; - } - - // Extract just the path - assert(!layer->manifest_path.empty()); - const QFileInfo file(layer->manifest_path.c_str()); - const std::string absolute_path(file.absolutePath().toStdString().c_str()); - - if (!path_gui.contains(ConvertNativeSeparators(absolute_path.c_str()).c_str()) && - !path_env_set.contains(ConvertNativeSeparators(absolute_path.c_str()).c_str()) && - !path_env_add.contains(ConvertNativeSeparators(absolute_path.c_str()).c_str())) { - // Make sure the path is not already in the system path list - if (layer_system_paths.contains(absolute_path.c_str())) { - continue; - } - - layer_system_paths << absolute_path.c_str(); - } else { - // Make sure the path is not already in the override path list - if (layer_override_paths.contains(ConvertNativeSeparators(absolute_path.c_str()).c_str())) { - continue; - } - - // Okay, add to the list - layer_override_paths << absolute_path.c_str(); - } - } - - const Version version = ComputeMinApiVersion(environment.api_version, configuration.parameters, available_layers); - - QJsonArray json_paths; - - // First add override paths so that they take precedent over system paths - for (int i = 0, n = layer_override_paths.count(); i < n; ++i) { - const std::string& path = ConvertNativeSeparators(layer_override_paths[i].toStdString()); - json_paths.append(path.c_str()); - } - - // Second add system paths, so that a layers configuration can run with both system and user-defined layers - for (int i = 0, n = layer_system_paths.count(); i < n; ++i) { - const std::string& path = ConvertNativeSeparators(layer_system_paths[i].toStdString()); - json_paths.append(path.c_str()); - } - - QJsonArray json_overridden_layers; - QJsonArray json_excluded_layers; - if (environment.GetMode() == LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED) { - for (std::size_t i = 0, n = available_layers.size(); i < n; ++i) { - json_excluded_layers.append(available_layers[i].key.c_str()); - } - } else { - for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { - const Parameter& parameter = configuration.parameters[i]; - if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { - continue; - } - - if (parameter.state == LAYER_STATE_OVERRIDDEN) - json_overridden_layers.append(parameter.key.c_str()); - else if (parameter.state == LAYER_STATE_EXCLUDED) - json_excluded_layers.append(parameter.key.c_str()); - } - } - - QJsonObject disable; - disable.insert("DISABLE_VK_LAYER_LUNARG_override", "1"); - - QJsonObject layer; - layer.insert("name", "VK_LAYER_LUNARG_override"); - layer.insert("type", "GLOBAL"); - layer.insert("api_version", version.str().c_str()); - layer.insert("implementation_version", "1"); - layer.insert("description", "LunarG Override Layer"); - layer.insert("override_paths", json_paths); - layer.insert("component_layers", json_overridden_layers); - layer.insert("blacklisted_layers", json_excluded_layers); - layer.insert("disable_environment", disable); - - // This has to contain something, or it will apply globally! - if (environment.GetUseApplicationList() && environment.HasOverriddenApplications()) { - const std::vector& applications = environment.GetApplications(); - - QJsonArray json_applist; - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - if (applications[i].layers_mode == LAYERS_MODE_BY_APPLICATIONS) continue; - - const std::string& executable_path = - ConvertNativeSeparators(ReplaceBuiltInVariable(applications[i].executable_path.c_str())); - - const std::string& absolute_path( - ConvertNativeSeparators(QFileInfo(executable_path.c_str()).absoluteFilePath().toStdString())); - assert(QFileInfo(absolute_path.c_str()).exists()); - json_applist.append(absolute_path.c_str()); - } - - layer.insert("app_keys", json_applist); - } - - QJsonObject root; - root.insert("file_format_version", "1.1.2"); - root.insert("layer", layer); - QJsonDocument doc(root); - - QFile json_file(layers_path.c_str()); - const bool result_layers_file = json_file.open(QIODevice::WriteOnly | QIODevice::Text); - assert(result_layers_file); - json_file.write(doc.toJson()); - json_file.close(); - - return result_layers_file; -} - -const char* GetString(LayerControl control) { - static const char* table[] = {"on", "off", "auto", "application_enabled_layers", "unordered_layer_location"}; - - return table[control]; -} - -struct LayerSettings { - std::string name; - std::string path; - LayerControl control; - bool implicit; -}; - -enum LogType { - LOG_ERROR = 0, - LOG_WARN, - LOG_INFO, - LOG_DEBUG, - - LOG_FIRST = LOG_ERROR, - LOG_LAST = LOG_DEBUG, -}; - -enum { LOG_COUNT = LOG_LAST - LOG_FIRST + 1 }; - -enum LogFlag { - LOG_ERROR_BIT = 1 << LOG_ERROR, - LOG_WARN_BIT = 1 << LOG_WARN, - LOG_INFO_BIT = 1 << LOG_INFO, - LOG_DEBUG_BIT = 1 << LOG_DEBUG, - - LOG_DEBUG_ALL = LOG_ERROR_BIT | LOG_WARN_BIT | LOG_INFO_BIT | LOG_DEBUG_BIT -}; - -struct LoaderSettings { - std::string executable_path; - std::vector layers; - int stderr_log_flags; -}; - -static std::vector GetStderrLogStrings(int stderr_log_flags) { - static const char* table[] = {"error", "warn", "info", "debug"}; - static_assert(countof(table) == LOG_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - std::vector result; - - for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { - if (stderr_log_flags & (1 << i)) { - result.push_back(table[i]); - } - } - - return result; -} - -static QJsonObject CreateJsonSettingObject(const LoaderSettings& loader_settings) { - QJsonArray json_app_keys; - json_app_keys.append(loader_settings.executable_path.c_str()); - - QJsonArray json_layers; - for (std::size_t j = 0, o = loader_settings.layers.size(); j < o; ++j) { - const LayerSettings& layer = loader_settings.layers[j]; - - QJsonObject json_layer; - json_layer.insert("name", layer.name.c_str()); - json_layer.insert("path", layer.path.c_str()); - json_layer.insert("control", GetString(layer.control)); - json_layer.insert("treat_as_implicit_manifest", layer.implicit); - json_layers.append(json_layer); - } - - QJsonArray json_stderr_log; - const std::vector& stderr_log = GetStderrLogStrings(loader_settings.stderr_log_flags); - for (std::size_t i = 0, n = stderr_log.size(); i < n; ++i) { - json_stderr_log.append(stderr_log[i].c_str()); - } - - QJsonObject json_settings; - json_settings.insert("app_keys", json_app_keys); - json_settings.insert("layers", json_layers); - json_settings.insert("stderr_log", json_stderr_log); - return json_settings; -} - -// Create and write vk_loader_settings.json file -bool WriteLoaderSettings(const Environment& environment, const std::vector& available_layers, - const Configuration& configuration, const std::string& layers_path) { - assert(!layers_path.empty()); - assert(QFileInfo(layers_path.c_str()).absoluteDir().exists()); - - std::vector loader_settings_array; - - if (environment.GetPerApplicationConfig()) { - for (std::size_t i = 0, n = environment.GetApplications().size(); i < n; ++i) { - LoaderSettings loader_settings; - - const Application& application = environment.GetApplication(i); - - switch (application.layers_mode) { - case LAYERS_MODE_BY_APPLICATIONS: { - } break; - case LAYERS_MODE_BY_CONFIGURATOR_RUNNING: { - } break; - case LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED: { - } break; - } - - loader_settings_array.push_back(loader_settings); - } - } else { - const std::string& selected_configuration = environment.GetSelectedConfiguration(); - - LoaderSettings loader_settings; - loader_settings.stderr_log_flags = 0; - - if (environment.GetMode() != LAYERS_MODE_BY_APPLICATIONS) { - for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { - LayerSettings layer_settings; - - const Parameter& parameter = configuration.parameters[i]; - if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { - continue; - } - - if (parameter.state != LAYER_STATE_OVERRIDDEN) { - continue; - } - - const Layer* layer = FindByKey(available_layers, parameter.key.c_str()); - if (layer == nullptr) { - continue; - } - - // Extract just the path - assert(!layer->manifest_path.empty()); - layer_settings.name = layer->key; - layer_settings.path = QFileInfo(layer->manifest_path.c_str()).absolutePath().toStdString(); - layer_settings.control = LAYER_CONTROL_AUTO; // TODO - layer_settings.implicit = layer->type == LAYER_TYPE_IMPLICIT; - - loader_settings.layers.push_back(layer_settings); - } - } - - loader_settings_array.push_back(loader_settings); - } - - QJsonObject root; - root.insert("file_format_version", "1.0.0"); - if (loader_settings_array.size() > 1) { - QJsonArray json_settings_array; - for (std::size_t i = 0, n = loader_settings_array.size(); i < n; ++i) { - json_settings_array.append(CreateJsonSettingObject(loader_settings_array[i])); - } - root.insert("settings_array", json_settings_array); - } else { - root.insert("settings", CreateJsonSettingObject(loader_settings_array[0])); - } - QJsonDocument doc(root); - - QFile json_file(layers_path.c_str()); - const bool result_layers_file = json_file.open(QIODevice::WriteOnly | QIODevice::Text); - assert(result_layers_file); - json_file.write(doc.toJson()); - json_file.close(); - - return result_layers_file; -} - -// Create and write vk_layer_settings.txt file -bool WriteLayersSettings(const std::vector& available_layers, const Configuration& configuration, - const std::string& settings_path) { - if (settings_path.empty() || !QFileInfo(settings_path.c_str()).absoluteDir().exists()) { - fprintf(stderr, "Cannot open file %s\n", settings_path.c_str()); - exit(1); - }; - QFile file(settings_path.c_str()); - const bool result_settings_file = file.open(QIODevice::WriteOnly | QIODevice::Text); - if (!result_settings_file) { - fprintf(stderr, "Cannot open file %s\n", settings_path.c_str()); - exit(1); - } - QTextStream stream(&file); - - bool has_missing_layers = false; - - // Loop through all the layers - for (std::size_t j = 0, n = configuration.parameters.size(); j < n; ++j) { - const Parameter& parameter = configuration.parameters[j]; - if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { - continue; - } - - const Layer* layer = FindByKey(available_layers, parameter.key.c_str()); - if (layer == nullptr) { - has_missing_layers = true; - continue; - } - - if (parameter.state != LAYER_STATE_OVERRIDDEN) continue; - - const bool use_builtin_validation = UseBuiltinValidationSettings(parameter); - - stream << "\n"; - stream << "# " << layer->key.c_str() << "\n\n"; - - std::string lc_layer_name = GetLayerSettingPrefix(layer->key); - - for (std::size_t i = 0, m = parameter.settings.size(); i < m; ++i) { - const SettingData* setting_data = parameter.settings[i]; - - // Skip groups - they aren't settings, so not relevant in this output - if (setting_data->type == SETTING_GROUP) { - continue; - } - - if (!use_builtin_validation) { - if (setting_data->key == "enables") { - continue; - } - - if (setting_data->key == "disables") { - continue; - } - } - - // Skip missing settings - const SettingMeta* meta = FindSetting(layer->settings, setting_data->key.c_str()); - if (meta == nullptr) { - continue; - } - - // Skip overriden settings - if (::CheckSettingOverridden(*meta)) { - continue; - } - - stream << "# "; - stream << meta->label.c_str(); - stream << "\n# =====================\n# ."; - stream << meta->key.c_str() << "\n"; - - // Break up description into smaller words - std::string description = meta->description; - std::vector words; - std::size_t pos; - while ((pos = description.find(" ")) != std::string::npos) { - words.push_back(description.substr(0, pos)); - description.erase(0, pos + 1); - } - if (description.size() > 0) words.push_back(description); - if (words.size() > 0) { - stream << "#"; - std::size_t nchars = 2; - for (auto word : words) { - if (word.size() + nchars > 80) { - stream << "\n#"; - nchars = 2; - } - stream << " " << word.c_str(); - nchars += (word.size() + 1); - } - } - stream << "\n"; - - // If feature has unmet dependency, output it but comment it out - if (::CheckDependence(*meta, parameter.settings) != SETTING_DEPENDENCE_ENABLE) { - stream << "#"; - } - - stream << lc_layer_name.c_str() << setting_data->key.c_str() << " = "; - stream << setting_data->Export(EXPORT_MODE_OVERRIDE).c_str(); - stream << "\n\n"; - } - } - file.close(); - - return result_settings_file && !has_missing_layers; -} - -bool OverrideConfiguration(const Environment& environment, const std::vector& available_layers, - const Configuration& configuration) { - const std::string layers_path = GetPath(BUILTIN_PATH_OVERRIDE_LAYERS); - const std::string settings_path = GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS); - - // Clean up - SurrenderConfiguration(environment); - - // VkLayer_override.json - const bool result_layers = WriteLayersOverride(environment, available_layers, configuration, layers_path); - - // vk_layer_settings.txt - const bool result_settings = WriteLayersSettings(available_layers, configuration, settings_path); - - // On Windows only, we need to write these values to the registry -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS - AppendRegistryEntriesForLayers(layers_path.c_str(), settings_path.c_str()); -#endif - - return result_settings && result_layers; -} - -bool EraseLayersOverride(const std::string& layers_path) { return std::remove(layers_path.c_str()) == 0; } - -bool EraseSettingsOverride(const std::string& settings_path) { return std::remove(settings_path.c_str()) == 0; } - -bool SurrenderConfiguration(const Environment& environment) { - (void)environment; - - const std::string layers_path = GetPath(BUILTIN_PATH_OVERRIDE_LAYERS); - const std::string settings_path = GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS); - - const bool result_layers = EraseLayersOverride(layers_path); - const bool result_settings = EraseSettingsOverride(settings_path); - -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS - RemoveRegistryEntriesForLayers(layers_path.c_str(), settings_path.c_str()); -#endif - - return result_layers && result_settings; -} - -bool HasOverride() { - const std::string layers_path = GetPath(BUILTIN_PATH_OVERRIDE_LAYERS); - const std::string settings_path = GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS); - - const QFileInfo override_settings_file_info(layers_path.c_str()); - const QFileInfo override_layers_file_info(settings_path.c_str()); - - return override_settings_file_info.exists() || override_layers_file_info.exists(); -} diff --git a/vkconfig_core/override.h b/vkconfig_core/override.h deleted file mode 100644 index 739a11d6c2..0000000000 --- a/vkconfig_core/override.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "configuration.h" -#include "environment.h" -#include "application.h" - -// Create the VkLayer_override.json and vk_layer_settings.txt files to take over Vulkan layers from Vulkan applications -bool OverrideConfiguration(const Environment& environment, const std::vector& available_layers, - const Configuration& configuration); - -// Remove the VkLayer_override.json and vk_layer_settings.txt files to return full control of the layers to the Vulkan applications -bool SurrenderConfiguration(const Environment& environment); - -// Check whether a layers configuration is activated -bool HasOverride(); - -// Write the settings file -bool WriteLayersSettings(const std::vector& available_layers, const Configuration& configuration, - const std::string& settings_path); diff --git a/vkconfig_core/parameter.cpp b/vkconfig_core/parameter.cpp index 2e616e6336..02c2d311c5 100644 --- a/vkconfig_core/parameter.cpp +++ b/vkconfig_core/parameter.cpp @@ -20,7 +20,7 @@ #include "setting_filesystem.h" #include "parameter.h" -#include "platform.h" +#include "type_platform.h" #include "version.h" #include "util.h" #include "path.h" @@ -56,15 +56,15 @@ ParameterRank GetParameterOrdering(const std::vector& available_layers, c const Layer* layer = FindByKey(available_layers, parameter.key.c_str()); if (layer == nullptr) { return PARAMETER_RANK_MISSING; - } else if (parameter.state == LAYER_STATE_EXCLUDED) { + } else if (parameter.control == LAYER_CONTROL_OFF) { return PARAMETER_RANK_EXCLUDED; - } else if (parameter.state == LAYER_STATE_APPLICATION_CONTROLLED && layer->type == LAYER_TYPE_IMPLICIT) { + } else if (parameter.control == LAYER_CONTROL_AUTO && layer->type == LAYER_TYPE_IMPLICIT) { return PARAMETER_RANK_IMPLICIT_AVAILABLE; - } else if (parameter.state == LAYER_STATE_OVERRIDDEN && layer->type == LAYER_TYPE_IMPLICIT) { + } else if (parameter.control == LAYER_CONTROL_ON && layer->type == LAYER_TYPE_IMPLICIT) { return PARAMETER_RANK_IMPLICIT_OVERRIDDEN; - } else if (parameter.state == LAYER_STATE_OVERRIDDEN && layer->type != LAYER_TYPE_IMPLICIT) { + } else if (parameter.control == LAYER_CONTROL_ON && layer->type != LAYER_TYPE_IMPLICIT) { return PARAMETER_RANK_EXPLICIT_OVERRIDDEN; - } else if (parameter.state == LAYER_STATE_APPLICATION_CONTROLLED && layer->type != LAYER_TYPE_IMPLICIT) { + } else if (parameter.control == LAYER_CONTROL_AUTO && layer->type != LAYER_TYPE_IMPLICIT) { return PARAMETER_RANK_EXPLICIT_AVAILABLE; } else { assert(0); // Unknown ordering @@ -103,7 +103,7 @@ void OrderParameter(std::vector& parameters, const std::vector const bool both_ranked = a.overridden_rank != Parameter::NO_RANK && b.overridden_rank != Parameter::NO_RANK; - if (rankA == rankB && a.state == LAYER_STATE_OVERRIDDEN) + if (rankA == rankB && a.control == LAYER_CONTROL_ON) if (a.overridden_rank != Parameter::NO_RANK && b.overridden_rank != Parameter::NO_RANK) return a.overridden_rank < b.overridden_rank; else if (a.key == VK_LAYER_KHRONOS_PROFILES_NAME) @@ -120,7 +120,7 @@ void OrderParameter(std::vector& parameters, const std::vector return a.overridden_rank < b.overridden_rank; else if (both_ranked && rankA == PARAMETER_RANK_EXPLICIT_OVERRIDDEN && rankB == PARAMETER_RANK_IMPLICIT_OVERRIDDEN) return a.overridden_rank < b.overridden_rank; - else if (rankA == rankB && a.state != LAYER_STATE_OVERRIDDEN) + else if (rankA == rankB && a.control != LAYER_CONTROL_ON) return a.key < b.key; else if (rankA != rankB) return rankA < rankB; @@ -134,18 +134,20 @@ void OrderParameter(std::vector& parameters, const std::vector std::sort(parameters.begin(), parameters.end(), ParameterCompare(layers)); for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - if (parameters[i].state == LAYER_STATE_OVERRIDDEN) + if (parameters[i].control == LAYER_CONTROL_ON) parameters[i].overridden_rank = static_cast(i); else parameters[i].overridden_rank = Parameter::NO_RANK; } } -void FilterParameters(std::vector& parameters, const LayerState state) { +void FilterParameters(std::vector& parameters, const LayerControl control) { std::vector filtered_parameters; for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - if (parameters[i].state == state) continue; + if (parameters[i].control == control) { + continue; + } filtered_parameters.push_back(parameters[i]); } @@ -155,7 +157,7 @@ void FilterParameters(std::vector& parameters, const LayerState state bool HasMissingLayer(const std::vector& parameters, const std::vector& layers, std::string& missing_layer) { for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it) { - if (it->state == LAYER_STATE_EXCLUDED) { + if (it->control == LAYER_CONTROL_OFF) { continue; // If excluded are missing, it doesn't matter } @@ -176,9 +178,13 @@ std::size_t CountOverriddenLayers(const std::vector& parameters) { for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { const Parameter& parameter = parameters[i]; - if (!IsPlatformSupported(parameter.platform_flags)) continue; + if (!IsPlatformSupported(parameter.platform_flags)) { + continue; + } - if (parameter.state != LAYER_STATE_OVERRIDDEN) continue; + if (parameter.control != LAYER_CONTROL_ON) { + continue; + } ++count; } @@ -191,12 +197,18 @@ std::size_t CountExcludedLayers(const std::vector& parameters, const for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { const Parameter& parameter = parameters[i]; - if (!IsPlatformSupported(parameter.platform_flags)) continue; + if (!IsPlatformSupported(parameter.platform_flags)) { + continue; + } - if (parameter.state != LAYER_STATE_EXCLUDED) continue; + if (parameter.control != LAYER_CONTROL_OFF) { + continue; + } const Layer* layer = FindByKey(layers, parameter.key.c_str()); - if (layer == nullptr) continue; // Do not display missing excluded layers + if (layer == nullptr) { + continue; // Do not display missing excluded layers + } ++count; } @@ -206,13 +218,13 @@ std::size_t CountExcludedLayers(const std::vector& parameters, const std::vector GatherParameters(const std::vector& parameters, const std::vector& available_layers) { std::vector gathered_parameters; - /* - Parameter application_enabled_layers; - application_enabled_layers.key = "Application Enabled Layers"; - application_enabled_layers.control = LAYER_CONTROL_APPLICATIONS; - application_enabled_layers.overridden_rank = Parameter::NO_RANK; - gathered_parameters.push_back(application_enabled_layers); - */ + + Parameter application_enabled_layers; + application_enabled_layers.key = "Application Enabled Layers"; + application_enabled_layers.control = LAYER_CONTROL_APPLICATIONS; + application_enabled_layers.overridden_rank = Parameter::NO_RANK; + gathered_parameters.push_back(application_enabled_layers); + // Loop through the layers. They are expected to be in order for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { const Parameter& parameter = parameters[i]; @@ -225,39 +237,26 @@ std::vector GatherParameters(const std::vector& parameters const Layer& layer = available_layers[i]; // The layer is already in the layer tree - if (IsFound(parameters, layer.key.c_str())) continue; + if (IsFound(parameters, layer.key.c_str())) { + continue; + } Parameter parameter; parameter.key = layer.key; - parameter.state = LAYER_STATE_APPLICATION_CONTROLLED; - parameter.api_version = layer.api_version; - CollectDefaultSettingData(layer.settings, parameter.settings); + parameter.control = LAYER_CONTROL_AUTO; + // parameter.api_version = layer.api_version; + // CollectDefaultSettingData(layer.settings, parameter.settings); gathered_parameters.push_back(parameter); } OrderParameter(gathered_parameters, available_layers); - /* - Parameter unordered_layer_location; - unordered_layer_location.key = "Unordered Layers"; - unordered_layer_location.control = LAYER_CONTROL_UNORDERED; - unordered_layer_location.overridden_rank = 999; - gathered_parameters.push_back(unordered_layer_location); - */ - return gathered_parameters; -} - -bool UseBuiltinValidationSettings(const Parameter& parameter) { - if (parameter.key != "VK_LAYER_KHRONOS_validation") { - return false; - } - for (std::size_t j = 0, m = parameter.settings.size(); j < m; ++j) { - const SettingData* setting_data = parameter.settings[j]; - if (setting_data->key == "validation_control") { - return false; - } - } + Parameter unordered_layer_location; + unordered_layer_location.key = "Unordered Layers"; + unordered_layer_location.control = LAYER_CONTROL_UNORDERED; + unordered_layer_location.overridden_rank = 999; + gathered_parameters.push_back(unordered_layer_location); - return true; + return gathered_parameters; } diff --git a/vkconfig_core/parameter.h b/vkconfig_core/parameter.h index beed5f3c6a..ac291f8c83 100644 --- a/vkconfig_core/parameter.h +++ b/vkconfig_core/parameter.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,8 @@ #pragma once #include "layer.h" -#include "layer_state.h" #include "setting.h" +#include "type_layer_control.h" #include @@ -35,51 +35,30 @@ enum ParameterRank { PARAMETER_RANK_EXPLICIT_AVAILABLE }; -enum LayerControl { - LAYER_CONTROL_OFF = 0, - LAYER_CONTROL_ON, - LAYER_CONTROL_AUTO, - LAYER_CONTROL_APPLICATIONS, - LAYER_CONTROL_UNORDERED, - - LAYER_CONTROL_FIRST = LAYER_CONTROL_OFF, - LAYER_CONTROL_LAST = LAYER_CONTROL_UNORDERED -}; - -enum { LAYER_CONTROL_COUNT = LAYER_CONTROL_LAST - LAYER_CONTROL_FIRST + 1 }; - struct Parameter { static const int NO_RANK = -1; - Parameter() : state(LAYER_STATE_APPLICATION_CONTROLLED), platform_flags(PLATFORM_DESKTOP_BIT), overridden_rank(NO_RANK) { - assert(true); - } + Parameter() : control(LAYER_CONTROL_AUTO) {} - Parameter(const std::string& key, const LayerState state) - : key(key), state(state), control(LAYER_CONTROL_AUTO), platform_flags(PLATFORM_DESKTOP_BIT), overridden_rank(NO_RANK) { - assert(true); - } + Parameter(const std::string& key, const LayerControl control) : key(key), control(control) {} bool ApplyPresetSettings(const LayerPreset& preset); std::string key; - LayerState state; - LayerControl control; - int platform_flags; + LayerControl control = LAYER_CONTROL_AUTO; + int platform_flags = PLATFORM_DESKTOP_BIT; SettingDataSet settings; - int overridden_rank; - Version api_version; + int overridden_rank = NO_RANK; + Version api_version = Version::VERSION_NULL; }; ParameterRank GetParameterOrdering(const std::vector& available_layers, const Parameter& parameter); Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const std::vector& layers); void OrderParameter(std::vector& parameters, const std::vector& layers); -void FilterParameters(std::vector& parameters, const LayerState state); +void FilterParameters(std::vector& parameters, const LayerControl control); std::vector GatherParameters(const std::vector& parameters, const std::vector& available_layers); bool HasMissingLayer(const std::vector& parameters, const std::vector& layers, std::string& missing_layer); std::size_t CountOverriddenLayers(const std::vector& parameters); std::size_t CountExcludedLayers(const std::vector& parameters, const std::vector& layers); - -bool UseBuiltinValidationSettings(const Parameter& parameter); diff --git a/vkconfig_core/path.cpp b/vkconfig_core/path.cpp index a7649def4f..3b136a2064 100644 --- a/vkconfig_core/path.cpp +++ b/vkconfig_core/path.cpp @@ -22,281 +22,399 @@ #include "json.h" #include "alert.h" #include "path.h" -#include "path_manager.h" -#include "platform.h" +#include "type_platform.h" #include +#include #include #include #include -std::string vkconfig_version = "vkconfig"; +static const std::string VKCONFIG_VERSION("vkconfig"); -Path::Path() {} +struct BuiltinDesc { + const char* key; + const Path::Builtin path; +}; -Path::Path(const char* path) : data(ConvertNativeSeparators(path)) {} +static const BuiltinDesc VARIABLES[] = {{"${VK_HOME}", Path::HOME}, + {"${VK_APPDATA}", Path::APPDATA}, + {"${VULKAN_SDK}", Path::SDK}, + {"${VULKAN_CONTENT}", Path::CONTENT}}; -Path::Path(const std::string& path) : data(ConvertNativeSeparators(path)) {} +static std::string ConvertSeparators(const std::string& path, const char* native_separator, const char* alien_separator) { + const std::size_t native_separator_size = std::strlen(native_separator); + const std::size_t alien_separator_size = std::strlen(alien_separator); -Path& Path::operator=(const std::string& path) { - data = ConvertNativeSeparators(path); - return *this; -} + std::string current_path = path; + while (current_path.find_first_of(alien_separator) < current_path.size()) { + const std::size_t found = current_path.find_first_of(alien_separator); + const std::size_t size = current_path.size(); -const char* Path::c_str() const { - assert(ConvertNativeSeparators(data) == data); + if (found < size - alien_separator_size) + current_path = current_path.substr(0, found) + native_separator + + current_path.substr(found + alien_separator_size, size - found - alien_separator_size); + else + current_path = current_path.substr(0, found); + } - return data.c_str(); + // Remove trailing native separator + const std::size_t found = current_path.find_last_of(native_separator); + const std::size_t size = current_path.size(); + if (found == size - native_separator_size) { + current_path = current_path.substr(0, found); + } + + return current_path; } -void CheckPathsExist(const std::string& path, bool is_full_path) { - QString tmp_path(ConvertNativeSeparators(path).c_str()); +static const char* GetNativeSeparator() { + static const char* native_separator = VKC_ENV == VKC_ENV_WIN32 ? "\\" : "/"; + return native_separator; +} - if (is_full_path) { - QFileInfo file_info(tmp_path); - tmp_path = file_info.absoluteDir().absolutePath(); - } +static std::string ConvertNativeSeparators(const std::string& path) { + const char* native_separator = GetNativeSeparator(); + const char* alien_separator = VKC_ENV != VKC_ENV_WIN32 ? "\\" : "/"; - QDir dir; - if (!dir.exists(tmp_path)) { - dir.mkpath(tmp_path); - assert(dir.exists(tmp_path)); - } + return ConvertSeparators(path, native_separator, alien_separator); } -std::string GetPath(BuiltinPath path) { - std::string result; +Path::Path() {} - switch (path) { - case BUILTIN_PATH_HOME: { - result = QDir().homePath().toStdString(); - break; - } - case BUILTIN_PATH_LOCAL_LEGACY: - case BUILTIN_PATH_LOCAL: { - result = qgetenv("VK_LOCAL").toStdString(); - if (result.empty()) { - result = GetPath(BUILTIN_PATH_HOME) + "/VulkanSDK"; - } - break; - } - case BUILTIN_PATH_CONFIG_REF: { - static const std::string TABLE[] = { - "/" + vkconfig_version + "/configurations", // ENVIRONMENT_WIN32 - "/lunarg-" + vkconfig_version + "/configurations" // ENVIRONMENT_UNIX - }; - static_assert(countof(TABLE) == ENVIRONMENT_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - result = GetPath(BUILTIN_PATH_APPDATA) + TABLE[VKC_ENV]; - break; - } - case BUILTIN_PATH_CONFIG_LAST: { - const std::string config = format("_%d_%d_%d", Version::LAYER_CONFIG.GetMajor(), Version::LAYER_CONFIG.GetMinor(), - Version::LAYER_CONFIG.GetPatch()); +Path::Path(const Path& path) : data(path.data) {} - result = GetPath(BUILTIN_PATH_CONFIG_REF) + config; - break; - } - case BUILTIN_PATH_APPLIST: { - result = GetPath(BUILTIN_PATH_CONFIG_LAST) + "/../applist.json"; - break; - } - case BUILTIN_PATH_VKCONFIG_SETTINGS: { - result = GetPath(BUILTIN_PATH_CONFIG_LAST) + "/../vkconfig.json"; - break; - } - case BUILTIN_PATH_OVERRIDE_SETTINGS: { - static const std::string TABLE[] = { - "/" + vkconfig_version + "/override", // ENVIRONMENT_WIN32 - "/settings.d" // ENVIRONMENT_UNIX - }; - static_assert(countof(TABLE) == ENVIRONMENT_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - result = qgetenv("VK_LAYER_SETTINGS_PATH").toStdString(); - if (result.empty()) { - result = GetPath(BUILTIN_PATH_APPDATA) + TABLE[VKC_ENV]; - } - if (result.find("vk_layer_settings.txt") == std::string::npos) { - result += "/vk_layer_settings.txt"; +Path::Path(const char* path) : Path(std::string(path)) {} + +Path::Path(const std::string& path, bool recover_vars) { + std::string result = path; + + if (recover_vars) { + for (std::size_t i = 0, n = std::size(VARIABLES); i < n; ++i) { + std::string substring = ::Get(VARIABLES[i].path).AbsolutePath(); + + const std::size_t found = result.find(substring); + if (found < substring.size()) { + assert(found == 0); // The builtin variable must be first part of the path + const std::size_t offset = found + substring.size(); + const std::string replaced_path = VARIABLES[i].key + result.substr(found + offset, result.size() - offset); + result = ConvertNativeSeparators(replaced_path); + break; } - break; - } - case BUILTIN_PATH_OVERRIDE_LAYERS: { - static const std::string TABLE[] = { - "/" + vkconfig_version + "/override", // ENVIRONMENT_WIN32 - "/implicit_layer.d" // ENVIRONMENT_UNIX - }; - static_assert(countof(TABLE) == ENVIRONMENT_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - result = GetPath(BUILTIN_PATH_APPDATA) + TABLE[VKC_ENV]; - result += "/VkLayer_override.json"; - break; - } - case BUILTIN_PATH_APPDATA: { - static const char* TABLE[] = { - "/AppData/Local/LunarG", // ENVIRONMENT_WIN32 - "/.local/share/vulkan" // ENVIRONMENT_UNIX - }; - static_assert(countof(TABLE) == ENVIRONMENT_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - result = GetPath(BUILTIN_PATH_HOME) + TABLE[VKC_ENV]; - break; } - case BUILTIN_PATH_EXPLICIT_LAYERS: { - static const char* TABLE[] = { - "/Bin", // ENVIRONMENT_WIN32 - "/etc/vulkan/explicit_layer.d" // ENVIRONMENT_UNIX - }; - static_assert(countof(TABLE) == ENVIRONMENT_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - result = GetPath(BUILTIN_PATH_VULKAN_SDK) + TABLE[VKC_ENV]; - break; - } - case BUILTIN_PATH_VULKAN_SDK: { - static const char* TABLE[] = { - "N/A", // PLATFORM_WINDOWS - "/usr", // PLATFORM_LINUX - "/usr/local/share/vulkan", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID - }; - static_assert(countof(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - result = qgetenv("VULKAN_SDK").toStdString(); - if (result.empty()) { - if (VKC_PLATFORM != VKC_PLATFORM_WINDOWS) { - result = TABLE[VKC_PLATFORM]; - } else { - result = GetPath(BUILTIN_PATH_LOCAL); - } - } else { // VULKAN_SDK may be set on macOS - if (VKC_PLATFORM == VKC_PLATFORM_MACOS) result += "/share/vulkan"; - } + } - break; - } - case BUILTIN_PATH_VULKAN_CONTENT: { - static const char* TABLE[] = { - "/Config", // PLATFORM_WINDOWS - "/share/vulkan/config", // PLATFORM_LINUX - "/config", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID - }; - static_assert(countof(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - result = GetPath(BUILTIN_PATH_VULKAN_SDK) + TABLE[VKC_PLATFORM]; - break; + this->data = result; +} + +bool Path::IsFile() const { return QFileInfo(this->data.c_str()).isFile(); } + +bool Path::IsDir() const { return QFileInfo(this->data.c_str()).isDir(); } + +Path& Path::operator=(const Path& path) { + this->data = path.data; + return *this; +} + +Path& Path::operator=(const char* path) { + this->data = path; + return *this; +} + +Path& Path::operator=(const std::string& path) { + this->data = path; + return *this; +} + +Path& Path::operator+=(const std::string& extend) { + this->data += extend; + return *this; +} + +void Path::Clear() { this->data.clear(); } + +bool Path::Exists() const { return QFileInfo(this->AbsolutePath().c_str()).exists(); } + +bool Path::Create(bool as_file) const { + if (this->data.empty()) { + return false; + } + + if (as_file) { + QFile file(this->AbsolutePath().c_str()); + if (!file.exists()) { + return file.open(QFile::WriteOnly); } - default: { - assert(0); - return ""; + } else { + QDir dir; + std::string actual_path = this->AbsolutePath(); + if (!dir.exists(actual_path.c_str())) { + return dir.mkpath(actual_path.c_str()); } } - return ConvertNativeSeparators(result); + return true; } -struct BuiltinDesc { - BuiltinPath type; - const char* name; -}; +bool Path::Remove() const { + if (!this->Exists()) { + return false; + } + + if (this->IsFile()) { + return QFile::remove(this->AbsolutePath().c_str()); + } else { + return QDir(this->AbsolutePath().c_str()).removeRecursively(); + } +} -std::string ReplaceBuiltInVariable(const std::string& path) { - static const BuiltinDesc VARIABLES[] = {{BUILTIN_PATH_HOME, "${HOME}"}, - {BUILTIN_PATH_LOCAL_LEGACY, "${LOCAL}"}, - {BUILTIN_PATH_LOCAL, "${VK_LOCAL}"}, - {BUILTIN_PATH_APPDATA, "${VK_APPDATA}"}, - {BUILTIN_PATH_VULKAN_SDK, "${VULKAN_SDK}"}, - {BUILTIN_PATH_VULKAN_CONTENT, "${VULKAN_CONTENT}"}}; - - for (std::size_t i = 0, n = countof(VARIABLES); i < n; ++i) { - const std::size_t found = path.find(VARIABLES[i].name); - if (found < path.size()) { +std::string Path::Filename() const { + QFileInfo info(this->AbsolutePath().c_str()); + return info.fileName().toStdString(); +} + +std::string Path::Basename() const { + QFileInfo info(this->AbsolutePath().c_str()); + return info.baseName().toStdString(); +} + +std::string Path::AbsoluteDir() const { + QFileInfo info(this->AbsolutePath().c_str()); + return ConvertNativeSeparators(info.absoluteDir().path().toStdString()); +} + +std::string Path::AbsolutePath() const { + for (std::size_t i = 0, n = std::size(VARIABLES); i < n; ++i) { + const std::size_t found = this->data.find(VARIABLES[i].key); + if (found < this->data.size()) { assert(found == 0); // The builtin variable must be first part of the path - const std::size_t offset = found + std::strlen(VARIABLES[i].name); - const std::string replaced_path = GetPath(VARIABLES[i].type) + path.substr(found + offset, path.size() - offset); + const std::size_t offset = found + std::strlen(VARIABLES[i].key); + const std::string replaced_path = + Get(VARIABLES[i].path).RelativePath() + this->data.substr(found + offset, this->data.size() - offset); return ConvertNativeSeparators(replaced_path); } } // No built-in variable found, return unchanged - return path; + return ConvertNativeSeparators(this->data); } -std::string ConvertSeparators(const std::string& path, const char* native_separator, const char* alien_separator) { - const std::size_t native_separator_size = std::strlen(native_separator); - const std::size_t alien_separator_size = std::strlen(alien_separator); +std::string Path::RelativePath() const { + // Store trailing separator to enable operator + and += + return ConvertNativeSeparators(this->data); +} - std::string current_path = path; - while (current_path.find_first_of(alien_separator) < current_path.size()) { - const std::size_t found = current_path.find_first_of(alien_separator); - const std::size_t size = current_path.size(); +std::string Path::LastModified() const { + QFileInfo file_info(this->data.c_str()); - if (found < size - alien_separator_size) - current_path = current_path.substr(0, found) + native_separator + - current_path.substr(found + alien_separator_size, size - found - alien_separator_size); - else - current_path = current_path.substr(0, found); + return file_info.lastModified().toString(Qt::ISODate).toStdString(); +} + +bool operator==(const Path& a, const Path& b) { return a.AbsolutePath() == b.AbsolutePath(); } + +Path operator+(const Path& path, const std::string& extend) { return Path(path.data + extend); } + +static const Path GetHomePath() { + std::string result = qgetenv("VK_HOME").toStdString(); + + if (result.empty()) { // Defaukt path + result = QDir().homePath().toStdString() + "/VulkanSDK"; } - // Remove trailing native separator - const std::size_t found = current_path.find_last_of(native_separator); - const std::size_t size = current_path.size(); - if (found == size - native_separator_size) current_path = current_path.substr(0, found); + Path path(result); - return current_path; + if (!path.Exists()) { + path.Create(); + } + + return path; } -const char* GetNativeSeparator() { - static const char* native_separator = VKC_ENV == VKC_ENV_WIN32 ? "\\" : "/"; - return native_separator; +static const Path GetAppDataPath() { + const char* TABLE[] = { + "/AppData/Local/LunarG", // ENVIRONMENT_WIN32 + "/.local/share/vulkan" // ENVIRONMENT_UNIX + }; + static_assert(std::size(TABLE) == ENVIRONMENT_COUNT); + + return QDir().homePath().toStdString() + TABLE[VKC_ENV]; } -std::string ConvertNativeSeparators(const std::string& path) { - const char* native_separator = GetNativeSeparator(); - const char* alien_separator = VKC_ENV != VKC_ENV_WIN32 ? "\\" : "/"; +static const Path GetInitPath() { + const std::string TABLE[] = { + "/" + VKCONFIG_VERSION + "/vkconfig.json", // ENVIRONMENT_WIN32 + "/lunarg-" + VKCONFIG_VERSION + "/vkconfig.json" // ENVIRONMENT_UNIX + }; + static_assert(std::size(TABLE) == ENVIRONMENT_COUNT); - return ConvertSeparators(path, native_separator, alien_separator); + return GetAppDataPath().RelativePath() + TABLE[VKC_ENV]; } -static bool IsPortableChar(char c) { - if (c == '\\' || c == '/') return false; - if (c == '|' || c == '<' || c == '>') return false; - if (c == ':' || c == '*' || c == '?') return false; +static const Path GetConfigsPath() { + const std::string TABLE[] = { + "/" + VKCONFIG_VERSION + "/configurations", // ENVIRONMENT_WIN32 + "/lunarg-" + VKCONFIG_VERSION + "/configurations" // ENVIRONMENT_UNIX + }; + static_assert(std::size(TABLE) == ENVIRONMENT_COUNT); - return true; + Path app_data_path = GetAppDataPath(); + Path path(app_data_path + TABLE[VKC_ENV]); + + if (!path.Exists()) { + path.Create(); + } + + return path; } -bool IsPortableFilename(const std::string& path) { - if (path.empty()) return false; +static const Path GetLayersSettingsPath() { +#if VKC_ENV == VKC_ENV_WIN32 + const std::string layers_settings_path = "/" + VKCONFIG_VERSION + "/override"; +#elif VKC_ENV == VKC_ENV_UNIX + const std::string layers_settings_path = "/settings.d"; +#else +#error Unknown platform +#endif + + std::string result = qgetenv("VK_LAYER_SETTINGS_PATH").toStdString(); + if (result.empty()) { + result = GetAppDataPath().RelativePath() + layers_settings_path; + } + if (result.find("vk_layer_settings.txt") == std::string::npos) { + result += "/vk_layer_settings.txt"; + } - if (path == ".") return false; + Path path(result); - if (path.find("..") != std::string::npos) return false; + Path folder(path.AbsoluteDir()); + if (!folder.Exists()) { + folder.Create(); + } + + return path; +} - for (std::size_t i = 0, n = path.size(); i < n; ++i) { - if (!IsPortableChar(path[i])) return false; +static const Path GetLoaderSettingsPath() { +#if VKC_ENV == VKC_ENV_WIN32 + const std::string loader_settings_path = "/vulkan"; +#elif VKC_ENV == VKC_ENV_UNIX + const std::string loader_settings_path = "/loader_settings.d"; +#else +#error Unknown platform +#endif + + std::string result = GetAppDataPath().RelativePath() + loader_settings_path; + if (result.find("vk_loader_settings.json") == std::string::npos) { + result += "/vk_loader_settings.json"; } - return true; + Path path(result); + + Path folder(path.AbsoluteDir()); + if (!folder.Exists()) { + folder.Create(); + } + + return path; } -QFileInfoList GetJSONFiles(const char* directory) { - QDir dir(directory); - dir.setFilter(QDir::Files | QDir::NoSymLinks); - dir.setNameFilters(QStringList() << "*.json"); - return dir.entryInfoList(); +static const Path GetSDKPath() { + const char* TABLE[] = { + "", // PLATFORM_WINDOWS + "/usr", // PLATFORM_LINUX + "/usr/local/share/vulkan", // PLATFORM_MACOS + "" // PLATFORM_ANDROID + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + std::string result = qgetenv("VULKAN_SDK").toStdString(); + if (result.empty()) { + result = TABLE[VKC_PLATFORM]; + } else { // VULKAN_SDK may be set on macOS + if (VKC_PLATFORM == VKC_PLATFORM_MACOS) { + result += "/share/vulkan"; + } + } + + return result; +} + +static const Path GetSDKBinPath() { + const char* TABLE[] = { + "/Bin", // ENVIRONMENT_WIN32 + "/bin", // ENVIRONMENT_UNIX + }; + static_assert(std::size(TABLE) == ENVIRONMENT_COUNT); + + return GetSDKPath() + TABLE[VKC_ENV]; +} + +static const Path GetExplicitLayersPath() { + static const std::string TABLE[] = { + "/Bin", // ENVIRONMENT_WIN32 + "/etc/vulkan/explicit_layer.d" // ENVIRONMENT_UNIX + }; + static_assert(std::size(TABLE) == ENVIRONMENT_COUNT); + + return GetSDKPath().RelativePath() + TABLE[VKC_ENV]; } -std::string ExtractAbsoluteDir(const std::string& path) { - assert(!path.empty()); +static const Path GetVulkanContentPath() { + static const std::string TABLE[] = { + "/Config", // PLATFORM_WINDOWS + "/share/vulkan/config", // PLATFORM_LINUX + "/config", // PLATFORM_MACOS + "N/A" // PLATFORM_ANDROID + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT); - return ConvertNativeSeparators(QFileInfo(path.c_str()).absoluteDir().path().toStdString()); + return GetSDKPath().RelativePath() + TABLE[VKC_PLATFORM]; +} + +Path Get(Path::Builtin path) { + switch (path) { + default: + assert(0); + return ""; + case Path::HOME: + return ::GetHomePath(); + case Path::APPDATA: + return ::GetAppDataPath(); + case Path::INIT: + return ::GetInitPath(); + case Path::CONFIGS: + return ::GetConfigsPath(); + case Path::LAYERS_SETTINGS: + return ::GetLayersSettingsPath(); + case Path::LOADER_SETTINGS: + return ::GetLoaderSettingsPath(); + case Path::SDK: + return ::GetSDKPath(); + case Path::SDK_BIN: + return ::GetSDKBinPath(); + case Path::EXPLICIT_LAYERS: + return ::GetExplicitLayersPath(); + case Path::CONTENT: + return ::GetVulkanContentPath(); + } +} + +std::string AbsolutePath(Path::Builtin path) { return Get(path).AbsolutePath(); } + +std::string RelativePath(Path::Builtin path) { return Get(path).RelativePath(); } + +std::vector CollectFilePaths(const Path& directory, const char* filter) { + const std::string& absolute_path = directory.AbsolutePath(); + + const QDir dir(absolute_path.c_str()); + const QFileInfoList& list = dir.entryInfoList(QStringList() << filter, QDir::Files | QDir::NoSymLinks); + + std::vector result; + for (int i = 0, n = list.size(); i < n; ++i) { + result.push_back(list[i].absoluteFilePath().toStdString()); + } + return result; } static std::vector LoadProfiles(const QJsonDocument& doc) { @@ -310,13 +428,12 @@ static std::vector LoadProfiles(const QJsonDocument& doc) { return ConvertString(ReadObject(json_root_object, "profiles").keys()); } -std::vector GetProfileNamesFromFile(const std::string& profile_path) { - const std::string& value = ReplaceBuiltInVariable(profile_path); - if (value.empty()) { +std::vector CollectProfileNamesFromFile(const Path& profile_path) { + if (profile_path.Empty()) { return std::vector(); } - const QJsonDocument& doc = ParseJsonFile(value.c_str()); + const QJsonDocument& doc = ParseJsonFile(profile_path.AbsolutePath().c_str()); if (doc.isNull() || doc.isEmpty()) { return std::vector(); @@ -331,33 +448,57 @@ std::vector GetProfileNamesFromFile(const std::string& profile_path return LoadProfiles(doc); } -std::vector GetProfileNamesFromDir(const std::string& profile_path) { - std::vector profile_names; - - std::string value = ReplaceBuiltInVariable(profile_path); - if (value.empty()) { +std::vector CollectProfileNamesFromDir(const Path& profile_path) { + if (profile_path.Empty()) { return std::vector(); } + Path path = profile_path; + // Windows workaround so that the user could select C: D: etc QDir doesn't recognize it as valid path other wise if (VKC_ENV == VKC_ENV_WIN32) { - if (!EndsWith(value, "\\")) { - value += "\\"; + if (!EndsWith(path.AbsolutePath().c_str(), "\\")) { + path += "\\"; } } - QDir dir(value.c_str()); - QFileInfoList file_info_list = dir.entryInfoList(QStringList() << "*.json", QDir::Files); - - QStringList files; - for (int file_index = 0, file_count = file_info_list.size(); file_index < file_count; ++file_index) { - files << file_info_list[file_index].filePath(); - } + const std::vector& files = CollectFilePaths(path.AbsolutePath().c_str()); + std::vector profile_names; for (std::size_t i = 0, n = files.size(); i < n; ++i) { - const std::vector& profile_names_of_files = GetProfileNamesFromFile(files[i].toStdString()); + const std::vector& profile_names_of_files = CollectProfileNamesFromFile(files[i]); profile_names.insert(profile_names.end(), profile_names_of_files.begin(), profile_names_of_files.end()); } return profile_names; } + +static bool IsPortableChar(char c) { + if (c == '\\' || c == '/') return false; + if (c == '|' || c == '<' || c == '>') return false; + if (c == ':' || c == '*' || c == '?') return false; + + return true; +} + +bool IsPortableFilename(const std::string& s) { + if (s.empty()) { + return false; + } + + if (s == ".") { + return false; + } + + if (s.find("..") != std::string::npos) { + return false; + } + + for (std::size_t i = 0, n = s.size(); i < n; ++i) { + if (!IsPortableChar(s[i])) { + return false; + } + } + + return true; +} diff --git a/vkconfig_core/path.h b/vkconfig_core/path.h index 2003ce803b..9ddc71bc26 100644 --- a/vkconfig_core/path.h +++ b/vkconfig_core/path.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,64 +24,66 @@ #include -enum BuiltinPath { - BUILTIN_PATH_HOME = 0, - BUILTIN_PATH_LOCAL_LEGACY, - BUILTIN_PATH_LOCAL, - BUILTIN_PATH_APPDATA, - BUILTIN_PATH_CONFIG_REF, - BUILTIN_PATH_CONFIG_LAST, - BUILTIN_PATH_APPLIST, - BUILTIN_PATH_OVERRIDE_LAYERS, - BUILTIN_PATH_OVERRIDE_SETTINGS, - BUILTIN_PATH_EXPLICIT_LAYERS, - BUILTIN_PATH_VULKAN_SDK, - BUILTIN_PATH_VULKAN_CONTENT, - BUILTIN_PATH_VKCONFIG_SETTINGS, - - BUILTIN_PATH_FIRST = BUILTIN_PATH_HOME, - BUILTIN_PATH_LAST = BUILTIN_PATH_VKCONFIG_SETTINGS, -}; - -enum { BUILTIN_PATH_COUNT = BUILTIN_PATH_LAST - BUILTIN_PATH_FIRST + 1 }; - -extern std::string vkconfig_version; - class Path { public: + enum Builtin { + HOME, // Vulkan SDK user directory + APPDATA, + INIT, + CONFIGS, + LAYERS_SETTINGS, + LOADER_SETTINGS, + SDK, + SDK_BIN, + EXPLICIT_LAYERS, + CONTENT, + }; + Path(); - explicit Path(const char* path); - explicit Path(const std::string& path); + Path(const Path& path); + Path(const char* path); + Path(const std::string& path, bool recover_vars = false); + Path& operator=(const Path& path); + Path& operator=(const char* path); Path& operator=(const std::string& path); + Path& operator+=(const std::string& extend); - const char* c_str() const; - bool empty() const { return data.empty(); } - - private: - std::string data; -}; + bool IsFile() const; + bool IsDir() const; -std::string ConvertSeparators(const std::string& path, const char* native_separator, const char* alien_separator); + void Clear(); + bool Exists() const; + bool Create(bool as_file = false) const; + bool Remove() const; + std::string Filename() const; + std::string Basename() const; + std::string AbsoluteDir() const; + std::string AbsolutePath() const; // Translate built-in variables into actual path + std::string RelativePath() const; // May contain built-in variables + std::string LastModified() const; -std::string ConvertNativeSeparators(const std::string& path); + bool Empty() const { return this->data.empty(); } -const char* GetNativeSeparator(); + private: + std::string data; -// Create a directory if it doesn't exist -void CheckPathsExist(const std::string& path, bool is_full_path = false); + friend bool operator==(const Path& a, const Path& b); + friend Path operator+(const Path& path, const std::string& extend); +}; -std::string GetPath(BuiltinPath path); +Path Get(Path::Builtin path); +std::string AbsolutePath(Path::Builtin path); +std::string RelativePath(Path::Builtin path); -// Replace built-in variable by the actual path -std::string ReplaceBuiltInVariable(const std::string& path); +bool operator==(const Path& a, const Path& b); -bool IsPortableFilename(const std::string& path); +Path operator+(const Path& path, const std::string& extend); -QFileInfoList GetJSONFiles(const char* directory); +std::vector CollectFilePaths(const Path& directory, const char* filter = "*json"); -std::string ExtractAbsoluteDir(const std::string& path); +std::vector CollectProfileNamesFromFile(const Path& profile_path); -std::vector GetProfileNamesFromFile(const std::string& profile_path); +std::vector CollectProfileNamesFromDir(const Path& profile_path); -std::vector GetProfileNamesFromDir(const std::string& profile_path); +bool IsPortableFilename(const std::string& s); diff --git a/vkconfig_core/path_manager.cpp b/vkconfig_core/path_manager.cpp deleted file mode 100644 index fbf11d78ad..0000000000 --- a/vkconfig_core/path_manager.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "path_manager.h" -#include "path.h" -#include "util.h" -#include "platform.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -struct DirectoryDesc { - const char* default_extension; // file extension used to path - const char* setting_data; // system token to store the path, if empty the directory is not saved - const char* default_filename; // a default filename, if empty there is no default filename - PathType alternative; -}; - -static const DirectoryDesc& GetDesc(PathType directory) { - assert(directory >= PATH_FIRST && directory <= PATH_LAST); - - static const DirectoryDesc table[] = { - {".json", "lastImportPath", nullptr, PATH_EXPORT_CONFIGURATION}, // PATH_IMPORT - {".json", "lastExportPath", nullptr, PATH_IMPORT_CONFIGURATION}, // PATH_EXPORT -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS - {".exe", "lastExecutablePath", nullptr, PATH_WORKING_DIR}, // PATH_EXECUTABLE -#else - {"", "lastExecutablePath", nullptr, PATH_WORKING_DIR}, // PATH_EXECUTABLE -#endif - {nullptr, "lastWorkingDirPath", nullptr, PATH_EXECUTABLE}, // PATH_EXECUTABLE - {".txt", "lastLauncherLogFile", "log", PATH_LAUNCHER_LOG_FILE}, // PATH_LAUNCHER_LOG_FILE - {".json", "lastLayersPaths", nullptr, PATH_USER_DEFINED_LAYERS_GUI}, // PATH_USER_DEFINED_LAYERS_GUI - {nullptr, "vulkan_sdk", nullptr, PATH_VULKAN_SDK} // PATH_VULKAN_SDK - }; - static_assert(countof(table) == PATH_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return table[directory]; -} - -PathManager::PathManager(const std::string& VULKAN_SDK, const std::vector& SUPPORTED_CONFIG_FILES) - : SUPPORTED_CONFIG_FILES(SUPPORTED_CONFIG_FILES) { - const bool result = Load(); - - const std::string path = VULKAN_SDK.empty() ? qgetenv("VULKAN_SDK").toStdString() : VULKAN_SDK; - if (!path.empty()) { - this->SetPath(PATH_VULKAN_SDK, path); - } - - assert(result); -} - -PathManager::~PathManager() { - const bool result = Save(); - assert(result); -} - -bool PathManager::Load() { - QSettings settings; - for (std::size_t i = 0; i < PATH_COUNT; ++i) { - const PathType type = static_cast(i); - if (GetDesc(type).setting_data == nullptr) continue; - paths[type] = settings.value(GetDesc(type).setting_data).toString().toStdString(); - } - - CheckPathsExist(::GetPath(BUILTIN_PATH_LOCAL)); - CheckPathsExist(::GetPath(BUILTIN_PATH_CONFIG_LAST)); - - CheckPathsExist(::GetPath(BUILTIN_PATH_OVERRIDE_LAYERS), true); - CheckPathsExist(::GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS), true); - - return true; -} - -bool PathManager::Save() { - QSettings settings; - for (std::size_t i = 0; i < PATH_COUNT; ++i) { - const PathType type = static_cast(i); - if (GetDesc(type).setting_data == nullptr) continue; - settings.setValue(GetDesc(type).setting_data, paths[type].c_str()); - } - - return true; -} - -void PathManager::Clear() { - for (std::size_t i = 0; i < PATH_COUNT; ++i) { - const PathType type = static_cast(i); - paths[type].clear(); - } -} - -void PathManager::Reset() { - for (std::size_t i = 0; i < PATH_COUNT; ++i) { - paths[static_cast(i)].clear(); - } -} - -const std::string PathManager::GetPath(PathType path) const { - assert(path >= PATH_FIRST && path <= PATH_LAST); - - if (!paths[path].empty()) { - return paths[path].c_str(); - } - - const PathType alternative_path = GetDesc(path).alternative; - if (!paths[alternative_path].empty()) { - return paths[alternative_path].c_str(); - } - - return ::GetPath(BUILTIN_PATH_HOME); -} - -void PathManager::SetPath(PathType path, const char* path_value) { - assert(path >= PATH_FIRST && path <= PATH_LAST); - assert(path_value); - - const QDir directory(path_value); - const std::string native_path(ConvertNativeSeparators(directory.absolutePath().toStdString())); - paths[path] = native_path; -} - -void PathManager::SetPath(PathType directory, const std::string& path_value) { - assert(!path_value.empty()); - - SetPath(directory, path_value.c_str()); -} - -std::string PathManager::GetFullPath(PathType path, const char* filename) const { - const QFileInfo file_info(filename); - - const std::string path_base(GetPath(path).c_str()); - - const std::string path_filename = - filename != nullptr ? QFileInfo(filename).baseName().toStdString() : GetDesc(path).default_filename; - assert(!path_filename.empty()); // Did you really mean to use GetFullPath? GetPath seem to be the right function here - - const std::string path_suffix = !file_info.completeSuffix().isEmpty() - ? std::string(".") + file_info.completeSuffix().toStdString() - : GetDesc(path).default_extension; - assert(!path_suffix.empty() || VKC_PLATFORM != VKC_PLATFORM_WINDOWS); // Only Windows has a suffix for executable - - const std::string full_path(ConvertNativeSeparators(path_base + GetNativeSeparator() + path_filename + path_suffix)); - return full_path; -} - -std::string PathManager::GetFullPath(PathType path, const std::string& filename) const { - return GetFullPath(path, filename.c_str()); -} - -std::string PathManager::SelectPath(QWidget* parent, PathType path) { - assert(parent); - assert(path >= PATH_FIRST && path <= PATH_LAST); - - return SelectPathImpl(parent, path, GetPath(path).c_str()); -} - -std::string PathManager::SelectPath(QWidget* parent, PathType path, const std::string& suggested_path) { - assert(parent); - assert(path >= PATH_FIRST && path <= PATH_LAST); - - if (suggested_path.empty()) - return SelectPathImpl(parent, path, GetPath(path).c_str()); - else - return SelectPathImpl(parent, path, suggested_path); -} - -std::string PathManager::SelectPathImpl(QWidget* parent, PathType path, const std::string& suggested_path) { - assert(parent); - assert(path >= PATH_FIRST && path <= PATH_LAST); - assert(!suggested_path.empty()); - - switch (path) { - case PATH_LAUNCHER_LOG_FILE: { - const std::string selected_path = - QFileDialog::getSaveFileName(parent, "Set Log File To...", suggested_path.c_str(), "Log text(*.txt)").toStdString(); - if (selected_path.empty()) // The user cancelled - return ""; - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return GetFullPath(path, QFileInfo(selected_path.c_str()).baseName().toStdString()); - } break; - case PATH_EXECUTABLE: { - static const char* TABLE[] = { - "Applications (*.exe)", // PLATFORM_WINDOWS - "Applications (*)", // PLATFORM_LINUX - "Applications (*.app, *)", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID - }; - static_assert(countof(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - const std::string filter = TABLE[VKC_PLATFORM]; - const std::string selected_path = - QFileDialog::getOpenFileName(parent, "Select a Vulkan Executable...", suggested_path.c_str(), filter.c_str()) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return ""; - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return GetFullPath(path, QFileInfo(selected_path.c_str()).fileName().toStdString()); - } - case PATH_WORKING_DIR: { - const std::string selected_path = - QFileDialog::getExistingDirectory(parent, "Set Working Folder To...", suggested_path.c_str()).toStdString(); - if (selected_path.empty()) // The user cancelled - return ""; - - SetPath(path, selected_path); - return GetPath(path).c_str(); - } - case PATH_USER_DEFINED_LAYERS_GUI: { - const std::string selected_path = - QFileDialog::getExistingDirectory(parent, "Add User-Defined Layers Folder...", suggested_path.c_str(), - QFileDialog::DontUseNativeDialog) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return ""; - - SetPath(path, selected_path); - return GetPath(path).c_str(); - } - case PATH_IMPORT_CONFIGURATION: { - const std::string selected_path = QFileDialog::getOpenFileName(parent, "Import Layers Configuration File", - suggested_path.c_str(), "JSON configuration(*.json)") - .toStdString(); - if (selected_path.empty()) // The user cancelled - return ""; - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return selected_path; - } - case PATH_EXPORT_CONFIGURATION: { - const std::string selected_path = QFileDialog::getSaveFileName(parent, "Export Layers Configuration File", - suggested_path.c_str(), "JSON configuration(*.json)") - .toStdString(); - if (selected_path.empty()) // The user cancelled - return ""; - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return selected_path; - } - default: - assert(0); - return ""; - } -} diff --git a/vkconfig_core/path_manager.h b/vkconfig_core/path_manager.h deleted file mode 100644 index e158db993e..0000000000 --- a/vkconfig_core/path_manager.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "path.h" -#include "version.h" - -#include -#include - -enum PathType { - PATH_IMPORT_CONFIGURATION = 0, // The last path used by the user to import a configuration - PATH_EXPORT_CONFIGURATION, // The last path used by the user to export a configuration - PATH_EXECUTABLE, // The last path used by the user when adding an executable to the application list - PATH_WORKING_DIR, // The last path used as a working directory - PATH_LAUNCHER_LOG_FILE, // The last path used by the user to set the launcher log file - PATH_USER_DEFINED_LAYERS_GUI, // The last user-defined layers path - PATH_VULKAN_SDK, // Path of the Vulkan SDK - - PATH_FIRST = PATH_IMPORT_CONFIGURATION, - PATH_LAST = PATH_VULKAN_SDK -}; - -enum { PATH_COUNT = PATH_LAST - PATH_FIRST + 1 }; - -class PathManager { - public: - PathManager(const std::string& VULKAN_SDK, const std::vector& SUPPORTED_CONFIG_FILES); - ~PathManager(); - - bool Load(); - bool Save(); - - const std::string GetPath(PathType path) const; - - // The path value should not have the filename - void SetPath(PathType path, const char* path_value); - - // The path value should not have the filename - void SetPath(PathType path, const std::string& path_value); - - // When filename is set to nullptr, the function will try to use the default filename if there is one for the DirectoryType - std::string GetFullPath(PathType path, const char* filename = nullptr) const; - std::string GetFullPath(PathType path, const std::string& filename) const; - - std::string SelectPath(QWidget* parent, PathType path); - std::string SelectPath(QWidget* parent, PathType path, const std::string& suggested_path); - - void Clear(); - void Reset(); - - const std::vector SUPPORTED_CONFIG_FILES; - - private: - PathManager(const PathManager&) = delete; - PathManager& operator=(const PathManager&) = delete; - - std::string SelectPathImpl(QWidget* parent, PathType path, const std::string& suggested_path); - - std::array paths; -}; diff --git a/vkconfig_core/registry.cpp b/vkconfig_core/registry.cpp index 919216be03..b2accffa16 100644 --- a/vkconfig_core/registry.cpp +++ b/vkconfig_core/registry.cpp @@ -31,13 +31,13 @@ /// On Windows the overide json file and settings file are not used unless the path to those /// files are stored in the registry. -void AppendRegistryEntriesForLayers(QString override_file, QString settings_file) { +void AppendRegistryEntriesForLayers(QString loader_settings_file, QString layers_settings_file) { // Layer override json file HKEY key; const HKEY userKey = IsUserAnAdmin() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; REGSAM access = KEY_WRITE; - LSTATUS err = RegCreateKeyEx(userKey, TEXT("SOFTWARE\\Khronos\\Vulkan\\ImplicitLayers"), 0, NULL, REG_OPTION_NON_VOLATILE, + LSTATUS err = RegCreateKeyEx(userKey, TEXT("SOFTWARE\\Khronos\\Vulkan\\LoaderSettings"), 0, NULL, REG_OPTION_NON_VOLATILE, access, NULL, &key, NULL); if (err != ERROR_SUCCESS) return; @@ -45,7 +45,7 @@ void AppendRegistryEntriesForLayers(QString override_file, QString settings_file DWORD value_count; DWORD value = 0; RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, &value_count, NULL, NULL, NULL, NULL); - RegSetValueExW(key, (LPCWSTR)override_file.utf16(), 0, REG_DWORD, (BYTE *)&value, sizeof(value)); + RegSetValueExW(key, (LPCWSTR)loader_settings_file.utf16(), 0, REG_DWORD, (BYTE *)&value, sizeof(value)); RegCloseKey(key); // Layer settings file @@ -54,23 +54,23 @@ void AppendRegistryEntriesForLayers(QString override_file, QString settings_file if (err != ERROR_SUCCESS) return; RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL, &value_count, NULL, NULL, NULL, NULL); - RegSetValueExW(key, (LPCWSTR)settings_file.utf16(), 0, REG_DWORD, (BYTE *)&value, sizeof(value)); + RegSetValueExW(key, (LPCWSTR)layers_settings_file.utf16(), 0, REG_DWORD, (BYTE *)&value, sizeof(value)); RegCloseKey(key); } /// On Windows the overide json file and settings file are not used unless the path to those /// files are stored in the registry. -void RemoveRegistryEntriesForLayers(QString override_file, QString settings_file) { +void RemoveRegistryEntriesForLayers(QString loader_settings_file, QString layers_settings_file) { // Layer override json file HKEY key; HKEY userKey = IsUserAnAdmin() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; REGSAM access = KEY_WRITE; - LSTATUS err = RegCreateKeyEx(userKey, TEXT("SOFTWARE\\Khronos\\Vulkan\\ImplicitLayers"), 0, NULL, REG_OPTION_NON_VOLATILE, + LSTATUS err = RegCreateKeyEx(userKey, TEXT("SOFTWARE\\Khronos\\Vulkan\\LoaderSettings"), 0, NULL, REG_OPTION_NON_VOLATILE, access, NULL, &key, NULL); if (err != ERROR_SUCCESS) return; - RegDeleteValueW(key, (LPCWSTR)override_file.utf16()); + RegDeleteValueW(key, (LPCWSTR)loader_settings_file.utf16()); RegCloseKey(key); // Layer settings file @@ -78,12 +78,12 @@ void RemoveRegistryEntriesForLayers(QString override_file, QString settings_file NULL); if (err != ERROR_SUCCESS) return; - RegDeleteValueW(key, (LPCWSTR)settings_file.utf16()); + RegDeleteValueW(key, (LPCWSTR)layers_settings_file.utf16()); RegCloseKey(key); } /// Look for device specific layers -static void LoadDeviceRegistry(DEVINST id, const QString &entry, std::vector &layers, LayerType type) { +static void LoadDeviceRegistry(DEVINST id, const QString &entry, std::vector &layers_paths) { HKEY key; if (CM_Open_DevNode_Key(id, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &key, CM_REGISTRY_SOFTWARE) != CR_SUCCESS) return; @@ -103,10 +103,8 @@ static void LoadDeviceRegistry(DEVINST id, const QString &entry, std::vector &layers, LayerType type) { +std::vector LoadRegistryLayers(const QString &path) { + std::vector layers_paths; + QString root_string = path.section('\\', 0, 0); static QHash root_keys = { {"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT}, @@ -156,10 +156,10 @@ void LoadRegistryLayers(const QString &path, std::vector &layers, LayerTy // This has already been set by now if (path.endsWith("VulkanExplicitLayers")) { entry = "VulkanExplicitLayers"; - type = LAYER_TYPE_EXPLICIT; + // type = LAYER_TYPE_EXPLICIT; } else if (path.endsWith("VulkanImplicitLayers")) { entry = "VulkanImplicitLayers"; - type = LAYER_TYPE_IMPLICIT; + // type = LAYER_TYPE_IMPLICIT; } for (wchar_t *device_name = device_names; device_name[0] != '\0'; device_name += wcslen(device_name) + 1) { @@ -167,7 +167,7 @@ void LoadRegistryLayers(const QString &path, std::vector &layers, LayerTy if (CM_Locate_DevNodeW(&device_id, device_name, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS) { continue; } - LoadDeviceRegistry(device_id, entry, layers, type); + LoadDeviceRegistry(device_id, entry, layers_paths); DEVINST child_id; if (CM_Get_Child(&child_id, device_id, 0) != CR_SUCCESS) { @@ -184,7 +184,7 @@ void LoadRegistryLayers(const QString &path, std::vector &layers, LayerTy continue; } if (wcscmp(child_guid, (LPCWSTR)SOFTWARE_COMPONENT_GUID.utf16()) == 0) { - LoadDeviceRegistry(child_id, entry, layers, type); + LoadDeviceRegistry(child_id, entry, layers_paths); break; } } while (CM_Get_Sibling(&child_id, child_id, 0) == CR_SUCCESS); @@ -194,6 +194,8 @@ void LoadRegistryLayers(const QString &path, std::vector &layers, LayerTy if (device_names != nullptr) { delete[] device_names; } + + return layers_paths; } #endif // VKC_PLATFORM == VKC_PLATFORM_WINDOWS diff --git a/vkconfig_core/registry.h b/vkconfig_core/registry.h index 75ec04598e..2b587180f8 100644 --- a/vkconfig_core/registry.h +++ b/vkconfig_core/registry.h @@ -20,7 +20,7 @@ #pragma once -#include "platform.h" +#include "type_platform.h" #include "layer.h" #if VKC_PLATFORM == VKC_PLATFORM_WINDOWS @@ -33,6 +33,6 @@ void AppendRegistryEntriesForLayers(QString override_file, QString settings_file void RemoveRegistryEntriesForLayers(QString override_file, QString settings_file); -void LoadRegistryLayers(const QString &path, std::vector &layers, LayerType type); +std::vector LoadRegistryLayers(const QString &path); #endif // VKC_PLATFORM == VKC_PLATFORM_WINDOWS diff --git a/vkconfig_core/setting.cpp b/vkconfig_core/setting.cpp index 2520cd48a5..cc9c4344d0 100644 --- a/vkconfig_core/setting.cpp +++ b/vkconfig_core/setting.cpp @@ -45,10 +45,6 @@ SettingType GetSettingType(const char* token) { assert(token != nullptr); assert(std::strcmp(token, "") != 0); - if (SUPPORT_LAYER_CONFIG_2_2_0 && ToUpperCase(token) == "MULTI_ENUM") return SETTING_FLAGS; - if (SUPPORT_LAYER_CONFIG_2_2_0 && ToUpperCase(token) == "VUID_EXCLUDE") return SETTING_LIST; - if (SUPPORT_LAYER_CONFIG_2_2_0 && ToUpperCase(token) == "INT_RANGES") return SETTING_FRAMES; - for (int i = SETTING_FIRST; i <= SETTING_LAST; ++i) { const SettingType type = static_cast(i); if (ToUpperCase(token) == GetToken(type)) return type; @@ -77,7 +73,7 @@ const char* GetToken(SettingType type) { "FRAMES", // SETTING_FRAMES "LIST" // SETTING_LIST }; - static_assert(countof(table) == SETTING_COUNT, "The tranlation table size doesn't match the enum number of elements"); + static_assert(std::size(table) == SETTING_COUNT, "The tranlation table size doesn't match the enum number of elements"); return table[type]; } @@ -352,7 +348,7 @@ const char* GetToken(DependenceMode type) { "ALL", // DEPENDENCE_ALL "ANY" // DEPENDENCE_ANY }; - static_assert(countof(table) == DEPENDENCE_COUNT, "The tranlation table size doesn't match the enum number of elements"); + static_assert(std::size(table) == DEPENDENCE_COUNT, "The tranlation table size doesn't match the enum number of elements"); return table[type]; } diff --git a/vkconfig_core/setting_filesystem.cpp b/vkconfig_core/setting_filesystem.cpp index e2d8e258dd..bda0a9f6a7 100644 --- a/vkconfig_core/setting_filesystem.cpp +++ b/vkconfig_core/setting_filesystem.cpp @@ -43,14 +43,16 @@ std::string SettingMetaFilesystem::Export(ExportMode export_mode) const { assert(0); return ""; case EXPORT_MODE_OVERRIDE: - return ReplaceBuiltInVariable(this->default_value).c_str(); + return this->default_value.AbsolutePath(); case EXPORT_MODE_DOC: - return this->default_value; + return this->default_value.RelativePath(); } } bool SettingMetaFilesystem::Equal(const SettingMeta& other) const { - if (!SettingMeta::Equal(other)) return false; + if (!SettingMeta::Equal(other)) { + return false; + } const SettingMetaFilesystem& meta = static_cast(other); @@ -59,7 +61,34 @@ bool SettingMetaFilesystem::Equal(const SettingMeta& other) const { // SettingDataFilesystem -SettingDataFilesystem::SettingDataFilesystem(const std::string& key, const SettingType& type) : SettingDataString(key, type) {} +SettingDataFilesystem::SettingDataFilesystem(const SettingMetaFilesystem* meta) : SettingData(meta->key, meta->type), meta(meta) { + assert(meta != nullptr); + this->Reset(); +} + +SettingDataFilesystem::SettingDataFilesystem(const std::string& key, const SettingType& type) : SettingData(key, type) {} + +void SettingDataFilesystem::Reset() { + assert(meta != nullptr); + this->value = this->meta->default_value; +} + +void SettingDataFilesystem::Copy(const SettingData* data) { + if (data->type != this->type) return; + + const SettingDataFilesystem* setting_data = static_cast(data); + this->value = setting_data->value; +} + +bool SettingDataFilesystem::Load(const QJsonObject& json_setting) { + this->value = ReadStringValue(json_setting, "value"); + return true; +} + +bool SettingDataFilesystem::Save(QJsonObject& json_setting) const { + json_setting.insert("value", this->value.RelativePath().c_str()); + return true; +} std::string SettingDataFilesystem::Export(ExportMode export_mode) const { switch (export_mode) { @@ -67,17 +96,24 @@ std::string SettingDataFilesystem::Export(ExportMode export_mode) const { assert(0); return ""; case EXPORT_MODE_OVERRIDE: { - std::string file = this->value; - if (VKC_ENV == VKC_ENV_WIN32) { - file = ConvertSeparators(file, "/", GetNativeSeparator()); - } - return ReplaceBuiltInVariable(file).c_str(); + Path file(this->value); + return file.AbsolutePath(); } case EXPORT_MODE_DOC: - return this->value; + return Path(this->value).RelativePath(); } } +const Path& SettingDataFilesystem::GetValue() const { return this->value; } + +void SettingDataFilesystem::SetValue(const Path& value) { this->value = value; } + +bool SettingDataFilesystem::Equal(const SettingData& other) const { + if (!SettingData::Equal(other)) return false; + + return this->value == static_cast(other).value; +} + // SettingMetaFileLoad const SettingType SettingMetaFileLoad::TYPE(SETTING_LOAD_FILE); @@ -97,7 +133,9 @@ SettingDataFileLoad::SettingDataFileLoad(const SettingMetaFileLoad* meta) : SettingDataFilesystem(meta->key, meta->type), meta(meta) {} void SettingDataFileLoad::Copy(const SettingData* data) { - if (data->type != this->type) return; + if (data->type != this->type) { + return; + } const SettingDataFileLoad* setting_data = static_cast(data); this->value = setting_data->value; @@ -105,10 +143,10 @@ void SettingDataFileLoad::Copy(const SettingData* data) { } bool SettingDataFileLoad::Load(const QJsonObject& json_setting) { - SettingDataString::Load(json_setting); + this->value = Path(ReadStringValue(json_setting, "value")); if (this->meta->format == "PROFILE") { - this->profile_names = GetProfileNamesFromFile(this->value); + this->profile_names = CollectProfileNamesFromFile(this->value); } return true; } @@ -134,7 +172,9 @@ SettingDataFileSave::SettingDataFileSave(const SettingMetaFileSave* meta) : SettingDataFilesystem(meta->key, meta->type), meta(meta) {} void SettingDataFileSave::Copy(const SettingData* data) { - if (data->type != this->type) return; + if (data->type != this->type) { + return; + } const SettingDataFileSave* setting_data = static_cast(data); this->value = setting_data->value; @@ -168,10 +208,10 @@ void SettingDataFolderLoad::Copy(const SettingData* data) { } bool SettingDataFolderLoad::Load(const QJsonObject& json_setting) { - SettingDataString::Load(json_setting); + SettingDataFilesystem::Load(json_setting); if (this->meta->format == "PROFILE") { - this->profile_names = GetProfileNamesFromDir(this->value); + this->profile_names = CollectProfileNamesFromDir(this->value); } return true; } @@ -197,7 +237,9 @@ SettingDataFolderSave::SettingDataFolderSave(const SettingMetaFolderSave* meta) : SettingDataFilesystem(meta->key, meta->type), meta(meta) {} void SettingDataFolderSave::Copy(const SettingData* data) { - if (data->type != this->type) return; + if (data->type != this->type) { + return; + } const SettingDataFolderSave* setting_data = static_cast(data); this->value = setting_data->value; diff --git a/vkconfig_core/setting_filesystem.h b/vkconfig_core/setting_filesystem.h index ff976444da..3ef2257850 100644 --- a/vkconfig_core/setting_filesystem.h +++ b/vkconfig_core/setting_filesystem.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,12 +21,13 @@ #pragma once #include "setting_string.h" +#include "path.h" struct SettingMetaFilesystem : public SettingMeta { bool Load(const QJsonObject& json_setting) override; std::string Export(ExportMode export_mode) const override; - std::string default_value; + Path default_value; std::string filter; std::string format; @@ -36,11 +37,26 @@ struct SettingMetaFilesystem : public SettingMeta { bool Equal(const SettingMeta& other) const override; }; -struct SettingDataFilesystem : public SettingDataString { +struct SettingDataFilesystem : public SettingData { + SettingDataFilesystem(const SettingMetaFilesystem* meta); + + void Reset() override; + void Copy(const SettingData* data) override; + bool Load(const QJsonObject& json_setting) override; + bool Save(QJsonObject& json_setting) const override; std::string Export(ExportMode export_mode) const override; + const Path& GetValue() const; + void SetValue(const Path& value); + + Path value; + protected: SettingDataFilesystem(const std::string& key, const SettingType& type); + + bool Equal(const SettingData& other) const override; + + const SettingMetaFilesystem* meta; }; struct SettingMetaFileLoad : public SettingMetaFilesystem { diff --git a/vkconfig_core/setting_list.cpp b/vkconfig_core/setting_list.cpp index d1c54a3161..6e616a589a 100644 --- a/vkconfig_core/setting_list.cpp +++ b/vkconfig_core/setting_list.cpp @@ -49,7 +49,7 @@ void LoadVUIDs(std::vector& value) { } if (json_text.isEmpty()) { - json_text = ReadAll(":/layers/validusage.json"); + json_text = ReadAll(":/vkconfig/validusage.json"); } if (json_text.isEmpty()) { diff --git a/vkconfig_core/setting_string.cpp b/vkconfig_core/setting_string.cpp index 615b88d643..6d944a4785 100644 --- a/vkconfig_core/setting_string.cpp +++ b/vkconfig_core/setting_string.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,7 +49,9 @@ std::string SettingMetaString::Export(ExportMode export_mode) const { } bool SettingMetaString::Equal(const SettingMeta& other) const { - if (!SettingMeta::Equal(other)) return false; + if (!SettingMeta::Equal(other)) { + return false; + } return this->default_value == static_cast(other).default_value; } diff --git a/vkconfig_core/test/CMakeLists.txt b/vkconfig_core/test/CMakeLists.txt index 62e0827767..f817f49bbc 100644 --- a/vkconfig_core/test/CMakeLists.txt +++ b/vkconfig_core/test/CMakeLists.txt @@ -8,13 +8,14 @@ function(vkConfigTest NAME) set(TEST_FILE ./${NAME}.cpp) set(TEST_NAME vkconfig_${NAME}) + file(GLOB FILES_LAYER_JSON ./layers/*.json) file(GLOB FILES_JSON ./*.json) file(GLOB FILES_TEXT ./*.txt) - source_group("Test Files" FILES ${FILES_JSON} ${FILES_TEXT}) + source_group("Test Files" FILES ${FILES_JSON} ${FILES_TEXT} ${FILES_LAYER_JSON}) add_executable(${TEST_NAME} ${TEST_FILE} ${FILES_JSON} ${FILES_TEXT} resources.qrc) - set_target_properties(${TEST_NAME} PROPERTIES FOLDER "vkconfig_core/tests") - target_link_libraries(${TEST_NAME} vkconfig_core + set_target_properties(${TEST_NAME} PROPERTIES FOLDER "vkconfig/tests") + target_link_libraries(${TEST_NAME} vkconfig-core Vulkan::LayerSettings GTest::gtest GTest::gtest_main @@ -26,6 +27,10 @@ function(vkConfigTest NAME) if(WIN32) target_link_libraries(${TEST_NAME} Cfgmgr32) endif() + if (RUN_ON_GITHUB) + target_compile_definitions(${TEST_NAME} PRIVATE RUN_ON_GITHUB) + endif() + add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) endfunction() @@ -36,11 +41,8 @@ vkConfigTest(test_environment) vkConfigTest(test_command_line) vkConfigTest(test_json) vkConfigTest(test_layer) -vkConfigTest(test_layer_built_in) vkConfigTest(test_layer_manager) vkConfigTest(test_layer_preset) -vkConfigTest(test_layer_type) -vkConfigTest(test_layer_state) vkConfigTest(test_setting) vkConfigTest(test_setting_type_bool) vkConfigTest(test_setting_type_bool_numeric) @@ -56,15 +58,22 @@ vkConfigTest(test_setting_type_int) vkConfigTest(test_setting_type_list) vkConfigTest(test_setting_type_string) vkConfigTest(test_header) +vkConfigTest(test_bitfield) vkConfigTest(test_parameter) vkConfigTest(test_path) -vkConfigTest(test_path_manager) -vkConfigTest(test_platform) vkConfigTest(test_configuration) vkConfigTest(test_configuration_built_in) vkConfigTest(test_configuration_manager) vkConfigTest(test_override) vkConfigTest(test_application_singleton) +vkConfigTest(test_type_hide_message) +vkConfigTest(test_type_layer_control) +vkConfigTest(test_type_layer_type) +vkConfigTest(test_type_layers_mode) +vkConfigTest(test_type_log) +vkConfigTest(test_type_platform) +vkConfigTest(test_type_status) +vkConfigTest(test_type_tab) vkConfigTest(test_vulkan) diff --git a/vkconfig_core/test/Configuration 2.2.2.json b/vkconfig_core/test/Configuration 3.0.0.json similarity index 97% rename from vkconfig_core/test/Configuration 2.2.2.json rename to vkconfig_core/test/Configuration 3.0.0.json index 7702622897..1198e73b97 100644 --- a/vkconfig_core/test/Configuration 2.2.2.json +++ b/vkconfig_core/test/Configuration 3.0.0.json @@ -1,5 +1,5 @@ { - "file_format_version": "2.2.2", + "file_format_version": "3.0.0", "configuration": { "name": "All layers", "platforms": [ @@ -13,6 +13,7 @@ { "name": "VK_LAYER_LUNARG_reference_1_2_1", "rank": 8, + "version": "latest", "settings": [ { "key": "enum_required_only", @@ -113,7 +114,7 @@ ] } ], - "state": "OVERRIDDEN" + "control": "on" } ] } diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_reference_1_1_0.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_reference_1_1_0.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_reference_1_1_0.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_reference_1_1_0.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_reference_1_2_0.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_reference_1_2_0.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_reference_1_2_0.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_reference_1_2_0.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_reference_1_2_1.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_reference_1_2_1.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_reference_1_2_1.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_reference_1_2_1.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_test_00.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_test_00.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_test_00.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_test_00.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_test_01.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_test_01.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_test_01.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_test_01.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_test_02.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_test_02.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_test_02.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_test_02.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_test_03.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_test_03.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_test_03.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_test_03.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_test_04.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_test_04.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_test_04.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_test_04.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_test_05.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_test_05.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_test_05.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_test_05.json diff --git a/vkconfig_core/test/VK_LAYER_LUNARG_test_06.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_test_06.json similarity index 100% rename from vkconfig_core/test/VK_LAYER_LUNARG_test_06.json rename to vkconfig_core/test/layers/VK_LAYER_LUNARG_test_06.json diff --git a/vkconfig_core/test/override_settings_2_2_2_schema_1_2_1.txt b/vkconfig_core/test/layers_settings.txt similarity index 100% rename from vkconfig_core/test/override_settings_2_2_2_schema_1_2_1.txt rename to vkconfig_core/test/layers_settings.txt diff --git a/vkconfig_core/test/override_layers_2_2_2_schema_1_2_1.json b/vkconfig_core/test/loader_settings.json similarity index 100% rename from vkconfig_core/test/override_layers_2_2_2_schema_1_2_1.json rename to vkconfig_core/test/loader_settings.json diff --git a/vkconfig_core/test/profiles/VP_KHR_roadmap.json b/vkconfig_core/test/profiles/VP_KHR_roadmap.json new file mode 100644 index 0000000000..e7a8500556 --- /dev/null +++ b/vkconfig_core/test/profiles/VP_KHR_roadmap.json @@ -0,0 +1,390 @@ +{ + "$schema": "https://schema.khronos.org/vulkan/profiles-0.8.2-276.json#", + "capabilities": { + "vulkan10requirements": { + "features": { + "VkPhysicalDeviceFeatures": { + "robustBufferAccess": true + } + } + }, + "vulkan11requirements": { + "features": { + "VkPhysicalDeviceVulkan11Features": { + "multiview": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan11Properties": { + "maxMultiviewViewCount": 6, + "maxMultiviewInstanceIndex": 134217727 + } + } + }, + "vulkan12requirements": { + "features": { + "VkPhysicalDeviceVulkan12Features": { + "uniformBufferStandardLayout": true, + "subgroupBroadcastDynamicId": true, + "imagelessFramebuffer": true, + "separateDepthStencilLayouts": true, + "hostQueryReset": true, + "timelineSemaphore": true, + "shaderSubgroupExtendedTypes": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan12Properties": { + "maxTimelineSemaphoreValueDifference": 2147483647 + } + } + }, + "vulkan13requirements": { + "features": { + "VkPhysicalDeviceVulkan12Features": { + "vulkanMemoryModel": true, + "vulkanMemoryModelDeviceScope": true, + "bufferDeviceAddress": true + }, + "VkPhysicalDeviceVulkan13Features": { + "robustImageAccess": true, + "shaderTerminateInvocation": true, + "shaderZeroInitializeWorkgroupMemory": true, + "synchronization2": true, + "shaderIntegerDotProduct": true, + "maintenance4": true, + "pipelineCreationCacheControl": true, + "subgroupSizeControl": true, + "computeFullSubgroups": true, + "shaderDemoteToHelperInvocation": true, + "inlineUniformBlock": true, + "dynamicRendering": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan13Properties": { + "maxBufferSize": 1073741824, + "maxInlineUniformBlockSize": 256, + "maxPerStageDescriptorInlineUniformBlocks": 4, + "maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks": 4, + "maxDescriptorSetInlineUniformBlocks": 4, + "maxDescriptorSetUpdateAfterBindInlineUniformBlocks": 4, + "maxInlineUniformTotalSize": 256 + } + } + }, + "vulkan10requirements_roadmap2022": { + "features": { + "VkPhysicalDeviceFeatures": { + "fullDrawIndexUint32": true, + "imageCubeArray": true, + "independentBlend": true, + "sampleRateShading": true, + "drawIndirectFirstInstance": true, + "depthClamp": true, + "depthBiasClamp": true, + "samplerAnisotropy": true, + "occlusionQueryPrecise": true, + "fragmentStoresAndAtomics": true, + "shaderStorageImageExtendedFormats": true, + "shaderUniformBufferArrayDynamicIndexing": true, + "shaderSampledImageArrayDynamicIndexing": true, + "shaderStorageBufferArrayDynamicIndexing": true, + "shaderStorageImageArrayDynamicIndexing": true + } + }, + "properties": { + "VkPhysicalDeviceProperties": { + "limits": { + "maxImageDimension1D": 8192, + "maxImageDimension2D": 8192, + "maxImageDimensionCube": 8192, + "maxImageArrayLayers": 2048, + "maxUniformBufferRange": 65536, + "bufferImageGranularity": 4096, + "maxPerStageDescriptorSamplers": 64, + "maxPerStageDescriptorUniformBuffers": 15, + "maxPerStageDescriptorStorageBuffers": 30, + "maxPerStageDescriptorSampledImages": 200, + "maxPerStageDescriptorStorageImages": 16, + "maxPerStageResources": 200, + "maxDescriptorSetSamplers": 576, + "maxDescriptorSetUniformBuffers": 90, + "maxDescriptorSetStorageBuffers": 96, + "maxDescriptorSetSampledImages": 1800, + "maxDescriptorSetStorageImages": 144, + "maxFragmentCombinedOutputResources": 16, + "maxComputeWorkGroupInvocations": 256, + "maxComputeWorkGroupSize": [ 256, 256, 64 ], + "subTexelPrecisionBits": 8, + "mipmapPrecisionBits": 6, + "maxSamplerLodBias": 14, + "standardSampleLocations": true, + "maxColorAttachments": 7 + } + } + } + }, + "vulkan10optionals_roadmap2022": { + "features": { + "VkPhysicalDeviceFeatures": { + "largePoints": true, + "wideLines": true + } + }, + "properties": { + "VkPhysicalDeviceProperties": { + "limits": { + "pointSizeGranularity": 0.125, + "lineWidthGranularity": 0.5 + } + } + } + }, + "vulkan11requirements_roadmap2022": { + "features": { + "VkPhysicalDeviceVulkan11Features": { + "samplerYcbcrConversion": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan11Properties": { + "subgroupSize": 4, + "subgroupSupportedStages": [ "VK_SHADER_STAGE_COMPUTE_BIT", "VK_SHADER_STAGE_FRAGMENT_BIT" ], + "subgroupSupportedOperations": [ "VK_SUBGROUP_FEATURE_BASIC_BIT", "VK_SUBGROUP_FEATURE_VOTE_BIT", "VK_SUBGROUP_FEATURE_ARITHMETIC_BIT", "VK_SUBGROUP_FEATURE_BALLOT_BIT", "VK_SUBGROUP_FEATURE_SHUFFLE_BIT", "VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT", "VK_SUBGROUP_FEATURE_QUAD_BIT" ] + } + } + }, + "vulkan12requirements_roadmap2022": { + "features": { + "VkPhysicalDeviceVulkan12Features": { + "samplerMirrorClampToEdge": true, + "descriptorIndexing": true, + "shaderUniformTexelBufferArrayDynamicIndexing": true, + "shaderStorageTexelBufferArrayDynamicIndexing": true, + "shaderUniformBufferArrayNonUniformIndexing": true, + "shaderSampledImageArrayNonUniformIndexing": true, + "shaderStorageBufferArrayNonUniformIndexing": true, + "shaderStorageImageArrayNonUniformIndexing": true, + "shaderUniformTexelBufferArrayNonUniformIndexing": true, + "shaderStorageTexelBufferArrayNonUniformIndexing": true, + "descriptorBindingSampledImageUpdateAfterBind": true, + "descriptorBindingStorageImageUpdateAfterBind": true, + "descriptorBindingStorageBufferUpdateAfterBind": true, + "descriptorBindingUniformTexelBufferUpdateAfterBind": true, + "descriptorBindingStorageTexelBufferUpdateAfterBind": true, + "descriptorBindingUpdateUnusedWhilePending": true, + "descriptorBindingPartiallyBound": true, + "descriptorBindingVariableDescriptorCount": true, + "runtimeDescriptorArray": true, + "scalarBlockLayout": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan12Properties": { + "shaderSignedZeroInfNanPreserveFloat16": true, + "shaderSignedZeroInfNanPreserveFloat32": true, + "maxPerStageDescriptorUpdateAfterBindSamplers": 500000, + "maxPerStageDescriptorUpdateAfterBindUniformBuffers": 12, + "maxPerStageDescriptorUpdateAfterBindStorageBuffers": 500000, + "maxPerStageDescriptorUpdateAfterBindSampledImages": 500000, + "maxPerStageDescriptorUpdateAfterBindStorageImages": 500000, + "maxPerStageDescriptorUpdateAfterBindInputAttachments": 7, + "maxPerStageUpdateAfterBindResources": 500000, + "maxDescriptorSetUpdateAfterBindSamplers": 500000, + "maxDescriptorSetUpdateAfterBindUniformBuffers": 72, + "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic": 8, + "maxDescriptorSetUpdateAfterBindStorageBuffers": 500000, + "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic": 4, + "maxDescriptorSetUpdateAfterBindSampledImages": 500000, + "maxDescriptorSetUpdateAfterBindStorageImages": 500000, + "maxDescriptorSetUpdateAfterBindInputAttachments": 7 + } + } + }, + "vulkan13requirements_roadmap2022": { + "extensions": { + "VK_KHR_global_priority": 1 + }, + "features": { + "VkPhysicalDeviceVulkan13Features": { + "descriptorBindingInlineUniformBlockUpdateAfterBind": true + } + } + }, + "vulkan10requirements_roadmap2024": { + "features": { + "VkPhysicalDeviceFeatures": { + "multiDrawIndirect": true, + "shaderInt16": true, + "shaderImageGatherExtended": true + } + }, + "properties": { + "VkPhysicalDeviceProperties": { + "limits": { + "timestampComputeAndGraphics": true, + "maxColorAttachments": 8, + "maxBoundDescriptorSets": 7 + } + } + } + }, + "vulkan11requirements_roadmap2024": { + "features": { + "VkPhysicalDeviceVulkan11Features": { + "shaderDrawParameters": true, + "storageBuffer16BitAccess": true + } + } + }, + "vulkan12requirements_roadmap2024": { + "features": { + "VkPhysicalDeviceVulkan12Features": { + "shaderInt8": true, + "shaderFloat16": true, + "storageBuffer8BitAccess": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan12Properties": { + "shaderRoundingModeRTEFloat16": true, + "shaderRoundingModeRTEFloat32": true + } + } + }, + "vulkan13requirements_roadmap2024": { + "features": { + "VkPhysicalDeviceVulkan13Features": { + } + }, + "properties": { + "VkPhysicalDeviceVulkan13Properties": { + } + } + }, + "vulkanextensionrequirements_roadmap2024": { + "extensions": { + "VK_KHR_dynamic_rendering_local_read": 1, + "VK_KHR_load_store_op_none": 1, + "VK_KHR_shader_quad_control": 1, + "VK_KHR_shader_maximal_reconvergence": 1, + "VK_KHR_shader_subgroup_uniform_control_flow": 1, + "VK_KHR_shader_subgroup_rotate": 1, + "VK_KHR_shader_float_controls2": 1, + "VK_KHR_shader_expect_assume": 1, + "VK_KHR_line_rasterization": 1, + "VK_KHR_vertex_attribute_divisor": 1, + "VK_KHR_index_type_uint8": 1, + "VK_KHR_map_memory2": 1, + "VK_KHR_maintenance5": 1, + "VK_KHR_push_descriptor": 1 + } + } + }, + "profiles": { + "VP_KHR_roadmap_2024": { + "version": 1, + "api-version": "1.3.276", + "label": "Khronos Vulkan Roadmap 2024 profile", + "description": "This roadmap profile is intended to be supported by newer devices shipping in 2024 across mainstream smartphone, tablet, laptops, console and desktop devices.", + "profiles": [ + "VP_KHR_roadmap_2022" + ], + "capabilities": [ + "vulkan10requirements_roadmap2024", + "vulkan11requirements_roadmap2024", + "vulkan12requirements_roadmap2024", + "vulkan13requirements_roadmap2024", + "vulkanextensionrequirements_roadmap2024" + ] + }, + "VP_KHR_roadmap_2022": { + "version": 1, + "api-version": "1.3.204", + "label": "Khronos Vulkan Roadmap 2022 profile", + "description": "This roadmap profile is intended to be supported by newer devices shipping in 2022 across mainstream smartphone, tablet, laptops, console and desktop devices.", + "contributors": { + "Tobias Hector": { + "company": "AMD", + "email": "tobias.hector@amd.com", + "contact": true + }, + "Christophe Riccio": { + "company": "LunarG", + "email": "christophe@lunarg.com", + "contact": true + } + }, + "history": [ + { + "revision": 9, + "date": "2024-01-16", + "author": "Tobias Hector", + "comment": "Add Roadmap 2024 profile" + }, + { + "revision": 8, + "date": "2023-11-02", + "author": "Christophe Riccio", + "comment": "Remove unreferenced capabilities blocks that were written against Vulkan 1.2 for testing before Vulkan 1.3 was released" + }, + { + "revision": 7, + "date": "2022-11-16", + "author": "Christophe Riccio", + "comment": "Fix wideLines and largePoints that are optionals" + }, + { + "revision": 6, + "date": "2022-11-02", + "author": "Christophe Riccio", + "comment": "Fix roadmap 2022 maxInlineUniformTotalSize limit, 256 instead of 4" + }, + { + "revision": 5, + "date": "2022-05-02", + "author": "Christophe Riccio", + "comment": "Add missing dynamicRendering that is a Vulkan 1.3 requirement" + }, + { + "revision": 4, + "date": "2022-03-08", + "author": "Christophe Riccio", + "comment": "Refactor requirements per Vulkan API version" + }, + { + "revision": 3, + "date": "2022-03-08", + "author": "Christophe Riccio", + "comment": "Fix Vulkan 1.3.204 API version requirement" + }, + { + "revision": 2, + "date": "2022-01-03", + "author": "Christophe Riccio", + "comment": "Rebase against Vulkan 1.3.203 revision" + }, + { + "revision": 1, + "date": "2021-12-08", + "author": "Christophe Riccio", + "comment": "Initial revision" + } + ], + "capabilities": [ + "vulkan10requirements", + "vulkan10requirements_roadmap2022", + "vulkan11requirements", + "vulkan11requirements_roadmap2022", + "vulkan12requirements", + "vulkan12requirements_roadmap2022", + "vulkan13requirements", + "vulkan13requirements_roadmap2022" + ], + "optionals": [ + "vulkan10optionals_roadmap2022" + ] + } + } +} diff --git a/vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline.json b/vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline.json new file mode 100644 index 0000000000..dcfb010de3 --- /dev/null +++ b/vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline.json @@ -0,0 +1,6080 @@ +{ + "$schema": "https://schema.khronos.org/vulkan/profiles-config-latest.json#", + "capabilities": { + "VP_LUNARG_desktop_baseline_2022_block": { + "extensions": { + "VK_EXT_descriptor_indexing": 2, + "VK_EXT_host_query_reset": 1, + "VK_EXT_inline_uniform_block": 1, + "VK_EXT_memory_budget": 1, + "VK_EXT_robustness2": 1, + "VK_EXT_scalar_block_layout": 1, + "VK_EXT_subgroup_size_control": 2, + "VK_EXT_texel_buffer_alignment": 1, + "VK_EXT_vertex_attribute_divisor": 3, + "VK_KHR_16bit_storage": 1, + "VK_KHR_8bit_storage": 1, + "VK_KHR_bind_memory2": 1, + "VK_KHR_create_renderpass2": 1, + "VK_KHR_dedicated_allocation": 3, + "VK_KHR_depth_stencil_resolve": 1, + "VK_KHR_descriptor_update_template": 1, + "VK_KHR_device_group": 4, + "VK_KHR_driver_properties": 1, + "VK_KHR_external_fence": 1, + "VK_KHR_external_memory": 1, + "VK_KHR_external_semaphore": 1, + "VK_KHR_get_memory_requirements2": 1, + "VK_KHR_image_format_list": 1, + "VK_KHR_maintenance1": 2, + "VK_KHR_maintenance2": 1, + "VK_KHR_maintenance3": 1, + "VK_KHR_multiview": 1, + "VK_KHR_relaxed_block_layout": 1, + "VK_KHR_sampler_mirror_clamp_to_edge": 3, + "VK_KHR_shader_draw_parameters": 1, + "VK_KHR_shader_float16_int8": 1, + "VK_KHR_storage_buffer_storage_class": 1, + "VK_KHR_swapchain": 70, + "VK_KHR_swapchain_mutable_format": 1, + "VK_KHR_timeline_semaphore": 2, + "VK_KHR_uniform_buffer_standard_layout": 1, + "VK_KHR_variable_pointers": 1 + }, + "features": { + "VkPhysicalDevice16BitStorageFeaturesKHR": { + "storageBuffer16BitAccess": true, + "uniformAndStorageBuffer16BitAccess": true + }, + "VkPhysicalDevice8BitStorageFeaturesKHR": { + "storageBuffer8BitAccess": true, + "uniformAndStorageBuffer8BitAccess": true + }, + "VkPhysicalDeviceDescriptorIndexingFeaturesEXT": { + "shaderUniformTexelBufferArrayDynamicIndexing": true, + "shaderStorageTexelBufferArrayDynamicIndexing": true, + "shaderSampledImageArrayNonUniformIndexing": true, + "shaderUniformTexelBufferArrayNonUniformIndexing": true, + "descriptorBindingSampledImageUpdateAfterBind": true, + "descriptorBindingStorageImageUpdateAfterBind": true, + "descriptorBindingStorageBufferUpdateAfterBind": true, + "descriptorBindingUniformTexelBufferUpdateAfterBind": true, + "descriptorBindingStorageTexelBufferUpdateAfterBind": true, + "descriptorBindingUpdateUnusedWhilePending": true, + "descriptorBindingPartiallyBound": true, + "descriptorBindingVariableDescriptorCount": true, + "runtimeDescriptorArray": true + }, + "VkPhysicalDeviceFeatures": { + "depthBiasClamp": true, + "depthClamp": true, + "drawIndirectFirstInstance": true, + "dualSrcBlend": true, + "fillModeNonSolid": true, + "fragmentStoresAndAtomics": true, + "fullDrawIndexUint32": true, + "imageCubeArray": true, + "independentBlend": true, + "inheritedQueries": true, + "largePoints": true, + "multiDrawIndirect": true, + "multiViewport": true, + "occlusionQueryPrecise": true, + "robustBufferAccess": true, + "sampleRateShading": true, + "samplerAnisotropy": true, + "shaderClipDistance": true, + "shaderImageGatherExtended": true, + "shaderSampledImageArrayDynamicIndexing": true, + "shaderStorageBufferArrayDynamicIndexing": true, + "shaderStorageImageArrayDynamicIndexing": true, + "shaderStorageImageExtendedFormats": true, + "shaderStorageImageWriteWithoutFormat": true, + "shaderTessellationAndGeometryPointSize": true, + "shaderUniformBufferArrayDynamicIndexing": true, + "tessellationShader": true, + "textureCompressionBC": true, + "vertexPipelineStoresAndAtomics": true + }, + "VkPhysicalDeviceFloat16Int8FeaturesKHR": { + "shaderInt8": true + }, + "VkPhysicalDeviceHostQueryResetFeaturesEXT": { + "hostQueryReset": true + }, + "VkPhysicalDeviceInlineUniformBlockFeaturesEXT": { + "inlineUniformBlock": true, + "descriptorBindingInlineUniformBlockUpdateAfterBind": true + }, + "VkPhysicalDeviceMultiviewFeaturesKHR": { + "multiview": true + }, + "VkPhysicalDeviceRobustness2FeaturesEXT": { + "robustImageAccess2": true + }, + "VkPhysicalDeviceScalarBlockLayoutFeaturesEXT": { + "scalarBlockLayout": true + }, + "VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT": { + "texelBufferAlignment": true + }, + "VkPhysicalDeviceTimelineSemaphoreFeaturesKHR": { + "timelineSemaphore": true + }, + "VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR": { + "uniformBufferStandardLayout": true + }, + "VkPhysicalDeviceVariablePointersFeaturesKHR": { + "variablePointersStorageBuffer": true, + "variablePointers": true + }, + "VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT": { + "vertexAttributeInstanceRateDivisor": true, + "vertexAttributeInstanceRateZeroDivisor": true + } + }, + "properties": { + "VkPhysicalDeviceDepthStencilResolvePropertiesKHR": { + "independentResolve": true, + "independentResolveNone": true, + "supportedDepthResolveModes": [ + "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT" + ], + "supportedStencilResolveModes": [ + "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT" + ] + }, + "VkPhysicalDeviceDescriptorIndexingPropertiesEXT": { + "maxDescriptorSetUpdateAfterBindInputAttachments": 256, + "maxDescriptorSetUpdateAfterBindSampledImages": 640, + "maxDescriptorSetUpdateAfterBindSamplers": 80, + "maxDescriptorSetUpdateAfterBindStorageBuffers": 155, + "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic": 8, + "maxDescriptorSetUpdateAfterBindStorageImages": 40, + "maxDescriptorSetUpdateAfterBindUniformBuffers": 90, + "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic": 8, + "maxPerStageDescriptorUpdateAfterBindInputAttachments": 64, + "maxPerStageDescriptorUpdateAfterBindSampledImages": 128, + "maxPerStageDescriptorUpdateAfterBindSamplers": 16, + "maxPerStageDescriptorUpdateAfterBindStorageBuffers": 31, + "maxPerStageDescriptorUpdateAfterBindStorageImages": 8, + "maxPerStageDescriptorUpdateAfterBindUniformBuffers": 15, + "maxPerStageUpdateAfterBindResources": 159, + "maxUpdateAfterBindDescriptorsInAllPools": 1048576, + "robustBufferAccessUpdateAfterBind": true + }, + "VkPhysicalDeviceInlineUniformBlockPropertiesEXT": { + "maxDescriptorSetInlineUniformBlocks": 4, + "maxDescriptorSetUpdateAfterBindInlineUniformBlocks": 4, + "maxInlineUniformBlockSize": 256, + "maxPerStageDescriptorInlineUniformBlocks": 4, + "maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks": 4 + }, + "VkPhysicalDeviceMaintenance3PropertiesKHR": { + "maxMemoryAllocationSize": 2147483648, + "maxPerSetDescriptors": 700 + }, + "VkPhysicalDeviceMultiviewPropertiesKHR": { + "maxMultiviewInstanceIndex": 134217727, + "maxMultiviewViewCount": 6 + }, + "VkPhysicalDeviceProperties": { + "sparseProperties": {}, + "limits": { + "bufferImageGranularity": 65536, + "discreteQueuePriorities": 2, + "framebufferColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferNoAttachmentsSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "lineWidthGranularity": 1.0, + "maxBoundDescriptorSets": 8, + "maxClipDistances": 8, + "maxColorAttachments": 8, + "maxCombinedClipAndCullDistances": 8, + "maxComputeSharedMemorySize": 32768, + "maxComputeWorkGroupInvocations": 1024, + "maxCullDistances": 0, + "maxDescriptorSetInputAttachments": 7, + "maxDescriptorSetSampledImages": 640, + "maxDescriptorSetSamplers": 80, + "maxDescriptorSetStorageBuffers": 155, + "maxDescriptorSetStorageBuffersDynamic": 8, + "maxDescriptorSetStorageImages": 40, + "maxDescriptorSetUniformBuffers": 90, + "maxDescriptorSetUniformBuffersDynamic": 8, + "maxDrawIndexedIndexValue": 4294967294, + "maxDrawIndirectCount": 1073741824, + "maxFragmentCombinedOutputResources": 8, + "maxFragmentDualSrcAttachments": 1, + "maxFragmentInputComponents": 116, + "maxFragmentOutputAttachments": 8, + "maxFramebufferHeight": 16384, + "maxFramebufferLayers": 1024, + "maxFramebufferWidth": 16384, + "maxGeometryInputComponents": 0, + "maxGeometryOutputComponents": 0, + "maxGeometryOutputVertices": 0, + "maxGeometryShaderInvocations": 0, + "maxGeometryTotalOutputComponents": 0, + "maxImageArrayLayers": 2048, + "maxImageDimension1D": 16384, + "maxImageDimension2D": 16384, + "maxImageDimension3D": 2048, + "maxImageDimensionCube": 16384, + "maxInterpolationOffset": 0.4375, + "maxMemoryAllocationCount": 4096, + "maxPerStageDescriptorInputAttachments": 7, + "maxPerStageDescriptorSampledImages": 128, + "maxPerStageDescriptorSamplers": 16, + "maxPerStageDescriptorStorageBuffers": 31, + "maxPerStageDescriptorStorageImages": 8, + "maxPerStageDescriptorUniformBuffers": 15, + "maxPerStageResources": 159, + "maxPushConstantsSize": 128, + "maxSampleMaskWords": 1, + "maxSamplerAllocationCount": 1024, + "maxSamplerAnisotropy": 16, + "maxSamplerLodBias": 0.0, + "maxStorageBufferRange": 1073741820, + "maxTessellationControlPerPatchOutputComponents": 120, + "maxTessellationControlPerVertexInputComponents": 124, + "maxTessellationControlPerVertexOutputComponents": 124, + "maxTessellationControlTotalOutputComponents": 2048, + "maxTessellationEvaluationInputComponents": 124, + "maxTessellationEvaluationOutputComponents": 124, + "maxTessellationGenerationLevel": 64, + "maxTessellationPatchSize": 32, + "maxTexelBufferElements": 67108864, + "maxTexelGatherOffset": 7, + "maxTexelOffset": 7, + "maxUniformBufferRange": 65536, + "maxVertexInputAttributeOffset": 2047, + "maxVertexInputAttributes": 28, + "maxVertexInputBindingStride": 2048, + "maxVertexInputBindings": 28, + "maxVertexOutputComponents": 124, + "maxViewports": 16, + "minInterpolationOffset": -0.5, + "minMemoryMapAlignment": 4096, + "minStorageBufferOffsetAlignment": 64, + "minTexelBufferOffsetAlignment": 256, + "minTexelGatherOffset": -8, + "minTexelOffset": -8, + "minUniformBufferOffsetAlignment": 256, + "mipmapPrecisionBits": 4, + "nonCoherentAtomSize": 256, + "optimalBufferCopyOffsetAlignment": 256, + "optimalBufferCopyRowPitchAlignment": 128, + "pointSizeGranularity": 1, + "sampledImageColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageIntegerSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sparseAddressSpaceSize": 0, + "storageImageSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT" + ], + "subPixelInterpolationOffsetBits": 4, + "subPixelPrecisionBits": 4, + "subTexelPrecisionBits": 4, + "timestampComputeAndGraphics": true, + "viewportSubPixelBits": 0, + "maxComputeWorkGroupCount": [ + 65535, + 65535, + 65535 + ], + "maxViewportDimensions": [ + 16384, + 16384 + ], + "pointSizeRange": [ + 1, + 64 + ], + "viewportBoundsRange": [ + -32768, + 32767 + ], + "lineWidthRange": [ + 1, + 1 + ] + } + }, + "VkPhysicalDeviceRobustness2PropertiesEXT": { + "robustStorageBufferAccessSizeAlignment": 4, + "robustUniformBufferAccessSizeAlignment": 256 + }, + "VkPhysicalDeviceSubgroupSizeControlPropertiesEXT": { + "maxComputeWorkgroupSubgroups": 16, + "maxSubgroupSize": 1, + "minSubgroupSize": 64, + "requiredSubgroupSizeStages": [] + }, + "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT": { + "storageTexelBufferOffsetAlignmentBytes": 256, + "uniformTexelBufferOffsetAlignmentBytes": 256 + }, + "VkPhysicalDeviceTimelineSemaphorePropertiesKHR": { + "maxTimelineSemaphoreValueDifference": 2147483647 + }, + "VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT": { + "maxVertexAttribDivisor": 268435455 + } + }, + "formats": { + "VK_FORMAT_A2B10G10R10_SNORM_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2B10G10R10_UINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2B10G10R10_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2R10G10B10_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SRGB_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SSCALED_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_UINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_USCALED_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_B10G11R11_UFLOAT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_B8G8R8A8_SRGB": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_B8G8R8A8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGBA_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGBA_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGB_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGB_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC2_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC2_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC3_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC3_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC4_SNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC4_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC5_SNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC5_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC6H_SFLOAT_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC6H_UFLOAT_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC7_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC7_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D16_UNORM": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D32_SFLOAT": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D32_SFLOAT_S8_UINT": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_SFLOAT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_SINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_UINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SRGB": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + } + } + }, + "VP_LUNARG_desktop_baseline_2023_block": { + "extensions": { + "VK_EXT_descriptor_indexing": 2, + "VK_EXT_host_query_reset": 1, + "VK_EXT_image_robustness": 1, + "VK_EXT_inline_uniform_block": 1, + "VK_EXT_memory_budget": 1, + "VK_EXT_robustness2": 1, + "VK_EXT_subgroup_size_control": 2, + "VK_EXT_texel_buffer_alignment": 1, + "VK_EXT_vertex_attribute_divisor": 3, + "VK_KHR_16bit_storage": 1, + "VK_KHR_8bit_storage": 1, + "VK_KHR_bind_memory2": 1, + "VK_KHR_create_renderpass2": 1, + "VK_KHR_dedicated_allocation": 3, + "VK_KHR_depth_stencil_resolve": 1, + "VK_KHR_descriptor_update_template": 1, + "VK_KHR_device_group": 4, + "VK_KHR_driver_properties": 1, + "VK_KHR_external_fence": 1, + "VK_KHR_external_memory": 1, + "VK_KHR_external_semaphore": 1, + "VK_KHR_get_memory_requirements2": 1, + "VK_KHR_image_format_list": 1, + "VK_KHR_imageless_framebuffer": 1, + "VK_KHR_maintenance1": 2, + "VK_KHR_maintenance2": 1, + "VK_KHR_maintenance3": 1, + "VK_KHR_multiview": 1, + "VK_KHR_relaxed_block_layout": 1, + "VK_KHR_sampler_mirror_clamp_to_edge": 3, + "VK_KHR_separate_depth_stencil_layouts": 1, + "VK_KHR_shader_draw_parameters": 1, + "VK_KHR_shader_float16_int8": 1, + "VK_KHR_shader_float_controls": 4, + "VK_KHR_spirv_1_4": 1, + "VK_KHR_storage_buffer_storage_class": 1, + "VK_KHR_swapchain": 70, + "VK_KHR_swapchain_mutable_format": 1, + "VK_KHR_timeline_semaphore": 2, + "VK_KHR_uniform_buffer_standard_layout": 1, + "VK_KHR_variable_pointers": 1 + }, + "features": { + "VkPhysicalDeviceFeatures": { + "depthBiasClamp": true, + "depthClamp": true, + "drawIndirectFirstInstance": true, + "dualSrcBlend": true, + "fillModeNonSolid": true, + "fragmentStoresAndAtomics": true, + "fullDrawIndexUint32": true, + "imageCubeArray": true, + "independentBlend": true, + "inheritedQueries": true, + "largePoints": true, + "multiDrawIndirect": true, + "multiViewport": true, + "occlusionQueryPrecise": true, + "robustBufferAccess": true, + "sampleRateShading": true, + "samplerAnisotropy": true, + "shaderClipDistance": true, + "shaderImageGatherExtended": true, + "shaderSampledImageArrayDynamicIndexing": true, + "shaderStorageBufferArrayDynamicIndexing": true, + "shaderStorageImageArrayDynamicIndexing": true, + "shaderStorageImageExtendedFormats": true, + "shaderStorageImageWriteWithoutFormat": true, + "shaderTessellationAndGeometryPointSize": true, + "shaderUniformBufferArrayDynamicIndexing": true, + "tessellationShader": true, + "textureCompressionBC": true, + "vertexPipelineStoresAndAtomics": true + }, + "VkPhysicalDeviceImageRobustnessFeaturesEXT": { + "robustImageAccess": true + }, + "VkPhysicalDeviceInlineUniformBlockFeaturesEXT": { + "inlineUniformBlock": true, + "descriptorBindingInlineUniformBlockUpdateAfterBind": true + }, + "VkPhysicalDeviceRobustness2FeaturesEXT": { + "robustImageAccess2": true + }, + "VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT": { + "texelBufferAlignment": true + }, + "VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT": { + "vertexAttributeInstanceRateDivisor": true, + "vertexAttributeInstanceRateZeroDivisor": true + }, + "VkPhysicalDeviceVulkan11Features": { + "storageBuffer16BitAccess": true, + "uniformAndStorageBuffer16BitAccess": true, + "multiview": true, + "variablePointersStorageBuffer": true, + "variablePointers": true, + "protectedMemory": false, + "shaderDrawParameters": true + }, + "VkPhysicalDeviceVulkan12Features": { + "samplerMirrorClampToEdge": true, + "storageBuffer8BitAccess": true, + "uniformAndStorageBuffer8BitAccess": true, + "shaderInt8": true, + "descriptorIndexing": true, + "shaderUniformTexelBufferArrayDynamicIndexing": true, + "shaderStorageTexelBufferArrayDynamicIndexing": true, + "shaderSampledImageArrayNonUniformIndexing": true, + "shaderUniformTexelBufferArrayNonUniformIndexing": true, + "descriptorBindingSampledImageUpdateAfterBind": true, + "descriptorBindingStorageImageUpdateAfterBind": true, + "descriptorBindingStorageBufferUpdateAfterBind": true, + "descriptorBindingUniformTexelBufferUpdateAfterBind": true, + "descriptorBindingStorageTexelBufferUpdateAfterBind": true, + "descriptorBindingUpdateUnusedWhilePending": true, + "descriptorBindingPartiallyBound": true, + "descriptorBindingVariableDescriptorCount": true, + "runtimeDescriptorArray": true, + "imagelessFramebuffer": true, + "uniformBufferStandardLayout": true, + "separateDepthStencilLayouts": true, + "hostQueryReset": true, + "timelineSemaphore": true + } + }, + "properties": { + "VkPhysicalDeviceProperties": { + "sparseProperties": {}, + "limits": { + "bufferImageGranularity": 65536, + "discreteQueuePriorities": 2, + "framebufferColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferNoAttachmentsSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "maxBoundDescriptorSets": 8, + "maxClipDistances": 8, + "maxColorAttachments": 8, + "maxCombinedClipAndCullDistances": 8, + "maxComputeSharedMemorySize": 32768, + "maxComputeWorkGroupInvocations": 1024, + "maxCullDistances": 0, + "maxDescriptorSetInputAttachments": 7, + "maxDescriptorSetSampledImages": 640, + "maxDescriptorSetSamplers": 80, + "maxDescriptorSetStorageBuffers": 155, + "maxDescriptorSetStorageBuffersDynamic": 8, + "maxDescriptorSetStorageImages": 40, + "maxDescriptorSetUniformBuffers": 90, + "maxDescriptorSetUniformBuffersDynamic": 8, + "maxDrawIndexedIndexValue": 4294967295, + "maxDrawIndirectCount": 1073741824, + "maxFragmentCombinedOutputResources": 8, + "maxFragmentDualSrcAttachments": 1, + "maxFragmentInputComponents": 116, + "maxFragmentOutputAttachments": 8, + "maxFramebufferHeight": 16384, + "maxFramebufferLayers": 1024, + "maxFramebufferWidth": 16384, + "maxGeometryInputComponents": 0, + "maxGeometryOutputComponents": 0, + "maxGeometryOutputVertices": 0, + "maxGeometryShaderInvocations": 0, + "maxGeometryTotalOutputComponents": 0, + "maxImageArrayLayers": 2048, + "maxImageDimension1D": 16384, + "maxImageDimension2D": 16384, + "maxImageDimension3D": 2048, + "maxImageDimensionCube": 16384, + "maxInterpolationOffset": 0.4375, + "maxMemoryAllocationCount": 4096, + "maxPerStageDescriptorInputAttachments": 7, + "maxPerStageDescriptorSampledImages": 128, + "maxPerStageDescriptorSamplers": 16, + "maxPerStageDescriptorStorageBuffers": 31, + "maxPerStageDescriptorStorageImages": 8, + "maxPerStageDescriptorUniformBuffers": 15, + "maxPerStageResources": 159, + "maxPushConstantsSize": 128, + "maxSampleMaskWords": 1, + "maxSamplerAllocationCount": 4000, + "maxSamplerAnisotropy": 16, + "maxSamplerLodBias": 4, + "maxStorageBufferRange": 1073741820, + "maxTessellationControlPerPatchOutputComponents": 120, + "maxTessellationControlPerVertexInputComponents": 124, + "maxTessellationControlPerVertexOutputComponents": 124, + "maxTessellationControlTotalOutputComponents": 2048, + "maxTessellationEvaluationInputComponents": 124, + "maxTessellationEvaluationOutputComponents": 124, + "maxTessellationGenerationLevel": 64, + "maxTessellationPatchSize": 32, + "maxTexelBufferElements": 67108864, + "maxTexelGatherOffset": 7, + "maxTexelOffset": 7, + "maxUniformBufferRange": 65536, + "maxVertexInputAttributeOffset": 2047, + "maxVertexInputAttributes": 28, + "maxVertexInputBindingStride": 2048, + "maxVertexInputBindings": 28, + "maxVertexOutputComponents": 124, + "maxViewports": 16, + "minInterpolationOffset": -0.5, + "minMemoryMapAlignment": 4096, + "minStorageBufferOffsetAlignment": 64, + "minTexelBufferOffsetAlignment": 256, + "minTexelGatherOffset": -8, + "minTexelOffset": -8, + "minUniformBufferOffsetAlignment": 256, + "mipmapPrecisionBits": 4, + "nonCoherentAtomSize": 256, + "optimalBufferCopyOffsetAlignment": 256, + "optimalBufferCopyRowPitchAlignment": 128, + "pointSizeGranularity": 1, + "sampledImageColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageIntegerSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sparseAddressSpaceSize": 0, + "storageImageSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT" + ], + "subPixelInterpolationOffsetBits": 4, + "subPixelPrecisionBits": 4, + "subTexelPrecisionBits": 4, + "timestampComputeAndGraphics": true, + "viewportSubPixelBits": 0, + "maxComputeWorkGroupCount": [ + 65535, + 65535, + 65535 + ], + "maxComputeWorkGroupSize": [ + 1024, + 1024, + 64 + ], + "maxViewportDimensions": [ + 16384, + 16384 + ], + "pointSizeRange": [ + 1, + 64 + ], + "viewportBoundsRange": [ + -32768, + 32767 + ], + "lineWidthGranularity": 1.0, + "lineWidthRange": [ + 1, + 1 + ] + } + }, + "VkPhysicalDeviceVulkan11Properties": { + "subgroupSize": 1, + "subgroupSupportedStages": [ + "VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT", + "VK_SHADER_STAGE_FRAGMENT_BIT", + "VK_SHADER_STAGE_COMPUTE_BIT" + ], + "subgroupSupportedOperations": [ + "VK_SUBGROUP_FEATURE_BASIC_BIT" + ], + "maxMultiviewViewCount": 6, + "maxMultiviewInstanceIndex": 134217727, + "maxPerSetDescriptors": 700, + "maxMemoryAllocationSize": 1610612736 + }, + "VkPhysicalDeviceVulkan12Properties": { + "shaderSignedZeroInfNanPreserveFloat32": true, + "maxUpdateAfterBindDescriptorsInAllPools": 1048576, + "maxPerStageDescriptorUpdateAfterBindSamplers": 16, + "maxPerStageDescriptorUpdateAfterBindUniformBuffers": 15, + "maxPerStageDescriptorUpdateAfterBindStorageBuffers": 31, + "maxPerStageDescriptorUpdateAfterBindSampledImages": 128, + "maxPerStageDescriptorUpdateAfterBindStorageImages": 8, + "maxPerStageDescriptorUpdateAfterBindInputAttachments": 64, + "maxPerStageUpdateAfterBindResources": 159, + "maxDescriptorSetUpdateAfterBindSamplers": 80, + "maxDescriptorSetUpdateAfterBindUniformBuffers": 90, + "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic": 8, + "maxDescriptorSetUpdateAfterBindStorageBuffers": 155, + "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic": 8, + "maxDescriptorSetUpdateAfterBindSampledImages": 640, + "maxDescriptorSetUpdateAfterBindStorageImages": 40, + "maxDescriptorSetUpdateAfterBindInputAttachments": 256, + "supportedDepthResolveModes": [ + "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT" + ], + "supportedStencilResolveModes": [ + "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT" + ], + "independentResolveNone": true, + "independentResolve": true, + "maxTimelineSemaphoreValueDifference": 0, + "framebufferIntegerColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT" + ] + } + }, + "formats": { + "VK_FORMAT_A2B10G10R10_SNORM_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2B10G10R10_UINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2B10G10R10_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2R10G10B10_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SRGB_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SSCALED_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_UINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_USCALED_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_B10G11R11_UFLOAT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_B8G8R8A8_SRGB": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_B8G8R8A8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGBA_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGBA_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGB_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGB_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC2_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC2_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC3_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC3_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC4_SNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC4_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC5_SNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC5_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC6H_SFLOAT_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC6H_UFLOAT_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC7_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC7_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D16_UNORM": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D32_SFLOAT": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D32_SFLOAT_S8_UINT": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_SFLOAT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_SINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_UINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SRGB": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + } + } + }, + "VP_LUNARG_desktop_baseline_2024_block": { + "extensions": { + "VK_EXT_4444_formats": 1, + "VK_EXT_calibrated_timestamps": 2, + "VK_EXT_descriptor_indexing": 2, + "VK_EXT_extended_dynamic_state": 1, + "VK_EXT_extended_dynamic_state2": 1, + "VK_EXT_external_memory_host": 1, + "VK_EXT_host_query_reset": 1, + "VK_EXT_image_robustness": 1, + "VK_EXT_inline_uniform_block": 1, + "VK_EXT_memory_budget": 1, + "VK_EXT_pipeline_creation_cache_control": 3, + "VK_EXT_pipeline_creation_feedback": 1, + "VK_EXT_private_data": 1, + "VK_EXT_robustness2": 1, + "VK_EXT_scalar_block_layout": 1, + "VK_EXT_separate_stencil_usage": 1, + "VK_EXT_shader_atomic_float": 1, + "VK_EXT_shader_demote_to_helper_invocation": 1, + "VK_EXT_shader_subgroup_ballot": 1, + "VK_EXT_shader_subgroup_vote": 1, + "VK_EXT_shader_viewport_index_layer": 1, + "VK_EXT_subgroup_size_control": 2, + "VK_EXT_texel_buffer_alignment": 1, + "VK_EXT_vertex_attribute_divisor": 3, + "VK_KHR_16bit_storage": 1, + "VK_KHR_8bit_storage": 1, + "VK_KHR_bind_memory2": 1, + "VK_KHR_buffer_device_address": 1, + "VK_KHR_copy_commands2": 1, + "VK_KHR_create_renderpass2": 1, + "VK_KHR_dedicated_allocation": 3, + "VK_KHR_depth_stencil_resolve": 1, + "VK_KHR_descriptor_update_template": 1, + "VK_KHR_device_group": 4, + "VK_KHR_driver_properties": 1, + "VK_KHR_dynamic_rendering": 1, + "VK_KHR_external_fence": 1, + "VK_KHR_external_memory": 1, + "VK_KHR_external_semaphore": 1, + "VK_KHR_format_feature_flags2": 2, + "VK_KHR_get_memory_requirements2": 1, + "VK_KHR_image_format_list": 1, + "VK_KHR_imageless_framebuffer": 1, + "VK_KHR_maintenance1": 2, + "VK_KHR_maintenance2": 1, + "VK_KHR_maintenance3": 1, + "VK_KHR_multiview": 1, + "VK_KHR_push_descriptor": 2, + "VK_KHR_relaxed_block_layout": 1, + "VK_KHR_sampler_mirror_clamp_to_edge": 3, + "VK_KHR_separate_depth_stencil_layouts": 1, + "VK_KHR_shader_draw_parameters": 1, + "VK_KHR_shader_float16_int8": 1, + "VK_KHR_shader_float_controls": 4, + "VK_KHR_shader_non_semantic_info": 1, + "VK_KHR_shader_subgroup_extended_types": 1, + "VK_KHR_spirv_1_4": 1, + "VK_KHR_storage_buffer_storage_class": 1, + "VK_KHR_swapchain": 70, + "VK_KHR_swapchain_mutable_format": 1, + "VK_KHR_synchronization2": 1, + "VK_KHR_timeline_semaphore": 2, + "VK_KHR_uniform_buffer_standard_layout": 1, + "VK_KHR_variable_pointers": 1 + }, + "features": { + "VkPhysicalDevice4444FormatsFeaturesEXT": { + "formatA4R4G4B4": true + }, + "VkPhysicalDeviceExtendedDynamicState2FeaturesEXT": { + "extendedDynamicState2": true + }, + "VkPhysicalDeviceExtendedDynamicStateFeaturesEXT": { + "extendedDynamicState": true + }, + "VkPhysicalDeviceFeatures": { + "depthBiasClamp": true, + "depthClamp": true, + "drawIndirectFirstInstance": true, + "dualSrcBlend": true, + "fillModeNonSolid": true, + "fragmentStoresAndAtomics": true, + "fullDrawIndexUint32": true, + "imageCubeArray": true, + "independentBlend": true, + "inheritedQueries": true, + "largePoints": true, + "multiDrawIndirect": true, + "multiViewport": true, + "occlusionQueryPrecise": true, + "robustBufferAccess": true, + "sampleRateShading": true, + "samplerAnisotropy": true, + "shaderClipDistance": true, + "shaderImageGatherExtended": true, + "shaderInt16": true, + "shaderSampledImageArrayDynamicIndexing": true, + "shaderStorageBufferArrayDynamicIndexing": true, + "shaderStorageImageArrayDynamicIndexing": true, + "shaderStorageImageExtendedFormats": true, + "shaderStorageImageWriteWithoutFormat": true, + "shaderTessellationAndGeometryPointSize": true, + "shaderUniformBufferArrayDynamicIndexing": true, + "tessellationShader": true, + "textureCompressionBC": true, + "vertexPipelineStoresAndAtomics": true + }, + "VkPhysicalDeviceRobustness2FeaturesEXT": { + "robustImageAccess2": true + }, + "VkPhysicalDeviceShaderAtomicFloatFeaturesEXT": { + "shaderBufferFloat32Atomics": true, + "shaderSharedFloat32Atomics": true + }, + "VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT": { + "texelBufferAlignment": true + }, + "VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT": { + "vertexAttributeInstanceRateDivisor": true, + "vertexAttributeInstanceRateZeroDivisor": true + }, + "VkPhysicalDeviceVulkan11Features": { + "storageBuffer16BitAccess": true, + "uniformAndStorageBuffer16BitAccess": true, + "multiview": true, + "variablePointersStorageBuffer": true, + "variablePointers": true, + "protectedMemory": false, + "shaderDrawParameters": true + }, + "VkPhysicalDeviceVulkan12Features": { + "samplerMirrorClampToEdge": true, + "storageBuffer8BitAccess": true, + "uniformAndStorageBuffer8BitAccess": true, + "shaderInt8": true, + "descriptorIndexing": true, + "shaderUniformTexelBufferArrayDynamicIndexing": true, + "shaderStorageTexelBufferArrayDynamicIndexing": true, + "shaderSampledImageArrayNonUniformIndexing": true, + "shaderStorageBufferArrayNonUniformIndexing": true, + "shaderStorageImageArrayNonUniformIndexing": true, + "shaderUniformTexelBufferArrayNonUniformIndexing": true, + "shaderStorageTexelBufferArrayNonUniformIndexing": true, + "descriptorBindingSampledImageUpdateAfterBind": true, + "descriptorBindingStorageImageUpdateAfterBind": true, + "descriptorBindingStorageBufferUpdateAfterBind": true, + "descriptorBindingUniformTexelBufferUpdateAfterBind": true, + "descriptorBindingStorageTexelBufferUpdateAfterBind": true, + "descriptorBindingUpdateUnusedWhilePending": true, + "descriptorBindingPartiallyBound": true, + "descriptorBindingVariableDescriptorCount": true, + "runtimeDescriptorArray": true, + "scalarBlockLayout": true, + "imagelessFramebuffer": true, + "uniformBufferStandardLayout": true, + "shaderSubgroupExtendedTypes": true, + "separateDepthStencilLayouts": true, + "hostQueryReset": true, + "timelineSemaphore": true, + "bufferDeviceAddress": true, + "shaderOutputViewportIndex": true, + "shaderOutputLayer": true, + "subgroupBroadcastDynamicId": true + } + }, + "properties": { + "VkPhysicalDeviceExternalMemoryHostPropertiesEXT": { + "minImportedHostPointerAlignment": 4096 + }, + "VkPhysicalDeviceFloatControlsPropertiesKHR": { + "shaderDenormPreserveFloat16": true, + "shaderRoundingModeRTEFloat16": true, + "shaderRoundingModeRTEFloat32": true, + "shaderRoundingModeRTEFloat64": true, + "shaderRoundingModeRTZFloat32": true, + "shaderRoundingModeRTZFloat64": true, + "shaderSignedZeroInfNanPreserveFloat16": true, + "shaderSignedZeroInfNanPreserveFloat32": true, + "shaderSignedZeroInfNanPreserveFloat64": true + }, + "VkPhysicalDeviceInlineUniformBlockPropertiesEXT": { + "maxDescriptorSetInlineUniformBlocks": 4, + "maxDescriptorSetUpdateAfterBindInlineUniformBlocks": 4, + "maxInlineUniformBlockSize": 256, + "maxPerStageDescriptorInlineUniformBlocks": 4, + "maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks": 4 + }, + "VkPhysicalDeviceProperties": { + "sparseProperties": { + "residencyAlignedMipSize": false + }, + "limits": { + "bufferImageGranularity": 1024, + "discreteQueuePriorities": 2, + "framebufferColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferNoAttachmentsSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "lineWidthGranularity": 0.125, + "maxBoundDescriptorSets": 8, + "maxClipDistances": 8, + "maxColorAttachments": 8, + "maxCombinedClipAndCullDistances": 8, + "maxComputeSharedMemorySize": 32768, + "maxComputeWorkGroupInvocations": 1024, + "maxCullDistances": 0, + "maxDescriptorSetInputAttachments": 7, + "maxDescriptorSetSampledImages": 640, + "maxDescriptorSetSamplers": 80, + "maxDescriptorSetStorageBuffers": 155, + "maxDescriptorSetStorageBuffersDynamic": 8, + "maxDescriptorSetStorageImages": 40, + "maxDescriptorSetUniformBuffers": 155, + "maxDescriptorSetUniformBuffersDynamic": 8, + "maxDrawIndexedIndexValue": 4294967295, + "maxDrawIndirectCount": 1073741824, + "maxFragmentCombinedOutputResources": 16, + "maxFragmentDualSrcAttachments": 1, + "maxFragmentInputComponents": 116, + "maxFragmentOutputAttachments": 8, + "maxFramebufferHeight": 16384, + "maxFramebufferLayers": 1024, + "maxFramebufferWidth": 16384, + "maxGeometryInputComponents": 0, + "maxGeometryOutputComponents": 0, + "maxGeometryOutputVertices": 0, + "maxGeometryShaderInvocations": 0, + "maxGeometryTotalOutputComponents": 0, + "maxImageArrayLayers": 2048, + "maxImageDimension1D": 16384, + "maxImageDimension2D": 16384, + "maxImageDimension3D": 2048, + "maxImageDimensionCube": 16384, + "maxInterpolationOffset": 0.4375, + "maxMemoryAllocationCount": 4096, + "maxPerStageDescriptorInputAttachments": 7, + "maxPerStageDescriptorSampledImages": 128, + "maxPerStageDescriptorSamplers": 16, + "maxPerStageDescriptorStorageBuffers": 31, + "maxPerStageDescriptorStorageImages": 8, + "maxPerStageDescriptorUniformBuffers": 15, + "maxPerStageResources": 159, + "maxPushConstantsSize": 128, + "maxSampleMaskWords": 1, + "maxSamplerAllocationCount": 4000, + "maxSamplerAnisotropy": 16, + "maxSamplerLodBias": 4.0, + "maxStorageBufferRange": 1073741820, + "maxTessellationControlPerPatchOutputComponents": 120, + "maxTessellationControlPerVertexInputComponents": 124, + "maxTessellationControlPerVertexOutputComponents": 124, + "maxTessellationControlTotalOutputComponents": 2048, + "maxTessellationEvaluationInputComponents": 124, + "maxTessellationEvaluationOutputComponents": 124, + "maxTessellationGenerationLevel": 64, + "maxTessellationPatchSize": 32, + "maxTexelBufferElements": 67108864, + "maxTexelGatherOffset": 7, + "maxTexelOffset": 7, + "maxUniformBufferRange": 65536, + "maxVertexInputAttributeOffset": 2047, + "maxVertexInputAttributes": 29, + "maxVertexInputBindingStride": 2048, + "maxVertexInputBindings": 31, + "maxVertexOutputComponents": 124, + "maxViewports": 16, + "minInterpolationOffset": -0.5, + "minMemoryMapAlignment": 4096, + "minStorageBufferOffsetAlignment": 64, + "minTexelBufferOffsetAlignment": 64, + "minTexelGatherOffset": -8, + "minTexelOffset": -8, + "minUniformBufferOffsetAlignment": 256, + "mipmapPrecisionBits": 4, + "nonCoherentAtomSize": 128, + "optimalBufferCopyOffsetAlignment": 128, + "optimalBufferCopyRowPitchAlignment": 128, + "pointSizeGranularity": 1.0, + "sampledImageColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageIntegerSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_2_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sparseAddressSpaceSize": 0, + "storageImageSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT" + ], + "subPixelInterpolationOffsetBits": 4, + "subPixelPrecisionBits": 4, + "subTexelPrecisionBits": 4, + "timestampComputeAndGraphics": true, + "viewportSubPixelBits": 0, + "maxComputeWorkGroupCount": [ + 65535, + 65535, + 65535 + ], + "maxComputeWorkGroupSize": [ + 1024, + 1024, + 64 + ], + "maxViewportDimensions": [ + 16384, + 16384 + ], + "pointSizeRange": [ + 1, + 255.875 + ], + "viewportBoundsRange": [ + -32768, + 32767 + ], + "lineWidthRange": [ + 1, + 1 + ] + } + }, + "VkPhysicalDevicePushDescriptorPropertiesKHR": { + "maxPushDescriptors": 32 + }, + "VkPhysicalDeviceRobustness2PropertiesEXT": { + "robustStorageBufferAccessSizeAlignment": 4, + "robustUniformBufferAccessSizeAlignment": 256 + }, + "VkPhysicalDeviceSubgroupSizeControlPropertiesEXT": { + "maxComputeWorkgroupSubgroups": 32, + "maxSubgroupSize": 32, + "minSubgroupSize": 64, + "requiredSubgroupSizeStages": [] + }, + "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT": { + "storageTexelBufferOffsetAlignmentBytes": 16, + "uniformTexelBufferOffsetAlignmentBytes": 16 + }, + "VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT": { + "maxVertexAttribDivisor": 268435455 + }, + "VkPhysicalDeviceVulkan11Properties": { + "subgroupSize": 32, + "subgroupSupportedStages": [ + "VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT", + "VK_SHADER_STAGE_FRAGMENT_BIT", + "VK_SHADER_STAGE_COMPUTE_BIT" + ], + "subgroupSupportedOperations": [ + "VK_SUBGROUP_FEATURE_BASIC_BIT", + "VK_SUBGROUP_FEATURE_VOTE_BIT", + "VK_SUBGROUP_FEATURE_ARITHMETIC_BIT", + "VK_SUBGROUP_FEATURE_BALLOT_BIT", + "VK_SUBGROUP_FEATURE_SHUFFLE_BIT", + "VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT", + "VK_SUBGROUP_FEATURE_QUAD_BIT" + ], + "subgroupQuadOperationsInAllStages": true, + "maxMultiviewViewCount": 6, + "maxMultiviewInstanceIndex": 134217727, + "maxPerSetDescriptors": 1024, + "maxMemoryAllocationSize": 2147483648 + }, + "VkPhysicalDeviceVulkan12Properties": { + "shaderSignedZeroInfNanPreserveFloat32": true, + "maxUpdateAfterBindDescriptorsInAllPools": 1048576, + "robustBufferAccessUpdateAfterBind": true, + "maxPerStageDescriptorUpdateAfterBindSamplers": 16, + "maxPerStageDescriptorUpdateAfterBindUniformBuffers": 15, + "maxPerStageDescriptorUpdateAfterBindStorageBuffers": 31, + "maxPerStageDescriptorUpdateAfterBindSampledImages": 128, + "maxPerStageDescriptorUpdateAfterBindStorageImages": 8, + "maxPerStageDescriptorUpdateAfterBindInputAttachments": 64, + "maxPerStageUpdateAfterBindResources": 159, + "maxDescriptorSetUpdateAfterBindSamplers": 80, + "maxDescriptorSetUpdateAfterBindUniformBuffers": 155, + "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic": 8, + "maxDescriptorSetUpdateAfterBindStorageBuffers": 155, + "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic": 8, + "maxDescriptorSetUpdateAfterBindSampledImages": 640, + "maxDescriptorSetUpdateAfterBindStorageImages": 40, + "maxDescriptorSetUpdateAfterBindInputAttachments": 256, + "supportedDepthResolveModes": [ + "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT", + "VK_RESOLVE_MODE_MIN_BIT", + "VK_RESOLVE_MODE_MAX_BIT" + ], + "supportedStencilResolveModes": [ + "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT" + ], + "independentResolveNone": true, + "independentResolve": true, + "maxTimelineSemaphoreValueDifference": 2147483647, + "framebufferIntegerColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT" + ] + } + }, + "formats": { + "VK_FORMAT_A1R5G5B5_UNORM_PACK16": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_A2B10G10R10_SNORM_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2B10G10R10_UINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2B10G10R10_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A2R10G10B10_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SRGB_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_SSCALED_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_UINT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_UNORM_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_A8B8G8R8_USCALED_PACK32": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_B10G11R11_UFLOAT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_B4G4R4A4_UNORM_PACK16": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_B8G8R8A8_SRGB": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_B8G8R8A8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGBA_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGBA_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGB_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC1_RGB_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC2_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC2_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC3_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC3_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC4_SNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC4_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC5_SNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC5_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC6H_SFLOAT_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC6H_UFLOAT_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC7_SRGB_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_BC7_UNORM_BLOCK": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D16_UNORM": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D32_SFLOAT": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_D32_SFLOAT_S8_UINT": { + "VkFormatProperties": { + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16A16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16_SNORM": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16_UNORM": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16B16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16G16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R16_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32A32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_SFLOAT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_SINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32B32_UINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32G32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_SFLOAT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R32_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R4G4B4A4_UNORM_PACK16": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R5G6B5_UNORM_PACK16": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SRGB": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8A8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8_SINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8_SNORM": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8_UINT": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8_UNORM": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8B8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8G8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_SSCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_UINT": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_UNORM": { + "VkFormatProperties": { + "linearTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "optimalTilingFeatures": [ + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", + "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", + "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", + "VK_FORMAT_FEATURE_BLIT_SRC_BIT", + "VK_FORMAT_FEATURE_BLIT_DST_BIT", + "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", + "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", + "VK_FORMAT_FEATURE_TRANSFER_DST_BIT" + ], + "bufferFeatures": [ + "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + }, + "VK_FORMAT_R8_USCALED": { + "VkFormatProperties": { + "bufferFeatures": [ + "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" + ] + } + } + } + } + }, + "profiles": { + "VP_LUNARG_desktop_baseline_2022": { + "version": 2, + "api-version": "1.1.139", + "label": "LunarG Vulkan Desktop Baseline 2022 profile", + "description": "A profile generated by the intersection of a collection of GPUInfo.org device reports to support a large number of actual systems in the Vulkan ecosystem. This profile is meant to be a usage example for Vulkan application developer.", + "capabilities": [ + "VP_LUNARG_desktop_baseline_2022_block" + ] + }, + "VP_LUNARG_desktop_baseline_2023": { + "version": 2, + "api-version": "1.2.148", + "label": "LunarG Vulkan Desktop Baseline 2023 profile", + "description": "A profile generated by the intersection of a collection of GPUInfo.org device reports to support a large number of actual systems in the Vulkan ecosystem. This profile is meant to be a usage example for Vulkan application developer.", + "capabilities": [ + "VP_LUNARG_desktop_baseline_2023_block" + ] + }, + "VP_LUNARG_desktop_baseline_2024": { + "version": 1, + "api-version": "1.2.197", + "label": "LunarG Vulkan Desktop Baseline 2024 profile", + "description": "A profile generated by the intersection of a collection of GPUInfo.org device reports to support a large number of actual systems in the Vulkan ecosystem. This profile is meant to be a usage example for Vulkan application developer.", + "capabilities": [ + "VP_LUNARG_desktop_baseline_2024_block" + ] + } + }, + "contributors": { + "Christophe Riccio": { + "company": "LunarG", + "email": "christophe@lunarg.com", + "contact": true + } + }, + "history": [ + { + "revision": 2, + "date": "2024-02-21", + "author": "Christophe Riccio", + "comment": "Updated Desktop Baseline 2023 and 2022 to version 2 with ARC support" + }, + { + "revision": 1, + "date": "2024-02-21", + "author": "Christophe Riccio", + "comment": "Merged Desktop Baseline 2024, 2023 and 2022 into a single file" + } + ] +} \ No newline at end of file diff --git a/vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline_config.json b/vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline_config.json new file mode 100644 index 0000000000..86b00e0be2 --- /dev/null +++ b/vkconfig_core/test/profiles/VP_LUNARG_desktop_baseline_config.json @@ -0,0 +1,56 @@ +{ + "$schema": "profiles-config-latest", + "profiles": { + "VP_LUNARG_desktop_baseline_2022": { + "version": 2, + "input": "VP_LUNARG_desktop_baseline_2022", + "label": "LunarG Vulkan Desktop Baseline 2022 profile", + "description": "A profile generated by the intersection of a collection of GPUInfo.org device reports to support a large number of actual systems in the Vulkan ecosystem. This profile is meant to be a usage example for Vulkan application developer.", + "date": "2023-01-26", + "stage": "STABLE", + "api-version": "1.1.139", + "required-profiles": "" + }, + "VP_LUNARG_desktop_baseline_2023": { + "version": 2, + "input": "VP_LUNARG_desktop_baseline_2023", + "label": "LunarG Vulkan Desktop Baseline 2023 profile", + "description": "A profile generated by the intersection of a collection of GPUInfo.org device reports to support a large number of actual systems in the Vulkan ecosystem. This profile is meant to be a usage example for Vulkan application developer.", + "date": "2023-01-30", + "stage": "STABLE", + "api-version": "1.2.148", + "required-profiles": "" + }, + "VP_LUNARG_desktop_baseline_2024": { + "version": 1, + "input": "VP_LUNARG_desktop_baseline_2024", + "label": "LunarG Vulkan Desktop Baseline 2024 profile", + "description": "A profile generated by the intersection of a collection of GPUInfo.org device reports to support a large number of actual systems in the Vulkan ecosystem. This profile is meant to be a usage example for Vulkan application developer.", + "date": "2024-02-20", + "stage": "STABLE", + "api-version": "1.2.197", + "required-profiles": "" + } + }, + "contributors": { + "Christophe Riccio": { + "company": "LunarG", + "email": "christophe@lunarg.com", + "contact": true + } + }, + "history": [ + { + "revision": 2, + "date": "2024-02-21", + "author": "Christophe Riccio", + "comment": "Updated Desktop Baseline 2023 and 2022 to version 2 with ARC support" + }, + { + "revision": 1, + "date": "2024-02-21", + "author": "Christophe Riccio", + "comment": "Merged Desktop Baseline 2024, 2023 and 2022 into a single file" + } + ] +} \ No newline at end of file diff --git a/vkconfig_core/test/profiles/VP_LUNARG_minimum_requirements.json b/vkconfig_core/test/profiles/VP_LUNARG_minimum_requirements.json new file mode 100644 index 0000000000..f8c1b55a64 --- /dev/null +++ b/vkconfig_core/test/profiles/VP_LUNARG_minimum_requirements.json @@ -0,0 +1,400 @@ +{ + "$schema": "https://schema.khronos.org/vulkan/profiles-0.8.1-204.json#", + "capabilities": { + "vulkan10requirements": { + "features": { + "VkPhysicalDeviceFeatures": { + "robustBufferAccess": true + } + }, + "properties": { + "VkPhysicalDeviceProperties": { + "limits": { + "maxImageDimension1D": 4096, + "maxImageDimension2D": 4096, + "maxImageDimension3D": 256, + "maxImageDimensionCube": 4096, + "maxImageArrayLayers": 256, + "maxTexelBufferElements": 65536, + "maxUniformBufferRange": 16384, + "maxStorageBufferRange": 134217728, + "maxPushConstantsSize": 128, + "maxMemoryAllocationCount": 4096, + "maxSamplerAllocationCount": 4000, + "bufferImageGranularity": 131072, + "sparseAddressSpaceSize": 0, + "maxBoundDescriptorSets": 4, + "maxPerStageDescriptorSamplers": 16, + "maxPerStageDescriptorUniformBuffers": 12, + "maxPerStageDescriptorStorageBuffers": 4, + "maxPerStageDescriptorSampledImages": 16, + "maxPerStageDescriptorStorageImages": 4, + "maxPerStageDescriptorInputAttachments": 4, + "maxPerStageResources": 128, + "maxDescriptorSetSamplers": 96, + "maxDescriptorSetUniformBuffers": 72, + "maxDescriptorSetUniformBuffersDynamic": 8, + "maxDescriptorSetStorageBuffers": 24, + "maxDescriptorSetStorageBuffersDynamic": 4, + "maxDescriptorSetSampledImages": 96, + "maxDescriptorSetStorageImages": 24, + "maxDescriptorSetInputAttachments": 4, + "maxVertexInputAttributes": 16, + "maxVertexInputBindings": 16, + "maxVertexInputAttributeOffset": 2047, + "maxVertexInputBindingStride": 2048, + "maxVertexOutputComponents": 64, + "maxTessellationGenerationLevel": 0, + "maxTessellationPatchSize": 0, + "maxTessellationControlPerVertexInputComponents": 0, + "maxTessellationControlPerVertexOutputComponents": 0, + "maxTessellationControlPerPatchOutputComponents": 0, + "maxTessellationControlTotalOutputComponents": 0, + "maxTessellationEvaluationInputComponents": 0, + "maxTessellationEvaluationOutputComponents": 0, + "maxGeometryShaderInvocations": 0, + "maxGeometryInputComponents": 0, + "maxGeometryOutputComponents": 0, + "maxGeometryOutputVertices": 0, + "maxGeometryTotalOutputComponents": 0, + "maxFragmentInputComponents": 64, + "maxFragmentOutputAttachments": 4, + "maxFragmentDualSrcAttachments": 0, + "maxFragmentCombinedOutputResources": 4, + + "maxComputeSharedMemorySize": 16384, + "maxComputeWorkGroupCount": [ + 65535, + 65535, + 65535 + ], + "maxComputeWorkGroupInvocations": 128, + "maxComputeWorkGroupSize": [ + 128, + 128, + 64 + ], + "subPixelPrecisionBits": 4, + "subTexelPrecisionBits": 4, + "mipmapPrecisionBits": 4, + "maxDrawIndexedIndexValue": 16777216, + "maxDrawIndirectCount": 1, + "maxSamplerLodBias": 2, + "maxSamplerAnisotropy": 1, + "maxViewports": 1, + "maxViewportDimensions": [ + 4096, + 4096 + ], + "viewportBoundsRange": [ + -8192, + 8192 + ], + "viewportSubPixelBits": 0, + "minMemoryMapAlignment": 64, + "minTexelBufferOffsetAlignment": 256, + "minUniformBufferOffsetAlignment": 256, + "minStorageBufferOffsetAlignment": 256, + "minTexelOffset": -8, + "maxTexelOffset": 7, + "minTexelGatherOffset": -8, + "maxTexelGatherOffset": 7, + "minInterpolationOffset": 0.0, + "maxInterpolationOffset": 0.0, + "subPixelInterpolationOffsetBits": 0, + "maxFramebufferWidth": 4096, + "maxFramebufferHeight": 4096, + "maxFramebufferLayers": 256, + "framebufferColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "framebufferNoAttachmentsSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "maxColorAttachments": 4, + "sampledImageColorSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageIntegerSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageDepthSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "sampledImageStencilSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT", + "VK_SAMPLE_COUNT_4_BIT" + ], + "storageImageSampleCounts": [ + "VK_SAMPLE_COUNT_1_BIT" + ], + "maxSampleMaskWords": 1, + "maxClipDistances": 0, + "maxCullDistances": 0, + "maxCombinedClipAndCullDistances": 0, + "discreteQueuePriorities": 2, + "pointSizeRange": [ + 1.0, + 1.0 + ], + "lineWidthRange": [ + 1.0, + 1.0 + ], + "pointSizeGranularity": 1.0, + "lineWidthGranularity": 1.0, + "nonCoherentAtomSize": 256 + }, + "sparseProperties": { + "residencyStandard2DBlockShape": false, + "residencyStandard2DMultisampleBlockShape": false, + "residencyStandard3DBlockShape": false, + "residencyNonResidentStrict": false + } + } + } + }, + "vulkan11requirements_split": { + "features": { + "VkPhysicalDeviceMultiviewFeatures": { + "multiview": true + } + }, + "properties": { + "VkPhysicalDeviceSubgroupProperties": { + "subgroupSize": 1, + "supportedStages": [ "VK_SHADER_STAGE_COMPUTE_BIT" ], + "supportedOperations": [ "VK_SUBGROUP_FEATURE_BASIC_BIT" ] + }, + "VkPhysicalDeviceMultiviewProperties": { + "maxMultiviewViewCount": 6, + "maxMultiviewInstanceIndex": 134217727 + }, + "VkPhysicalDeviceMaintenance3Properties": { + "maxPerSetDescriptors": 1024, + "maxMemoryAllocationSize": 1073741824 + } + + } + }, + "vulkan11requirements": { + "features": { + "VkPhysicalDeviceVulkan11Features": { + "multiview": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan11Properties": { + "subgroupSize": 1, + "subgroupSupportedStages": [ "VK_SHADER_STAGE_COMPUTE_BIT" ], + "subgroupSupportedOperations": [ "VK_SUBGROUP_FEATURE_BASIC_BIT" ], + "maxMultiviewViewCount": 6, + "maxMultiviewInstanceIndex": 134217727, + "maxPerSetDescriptors": 1024, + "maxMemoryAllocationSize": 1073741824 + } + } + }, + "vulkan12requirements": { + "features": { + "VkPhysicalDeviceVulkan12Features": { + "uniformBufferStandardLayout": true, + "subgroupBroadcastDynamicId": true, + "imagelessFramebuffer": true, + "separateDepthStencilLayouts": true, + "hostQueryReset": true, + "timelineSemaphore": true, + "shaderSubgroupExtendedTypes": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan12Properties": { + "shaderSignedZeroInfNanPreserveFloat16": false, + "shaderSignedZeroInfNanPreserveFloat32": false, + "shaderSignedZeroInfNanPreserveFloat64": false, + "shaderDenormPreserveFloat16": false, + "shaderDenormPreserveFloat32": false, + "shaderDenormPreserveFloat64": false, + "shaderDenormFlushToZeroFloat16": false, + "shaderDenormFlushToZeroFloat32": false, + "shaderDenormFlushToZeroFloat64": false, + "shaderRoundingModeRTEFloat16": false, + "shaderRoundingModeRTEFloat32": false, + "shaderRoundingModeRTEFloat64": false, + "shaderRoundingModeRTZFloat16": false, + "shaderRoundingModeRTZFloat32": false, + "shaderRoundingModeRTZFloat64": false, + "maxUpdateAfterBindDescriptorsInAllPools": 0, + "shaderUniformBufferArrayNonUniformIndexingNative": false, + "shaderSampledImageArrayNonUniformIndexingNative": false, + "shaderStorageBufferArrayNonUniformIndexingNative": false, + "shaderStorageImageArrayNonUniformIndexingNative": false, + "shaderInputAttachmentArrayNonUniformIndexingNative": false, + "robustBufferAccessUpdateAfterBind": false, + "quadDivergentImplicitLod": false, + "maxPerStageDescriptorUpdateAfterBindSamplers": 0, + "maxPerStageDescriptorUpdateAfterBindUniformBuffers": 0, + "maxPerStageDescriptorUpdateAfterBindStorageBuffers": 0, + "maxPerStageDescriptorUpdateAfterBindSampledImages": 0, + "maxPerStageDescriptorUpdateAfterBindStorageImages": 0, + "maxPerStageDescriptorUpdateAfterBindInputAttachments": 0, + "maxPerStageUpdateAfterBindResources": 0, + "maxDescriptorSetUpdateAfterBindSamplers": 0, + "maxDescriptorSetUpdateAfterBindUniformBuffers": 0, + "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic": 0, + "maxDescriptorSetUpdateAfterBindStorageBuffers": 0, + "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic": 0, + "maxDescriptorSetUpdateAfterBindSampledImages": 0, + "maxDescriptorSetUpdateAfterBindStorageImages": 0, + "maxDescriptorSetUpdateAfterBindInputAttachments": 0, + "supportedDepthResolveModes": [], + "supportedStencilResolveModes": [], + "independentResolveNone": false, + "independentResolve": false, + "filterMinmaxSingleComponentFormats": false, + "filterMinmaxImageComponentMapping": false, + "maxTimelineSemaphoreValueDifference": 2147483647, + "framebufferIntegerColorSampleCounts": [ "VK_SAMPLE_COUNT_1_BIT" ] + } + } + }, + "vulkan13requirements": { + "features": { + "VkPhysicalDeviceVulkan12Features": { + "vulkanMemoryModel": true, + "vulkanMemoryModelDeviceScope": true, + "bufferDeviceAddress": true + }, + "VkPhysicalDeviceVulkan13Features": { + "robustImageAccess": true, + "inlineUniformBlock": true, + "pipelineCreationCacheControl": true, + "shaderDemoteToHelperInvocation": true, + "shaderTerminateInvocation": true, + "subgroupSizeControl": true, + "computeFullSubgroups": true, + "synchronization2": true, + "shaderZeroInitializeWorkgroupMemory": true, + "dynamicRendering": true, + "shaderIntegerDotProduct": true, + "maintenance4": true + } + }, + "properties": { + "VkPhysicalDeviceVulkan13Properties": { + "maxComputeWorkgroupSubgroups": 0, + "requiredSubgroupSizeStages": [], + "maxInlineUniformBlockSize": 256, + "maxPerStageDescriptorInlineUniformBlocks": 4, + "maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks": 4, + "maxDescriptorSetInlineUniformBlocks": 4, + "maxDescriptorSetUpdateAfterBindInlineUniformBlocks": 4, + "maxInlineUniformTotalSize": 256, + "integerDotProduct8BitUnsignedAccelerated": false, + "integerDotProduct8BitSignedAccelerated": false, + "integerDotProduct8BitMixedSignednessAccelerated": false, + "integerDotProduct4x8BitPackedUnsignedAccelerated": false, + "integerDotProduct4x8BitPackedSignedAccelerated": false, + "integerDotProduct4x8BitPackedMixedSignednessAccelerated": false, + "integerDotProduct16BitUnsignedAccelerated": false, + "integerDotProduct16BitSignedAccelerated": false, + "integerDotProduct16BitMixedSignednessAccelerated": false, + "integerDotProduct32BitUnsignedAccelerated": false, + "integerDotProduct32BitSignedAccelerated": false, + "integerDotProduct32BitMixedSignednessAccelerated": false, + "integerDotProduct64BitUnsignedAccelerated": false, + "integerDotProduct64BitSignedAccelerated": false, + "integerDotProduct64BitMixedSignednessAccelerated": false, + "integerDotProductAccumulatingSaturating8BitUnsignedAccelerated": false, + "integerDotProductAccumulatingSaturating8BitSignedAccelerated": false, + "integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated": false, + "integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated": false, + "integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated": false, + "integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated": false, + "integerDotProductAccumulatingSaturating16BitUnsignedAccelerated": false, + "integerDotProductAccumulatingSaturating16BitSignedAccelerated": false, + "integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated": false, + "integerDotProductAccumulatingSaturating32BitUnsignedAccelerated": false, + "integerDotProductAccumulatingSaturating32BitSignedAccelerated": false, + "integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated": false, + "integerDotProductAccumulatingSaturating64BitUnsignedAccelerated": false, + "integerDotProductAccumulatingSaturating64BitSignedAccelerated": false, + "integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated": false, + "maxBufferSize": 1073741824 + } + } + } + }, + "profiles": { + "VP_LUNARG_minimum_requirements_1_0": { + "version": 1, + "api-version": "1.0.68", + "label": "Vulkan Core 1.0 Minimum Requirements", + "description": "Vulkan Core 1.0 Minimum Requirements.", + "capabilities": [ + "vulkan10requirements" + ] + }, + "VP_LUNARG_minimum_requirements_1_1": { + "version": 1, + "api-version": "1.1.108", + "label": "Vulkan Core 1.1 Minimum Requirements", + "description": "Vulkan Core 1.1 Minimum Requirements.", + "capabilities": [ + "vulkan10requirements", + "vulkan11requirements_split" + ] + }, + "VP_LUNARG_minimum_requirements_1_2": { + "version": 1, + "api-version": "1.2.131", + "label": "Vulkan Core 1.2 Minimum Requirements", + "description": "Vulkan Core 1.2 Minimum Requirements.", + "capabilities": [ + "vulkan10requirements", + "vulkan11requirements", + "vulkan12requirements" + ] + }, + "VP_LUNARG_minimum_requirements_1_3": { + "version": 1, + "api-version": "1.3.204", + "label": "Vulkan Core 1.3 Minimum Requirements", + "description": "Vulkan Core 1.3 Minimum Requirements.", + "capabilities": [ + "vulkan10requirements", + "vulkan11requirements", + "vulkan12requirements", + "vulkan13requirements" + ] + } + }, + "contributors": { + "Christophe Riccio": { + "company": "LunarG", + "email": "christophe@lunarg.com", + "contact": true + } + }, + "history": [ + { + "revision": 1, + "date": "2023-11-01", + "author": "Christophe Riccio", + "comment": "Initial revision" + } + ] +} diff --git a/vkconfig_core/test/resources.qrc b/vkconfig_core/test/resources.qrc index fb214b31f4..c3de24915b 100644 --- a/vkconfig_core/test/resources.qrc +++ b/vkconfig_core/test/resources.qrc @@ -1,89 +1,54 @@ - - Configuration 2.2.2.json - - VK_LAYER_LUNARG_reference_1_1_0.json - VK_LAYER_LUNARG_reference_1_2_0.json - VK_LAYER_LUNARG_reference_1_2_1.json - - VK_LAYER_LUNARG_test_00.json - VK_LAYER_LUNARG_test_01.json - VK_LAYER_LUNARG_test_02.json - VK_LAYER_LUNARG_test_03.json - VK_LAYER_LUNARG_test_04.json - VK_LAYER_LUNARG_test_05.json - VK_LAYER_LUNARG_test_06.json - - override_layers_2_2_2_schema_1_2_1.json - override_settings_2_2_2_schema_1_2_1.txt - - - - ../configurations/2.2.2/API dump.json - ../configurations/2.2.2/Frame Capture.json - ../configurations/2.2.2/Portability.json - ../configurations/2.2.2/Synchronization.json - ../configurations/2.2.2/Validation.json - - - + ../layers/layers_schema.json ../layers/validusage.json - - ../layers/130/VK_LAYER_KHRONOS_validation.json - ../layers/130/VK_LAYER_LUNARG_api_dump.json - ../layers/130/VK_LAYER_LUNARG_monitor.json - ../layers/130/VK_LAYER_LUNARG_screenshot.json - + + Configuration 3.0.0.json - - ../layers/135/VK_LAYER_KHRONOS_validation.json - ../layers/135/VK_LAYER_LUNARG_api_dump.json - ../layers/135/VK_LAYER_LUNARG_monitor.json - ../layers/135/VK_LAYER_LUNARG_screenshot.json + loader_settings.json + layers_settings.txt - - ../layers/141/VK_LAYER_KHRONOS_validation.json - ../layers/141/VK_LAYER_LUNARG_api_dump.json - ../layers/141/VK_LAYER_LUNARG_gfxreconstruct.json - ../layers/141/VK_LAYER_LUNARG_monitor.json - ../layers/141/VK_LAYER_LUNARG_screenshot.json + + ./sdk/VkLayer_api_dump.json + ./sdk/VkLayer_gfxreconstruct.json + ./sdk/VkLayer_khronos_profiles.json + ./sdk/VkLayer_khronos_shader_object.json + ./sdk/VkLayer_khronos_synchronization2.json + ./sdk/VkLayer_khronos_validation.json + ./sdk/VkLayer_monitor.json + ./sdk/VkLayer_screenshot.json - - ../layers/148/VK_LAYER_KHRONOS_validation.json - ../layers/148/VK_LAYER_LUNARG_api_dump.json - ../layers/148/VK_LAYER_LUNARG_gfxreconstruct.json - ../layers/148/VK_LAYER_LUNARG_monitor.json - ../layers/148/VK_LAYER_LUNARG_screenshot.json - + + ./layers/VK_LAYER_LUNARG_reference_1_1_0.json + ./layers/VK_LAYER_LUNARG_reference_1_2_0.json + ./layers/VK_LAYER_LUNARG_reference_1_2_1.json - - ../layers/154/VK_LAYER_KHRONOS_validation.json - ../layers/154/VK_LAYER_LUNARG_api_dump.json - ../layers/154/VK_LAYER_LUNARG_gfxreconstruct.json - ../layers/154/VK_LAYER_LUNARG_monitor.json - ../layers/154/VK_LAYER_LUNARG_screenshot.json + ./layers/VK_LAYER_LUNARG_test_00.json + ./layers/VK_LAYER_LUNARG_test_01.json + ./layers/VK_LAYER_LUNARG_test_02.json + ./layers/VK_LAYER_LUNARG_test_03.json + ./layers/VK_LAYER_LUNARG_test_04.json + ./layers/VK_LAYER_LUNARG_test_05.json + ./layers/VK_LAYER_LUNARG_test_06.json - - ../layers/162/VK_LAYER_KHRONOS_validation.json - ../layers/162/VK_LAYER_LUNARG_api_dump.json - ../layers/162/VK_LAYER_LUNARG_gfxreconstruct.json - ../layers/162/VK_LAYER_LUNARG_monitor.json - ../layers/162/VK_LAYER_LUNARG_screenshot.json - + + ../configurations/3.0.0/API dump.json + ../configurations/3.0.0/Frame Capture.json + ../configurations/3.0.0/Portability.json + ../configurations/3.0.0/Synchronization.json + ../configurations/3.0.0/Validation.json + - - ../layers/170/VK_LAYER_KHRONOS_synchronization2.json - ../layers/170/VK_LAYER_KHRONOS_validation.json - ../layers/170/VK_LAYER_LUNARG_api_dump.json - ../layers/170/VK_LAYER_LUNARG_gfxreconstruct.json - ../layers/170/VK_LAYER_LUNARG_monitor.json - ../layers/170/VK_LAYER_LUNARG_screenshot.json - + + ./profiles/VP_KHR_roadmap.json + ./profiles/VP_LUNARG_desktop_baseline.json + ./profiles/VP_LUNARG_desktop_baseline_config.json + ./profiles/VP_LUNARG_minimum_requirements.json + diff --git a/vkconfig_core/layers/170/VK_LAYER_LUNARG_api_dump.json b/vkconfig_core/test/sdk/VkLayer_api_dump.json similarity index 88% rename from vkconfig_core/layers/170/VK_LAYER_LUNARG_api_dump.json rename to vkconfig_core/test/sdk/VkLayer_api_dump.json index 87a65ca201..08cdb5d949 100644 --- a/vkconfig_core/layers/170/VK_LAYER_LUNARG_api_dump.json +++ b/vkconfig_core/test/sdk/VkLayer_api_dump.json @@ -4,12 +4,23 @@ "name": "VK_LAYER_LUNARG_api_dump", "type": "GLOBAL", "library_path": ".\\VkLayer_api_dump.dll", - "api_version": "1.2.170", + "api_version": "1.3.283", "implementation_version": "2", "description": "LunarG API dump layer", "introduction": "The API Dump utility layer prints API calls, parameters, and values to the identified output stream.", "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/api_dump_layer.html", - "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], + "instance_extensions": [ + { + "name": "VK_EXT_layer_settings", + "spec_version": "2" + } + ], "device_extensions": [ { "name": "VK_EXT_tooling_info", @@ -24,7 +35,12 @@ { "label": "Console Output", "description": "Output API dump to stdout", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], "status": "STABLE", "settings": [ { @@ -44,7 +60,12 @@ { "label": "Text Output", "description": "Output API dump to a text file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], "status": "STABLE", "settings": [ { @@ -64,7 +85,12 @@ { "label": "HTML Output", "description": "Output API dump to a HTML file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], "status": "STABLE", "settings": [ { @@ -84,7 +110,12 @@ { "label": "JSON Output", "description": "Output API dump to a JSON file", - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], "status": "STABLE", "settings": [ { @@ -142,7 +173,6 @@ "description": "Setting this to true indicates that output should be written to file instead of stdout", "type": "BOOL", "default": false, - "platforms": [ "WINDOWS", "LINUX", "MACOS" ], "settings": [ { "key": "log_filename", @@ -195,7 +225,7 @@ "label": "Type Size", "description": "The number of characters the name of a type should consume, assuming more are not required", "type": "INT", - "default": 32, + "default": 0, "range": { "min": 0 }, @@ -212,7 +242,7 @@ ] }, { - "key": "show_timestamp", + "key": "timestamp", "env": "VK_APIDUMP_TIMESTAMP", "label": "Show Timestamp", "description": "Show the timestamp of function calls since start in microseconds", @@ -271,6 +301,13 @@ } } ] + }, + { + "key": "show_thread_and_frame", + "label": "Show Thread and Frame", + "description": "Show the thread and frame of each function called", + "type": "BOOL", + "default": true } ] } diff --git a/vkconfig_core/layers/170/VK_LAYER_LUNARG_gfxreconstruct.json b/vkconfig_core/test/sdk/VkLayer_gfxreconstruct.json similarity index 79% rename from vkconfig_core/layers/170/VK_LAYER_LUNARG_gfxreconstruct.json rename to vkconfig_core/test/sdk/VkLayer_gfxreconstruct.json index f359921d93..c7095acb59 100644 --- a/vkconfig_core/layers/170/VK_LAYER_LUNARG_gfxreconstruct.json +++ b/vkconfig_core/test/sdk/VkLayer_gfxreconstruct.json @@ -4,12 +4,13 @@ "name": "VK_LAYER_LUNARG_gfxreconstruct", "type": "GLOBAL", "library_path": ".\\VkLayer_gfxreconstruct.dll", - "api_version": "1.2.170", - "implementation_version": "36870", - "description": "GFXReconstruct Capture Layer Version 0.9.6", + "api_version": "1.3.283", + "implementation_version": "4194308", + "description": "GFXReconstruct Capture Layer Version 1.0.4", "introduction": "The GFXReconstruct Capture Layer intercepts Vulkan API calls and logs them to a capture file. Other tools in the GFXReconstruct suite can inspect, modify, or replay capture files generated by this component.", - "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/capture_tools.html", "platforms": [ "WINDOWS", "LINUX", "ANDROID" ], + "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/capture_tools.html", + "status": "STABLE", "device_extensions": [ { "name": "VK_EXT_tooling_info", @@ -22,6 +23,7 @@ { "label": "Initialization", "description": "Capture the first two frames.", + "platforms": [ "WINDOWS", "LINUX" ], "settings": [ { "key": "capture_trigger", @@ -30,16 +32,13 @@ { "key": "capture_frames", "value": "1-2" - }, - { - "key": "memory_tracking_mode", - "value": "unassisted" } ] }, { "label": "Range", "description": "Capture a range of frames between presses of the F5 key.", + "platforms": [ "WINDOWS", "LINUX" ], "settings": [ { "key": "capture_trigger", @@ -48,10 +47,6 @@ { "key": "capture_frames", "value": "" - }, - { - "key": "memory_tracking_mode", - "value": "page_guard" } ] } @@ -62,6 +57,7 @@ "env": "GFXRECON_CAPTURE_TRIGGER", "label": "Hotkey Capture Trigger", "description": "Specify a hotkey (any one of F1-F12, TAB, CONTROL) that will be used to start/stop capture. Example: F3 will set the capture trigger to F3 hotkey. One capture file will be generated for each pair of start/stop hotkey presses. Default is: Empty string (hotkey capture trigger is disabled).", + "platforms" : [ "WINDOWS", "LINUX" ], "type": "ENUM", "flags": [ { @@ -72,81 +68,84 @@ { "key": "F1", "label": "F1", - "description": "" + "description": "F1 Key" }, { "key": "F2", "label": "F2", - "description": "" + "description": "F2 Key" }, { "key": "F3", "label": "F3", - "description": "" + "description": "F3 Key" }, { "key": "F4", "label": "F4", - "description": "" + "description": "F4 Key" }, { "key": "F5", "label": "F5", - "description": "" + "description": "F5 Key" }, { "key": "F6", "label": "F6", - "description": "" + "description": "F6 Key" }, { "key": "F7", "label": "F7", - "description": "" + "description": "F7 Key" }, { "key": "F8", "label": "F8", - "description": "" + "description": "F8 Key" }, { "key": "F9", "label": "F9", - "description": "" + "description": "F9 Key" }, { "key": "F10", "label": "F10", - "description": "" - }, - { - "key": "F10", - "label": "F10", - "description": "" + "description": "F10 Key" }, { "key": "F11", "label": "F11", - "description": "" + "description": "F11 Key" }, { "key": "F12", "label": "F12", - "description": "" + "description": "F12 Key" }, { "key": "TAB", "label": "TAB", - "description": "" + "description": "TAB Key" }, { "key": "CONTROL", "label": "CONTROL", - "description": "" + "description": "CONTROL Key" } ], "default": "" }, + { + "key": "capture_trigger_frames", + "env": "GFXRECON_CAPTURE_TRIGGER_FRAMES", + "label": "Hotkey Capture Frame Limit", + "description": "Specify a limit on the number of frames to be captured via hotkey. Example: 1 will capture exactly one frame when the trigger key is pressed. Default is: Empty string (no limit)", + "type": "STRING", + "default": "" + }, { "key": "capture_frames", "env": "GFXRECON_CAPTURE_FRAMES", @@ -162,7 +161,7 @@ "description": "Path to use when creating the capture file. Default is: gfxrecon_capture.gfxr", "type": "SAVE_FILE", "filter": "*.gfxr", - "default": "${VK_LOCAL}/gfxrecon_capture.gfxr", + "default": "gfxrecon_capture.gfxr", "settings": [ { "key": "capture_file_timestamp", @@ -178,7 +177,7 @@ "label": "Capture File Flush After Write", "description": "Flush output stream after each packet is written to the capture file. Default is: false.", "type": "BOOL", - "default": true + "default": false } ] }, @@ -292,7 +291,7 @@ { "key": "page_guard_persistent_memory", "env": "GFXRECON_PAGE_GUARD_PERSISTENT_MEMORY", - "label": "Page Guard Persisent Memory", + "label": "Page Guard Persistent Memory", "description": "When the page_guard memory tracking mode is enabled, this option changes the way that the shadow memory used to detect modifications to mapped memory is allocated. The default behavior is to allocate and copy the mapped memory range on map and free the allocation on unmap. When this option is enabled, an allocation with a size equal to that of the object being mapped is made once on the first map and is not freed until the object is destroyed. This option is intended to be used with applications that frequently map and unmap large memory ranges, to avoid frequent allocation and copy operations that can have a negative impact on performance. This option is ignored when GFXRECON_PAGE_GUARD_EXTERNAL_MEMORY is enabled.", "type": "BOOL", "default": false, @@ -309,6 +308,48 @@ } ] } + }, + { + "key": "page_guard_align_buffer_sizes", + "env": "GFXRECON_PAGE_GUARD_ALIGN_BUFFER_SIZES", + "label": "Page Guard Align Buffer Sizes", + "description": "When the page_guard memory tracking mode is enabled, this option overrides the Vulkan API calls that report buffer memory properties to report that buffer sizes and alignments must be a multiple of the system page size. This option is intended to be used with applications that perform CPU writes and GPU writes/copies to different buffers that are bound to the same page of mapped memory, which may result in data being lost when copying pages from the page_guard shadow allocation to the real allocation. This data loss can result in visible corruption during capture. Forcing buffer sizes and alignments to a multiple of the system page size prevents multiple buffers from being bound to the same page, avoiding data loss from simultaneous CPU writes to the shadow allocation and GPU writes to the real allocation for different buffers bound to the same page. This option is only available for the Vulkan API.", + "type": "BOOL", + "default": true, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "memory_tracking_mode", + "value": "page_guard" + }, + { + "key": "page_guard_external_memory", + "value": false + } + ] + } + }, + { + "key": "page_guard_unblock_sigsegv", + "env": "GFXRECON_PAGE_GUARD_UNBLOCK_SIGSEGV", + "label": "Page Guard unblock SIGSEGV from thread's signal mask", + "description": "When the page_guard memory tracking mode is enabled, this option overrides enables SIGSEGV in thread's signal mask in the case that it has been disabled.", + "type": "BOOL", + "default": false, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "memory_tracking_mode", + "value": "page_guard" + }, + { + "key": "page_guard_external_memory", + "value": false + } + ] + } } ] }, @@ -322,7 +363,7 @@ "key": "log_level", "env": "GFXRECON_LOG_LEVEL", "label": "Level", - "description": "Specify the highest level message to log. Options are: debug, info, warning, error, and fatal. The specified level and all levels listed after it will be enabled for logging. For example, choosing the warning level will also enable the error and fatal levels.", + "description": "Specify the minimum severity level of messages to log. Options are: debug, info, warning, error, and fatal. The specified level and all higher levels will be enabled for logging. For example, choosing the warning level will also enable the error and fatal levels.", "type": "ENUM", "flags": [ { @@ -361,6 +402,14 @@ "type": "BOOL", "default": false }, + { + "key": "log_allow_indents", + "env": "GFXRECON_LOG_ALLOW_INDENTS", + "label": "Log Name and Line Number", + "description": "Apply additional indentation formatting to log messages.", + "type": "BOOL", + "default": false + }, { "key": "log_output_to_console", "env": "GFXRECON_LOG_OUTPUT_TO_CONSOLE", diff --git a/vkconfig_core/test/sdk/VkLayer_khronos_profiles.json b/vkconfig_core/test/sdk/VkLayer_khronos_profiles.json new file mode 100644 index 0000000000..9280b82a6a --- /dev/null +++ b/vkconfig_core/test/sdk/VkLayer_khronos_profiles.json @@ -0,0 +1,1280 @@ +{ + "file_format_version": "1.2.1", + "layer": { + "name": "VK_LAYER_KHRONOS_profiles", + "type": "GLOBAL", + "library_path": ".\\VkLayer_khronos_profiles.dll", + "api_version": "1.3.283", + "implementation_version": "1.3.0", + "status": "STABLE", + "description": "Khronos Profiles layer", + "introduction": "The Khronos Profiles layer helps test across a wide range of hardware capabilities without requiring a physical copy of every device.", + "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/profiles_layer.html", + "instance_extensions": [ + { + "name": "VK_EXT_layer_settings", + "spec_version": "2" + } + ], + "device_extensions": [ + { + "name": "VK_EXT_tooling_info", + "spec_version": "1", + "entrypoints": [ + "vkGetPhysicalDeviceToolPropertiesEXT" + ] + } + ], + "features": { + "presets": [ + { + "label": "Force Physical Device Only", + "description": "Use the Profiles layer to force a specific physical device", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "status": "STABLE", + "settings": [ + { + "key": "force_device", + "value": "FORCE_DEVICE_WITH_NAME" + }, + { + "key": "profile_emulation", + "value": false + }, + { + "key": "simulate_capabilities", + "value": [] + }, + { + "key": "emulate_portability", + "value": false + } + ] + }, + { + "label": "Emulate a Vulkan Conformant Profile", + "description": "Emulate a Conformant Vulkan Profile", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "status": "STABLE", + "settings": [ + { + "key": "force_device", + "value": "FORCE_DEVICE_OFF" + }, + { + "key": "profile_emulation", + "value": true + }, + { + "key": "profile_dirs", + "value": "${VULKAN_CONTENT}/VK_LAYER_KHRONOS_profiles" + }, + { + "key": "profile_name", + "value": "VP_LUNARG_desktop_baseline_2023" + }, + { + "key": "simulate_capabilities", + "value": [ "SIMULATE_API_VERSION_BIT", "SIMULATE_FEATURES_BIT", "SIMULATE_PROPERTIES_BIT" ] + }, + { + "key": "emulate_portability", + "value": false + } + ] + }, + { + "label": "Emulate a Vulkan Portability Profile", + "description": "Emulate a Vulkan Profile with Vulkan Portability", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "status": "STABLE", + "settings": [ + { + "key": "force_device", + "value": "FORCE_DEVICE_OFF" + }, + { + "key": "profile_emulation", + "value": true + }, + { + "key": "profile_dirs", + "value": "${VULKAN_CONTENT}/VK_LAYER_KHRONOS_profiles" + }, + { + "key": "profile_name", + "value": "VP_LUNARG_desktop_baseline_2023" + }, + { + "key": "simulate_capabilities", + "value": [ "SIMULATE_API_VERSION_BIT", "SIMULATE_FEATURES_BIT", "SIMULATE_PROPERTIES_BIT" ] + }, + { + "key": "emulate_portability", + "value": true + }, + { + "key": "vertexAttributeAccessBeyondStride", + "value": true + }, + { + "key": "separateStencilMaskRef", + "value": true + }, + { + "key": "mutableComparisonSamplers", + "value": true + }, + { + "key": "multisampleArrayImage", + "value": true + }, + { + "key": "imageViewFormatSwizzle", + "value": true + }, + { + "key": "imageViewFormatReinterpretation", + "value": true + }, + { + "key": "events", + "value": true + }, + { + "key": "constantAlphaColorBlendFactors", + "value": true + } + ] + } + ], + "settings": [ + { + "key": "force_device", + "label": "Force Device", + "description": "On system with multiple physical devices, force the use of one specific physical device.", + "status": "STABLE", + "type": "ENUM", + "default": "FORCE_DEVICE_OFF", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "flags": [ + { + "key": "FORCE_DEVICE_OFF", + "label": "Off", + "description": "Let the Vulkan Loader list all the Physical Device." + }, + { + "key": "FORCE_DEVICE_WITH_UUID", + "label": "Using Device UUID", + "description": "Force the Physical Device identified by the device UUID.", + "settings": [ + { + "key": "force_device_uuid", + "label": "Device UUID", + "description": "Device UUID of the forced physical devices", + "status": "STABLE", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "type": "STRING", + "default": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "force_device", + "value": "FORCE_DEVICE_WITH_UUID" + } + ] + } + } + ] + }, + { + "key": "FORCE_DEVICE_WITH_NAME", + "label": "Using Device Name", + "description": "Force the Physical Device identified by the device UUID.", + "settings": [ + { + "key": "force_device_name", + "label": "Device Name", + "description": "Device Name of the forced physical devices", + "status": "STABLE", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "type": "ENUM", + "flags": [], + "default": "${VP_PHYSICAL_DEVICES}", + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "force_device", + "value": "FORCE_DEVICE_WITH_NAME" + } + ] + } + } + ] + } + ] + }, + { + "key": "profile_emulation", + "label": "Emulate a Vulkan Profile", + "description": "Emulate a Vulkan Profile on the Developer System", + "status": "STABLE", + "type": "BOOL", + "default": true, + "settings": [ + { + "key": "profile_dirs", + "label": "Loading Directory", + "description": "Select the location all the profiles.", + "type": "LOAD_FOLDER", + "format": "PROFILE", + "default": "", + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "profile_emulation", + "value": true + } + ] + } + }, + { + "key": "profile_name", + "label": "Name", + "description": "Name of the profile specified by the profile file to use.", + "type": "ENUM", + "flags": [], + "default": "${VP_DEFAULT}", + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "profile_emulation", + "value": true + } + ] + } + }, + { + "key": "profile_validation", + "label": "Schema Validation", + "description": "Validate the profile files against the Vulkan SDK profile schema if the file is found.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "profile_emulation", + "value": true + } + ] + } + } + ] + }, + { + "key": "simulate_capabilities", + "label": "Simulate Profile Capabilities", + "description": "Control of the simulated capabilities of the Vulkan physical device from the selected Vulkan Profile.", + "status": "STABLE", + "type": "FLAGS", + "flags": [ + { + "key": "SIMULATE_API_VERSION_BIT", + "label": "Version", + "description": "The Vulkan device will report the API version from the selected Profile. It also overrides the `api-version` set in VkPhysicalDeviceProperties." + }, + { + "key": "SIMULATE_FEATURES_BIT", + "label": "Features", + "description": "The Vulkan device will report the features from the selected Profile.", + "settings": [ + { + "key": "default_feature_values", + "label": "Unspecified Features", + "description": "Feature values when not specified in the select Vulkan profiles.", + "status": "STABLE", + "type": "ENUM", + "default": "DEFAULT_FEATURE_VALUES_DEVICE", + "flags": [ + { + "key": "DEFAULT_FEATURE_VALUES_DEVICE", + "label": "Use Device Values", + "description": "When a feature is not mentionned in the select Vulkan profiles, set is to the physical device value." + }, + { + "key": "DEFAULT_FEATURE_VALUES_FALSE", + "label": "Use False", + "description": "When a feature is not mentionned in the select Vulkan profiles, set it to false." + } + ] + } + ] + }, + { + "key": "SIMULATE_PROPERTIES_BIT", + "label": "Properties", + "description": "The Vulkan device will report the properties from the selected Profile." + }, + { + "key": "SIMULATE_EXTENSIONS_BIT", + "label": "Device Extensions", + "description": "The Vulkan device will report the extensions from the selected Profile." + }, + { + "key": "SIMULATE_FORMATS_BIT", + "label": "Formats", + "description": "The Vulkan device will report the formats from the selected Profile." + } + ], + "default": [ "SIMULATE_API_VERSION_BIT", "SIMULATE_FEATURES_BIT", "SIMULATE_PROPERTIES_BIT" ] + }, + { + "key": "emulate_portability", + "label": "Emulate VK_KHR_portability_subset", + "description": "Emulate the VK_KHR_portability_subset extension on the device.", + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "type": "BOOL", + "default": true, + "settings": [ + { + "key": "constantAlphaColorBlendFactors", + "label": "constantAlphaColorBlendFactors", + "description": "Indicates whether this implementation supports constant alpha Blend Factors used as source or destination color Blending.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "events", + "label": "events", + "description": "Indicates whether this implementation supports synchronization using Events", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "imageViewFormatReinterpretation", + "label": "imageViewFormatReinterpretation", + "description": "Indicates whether this implementation supports a VkImageView being created with a texel format containing a different number of components, or a different number of bits in each component, than the texel format of the underlying VkImage.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "imageViewFormatSwizzle", + "label": "imageViewFormatSwizzle", + "description": "Indicates whether this implementation supports remapping format components using VkImageViewCreateInfo::components.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "imageView2DOn3DImage", + "label": "imageView2DOn3DImage", + "description": "Indicates whether this implementation supports a VkImage being created with the VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT flag set, permitting a 2D or 2D array image view to be created on a 3D VkImage.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "multisampleArrayImage", + "label": "multisampleArrayImage", + "description": "Indicates whether this implementation supports a VkImage being created as a 2D array with multiple samples per texel.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "mutableComparisonSamplers", + "label": "mutableComparisonSamplers", + "description": "Indicates whether this implementation allows descriptors with comparison samplers to be updated.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "pointPolygons", + "label": "pointPolygons", + "description": "Indicates whether this implementation supports Rasterization using a point Polygon Mode.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "samplerMipLodBias", + "label": "samplerMipLodBias", + "description": "Indicates whether this implementation supports setting a mipmap LOD bias value when creating a sampler.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "separateStencilMaskRef", + "label": "separateStencilMaskRef", + "description": "Indicates whether this implementation supports separate front and back Stencil Test reference values.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "shaderSampleRateInterpolationFunctions", + "label": "shaderSampleRateInterpolationFunctions", + "description": "Indicates whether this implementation supports fragment shaders which use the InterpolationFunction capability.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "tessellationIsolines", + "label": "tessellationIsolines", + "description": "Indicates whether this implementation supports isoline output from the Tessellation stage of a graphics pipeline. This member is only meaningful if tessellationShader are supported.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "triangleFans", + "label": "triangleFans", + "description": "Indicates whether this implementation supports Triangle Fans primitive topology.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + } + }, + { + "key": "vertexAttributeAccessBeyondStride", + "label": "vertexAttributeAccessBeyondStride", + "description": "Indicates whether this implementation supports accessing a vertex input attribute beyond the stride of the corresponding vertex input binding.", + "type": "BOOL", + "default": false, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "emulate_portability", + "value": true + } + ] + }, + "settings": [ + { + "key": "minVertexInputBindingStrideAlignment", + "label": "minVertexInputBindingStrideAlignment", + "description": "Indicates whether this implementation supports accessing a vertex input attribute beyond the stride of the corresponding vertex input binding.", + "type": "INT", + "default": 4, + "platforms": [ "WINDOWS", "LINUX" ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "vertexAttributeAccessBeyondStride", + "value": false + } + ] + } + } + ] + } + ] + }, + { + "key": "exclude_device_extensions", + "label": "Exclude Device Extensions", + "description": "Removes the listed device extensions from being reported by the Vulkan physical device.", + "status": "STABLE", + "type": "LIST", + "list": [ + "VK_KHR_16bit_storage", + "VK_KHR_8bit_storage", + "VK_KHR_acceleration_structure", + "VK_KHR_bind_memory2", + "VK_KHR_buffer_device_address", + "VK_KHR_copy_commands2", + "VK_KHR_create_renderpass2", + "VK_KHR_dedicated_allocation", + "VK_KHR_deferred_host_operations", + "VK_KHR_depth_stencil_resolve", + "VK_KHR_descriptor_update_template", + "VK_KHR_device_group", + "VK_KHR_display_swapchain", + "VK_KHR_draw_indirect_count", + "VK_KHR_driver_properties", + "VK_KHR_dynamic_rendering", + "VK_KHR_external_fence", + "VK_KHR_external_fence_fd", + "VK_KHR_external_fence_win32", + "VK_KHR_external_memory", + "VK_KHR_external_memory_fd", + "VK_KHR_external_memory_win32", + "VK_KHR_external_semaphore", + "VK_KHR_external_semaphore_fd", + "VK_KHR_external_semaphore_win32", + "VK_KHR_format_feature_flags2", + "VK_KHR_fragment_shading_rate", + "VK_KHR_get_memory_requirements2", + "VK_KHR_image_format_list", + "VK_KHR_imageless_framebuffer", + "VK_KHR_incremental_present", + "VK_KHR_maintenance1", + "VK_KHR_maintenance2", + "VK_KHR_maintenance3", + "VK_KHR_maintenance4", + "VK_KHR_multiview", + "VK_KHR_performance_query", + "VK_KHR_pipeline_executable_properties", + "VK_KHR_pipeline_library", + "VK_KHR_portability_subset", + "VK_KHR_present_id", + "VK_KHR_present_wait", + "VK_KHR_push_descriptor", + "VK_KHR_ray_query", + "VK_KHR_ray_tracing_pipeline", + "VK_KHR_relaxed_block_layout", + "VK_KHR_sampler_mirror_clamp_to_edge", + "VK_KHR_sampler_ycbcr_conversion", + "VK_KHR_separate_depth_stencil_layouts", + "VK_KHR_shader_atomic_int64", + "VK_KHR_shader_clock", + "VK_KHR_shader_draw_parameters", + "VK_KHR_shader_float16_int8", + "VK_KHR_shader_float_controls", + "VK_KHR_shader_integer_dot_product", + "VK_KHR_shader_non_semantic_info", + "VK_KHR_shader_subgroup_extended_types", + "VK_KHR_shader_subgroup_uniform_control_flow", + "VK_KHR_shader_terminate_invocation", + "VK_KHR_shared_presentable_image", + "VK_KHR_spirv_1_4", + "VK_KHR_storage_buffer_storage_class", + "VK_KHR_swapchain", + "VK_KHR_swapchain_mutable_format", + "VK_KHR_synchronization2", + "VK_KHR_timeline_semaphore", + "VK_KHR_uniform_buffer_standard_layout", + "VK_KHR_variable_pointers", + "VK_KHR_video_decode_queue", + "VK_KHR_video_encode_queue", + "VK_KHR_video_queue", + "VK_KHR_vulkan_memory_model", + "VK_KHR_win32_keyed_mutex", + "VK_KHR_workgroup_memory_explicit_layout", + "VK_KHR_zero_initialize_workgroup_memory", + "VK_EXT_4444_formats", + "VK_EXT_astc_decode_mode", + "VK_EXT_blend_operation_advanced", + "VK_EXT_border_color_swizzle", + "VK_EXT_buffer_device_address", + "VK_EXT_calibrated_timestamps", + "VK_EXT_color_write_enable", + "VK_EXT_conditional_rendering", + "VK_EXT_conservative_rasterization", + "VK_EXT_custom_border_color", + "VK_EXT_debug_marker", + "VK_EXT_depth_clip_control", + "VK_EXT_depth_clip_enable", + "VK_EXT_depth_range_unrestricted", + "VK_EXT_descriptor_indexing", + "VK_EXT_device_memory_report", + "VK_EXT_discard_rectangles", + "VK_EXT_display_control", + "VK_EXT_extended_dynamic_state", + "VK_EXT_extended_dynamic_state2", + "VK_EXT_external_memory_dma_buf", + "VK_EXT_external_memory_host", + "VK_EXT_filter_cubic", + "VK_EXT_fragment_density_map", + "VK_EXT_fragment_density_map2", + "VK_EXT_fragment_shader_interlock", + "VK_EXT_full_screen_exclusive", + "VK_EXT_global_priority", + "VK_EXT_global_priority_query", + "VK_EXT_hdr_metadata", + "VK_EXT_host_query_reset", + "VK_EXT_image_drm_format_modifier", + "VK_EXT_image_robustness", + "VK_EXT_image_view_min_lod", + "VK_EXT_index_type_uint8", + "VK_EXT_inline_uniform_block", + "VK_EXT_line_rasterization", + "VK_EXT_load_store_op_none", + "VK_EXT_memory_budget", + "VK_EXT_memory_priority", + "VK_EXT_multi_draw", + "VK_EXT_pageable_device_local_memory", + "VK_EXT_pci_bus_info", + "VK_EXT_physical_device_drm", + "VK_EXT_pipeline_creation_cache_control", + "VK_EXT_pipeline_creation_feedback", + "VK_EXT_post_depth_coverage", + "VK_EXT_primitive_topology_list_restart", + "VK_EXT_private_data", + "VK_EXT_provoking_vertex", + "VK_EXT_queue_family_foreign", + "VK_EXT_rgba10x6_formats", + "VK_EXT_robustness2", + "VK_EXT_sample_locations", + "VK_EXT_sampler_filter_minmax", + "VK_EXT_scalar_block_layout", + "VK_EXT_separate_stencil_usage", + "VK_EXT_shader_atomic_float", + "VK_EXT_shader_atomic_float2", + "VK_EXT_shader_demote_to_helper_invocation", + "VK_EXT_shader_image_atomic_int64", + "VK_EXT_shader_stencil_export", + "VK_EXT_shader_subgroup_ballot", + "VK_EXT_shader_subgroup_vote", + "VK_EXT_shader_viewport_index_layer", + "VK_EXT_subgroup_size_control", + "VK_EXT_texel_buffer_alignment", + "VK_EXT_texture_compression_astc_hdr", + "VK_EXT_tooling_info", + "VK_EXT_transform_feedback", + "VK_EXT_validation_cache", + "VK_EXT_vertex_attribute_divisor", + "VK_EXT_vertex_input_dynamic_state", + "VK_EXT_video_decode_h264", + "VK_EXT_video_decode_h265", + "VK_EXT_video_encode_h264", + "VK_EXT_video_encode_h265", + "VK_EXT_ycbcr_2plane_444_formats", + "VK_EXT_ycbcr_image_arrays", + "VK_AMD_buffer_marker", + "VK_AMD_device_coherent_memory", + "VK_AMD_display_native_hdr", + "VK_AMD_draw_indirect_count", + "VK_AMD_gcn_shader", + "VK_AMD_gpu_shader_half_float", + "VK_AMD_gpu_shader_int16", + "VK_AMD_memory_overallocation_behavior", + "VK_AMD_mixed_attachment_samples", + "VK_AMD_negative_viewport_height", + "VK_AMD_pipeline_compiler_control", + "VK_AMD_rasterization_order", + "VK_AMD_shader_ballot", + "VK_AMD_shader_core_properties", + "VK_AMD_shader_core_properties2", + "VK_AMD_shader_explicit_vertex_parameter", + "VK_AMD_shader_fragment_mask", + "VK_AMD_shader_image_load_store_lod", + "VK_AMD_shader_info", + "VK_AMD_shader_trinary_minmax", + "VK_AMD_texture_gather_bias_lod", + "VK_ANDROID_external_memory_android_hardware_buffer", + "VK_ARM_rasterization_order_attachment_access", + "VK_FUCHSIA_buffer_collection", + "VK_FUCHSIA_external_memory", + "VK_FUCHSIA_external_semaphore", + "VK_GGP_frame_token", + "VK_GOOGLE_decorate_string", + "VK_GOOGLE_display_timing", + "VK_GOOGLE_hlsl_functionality1", + "VK_GOOGLE_user_type", + "VK_HUAWEI_invocation_mask", + "VK_HUAWEI_subpass_shading", + "VK_IMG_filter_cubic", + "VK_IMG_format_pvrtc", + "VK_INTEL_performance_query", + "VK_INTEL_shader_integer_functions2", + "VK_NV_acquire_winrt_display", + "VK_NV_clip_space_w_scaling", + "VK_NV_compute_shader_derivatives", + "VK_NV_cooperative_matrix", + "VK_NV_corner_sampled_image", + "VK_NV_coverage_reduction_mode", + "VK_NV_dedicated_allocation", + "VK_NV_dedicated_allocation_image_aliasing", + "VK_NV_device_diagnostic_checkpoints", + "VK_NV_device_diagnostics_config", + "VK_NV_device_generated_commands", + "VK_NV_external_memory", + "VK_NV_external_memory_rdma", + "VK_NV_external_memory_win32", + "VK_NV_fill_rectangle", + "VK_NV_fragment_coverage_to_color", + "VK_NV_fragment_shader_barycentric", + "VK_NV_fragment_shading_rate_enums", + "VK_NV_framebuffer_mixed_samples", + "VK_NV_geometry_shader_passthrough", + "VK_NV_glsl_shader", + "VK_NV_inherited_viewport_scissor", + "VK_NV_mesh_shader", + "VK_NV_ray_tracing", + "VK_NV_ray_tracing_motion_blur", + "VK_NV_representative_fragment_test", + "VK_NV_sample_mask_override_coverage", + "VK_NV_scissor_exclusive", + "VK_NV_shader_image_footprint", + "VK_NV_shader_sm_builtins", + "VK_NV_shader_subgroup_partitioned", + "VK_NV_shading_rate_image", + "VK_NV_viewport_array2", + "VK_NV_viewport_swizzle", + "VK_NV_win32_keyed_mutex", + "VK_QCOM_render_pass_shader_resolve", + "VK_QCOM_render_pass_store_ops", + "VK_QCOM_render_pass_transform", + "VK_QCOM_rotated_copy_commands", + "VK_VALVE_mutable_descriptor_type", + "VK_QCOM_fragment_density_map_offset", + "VK_NV_linear_color_attachment", + "VK_KHR_global_priority" + ], + "default": [] + }, + { + "key": "exclude_formats", + "label": "Exclude Formats", + "description": "Removes the format feature flags from being reported by the Vulkan physical device.", + "status": "STABLE", + "type": "LIST", + "list": [ + "VK_FORMAT_R4G4_UNORM_PACK8", + "VK_FORMAT_R4G4B4A4_UNORM_PACK16", + "VK_FORMAT_B4G4R4A4_UNORM_PACK16", + "VK_FORMAT_R5G6B5_UNORM_PACK16", + "VK_FORMAT_B5G6R5_UNORM_PACK16", + "VK_FORMAT_R5G5B5A1_UNORM_PACK16", + "VK_FORMAT_B5G5R5A1_UNORM_PACK16", + "VK_FORMAT_A1R5G5B5_UNORM_PACK16", + "VK_FORMAT_R8_UNORM", + "VK_FORMAT_R8_SNORM", + "VK_FORMAT_R8_USCALED", + "VK_FORMAT_R8_SSCALED", + "VK_FORMAT_R8_UINT", + "VK_FORMAT_R8_SINT", + "VK_FORMAT_R8_SRGB", + "VK_FORMAT_R8G8_UNORM", + "VK_FORMAT_R8G8_SNORM", + "VK_FORMAT_R8G8_USCALED", + "VK_FORMAT_R8G8_SSCALED", + "VK_FORMAT_R8G8_UINT", + "VK_FORMAT_R8G8_SINT", + "VK_FORMAT_R8G8_SRGB", + "VK_FORMAT_R8G8B8_UNORM", + "VK_FORMAT_R8G8B8_SNORM", + "VK_FORMAT_R8G8B8_USCALED", + "VK_FORMAT_R8G8B8_SSCALED", + "VK_FORMAT_R8G8B8_UINT", + "VK_FORMAT_R8G8B8_SINT", + "VK_FORMAT_R8G8B8_SRGB", + "VK_FORMAT_B8G8R8_UNORM", + "VK_FORMAT_B8G8R8_SNORM", + "VK_FORMAT_B8G8R8_USCALED", + "VK_FORMAT_B8G8R8_SSCALED", + "VK_FORMAT_B8G8R8_UINT", + "VK_FORMAT_B8G8R8_SINT", + "VK_FORMAT_B8G8R8_SRGB", + "VK_FORMAT_R8G8B8A8_UNORM", + "VK_FORMAT_R8G8B8A8_SNORM", + "VK_FORMAT_R8G8B8A8_USCALED", + "VK_FORMAT_R8G8B8A8_SSCALED", + "VK_FORMAT_R8G8B8A8_UINT", + "VK_FORMAT_R8G8B8A8_SINT", + "VK_FORMAT_R8G8B8A8_SRGB", + "VK_FORMAT_B8G8R8A8_UNORM", + "VK_FORMAT_B8G8R8A8_SNORM", + "VK_FORMAT_B8G8R8A8_USCALED", + "VK_FORMAT_B8G8R8A8_SSCALED", + "VK_FORMAT_B8G8R8A8_UINT", + "VK_FORMAT_B8G8R8A8_SINT", + "VK_FORMAT_B8G8R8A8_SRGB", + "VK_FORMAT_A8B8G8R8_UNORM_PACK32", + "VK_FORMAT_A8B8G8R8_SNORM_PACK32", + "VK_FORMAT_A8B8G8R8_USCALED_PACK32", + "VK_FORMAT_A8B8G8R8_SSCALED_PACK32", + "VK_FORMAT_A8B8G8R8_UINT_PACK32", + "VK_FORMAT_A8B8G8R8_SINT_PACK32", + "VK_FORMAT_A8B8G8R8_SRGB_PACK32", + "VK_FORMAT_A2R10G10B10_UNORM_PACK32", + "VK_FORMAT_A2R10G10B10_SNORM_PACK32", + "VK_FORMAT_A2R10G10B10_USCALED_PACK32", + "VK_FORMAT_A2R10G10B10_SSCALED_PACK32", + "VK_FORMAT_A2R10G10B10_UINT_PACK32", + "VK_FORMAT_A2R10G10B10_SINT_PACK32", + "VK_FORMAT_A2B10G10R10_UNORM_PACK32", + "VK_FORMAT_A2B10G10R10_SNORM_PACK32", + "VK_FORMAT_A2B10G10R10_USCALED_PACK32", + "VK_FORMAT_A2B10G10R10_SSCALED_PACK32", + "VK_FORMAT_A2B10G10R10_UINT_PACK32", + "VK_FORMAT_A2B10G10R10_SINT_PACK32", + "VK_FORMAT_R16_UNORM", + "VK_FORMAT_R16_SNORM", + "VK_FORMAT_R16_USCALED", + "VK_FORMAT_R16_SSCALED", + "VK_FORMAT_R16_UINT", + "VK_FORMAT_R16_SINT", + "VK_FORMAT_R16_SFLOAT", + "VK_FORMAT_R16G16_UNORM", + "VK_FORMAT_R16G16_SNORM", + "VK_FORMAT_R16G16_USCALED", + "VK_FORMAT_R16G16_SSCALED", + "VK_FORMAT_R16G16_UINT", + "VK_FORMAT_R16G16_SINT", + "VK_FORMAT_R16G16_SFLOAT", + "VK_FORMAT_R16G16B16_UNORM", + "VK_FORMAT_R16G16B16_SNORM", + "VK_FORMAT_R16G16B16_USCALED", + "VK_FORMAT_R16G16B16_SSCALED", + "VK_FORMAT_R16G16B16_UINT", + "VK_FORMAT_R16G16B16_SINT", + "VK_FORMAT_R16G16B16_SFLOAT", + "VK_FORMAT_R16G16B16A16_UNORM", + "VK_FORMAT_R16G16B16A16_SNORM", + "VK_FORMAT_R16G16B16A16_USCALED", + "VK_FORMAT_R16G16B16A16_SSCALED", + "VK_FORMAT_R16G16B16A16_UINT", + "VK_FORMAT_R16G16B16A16_SINT", + "VK_FORMAT_R16G16B16A16_SFLOAT", + "VK_FORMAT_R32_UINT", + "VK_FORMAT_R32_SINT", + "VK_FORMAT_R32_SFLOAT", + "VK_FORMAT_R32G32_UINT", + "VK_FORMAT_R32G32_SINT", + "VK_FORMAT_R32G32_SFLOAT", + "VK_FORMAT_R32G32B32_UINT", + "VK_FORMAT_R32G32B32_SINT", + "VK_FORMAT_R32G32B32_SFLOAT", + "VK_FORMAT_R32G32B32A32_UINT", + "VK_FORMAT_R32G32B32A32_SINT", + "VK_FORMAT_R32G32B32A32_SFLOAT", + "VK_FORMAT_R64_UINT", + "VK_FORMAT_R64_SINT", + "VK_FORMAT_R64_SFLOAT", + "VK_FORMAT_R64G64_UINT", + "VK_FORMAT_R64G64_SINT", + "VK_FORMAT_R64G64_SFLOAT", + "VK_FORMAT_R64G64B64_UINT", + "VK_FORMAT_R64G64B64_SINT", + "VK_FORMAT_R64G64B64_SFLOAT", + "VK_FORMAT_R64G64B64A64_UINT", + "VK_FORMAT_R64G64B64A64_SINT", + "VK_FORMAT_R64G64B64A64_SFLOAT", + "VK_FORMAT_B10G11R11_UFLOAT_PACK32", + "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32", + "VK_FORMAT_D16_UNORM", + "VK_FORMAT_X8_D24_UNORM_PACK32", + "VK_FORMAT_D32_SFLOAT", + "VK_FORMAT_S8_UINT", + "VK_FORMAT_D16_UNORM_S8_UINT", + "VK_FORMAT_D24_UNORM_S8_UINT", + "VK_FORMAT_D32_SFLOAT_S8_UINT", + "VK_FORMAT_BC1_RGB_UNORM_BLOCK", + "VK_FORMAT_BC1_RGB_SRGB_BLOCK", + "VK_FORMAT_BC1_RGBA_UNORM_BLOCK", + "VK_FORMAT_BC1_RGBA_SRGB_BLOCK", + "VK_FORMAT_BC2_UNORM_BLOCK", + "VK_FORMAT_BC2_SRGB_BLOCK", + "VK_FORMAT_BC3_UNORM_BLOCK", + "VK_FORMAT_BC3_SRGB_BLOCK", + "VK_FORMAT_BC4_UNORM_BLOCK", + "VK_FORMAT_BC4_SNORM_BLOCK", + "VK_FORMAT_BC5_UNORM_BLOCK", + "VK_FORMAT_BC5_SNORM_BLOCK", + "VK_FORMAT_BC6H_UFLOAT_BLOCK", + "VK_FORMAT_BC6H_SFLOAT_BLOCK", + "VK_FORMAT_BC7_UNORM_BLOCK", + "VK_FORMAT_BC7_SRGB_BLOCK", + "VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK", + "VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK", + "VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK", + "VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK", + "VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK", + "VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK", + "VK_FORMAT_EAC_R11_UNORM_BLOCK", + "VK_FORMAT_EAC_R11_SNORM_BLOCK", + "VK_FORMAT_EAC_R11G11_UNORM_BLOCK", + "VK_FORMAT_EAC_R11G11_SNORM_BLOCK", + "VK_FORMAT_ASTC_4x4_UNORM_BLOCK", + "VK_FORMAT_ASTC_4x4_SRGB_BLOCK", + "VK_FORMAT_ASTC_5x4_UNORM_BLOCK", + "VK_FORMAT_ASTC_5x4_SRGB_BLOCK", + "VK_FORMAT_ASTC_5x5_UNORM_BLOCK", + "VK_FORMAT_ASTC_5x5_SRGB_BLOCK", + "VK_FORMAT_ASTC_6x5_UNORM_BLOCK", + "VK_FORMAT_ASTC_6x5_SRGB_BLOCK", + "VK_FORMAT_ASTC_6x6_UNORM_BLOCK", + "VK_FORMAT_ASTC_6x6_SRGB_BLOCK", + "VK_FORMAT_ASTC_8x5_UNORM_BLOCK", + "VK_FORMAT_ASTC_8x5_SRGB_BLOCK", + "VK_FORMAT_ASTC_8x6_UNORM_BLOCK", + "VK_FORMAT_ASTC_8x6_SRGB_BLOCK", + "VK_FORMAT_ASTC_8x8_UNORM_BLOCK", + "VK_FORMAT_ASTC_8x8_SRGB_BLOCK", + "VK_FORMAT_ASTC_10x5_UNORM_BLOCK", + "VK_FORMAT_ASTC_10x5_SRGB_BLOCK", + "VK_FORMAT_ASTC_10x6_UNORM_BLOCK", + "VK_FORMAT_ASTC_10x6_SRGB_BLOCK", + "VK_FORMAT_ASTC_10x8_UNORM_BLOCK", + "VK_FORMAT_ASTC_10x8_SRGB_BLOCK", + "VK_FORMAT_ASTC_10x10_UNORM_BLOCK", + "VK_FORMAT_ASTC_10x10_SRGB_BLOCK", + "VK_FORMAT_ASTC_12x10_UNORM_BLOCK", + "VK_FORMAT_ASTC_12x10_SRGB_BLOCK", + "VK_FORMAT_ASTC_12x12_UNORM_BLOCK", + "VK_FORMAT_ASTC_12x12_SRGB_BLOCK", + "VK_FORMAT_G8B8G8R8_422_UNORM", + "VK_FORMAT_B8G8R8G8_422_UNORM", + "VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM", + "VK_FORMAT_G8_B8R8_2PLANE_420_UNORM", + "VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM", + "VK_FORMAT_G8_B8R8_2PLANE_422_UNORM", + "VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM", + "VK_FORMAT_R10X6_UNORM_PACK16", + "VK_FORMAT_R10X6G10X6_UNORM_2PACK16", + "VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16", + "VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16", + "VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16", + "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16", + "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16", + "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16", + "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16", + "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16", + "VK_FORMAT_R12X4_UNORM_PACK16", + "VK_FORMAT_R12X4G12X4_UNORM_2PACK16", + "VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16", + "VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16", + "VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16", + "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16", + "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16", + "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16", + "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16", + "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16", + "VK_FORMAT_G16B16G16R16_422_UNORM", + "VK_FORMAT_B16G16R16G16_422_UNORM", + "VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM", + "VK_FORMAT_G16_B16R16_2PLANE_420_UNORM", + "VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM", + "VK_FORMAT_G16_B16R16_2PLANE_422_UNORM", + "VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM", + "VK_FORMAT_G8_B8R8_2PLANE_444_UNORM", + "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16", + "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16", + "VK_FORMAT_G16_B16R16_2PLANE_444_UNORM", + "VK_FORMAT_A4R4G4B4_UNORM_PACK16", + "VK_FORMAT_A4B4G4R4_UNORM_PACK16", + "VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK", + "VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK", + "VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG", + "VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG", + "VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG", + "VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG", + "VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG", + "VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG", + "VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG", + "VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG" + ], + "default": [] + }, + { + "key": "debug_actions", + "label": "Debug Actions", + "description": "This indicates what action is to be taken when a layer wants to report information", + "status": "STABLE", + "type": "FLAGS", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "flags": [ + { + "key": "DEBUG_ACTION_STDOUT_BIT", + "label": "Log to stdout", + "description": "Log messages using the stdout." + }, + { + "key": "DEBUG_ACTION_OUTPUT_BIT", + "label": "Log to OutputDebugString", + "description": "Log messages using the Windows OutputDebugString for Vulkan Studio output display.", + "platforms": [ "WINDOWS" ] + }, + { + "key": "DEBUG_ACTION_FILE_BIT", + "label": "Log to File", + "description": "Log messages to a file.", + "settings": [ + { + "key": "debug_filename", + "label": "Log Filename", + "description": "Specifies the output filename", + "type": "SAVE_FILE", + "default": "profiles_layer_log.txt", + "dependence": { + "mode": "ANY", + "settings": [ + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_OUTPUT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT", "DEBUG_ACTION_OUTPUT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_OUTPUT_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT", "DEBUG_ACTION_OUTPUT_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + } + ] + } + }, + { + "key": "debug_file_clear", + "label": "Clear Log at Launch", + "description": "Discard the content of the log file between each layer run", + "type": "BOOL", + "default": true, + "dependence": { + "mode": "ANY", + "settings": [ + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_OUTPUT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT", "DEBUG_ACTION_OUTPUT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_OUTPUT_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + }, + { + "key": "debug_actions", + "value": [ "DEBUG_ACTION_FILE_BIT", "DEBUG_ACTION_STDOUT_BIT", "DEBUG_ACTION_OUTPUT_BIT", "DEBUG_ACTION_BREAKPOINT_BIT" ] + } + ] + } + } + ], + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "expanded": true + }, + { + "key": "DEBUG_ACTION_BREAKPOINT_BIT", + "label": "Break", + "description": "Trigger a breakpoint if a debugger is in use." + } + ], + "default": [ "DEBUG_ACTION_STDOUT_BIT" ] + }, + { + "key": "debug_fail_on_error", + "label": "Fail on Error", + "description": "If the device doesn't support the capabilities of the selected Profile, the layer fail to load. When enabled, vkEnumeratePhysicalDevices will fail when the selected Profile is not supported.", + "status": "STABLE", + "type": "BOOL", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "default": false + }, + { + "key": "debug_reports", + "label": "Message Types", + "description": "This is a comma-delineated list of options telling the layer what types of messages it should report back", + "status": "STABLE", + "type": "FLAGS", + "platforms": [ "WINDOWS", "LINUX", "MACOS" ], + "flags": [ + { + "key": "DEBUG_REPORT_NOTIFICATION_BIT", + "label": "Notification", + "description": "Report notifications." + }, + { + "key": "DEBUG_REPORT_WARNING_BIT", + "label": "Warning", + "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." + }, + { + "key": "DEBUG_REPORT_ERROR_BIT", + "label": "Error", + "description": "Report errors in API usage." + }, + { + "key": "DEBUG_REPORT_DEBUG_BIT", + "label": "Debug", + "description": "Report debug information for the Profiles Layer development.", + "view": "ADVANCED" + } + ], + "default": [ + "DEBUG_REPORT_NOTIFICATION_BIT", + "DEBUG_REPORT_WARNING_BIT", + "DEBUG_REPORT_ERROR_BIT" + ] + } + ] + } + } +} diff --git a/vkconfig_core/test/sdk/VkLayer_khronos_shader_object.json b/vkconfig_core/test/sdk/VkLayer_khronos_shader_object.json new file mode 100644 index 0000000000..d3b9a2a4f4 --- /dev/null +++ b/vkconfig_core/test/sdk/VkLayer_khronos_shader_object.json @@ -0,0 +1,90 @@ +{ + "file_format_version" : "1.2.0", + "layer": { + "name": "VK_LAYER_KHRONOS_shader_object", + "type": "GLOBAL", + "library_path": ".\\VkLayer_khronos_shader_object.dll", + "api_version": "1.3.283", + "implementation_version": "1", + "description": "Khronos Shader object layer", + "instance_extensions": [ + { + "name": "VK_EXT_layer_settings", + "spec_version": "2" + } + ], + "device_extensions": [ + { + "name": "VK_EXT_shader_object", + "spec_version": "1", + "entrypoints": [ + "vkCmdBindShadersEXT", + "vkCmdBindVertexBuffers2EXT", + "vkCmdSetAlphaToCoverageEnableEXT", + "vkCmdSetAlphaToOneEnableEXT", + "vkCmdSetColorBlendAdvancedEXT", + "vkCmdSetColorBlendEnableEXT", + "vkCmdSetColorBlendEquationEXT", + "vkCmdSetColorWriteMaskEXT", + "vkCmdSetConservativeRasterizationModeEXT", + "vkCmdSetCoverageModulationModeNV", + "vkCmdSetCoverageModulationTableEnableNV", + "vkCmdSetCoverageModulationTableNV", + "vkCmdSetCoverageReductionModeNV", + "vkCmdSetCoverageToColorEnableNV", + "vkCmdSetCoverageToColorLocationNV", + "vkCmdSetCullModeEXT", + "vkCmdSetDepthBiasEnableEXT", + "vkCmdSetDepthBoundsTestEnableEXT", + "vkCmdSetDepthClampEnableEXT", + "vkCmdSetDepthClipEnableEXT", + "vkCmdSetDepthClipNegativeOneToOneEXT", + "vkCmdSetDepthCompareOpEXT", + "vkCmdSetDepthTestEnableEXT", + "vkCmdSetDepthWriteEnableEXT", + "vkCmdSetExtraPrimitiveOverestimationSizeEXT", + "vkCmdSetFrontFaceEXT", + "vkCmdSetLineRasterizationModeEXT", + "vkCmdSetLineStippleEnableEXT", + "vkCmdSetLogicOpEXT", + "vkCmdSetLogicOpEnableEXT", + "vkCmdSetPatchControlPointsEXT", + "vkCmdSetPolygonModeEXT", + "vkCmdSetPrimitiveRestartEnableEXT", + "vkCmdSetPrimitiveTopologyEXT", + "vkCmdSetProvokingVertexModeEXT", + "vkCmdSetRasterizationSamplesEXT", + "vkCmdSetRasterizationStreamEXT", + "vkCmdSetRasterizerDiscardEnableEXT", + "vkCmdSetRepresentativeFragmentTestEnableNV", + "vkCmdSetSampleLocationsEnableEXT", + "vkCmdSetSampleMaskEXT", + "vkCmdSetScissorWithCountEXT", + "vkCmdSetShadingRateImageEnableNV", + "vkCmdSetStencilOpEXT", + "vkCmdSetStencilTestEnableEXT", + "vkCmdSetTessellationDomainOriginEXT", + "vkCmdSetVertexInputEXT", + "vkCmdSetViewportSwizzleNV", + "vkCmdSetViewportWScalingEnableNV", + "vkCmdSetViewportWithCountEXT", + "vkCreateShadersEXT", + "vkDestroyShaderEXT", + "vkGetShaderBinaryDataEXT" + ] + } + ], + "features": { + "settings": [ + { + "key": "force_enable", + "env": "VK_SHADER_OBJECT_FORCE_ENABLE", + "label": "Force Enable", + "description": "Force the layer to be active even if the underlying driver also implements the shader object extension.", + "type": "BOOL", + "default": false + } + ] + } + } +} diff --git a/vkconfig_core/layers/170/VK_LAYER_KHRONOS_synchronization2.json b/vkconfig_core/test/sdk/VkLayer_khronos_synchronization2.json similarity index 52% rename from vkconfig_core/layers/170/VK_LAYER_KHRONOS_synchronization2.json rename to vkconfig_core/test/sdk/VkLayer_khronos_synchronization2.json index a35effffbb..7b3fc1556e 100644 --- a/vkconfig_core/layers/170/VK_LAYER_KHRONOS_synchronization2.json +++ b/vkconfig_core/test/sdk/VkLayer_khronos_synchronization2.json @@ -3,27 +3,43 @@ "layer": { "name": "VK_LAYER_KHRONOS_synchronization2", "type": "GLOBAL", - "library_path": "./libVkLayer_khronos_synchronization2.so", - "api_version": "1.2.170", + "library_path": ".\\VkLayer_khronos_synchronization2.dll", + "api_version": "1.3.283", "implementation_version": "1", "description": "Khronos Synchronization2 layer", "introduction": "The VK_LAYER_KHRONOS_synchronization2 extension layer implements the VK_KHR_synchronization2 extension.", "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/synchronization2_layer.html", + "status": "STABLE", "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], - "status": "BETA", + "instance_extensions": [ + { + "name": "VK_EXT_layer_settings", + "spec_version": "2" + } + ], "device_extensions": [ { "name": "VK_KHR_synchronization2", - "spec_version": 1 + "spec_version": "1", + "entrypoints": [ + "vkCmdSetEvent2KHR", + "vkCmdResetEvent2KHR", + "vkCmdWaitEvents2KHR", + "vkCmdPipelineBarrier2KHR", + "vkCmdWriteTimestamp2KHR", + "vkQueueSubmit2KHR", + "vkCmdWriteBufferMarker2AMD", + "vkGetQueueCheckpointData2NV" + ] } ], "features": { "settings": [ { "key": "force_enable", - "env": "VK_SYNC2_FORCE_ENABLE", + "env": "VK_SYNCHRONIZATION2_FORCE_ENABLE", "label": "Force Enable", - "description": "Force the layer to be active even if the underlying driver already supports the synchonization2 extension.", + "description": "Force the layer to be active even if the underlying driver also implements the synchonization2 extension.", "type": "BOOL", "default": false } diff --git a/vkconfig_core/test/sdk/VkLayer_khronos_validation.json b/vkconfig_core/test/sdk/VkLayer_khronos_validation.json new file mode 100644 index 0000000000..082dacc1ff --- /dev/null +++ b/vkconfig_core/test/sdk/VkLayer_khronos_validation.json @@ -0,0 +1,1694 @@ +{ + "file_format_version": "1.2.0", + "layer": { + "name": "VK_LAYER_KHRONOS_validation", + "type": "GLOBAL", + "library_path": ".\\VkLayer_khronos_validation.dll", + "api_version": "1.3.283", + "implementation_version": "1", + "description": "Khronos Validation Layer", + "introduction": "The main, comprehensive Khronos validation layer.\n\nVulkan is an Explicit API, enabling direct control over how GPUs actually work. By design, minimal error checking is done inside a Vulkan driver. Applications have full control and responsibility for correct operation. Any errors in how Vulkan is used can result in a crash. \n\nThe Khronos Valiation Layer can be enabled to assist development by enabling developers to verify their applications correctly use the Vulkan API.", + "platforms": [ + "WINDOWS", + "LINUX", + "ANDROID", + "MACOS" + ], + "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/khronos_validation_layer.html", + "instance_extensions": [ + { + "name": "VK_EXT_debug_report", + "spec_version": "9" + }, + { + "name": "VK_EXT_debug_utils", + "spec_version": "1" + }, + { + "name": "VK_EXT_layer_settings", + "spec_version": "2" + }, + { + "name": "VK_EXT_validation_features", + "spec_version": "2" + } + ], + "device_extensions": [ + { + "name": "VK_EXT_debug_marker", + "spec_version": "4", + "entrypoints": [ + "vkDebugMarkerSetObjectTagEXT", + "vkDebugMarkerSetObjectNameEXT", + "vkCmdDebugMarkerBeginEXT", + "vkCmdDebugMarkerEndEXT", + "vkCmdDebugMarkerInsertEXT" + ] + }, + { + "name": "VK_EXT_validation_cache", + "spec_version": "1", + "entrypoints": [ + "vkCreateValidationCacheEXT", + "vkDestroyValidationCacheEXT", + "vkGetValidationCacheDataEXT", + "vkMergeValidationCachesEXT" + ] + }, + { + "name": "VK_EXT_tooling_info", + "spec_version": "1", + "entrypoints": [ + "vkGetPhysicalDeviceToolPropertiesEXT" + ] + } + ], + "features": { + "presets": [ + { + "label": "Standard", + "description": "Good default validation setup that balance validation coverage and performance.", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], + "status": "STABLE", + "settings": [ + { + "key": "validate_core", + "value": true + }, + { + "key": "check_image_layout", + "value": true + }, + { + "key": "check_command_buffer", + "value": true + }, + { + "key": "check_object_in_use", + "value": true + }, + { + "key": "check_query", + "value": true + }, + { + "key": "check_shaders", + "value": true + }, + { + "key": "check_shaders_caching", + "value": true + }, + { + "key": "unique_handles", + "value": true + }, + { + "key": "object_lifetime", + "value": true + }, + { + "key": "stateless_param", + "value": true + }, + { + "key": "thread_safety", + "value": false + }, + { + "key": "validate_sync", + "value": false + }, + { + "key": "validate_gpu_based", + "value": "GPU_BASED_NONE" + }, + { + "key": "validate_best_practices", + "value": false + }, + { + "key": "report_flags", + "value": ["error"] + } + ] + }, + { + "label": "Reduced-Overhead", + "description": "Disables some checks in the interest of better performance.", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS" + ], + "status": "STABLE", + "settings": [ + { + "key": "validate_core", + "value": true + }, + { + "key": "check_image_layout", + "value": false + }, + { + "key": "check_command_buffer", + "value": false + }, + { + "key": "check_object_in_use", + "value": false + }, + { + "key": "check_query", + "value": false + }, + { + "key": "check_shaders", + "value": true + }, + { + "key": "check_shaders_caching", + "value": true + }, + { + "key": "unique_handles", + "value": false + }, + { + "key": "object_lifetime", + "value": true + }, + { + "key": "stateless_param", + "value": true + }, + { + "key": "thread_safety", + "value": false + }, + { + "key": "validate_sync", + "value": false + }, + { + "key": "validate_gpu_based", + "value": "GPU_BASED_NONE" + }, + { + "key": "validate_best_practices", + "value": false + }, + { + "key": "report_flags", + "value": ["error"] + } + ] + }, + { + "label": "Best Practices", + "description": "Provides warnings on valid API usage that is potential API misuse.", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], + "status": "STABLE", + "settings": [ + { + "key": "validate_core", + "value": false + }, + { + "key": "check_image_layout", + "value": false + }, + { + "key": "check_command_buffer", + "value": false + }, + { + "key": "check_object_in_use", + "value": false + }, + { + "key": "check_query", + "value": false + }, + { + "key": "check_shaders", + "value": false + }, + { + "key": "check_shaders_caching", + "value": false + }, + { + "key": "unique_handles", + "value": false + }, + { + "key": "object_lifetime", + "value": false + }, + { + "key": "stateless_param", + "value": false + }, + { + "key": "thread_safety", + "value": false + }, + { + "key": "validate_sync", + "value": false + }, + { + "key": "validate_gpu_based", + "value": "GPU_BASED_NONE" + }, + { + "key": "validate_best_practices", + "value": true + }, + { + "key": "report_flags", + "value": ["error", "warn", "perf"] + } + ] + }, + { + "label": "Synchronization", + "description": "Identify resource access conflicts due to missing or incorrect synchronization operations between actions reading or writing the same regions of memory.", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], + "status": "STABLE", + "settings": [ + { + "key": "validate_core", + "value": false + }, + { + "key": "check_image_layout", + "value": false + }, + { + "key": "check_command_buffer", + "value": false + }, + { + "key": "check_object_in_use", + "value": false + }, + { + "key": "check_query", + "value": false + }, + { + "key": "check_shaders", + "value": false + }, + { + "key": "check_shaders_caching", + "value": false + }, + { + "key": "unique_handles", + "value": true + }, + { + "key": "object_lifetime", + "value": false + }, + { + "key": "stateless_param", + "value": false + }, + { + "key": "thread_safety", + "value": true + }, + { + "key": "validate_sync", + "value": true + }, + { + "key": "sync_queue_submit", + "value": true + }, + { + "key": "validate_gpu_based", + "value": "GPU_BASED_NONE" + }, + { + "key": "validate_best_practices", + "value": false + }, + { + "key": "report_flags", + "value": ["error"] + } + ] + }, + { + "label": "GPU-Assisted", + "description": "Check for API usage errors at shader execution time.", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "status": "STABLE", + "settings": [ + { + "key": "validate_core", + "value": false + }, + { + "key": "check_image_layout", + "value": false + }, + { + "key": "check_command_buffer", + "value": false + }, + { + "key": "check_object_in_use", + "value": false + }, + { + "key": "check_query", + "value": false + }, + { + "key": "check_shaders", + "value": false + }, + { + "key": "check_shaders_caching", + "value": false + }, + { + "key": "unique_handles", + "value": false + }, + { + "key": "object_lifetime", + "value": false + }, + { + "key": "stateless_param", + "value": false + }, + { + "key": "thread_safety", + "value": false + }, + { + "key": "validate_sync", + "value": false + }, + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + }, + { + "key": "gpuav_reserve_binding_slot", + "value": true + }, + { + "key": "validate_best_practices", + "value": false + }, + { + "key": "report_flags", + "value": ["error"] + } + ] + }, + { + "label": "Debug Printf", + "description": "Debug shader code by \"printing\" any values of interest to the debug callback or stdout.", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "status": "STABLE", + "settings": [ + { + "key": "validate_core", + "value": false + }, + { + "key": "check_image_layout", + "value": false + }, + { + "key": "check_command_buffer", + "value": false + }, + { + "key": "check_object_in_use", + "value": false + }, + { + "key": "check_query", + "value": false + }, + { + "key": "check_shaders", + "value": false + }, + { + "key": "check_shaders_caching", + "value": false + }, + { + "key": "unique_handles", + "value": false + }, + { + "key": "object_lifetime", + "value": false + }, + { + "key": "stateless_param", + "value": false + }, + { + "key": "thread_safety", + "value": false + }, + { + "key": "validate_sync", + "value": false + }, + { + "key": "validate_gpu_based", + "value": "GPU_BASED_DEBUG_PRINTF" + }, + { + "key": "validate_best_practices", + "value": false + }, + { + "key": "report_flags", + "value": ["error"] + } + ] + } + ], + "settings": [ + { + "key": "validation_control", + "label": "Validation Areas", + "description": "Control of the Validation layer validation", + "type": "GROUP", + "expanded": true, + "settings": [ + { + "key": "fine_grained_locking", + "env": "VK_LAYER_FINE_GRAINED_LOCKING", + "label": "Fine Grained Locking", + "description": "Enable fine grained locking for Core Validation, which should improve performance in multithreaded applications. This setting allows the optimization to be disabled for debugging.", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "validate_core", + "label": "Core", + "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors.", + "type": "BOOL", + "default": true, + "settings": [ + { + "key": "check_image_layout", + "label": "Image Layout", + "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", + "type": "BOOL", + "default": true, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_core", + "value": true + } + ] + } + }, + { + "key": "check_command_buffer", + "label": "Command Buffer State", + "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", + "type": "BOOL", + "default": true, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_core", + "value": true + } + ] + } + }, + { + "key": "check_object_in_use", + "label": "Object in Use", + "description": "Check that Vulkan objects are not in use by a command buffer when they are destroyed.", + "type": "BOOL", + "default": true, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_core", + "value": true + } + ] + } + }, + { + "key": "check_query", + "label": "Query", + "description": "Checks for commands that use VkQueryPool objects.", + "type": "BOOL", + "default": true, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_core", + "value": true + } + ] + } + }, + { + "key": "check_shaders", + "label": "Shader", + "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", + "type": "BOOL", + "default": true, + "expanded": true, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_core", + "value": true + } + ] + }, + "settings": [ + { + "key": "check_shaders_caching", + "label": "Caching", + "description": "Enable caching of shader validation results.", + "type": "BOOL", + "default": true, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_core", + "value": true + }, + { + "key": "check_shaders", + "value": true + } + ] + } + } + ] + } + ] + }, + { + "key": "unique_handles", + "label": "Handle Wrapping", + "description": "Handle wrapping checks. Disable this feature if you are exerience crashes when creating new extensions or developing new Vulkan objects/structures.", + "type": "BOOL", + "default": true, + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "object_lifetime", + "label": "Object Lifetime", + "description": "Object tracking checks. This may not always be necessary late in a development cycle.", + "type": "BOOL", + "default": true, + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "stateless_param", + "label": "Stateless Parameter", + "description": "Stateless parameter checks. This may not always be necessary late in a development cycle.", + "type": "BOOL", + "default": true, + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "thread_safety", + "label": "Thread Safety", + "description": "Thread checks. In order to not degrade performance, it might be best to run your program with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check or when debugging difficult application behaviors.", + "type": "BOOL", + "default": true, + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "validate_sync", + "label": "Synchronization", + "description": "Enable synchronization validation during command buffers recording. This feature reports resource access conflicts due to missing or incorrect synchronization operations between actions (Draw, Copy, Dispatch, Blit) reading or writing the same regions of memory.", + "url": "${LUNARG_SDK}/synchronization_usage.html", + "type": "BOOL", + "default": false, + "expanded": true, + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], + "settings": [ + { + "key": "sync_queue_submit", + "label": "QueueSubmit Synchronization Validation", + "description": "Enable synchronization validation between submitted command buffers when Synchronization Validation is enabled. This option will increase the synchronization performance cost.", + "type": "BOOL", + "default": true, + "status": "STABLE", + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_sync", + "value": true + } + ] + } + } + ] + }, + { + "key": "validate_gpu_based", + "label": "GPU Base", + "description": "Setting an option here will enable specialized areas of validation", + "type": "ENUM", + "default": "GPU_BASED_NONE", + "expanded": true, + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "flags": [ + { + "key": "GPU_BASED_NONE", + "label": "None", + "description": "No GPU-based validation." + }, + { + "key": "GPU_BASED_DEBUG_PRINTF", + "label": "Debug Printf", + "description": "Enables processing of debug printf instructions in shaders and sending debug strings to the debug callback.", + "url": "${LUNARG_SDK}/debug_printf.html", + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "settings": [ + { + "key": "printf_to_stdout", + "label": "Redirect Printf messages to stdout", + "description": "Enable redirection of Debug Printf messages from the debug callback to stdout", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_DEBUG_PRINTF" + } + ] + } + }, + { + "key": "printf_verbose", + "label": "Printf verbose", + "description": "Set the verbosity of debug printf messages", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_DEBUG_PRINTF" + } + ] + } + }, + { + "key": "printf_buffer_size", + "label": "Printf buffer size", + "description": "Set the size in bytes of the buffer used by debug printf", + "type": "INT", + "default": 1024, + "range": { + "min": 128, + "max": 1048576 + }, + "unit": "bytes", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_DEBUG_PRINTF" + } + ] + } + } + ] + }, + { + "key": "GPU_BASED_GPU_ASSISTED", + "label": "GPU-Assisted", + "description": "Check for API usage errors at shader execution time.", + "url": "${LUNARG_SDK}/gpu_validation.html", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "label": "Shader instrumentation", + "description": "Instrument shaders to validate descriptors, descriptor indexing, buffer device addresses and ray queries. Warning: will considerably slow down shader executions.", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + }, + "settings": [ + { + "key": "gpuav_descriptor_checks", + "label": "Descriptors indexing", + "description": "Enable descriptors and buffer out of bounds validation when using descriptor indexing", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "value": true + } + ] + }, + "settings": [ + { + "key": "gpuav_warn_on_robust_oob", + "label": "Generate warning on out of bounds accesses even if buffer robustness is enabled", + "description": "Warn on out of bounds accesses even if robustness is enabled", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "value": true + } + ] + } + } + ] + }, + { + "key": "gpuav_buffer_address_oob", + "label": "Out of bounds buffer device addresses", + "type": "BOOL", + "default": true, + "description": "Check for ", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "value": true + } + ] + }, + "settings": [ + { + "key": "gpuav_max_buffer_device_addresses", + "label": "Maximum number of buffer device addresses in use at one time", + "description": "", + "type": "INT", + "default": 10000, + "range": { + "min": 100, + "max": 10000000 + }, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "value": true + } + ] + } + } + ] + }, + { + "key": "gpuav_validate_ray_query", + "label": "RayQuery SPIR-V Instructions", + "description": "Enable shader instrumentation on OpRayQueryInitializeKHR", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "value": true + } + ] + } + }, + { + "key": "gpuav_cache_instrumented_shaders", + "label": "Cache instrumented shaders rather than instrumenting them on every run", + "description": "Enable instrumented shader caching", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "value": true + } + ] + } + }, + { + "key": "gpuav_select_instrumented_shaders", + "label": "Enable instrumenting shaders selectively", + "description": "Select which shaders to instrument passing a VkValidationFeaturesEXT struct with GPU-AV enabled in the VkShaderModuleCreateInfo pNext", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_shader_instrumentation", + "value": true + } + ] + } + } + ] + }, + { + "key": "gpuav_buffers_validation", + "label": "Buffer content validation", + "description": "Validate buffers containing parameters used in indirect Vulkan commands, or used in copy commands", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + }, + "settings": [ + { + "key": "gpuav_indirect_draws_buffers", + "label": "Indirect draws parameters", + "type": "BOOL", + "default": true, + "description": "Validate buffers containing draw parameters used in indirect draw commands", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_buffers_validation", + "value": true + } + ] + } + }, + { + "key": "indirect_dispatches", + "label": "Indirect dispatches parameters", + "type": "BOOL", + "default": true, + "description": "Validate buffers containing dispatch parameters used in indirect dispatch commands", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_buffers_validation", + "value": true + } + ] + } + }, + { + "key": "indirect_trace_rays", + "label": "Indirect trace rays parameters", + "type": "BOOL", + "default": true, + "description": "Validate buffers containing ray tracing parameters used in indirect ray tracing commands", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_buffers_validation", + "value": true + } + ] + } + }, + { + "key": "gpuav_buffer_copies", + "label": "Buffer copies", + "type": "BOOL", + "default": true, + "description": "Validate copies involving a VkBuffer. Right now only validates copy buffer to image.", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "gpuav_buffers_validation", + "value": true + } + ] + } + } + ] + }, + { + "key": "gpuav_advanced_settings", + "label": "Advanced Settings", + "description": "GPU-AV advanced settings", + "type": "GROUP", + "view": "ADVANCED", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + }, + "settings": [ + { + "key": "gpuav_reserve_binding_slot", + "label": "Reserve Descriptor Set Binding Slot", + "type": "BOOL", + "default": true, + "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + } + }, + { + "key": "gpuav_vma_linear_output", + "label": "Linear Memory Allocation Mode", + "description": "Use VMA linear memory allocations for GPU-AV output buffers instead of finding best place for new allocations among free regions to optimize memory usage. Enabling this setting reduces performance cost but disabling this method minimizes memory usage.", + "type": "BOOL", + "default": true, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + } + } + ] + }, + { + "key": "gpuav_debug_settings", + "label": "Developer Debug Settings", + "description": "GPU-AV debug settings", + "type": "GROUP", + "view": "ADVANCED", + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + }, + "settings": [ + { + "key": "gpuav_debug_validate_instrumented_shaders", + "label": "Validate instrumented shaders", + "description": "Run spirv-val after doing shader instrumentation", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + } + }, + { + "key": "gpuav_debug_dump_instrumented_shaders", + "label": "Dump instrumented shaders", + "description": "Will dump the instrumented shaders (before and after) to working directory", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_gpu_based", + "value": "GPU_BASED_GPU_ASSISTED" + } + ] + } + } + ] + } + ] + } + ] + }, + { + "key": "validate_best_practices", + "label": "Best Practices", + "description": "Outputs warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", + "url": "${LUNARG_SDK}/best_practices.html", + "type": "BOOL", + "default": false, + "expanded": true, + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], + "settings": [ + { + "key": "validate_best_practices_arm", + "label": "ARM-specific best practices", + "description": "Outputs warnings for spec-conforming but non-ideal code on ARM GPUs.", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_best_practices", + "value": true + } + ] + } + }, + { + "key": "validate_best_practices_amd", + "label": "AMD-specific best practices", + "description": "Outputs warnings for spec-conforming but non-ideal code on AMD GPUs.", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_best_practices", + "value": true + } + ] + } + }, + { + "key": "validate_best_practices_img", + "label": "IMG-specific best practices", + "description": "Outputs warnings for spec-conforming but non-ideal code on Imagination GPUs.", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_best_practices", + "value": true + } + ] + } + }, + { + "key": "validate_best_practices_nvidia", + "label": "NVIDIA-specific best practices", + "description": "Outputs warnings for spec-conforming but non-ideal code on NVIDIA GPUs.", + "type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX", + "ANDROID" + ], + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "validate_best_practices", + "value": true + } + ] + } + } + ] + } + ] + }, + { + "key": "debug_action", + "label": "Debug Action", + "description": "Specifies what action is to be taken when a layer reports information", + "type": "FLAGS", + "flags": [ + { + "key": "VK_DBG_LAYER_ACTION_LOG_MSG", + "label": "Log Message", + "description": "Log a txt message to stdout or to a log filename.", + "settings": [ + { + "key": "log_filename", + "label": "Log Filename", + "description": "Specifies the output filename", + "type": "SAVE_FILE", + "default": "stdout", + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "debug_action", + "value": [ + "VK_DBG_LAYER_ACTION_LOG_MSG" + ] + } + ] + } + } + ] + }, + { + "key": "VK_DBG_LAYER_ACTION_CALLBACK", + "label": "Callback", + "description": "Call user defined callback function(s) that have been registered via the VK_EXT_debug_report extension. Since application must register callback, this is a NOOP for the settings file.", + "view": "HIDDEN" + }, + { + "key": "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT", + "label": "Debug Output", + "description": "Log a txt message using the Windows OutputDebugString function.", + "platforms": [ + "WINDOWS" + ] + }, + { + "key": "VK_DBG_LAYER_ACTION_BREAK", + "label": "Break", + "description": "Trigger a breakpoint if a debugger is in use." + } + ], + "default": [ + "VK_DBG_LAYER_ACTION_LOG_MSG" + ] + }, + { + "key": "report_flags", + "label": "Message Severity", + "description": "Comma-delineated list of options specifying the types of messages to be reported", + "type": "FLAGS", + "flags": [ + { + "key": "info", + "label": "Info", + "description": "Report informational messages." + }, + { + "key": "warn", + "label": "Warning", + "description": "Report warnings from using the API in a manner which may lead to undefined behavior or to warn the user of common trouble spots. A warning does NOT necessarily signify illegal application behavior." + }, + { + "key": "perf", + "label": "Performance", + "description": "Report usage of the API that may cause suboptimal performance." + }, + { + "key": "error", + "label": "Error", + "description": "Report errors in API usage." + }, + { + "key": "debug", + "label": "Debug", + "description": "For layer development. Report messages for debugging layer behavior.", + "view": "HIDDEN" + } + ], + "default": [ + "error" + ] + }, + { + "key": "enable_message_limit", + "label": "Limit Duplicated Messages", + "description": "Enable limiting of duplicate messages.", + "type": "BOOL", + "default": true, + "settings": [ + { + "key": "duplicate_message_limit", + "env": "VK_LAYER_DUPLICATE_MESSAGE_LIMIT", + "label": "Max Duplicated Messages", + "description": "Maximum number of times any single validation message should be reported.", + "type": "INT", + "default": 10, + "range": { + "min": 1 + }, + "dependence": { + "mode": "ALL", + "settings": [ + { + "key": "enable_message_limit", + "value": true + } + ] + } + } + ] + }, + { + "key": "message_id_filter", + "label": "Mute Message VUIDs", + "description": "List of VUIDs and VUID identifers which are to be IGNORED by the validation layer", + "type": "LIST", + "env": "VK_LAYER_MESSAGE_ID_FILTER", + "default": [] + }, + { + "key": "message_format", + "label": "Message Format", + "description": "Specifies how error messages are reported", + "type": "GROUP", + "expanded": true, + "settings": [ + { + "key": "message_format_display_application_name", + "label": "Display Application Name", + "description": "Useful when running multiple instances to know which instance the message is from.","type": "BOOL", + "default": false, + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + } + ] + }, + { + "key": "disables", + "label": "Disables", + "description": "Specify areas of validation to be disabled", + "type": "FLAGS", + "env": "VK_LAYER_DISABLES", + "flags": [ + { + "key": "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", + "label": "Thread Safety", + "description": "Thread checks. In order to not degrade performance, it might be best to run your program with thread-checking disabled most of the time, enabling it occasionally for a quick sanity check or when debugging difficult application behaviors." + }, + { + "key": "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", + "label": "Stateless Parameter", + "description": "Stateless parameter checks. This may not always be necessary late in a development cycle." + }, + { + "key": "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", + "label": "Object Lifetime", + "description": "Object tracking checks. This may not always be necessary late in a development cycle." + }, + { + "key": "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", + "label": "Core", + "description": "The main, heavy-duty validation checks. This may be valuable early in the development cycle to reduce validation output while correcting parameter/object usage errors." + }, + { + "key": "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", + "label": "Handle Wrapping", + "description": "Handle wrapping checks. Disable this feature if you are exerience crashes when creating new extensions or developing new Vulkan objects/structures." + }, + { + "key": "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", + "label": "Shader Validation", + "description": "Shader checks. These checks can be CPU intensive during application start up, especially if Shader Validation Caching is also disabled.", + "view": "ADVANCED" + }, + { + "key": "VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", + "label": "Command Buffer State", + "description": "Check that all Vulkan objects used by a command buffer have not been destroyed. These checks can be CPU intensive for some applications.", + "view": "ADVANCED" + }, + { + "key": "VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", + "label": "Image Layout", + "description": "Check that the layout of each image subresource is correct whenever it is used by a command buffer. These checks are very CPU intensive for some applications.", + "view": "ADVANCED" + }, + { + "key": "VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", + "label": "Query", + "description": "Checks for commands that use VkQueryPool objects.", + "view": "ADVANCED" + }, + { + "key": "VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", + "label": "Object in Use", + "description": "Check that Vulkan objects are not in use by a command buffer when they are destroyed.", + "view": "ADVANCED" + }, + { + "key": "VALIDATION_CHECK_DISABLE_SYNCHRONIZATION_VALIDATION_QUEUE_SUBMIT", + "label": "QueueSubmit Synchronization Validation", + "description": "Check synchronization validation between submitted command buffers when Synchronization Validation is enabled.", + "view": "ADVANCED" + }, + { + "key": "VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT", + "label": "Shader Validation Caching", + "description": "Disable caching of shader validation results.", + "view": "ADVANCED" + } + ], + "default": [ + "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT" + ] + }, + { + "key": "enables", + "label": "Enables", + "description": "Setting an option here will enable specialized areas of validation", + "type": "FLAGS", + "env": "VK_LAYER_ENABLES", + "flags": [ + { + "key": "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", + "label": "Synchronization", + "description": "This feature reports resource access conflicts due to missing or incorrect synchronization operations between actions (Draw, Copy, Dispatch, Blit) reading or writing the same regions of memory.", + "url": "${LUNARG_SDK}/synchronization_usage.html", + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT", + "label": "Debug Printf", + "description": "Enables processing of debug printf instructions in shaders and sending debug strings to the debug callback.", + "url": "${LUNARG_SDK}/debug_printf.html", + "status": "STABLE", + "platforms": [ + "WINDOWS", + "LINUX" + ] + }, + { + "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", + "label": "GPU-Assisted", + "description": "Check for API usage errors at shader execution time.", + "url": "${LUNARG_SDK}/gpu_validation.html", + "platforms": [ + "WINDOWS", + "LINUX" + ] + }, + { + "key": "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT", + "label": "Reserve Descriptor Set Binding Slot", + "description": "Specifies that the validation layers reserve a descriptor set binding slot for their own use. The layer reports a value for VkPhysicalDeviceLimits::maxBoundDescriptorSets that is one less than the value reported by the device. If the device supports the binding of only one descriptor set, the validation layer does not perform GPU-assisted validation.", + "platforms": [ + "WINDOWS", + "LINUX" + ] + }, + { + "key": "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", + "label": "Best Practices", + "description": "Activating this feature enables the output of warnings related to common misuse of the API, but which are not explicitly prohibited by the specification.", + "url": "${LUNARG_SDK}/best_practices.html", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM", + "label": "ARM-specific best practices", + "description": "Activating this feature enables the output of warnings related to ARM-specific misuse of the API, but which are not explicitly prohibited by the specification.", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS", + "ANDROID" + ] + }, + { + "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD", + "label": "AMD-specific best practices", + "description": "Adds check for spec-conforming but non-ideal code on AMD GPUs.", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS" + ] + }, + { + "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_IMG", + "label": "IMG-specific best practices", + "description": "Adds check for spec-conforming but non-ideal code on Imagination GPUs.", + "platforms": [ + "WINDOWS", + "LINUX", + "MACOS" + ] + }, + { + "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA", + "label": "NVIDIA-specific best practices", + "description": "Activating this feature enables the output of warnings related to NVIDIA-specific misuse of the API, but which are not explicitly prohibited by the specification.", + "platforms": [ + "WINDOWS", + "LINUX", + "ANDROID" + ] + }, + { + "key": "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ALL", + "label": "Hardware specific best practices", + "description": "Activating this feature enables all vendor specific best practices.", + "platforms": [ + "WINDOWS", + "LINUX", + "ANDROID" + ] + } + ], + "default": [] + } + ] + } + } +} diff --git a/vkconfig_core/layers/170/VK_LAYER_LUNARG_monitor.json b/vkconfig_core/test/sdk/VkLayer_monitor.json similarity index 66% rename from vkconfig_core/layers/170/VK_LAYER_LUNARG_monitor.json rename to vkconfig_core/test/sdk/VkLayer_monitor.json index c5fc7d2b55..f14ed40a5d 100644 --- a/vkconfig_core/layers/170/VK_LAYER_LUNARG_monitor.json +++ b/vkconfig_core/test/sdk/VkLayer_monitor.json @@ -4,12 +4,18 @@ "name": "VK_LAYER_LUNARG_monitor", "type": "GLOBAL", "library_path": ".\\VkLayer_monitor.dll", - "api_version": "1.2.170", + "api_version": "1.3.283", "implementation_version": "1", "description": "Execution Monitoring Layer", - "introduction": "The monitor utility layer prints the real-time frames-per-second value to the application's title bar.", + "introduction": "The monitor utility layer displays the real-time frame rate in frames-per-second in the application's title bar.", "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/monitor_layer.html", "platforms": [ "WINDOWS", "LINUX" ], + "instance_extensions": [ + { + "name": "VK_EXT_layer_settings", + "spec_version": "2" + } + ], "device_extensions": [ { "name": "VK_EXT_tooling_info", diff --git a/vkconfig_core/layers/130/VK_LAYER_LUNARG_screenshot.json b/vkconfig_core/test/sdk/VkLayer_screenshot.json similarity index 71% rename from vkconfig_core/layers/130/VK_LAYER_LUNARG_screenshot.json rename to vkconfig_core/test/sdk/VkLayer_screenshot.json index f51617c810..d5c9d728dd 100644 --- a/vkconfig_core/layers/130/VK_LAYER_LUNARG_screenshot.json +++ b/vkconfig_core/test/sdk/VkLayer_screenshot.json @@ -1,15 +1,21 @@ { - "file_format_version": "1.2.0", + "file_format_version" : "1.2.0", "layer": { "name": "VK_LAYER_LUNARG_screenshot", "type": "GLOBAL", "library_path": ".\\VkLayer_screenshot.dll", - "api_version": "1.1.130", + "api_version": "1.3.283", "implementation_version": "1", "description": "LunarG image capture layer", "introduction": "The screenshot layer records frames to image files.", "url": "https://vulkan.lunarg.com/doc/sdk/latest/windows/screenshot_layer.html", - "platforms": [ "WINDOWS", "LINUX" ], + "platforms": [ "WINDOWS", "LINUX", "MACOS", "ANDROID" ], + "instance_extensions": [ + { + "name": "VK_EXT_layer_settings", + "spec_version": "2" + } + ], "device_extensions": [ { "name": "VK_EXT_tooling_info", @@ -25,7 +31,7 @@ "key": "frames", "env": "VK_SCREENSHOT_FRAMES", "label": "Frames", - "description": "Comma separated list of frames to output as screen shots or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9.", + "description": "Specifies list of frames to output as screenshots. It is specified as a comma-separated list of frames or a range of frames with a start, count, and optional interval separated by a dash. Setting the variable to \"all\" will output every frame. Example: \"5-8-2\" will output frame 5, continue until frame 13, dumping every other frame. Example: \"3,8-2\" will output frames 3, 8, and 9. If it is not set or it set to an empty string, no screenshots are created.", "type": "STRING", "default": "" }, @@ -33,7 +39,7 @@ "key": "dir", "env": "VK_SCREENSHOT_DIR", "label": "Directory", - "description": "This can be set to specify the directory in which to create the screenshot files.", + "description": "Specifies the directory in which to create the screenshot files. If it is not set or is set to an empty string, the files will be created in the current working directory.", "type": "SAVE_FOLDER", "default": "" }, @@ -41,7 +47,7 @@ "key": "format", "env": "VK_SCREENSHOT_FORMAT", "label": "Format", - "description": "This can be set to a color space for the output.", + "description": "Specify a color space for the output. If it is not set, set to null, or set to USE_SWAPCHAIN_COLORSPACE the format will be set to use the same color space as the swapchain object.", "type": "ENUM", "flags": [ { diff --git a/vkconfig_core/test/test_bitfield.cpp b/vkconfig_core/test/test_bitfield.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vkconfig_core/test/test_command_line.cpp b/vkconfig_core/test/test_command_line.cpp index f1a6fe775c..2358c1f75d 100644 --- a/vkconfig_core/test/test_command_line.cpp +++ b/vkconfig_core/test/test_command_line.cpp @@ -21,7 +21,7 @@ #include "../command_line.h" #include "../util.h" -#include "../platform.h" +#include "../type_platform.h" #if VKC_PLATFORM == VKC_PLATFORM_LINUX #pragma GCC diagnostic push @@ -37,7 +37,7 @@ TEST(test_command_line, execute_mode) { static char* argv[] = {"vkconfig"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -49,7 +49,7 @@ TEST(test_command_line, execute_mode) { TEST(test_command_line, usage_mode_help) { static char* argv[] = {"vkconfig", "--help"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -62,7 +62,7 @@ TEST(test_command_line, usage_mode_help) { TEST(test_command_line, usage_mode_h) { static char* argv[] = {"vkconfig", "-h"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -75,7 +75,7 @@ TEST(test_command_line, usage_mode_h) { TEST(test_command_line, usage_mode_version) { static char* argv[] = {"vkconfig", "--version"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -88,7 +88,7 @@ TEST(test_command_line, usage_mode_version) { TEST(test_command_line, usage_mode_invalid) { static char* argv[] = {"vkconfig", "--dfhsjfgasjkgf"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -101,7 +101,7 @@ TEST(test_command_line, usage_mode_invalid) { TEST(test_command_line, usage_mode_layers_missing_argv) { static char* argv[] = {"vkconfig", "layers"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -114,7 +114,7 @@ TEST(test_command_line, usage_mode_layers_missing_argv) { TEST(test_command_line, usage_mode_layers_invalid_argv) { static char* argv[] = {"vkconfig", "layers", "--pouet"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -127,7 +127,7 @@ TEST(test_command_line, usage_mode_layers_invalid_argv) { TEST(test_command_line, usage_mode_layers_list) { static char* argv[] = {"vkconfig", "layers", "--list"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -140,7 +140,7 @@ TEST(test_command_line, usage_mode_layers_list) { TEST(test_command_line, usage_mode_layers_surrender) { static char* argv[] = {"vkconfig", "layers", "--surrender"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -153,7 +153,7 @@ TEST(test_command_line, usage_mode_layers_surrender) { TEST(test_command_line, usage_mode_layers_surrender_invalid) { static char* argv[] = {"vkconfig", "layers", "--surrender", "file.json"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -165,8 +165,8 @@ TEST(test_command_line, usage_mode_layers_surrender_invalid) { } TEST(test_command_line, usage_mode_layers_override) { - static char* argv[] = {"vkconfig", "layers", "--override", ":/Configuration 2.2.2.json"}; - int argc = static_cast(countof(argv)); + static char* argv[] = {"vkconfig", "layers", "--override", ":/test/Configuration 3.0.0.json"}; + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -179,7 +179,7 @@ TEST(test_command_line, usage_mode_layers_override) { TEST(test_command_line, usage_mode_layers_override_invalid) { static char* argv[] = {"vkconfig", "layers", "--override"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); @@ -192,7 +192,7 @@ TEST(test_command_line, usage_mode_layers_override_invalid) { TEST(test_command_line, usage_mode_layers_override_invalid_args) { static char* argv[] = {"vkconfig", "layers", "--override", "bla", "blo"}; - int argc = static_cast(countof(argv)); + int argc = static_cast(std::size(argv)); CommandLine command_line(argc, argv); diff --git a/vkconfig_core/test/test_configuration.cpp b/vkconfig_core/test/test_configuration.cpp index ff9151471e..16e306deed 100644 --- a/vkconfig_core/test/test_configuration.cpp +++ b/vkconfig_core/test/test_configuration.cpp @@ -45,7 +45,7 @@ static bool operator!=(const Configuration& a, const Configuration& b) { return static bool operator==(const Parameter& a, const Parameter& b) { if (a.key != b.key) return false; - if (a.state != b.state) return false; + if (a.control != b.control) return false; if (a.settings.size() != b.settings.size()) return false; @@ -58,21 +58,21 @@ static bool operator==(const Parameter& a, const Parameter& b) { static bool operator!=(const std::vector& a, const std::vector& b) { return !(a == b); } -TEST(test_configuration, load_and_save_v2_2_2) { +TEST(test_configuration, load_and_save) { Configuration configuration_loaded; - const bool load_loaded = configuration_loaded.Load(std::vector(), ":/Configuration 2.2.2.json"); + const bool load_loaded = configuration_loaded.Load(":/test/Configuration 3.0.0.json", std::vector()); EXPECT_TRUE(load_loaded); EXPECT_EQ(1, configuration_loaded.parameters.size()); EXPECT_TRUE(!configuration_loaded.description.empty()); Parameter* parameter = FindByKey(configuration_loaded.parameters, "VK_LAYER_LUNARG_reference_1_2_1"); EXPECT_TRUE(parameter != nullptr); - EXPECT_EQ(LAYER_STATE_OVERRIDDEN, parameter->state); + EXPECT_EQ(LAYER_CONTROL_ON, parameter->control); - configuration_loaded.Save(std::vector(), "test_v2_2_2_layer_1_2_1.json"); + configuration_loaded.Save("test_layer_1_2_1.json"); Configuration configuration_saved; - configuration_saved.Load(std::vector(), "test_v2_2_2_layer_1_2_1.json"); + configuration_saved.Load("test_layer_1_2_1.json", std::vector()); EXPECT_EQ(configuration_loaded, configuration_saved); } diff --git a/vkconfig_core/test/test_configuration_built_in.cpp b/vkconfig_core/test/test_configuration_built_in.cpp index 2f30098db5..ca3d0f7160 100644 --- a/vkconfig_core/test/test_configuration_built_in.cpp +++ b/vkconfig_core/test/test_configuration_built_in.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,13 @@ #include "../configuration.h" #include "../util.h" #include "../layer_manager.h" +#include "../environment.h" #include #include #include -static const std::vector SUPPORTED_CONFIG_FILES = {"_2_2_3", "_2_2_2", "_2_2_1"}; - static bool operator==(const Configuration& a, const Configuration& b) { if (a.key != b.key) return false; @@ -48,7 +47,7 @@ static bool operator!=(const Configuration& a, const Configuration& b) { return static bool operator==(const Parameter& a, const Parameter& b) { if (a.key != b.key) return false; - if (a.state != b.state) return false; + if (a.control != b.control) return false; if (a.settings.size() != b.settings.size()) return false; @@ -62,13 +61,8 @@ static bool operator==(const Parameter& a, const Parameter& b) { static bool operator!=(const std::vector& a, const std::vector& b) { return !(a == b); } struct TestBuilin { - TestBuilin(const char* layers_version, const char* configurations_version) - : paths("", SUPPORTED_CONFIG_FILES), - layers_version(layers_version), - configurations_version(configurations_version), - environment(paths), - layer_manager(environment) { - this->layer_manager.LoadLayersFromPath(format(":/layers/%s", layers_version).c_str()); + TestBuilin() : environment(), layer_manager() { + this->layer_manager.LoadLayersFromPath(":/sdk"); EXPECT_TRUE(!this->layer_manager.selected_layers.empty()); } @@ -78,288 +72,30 @@ struct TestBuilin { Configuration Load(const char* configuration_name) { Configuration configuration_loaded; - const bool result = configuration_loaded.Load( - layer_manager.selected_layers, - format(":/configurations/%s/%s.json", configurations_version.c_str(), configuration_name).c_str()); + const bool result = configuration_loaded.Load(format(":/configurations/%s.json", configuration_name).c_str(), + layer_manager.selected_layers); return result ? configuration_loaded : Configuration(); } Configuration Restore(const Configuration& configuration_loaded) { - const std::string filename = format("test_%s_layers_%s.json", configuration_loaded.key.c_str(), layers_version.c_str()); - const bool saved = configuration_loaded.Save(this->layer_manager.selected_layers, filename.c_str()); + const std::string filename = format("test_%s_layers.json", configuration_loaded.key.c_str()); + const bool saved = configuration_loaded.Save(filename.c_str()); EXPECT_TRUE(saved); Configuration configuration_saved; - EXPECT_TRUE(configuration_saved.Load(this->layer_manager.selected_layers, filename.c_str())); + EXPECT_TRUE(configuration_saved.Load(filename.c_str(), this->layer_manager.selected_layers)); return configuration_saved; } std::string layers_version; std::string configurations_version; - PathManager paths; Environment environment; LayerManager layer_manager; }; -static const char* CONFIGURATION_VERSION = "2.2.2"; - -// Layers 130 - -TEST(test_built_in_load, layers_130_with_configuration) { - TestBuilin test("130", CONFIGURATION_VERSION); - EXPECT_EQ(4, test.layer_manager.selected_layers.size()); - - { - Configuration load_api_dump = test.Load("API dump"); - EXPECT_EQ(1, load_api_dump.Size()); - Configuration save_api_dump = test.Restore(load_api_dump); - EXPECT_EQ(save_api_dump, load_api_dump); - } - - { - Configuration load_frame_capture = test.Load("Frame Capture"); - EXPECT_EQ(1, load_frame_capture.Size()); - Configuration save_frame_capture = test.Restore(load_frame_capture); - EXPECT_EQ(save_frame_capture, load_frame_capture); - } - - { - Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(7, load_portability.Size()); - Configuration save_portability = test.Restore(load_portability); - EXPECT_EQ(save_portability, load_portability); - } - - { - Configuration load_synchronization = test.Load("Synchronization"); - EXPECT_EQ(2, load_synchronization.Size()); - Configuration save_synchronization = test.Restore(load_synchronization); - EXPECT_EQ(save_synchronization, load_synchronization); - } - - { - Configuration load_validation = test.Load("Validation"); - EXPECT_EQ(1, load_validation.Size()); - Configuration save_validation = test.Restore(load_validation); - EXPECT_EQ(save_validation, load_validation); - } -} - -// Layers 135 - -TEST(test_built_in_load, layers_135_with_configuration) { - TestBuilin test("135", CONFIGURATION_VERSION); - EXPECT_EQ(4, test.layer_manager.selected_layers.size()); - - { - Configuration load_api_dump = test.Load("API dump"); - EXPECT_EQ(1, load_api_dump.Size()); - Configuration save_api_dump = test.Restore(load_api_dump); - EXPECT_EQ(save_api_dump, load_api_dump); - } - - { - Configuration load_frame_capture = test.Load("Frame Capture"); - EXPECT_EQ(1, load_frame_capture.Size()); - Configuration save_frame_capture = test.Restore(load_frame_capture); - EXPECT_EQ(save_frame_capture, load_frame_capture); - } - - { - Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(7, load_portability.Size()); - Configuration save_portability = test.Restore(load_portability); - EXPECT_EQ(save_portability, load_portability); - } - - { - Configuration load_synchronization = test.Load("Synchronization"); - EXPECT_EQ(2, load_synchronization.Size()); - Configuration save_synchronization = test.Restore(load_synchronization); - EXPECT_EQ(save_synchronization, load_synchronization); - } - - { - Configuration load_validation = test.Load("Validation"); - EXPECT_EQ(1, load_validation.Size()); - Configuration save_validation = test.Restore(load_validation); - EXPECT_EQ(save_validation, load_validation); - } -} - -// Layers 141 - -TEST(test_built_in_load, layers_141_with_configuration) { - TestBuilin test("141", CONFIGURATION_VERSION); - EXPECT_EQ(5, test.layer_manager.selected_layers.size()); - - { - Configuration load_api_dump = test.Load("API dump"); - EXPECT_EQ(1, load_api_dump.Size()); - Configuration save_api_dump = test.Restore(load_api_dump); - EXPECT_EQ(save_api_dump, load_api_dump); - } - - { - Configuration load_frame_capture = test.Load("Frame Capture"); - EXPECT_EQ(1, load_frame_capture.Size()); - Configuration save_frame_capture = test.Restore(load_frame_capture); - EXPECT_EQ(save_frame_capture, load_frame_capture); - } - - { - Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(7, load_portability.Size()); - Configuration save_portability = test.Restore(load_portability); - EXPECT_EQ(save_portability, load_portability); - } - - { - Configuration load_synchronization = test.Load("Synchronization"); - EXPECT_EQ(2, load_synchronization.Size()); - Configuration save_synchronization = test.Restore(load_synchronization); - EXPECT_EQ(save_synchronization, load_synchronization); - } - - { - Configuration load_validation = test.Load("Validation"); - EXPECT_EQ(1, load_validation.Size()); - Configuration save_validation = test.Restore(load_validation); - EXPECT_EQ(save_validation, load_validation); - } -} - -// Layers 148 - -TEST(test_built_in_load, layers_148_with_configuration) { - TestBuilin test("148", CONFIGURATION_VERSION); - EXPECT_EQ(5, test.layer_manager.selected_layers.size()); - - { - Configuration load_api_dump = test.Load("API dump"); - EXPECT_EQ(1, load_api_dump.Size()); - Configuration save_api_dump = test.Restore(load_api_dump); - EXPECT_EQ(save_api_dump, load_api_dump); - } - - { - Configuration load_frame_capture = test.Load("Frame Capture"); - EXPECT_EQ(1, load_frame_capture.Size()); - Configuration save_frame_capture = test.Restore(load_frame_capture); - EXPECT_EQ(save_frame_capture, load_frame_capture); - } - - { - Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(7, load_portability.Size()); - Configuration save_portability = test.Restore(load_portability); - EXPECT_EQ(save_portability, load_portability); - } - - { - Configuration load_synchronization = test.Load("Synchronization"); - EXPECT_EQ(2, load_synchronization.Size()); - Configuration save_synchronization = test.Restore(load_synchronization); - EXPECT_EQ(save_synchronization, load_synchronization); - } - - { - Configuration load_validation = test.Load("Validation"); - EXPECT_EQ(1, load_validation.Size()); - Configuration save_validation = test.Restore(load_validation); - EXPECT_EQ(save_validation, load_validation); - } -} - -// Layers 154 - -TEST(test_built_in_load, layers_154_with_configuration) { - TestBuilin test("154", CONFIGURATION_VERSION); - EXPECT_EQ(5, test.layer_manager.selected_layers.size()); - - { - Configuration load_api_dump = test.Load("API dump"); - EXPECT_EQ(1, load_api_dump.Size()); - Configuration save_api_dump = test.Restore(load_api_dump); - EXPECT_EQ(save_api_dump, load_api_dump); - } - - { - Configuration load_frame_capture = test.Load("Frame Capture"); - EXPECT_EQ(1, load_frame_capture.Size()); - Configuration save_frame_capture = test.Restore(load_frame_capture); - EXPECT_EQ(save_frame_capture, load_frame_capture); - } - - { - Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(7, load_portability.Size()); - Configuration save_portability = test.Restore(load_portability); - EXPECT_EQ(save_portability, load_portability); - } - - { - Configuration load_synchronization = test.Load("Synchronization"); - EXPECT_EQ(2, load_synchronization.Size()); - Configuration save_synchronization = test.Restore(load_synchronization); - EXPECT_EQ(save_synchronization, load_synchronization); - } - - { - Configuration load_validation = test.Load("Validation"); - EXPECT_EQ(1, load_validation.Size()); - Configuration save_validation = test.Restore(load_validation); - EXPECT_EQ(save_validation, load_validation); - } -} - -// Layers 162 - -TEST(test_built_in_load, layers_162_with_configuration) { - TestBuilin test("162", CONFIGURATION_VERSION); - EXPECT_EQ(5, test.layer_manager.selected_layers.size()); - - { - Configuration load_api_dump = test.Load("API dump"); - EXPECT_EQ(1, load_api_dump.Size()); - Configuration save_api_dump = test.Restore(load_api_dump); - EXPECT_EQ(save_api_dump, load_api_dump); - } - - { - Configuration load_frame_capture = test.Load("Frame Capture"); - EXPECT_EQ(1, load_frame_capture.Size()); - Configuration save_frame_capture = test.Restore(load_frame_capture); - EXPECT_EQ(save_frame_capture, load_frame_capture); - } - - { - Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(7, load_portability.Size()); - Configuration save_portability = test.Restore(load_portability); - EXPECT_EQ(save_portability, load_portability); - } - - { - Configuration load_synchronization = test.Load("Synchronization"); - EXPECT_EQ(2, load_synchronization.Size()); - Configuration save_synchronization = test.Restore(load_synchronization); - EXPECT_EQ(save_synchronization, load_synchronization); - } - - { - Configuration load_validation = test.Load("Validation"); - EXPECT_EQ(1, load_validation.Size()); - Configuration save_validation = test.Restore(load_validation); - EXPECT_EQ(save_validation, load_validation); - } -} - -// Layers 170 - -TEST(test_built_in_load, layers_170_with_configuration) { - TestBuilin test("170", CONFIGURATION_VERSION); - EXPECT_EQ(6, test.layer_manager.selected_layers.size()); +TEST(test_built_in_load, sdk_layers_with_configuration) { + TestBuilin test; + EXPECT_TRUE(test.layer_manager.selected_layers.size() >= 8); { Configuration load_api_dump = test.Load("API dump"); @@ -377,7 +113,7 @@ TEST(test_built_in_load, layers_170_with_configuration) { { Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(7, load_portability.Size()); + EXPECT_EQ(2, load_portability.Size()); Configuration save_portability = test.Restore(load_portability); EXPECT_EQ(save_portability, load_portability); } diff --git a/vkconfig_core/test/test_configuration_manager.cpp b/vkconfig_core/test/test_configuration_manager.cpp index e1f09278f8..58a4fcb9d7 100644 --- a/vkconfig_core/test/test_configuration_manager.cpp +++ b/vkconfig_core/test/test_configuration_manager.cpp @@ -22,30 +22,19 @@ #include -static const std::vector SUPPORTED_CONFIG_FILES = {"_2_2_3", "_2_2_2", "_2_2_1"}; - TEST(test_configuration_manager, create_remove) { - PathManager path_manager("", SUPPORTED_CONFIG_FILES); - Environment environment(path_manager); - environment.Reset(Environment::DEFAULT); - std::vector available_layers; Layer layer; layer.key = "VK_LAYER_KHRONOS_validation"; layer.manifest_path = "VK_LAYER_KHRONOS_validation.dummy_path"; available_layers.push_back(layer); - ConfigurationManager configuration_manager(environment); - - // No active configuration by default - EXPECT_EQ(nullptr, configuration_manager.FindActiveConfiguration()); - EXPECT_EQ(false, configuration_manager.HasActiveConfiguration(available_layers)); + ConfigurationManager configuration_manager; // Create configuration configuration_manager.CreateConfiguration(available_layers, "Configuration A"); configuration_manager.CreateConfiguration(available_layers, "Configuration B"); EXPECT_EQ(2, configuration_manager.available_configurations.size()); - EXPECT_EQ(false, configuration_manager.HasActiveConfiguration(available_layers)); // Create configuration with the same name, updating the name const std::string configuration_duplicate_key = @@ -63,12 +52,8 @@ TEST(test_configuration_manager, create_remove) { // Already deleted configuration_manager.RemoveConfiguration(available_layers, "Configuration A"); EXPECT_EQ(1, configuration_manager.available_configurations.size()); - EXPECT_EQ(false, configuration_manager.HasActiveConfiguration(available_layers)); // Remove configuration configuration_manager.RemoveConfiguration(available_layers, configuration_duplicate_key.c_str()); EXPECT_EQ(true, configuration_manager.Empty()); - EXPECT_EQ(false, configuration_manager.HasActiveConfiguration(available_layers)); - - environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit } diff --git a/vkconfig_core/test/test_environment.cpp b/vkconfig_core/test/test_environment.cpp index 813e6715b7..158153bc28 100644 --- a/vkconfig_core/test/test_environment.cpp +++ b/vkconfig_core/test/test_environment.cpp @@ -19,24 +19,75 @@ * - Christophe Riccio */ -#include "../path_manager.h" #include "../environment.h" +#include "../type_platform.h" #include #include +TEST(test_environment, reset_default_applications_sdk_found) { + Environment environment(Environment::MODE_UNINITIALIZED); + environment.Reset(Environment::DEFAULT); + + const std::vector& applications = environment.GetApplications(); + + std::string result = qgetenv("VULKAN_SDK").toStdString(); + + if (!result.empty()) { + EXPECT_EQ(2, applications.size()); + + // Make sure the variable are not replaced + EXPECT_TRUE(applications[0].executable_path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(applications[0].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(applications[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(applications[1].executable_path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(applications[1].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(applications[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + } + + environment.Reset(Environment::SYSTEM); +} + +TEST(test_environment, reset_default_applications_no_sdk) { + qunsetenv("VULKAN_SDK"); + + Environment environment(Environment::MODE_UNINITIALIZED); + environment.Reset(Environment::DEFAULT); + + const std::vector& applications = environment.GetApplications(); + + EXPECT_EQ(2, applications.size()); + + // Make sure the variable are not replaced + EXPECT_TRUE(applications[0].executable_path.RelativePath().find("vkcube") != std::string::npos); + EXPECT_TRUE(applications[0].options[0].working_folder.RelativePath().find(".") != std::string::npos); + EXPECT_TRUE(applications[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(applications[1].executable_path.RelativePath().find("vkcubepp") != std::string::npos); + EXPECT_TRUE(applications[1].options[0].working_folder.RelativePath().find(".") != std::string::npos); + EXPECT_TRUE(applications[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + + environment.Reset(Environment::SYSTEM); +} + TEST(test_environment, remove_missing_applications) { - PathManager path_manager("", std::vector()); - Environment environment(path_manager); + Environment environment(Environment::MODE_UNINITIALIZED); + + const Path& path_missing = ::Get(Path::HOME) + "my_missing_executable"; + const Path& path_exciting = ::Get(Path::HOME) + "my_exciting_executable"; - QFile file("my_exciting_executable"); + QFile file(path_exciting.AbsolutePath().c_str()); const bool result = file.open(QIODevice::WriteOnly); ASSERT_TRUE(result); std::vector applications; - applications.push_back(Application("missing", "my_missing_executable", "")); - applications.push_back(Application("exciting", "my_exciting_executable", "")); + Application application; + + application.executable_path = path_missing.AbsolutePath(); + applications.push_back(application); + + application.executable_path = path_exciting.AbsolutePath(); + applications.push_back(application); EXPECT_EQ(1, environment.RemoveMissingApplications(applications).size()); } diff --git a/vkconfig_core/test/test_layer.cpp b/vkconfig_core/test/test_layer.cpp index 83bd9a318c..cc61f0e102 100644 --- a/vkconfig_core/test/test_layer.cpp +++ b/vkconfig_core/test/test_layer.cpp @@ -58,12 +58,12 @@ TEST(test_layer, collect_settings) { TEST(test_layer, load_header_overridden) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_test_00.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_00.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); EXPECT_STREQ("VK_LAYER_LUNARG_test_00", layer.key.c_str()); - EXPECT_STREQ(".\\VkLayer_test.dll", layer.binary_path.c_str()); + EXPECT_STREQ(Path(".\\VkLayer_test.dll").RelativePath().c_str(), layer.binary_path.RelativePath().c_str()); EXPECT_EQ(Version(1, 2, 170), layer.api_version); EXPECT_STREQ("Build 76", layer.implementation_version.c_str()); EXPECT_STREQ("test layer", layer.description.c_str()); @@ -76,12 +76,12 @@ TEST(test_layer, load_header_overridden) { TEST(test_layer, load_header_default) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_test_01.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_01.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); EXPECT_STREQ("VK_LAYER_LUNARG_test_01", layer.key.c_str()); - EXPECT_STREQ(".\\VkLayer_test.dll", layer.binary_path.c_str()); + EXPECT_STREQ(Path(".\\VkLayer_test.dll").RelativePath().c_str(), layer.binary_path.RelativePath().c_str()); EXPECT_EQ(Version(1, 2, 170), layer.api_version); EXPECT_STREQ("Build 76", layer.implementation_version.c_str()); EXPECT_STREQ("test layer", layer.description.c_str()); @@ -94,7 +94,7 @@ TEST(test_layer, load_header_default) { TEST(test_layer, load_header_override) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_test_02.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_02.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -106,7 +106,7 @@ TEST(test_layer, load_header_override) { TEST(test_layer, load_setting_interit) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_test_03.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_03.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -128,7 +128,7 @@ TEST(test_layer, load_setting_interit) { TEST(test_layer, load_preset_interit) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_test_04.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_04.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -148,7 +148,7 @@ TEST(test_layer, load_preset_interit) { TEST(test_layer, load_setting_children_interit) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_test_05.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_05.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -170,7 +170,7 @@ TEST(test_layer, load_setting_children_interit) { TEST(test_layer, load_setting_enum_interit) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_test_06.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_06.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -212,12 +212,12 @@ TEST(test_layer, load_setting_enum_interit) { TEST(test_layer, load_1_1_0_header) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_reference_1_1_0.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 1, 0), layer.file_format_version); EXPECT_STREQ("VK_LAYER_LUNARG_reference_1_1_0", layer.key.c_str()); - EXPECT_STREQ(".\\VkLayer_reference.dll", layer.binary_path.c_str()); + EXPECT_STREQ(Path(".\\VkLayer_reference.dll").RelativePath().c_str(), layer.binary_path.RelativePath().c_str()); EXPECT_EQ(Version(1, 2, 162), layer.api_version); EXPECT_STREQ("Build 75", layer.implementation_version.c_str()); EXPECT_STREQ("reference layer", layer.description.c_str()); @@ -230,7 +230,7 @@ TEST(test_layer, load_1_1_0_header) { TEST(test_layer, load_1_2_0_preset_and_setting_type) { Layer layer; - const bool load_loaded = layer.Load(std::vector(), ":/VK_LAYER_LUNARG_reference_1_2_0.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_reference_1_2_0.json", LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); // Preset Enum @@ -277,11 +277,11 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { { const std::size_t index = 2; - const SettingDataFileLoad* setting_only = - static_cast(FindSetting(layer.presets[index].settings, "string_required_only")); + const SettingDataString* setting_only = + static_cast(FindSetting(layer.presets[index].settings, "string_required_only")); ASSERT_TRUE(setting_only); - const SettingDataFileLoad* setting_opt = - static_cast(FindSetting(layer.presets[index].settings, "string_with_optional")); + const SettingDataString* setting_opt = + static_cast(FindSetting(layer.presets[index].settings, "string_with_optional")); ASSERT_TRUE(setting_opt); EXPECT_STREQ("Preset String", layer.presets[index].label.c_str()); @@ -321,8 +321,8 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_STREQ("Description Load File", layer.presets[index].description.c_str()); EXPECT_EQ(PLATFORM_WINDOWS_BIT | PLATFORM_MACOS_BIT, layer.presets[index].platform_flags); EXPECT_EQ(STATUS_DEPRECATED, layer.presets[index].status); - EXPECT_STREQ("./text.log", setting_only->value.c_str()); - EXPECT_STREQ("./text.log", setting_opt->value.c_str()); + EXPECT_STREQ(Path("./text.log").RelativePath().c_str(), setting_only->value.RelativePath().c_str()); + EXPECT_STREQ(Path("./text.log").RelativePath().c_str(), setting_opt->value.RelativePath().c_str()); } // Preset Load Folder @@ -340,8 +340,8 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_STREQ("Description Load Folder", layer.presets[index].description.c_str()); EXPECT_EQ(PLATFORM_WINDOWS_BIT | PLATFORM_MACOS_BIT, layer.presets[index].platform_flags); EXPECT_EQ(STATUS_DEPRECATED, layer.presets[index].status); - EXPECT_STREQ("./text", setting_only->value.c_str()); - EXPECT_STREQ("./text", setting_opt->value.c_str()); + EXPECT_STREQ(Path("./text").RelativePath().c_str(), setting_only->value.RelativePath().c_str()); + EXPECT_STREQ(Path("./text").RelativePath().c_str(), setting_opt->value.RelativePath().c_str()); } // Preset Save File @@ -359,8 +359,8 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_STREQ("Description Save File", layer.presets[index].description.c_str()); EXPECT_EQ(PLATFORM_WINDOWS_BIT | PLATFORM_MACOS_BIT, layer.presets[index].platform_flags); EXPECT_EQ(STATUS_DEPRECATED, layer.presets[index].status); - EXPECT_STREQ("./text.log", setting_only->value.c_str()); - EXPECT_STREQ("./text.log", setting_opt->value.c_str()); + EXPECT_STREQ(Path("./text.log").RelativePath().c_str(), setting_only->value.RelativePath().c_str()); + EXPECT_STREQ(Path("./text.log").RelativePath().c_str(), setting_opt->value.RelativePath().c_str()); } // Preset Save Folder @@ -378,8 +378,8 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_STREQ("Description Save Folder", layer.presets[index].description.c_str()); EXPECT_EQ(PLATFORM_WINDOWS_BIT | PLATFORM_MACOS_BIT, layer.presets[index].platform_flags); EXPECT_EQ(STATUS_DEPRECATED, layer.presets[index].status); - EXPECT_STREQ("./text", setting_only->value.c_str()); - EXPECT_STREQ("./text", setting_opt->value.c_str()); + EXPECT_STREQ(Path("./text").RelativePath().c_str(), setting_only->value.RelativePath().c_str()); + EXPECT_STREQ(Path("./text").RelativePath().c_str(), setting_opt->value.RelativePath().c_str()); } // Preset int @@ -705,7 +705,7 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_EQ(PLATFORM_DESKTOP_BIT, setting_meta->platform_flags); EXPECT_TRUE(setting_meta->filter.empty()); - EXPECT_STREQ("./test.txt", setting_meta->default_value.c_str()); + EXPECT_STREQ(setting_meta->default_value.RelativePath().c_str(), Path("./test.txt").RelativePath().c_str()); } // Load File With Optional @@ -725,7 +725,7 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_EQ(PLATFORM_WINDOWS_BIT | PLATFORM_LINUX_BIT, setting_meta->platform_flags); EXPECT_STREQ("*.txt", setting_meta->filter.c_str()); - EXPECT_STREQ("./test.txt", setting_meta->default_value.c_str()); + EXPECT_STREQ(setting_meta->default_value.RelativePath().c_str(), Path("./test.txt").RelativePath().c_str()); } // Save File Required Only @@ -745,7 +745,7 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_EQ(PLATFORM_DESKTOP_BIT, setting_meta->platform_flags); EXPECT_TRUE(setting_meta->filter.empty()); - EXPECT_STREQ("./test.json", setting_meta->default_value.c_str()); + EXPECT_STREQ(setting_meta->default_value.RelativePath().c_str(), Path("./test.json").RelativePath().c_str()); } // Save File With Optional @@ -765,7 +765,7 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_EQ(PLATFORM_WINDOWS_BIT | PLATFORM_LINUX_BIT, setting_meta->platform_flags); EXPECT_STREQ("*.json", setting_meta->filter.c_str()); - EXPECT_STREQ("./test.json", setting_meta->default_value.c_str()); + EXPECT_STREQ(setting_meta->default_value.RelativePath().c_str(), Path("./test.json").RelativePath().c_str()); } // Save Folder Required Only @@ -784,7 +784,7 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_EQ(SETTING_VIEW_STANDARD, setting_meta->view); EXPECT_EQ(PLATFORM_DESKTOP_BIT, setting_meta->platform_flags); - EXPECT_STREQ("./test", setting_meta->default_value.c_str()); + EXPECT_STREQ(setting_meta->default_value.RelativePath().c_str(), Path("./test").RelativePath().c_str()); } // Save Folder With Optional @@ -803,7 +803,7 @@ TEST(test_layer, load_1_2_0_preset_and_setting_type) { EXPECT_EQ(SETTING_VIEW_ADVANCED, setting_meta->view); EXPECT_EQ(PLATFORM_WINDOWS_BIT | PLATFORM_LINUX_BIT, setting_meta->platform_flags); - EXPECT_STREQ("./test", setting_meta->default_value.c_str()); + EXPECT_STREQ(setting_meta->default_value.RelativePath().c_str(), Path("./test").RelativePath().c_str()); } // Int Required Only diff --git a/vkconfig_core/test/test_layer_built_in.cpp b/vkconfig_core/test/test_layer_built_in.cpp index 4724241d53..3d93f2d3e1 100644 --- a/vkconfig_core/test/test_layer_built_in.cpp +++ b/vkconfig_core/test/test_layer_built_in.cpp @@ -236,7 +236,7 @@ TEST(test_layer_built_in, layer_162_screenshot) { TEST(test_layer_built_in, layer_170_validation) { Layer layer; - EXPECT_TRUE(layer.Load(std::vector(), ":/layers/170/VK_LAYER_KHRONOS_validation.json", LAYER_TYPE_EXPLICIT)); + EXPECT_TRUE(layer.Load(":/layers/170/VK_LAYER_KHRONOS_validation.json", LAYER_TYPE_EXPLICIT)); EXPECT_EQ(12, CountSettings(layer.settings)); EXPECT_EQ(6, layer.presets.size()); EXPECT_TRUE(static_cast(FindSetting(layer.presets[0].settings, "enables"))->value.empty()); @@ -246,7 +246,7 @@ TEST(test_layer_built_in, layer_170_validation) { TEST(test_layer_built_in, layer_170_synchronization2) { Layer layer; - EXPECT_TRUE(layer.Load(std::vector(), ":/layers/170/VK_LAYER_KHRONOS_synchronization2.json", LAYER_TYPE_EXPLICIT)); + EXPECT_TRUE(layer.Load(":/layers/170/VK_LAYER_KHRONOS_synchronization2.json", LAYER_TYPE_EXPLICIT)); EXPECT_EQ(1, CountSettings(layer.settings)); EXPECT_EQ(0, layer.presets.size()); } diff --git a/vkconfig_core/test/test_layer_manager.cpp b/vkconfig_core/test/test_layer_manager.cpp index e80ff8c35a..b81e10f6c0 100644 --- a/vkconfig_core/test/test_layer_manager.cpp +++ b/vkconfig_core/test/test_layer_manager.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,17 +22,77 @@ #include -static const std::vector SUPPORTED_CONFIG_FILES = {"_1_0_0"}; +TEST(test_layer_manager, clear) { + LayerManager layer_manager; + layer_manager.Clear(); -TEST(test_layer_manager, load_only_layer_json) { - PathManager paths("", SUPPORTED_CONFIG_FILES); - Environment environment(paths); - environment.Reset(Environment::DEFAULT); + EXPECT_TRUE(layer_manager.Empty()); + EXPECT_TRUE(layer_manager.Size() == 0); +} + +TEST(test_layer_manager, load_all) { + std::vector user_defined_paths; + user_defined_paths.push_back(":/layers"); + + LayerManager layer_manager(user_defined_paths); + + EXPECT_TRUE(layer_manager.Size() >= 10); + EXPECT_TRUE(!layer_manager.Empty()); + + layer_manager.Clear(); + EXPECT_TRUE(layer_manager.Empty()); +} + +TEST(test_layer_manager, load_dir) { + LayerManager layer_manager; + layer_manager.Clear(); + EXPECT_TRUE(layer_manager.Empty()); + + layer_manager.LoadLayersFromPath(":/layers"); + + EXPECT_TRUE(!layer_manager.Empty()); + EXPECT_EQ(10, layer_manager.Size()); + + EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); + + layer_manager.Clear(); + EXPECT_TRUE(layer_manager.Empty()); +} + +TEST(test_layer_manager, load_file) { + LayerManager layer_manager; + layer_manager.Clear(); + EXPECT_TRUE(layer_manager.Empty()); + + layer_manager.LoadLayersFromPath(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json"); + + EXPECT_TRUE(!layer_manager.Empty()); + EXPECT_EQ(1, layer_manager.Size()); + + EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); + + layer_manager.Clear(); + EXPECT_TRUE(layer_manager.Empty()); +} + +TEST(test_layer_manager, find) { + std::vector user_defined_paths; + user_defined_paths.push_back(":/layers"); + + LayerManager layer_manager(user_defined_paths); + + EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); + EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_test_03") != nullptr); +} - LayerManager layer_manager(environment); - layer_manager.LoadLayersFromPath(":/"); +TEST(test_layer_manager, avoid_duplicate) { + LayerManager layer_manager; + layer_manager.Clear(); + EXPECT_TRUE(layer_manager.Empty()); - EXPECT_EQ(10, layer_manager.selected_layers.size()); + layer_manager.LoadLayersFromPath(":/layers"); + EXPECT_EQ(10, layer_manager.Size()); - environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit + layer_manager.LoadLayersFromPath(":/layers"); + EXPECT_EQ(10, layer_manager.Size()); } diff --git a/vkconfig_core/test/test_override.cpp b/vkconfig_core/test/test_override.cpp index 7f14f7cc38..3437ddf83e 100644 --- a/vkconfig_core/test/test_override.cpp +++ b/vkconfig_core/test/test_override.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2022 Valve Corporation - * Copyright (c) 2020-2022 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,11 @@ * - Christophe Riccio */ -#include "../override.h" +#include "../configurator.h" #include "../environment.h" #include "../layer.h" #include "../layer_manager.h" + #include #include @@ -30,44 +31,83 @@ #include -static const std::vector SUPPORTED_CONFIG_FILES = {"_2_2_3", "_2_2_2", "_2_2_1"}; +/* +TEST(test_override, write_erase_global) { + const std::string LOADER_SETTINGS("/test/loader_settings.json"); + const std::string LAYERS_SETTINGS("/test/layers_settings.txt"); -extern bool WriteLayersOverride(const Environment& environment, const std::vector& available_layers, - const Configuration& configuration, const std::string& layers_path); + Configurator& configurator = Configurator::Get(); + configurator.environment.Reset(Environment::DEFAULT); + configurator.layers.LoadLayersFromPath(":/layers"); -extern bool WriteLayersSettings(const std::vector& available_layers, const Configuration& configuration, - const std::string& settings_path); + Configuration configuration; + const bool load = configuration.Load(configurator.layers.selected_layers, ":/test/Configuration 3.0.0.json"); + EXPECT_TRUE(load); + EXPECT_TRUE(!configuration.parameters.empty()); -extern bool EraseLayersOverride(const std::string& layers_path); + EXPECT_EQ(true, configurator.Override()); -extern bool EraseSettingsOverride(const std::string& settings_path); + QFile file_layers_override_ref((":" + LOADER_SETTINGS).c_str()); + const bool result_layers_override_ref = file_layers_override_ref.open(QIODevice::ReadOnly | QIODevice::Text); + assert(result_layers_override_ref); + QString text_layers_override_ref = file_layers_override_ref.readAll(); + file_layers_override_ref.close(); -TEST(test_override, write_erase_2_2_2) { - const std::string LAYERS("/override_layers_2_2_2_schema_1_2_1.json"); - const std::string SETTINGS("/override_settings_2_2_2_schema_1_2_1.txt"); + QFile file_layers_override_gen(("." + LOADER_SETTINGS).c_str()); + const bool result_layers_override_gen = file_layers_override_gen.open(QIODevice::ReadOnly | QIODevice::Text); + assert(result_layers_override_gen); + QString text_layers_override_gen = file_layers_override_gen.readAll(); + file_layers_override_gen.close(); - PathManager paths("", SUPPORTED_CONFIG_FILES); - Environment env(paths, Version(1, 2, 170)); - env.Reset(Environment::DEFAULT); + EXPECT_STREQ(text_layers_override_ref.toStdString().c_str(), text_layers_override_gen.toStdString().c_str()); - LayerManager layer_manager(env); - layer_manager.LoadLayersFromPath(":/"); + QFile file_settings_override_ref((":" + LAYERS_SETTINGS).c_str()); + const bool result_settings_override_ref = file_settings_override_ref.open(QFile::ReadOnly); + assert(result_settings_override_ref); + QString text_settings_override_ref = file_settings_override_ref.readAll(); + file_settings_override_ref.close(); + + text_settings_override_ref.replace("\r\n", "\n"); // Using UNIX EOL + + QFile file_settings_override_gen(("." + LAYERS_SETTINGS).c_str()); + const bool result_settings_override_gen = file_settings_override_gen.open(QFile::ReadOnly); + assert(result_settings_override_gen); + QString text_settings_override_gen = file_settings_override_gen.readAll(); + file_settings_override_gen.close(); + + text_settings_override_gen.replace("\r\n", "\n"); // Using UNIX EOL + + EXPECT_EQ(text_settings_override_ref.size(), text_settings_override_gen.size()); + EXPECT_STREQ(text_settings_override_ref.toStdString().c_str(), text_settings_override_gen.toStdString().c_str()); + + EXPECT_EQ(true, configurator.Surrender()); + + configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit +} + +TEST(test_override, write_erase_per_application) { + const std::string LOADER_SETTINGS("/loader_settings.json"); + const std::string LAYERS_SETTINGS("/layers_settings.txt"); + + Configurator& configurator = Configurator::Get(); + configurator.environment.Reset(Environment::DEFAULT); + configurator.environment.SetPerApplicationConfig(true); + configurator.layers.LoadLayersFromPath(":/layers"); Configuration configuration; - const bool load = configuration.Load(layer_manager.selected_layers, ":/Configuration 2.2.2.json"); + const bool load = configuration.Load(configurator.layers.selected_layers, ":/test/Configuration 3.0.0.json"); EXPECT_TRUE(load); EXPECT_TRUE(!configuration.parameters.empty()); - EXPECT_EQ(true, WriteLayersOverride(env, layer_manager.selected_layers, configuration, "." + LAYERS)); - EXPECT_EQ(true, WriteLayersSettings(layer_manager.selected_layers, configuration, "." + SETTINGS)); + EXPECT_EQ(true, configurator.Override()); - QFile file_layers_override_ref((":" + LAYERS).c_str()); + QFile file_layers_override_ref((":" + LOADER_SETTINGS).c_str()); const bool result_layers_override_ref = file_layers_override_ref.open(QIODevice::ReadOnly | QIODevice::Text); assert(result_layers_override_ref); QString text_layers_override_ref = file_layers_override_ref.readAll(); file_layers_override_ref.close(); - QFile file_layers_override_gen(("." + LAYERS).c_str()); + QFile file_layers_override_gen(("." + LOADER_SETTINGS).c_str()); const bool result_layers_override_gen = file_layers_override_gen.open(QIODevice::ReadOnly | QIODevice::Text); assert(result_layers_override_gen); QString text_layers_override_gen = file_layers_override_gen.readAll(); @@ -75,7 +115,7 @@ TEST(test_override, write_erase_2_2_2) { EXPECT_STREQ(text_layers_override_ref.toStdString().c_str(), text_layers_override_gen.toStdString().c_str()); - QFile file_settings_override_ref((":" + SETTINGS).c_str()); + QFile file_settings_override_ref((":" + LAYERS_SETTINGS).c_str()); const bool result_settings_override_ref = file_settings_override_ref.open(QFile::ReadOnly); assert(result_settings_override_ref); QString text_settings_override_ref = file_settings_override_ref.readAll(); @@ -83,7 +123,7 @@ TEST(test_override, write_erase_2_2_2) { text_settings_override_ref.replace("\r\n", "\n"); // Using UNIX EOL - QFile file_settings_override_gen(("." + SETTINGS).c_str()); + QFile file_settings_override_gen(("." + LAYERS_SETTINGS).c_str()); const bool result_settings_override_gen = file_settings_override_gen.open(QFile::ReadOnly); assert(result_settings_override_gen); QString text_settings_override_gen = file_settings_override_gen.readAll(); @@ -94,28 +134,24 @@ TEST(test_override, write_erase_2_2_2) { EXPECT_EQ(text_settings_override_ref.size(), text_settings_override_gen.size()); EXPECT_STREQ(text_settings_override_ref.toStdString().c_str(), text_settings_override_gen.toStdString().c_str()); - EXPECT_EQ(true, EraseLayersOverride("." + LAYERS)); - EXPECT_EQ(true, EraseSettingsOverride("." + SETTINGS)); + EXPECT_EQ(true, configurator.Surrender()); - env.Reset(Environment::SYSTEM); // Don't change the system settings on exit + configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit } TEST(test_override, vk_layer_settings_txt) { const char* LAYER = "VK_LAYER_LUNARG_reference_1_2_1"; - PathManager paths("", SUPPORTED_CONFIG_FILES); - Environment env(paths, Version(1, 2, 162)); - env.Reset(Environment::DEFAULT); - - LayerManager layer_manager(env); - layer_manager.LoadLayersFromPath(":/"); + Configurator& configurator = Configurator::Get(); + configurator.environment.Reset(Environment::DEFAULT); + configurator.layers.LoadLayersFromPath(":/layers"); Configuration configuration; - const bool load = configuration.Load(layer_manager.selected_layers, ":/Configuration 2.2.2.json"); + const bool load = configuration.Load(configurator.layers.selected_layers, ":/test/Configuration 3.0.0.json"); EXPECT_TRUE(load); EXPECT_TRUE(!configuration.parameters.empty()); - EXPECT_EQ(true, OverrideConfiguration(env, layer_manager.selected_layers, configuration)); + EXPECT_EQ(true, configurator.Override()); VkuLayerSettingSet layerSettingSet = VK_NULL_HANDLE; vkuCreateLayerSettingSet(LAYER, nullptr, nullptr, nullptr, &layerSettingSet); @@ -248,31 +284,28 @@ TEST(test_override, vk_layer_settings_txt) { vkuGetLayerSettingValues(layerSettingSet, "list_empty", setting_list_empty); EXPECT_EQ(true, setting_list_empty.empty()); - EXPECT_EQ(true, SurrenderConfiguration(env)); + EXPECT_EQ(true, configurator.Surrender()); vkuDestroyLayerSettingSet(layerSettingSet, nullptr); - env.Reset(Environment::SYSTEM); // Don't change the system settings on exit + configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit } TEST(test_override, env_var) { const char* LAYER = "VK_LAYER_LUNARG_reference_1_2_1"; - PathManager paths("", SUPPORTED_CONFIG_FILES); - Environment env(paths, Version(1, 2, 162)); - env.Reset(Environment::DEFAULT); - - LayerManager layer_manager(env); - layer_manager.LoadLayersFromPath(":/"); + Configurator& configurator = Configurator::Get(); + configurator.environment.Reset(Environment::DEFAULT); + configurator.layers.LoadLayersFromPath(":/layers"); Configuration configuration; - const bool load = configuration.Load(layer_manager.selected_layers, ":/Configuration 2.2.2.json"); + const bool load = configuration.Load(configurator.layers.selected_layers, ":/test/Configuration 3.0.0.json"); EXPECT_TRUE(load); EXPECT_TRUE(!configuration.parameters.empty()); qputenv("VK_LAYER_SETTINGS_PATH", "./vk_layer_settings.txt"); - EXPECT_EQ(true, OverrideConfiguration(env, layer_manager.selected_layers, configuration)); + EXPECT_EQ(true, configurator.Override()); VkuLayerSettingSet layerSettingSet = VK_NULL_HANDLE; vkuCreateLayerSettingSet(LAYER, nullptr, nullptr, nullptr, &layerSettingSet); @@ -301,7 +334,8 @@ TEST(test_override, env_var) { vkuDestroyLayerSettingSet(layerSettingSet, nullptr); - EXPECT_EQ(true, SurrenderConfiguration(env)); + EXPECT_EQ(true, configurator.Surrender()); - env.Reset(Environment::SYSTEM); // Don't change the system settings on exit + configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit } +*/ diff --git a/vkconfig_core/test/test_parameter.cpp b/vkconfig_core/test/test_parameter.cpp index 1a9017cacb..0db2cca793 100644 --- a/vkconfig_core/test/test_parameter.cpp +++ b/vkconfig_core/test/test_parameter.cpp @@ -24,7 +24,7 @@ #include "../setting_string.h" #include - +/* inline SettingMetaString* InstantiateString(Layer& layer, const std::string& key) { return static_cast(layer.Instantiate(layer.settings, key, SETTING_STRING)); } @@ -45,9 +45,9 @@ static std::vector GenerateTestLayers() { static std::vector GenerateTestParametersExist() { std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer C1", LAYER_STATE_APPLICATION_CONTROLLED)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer C1", LAYER_CONTROL_AUTO)); return parameters; } @@ -62,76 +62,73 @@ static std::vector GenerateTestParametersImplicitOrdering() { static std::vector GenerateTestParametersMissing() { std::vector parameters; - parameters.push_back(Parameter("Layer E3", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer C1", LAYER_STATE_APPLICATION_CONTROLLED)); + parameters.push_back(Parameter("Layer E3", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer C1", LAYER_CONTROL_AUTO)); return parameters; } static std::vector GenerateTestParametersAll() { std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer E2", LAYER_STATE_APPLICATION_CONTROLLED)); - parameters.push_back(Parameter("Layer E3", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E4", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer E5", LAYER_STATE_APPLICATION_CONTROLLED)); - - parameters.push_back(Parameter("Layer I0", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer I1", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer I2", LAYER_STATE_APPLICATION_CONTROLLED)); - parameters.push_back(Parameter("Layer I3", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer I4", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer I5", LAYER_STATE_APPLICATION_CONTROLLED)); - - parameters.push_back(Parameter("Layer C0", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer C1", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer C2", LAYER_STATE_APPLICATION_CONTROLLED)); - parameters.push_back(Parameter("Layer C3", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer C4", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer C5", LAYER_STATE_APPLICATION_CONTROLLED)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_AUTO)); + parameters.push_back(Parameter("Layer E3", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E4", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer E5", LAYER_CONTROL_AUTO)); + + parameters.push_back(Parameter("Layer I0", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer I1", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer I2", LAYER_CONTROL_AUTO)); + parameters.push_back(Parameter("Layer I3", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer I4", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer I5", LAYER_CONTROL_AUTO)); + + parameters.push_back(Parameter("Layer C0", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer C1", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer C2", LAYER_CONTROL_AUTO)); + parameters.push_back(Parameter("Layer C3", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer C4", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer C5", LAYER_CONTROL_AUTO)); return parameters; } TEST(test_parameter, ordering_no_layers) { std::vector layers; - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_STATE_APPLICATION_CONTROLLED))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_STATE_OVERRIDDEN))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_STATE_EXCLUDED))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_CONTROL_AUTO))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_CONTROL_OFF))); } TEST(test_parameter, ordering_found_custom_layers) { const std::vector& layers = GenerateTestLayers(); - EXPECT_EQ(PARAMETER_RANK_EXPLICIT_AVAILABLE, - GetParameterOrdering(layers, Parameter("Layer C0", LAYER_STATE_APPLICATION_CONTROLLED))); - EXPECT_EQ(PARAMETER_RANK_EXPLICIT_OVERRIDDEN, GetParameterOrdering(layers, Parameter("Layer C1", LAYER_STATE_OVERRIDDEN))); - EXPECT_EQ(PARAMETER_RANK_EXCLUDED, GetParameterOrdering(layers, Parameter("Layer C1", LAYER_STATE_EXCLUDED))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer C3", LAYER_STATE_OVERRIDDEN))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer C4", LAYER_STATE_EXCLUDED))); + EXPECT_EQ(PARAMETER_RANK_EXPLICIT_AVAILABLE, GetParameterOrdering(layers, Parameter("Layer C0", LAYER_CONTROL_AUTO))); + EXPECT_EQ(PARAMETER_RANK_EXPLICIT_OVERRIDDEN, GetParameterOrdering(layers, Parameter("Layer C1", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_EXCLUDED, GetParameterOrdering(layers, Parameter("Layer C1", LAYER_CONTROL_OFF))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer C3", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer C4", LAYER_CONTROL_OFF))); } TEST(test_parameter, ordering_found_explicit_layers) { const std::vector& layers = GenerateTestLayers(); - EXPECT_EQ(PARAMETER_RANK_EXPLICIT_AVAILABLE, - GetParameterOrdering(layers, Parameter("Layer E0", LAYER_STATE_APPLICATION_CONTROLLED))); - EXPECT_EQ(PARAMETER_RANK_EXPLICIT_OVERRIDDEN, GetParameterOrdering(layers, Parameter("Layer E1", LAYER_STATE_OVERRIDDEN))); - EXPECT_EQ(PARAMETER_RANK_EXCLUDED, GetParameterOrdering(layers, Parameter("Layer E1", LAYER_STATE_EXCLUDED))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer E3", LAYER_STATE_OVERRIDDEN))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer E4", LAYER_STATE_EXCLUDED))); + EXPECT_EQ(PARAMETER_RANK_EXPLICIT_AVAILABLE, GetParameterOrdering(layers, Parameter("Layer E0", LAYER_CONTROL_AUTO))); + EXPECT_EQ(PARAMETER_RANK_EXPLICIT_OVERRIDDEN, GetParameterOrdering(layers, Parameter("Layer E1", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_EXCLUDED, GetParameterOrdering(layers, Parameter("Layer E1", LAYER_CONTROL_OFF))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer E3", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer E4", LAYER_CONTROL_OFF))); } TEST(test_parameter, ordering_found_implicit_layers) { const std::vector& layers = GenerateTestLayers(); - EXPECT_EQ(PARAMETER_RANK_IMPLICIT_AVAILABLE, - GetParameterOrdering(layers, Parameter("Layer I0", LAYER_STATE_APPLICATION_CONTROLLED))); - EXPECT_EQ(PARAMETER_RANK_IMPLICIT_OVERRIDDEN, GetParameterOrdering(layers, Parameter("Layer I1", LAYER_STATE_OVERRIDDEN))); - EXPECT_EQ(PARAMETER_RANK_EXCLUDED, GetParameterOrdering(layers, Parameter("Layer I1", LAYER_STATE_EXCLUDED))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer I3", LAYER_STATE_OVERRIDDEN))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer I4", LAYER_STATE_EXCLUDED))); + EXPECT_EQ(PARAMETER_RANK_IMPLICIT_AVAILABLE, GetParameterOrdering(layers, Parameter("Layer I0", LAYER_CONTROL_AUTO))); + EXPECT_EQ(PARAMETER_RANK_IMPLICIT_OVERRIDDEN, GetParameterOrdering(layers, Parameter("Layer I1", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_EXCLUDED, GetParameterOrdering(layers, Parameter("Layer I1", LAYER_CONTROL_OFF))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer I3", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer I4", LAYER_CONTROL_OFF))); } TEST(test_parameter, missing_layers) { @@ -151,15 +148,15 @@ TEST(test_parameter, missing_layers) { TEST(test_parameter, filter) { std::vector parameters_app_controlled = GenerateTestParametersExist(); - FilterParameters(parameters_app_controlled, LAYER_STATE_APPLICATION_CONTROLLED); + FilterParameters(parameters_app_controlled, LAYER_CONTROL_AUTO); EXPECT_EQ(2, parameters_app_controlled.size()); std::vector parameters_overridden = GenerateTestParametersExist(); - FilterParameters(parameters_overridden, LAYER_STATE_OVERRIDDEN); + FilterParameters(parameters_overridden, LAYER_CONTROL_ON); EXPECT_EQ(2, parameters_overridden.size()); std::vector parameters_excluded = GenerateTestParametersExist(); - FilterParameters(parameters_excluded, LAYER_STATE_EXCLUDED); + FilterParameters(parameters_excluded, LAYER_CONTROL_OFF); EXPECT_EQ(2, parameters_excluded.size()); } @@ -350,9 +347,9 @@ TEST(test_parameter, compute_min_api_version_exclude_middle) { layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer E2", LAYER_STATE_APPLICATION_CONTROLLED)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_AUTO)); Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); EXPECT_EQ(Version(1, 2, 148), min_version_A); @@ -368,9 +365,9 @@ TEST(test_parameter, compute_min_api_version_exclude_older) { layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E2", LAYER_STATE_APPLICATION_CONTROLLED)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_AUTO)); Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); EXPECT_EQ(Version(1, 2, 162), min_version_A); @@ -386,9 +383,9 @@ TEST(test_parameter, compute_min_api_version_exclude_newer) { layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_APPLICATION_CONTROLLED)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E2", LAYER_STATE_EXCLUDED)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_AUTO)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_OFF)); Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); EXPECT_EQ(Version(1, 2, 148), min_version_A); @@ -404,9 +401,9 @@ TEST(test_parameter, compute_min_api_version_exclude_all) { layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_EXCLUDED)); - parameters.push_back(Parameter("Layer E2", LAYER_STATE_EXCLUDED)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_OFF)); + parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_OFF)); Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); EXPECT_EQ(Version(1, 2, 170), min_version_A); @@ -418,9 +415,9 @@ TEST(test_parameter, compute_min_api_version_missing_one) { layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_APPLICATION_CONTROLLED)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E2", LAYER_STATE_OVERRIDDEN)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_AUTO)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_ON)); Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); EXPECT_EQ(Version(1, 2, 148), min_version_A); @@ -430,9 +427,9 @@ TEST(test_parameter, compute_min_api_version_missing_all) { std::vector layers; std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_STATE_APPLICATION_CONTROLLED)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E2", LAYER_STATE_OVERRIDDEN)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_AUTO)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_ON)); Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); EXPECT_EQ(Version(1, 2, 170), min_version_A); @@ -455,3 +452,4 @@ TEST(test_parameter, OrderParameter_ImplicitLayer) { EXPECT_STREQ(parameters[2].key.c_str(), "Layer E0"); EXPECT_STREQ(parameters[3].key.c_str(), "Layer I0"); } +*/ diff --git a/vkconfig_core/test/test_path.cpp b/vkconfig_core/test/test_path.cpp index 340be49f30..e18c85cb92 100644 --- a/vkconfig_core/test/test_path.cpp +++ b/vkconfig_core/test/test_path.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ #include "../path.h" #include "../util.h" -#include "../platform.h" +#include "../type_platform.h" #include @@ -28,52 +28,19 @@ #include -// Test that GetPath return the home directory when the stored path is empty -TEST(test_path, get_path) { EXPECT_STRNE(GetPath(BUILTIN_PATH_HOME).c_str(), ""); } - -TEST(test_path, replace_path_home) { - const std::string replaced_path = ReplaceBuiltInVariable("${HOME}/test.txt"); - - EXPECT_TRUE(replaced_path.find("${HOME}") > replaced_path.size()); -} - -TEST(test_path, replace_path_vk_local) { - const std::string replaced_path = ReplaceBuiltInVariable("${VK_LOCAL}/test.txt"); - - EXPECT_TRUE(replaced_path.find("${VK_LOCAL}") > replaced_path.size()); -} - -TEST(test_path, replace_path_vk_appdata) { - const std::string replaced_path = ReplaceBuiltInVariable("${VK_APPDATA}/test.txt"); - - EXPECT_TRUE(replaced_path.find("${VK_APPDATA}") > replaced_path.size()); -} - -TEST(test_path, replace_path_unknown) { - const std::string replaced_path = ReplaceBuiltInVariable("${UNKNOWN}/test.txt"); - - EXPECT_STREQ("${UNKNOWN}/test.txt", replaced_path.c_str()); -} - -TEST(test_path, convert_native_separator_empty) { - const std::string replaced_path = ReplaceBuiltInVariable(""); - - EXPECT_STREQ("", replaced_path.c_str()); -} - TEST(test_path, native_path) { static const char* table[] = { "/vkconfig/test\\path/format/", "/vkconfig/test\\path/format\\", "/vkconfig\\test/path/format/", "/vkconfig\\test/path\\format/", "/vkconfig\\test/path/format", "/vkconfig/test/path/format", "\\vkconfig\\test/path\\format", "/vkconfig/test/path/format/", "\\vkconfig\\test/path\\format\\"}; - for (std::size_t i = 0, n = countof(table); i < n; ++i) { + for (std::size_t i = 0, n = std::size(table); i < n; ++i) { const std::string test_case = table[i]; if (VKC_PLATFORM == VKC_PLATFORM_WINDOWS) { - EXPECT_STREQ("\\vkconfig\\test\\path\\format", ConvertNativeSeparators(test_case).c_str()); + EXPECT_STREQ("\\vkconfig\\test\\path\\format", Path(test_case).RelativePath().c_str()); } else { - EXPECT_STREQ("/vkconfig/test/path/format", ConvertNativeSeparators(test_case).c_str()); + EXPECT_STREQ("/vkconfig/test/path/format", Path(test_case).RelativePath().c_str()); } } } @@ -81,101 +48,279 @@ TEST(test_path, native_path) { TEST(test_path, native_path_with_file) { static const char* table[] = {"/vkconfig/test/path/format/file.txt", "\\vkconfig\\test/path\\format\\file.txt"}; - for (std::size_t i = 0, n = countof(table); i < n; ++i) { + for (std::size_t i = 0, n = std::size(table); i < n; ++i) { const std::string test_case = table[i]; if (VKC_PLATFORM == VKC_PLATFORM_WINDOWS) { - EXPECT_STREQ("\\vkconfig\\test\\path\\format\\file.txt", ConvertNativeSeparators(test_case).c_str()); + EXPECT_STREQ("\\vkconfig\\test\\path\\format\\file.txt", Path(test_case).RelativePath().c_str()); } else { - EXPECT_STREQ("/vkconfig/test/path/format/file.txt", ConvertNativeSeparators(test_case).c_str()); + EXPECT_STREQ("/vkconfig/test/path/format/file.txt", Path(test_case).RelativePath().c_str()); } } } -TEST(test_path, is_portable_filename_valid) { - EXPECT_TRUE(IsPortableFilename("VUlkanConfigurator2")); - EXPECT_TRUE(IsPortableFilename("VUlkanConfigurator2.json")); - EXPECT_TRUE(IsPortableFilename(".VUlkanConfigurator2.json")); +TEST(test_path, path_addition) { + Path pathR("testA/test"); + Path pathA = (Path("testA") += "/") + "test"; + Path pathB = Path("testA") + "/" + "test"; + Path pathC = Path("testA") += "/test"; + + EXPECT_TRUE(pathR == pathA); + EXPECT_TRUE(pathR == pathB); + EXPECT_TRUE(pathR == pathC); + EXPECT_STREQ(pathR.RelativePath().c_str(), pathA.RelativePath().c_str()); + EXPECT_STREQ(pathR.RelativePath().c_str(), pathB.RelativePath().c_str()); + EXPECT_STREQ(pathR.RelativePath().c_str(), pathC.RelativePath().c_str()); + EXPECT_STREQ(pathR.AbsolutePath().c_str(), pathA.AbsolutePath().c_str()); + EXPECT_STREQ(pathR.AbsolutePath().c_str(), pathB.AbsolutePath().c_str()); + EXPECT_STREQ(pathR.AbsolutePath().c_str(), pathC.AbsolutePath().c_str()); } -TEST(test_path, is_portable_filename_invalid) { - EXPECT_TRUE(!IsPortableFilename(".")); - EXPECT_TRUE(!IsPortableFilename("..")); - EXPECT_TRUE(!IsPortableFilename("../gni")); - EXPECT_TRUE(!IsPortableFilename("..gni.json")); - EXPECT_TRUE(!IsPortableFilename("VulkanConfigurator2\\.json")); - EXPECT_TRUE(!IsPortableFilename("VulkanConfigurator*")); - EXPECT_TRUE(!IsPortableFilename("Vulkan:Configurator")); +TEST(test_path, path_operation_clear) { + static const char* table[] = {"/vkconfig/test/path/format/file.txt", "\\vkconfig\\test/path\\format\\file.txt", + "/vkconfig\\test/path/format/", ""}; + + for (std::size_t i = 0, n = std::size(table); i < n; ++i) { + Path test_case = Path(table[i]); + test_case.Clear(); + + EXPECT_TRUE(test_case.Empty()); + } } -TEST(test_path, get_path_local) { - const QString value(::GetPath(BUILTIN_PATH_LOCAL).c_str()); +TEST(test_path, path_operations_valid) { + struct test_case { + std::string path; + bool is_file; + }; + + static const test_case CASES[] = {{"./fileA.pouet", true}, {"./testA/", false}}; + + for (std::size_t i = 0, n = std::size(CASES); i < n; ++i) { + Path test_case = Path(CASES[i].path.c_str()); + EXPECT_FALSE(test_case.Exists()); + EXPECT_TRUE(test_case.Create(CASES[i].is_file)); + EXPECT_TRUE(test_case.Exists()); + EXPECT_EQ(test_case.IsFile(), CASES[i].is_file); + EXPECT_TRUE(test_case.Create(CASES[i].is_file)); + EXPECT_TRUE(test_case.Exists()); + EXPECT_TRUE(test_case.Remove()); + EXPECT_FALSE(test_case.Exists()); + EXPECT_FALSE(test_case.Remove()); + EXPECT_FALSE(test_case.Exists()); + + test_case.Clear(); + EXPECT_TRUE(test_case.Empty()); + } +} + +TEST(test_path, path_operations_invalid) { + Path test_case(""); + EXPECT_TRUE(test_case.Empty()); + EXPECT_FALSE(test_case.Exists()); + EXPECT_FALSE(test_case.Create(true)); + EXPECT_FALSE(test_case.Create(false)); + EXPECT_FALSE(test_case.IsFile()); + EXPECT_FALSE(test_case.IsDir()); + EXPECT_FALSE(test_case.Remove()); +}; + +// Test that GetPath return the home directory when the stored path is empty +TEST(test_path, get_path) { EXPECT_STRNE(Get(Path::HOME).RelativePath().c_str(), ""); } - EXPECT_TRUE(value.endsWith("VulkanSDK")); +TEST(test_path, replace_path_vk_home) { + const std::string replaced_path = Path("${VK_HOME}/test.txt").AbsolutePath(); + + EXPECT_TRUE(replaced_path.find("${VK_HOME}") > replaced_path.size()); +} + +TEST(test_path, replace_path_vk_appdata) { + const std::string replaced_path = Path("${VK_APPDATA}/test.txt").AbsolutePath(); + + EXPECT_TRUE(replaced_path.find("${VK_APPDATA}") > replaced_path.size()); +} + +TEST(test_path, replace_path_unknown) { + const std::string replaced_path = Path("${UNKNOWN}/test.txt").AbsolutePath(); + + // unknown variables are not replaced or modified + EXPECT_TRUE(replaced_path.find("${UNKNOWN}") == 0); +} + +TEST(test_path, convert_to_variable) { + const std::string replaced_path = ::Get(Path::SDK).AbsolutePath(); + + Path recovered_path(replaced_path, true); + + EXPECT_EQ(::Get(Path::SDK), recovered_path); +} + +TEST(test_path, convert_to_variable_postfix) { + const Path base_path(::Get(Path::SDK).AbsolutePath(), true); + const Path reference_path = base_path + "/TestA"; + + const std::string replaced_path = reference_path.AbsolutePath(); + Path recovered_path(replaced_path, true); + + EXPECT_EQ(reference_path, recovered_path); +} + +TEST(test_path, convert_native_separator_empty) { + const std::string replaced_path = Path("").AbsolutePath(); + + EXPECT_STREQ("", replaced_path.c_str()); +} + +TEST(test_path, get_path_home) { + const std::string value_default(AbsolutePath(Path::HOME).c_str()); + + EXPECT_TRUE(EndsWith(value_default, "VulkanSDK")); + + qputenv("VK_HOME", ":/MyVulkanSDKLocalDir"); + + const std::string value_env(AbsolutePath(Path::HOME).c_str()); + + EXPECT_STREQ(Path(":/MyVulkanSDKLocalDir").RelativePath().c_str(), value_env.c_str()); } TEST(test_path, get_path_appdata) { - const QString value(::GetPath(BUILTIN_PATH_APPDATA).c_str()); + const std::string data(AbsolutePath(Path::APPDATA).c_str()); + const std::string home(Path(QDir().homePath().toStdString()).AbsolutePath()); + + EXPECT_TRUE(data.find(home.c_str()) == 0); +} + +TEST(test_path, get_path_init) { + const std::string init(AbsolutePath(Path::INIT).c_str()); + const std::string data(AbsolutePath(Path::APPDATA).c_str()); - EXPECT_TRUE(value.startsWith(::GetPath(BUILTIN_PATH_HOME).c_str())); + EXPECT_TRUE(init.find(data.c_str()) != std::string::npos); + EXPECT_TRUE(init.find("vkconfig.json") != std::string::npos); } TEST(test_path, get_path_config) { - const QString value(::GetPath(BUILTIN_PATH_CONFIG_REF).c_str()); + const QString value(AbsolutePath(Path::CONFIGS).c_str()); - EXPECT_TRUE(value.startsWith(::GetPath(BUILTIN_PATH_APPDATA).c_str())); + EXPECT_TRUE(value.startsWith(AbsolutePath(Path::CONFIGS).c_str())); EXPECT_TRUE(value.endsWith("configurations")); } +TEST(test_path, get_path_layers_settings) { + const std::string value(AbsolutePath(Path::LAYERS_SETTINGS).c_str()); + + EXPECT_TRUE(value.find("vk_layer_settings.txt") != std::string::npos); + EXPECT_TRUE(value.find(AbsolutePath(Path::APPDATA).c_str()) != std::string::npos); +} + +TEST(test_path, get_path_loader_settings) { + const std::string value(AbsolutePath(Path::LOADER_SETTINGS).c_str()); + + EXPECT_TRUE(value.find("vk_loader_settings.json") != std::string::npos); + EXPECT_TRUE(value.find(AbsolutePath(Path::APPDATA).c_str()) != std::string::npos); +} + TEST(test_path, get_path_override_settings) { { - const QString value(::GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS).c_str()); + const QString value(AbsolutePath(Path::LAYERS_SETTINGS).c_str()); EXPECT_TRUE(value.endsWith("vk_layer_settings.txt")); } { qputenv("VK_LAYER_SETTINGS_PATH", "~/VulkanSDK/vk_layer_settings.txt"); - const std::string value = ::GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS); - EXPECT_STREQ(ConvertNativeSeparators("~/VulkanSDK/vk_layer_settings.txt").c_str(), value.c_str()); + const std::string value = AbsolutePath(Path::LAYERS_SETTINGS).c_str(); + EXPECT_STREQ(Path("~/VulkanSDK/vk_layer_settings.txt").AbsolutePath().c_str(), value.c_str()); } { qputenv("VK_LAYER_SETTINGS_PATH", "~/VulkanSDK"); - const std::string value = ::GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS); - EXPECT_STREQ(ConvertNativeSeparators("~/VulkanSDK/vk_layer_settings.txt").c_str(), value.c_str()); + const std::string value = AbsolutePath(Path::LAYERS_SETTINGS).c_str(); + EXPECT_STREQ(Path("~/VulkanSDK/vk_layer_settings.txt").AbsolutePath().c_str(), value.c_str()); } } TEST(test_path, get_path_override_layers) { - const QString value(::GetPath(BUILTIN_PATH_OVERRIDE_LAYERS).c_str()); + const QString value(AbsolutePath(Path::LOADER_SETTINGS).c_str()); - EXPECT_TRUE(value.endsWith("VkLayer_override.json")); + EXPECT_TRUE(value.endsWith("vk_loader_settings.json")); } TEST(test_path, get_path_vulkan_sdk) { - { - qputenv("VULKAN_SDK", ""); - const std::string value = ::GetPath(BUILTIN_PATH_VULKAN_SDK); - EXPECT_TRUE(!value.empty()); - } - { #ifdef __APPLE__ qputenv("VULKAN_SDK", "~/VulkanSDK"); - const std::string value = ::GetPath(BUILTIN_PATH_VULKAN_SDK); - EXPECT_STREQ(ConvertNativeSeparators("~/VulkanSDK/share/vulkan").c_str(), value.c_str()); + const std::string value = AbsolutePath(Path::SDK); + EXPECT_STREQ(Path("~/VulkanSDK/share/vulkan").AbsolutePath().c_str(), value.c_str()); #else qputenv("VULKAN_SDK", "~/VulkanSDK"); - const std::string value = ::GetPath(BUILTIN_PATH_VULKAN_SDK); - EXPECT_STREQ(ConvertNativeSeparators("~/VulkanSDK").c_str(), value.c_str()); + const std::string value = AbsolutePath(Path::SDK); + EXPECT_STREQ(Path("~/VulkanSDK").AbsolutePath().c_str(), value.c_str()); #endif } } TEST(test_path, get_path_vulkan_content) { - const QString value(::GetPath(BUILTIN_PATH_VULKAN_CONTENT).c_str()); + const QString value(AbsolutePath(Path::CONTENT).c_str()); EXPECT_TRUE(!value.isEmpty()); - EXPECT_TRUE(value.startsWith(::GetPath(BUILTIN_PATH_VULKAN_SDK).c_str())); + EXPECT_TRUE(value.startsWith(AbsolutePath(Path::SDK).c_str())); EXPECT_TRUE(value.toLower().endsWith("config")); } + +TEST(test_path, collect_file_paths_success_set1) { + const std::vector& paths = CollectFilePaths(":/configurations/"); + + EXPECT_EQ(paths.size(), 5); + EXPECT_STREQ(Path(":/configurations/API dump.json").AbsolutePath().c_str(), paths[0].AbsolutePath().c_str()); +} + +TEST(test_path, collect_file_paths_success_set2) { + const std::vector& paths = CollectFilePaths(":/layers/"); + + EXPECT_EQ(paths.size(), 10); + EXPECT_STREQ(Path(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json").AbsolutePath().c_str(), paths[0].AbsolutePath().c_str()); +} + +TEST(test_path, collect_file_paths_success_set3) { + const std::vector& paths = CollectFilePaths(":/profiles/"); + + EXPECT_EQ(paths.size(), 4); + EXPECT_STREQ(Path(":/profiles/VP_KHR_roadmap.json").AbsolutePath().c_str(), paths[0].AbsolutePath().c_str()); +} + +TEST(test_path, collect_file_paths_not_found) { + const std::vector& result = CollectFilePaths(":/configurations_not_found/"); + + EXPECT_EQ(result.empty(), true); +} + +TEST(test_path, collect_profiles_from_file) { + const std::vector& result = CollectProfileNamesFromFile(":/profiles/VP_KHR_roadmap.json"); + + EXPECT_EQ(result.size(), 2); + EXPECT_STREQ("VP_KHR_roadmap_2022", result[0].c_str()); + EXPECT_STREQ("VP_KHR_roadmap_2024", result[1].c_str()); +} + +TEST(test_path, collect_profiles_from_dir) { + const std::vector& result = CollectProfileNamesFromDir(":/profiles/"); + + EXPECT_EQ(result.size(), 9); + EXPECT_STREQ("VP_KHR_roadmap_2022", result[0].c_str()); + EXPECT_STREQ("VP_KHR_roadmap_2024", result[1].c_str()); +} + +TEST(test_path, is_portable_filename_valid) { + EXPECT_TRUE(IsPortableFilename("VUlkanConfigurator2")); + EXPECT_TRUE(IsPortableFilename("VUlkanConfigurator2.json")); + EXPECT_TRUE(IsPortableFilename(".VUlkanConfigurator2.json")); +} + +TEST(test_path, is_portable_filename_invalid) { + EXPECT_TRUE(!IsPortableFilename(".")); + EXPECT_TRUE(!IsPortableFilename("..")); + EXPECT_TRUE(!IsPortableFilename("../gni")); + EXPECT_TRUE(!IsPortableFilename("..gni.json")); + EXPECT_TRUE(!IsPortableFilename("VulkanConfigurator2\\.json")); + EXPECT_TRUE(!IsPortableFilename("VulkanConfigurator*")); + EXPECT_TRUE(!IsPortableFilename("Vulkan:Configurator")); +} diff --git a/vkconfig_core/test/test_path_manager.cpp b/vkconfig_core/test/test_path_manager.cpp deleted file mode 100644 index 533b6484bf..0000000000 --- a/vkconfig_core/test/test_path_manager.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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: - * - Christophe Riccio - */ - -#include "../path_manager.h" -#include "../util.h" -#include "../platform.h" - -#include -#include - -#include - -static void Init(PathManager& paths, const std::string& path_value) { - for (int i = 0, n = PATH_COUNT; i < n; ++i) { - const PathType path = static_cast(i); - paths.SetPath(path, path_value); - } -} - -static std::string InitPath(const char* tail) { - const QDir dir(QString("vkconfig/test_path_manager/") + tail); - const std::string native_path(ConvertNativeSeparators(dir.absolutePath().toStdString())); - return native_path; -} - -TEST(test_path_manager, init_first) { - const std::string path_value = InitPath("init_first"); - PathManager paths("", std::vector()); - Init(paths, path_value); - - EXPECT_STREQ(path_value.c_str(), paths.GetPath(PATH_FIRST).c_str()); -} - -TEST(test_path_manager, init_last) { - const std::string path_value = InitPath("init_last"); - PathManager paths("", std::vector()); - Init(paths, path_value); - - EXPECT_STREQ(path_value.c_str(), paths.GetPath(PATH_LAST).c_str()); -} - -TEST(test_path_manager, init_all) { - PathManager paths("", std::vector()); - paths.Clear(); - - for (int i = PATH_FIRST, n = PATH_LAST; i <= n; ++i) { - const PathType path = static_cast(i); - - std::string init_path = InitPath("init_all_%d"); - std::string path_string = format(init_path.c_str(), i); - - paths.SetPath(path, path_string.c_str()); - - EXPECT_STREQ(path_string.c_str(), paths.GetPath(path).c_str()); - } -} - -TEST(test_path_manager, path_format) { - static const char* table[] = { - "/vkconfig/test\\path/format/", "/vkconfig/test\\path/format\\", "/vkconfig\\test/path/format/", - "/vkconfig\\test/path\\format/", "/vkconfig\\test/path/format", "/vkconfig/test/path/format", - "\\vkconfig\\test/path\\format", "/vkconfig/test/path/format/", "\\vkconfig\\test/path\\format\\"}; - - for (std::size_t i = 0, n = countof(table); i < n; ++i) { - PathManager paths("", std::vector()); - paths.Clear(); - paths.SetPath(PATH_EXPORT_CONFIGURATION, QDir::homePath().toStdString() + table[i]); - - const std::string path(paths.GetPath(PATH_EXPORT_CONFIGURATION).c_str()); - const std::string home_path(GetPath(BUILTIN_PATH_HOME).c_str()); - - if (VKC_PLATFORM == VKC_PLATFORM_WINDOWS) { - EXPECT_STREQ((home_path + "\\vkconfig\\test\\path\\format").c_str(), path.c_str()); - } else { - EXPECT_STREQ((home_path + "/vkconfig/test/path/format").c_str(), path.c_str()); - } - } -} - -// Test that export path is used as an alternative to import path when import path is empty -TEST(test_path_manager, empty_import) { - PathManager paths("", std::vector()); - paths.Clear(); - paths.SetPath(PATH_EXPORT_CONFIGURATION, InitPath("empty_import")); - - EXPECT_STRNE(paths.GetPath(PATH_IMPORT_CONFIGURATION).c_str(), GetPath(BUILTIN_PATH_HOME).c_str()); - EXPECT_STREQ(paths.GetPath(PATH_EXPORT_CONFIGURATION).c_str(), paths.GetPath(PATH_IMPORT_CONFIGURATION).c_str()); -} - -// Test that import path is used as an alternative to export path when export path is empty -TEST(test_path_manager, empty_export) { - PathManager paths("", std::vector()); - paths.Clear(); - paths.SetPath(PATH_IMPORT_CONFIGURATION, InitPath("empty_export")); - - EXPECT_STRNE(paths.GetPath(PATH_EXPORT_CONFIGURATION).c_str(), GetPath(BUILTIN_PATH_HOME).c_str()); - EXPECT_STREQ(paths.GetPath(PATH_IMPORT_CONFIGURATION).c_str(), paths.GetPath(PATH_EXPORT_CONFIGURATION).c_str()); - - paths.Load(); -} - -TEST(test_path_manager, check_missing_dir) { - PathManager paths("", std::vector()); - paths.Clear(); - paths.SetPath(PATH_EXPORT_CONFIGURATION, InitPath("check_missing_dir")); - - EXPECT_TRUE(strstr(paths.GetPath(PATH_EXPORT_CONFIGURATION).c_str(), "check_missing_dir") != nullptr); - - paths.Load(); -} - -TEST(test_path_manager, check_default_suffix) { - PathManager paths("", std::vector()); - paths.Clear(); - - const QString string = paths.GetFullPath(PATH_EXPORT_CONFIGURATION, "my_configuration").c_str(); - - EXPECT_TRUE(string.endsWith("my_configuration.json")); - - paths.Load(); -} - -TEST(test_path_manager, check_with_suffix) { - PathManager paths("", std::vector()); - paths.Clear(); - - const QString string = paths.GetFullPath(PATH_EXPORT_CONFIGURATION, "my_configuration.json").c_str(); - - EXPECT_TRUE(string.endsWith("my_configuration.json")); - - paths.Load(); -} diff --git a/vkconfig_core/test/test_setting_type_file_load.cpp b/vkconfig_core/test/test_setting_type_file_load.cpp index 4be7b57005..38b1bf5f9c 100644 --- a/vkconfig_core/test/test_setting_type_file_load.cpp +++ b/vkconfig_core/test/test_setting_type_file_load.cpp @@ -69,6 +69,6 @@ TEST(test_setting_type_file_load, value) { SettingDataFileLoad* data = Instantiate(meta); data->value = "${VULKAN_CONTENT}/value"; - EXPECT_STREQ("${VULKAN_CONTENT}/value", data->Export(EXPORT_MODE_DOC).c_str()); - EXPECT_STRNE("${VULKAN_CONTENT}/value", data->Export(EXPORT_MODE_OVERRIDE).c_str()); + EXPECT_STREQ(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), data->Export(EXPORT_MODE_DOC).c_str()); + EXPECT_STRNE(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), data->Export(EXPORT_MODE_OVERRIDE).c_str()); } diff --git a/vkconfig_core/test/test_setting_type_file_save.cpp b/vkconfig_core/test/test_setting_type_file_save.cpp index 0a489df4a8..417edd34a2 100644 --- a/vkconfig_core/test/test_setting_type_file_save.cpp +++ b/vkconfig_core/test/test_setting_type_file_save.cpp @@ -69,6 +69,6 @@ TEST(test_setting_type_file_save, value) { SettingDataFileSave* data = Instantiate(meta); data->value = "${VULKAN_CONTENT}/value"; - EXPECT_STREQ("${VULKAN_CONTENT}/value", data->Export(EXPORT_MODE_DOC).c_str()); - EXPECT_STRNE("${VULKAN_CONTENT}/value", data->Export(EXPORT_MODE_OVERRIDE).c_str()); + EXPECT_STREQ(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), data->Export(EXPORT_MODE_DOC).c_str()); + EXPECT_STRNE(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), data->Export(EXPORT_MODE_OVERRIDE).c_str()); } diff --git a/vkconfig_core/test/test_setting_type_folder_save.cpp b/vkconfig_core/test/test_setting_type_folder_save.cpp index a37c2c2f8c..3d0d9b6fcb 100644 --- a/vkconfig_core/test/test_setting_type_folder_save.cpp +++ b/vkconfig_core/test/test_setting_type_folder_save.cpp @@ -67,10 +67,10 @@ TEST(test_setting_type_folder_save, value) { SettingMetaFolderSave* meta = InstantiateFolderSave(layer, "key"); meta->default_value = "${VULKAN_CONTENT}/value"; - EXPECT_STREQ("${VULKAN_CONTENT}/value", meta->Export(EXPORT_MODE_DOC).c_str()); - EXPECT_STRNE("${VULKAN_CONTENT}/value", meta->Export(EXPORT_MODE_OVERRIDE).c_str()); + EXPECT_STREQ(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), meta->Export(EXPORT_MODE_DOC).c_str()); + EXPECT_STRNE(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), meta->Export(EXPORT_MODE_OVERRIDE).c_str()); SettingDataFolderSave* data = Instantiate(meta); - EXPECT_STREQ("${VULKAN_CONTENT}/value", data->Export(EXPORT_MODE_DOC).c_str()); - EXPECT_STRNE("${VULKAN_CONTENT}/value", data->Export(EXPORT_MODE_OVERRIDE).c_str()); + EXPECT_STREQ(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), data->Export(EXPORT_MODE_DOC).c_str()); + EXPECT_STRNE(Path("${VULKAN_CONTENT}/value").RelativePath().c_str(), data->Export(EXPORT_MODE_OVERRIDE).c_str()); } diff --git a/vkconfig_core/test/test_setting_type_list.cpp b/vkconfig_core/test/test_setting_type_list.cpp index 72de85b121..2087db2149 100644 --- a/vkconfig_core/test/test_setting_type_list.cpp +++ b/vkconfig_core/test/test_setting_type_list.cpp @@ -101,3 +101,12 @@ TEST(test_setting_type_list, validation_list) { EXPECT_TRUE(!list.empty()); } + +TEST(test_setting_type_list, validation_list_no_sdk) { + qunsetenv("VULKAN_SDK"); + + std::vector list; + LoadVUIDs(list); + + EXPECT_TRUE(!list.empty()); +} diff --git a/vkconfig_core/test/test_type_hide_message.cpp b/vkconfig_core/test/test_type_hide_message.cpp new file mode 100644 index 0000000000..86714af8be --- /dev/null +++ b/vkconfig_core/test/test_type_hide_message.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../type_hide_message.h" + +#include + +static const HideMessageBit HIDE_MESSAGE_NEED_APPLICATION_RESTART_BIT = + static_cast(1 << (HIDE_MESSAGE_NEED_APPLICATION_RESTART - HIDE_MESSAGE_FIRST)); +static const HideMessageBit HIDE_MESSAGE_USE_SYSTEM_TRAY_BIT = + static_cast(1 << (HIDE_MESSAGE_USE_SYSTEM_TRAY - HIDE_MESSAGE_FIRST)); +static const HideMessageBit HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE_BIT = + static_cast(1 << (HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE - HIDE_MESSAGE_FIRST)); + +TEST(test_type_hide_message, convert_specific_values) { + EXPECT_EQ(HIDE_MESSAGE_NEED_APPLICATION_RESTART_BIT, GetBit(HIDE_MESSAGE_NEED_APPLICATION_RESTART)); + EXPECT_EQ(HIDE_MESSAGE_NEED_APPLICATION_RESTART, GetValue(HIDE_MESSAGE_NEED_APPLICATION_RESTART_BIT)); + + EXPECT_EQ(HIDE_MESSAGE_USE_SYSTEM_TRAY_BIT, GetBit(HIDE_MESSAGE_USE_SYSTEM_TRAY)); + EXPECT_EQ(HIDE_MESSAGE_USE_SYSTEM_TRAY, GetValue(HIDE_MESSAGE_USE_SYSTEM_TRAY_BIT)); + + EXPECT_EQ(HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE_BIT, GetBit(HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE)); + EXPECT_EQ(HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE, GetValue(HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE_BIT)); +} + +TEST(test_type_hide_message, convert_invalid_value) { + EXPECT_EQ(0, GetBit(HIDE_MESSAGE_INVALID)); + EXPECT_EQ(HIDE_MESSAGE_INVALID, GetHideMessageType("UNKNOWN_VALUE")); + EXPECT_EQ(nullptr, GetToken(HIDE_MESSAGE_INVALID)); +} + +TEST(test_type_hide_message, convert_type_to_token) { + for (int i = HIDE_MESSAGE_FIRST, n = HIDE_MESSAGE_COUNT; i < n; ++i) { + const HideMessageType value = static_cast(i); + const char* string = GetToken(value); + EXPECT_EQ(value, GetHideMessageType(string)); + } +} + +TEST(test_type_hide_message, convert_bit_to_token) { + for (int i = HIDE_MESSAGE_FIRST, n = HIDE_MESSAGE_COUNT; i < n; ++i) { + const HideMessageBit bit = static_cast(1 << (i - HIDE_MESSAGE_FIRST)); + const char* string = GetToken(bit); + EXPECT_EQ(bit, GetHideMessageBit(string)); + } +} + +TEST(test_type_hide_message, convert_type_to_bit) { + for (int i = HIDE_MESSAGE_FIRST, n = HIDE_MESSAGE_COUNT; i < n; ++i) { + const HideMessageType type = static_cast(i); + const HideMessageBit bit = GetBit(type); + const HideMessageType back = GetValue(bit); + EXPECT_EQ(back, type); + } +} + +TEST(test_type_hide_message, convert_specific_flags) { + const std::vector TOKENS = {"NEED_APPLICATION_RESTART", "WARN_CORE_SHADER_IGNORE"}; + + HideMessageFlags flags = GetHideMessageFlags(TOKENS); + const std::vector& back = GetHideMessageTokens(flags); + + EXPECT_STREQ(TOKENS[0].c_str(), back[0].c_str()); + EXPECT_STREQ(TOKENS[1].c_str(), back[1].c_str()); +} + +TEST(test_type_hide_message, convert_all_flags_split) { + HideMessageFlags flags = 0; + for (int i = HIDE_MESSAGE_FIRST, l = HIDE_MESSAGE_LAST; i <= l; ++i) { + HideMessageType value = static_cast(i); + flags |= GetBit(value); + } + + const std::vector& tokens = GetHideMessageTokens(flags); + EXPECT_EQ(flags, GetHideMessageFlags(tokens)); +} + +TEST(test_type_hide_message, convert_all_flags_merge) { + HideMessageFlags flags = 0; + for (int i = HIDE_MESSAGE_FIRST, l = HIDE_MESSAGE_LAST; i <= l; ++i) { + HideMessageType value = static_cast(i); + flags |= GetBit(value); + } + + const std::string& string = GetHideMessageString(flags); + EXPECT_EQ(flags, GetHideMessageFlags(string)); +} + +TEST(test_type_hide_message, convert_specific_flags_merge) { + const std::string cases[] = {"NEED_APPLICATION_RESTART", "NEED_APPLICATION_RESTART,"}; + + for (std::size_t i = 0, n = std::size(cases); i < n; ++i) { + HideMessageFlags flags = GetHideMessageFlags(cases[i]); + EXPECT_EQ(flags, GetBit(HIDE_MESSAGE_NEED_APPLICATION_RESTART)); + } +} + +TEST(test_type_hide_message, convert_invalid_flags) { + const std::vector TOKENS = {"NEED_APPLICATION_RESTART", "UNKNOWN_VALUE", "WARN_CORE_SHADER_IGNORE"}; + + HideMessageFlags flags = GetHideMessageFlags(TOKENS); + const std::vector& back = GetHideMessageTokens(flags); + + EXPECT_STREQ(TOKENS[0].c_str(), back[0].c_str()); + EXPECT_STREQ(TOKENS[2].c_str(), back[1].c_str()); +} diff --git a/vkconfig_core/test/test_type_layer_control.cpp b/vkconfig_core/test/test_type_layer_control.cpp new file mode 100644 index 0000000000..fa4d930293 --- /dev/null +++ b/vkconfig_core/test/test_type_layer_control.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../type_layer_control.h" + +#include + +TEST(test_layer_control, convert_all) { + for (int i = LAYER_CONTROL_FIRST, n = LAYER_CONTROL_COUNT; i < n; ++i) { + const LayerControl value = static_cast(i); + const char* string = GetToken(value); + EXPECT_EQ(value, GetLayerControl(string)); + } +} diff --git a/vkconfig_core/test/test_type_layer_type.cpp b/vkconfig_core/test/test_type_layer_type.cpp new file mode 100644 index 0000000000..67260367a0 --- /dev/null +++ b/vkconfig_core/test/test_type_layer_type.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../type_layer_type.h" + +#include + +TEST(test_type_layer_type, convert_all) { + for (int i = LAYER_TYPE_FIRST, n = LAYER_TYPE_COUNT; i < n; ++i) { + const LayerType value = static_cast(i); + const char* string = GetToken(value); + EXPECT_EQ(value, GetLayerType(string)); + } +} diff --git a/vkconfig_core/test/test_type_layers_mode.cpp b/vkconfig_core/test/test_type_layers_mode.cpp new file mode 100644 index 0000000000..00e55507f3 --- /dev/null +++ b/vkconfig_core/test/test_type_layers_mode.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../type_layers_mode.h" + +#include + +TEST(test_type_layers_mode, convert_all) { + for (int i = LAYERS_MODE_FIRST, n = LAYERS_MODE_COUNT; i < n; ++i) { + const LayersMode value = static_cast(i); + const char* string = GetToken(value); + EXPECT_EQ(value, GetLayersMode(string)); + } +} diff --git a/vkconfig_core/test/test_type_log.cpp b/vkconfig_core/test/test_type_log.cpp new file mode 100644 index 0000000000..f0204d17f9 --- /dev/null +++ b/vkconfig_core/test/test_type_log.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../type_log.h" + +#include + +static const LogBit LOG_ERROR_BIT = static_cast(1 << (LOG_ERROR - LOG_FIRST)); +static const LogBit LOG_WARN_BIT = static_cast(1 << (LOG_WARN - LOG_FIRST)); +static const LogBit LOG_LAYER_BIT = static_cast(1 << (LOG_LAYER - LOG_FIRST)); + +TEST(test_type_log, convert_specific_values) { + EXPECT_EQ(LOG_ERROR_BIT, GetBit(LOG_ERROR)); + EXPECT_EQ(LOG_ERROR, GetValue(LOG_ERROR_BIT)); + + EXPECT_EQ(LOG_WARN_BIT, GetBit(LOG_WARN)); + EXPECT_EQ(LOG_WARN, GetValue(LOG_WARN_BIT)); + + EXPECT_EQ(LOG_LAYER_BIT, GetBit(LOG_LAYER)); + EXPECT_EQ(LOG_LAYER, GetValue(LOG_LAYER_BIT)); +} + +TEST(test_type_log, convert_invalid_value) { + EXPECT_EQ(0, GetBit(LOG_MESSAGE_INVALID)); + EXPECT_EQ(LOG_MESSAGE_INVALID, GetLogType("unknown")); + EXPECT_EQ(nullptr, GetToken(LOG_MESSAGE_INVALID)); +} + +TEST(test_type_log, convert_type_to_token) { + for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { + const LogType value = static_cast(i); + const char* string = GetToken(value); + EXPECT_EQ(value, GetLogType(string)); + } +} + +TEST(test_type_log, convert_bit_to_token) { + for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { + const LogBit bit = GetBit(static_cast(i)); + const char* string = GetToken(bit); + const LogBit back = GetLogBit(string); + EXPECT_EQ(bit, back); + } +} + +TEST(test_type_log, convert_type_to_bit) { + for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { + const LogType type = static_cast(i); + const LogBit bit = GetBit(type); + const LogType back = GetValue(bit); + EXPECT_EQ(back, type); + } +} + +TEST(test_type_log, convert_specific_flags) { + const std::vector TOKENS = {"error", "layer"}; + + LogFlags flags = GetLogFlags(TOKENS); + const std::vector& back = GetLogTokens(flags); + + EXPECT_STREQ(TOKENS[0].c_str(), back[0].c_str()); + EXPECT_STREQ(TOKENS[1].c_str(), back[1].c_str()); +} + +TEST(test_type_log, convert_all_flags_split) { + LogFlags flags = 0; + for (int i = LOG_FIRST, l = LOG_LAST; i <= l; ++i) { + LogType value = static_cast(i); + flags |= GetBit(value); + } + + const std::vector& tokens = GetLogTokens(flags); + EXPECT_EQ(flags, GetLogFlags(tokens)); +} + +TEST(test_type_log, convert_all_flags_merge) { + LogFlags flags = 0; + for (int i = LOG_FIRST, l = LOG_LAST; i <= l; ++i) { + LogType value = static_cast(i); + flags |= GetBit(value); + } + + const std::string& string = GetLogString(flags); + EXPECT_EQ(flags, GetLogFlags(string)); +} + +TEST(test_type_log, convert_specific_flags_merge) { + const std::string cases[] = {"warn", "warn,"}; + + for (std::size_t i = 0, n = std::size(cases); i < n; ++i) { + LogFlags flags = GetLogFlags(cases[i]); + EXPECT_EQ(flags, GetBit(LOG_WARN)); + } +} + +TEST(test_type_log, convert_invalid_flags) { + const std::vector TOKENS = {"error", "unknown", "layer"}; + + LogFlags flags = GetLogFlags(TOKENS); + const std::vector& back = GetLogTokens(flags); + + EXPECT_STREQ(TOKENS[0].c_str(), back[0].c_str()); + EXPECT_STREQ(TOKENS[2].c_str(), back[1].c_str()); +} diff --git a/vkconfig_core/test/test_platform.cpp b/vkconfig_core/test/test_type_platform.cpp similarity index 93% rename from vkconfig_core/test/test_platform.cpp rename to vkconfig_core/test/test_type_platform.cpp index d0090ae7a6..01a893b7d3 100644 --- a/vkconfig_core/test/test_platform.cpp +++ b/vkconfig_core/test/test_type_platform.cpp @@ -18,7 +18,7 @@ * - Christophe Riccio */ -#include "../platform.h" +#include "../type_platform.h" #include @@ -74,8 +74,3 @@ TEST(test_platform, platform_type_android) { EXPECT_STREQ("ANDROID", GetToken(PLATFORM_ANDROID)); EXPECT_EQ(PLATFORM_ANDROID, GetPlatformType("ANDROID")); } - -TEST(test_platform, status_type) { - EXPECT_STREQ("STABLE", GetToken(STATUS_STABLE)); - EXPECT_EQ(STATUS_STABLE, GetStatusType("STABLE")); -} diff --git a/vkconfig_core/test/test_type_status.cpp b/vkconfig_core/test/test_type_status.cpp new file mode 100644 index 0000000000..06b38ad9df --- /dev/null +++ b/vkconfig_core/test/test_type_status.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../type_status.h" + +#include + +TEST(test_type_status, convert_all) { + for (int i = STATUS_FIRST, n = STATUS_COUNT; i < n; ++i) { + const StatusType value = static_cast(i); + const char* string = GetToken(value); + EXPECT_EQ(value, GetStatusType(string)); + } +} diff --git a/vkconfig_core/test/test_layer_state.cpp b/vkconfig_core/test/test_type_tab.cpp similarity index 64% rename from vkconfig_core/test/test_layer_state.cpp rename to vkconfig_core/test/test_type_tab.cpp index 71788bf359..ef12714b1e 100644 --- a/vkconfig_core/test/test_layer_state.cpp +++ b/vkconfig_core/test/test_type_tab.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,14 @@ * - Christophe Riccio */ -#include "../layer_state.h" +#include "../type_tab.h" #include -TEST(test_layer_state, layer_state) { - EXPECT_STREQ("OVERRIDDEN", GetToken(LAYER_STATE_OVERRIDDEN)); - EXPECT_EQ(LAYER_STATE_OVERRIDDEN, GetLayerState("OVERRIDDEN")); +TEST(test_type_tab_type, convert_all) { + for (int i = TAB_FIRST, n = TAB_COUNT; i < n; ++i) { + const TabType value = static_cast(i); + const char* string = GetToken(value); + EXPECT_EQ(value, GetTabType(string)); + } } diff --git a/vkconfig_core/test/test_util.cpp b/vkconfig_core/test/test_util.cpp index db983541fa..24e6133548 100644 --- a/vkconfig_core/test/test_util.cpp +++ b/vkconfig_core/test/test_util.cpp @@ -19,7 +19,7 @@ */ #include "../util.h" -#include "../platform.h" +#include "../type_platform.h" #include @@ -27,59 +27,6 @@ #include -TEST(test_util, countof_int_2) { - const int test_data[]{8, 9}; - static_assert(countof(test_data) == 2, "countof for 2 ints is broken"); - - EXPECT_EQ(2, countof(test_data)); -} - -TEST(test_util, countof_int_1) { - const int test_data[]{7}; - static_assert(countof(test_data) == 1, "countof for 1 int is broken"); - - EXPECT_EQ(1, countof(test_data)); -} - -TEST(test_util, countof_cstring_3) { - const char* test_data[]{"GNI", "GNA", "GNE"}; - static_assert(countof(test_data) == 3, "countof for cstring is broken"); - - EXPECT_EQ(3, countof(test_data)); -} - -TEST(test_util, countof_string_3) { - const std::string test_data[]{"GNI", "GNA", "GNE"}; - static_assert(countof(test_data) == 3, "countof for string is broken"); - - EXPECT_EQ(3, countof(test_data)); -} - -TEST(test_util, countof_array_2) { - const std::array test_data{6, 7}; - static_assert(countof(test_data) == 2, "countof for array is broken"); - - EXPECT_EQ(2, countof(test_data)); -} - -TEST(test_util, countof_array_3) { - const std::array test_data{"GNI", "GNA", "GNE"}; - - EXPECT_EQ(3, countof(test_data)); -} - -TEST(test_util, countof_vector_2) { - const std::vector test_data{6, 7}; - - EXPECT_EQ(2, countof(test_data)); -} - -TEST(test_util, countof_vector_3) { - const std::vector test_data{"GNI", "GNA", "GNE"}; - - EXPECT_EQ(3, countof(test_data)); -} - TEST(test_util, format_int_1) { EXPECT_EQ("Test 1", format("Test %d", 1)); } TEST(test_util, format_strings_list) { diff --git a/vkconfig_core/test/test_vulkan.cpp b/vkconfig_core/test/test_vulkan.cpp index 5fd5126cbc..1cec145661 100644 --- a/vkconfig_core/test/test_vulkan.cpp +++ b/vkconfig_core/test/test_vulkan.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,4 +18,19 @@ * - Christophe Riccio */ +#include "../vulkan_util.h" + #include + +#ifndef RUN_ON_GITHUB + +TEST(test_vulkan, system_info) { + const VulkanSystemInfo& vulkan_system_info = BuildVulkanSystemInfo(); + + EXPECT_TRUE(vulkan_system_info.loaderVersion != Version::VERSION_NULL); + EXPECT_TRUE(!vulkan_system_info.instanceLayerProperties.empty()); + EXPECT_TRUE(!vulkan_system_info.instanceExtensionPropertie.empty()); + EXPECT_TRUE(!vulkan_system_info.physicalDevices.empty()); +} + +#endif // RUN_ON_GITHUB diff --git a/vkconfig_core/type_hide_message.cpp b/vkconfig_core/type_hide_message.cpp new file mode 100644 index 0000000000..b1eb6153cb --- /dev/null +++ b/vkconfig_core/type_hide_message.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "type_hide_message.h" +#include "bitfield.h" +#include "util.h" + +#include +#include + +const char* GetToken(HideMessageType value) { + static const char* TOKENS[]{ + "NEED_APPLICATION_RESTART", // HIDE_MESSAGE_NEED_APPLICATION_RESTART + "USE_SYSTEM_TRAY", // HIDE_MESSAGE_USE_SYSTEM_TRAY + "WIDGET_SETTING_FLOAT", // HIDE_MESSAGE_WIDGET_SETTING_FLOAT + "WIDGET_SETTING_INT", // HIDE_MESSAGE_WIDGET_SETTING_INT + "WIDGET_SETTING_FRAMES", // HIDE_MESSAGE_WIDGET_SETTING_FRAMES + "WARN_MISSING_LAYERS_IGNORE", // HIDE_MESSAGE_WARN_MISSING_LAYERS_IGNORE + "WARN_CORE_SHADER_IGNORE", // HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE + }; + static_assert(std::size(TOKENS) == HIDE_MESSAGE_COUNT); + + if (value >= HIDE_MESSAGE_FIRST && value <= HIDE_MESSAGE_LAST) { + return TOKENS[value - HIDE_MESSAGE_FIRST]; + } else { + return nullptr; + } +} + +HideMessageType GetHideMessageType(const char* token) { + for (int i = HIDE_MESSAGE_FIRST, l = HIDE_MESSAGE_LAST; i <= l; ++i) { + const HideMessageType value = static_cast(i); + if (std::strcmp(::GetToken(value), token) == 0) { + return value; + } + } + + return HIDE_MESSAGE_INVALID; +} + +const char* GetToken(HideMessageBit bit) { return GetToken(GetValue(bit)); } + +HideMessageBit GetHideMessageBit(const char* token) { + const HideMessageType value = GetHideMessageType(token); + if (value >= HIDE_MESSAGE_FIRST && value <= HIDE_MESSAGE_LAST) { + return static_cast(1 << (value - HIDE_MESSAGE_FIRST)); + } else { + return static_cast(0); + } +} + +HideMessageBit GetBit(HideMessageType value) { + if (value >= HIDE_MESSAGE_FIRST && value <= HIDE_MESSAGE_LAST) { + const int bit = GetBit(value, HIDE_MESSAGE_FIRST); + return static_cast(bit); + } else { + return static_cast(0); + } +} + +HideMessageType GetValue(HideMessageBit bit) { + const HideMessageType value = GetValue(bit, HIDE_MESSAGE_FIRST); + if (value >= HIDE_MESSAGE_FIRST && value <= HIDE_MESSAGE_LAST) { + return value; + } else { + return HIDE_MESSAGE_INVALID; + } +} + +HideMessageFlags GetHideMessageFlags(const std::vector& tokens) { + HideMessageFlags flags = 0; + + for (std::size_t i = 0, n = tokens.size(); i < n; ++i) { + const HideMessageType value = GetHideMessageType(tokens[i].c_str()); + if (value == HIDE_MESSAGE_INVALID) { + continue; + } + flags |= GetBit(value); + } + + return flags; +} + +std::vector GetHideMessageTokens(HideMessageFlags flags) { + std::vector result; + + for (std::size_t i = HIDE_MESSAGE_FIRST, l = HIDE_MESSAGE_LAST; i <= l; ++i) { + HideMessageType value = static_cast(i); + if (flags & GetBit(value)) { + result.push_back(GetToken(value)); + } + } + + return result; +} + +HideMessageFlags GetHideMessageFlags(const std::string& string) { + std::vector tokens = Split(string, ","); + return GetHideMessageFlags(tokens); +} + +std::string GetHideMessageString(HideMessageFlags flags) { + std::vector tokens = GetHideMessageTokens(flags); + return Merge(tokens, ","); +} diff --git a/vkconfig_core/type_hide_message.h b/vkconfig_core/type_hide_message.h new file mode 100644 index 0000000000..da41682a4d --- /dev/null +++ b/vkconfig_core/type_hide_message.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include +#include + +enum HideMessageType { + HIDE_MESSAGE_NEED_APPLICATION_RESTART = 0, + HIDE_MESSAGE_USE_SYSTEM_TRAY, + HIDE_MESSAGE_WIDGET_SETTING_FLOAT, + HIDE_MESSAGE_WIDGET_SETTING_INT, + HIDE_MESSAGE_WIDGET_SETTING_FRAMES, + HIDE_MESSAGE_WARN_MISSING_LAYERS_IGNORE, + HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE, + + HIDE_MESSAGE_FIRST = HIDE_MESSAGE_NEED_APPLICATION_RESTART, + HIDE_MESSAGE_LAST = HIDE_MESSAGE_WARN_CORE_SHADER_IGNORE, + + HIDE_MESSAGE_INVALID = ~0, +}; +enum { HIDE_MESSAGE_COUNT = HIDE_MESSAGE_LAST - HIDE_MESSAGE_FIRST + 1 }; + +enum HideMessageBit {}; +typedef int HideMessageFlags; + +const char* GetToken(HideMessageType value); + +HideMessageType GetHideMessageType(const char* token); + +const char* GetToken(HideMessageBit bit); + +HideMessageBit GetHideMessageBit(const char* token); + +HideMessageBit GetBit(HideMessageType type); + +HideMessageType GetValue(HideMessageBit bit); + +HideMessageFlags GetHideMessageFlags(const std::vector& tokens); + +std::vector GetHideMessageTokens(HideMessageFlags flags); + +HideMessageFlags GetHideMessageFlags(const std::string& string); + +std::string GetHideMessageString(HideMessageFlags flags); diff --git a/vkconfig_core/type_layer_control.cpp b/vkconfig_core/type_layer_control.cpp new file mode 100644 index 0000000000..1753655894 --- /dev/null +++ b/vkconfig_core/type_layer_control.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "type_layer_control.h" + +#include +#include + +const char* GetToken(LayerControl control) { + static const char* TOKENS[] = { + "auto", // LAYER_CONTROL_AUTO + "on", // LAYER_CONTROL_ON + "off", // LAYER_CONTROL_OFF + "application_enabled_layers", // LAYER_CONTROL_APPLICATIONS + "unordered_layer_location" // LAYER_CONTROL_UNORDERED + }; + static_assert(std::size(TOKENS) == LAYER_CONTROL_COUNT); + + return TOKENS[control]; +} + +LayerControl GetLayerControl(const char* token) { + for (int i = LAYER_CONTROL_FIRST, l = LAYER_CONTROL_LAST; i <= l; ++i) { + const LayerControl type = static_cast(i); + if (std::strcmp(::GetToken(type), token) == 0) { + return type; + } + } + + return LAYER_CONTROL_AUTO; +} diff --git a/vkconfig_core/type_layer_control.h b/vkconfig_core/type_layer_control.h new file mode 100644 index 0000000000..891fcbcfc1 --- /dev/null +++ b/vkconfig_core/type_layer_control.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +enum LayerControl { + LAYER_CONTROL_AUTO = 0, + LAYER_CONTROL_ON, + LAYER_CONTROL_OFF, + LAYER_CONTROL_APPLICATIONS, + LAYER_CONTROL_UNORDERED, + + LAYER_CONTROL_FIRST = LAYER_CONTROL_AUTO, + LAYER_CONTROL_LAST = LAYER_CONTROL_UNORDERED +}; + +enum { LAYER_CONTROL_COUNT = LAYER_CONTROL_LAST - LAYER_CONTROL_FIRST + 1 }; + +const char* GetToken(LayerControl control); + +LayerControl GetLayerControl(const char* token); diff --git a/vkconfig_core/type_layer_type.cpp b/vkconfig_core/type_layer_type.cpp new file mode 100644 index 0000000000..9a34437a08 --- /dev/null +++ b/vkconfig_core/type_layer_type.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "type_layer_type.h" + +#include +#include + +const char* GetToken(LayerType type) { + static const char* TOKENS[] = { + "Explicit", // LAYER_TYPE_EXPLICIT + "Implicit", // LAYER_TYPE_IMPLICIT + }; + static_assert(std::size(TOKENS) == LAYER_TYPE_COUNT); + + return TOKENS[type]; +} + +LayerType GetLayerType(const char* token) { + for (int i = LAYER_TYPE_FIRST, l = LAYER_TYPE_LAST; i <= l; ++i) { + const LayerType type = static_cast(i); + if (std::strcmp(::GetToken(type), token) == 0) { + return type; + } + } + + return LAYER_TYPE_EXPLICIT; +} diff --git a/vkconfig_core/layer_type.h b/vkconfig_core/type_layer_type.h similarity index 72% rename from vkconfig_core/layer_type.h rename to vkconfig_core/type_layer_type.h index 9cc959cb8c..0fbf83d8c3 100644 --- a/vkconfig_core/layer_type.h +++ b/vkconfig_core/type_layer_type.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,14 +22,15 @@ #pragma once enum LayerType { // Enum value can't be changed - LAYER_TYPE_EXPLICIT = 0, - LAYER_TYPE_IMPLICIT = 1, - LAYER_TYPE_USER_DEFINED = 2, + LAYER_TYPE_IMPLICIT = 0, + LAYER_TYPE_EXPLICIT, - LAYER_TYPE_FIRST = LAYER_TYPE_EXPLICIT, - LAYER_TYPE_LAST = LAYER_TYPE_USER_DEFINED + LAYER_TYPE_FIRST = LAYER_TYPE_IMPLICIT, + LAYER_TYPE_LAST = LAYER_TYPE_EXPLICIT }; enum { LAYER_TYPE_COUNT = LAYER_TYPE_LAST - LAYER_TYPE_FIRST + 1 }; -const char* GetLayerTypeLabel(LayerType type); +const char* GetToken(LayerType type); + +LayerType GetLayerType(const char* token); diff --git a/vkconfig_core/type_layers_mode.cpp b/vkconfig_core/type_layers_mode.cpp new file mode 100644 index 0000000000..591971a1d7 --- /dev/null +++ b/vkconfig_core/type_layers_mode.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "type_layers_mode.h" + +#include +#include + +const char* GetToken(LayersMode mode) { + static const char* TOKENS[] = { + "CONTROLLED_BY_APPLICATIONS", // LAYERS_MODE_BY_APPLICATIONS + "CONTROLLED_BY_CONFIGURATOR", // LAYERS_MODE_BY_CONFIGURATOR_RUNNING + "DISABLED_BY_CONFIGURATOR" // LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED + }; + static_assert(std::size(TOKENS) == LAYERS_MODE_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + return TOKENS[mode]; +} + +LayersMode GetLayersMode(const char* token) { + for (int i = LAYERS_MODE_FIRST, l = LAYERS_MODE_LAST; i <= l; ++i) { + const LayersMode type = static_cast(i); + if (std::strcmp(GetToken(type), token) == 0) { + return type; + } + } + + return LAYERS_CONTROLLED_BY_APPLICATIONS; +} diff --git a/vkconfig/dialog_about.h b/vkconfig_core/type_layers_mode.h similarity index 56% rename from vkconfig/dialog_about.h rename to vkconfig_core/type_layers_mode.h index 1cf7a6e1a5..e49d39758e 100644 --- a/vkconfig/dialog_about.h +++ b/vkconfig_core/type_layers_mode.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,28 +15,22 @@ * limitations under the License. * * Authors: - * - Richard S. Wright Jr. * - Christophe Riccio */ #pragma once -#include "ui_dialog_about.h" +enum LayersMode { + LAYERS_CONTROLLED_BY_APPLICATIONS = 0, + LAYERS_CONTROLLED_BY_CONFIGURATOR, + LAYERS_DISABLED_BY_CONFIGURATOR, -#include - -class AboutDialog : public QDialog { - Q_OBJECT - - public Q_SLOTS: - void aboutQt(); + LAYERS_MODE_FIRST = LAYERS_CONTROLLED_BY_APPLICATIONS, + LAYERS_MODE_LAST = LAYERS_DISABLED_BY_CONFIGURATOR +}; - public: - explicit AboutDialog(QWidget *parent = nullptr); +enum { LAYERS_MODE_COUNT = LAYERS_MODE_LAST - LAYERS_MODE_FIRST + 1 }; - private: - AboutDialog(const AboutDialog &) = delete; - AboutDialog &operator=(const AboutDialog &) = delete; +const char* GetToken(LayersMode mode); - std::unique_ptr ui; -}; +LayersMode GetLayersMode(const char* token); diff --git a/vkconfig_core/type_log.cpp b/vkconfig_core/type_log.cpp new file mode 100644 index 0000000000..99020c10e7 --- /dev/null +++ b/vkconfig_core/type_log.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "type_log.h" +#include "bitfield.h" +#include "util.h" + +#include +#include + +const char* GetToken(LogType value) { + static const char* TOKENS[] = { + "error", // LOG_ERROR + "warn", // LOG_WARN + "info", // LOG_INFO + "debug", // LOG_DEBUG + "perf", // LOG_PERF + "layer", // LOG_LAYER + "implem", // LOG_IMPLEM + }; + static_assert(std::size(TOKENS) == LOG_COUNT); + + if (value >= LOG_FIRST && value <= LOG_LAST) { + return TOKENS[value - LOG_FIRST]; + } else { + return nullptr; + } +} + +LogType GetLogType(const char* token) { + for (int i = LOG_FIRST, l = LOG_LAST; i <= l; ++i) { + const LogType value = static_cast(i); + if (std::strcmp(::GetToken(value), token) == 0) { + return value; + } + } + + return LOG_MESSAGE_INVALID; +} + +const char* GetToken(LogBit bit) { return GetToken(GetValue(bit)); } + +LogBit GetLogBit(const char* token) { + const LogType value = GetLogType(token); + if (value >= LOG_FIRST && value <= LOG_LAST) { + return static_cast(1 << (value - LOG_FIRST)); + } else { + return static_cast(0); + } +} + +LogBit GetBit(LogType value) { + if (value >= LOG_FIRST && value <= LOG_LAST) { + const int bit = GetBit(value, LOG_FIRST); + return static_cast(bit); + } else { + return static_cast(0); + } +} + +LogType GetValue(LogBit bit) { + const LogType value = GetValue(bit, LOG_FIRST); + if (value >= LOG_FIRST && value <= LOG_LAST) { + return value; + } else { + return LOG_MESSAGE_INVALID; + } +} + +LogFlags GetLogFlags(const std::vector& tokens) { + LogFlags flags = 0; + + for (std::size_t i = 0, n = tokens.size(); i < n; ++i) { + LogType value = GetLogType(tokens[i].c_str()); + if (value == LOG_MESSAGE_INVALID) { + continue; + } + flags |= GetBit(value); + } + + return flags; +} + +std::vector GetLogTokens(LogFlags flags) { + std::vector result; + + for (int i = LOG_FIRST, l = LOG_LAST; i <= l; ++i) { + LogType value = static_cast(i); + if (flags & GetBit(value)) { + result.push_back(GetToken(value)); + } + } + + return result; +} + +LogFlags GetLogFlags(const std::string& string) { + const std::vector& tokens = Split(string, ","); + return GetLogFlags(tokens); +} + +std::string GetLogString(LogFlags flags) { + const std::vector& tokens = GetLogTokens(flags); + return Merge(tokens, ","); +} diff --git a/vkconfig_core/type_log.h b/vkconfig_core/type_log.h new file mode 100644 index 0000000000..ec413d0d6e --- /dev/null +++ b/vkconfig_core/type_log.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include +#include + +enum LogType { + LOG_NONE = 0, + LOG_ERROR, + LOG_WARN, + LOG_INFO, + LOG_DEBUG, + LOG_PERF, + LOG_LAYER, + LOG_IMPLEM, + + LOG_FIRST = LOG_ERROR, + LOG_LAST = LOG_IMPLEM, + + LOG_MESSAGE_INVALID = ~0, +}; +enum { LOG_COUNT = LOG_LAST - LOG_FIRST + 1 }; + +enum LogBit {}; +typedef int LogFlags; + +const char* GetToken(LogType value); + +LogType GetLogType(const char* token); + +const char* GetToken(LogBit bit); + +LogBit GetLogBit(const char* token); + +LogBit GetBit(LogType type); + +LogType GetValue(LogBit bit); + +LogFlags GetLogFlags(const std::vector& tokens); + +std::vector GetLogTokens(LogFlags flags); + +LogFlags GetLogFlags(const std::string& string); + +std::string GetLogString(LogFlags flags); diff --git a/vkconfig_core/platform.cpp b/vkconfig_core/type_platform.cpp similarity index 68% rename from vkconfig_core/platform.cpp rename to vkconfig_core/type_platform.cpp index 571b7480a7..fb49df030f 100644 --- a/vkconfig_core/platform.cpp +++ b/vkconfig_core/type_platform.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,11 @@ * - Christophe Riccio */ -#include "platform.h" #include "path.h" #include "util.h" +#include "type_platform.h" +#include #include #include #include @@ -58,7 +59,7 @@ const char* GetToken(PlatformType type) { "MACOS", // PLATFORM_MACOS "ANDROID", // PLATFORM_ANDROID }; - static_assert(countof(table) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); + static_assert(std::size(table) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); return table[type]; } @@ -73,26 +74,4 @@ PlatformType GetPlatformType(const char* token) { return static_cast(-1); } -const char* GetToken(StatusType type) { - static const char* table[] = { - "STABLE", // STATUS_STABLE - "BETA", // STATUS_BETA - "ALPHA", // STATUS_ALPHA - "DEPRECATED" // STATUS_ALPHA - }; - static_assert(countof(table) == STATUS_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return table[type]; -} - -StatusType GetStatusType(const char* token) { - for (std::size_t i = 0, n = STATUS_COUNT; i < n; ++i) { - const StatusType status_type = static_cast(i); - if (std::strcmp(GetToken(status_type), token) == 0) return status_type; - } - - assert(0); - return static_cast(-1); -} - bool IsPlatformSupported(int platform_flags) { return platform_flags & (1 << VKC_PLATFORM); } diff --git a/vkconfig_core/platform.h b/vkconfig_core/type_platform.h similarity index 85% rename from vkconfig_core/platform.h rename to vkconfig_core/type_platform.h index 39aebec4c7..6d0ec0105e 100644 --- a/vkconfig_core/platform.h +++ b/vkconfig_core/type_platform.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -69,21 +69,6 @@ std::vector GetPlatformTokens(int platform_flags); PlatformType GetPlatformType(const char* token); const char* GetToken(PlatformType type); -enum StatusType { - STATUS_STABLE = 0, - STATUS_BETA, - STATUS_ALPHA, - STATUS_DEPRECATED, - - STATUS_FIRST = STATUS_STABLE, - STATUS_LAST = STATUS_DEPRECATED -}; - -enum { STATUS_COUNT = STATUS_LAST - STATUS_FIRST + 1 }; - -const char* GetToken(StatusType type); -StatusType GetStatusType(const char* token); - #ifdef _WIN32 #define VKC_PLATFORM VKC_PLATFORM_WINDOWS #define VKC_ENV VKC_ENV_WIN32 diff --git a/vkconfig_core/type_status.cpp b/vkconfig_core/type_status.cpp new file mode 100644 index 0000000000..dd2ac45823 --- /dev/null +++ b/vkconfig_core/type_status.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "type_status.h" + +#include +#include + +const char* GetToken(StatusType value) { + static const char* TOKENS[] = { + "STABLE", // STATUS_STABLE + "BETA", // STATUS_BETA + "ALPHA", // STATUS_ALPHA + "DEPRECATED" // STATUS_ALPHA + }; + static_assert(std::size(TOKENS) == STATUS_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + if (value >= STATUS_FIRST && value <= STATUS_LAST) { + return TOKENS[value - STATUS_FIRST]; + } else { + return nullptr; + } +} + +StatusType GetStatusType(const char* token) { + for (std::size_t i = 0, n = STATUS_COUNT; i < n; ++i) { + const StatusType value = static_cast(i); + if (std::strcmp(::GetToken(value), token) == 0) { + return value; + } + } + + return STATUS_INVALID; +} diff --git a/vkconfig3/vulkan_util.h b/vkconfig_core/type_status.h similarity index 60% rename from vkconfig3/vulkan_util.h rename to vkconfig_core/type_status.h index aefd6f68aa..f614d2b3fe 100644 --- a/vkconfig3/vulkan_util.h +++ b/vkconfig_core/type_status.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,20 @@ #pragma once -#include "../vkconfig_core/version.h" +enum StatusType { + STATUS_STABLE = 0, + STATUS_BETA, + STATUS_ALPHA, + STATUS_DEPRECATED, -#include + STATUS_FIRST = STATUS_STABLE, + STATUS_LAST = STATUS_DEPRECATED, -#include + STATUS_INVALID +}; -#include +enum { STATUS_COUNT = STATUS_LAST - STATUS_FIRST + 1 }; -Version GetVulkanLoaderVersion(); -std::string GenerateVulkanStatus(); -const char *GetVulkanLibrary(); -VkResult CreateInstance(QLibrary &library, VkInstance &instance, bool enumerate_portability); +const char* GetToken(StatusType type); + +StatusType GetStatusType(const char* token); diff --git a/vkconfig_core/type_tab.cpp b/vkconfig_core/type_tab.cpp new file mode 100644 index 0000000000..82df19a0a1 --- /dev/null +++ b/vkconfig_core/type_tab.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "type_tab.h" + +#include +#include + +const char* GetToken(TabType type) { + static const char* TOKENS[]{ + "DIAGNOSTIC", // TAB_DIAGNOSTIC + "APPLICATIONS", // TAB_APPLICATIONS + "LAYERS", // TAB_LAYERS + "CONFIGURATIONS", // TAB_CONFIGURATIONS + "PREFERENCES", // TAB_PREFERENCES + "HELP" // TAB_HELP + }; + + static_assert(std::size(TOKENS) == TAB_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + return TOKENS[type - TAB_FIRST]; +} + +TabType GetTabType(const char* token) { + for (int i = TAB_FIRST, n = TAB_LAST; i <= n; ++i) { + const TabType type = static_cast(i); + if (std::strcmp(::GetToken(type), token) == 0) { + return type; + } + } + + return TAB_DIAGNOSTIC; +} diff --git a/vkconfig3/combo_box.h b/vkconfig_core/type_tab.h similarity index 61% rename from vkconfig3/combo_box.h rename to vkconfig_core/type_tab.h index 828ae3d671..b1bb250674 100644 --- a/vkconfig3/combo_box.h +++ b/vkconfig_core/type_tab.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,20 @@ #pragma once -#include -#include +enum TabType { + TAB_DIAGNOSTIC = 0, + TAB_APPLICATIONS, + TAB_LAYERS, + TAB_CONFIGURATIONS, + TAB_PREFERENCES, + TAB_HELP, -class ComboBox : public QComboBox { - public: - ComboBox(QWidget* widget) : QComboBox(widget) {} - - void wheelEvent(QWheelEvent* e) override { - (void)e; - return; - } + TAB_FIRST = TAB_DIAGNOSTIC, + TAB_LAST = TAB_HELP }; + +enum { TAB_COUNT = TAB_LAST - TAB_FIRST + 1 }; + +const char* GetToken(TabType type); + +TabType GetTabType(const char* token); diff --git a/vkconfig_core/test/test_layer_type.cpp b/vkconfig_core/type_update.cpp similarity index 84% rename from vkconfig_core/test/test_layer_type.cpp rename to vkconfig_core/type_update.cpp index 0fe0b03d6c..572d5cf9c9 100644 --- a/vkconfig_core/test/test_layer_type.cpp +++ b/vkconfig_core/type_update.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,3 +17,5 @@ * Authors: * - Christophe Riccio */ + +#include "type_update.h" diff --git a/vkconfig/vulkan_util.h b/vkconfig_core/type_update.h similarity index 70% rename from vkconfig/vulkan_util.h rename to vkconfig_core/type_update.h index f2a58e593a..8fc9f6ce7f 100644 --- a/vkconfig/vulkan_util.h +++ b/vkconfig_core/type_update.h @@ -20,15 +20,9 @@ #pragma once -#include "../vkconfig_core/version.h" - -#include - -#include - -#include - -Version GetVulkanLoaderVersion(); -std::string GenerateVulkanStatus(); -const char *GetVulkanLibrary(); -VkResult CreateInstance(QLibrary &library, VkInstance &instance, bool enumerate_portability); +enum UpdateBits { + UPDATE_NONE = 0, + UPDATE_LOADER_SETTINGS_BIT = (1 << 0), + UPDATE_LAYERS_SETTINGS_BIT = (1 << 1), + UPDATE_ALL = UPDATE_LOADER_SETTINGS_BIT | UPDATE_LAYERS_SETTINGS_BIT +}; diff --git a/vkconfig_core/util.cpp b/vkconfig_core/util.cpp index d11ac730d4..545c7e51df 100644 --- a/vkconfig_core/util.cpp +++ b/vkconfig_core/util.cpp @@ -20,7 +20,10 @@ */ #include "util.h" -#include "platform.h" +#include "type_platform.h" + +#include +#include #include #include @@ -28,9 +31,6 @@ #include #include -#include -#include - #include #include #include diff --git a/vkconfig_core/util.h b/vkconfig_core/util.h index 75eb60eb70..0e51644639 100644 --- a/vkconfig_core/util.h +++ b/vkconfig_core/util.h @@ -35,23 +35,6 @@ #include #include -// Based on https://www.g-truc.net/post-0708.html#menu -template -inline constexpr std::size_t countof(T const (&)[N]) noexcept { - return N; -} - -template -inline constexpr std::size_t countof(std::array const& data) noexcept { - return data.size(); -} - -// For C++ container -template class C> -inline constexpr std::size_t countof(C const& data) noexcept { - return data.size(); -} - std::string format(const char* message, ...); bool IsFrames(const std::string& s); @@ -175,3 +158,10 @@ template bool IsFound(const std::vector& container, const char* key) { return FindByKey(container, key) != nullptr; } + +template +std::vector GetVector(const T& value) { + std::vector result; + result.push_back(value); + return result; +} diff --git a/vkconfig_core/version.cpp b/vkconfig_core/version.cpp index 576acf88d5..9326cfd176 100644 --- a/vkconfig_core/version.cpp +++ b/vkconfig_core/version.cpp @@ -28,9 +28,7 @@ #include #include -const Version Version::VKCONFIG(2, 6, 2); -const Version Version::VKCONFIG3(3, 0, 0); -const Version Version::LAYER_CONFIG(2, 2, 3); +const Version Version::VKCONFIG(3, 0, 0); const Version Version::VKHEADER(VK_HEADER_VERSION_COMPLETE); const Version Version::VERSION_NULL(0u); diff --git a/vkconfig_core/version.h b/vkconfig_core/version.h index b0e739349f..9fe42287a2 100644 --- a/vkconfig_core/version.h +++ b/vkconfig_core/version.h @@ -25,18 +25,14 @@ #include #include -#define SUPPORT_LAYER_CONFIG_2_2_0 1 - extern const char *VKCONFIG_NAME; extern const char *VKCONFIG_SHORT_NAME; class Version { public: static const Version VKCONFIG; - static const Version VKCONFIG3; static const Version VKHEADER; static const Version VERSION_NULL; - static const Version LAYER_CONFIG; explicit Version() : _major(0), _minor(0), _patch(0) {} explicit Version(uint32_t version_complete); diff --git a/vkconfig/vulkan_util.cpp b/vkconfig_core/vulkan_info.cpp similarity index 60% rename from vkconfig/vulkan_util.cpp rename to vkconfig_core/vulkan_info.cpp index 6347727a6c..97f11feb64 100644 --- a/vkconfig/vulkan_util.cpp +++ b/vkconfig_core/vulkan_info.cpp @@ -18,135 +18,23 @@ * - Christophe Riccio */ -#include "vulkan_util.h" -#include "configurator.h" - -#include "../vkconfig_core/alert.h" -#include "../vkconfig_core/util.h" -#include "../vkconfig_core/platform.h" -#include "../vkconfig_core/override.h" - -#include - -#include -#include - -#include - -const char *GetVulkanLibrary() { - static const char *TABLE[] = { - "vulkan-1.dll", // PLATFORM_WINDOWS - "libvulkan", // PLATFORM_LINUX - "/usr/local/lib/libvulkan", // PLATFORM_MACOS - "N/A", // PLATFORM_ANDROID - }; - static_assert(countof(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return TABLE[VKC_PLATFORM]; -} - -std::string GetUUIDString(const uint8_t deviceUUID[VK_UUID_SIZE]) { - std::string result; - - for (std::size_t i = 0, n = VK_UUID_SIZE; i < n; ++i) { - result += format("%02X", deviceUUID[i]); - } - - return result; -} - -Version GetVulkanLoaderVersion() { - // Check loader version - QLibrary library(GetVulkanLibrary()); - - if (!library.load()) return Version::VERSION_NULL; - - PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; - vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)library.resolve("vkEnumerateInstanceVersion"); - assert(vkEnumerateInstanceVersion); - - uint32_t version = 0; - const VkResult result = vkEnumerateInstanceVersion(&version); - assert(result == VK_SUCCESS); - - return Version(version); -} - +#include "vulkan_info.h" +/* static std::string GetUserDefinedLayersPathsLog(const char *label, UserDefinedLayersPaths custom_layer_path) { std::string log; - const std::vector &user_defined_layer_paths = + const std::vector &user_defined_layer_paths = Configurator::Get().environment.GetUserDefinedLayersPaths(custom_layer_path); if (!user_defined_layer_paths.empty()) { log += format(" - %s:\n", label); for (std::size_t i = 0, n = user_defined_layer_paths.size(); i < n; ++i) - log += format(" - %s\n", user_defined_layer_paths[i].c_str()); + log += format(" - %s\n", user_defined_layer_paths[i].AbsolutePath().c_str()); } else log += format(" - %s: None\n", label); return log; } -VkResult CreateInstance(QLibrary &library, VkInstance &instance, bool enumerate_portability) { - PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = - (PFN_vkEnumerateInstanceExtensionProperties)library.resolve("vkEnumerateInstanceExtensionProperties"); - assert(vkEnumerateInstanceExtensionProperties); - - uint32_t property_count = 0; - VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &property_count, nullptr); - assert(err == VK_SUCCESS); - - std::vector instance_properties(property_count); - err = vkEnumerateInstanceExtensionProperties(nullptr, &property_count, &instance_properties[0]); - assert(err == VK_SUCCESS); - - // Handle Portability Enumeration requirements - std::vector instance_extensions; - - for (std::size_t i = 0, n = instance_properties.size(); i < n; ++i) { - if (instance_properties[i].extensionName == std::string(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) { - instance_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME); - } -#if VK_KHR_portability_enumeration - if (enumerate_portability) { - if (instance_properties[i].extensionName == std::string(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) { - instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); - } - } -#endif - } - - // Check Vulkan Devices - - VkApplicationInfo app = {}; - app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app.pNext = nullptr; - app.pApplicationName = VKCONFIG_SHORT_NAME; - app.applicationVersion = 0; - app.pEngineName = VKCONFIG_SHORT_NAME; - app.engineVersion = 0; - app.apiVersion = VK_API_VERSION_1_1; - - VkInstanceCreateInfo inst_info = {}; - inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; -#if VK_KHR_portability_enumeration - if (enumerate_portability) { - inst_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; - } -#endif - inst_info.pNext = nullptr; - inst_info.pApplicationInfo = &app; - inst_info.enabledLayerCount = 0; - inst_info.ppEnabledLayerNames = nullptr; - inst_info.enabledExtensionCount = static_cast(instance_extensions.size()); - inst_info.ppEnabledExtensionNames = instance_extensions.empty() ? nullptr : &instance_extensions[0]; - - PFN_vkCreateInstance vkCreateInstance = (PFN_vkCreateInstance)library.resolve("vkCreateInstance"); - assert(vkCreateInstance); - - return vkCreateInstance(&inst_info, nullptr, &instance); -} - std::string GenerateVulkanStatus() { std::string log; @@ -155,10 +43,10 @@ std::string GenerateVulkanStatus() { // Layers override configuration switch (configurator.environment.GetMode()) { default: - case LAYERS_MODE_BY_APPLICATIONS: + case LAYERS_CONTROLLED_BY_APPLICATIONS: log += "- Vulkan Layers Controlled by Vulkan Applications\n"; break; - case LAYERS_MODE_BY_CONFIGURATOR_RUNNING: + case LAYERS_CONTROLLED_BY_CONFIGURATOR: if (configurator.configurations.HasActiveConfiguration(configurator.layers.selected_layers)) { log += format("- Vulkan Layers Controlled by \"%s\" configuration\n", configurator.environment.GetSelectedConfiguration().c_str()); @@ -167,7 +55,7 @@ std::string GenerateVulkanStatus() { configurator.environment.GetSelectedConfiguration().c_str()); } break; - case LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED: + case LAYERS_DISABLED_BY_CONFIGURATOR: log += "- Vulkan Layers Disabled by Vulkan Configurator\n"; break; } @@ -175,16 +63,14 @@ std::string GenerateVulkanStatus() { log += "- Environment variables:\n"; // Check Vulkan SDK path - const std::string vk_sdk_path(qgetenv("VULKAN_SDK")); - if (!vk_sdk_path.empty()) - log += format(" - VULKAN_SDK: %s\n", vk_sdk_path.c_str()); + if (Get(Path::SDK).Empty()) + log += " - ${VULKAN_SDK} not set\n"; else - log += " - VULKAN_SDK not set\n"; + log += format(" - ${VULKAN_SDK}: %s\n", AbsolutePath(Path::SDK).c_str()); - // Check VK_LOCAL path - const std::string vk_local_path(GetPath(BUILTIN_PATH_LOCAL)); - if (!vk_local_path.empty()) { - log += format(" - VK_LOCAL: %s\n", vk_local_path.c_str()); + // Check VK_HOME path + if (!Get(Path::HOME).Empty()) { + log += format(" - ${VK_HOME}: %s\n", AbsolutePath(Path::HOME).c_str()); } const Version loader_version = GetVulkanLoaderVersion(); @@ -196,39 +82,43 @@ std::string GenerateVulkanStatus() { return log; } else { log += format("- Vulkan Loader version: %s\n", loader_version.str().c_str()); - const int loader_message_types = configurator.environment.GetLoaderMessageTypes(); - if (loader_message_types != LOADER_MESSAGE_NONE) { - log += format(" - VK_LOADER_DEBUG=%s\n", GetLoaderMessageTokens(loader_message_types).c_str()); + const LogFlags log_flags = configurator.environment.GetLoaderMessageFlags(); + if (log_flags != 0) { + log += format(" - ${VK_LOADER_DEBUG}=%s\n", GetLogString(log_flags).c_str()); } } log += "- User-Defined Layers locations:\n"; - log += GetUserDefinedLayersPathsLog("VK_LAYER_PATH variable", USER_DEFINED_LAYERS_PATHS_ENV_SET); + log += GetUserDefinedLayersPathsLog("${VK_LAYER_PATH} variable", USER_DEFINED_LAYERS_PATHS_ENV_SET); log += GetUserDefinedLayersPathsLog("Per-configuration paths", USER_DEFINED_LAYERS_PATHS_GUI); - log += GetUserDefinedLayersPathsLog("VK_ADD_LAYER_PATH variable", USER_DEFINED_LAYERS_PATHS_ENV_ADD); + log += GetUserDefinedLayersPathsLog("${VK_ADD_LAYER_PATH} variable", USER_DEFINED_LAYERS_PATHS_ENV_ADD); - const std::string layer_settings_path(qgetenv("VK_LAYER_SETTINGS_PATH")); - if (!layer_settings_path.empty()) { + // vk_layer_settings.txt + const Path layer_settings_path(qgetenv("VK_LAYER_SETTINGS_PATH").toStdString()); + if (!layer_settings_path.Empty()) { log += "- `vk_layer_settings.txt` location overridden by VK_LAYER_SETTINGS_PATH:\n"; - if (layer_settings_path.find("vk_layer_settings.txt") == std::string::npos) { - log += format(" %s\n", layer_settings_path.c_str()); + if (layer_settings_path.RelativePath().find("vk_layer_settings.txt") == std::string::npos) { + log += format(" %s\n", layer_settings_path.RelativePath().c_str()); } else { - log += format(" %s\n", ExtractAbsoluteDir(layer_settings_path).c_str()); + log += format(" %s\n", layer_settings_path.AbsoluteDir().c_str()); } } else { - const std::string path = GetPath(BUILTIN_PATH_OVERRIDE_SETTINGS); log += "- `vk_layer_settings.txt` uses the default platform path:\n"; - log += format(" %s\n", ExtractAbsoluteDir(path).c_str()); + log += format(" %s\n", AbsolutePath(Path::LAYERS_SETTINGS).c_str()); } + // vk_loader_settings.json + log += "- `vk_loader_settings.json` uses the default platform path:\n"; + log += format(" %s\n", AbsolutePath(Path::LOADER_SETTINGS).c_str()); + // If there is no Vulkan loader installed, we can't call any Vulkan API. if (loader_version == Version::VERSION_NULL) { return log; } LayersMode saved_mode = configurator.environment.GetMode(); - configurator.environment.SetMode(LAYERS_MODE_BY_APPLICATIONS); - configurator.configurations.Configure(configurator.layers.selected_layers); + configurator.environment.SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); + configurator.Configure(configurator.layers.selected_layers); QLibrary library(GetVulkanLibrary()); PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = @@ -367,7 +257,8 @@ std::string GenerateVulkanStatus() { vkDestroyInstance(inst, NULL); configurator.environment.SetMode(saved_mode); - configurator.configurations.Configure(configurator.layers.selected_layers); + configurator.Configure(configurator.layers.selected_layers); return log; } +*/ diff --git a/vkconfig_core/vulkan_info.h b/vkconfig_core/vulkan_info.h new file mode 100644 index 0000000000..8578e795c5 --- /dev/null +++ b/vkconfig_core/vulkan_info.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "version.h" + +#include + +#include + +struct VulkanPhysicalDeviceInfo { + std::string deviceName; + std::string deviceUUID; + std::string driverUUID; + Version apiVersion; +}; + +struct VulkanSystemInfo { + Version loaderVersion; + std::vector instanceLayerProperties; + std::vector instanceExtensionPropertie; + std::vector physicalDevices; +}; diff --git a/vkconfig_core/vulkan_util.cpp b/vkconfig_core/vulkan_util.cpp new file mode 100644 index 0000000000..e9309e6573 --- /dev/null +++ b/vkconfig_core/vulkan_util.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "vulkan_util.h" + +#include "../vkconfig_core/version.h" +#include "../vkconfig_core/type_platform.h" +#include "../vkconfig_core/util.h" + +#include + +#include + +static std::string GetUUIDString(const uint8_t deviceUUID[VK_UUID_SIZE]) { + std::string result; + + for (std::size_t i = 0, n = VK_UUID_SIZE; i < n; ++i) { + result += format("%02X", deviceUUID[i]); + } + + return result; +} + +struct VulkanFunctions { + VulkanFunctions(); + bool Validate() const; + + PFN_vkEnumerateInstanceVersion EnumerateInstanceVersion; + PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties; + PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices; + PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; + PFN_vkCreateInstance CreateInstance; + PFN_vkDestroyInstance DestroyInstance; + PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2; +}; + +static const char *GetVulkanLibrary() { + static const char *TABLE[] = { + "vulkan-1.dll", // PLATFORM_WINDOWS + "libvulkan", // PLATFORM_LINUX + "/usr/local/lib/libvulkan", // PLATFORM_MACOS + "N/A", // PLATFORM_ANDROID + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + return TABLE[VKC_PLATFORM]; +} + +VulkanFunctions::VulkanFunctions() { + QLibrary library(GetVulkanLibrary()); + if (!library.load()) { + return; + } + + this->EnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)library.resolve("vkEnumerateInstanceVersion"); + this->EnumerateInstanceLayerProperties = + (PFN_vkEnumerateInstanceLayerProperties)library.resolve("vkEnumerateInstanceLayerProperties"); + this->EnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)library.resolve("vkEnumeratePhysicalDevices"); + this->EnumerateInstanceExtensionProperties = + (PFN_vkEnumerateInstanceExtensionProperties)library.resolve("vkEnumerateInstanceExtensionProperties"); + this->CreateInstance = (PFN_vkCreateInstance)library.resolve("vkCreateInstance"); + this->DestroyInstance = (PFN_vkDestroyInstance)library.resolve("vkDestroyInstance"); + this->GetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)library.resolve("vkGetPhysicalDeviceProperties2"); +} + +bool VulkanFunctions::Validate() const { + return this->EnumerateInstanceVersion != nullptr && this->EnumerateInstanceLayerProperties != nullptr && + this->EnumeratePhysicalDevices != nullptr && this->EnumerateInstanceExtensionProperties != nullptr && + this->CreateInstance != nullptr && this->DestroyInstance != nullptr && this->GetPhysicalDeviceProperties2 != nullptr; +} + +VulkanSystemInfo BuildVulkanSystemInfo() { + VulkanSystemInfo vulkan_system_info; + + VulkanFunctions vk; + if (!vk.Validate()) { + return vulkan_system_info; + } + + uint32_t api_version = 0; + VkResult result = vk.EnumerateInstanceVersion(&api_version); + vulkan_system_info.loaderVersion = Version(api_version); + assert(result == VK_SUCCESS); + + std::uint32_t instance_layer_count = 0; + result = vk.EnumerateInstanceLayerProperties(&instance_layer_count, nullptr); + assert(result == VK_SUCCESS); + vulkan_system_info.instanceLayerProperties.resize(instance_layer_count); + result = vk.EnumerateInstanceLayerProperties(&instance_layer_count, vulkan_system_info.instanceLayerProperties.data()); + assert(result == VK_SUCCESS); + + uint32_t instance_extension_count = 0; + result = vk.EnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr); + assert(result == VK_SUCCESS); + vulkan_system_info.instanceExtensionPropertie.resize(instance_extension_count); + result = vk.EnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, + vulkan_system_info.instanceExtensionPropertie.data()); + assert(result == VK_SUCCESS); + + // Handle Portability Enumeration requirements + std::vector instance_extensions; +#if VK_KHR_portability_enumeration + for (std::size_t i = 0, n = vulkan_system_info.instanceExtensionPropertie.size(); i < n; ++i) { + if (vulkan_system_info.instanceExtensionPropertie[i].extensionName == + std::string(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) { + instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + } + } +#endif + + VkApplicationInfo app = {}; + app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app.pNext = nullptr; + app.pApplicationName = VKCONFIG_SHORT_NAME; + app.applicationVersion = 0; + app.pEngineName = VKCONFIG_SHORT_NAME; + app.engineVersion = 0; + app.apiVersion = VK_API_VERSION_1_1; + + VkInstanceCreateInfo inst_info = {}; + inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; +#if VK_KHR_portability_enumeration + if (!instance_extensions.empty()) { + inst_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + } +#endif + inst_info.pNext = nullptr; + inst_info.pApplicationInfo = &app; + inst_info.enabledLayerCount = 0; + inst_info.ppEnabledLayerNames = nullptr; + inst_info.enabledExtensionCount = static_cast(instance_extensions.size()); + inst_info.ppEnabledExtensionNames = instance_extensions.empty() ? nullptr : &instance_extensions[0]; + + VkInstance instance = VK_NULL_HANDLE; + vk.CreateInstance(&inst_info, nullptr, &instance); + + uint32_t physical_device_count = 0; + result = vk.EnumeratePhysicalDevices(instance, &physical_device_count, nullptr); + + // This can fail on a new Linux setup. Check and fail gracefully rather than crash. + if (result != VK_SUCCESS) { + vk.DestroyInstance(instance, NULL); + return vulkan_system_info; + } + + std::vector devices; + devices.resize(physical_device_count); + result = vk.EnumeratePhysicalDevices(instance, &physical_device_count, devices.data()); + assert(result == VK_SUCCESS); + + vulkan_system_info.physicalDevices.resize(devices.size()); + + for (std::size_t i = 0, n = devices.size(); i < n; ++i) { + VulkanPhysicalDeviceInfo &device_info = vulkan_system_info.physicalDevices[i]; + + VkPhysicalDeviceIDPropertiesKHR properties_deviceid{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR, nullptr}; + VkPhysicalDeviceProperties2 properties2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &properties_deviceid}; + + vk.GetPhysicalDeviceProperties2(devices[i], &properties2); + + device_info.deviceName = properties2.properties.deviceName; + device_info.apiVersion = Version(properties2.properties.apiVersion); + device_info.deviceUUID = GetUUIDString(properties_deviceid.deviceUUID); + device_info.driverUUID = GetUUIDString(properties_deviceid.driverUUID); + } + + vk.DestroyInstance(instance, NULL); + + return vulkan_system_info; +} diff --git a/vkconfig/main_layers.h b/vkconfig_core/vulkan_util.h similarity index 78% rename from vkconfig/main_layers.h rename to vkconfig_core/vulkan_util.h index a4528437b6..f4f34cbfd3 100644 --- a/vkconfig/main_layers.h +++ b/vkconfig_core/vulkan_util.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,6 @@ #pragma once -#include "../vkconfig_core/command_line.h" +#include "../vkconfig_core/vulkan_info.h" -int run_layers(const CommandLine& command_line); +VulkanSystemInfo BuildVulkanSystemInfo(); diff --git a/vkconfig/CHANGELOG.md b/vkconfig_gui/CHANGELOG.md similarity index 95% rename from vkconfig/CHANGELOG.md rename to vkconfig_gui/CHANGELOG.md index 56a7674f5b..3bdc25925a 100644 --- a/vkconfig/CHANGELOG.md +++ b/vkconfig_gui/CHANGELOG.md @@ -1,6 +1,6 @@

      LunarG

      -

      Copyright � 2015-2024 LunarG, Inc.

      +

      Copyright � 2015-2022 LunarG, Inc.

      [![Creative Commons][3]][4] @@ -11,6 +11,7 @@ # Release notes +<<<<<<< HEAD:vkconfig/CHANGELOG.md ## [Vulkan Configurator 2.6.2](https://github.com/LunarG/VulkanTools/tree/main) - October 2024 ### Improvements: @@ -24,12 +25,20 @@ - Fix renaming configuration with the same name but different cases ## [Vulkan Configurator 2.6.1](https://github.com/LunarG/VulkanTools/tree/vulkan-sdk-1.3.290.0) - July 2024 +======= +## [Vulkan Configurator 3.0.0](https://github.com/LunarG/VulkanTools/tree/main) - ??? 2024 +>>>>>>> a680297a5... vkconfig3: UI for new Vulkan Loader settings:vkconfig_gui/CHANGELOG.md ### Features: -- Add Crash Diagnostic layer built-in configuration - -### Fixes: -- Fix system configuration not being update when toggling layers configuration modes #2046 +- Redesign main window UI around tabs +- Per-Application layers configurations +- Full ordering of Vulkan layers +- Split GUI and command line tool + +### Deprecation: +- Requires Vulkan Loader 1.3.261 or newer on Linux and macOS +- Requires Vulkan Loader 1.3.284 or newer on Windows. +- Highly recommand Validation layer 1.3.250 or newer. ## [Vulkan Configurator 2.6.0](https://github.com/LunarG/VulkanTools/tree/vulkan-sdk-1.3.283.0) - May 2024 diff --git a/vkconfig3/CMakeLists.txt b/vkconfig_gui/CMakeLists.txt similarity index 81% rename from vkconfig3/CMakeLists.txt rename to vkconfig_gui/CMakeLists.txt index d7fdf03845..9468a70df6 100644 --- a/vkconfig3/CMakeLists.txt +++ b/vkconfig_gui/CMakeLists.txt @@ -1,4 +1,4 @@ -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) @@ -6,9 +6,9 @@ set(CMAKE_AUTOUIC ON) find_package(Qt5 COMPONENTS Core Gui Widgets Network QUIET) if(NOT Qt5_FOUND) - message("WARNING: vkconfig3 will be excluded because Qt5 was not found. Please add Qt5 into the PATH environment variable") + message("WARNING: vkconfig will be excluded because Qt5 was not found. Please add Qt5 into the PATH environment variable") elseif(Qt5_VERSION VERSION_LESS 5.5) - message("WARNING: vkconfig3 will be excluded because the found Qt version is too old. vkconfig requires version 5.5.") + message("WARNING: vkconfig will be excluded because the found Qt version is too old. vkconfig requires version 5.5.") else() file(GLOB FILES_UI ./*.ui) @@ -36,7 +36,7 @@ else() add_executable(vkconfig-gui ${FILES_ALL} ${FILES_UI}) endif() - target_link_libraries(vkconfig-gui Vulkan::Headers vkconfig_core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) + target_link_libraries(vkconfig-gui Vulkan::Headers vkconfig-core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) target_compile_definitions(vkconfig-gui PRIVATE QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT) set_target_properties(vkconfig-gui PROPERTIES FOLDER "vkconfig") @@ -47,8 +47,8 @@ else() get_filename_component(QT_BIN_DIR "${QMAKE_EXE}" DIRECTORY) find_program(WINDEPLOYQT_EXE windeployqt HINTS "${QT_BIN_DIR}") - message(STATUS "Will run ${WINDEPLOYQT_EXE} at ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig3.exe") - install(CODE "execute_process(COMMAND ${WINDEPLOYQT_EXE} ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig3.exe)") + message(STATUS "Will run ${WINDEPLOYQT_EXE} at ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig-gui.exe") + install(CODE "execute_process(COMMAND ${WINDEPLOYQT_EXE} ${CMAKE_INSTALL_FULL_BINDIR}/vkconfig-gui.exe)") endif() else() include(macOS/vkconfig.cmake) diff --git a/vkconfig/CONTRIBUTING.md b/vkconfig_gui/CONTRIBUTING.md similarity index 100% rename from vkconfig/CONTRIBUTING.md rename to vkconfig_gui/CONTRIBUTING.md diff --git a/vkconfig3/README.md b/vkconfig_gui/README.md similarity index 100% rename from vkconfig3/README.md rename to vkconfig_gui/README.md diff --git a/vkconfig/combo_box.h b/vkconfig_gui/combo_box.h similarity index 100% rename from vkconfig/combo_box.h rename to vkconfig_gui/combo_box.h diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/configuration_layer_widget.cpp new file mode 100644 index 0000000000..b057d5b7fd --- /dev/null +++ b/vkconfig_gui/configuration_layer_widget.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "configuration_layer_widget.h" +#include "widget_setting.h" + +#include "../vkconfig_core/configurator.h" + +ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter) + : layer_name(parameter.key) { + // const bool is_implicit_layer = layers.empty() ? false : layers[0]->type == LAYER_TYPE_IMPLICIT; + + if (parameter.control != LAYER_CONTROL_APPLICATIONS && parameter.control != LAYER_CONTROL_UNORDERED) { + this->layer_version = new QComboBox(this); + this->layer_version->addItem("Latest"); + int version_index = 0; + + for (std::size_t i = 0, n = layers.size(); i < n; ++i) { + if (layers[i]->key != parameter.key) { + continue; + } + + if (layers[i]->api_version == parameter.api_version) { + this->layer_version->setToolTip(layers[i]->manifest_path.AbsolutePath().c_str()); + version_index = this->layer_version->count(); + } + + this->layer_version->addItem(layers[i]->api_version.str().c_str()); + } + this->layer_version->setCurrentIndex(version_index); + + // this->layer_version->setEnabled(layers.size() > 1); + this->connect(this->layer_version, SIGNAL(currentIndexChanged(int)), this, SLOT(on_layer_version_currentIndexChanged(int))); + // this->layer_version->installEventFilter(this); + + this->layer_state = new QComboBox(this); + this->layer_state->addItem("Auto"); + this->layer_state->addItem("On"); + this->layer_state->addItem("Off"); + this->layer_state->setEnabled(!layers.empty()); + this->layer_state->setCurrentIndex(parameter.control); + this->connect(this->layer_state, SIGNAL(currentIndexChanged(int)), this, SLOT(on_layer_state_currentIndexChanged(int))); + // this->layer_state->installEventFilter(this); + } + + std::string decorated_name = parameter.key; + + if (layers.empty()) { + // A layers configuration may have excluded layer that are misssing because they are not available on this platform + // We simply hide these layers to avoid confusing the Vulkan developers + if (parameter.control == LAYER_CONTROL_OFF) { + return; + } + + if (parameter.control != LAYER_CONTROL_APPLICATIONS && parameter.control != LAYER_CONTROL_UNORDERED) { + decorated_name += " (Missing)"; + } + } else { + if (layers[0]->status != STATUS_STABLE) { + decorated_name += format(" (%s)", GetToken(layers[0]->status)); + } + + // if (IsDLL32Bit(layer->manifest_path)) { + // decorated_name += " (32-bit)"; + //} + } + this->setText(decorated_name.c_str()); +} + +bool ConfigurationLayerWidget::eventFilter(QObject *target, QEvent *event) { + if (event->type() == QEvent::Wheel) { + return true; + } + + return false; +} + +void ConfigurationLayerWidget::resizeEvent(QResizeEvent *event) { + QSize size = event->size(); + + if (this->layer_state != nullptr) { + const QFontMetrics fm = this->layer_state->fontMetrics(); + const int width_state = std::max(HorizontalAdvance(fm, "Auto 000"), 80); + const int width_version = std::max(HorizontalAdvance(fm, "1.2.199 000"), 80); + + const QRect state_button_rect = QRect(size.width() - width_state, 0, width_state, size.height()); + this->layer_state->setGeometry(state_button_rect); + + const QRect version_button_rect = QRect(size.width() - width_state - width_version, 0, width_version, size.height()); + this->layer_version->setGeometry(version_button_rect); + } +} + +void ConfigurationLayerWidget::on_layer_version_currentIndexChanged(int index) { + assert(index >= 0); + const std::string &text = this->layer_version->itemText(index).toStdString(); + Version version = text == "latest" ? Version::VERSION_NULL : Version(text.c_str()); + + Configuration *configuration = Configurator::Get().GetActiveConfiguration(); + Parameter *parameter = configuration->Find(this->layer_name); + parameter->api_version = version; +} + +void ConfigurationLayerWidget::on_layer_state_currentIndexChanged(int index) { + assert(index >= 0); + const std::string &text = this->layer_state->itemText(index).toStdString(); + + Configuration *configuration = Configurator::Get().GetActiveConfiguration(); + Parameter *parameter = configuration->Find(this->layer_name); + parameter->control = GetLayerControl(text.c_str()); +} diff --git a/vkconfig3/widget_preset.h b/vkconfig_gui/configuration_layer_widget.h similarity index 53% rename from vkconfig3/widget_preset.h rename to vkconfig_gui/configuration_layer_widget.h index b7dcc5c6b3..091d868df2 100644 --- a/vkconfig3/widget_preset.h +++ b/vkconfig_gui/configuration_layer_widget.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,38 +20,31 @@ #pragma once -#include "../vkconfig_core/layer.h" #include "../vkconfig_core/parameter.h" +#include "../vkconfig_core/layer.h" -#include "widget_setting.h" -#include "combo_box.h" - +#include +#include +#include #include -#include - -class WidgetPreset : public WidgetSettingBase { +class ConfigurationLayerWidget : public QLabel { Q_OBJECT public: - explicit WidgetPreset(QTreeWidget* tree, QTreeWidgetItem* item, const Layer& layer, Parameter& parameter); + ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter); - void Refresh(RefreshAreas refresh_areas) override; + protected: + bool eventFilter(QObject *target, QEvent *event); + void resizeEvent(QResizeEvent *event) override; public Q_SLOTS: - void OnPresetChanged(int combox_preset_index); - - Q_SIGNALS: - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent* event) override; + void on_layer_version_currentIndexChanged(int index); + void on_layer_state_currentIndexChanged(int index); private: - int GetComboBoxIndex(const char* preset_label) const; + std::string layer_name; - std::vector preset_labels; // The preset in the combobox - const Layer& layer; - Parameter& parameter; - ComboBox* field; + QComboBox *layer_version = nullptr; + QComboBox *layer_state = nullptr; }; diff --git a/vkconfig3/dialog_vulkan_analysis.cpp b/vkconfig_gui/dialog_vulkan_analysis.cpp similarity index 98% rename from vkconfig3/dialog_vulkan_analysis.cpp rename to vkconfig_gui/dialog_vulkan_analysis.cpp index a5b54c9aba..585af580f2 100644 --- a/vkconfig3/dialog_vulkan_analysis.cpp +++ b/vkconfig_gui/dialog_vulkan_analysis.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ #include "dialog_vulkan_analysis.h" -#include "../vkconfig_core/platform.h" +#include "../vkconfig_core/type_platform.h" #include #include diff --git a/vkconfig/dialog_vulkan_analysis.h b/vkconfig_gui/dialog_vulkan_analysis.h similarity index 100% rename from vkconfig/dialog_vulkan_analysis.h rename to vkconfig_gui/dialog_vulkan_analysis.h diff --git a/vkconfig/dialog_vulkan_analysis.ui b/vkconfig_gui/dialog_vulkan_analysis.ui similarity index 100% rename from vkconfig/dialog_vulkan_analysis.ui rename to vkconfig_gui/dialog_vulkan_analysis.ui diff --git a/vkconfig/dialog_vulkan_info.cpp b/vkconfig_gui/dialog_vulkan_info.cpp similarity index 98% rename from vkconfig/dialog_vulkan_info.cpp rename to vkconfig_gui/dialog_vulkan_info.cpp index 1277cd80b4..a6698be1b8 100644 --- a/vkconfig/dialog_vulkan_info.cpp +++ b/vkconfig_gui/dialog_vulkan_info.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ #include "dialog_vulkan_info.h" #include "../vkconfig_core/util.h" -#include "../vkconfig_core/platform.h" +#include "../vkconfig_core/type_platform.h" #include #include @@ -54,7 +54,7 @@ void VulkanInfoDialog::Run() { "/usr/local/bin/vulkaninfo", // PLATFORM_MACOS "N/A", // PLATFORM_ANDROID }; - static_assert(countof(VULKAN_INFO_PATH) == PLATFORM_COUNT, + static_assert(std::size(VULKAN_INFO_PATH) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); ui->treeWidget->clear(); diff --git a/vkconfig/dialog_vulkan_info.h b/vkconfig_gui/dialog_vulkan_info.h similarity index 100% rename from vkconfig/dialog_vulkan_info.h rename to vkconfig_gui/dialog_vulkan_info.h diff --git a/vkconfig/dialog_vulkan_info.ui b/vkconfig_gui/dialog_vulkan_info.ui similarity index 100% rename from vkconfig/dialog_vulkan_info.ui rename to vkconfig_gui/dialog_vulkan_info.ui diff --git a/vkconfig/images/NewLunarGLogoBlack.png b/vkconfig_gui/images/NewLunarGLogoBlack.png similarity index 100% rename from vkconfig/images/NewLunarGLogoBlack.png rename to vkconfig_gui/images/NewLunarGLogoBlack.png diff --git a/vkconfig/images/presentation.gif b/vkconfig_gui/images/presentation.gif similarity index 100% rename from vkconfig/images/presentation.gif rename to vkconfig_gui/images/presentation.gif diff --git a/vkconfig/images/vkconfig_applications_collapsed.png b/vkconfig_gui/images/vkconfig_applications_collapsed.png similarity index 100% rename from vkconfig/images/vkconfig_applications_collapsed.png rename to vkconfig_gui/images/vkconfig_applications_collapsed.png diff --git a/vkconfig/images/vkconfig_applications_dialog.png b/vkconfig_gui/images/vkconfig_applications_dialog.png similarity index 100% rename from vkconfig/images/vkconfig_applications_dialog.png rename to vkconfig_gui/images/vkconfig_applications_dialog.png diff --git a/vkconfig/images/vkconfig_applications_expanded.png b/vkconfig_gui/images/vkconfig_applications_expanded.png similarity index 100% rename from vkconfig/images/vkconfig_applications_expanded.png rename to vkconfig_gui/images/vkconfig_applications_expanded.png diff --git a/vkconfig/images/vulkan_configurator.png b/vkconfig_gui/images/vulkan_configurator.png similarity index 100% rename from vkconfig/images/vulkan_configurator.png rename to vkconfig_gui/images/vulkan_configurator.png diff --git a/vkconfig/images/vulkan_layers_order.png b/vkconfig_gui/images/vulkan_layers_order.png similarity index 100% rename from vkconfig/images/vulkan_layers_order.png rename to vkconfig_gui/images/vulkan_layers_order.png diff --git a/vkconfig/images/vulkan_layers_order_small.png b/vkconfig_gui/images/vulkan_layers_order_small.png similarity index 100% rename from vkconfig/images/vulkan_layers_order_small.png rename to vkconfig_gui/images/vulkan_layers_order_small.png diff --git a/vkconfig/images/vulkan_loader.png b/vkconfig_gui/images/vulkan_loader.png similarity index 100% rename from vkconfig/images/vulkan_loader.png rename to vkconfig_gui/images/vulkan_loader.png diff --git a/vkconfig/images/vulkan_loader_640px.png b/vkconfig_gui/images/vulkan_loader_640px.png similarity index 100% rename from vkconfig/images/vulkan_loader_640px.png rename to vkconfig_gui/images/vulkan_loader_640px.png diff --git a/vkconfig3/macOS/Info.plist b/vkconfig_gui/macOS/Info.plist similarity index 100% rename from vkconfig3/macOS/Info.plist rename to vkconfig_gui/macOS/Info.plist diff --git a/vkconfig3/macOS/Resources/VulkanIcon.icns b/vkconfig_gui/macOS/Resources/VulkanIcon.icns similarity index 100% rename from vkconfig3/macOS/Resources/VulkanIcon.icns rename to vkconfig_gui/macOS/Resources/VulkanIcon.icns diff --git a/vkconfig/macOS/vkconfig.cmake b/vkconfig_gui/macOS/vkconfig.cmake similarity index 59% rename from vkconfig/macOS/vkconfig.cmake rename to vkconfig_gui/macOS/vkconfig.cmake index e64ce1eb80..b4afce4deb 100644 --- a/vkconfig/macOS/vkconfig.cmake +++ b/vkconfig_gui/macOS/vkconfig.cmake @@ -1,6 +1,6 @@ # ~~~ -# Copyright (c) 2018-2019 Valve Corporation -# Copyright (c) 2018-2019 LunarG, Inc. +# Copyright (c) 2018-2024 Valve Corporation +# Copyright (c) 2018-2024 LunarG, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ -add_executable(vkconfig +add_executable(vkconfig-gui MACOSX_BUNDLE ${FILES_ALL} ${CMAKE_CURRENT_SOURCE_DIR}/macOS/Resources/VulkanIcon.icns @@ -28,31 +28,31 @@ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/macOS/Resources/VulkanIc PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") -target_link_libraries(vkconfig vkconfig_core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) -target_link_libraries(vkconfig "-framework Cocoa -framework QuartzCore") +target_link_libraries(vkconfig-gui vkconfig-core Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) +target_link_libraries(vkconfig-gui "-framework Cocoa -framework QuartzCore") get_target_property(QMAKE_EXE Qt5::qmake IMPORTED_LOCATION) get_filename_component(QT_BIN_DIR "${QMAKE_EXE}" DIRECTORY) find_program(MACDEPLOYQT_EXE macdeployqt HINTS "${QT_BIN_DIR}") -add_custom_command(TARGET vkconfig POST_BUILD +add_custom_command(TARGET vkconfig-gui POST_BUILD COMMAND "${MACDEPLOYQT_EXE}" - "${CMAKE_CURRENT_BINARY_DIR}/vkconfig.app/" + "${CMAKE_CURRENT_BINARY_DIR}/vkconfig-gui.app/" -always-overwrite - -executable="${CMAKE_CURRENT_BINARY_DIR}/vkconfig.app/Contents/MacOS/vkconfig" + -executable="${CMAKE_CURRENT_BINARY_DIR}/vkconfig-gui.app/Contents/MacOS/vkconfig-gui" -verbose=1 COMMENT "Running macdeployqt..." ) -add_custom_command(TARGET vkconfig POST_BUILD +add_custom_command(TARGET vkconfig-gui POST_BUILD COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/macOS/Info.plist" - "${CMAKE_CURRENT_BINARY_DIR}/vkconfig.app/Contents/" - COMMENT "Copying Info.plist to vkconfig.app..." + "${CMAKE_CURRENT_BINARY_DIR}/vkconfig-gui.app/Contents/" + COMMENT "Copying Info.plist to vkconfig-gui.app..." ) -set_target_properties(vkconfig PROPERTIES SKIP_BUILD_RPATH FALSE) -set_target_properties(vkconfig PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) -set_target_properties(vkconfig PROPERTIES INSTALL_RPATH "") -set_target_properties(vkconfig PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) -install(TARGETS vkconfig BUNDLE DESTINATION "bin") +set_target_properties(vkconfig-gui PROPERTIES SKIP_BUILD_RPATH FALSE) +set_target_properties(vkconfig-gui PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) +set_target_properties(vkconfig-gui PROPERTIES INSTALL_RPATH "") +set_target_properties(vkconfig-gui PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) +install(TARGETS vkconfig-gui BUNDLE DESTINATION "bin") diff --git a/vkconfig3/main_gui.cpp b/vkconfig_gui/main.cpp similarity index 55% rename from vkconfig3/main_gui.cpp rename to vkconfig_gui/main.cpp index f614f40584..1333595342 100644 --- a/vkconfig3/main_gui.cpp +++ b/vkconfig_gui/main.cpp @@ -18,18 +18,30 @@ * - Christophe Riccio */ -#include "main_gui.h" - #include "mainwindow.h" +#include "../vkconfig_core/vulkan_util.h" +#include "../vkconfig_core/vulkan_util.h" #include "../vkconfig_core/alert.h" -#include "../vkconfig_core/version.h" #include "../vkconfig_core/application_singleton.h" +#include "../vkconfig_core/configurator.h" +#include "../vkconfig_core/configurator_signal.h" #include -#include -int run_gui(int argc, char* argv[], const CommandLine& command_line) { +#include + +// TODO, until Loader 284 release... +#if true || VKC_ENV == VKC_ENV_UNIX +static const Version REQUIRED_LOADER_VERSION(1, 3, 261); +#elif VKC_ENV == VKC_ENV_WIN32 +static const Version REQUIRED_LOADER_VERSION(1, 3, 284); +#else +#endif + +int main(int argc, char* argv[]) { + InitSignals(); + QCoreApplication::setOrganizationName("LunarG"); QCoreApplication::setOrganizationDomain("lunarg.com"); @@ -40,35 +52,45 @@ int run_gui(int argc, char* argv[], const CommandLine& command_line) { // settings from the previous version (assuming that's ever an issue) QCoreApplication::setApplicationName(VKCONFIG_SHORT_NAME); - // Older Qt versions do not have this. Dynamically check the version - // of Qt since it's just an enumerant. Versions 5.6.0 and later have - // high dpi support. We really don't need to check the 5, but for - // the sake of completeness and mabye compatibility with qt 6. - // Also ignoring the trailing point releases - const char* version = qVersion(); - int version_major, version_minor; - sscanf(version, "%d.%d", &version_major, &version_minor); - if (version_major >= 5 && version_minor >= 6) { - // Qt::AA_EnableHighDpiScaling = 20 from qnamespace.h in Qt 5.6 or later - QCoreApplication::setAttribute((Qt::ApplicationAttribute)20); - } + // Qt::AA_EnableHighDpiScaling = 20 from qnamespace.h in Qt 5.6 or later + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); // This has to go after the construction of QApplication in // order to use a QMessageBox and avoid some QThread warnings. ApplicationSingleton singleton("vkconfig_single_instance"); - while (!singleton.IsFirstInstance()) { - if (Alert::ConfiguratorSingleton() == QMessageBox::Cancel) { + if (Alert::StartSingleton() == QMessageBox::Cancel) { return -1; } } - // We simply cannot run without any layers - Configurator& configurator = Configurator::Get(command_line.command_vulkan_sdk); + Configurator& configurator = Configurator::Get(); + + // Make sure layers configuration is deleted otherwise BuildVulkanSystemInfo() will crash... (unexplained) + configurator.Surrender(); + + const VulkanSystemInfo& vulkan_info = BuildVulkanSystemInfo(); - if (!configurator.Init()) return -1; + if (vulkan_info.loaderVersion == Version::VERSION_NULL) { + Alert::StartLoaderFailure(); + return -1; + } + + if (vulkan_info.loaderVersion < REQUIRED_LOADER_VERSION) { + Alert::StartLoaderIncompatibleVersions(vulkan_info.loaderVersion, REQUIRED_LOADER_VERSION); + return -1; + } + + if (vulkan_info.physicalDevices.empty()) { + Alert::StartPhysicalDeviceFailure(); + return -1; + } + + if (!configurator.Init()) { + return -1; + } // The main GUI is driven here MainWindow main_window; diff --git a/vkconfig3/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp similarity index 82% rename from vkconfig3/mainwindow.cpp rename to vkconfig_gui/mainwindow.cpp index f7b6d9c519..9192e78fed 100644 --- a/vkconfig3/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -23,18 +23,17 @@ #include "dialog_vulkan_analysis.h" #include "dialog_vulkan_info.h" -#include "dialog_applications.h" - -#include "configurator.h" -#include "vulkan_util.h" +#include "../vkconfig_core/configurator.h" #include "../vkconfig_core/alert.h" #include "../vkconfig_core/util.h" #include "../vkconfig_core/version.h" -#include "../vkconfig_core/platform.h" #include "../vkconfig_core/help.h" #include "../vkconfig_core/doc.h" #include "../vkconfig_core/date.h" +#include "../vkconfig_core/type_platform.h" +#include "../vkconfig_core/type_log.h" +#include "../vkconfig_core/type_hide_message.h" #include #include @@ -44,7 +43,6 @@ #include #include #include -#include #include #include @@ -52,8 +50,6 @@ static const char *TEXT_EXECUTE_CLOSER_APPLICATION = "Execute Closer to the Vulkan Application"; static const char *TEXT_EXECUTE_CLOSER_DRIVER = "Execute Closer to the Vulkan Driver"; -enum Tab { TAB_DIAGNOSTIC = 0, TAB_APPLICATIONS, TAB_LAYERS, TAB_CONFIGURATIONS, TAB_PREFERENCES, TAB_HELP }; - #if VKC_PLATFORM == VKC_PLATFORM_LINUX || VKC_PLATFORM == VKC_PLATFORM_MACOS #include @@ -126,6 +122,94 @@ static const int LAUNCH_ROW_HEIGHT = 26; static const int LAUNCH_ROW_HEIGHT = 28; #endif +/* TODO + +Path PathManager::SelectPathImpl(QWidget* parent, PathType path, const Path& suggested_path) { + assert(parent); + assert(path >= PATH_FIRST && path <= PATH_LAST); + assert(!suggested_path.Empty()); + + switch (path) { + case PATH_LAUNCHER_LOG_FILE: { + const std::string selected_path = + QFileDialog::getSaveFileName(parent, "Set Log File To...", suggested_path.AbsolutePath().c_str(), "Log text(*.txt)") + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); + return GetFullPath(path, QFileInfo(selected_path.c_str()).baseName().toStdString()); + } break; + case PATH_EXECUTABLE: { + static const char* TABLE[] = { + "Applications (*.exe)", // PLATFORM_WINDOWS + "Applications (*)", // PLATFORM_LINUX + "Applications (*.app, *)", // PLATFORM_MACOS + "N/A" // PLATFORM_ANDROID + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT, + "The tranlation table size doesn't match the enum number of elements"); + + const std::string filter = TABLE[VKC_PLATFORM]; + const std::string selected_path = QFileDialog::getOpenFileName(parent, "Select a Vulkan Executable...", + suggested_path.AbsolutePath().c_str(), filter.c_str()) + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); + return GetFullPath(path, QFileInfo(selected_path.c_str()).fileName().toStdString()); + } + case PATH_WORKING_DIR: { + const std::string selected_path = + QFileDialog::getExistingDirectory(parent, "Set Working Folder To...", suggested_path.AbsolutePath().c_str()) + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, selected_path); + return Path(GetPath(path)); + } + case PATH_USER_DEFINED_LAYERS_GUI: { + const std::string selected_path = + QFileDialog::getExistingDirectory(parent, "Add User-Defined Layers Folder...", + suggested_path.AbsolutePath().c_str(), QFileDialog::DontUseNativeDialog) + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, selected_path); + return Path(GetPath(path)); + } + case PATH_IMPORT_CONFIGURATION: { + const std::string selected_path = + QFileDialog::getOpenFileName(parent, "Import Layers Configuration File", suggested_path.AbsolutePath().c_str(), + "JSON configuration(*.json)") + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); + return Path(selected_path); + } + case PATH_EXPORT_CONFIGURATION: { + const std::string selected_path = + QFileDialog::getSaveFileName(parent, "Export Layers Configuration File", suggested_path.AbsolutePath().c_str(), + "JSON configuration(*.json)") + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); + return Path(selected_path); + } + default: + assert(0); + return Path(""); + } +} +*/ + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _launch_application(nullptr), @@ -146,8 +230,7 @@ MainWindow::MainWindow(QWidget *parent) _tray_layers_controlled_by_configurator(nullptr), _tray_layers_disabled_by_configurator(nullptr), _tray_quit_action(nullptr), - ui(new Ui::MainWindow), - been_warned_about_old_loader(false) { + ui(new Ui::MainWindow) { ui->setupUi(this); ui->launcher_tree->installEventFilter(this); ui->configurations_tree->installEventFilter(this); @@ -198,21 +281,40 @@ MainWindow::MainWindow(QWidget *parent) Configurator &configurator = Configurator::Get(); Environment &environment = configurator.environment; - // Restore window geometry from last launch - // restoreGeometry(environment.Get(VKCONFIG3_LAYOUT_MAIN_GEOMETRY)); - // restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_WINDOW_STATE)); - // ui->splitter_main->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER1)); - // ui->splitter_configurations->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER2)); - // ui->splitter_settings->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER3)); + ui->combo_box_mode->setCurrentIndex(environment.GetActiveConfigurationInfo().GetMode()); + + // Update configuration application area + + if (environment.GetApplications().empty()) { + environment.SetPerApplicationConfig(false); - // Update launcher - const Application &application = configurator.environment.GetApplication(0); - ui->edit_executable->setText(application.executable_path.c_str()); - ui->edit_dir->setText(application.working_folder.c_str()); - ui->edit_arguments->setText(application.arguments.c_str()); - ui->edit_env->setText(application.env.c_str()); - ui->edit_log->setText(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); + ui->check_box_per_application->setEnabled(false); + ui->check_box_per_application->setVisible(false); + ui->combo_box_applications->setVisible(false); + } else { + ui->check_box_per_application->setEnabled(true); + + ui->combo_box_applications->blockSignals(true); + ui->combo_box_applications->clear(); + for (std::size_t i = 0, n = environment.GetApplications().size(); i < n; ++i) { + const Application &application = environment.GetApplications()[i]; + + ui->combo_box_applications->addItem(application.executable_path.RelativePath().c_str()); + } + ui->combo_box_applications->blockSignals(false); + this->on_check_box_per_application_toggled(environment.GetPerApplicationConfig()); + this->on_combo_box_applications_currentIndexChanged(environment.GetActiveApplicationIndex()); + ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); + } + + // ui->edit_executable->setText(application.executable_path.c_str()); + /* + ui->edit_dir->setText(application.working_folder.c_str()); + ui->edit_arguments->setText(application.arguments.c_str()); + ui->edit_env->setText(application.env.c_str()); + ui->edit_log->setText(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); + */ ui->execute_closer_application_label->setVisible(true); ui->execute_closer_driver_label->setVisible(true); @@ -228,7 +330,12 @@ MainWindow::MainWindow(QWidget *parent) ui->log_browser->document()->setMaximumBlockCount(2048); // ui->configuration_tree->scrollToItem(ui->configuration_tree->topLevelItem(0), QAbstractItemView::PositionAtTop); - ui->check_box_per_application->setChecked(configurator.environment.GetPerApplicationConfig()); + // Restore window geometry from last launch + // restoreGeometry(environment.Get(VKCONFIG3_LAYOUT_MAIN_GEOMETRY)); + // restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_WINDOW_STATE)); + // ui->splitter_main->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER1)); + // ui->splitter_configurations->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER2)); + // ui->splitter_settings->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER3)); this->InitTray(); this->UpdateTray(); @@ -282,33 +389,28 @@ void MainWindow::UpdateTray() { if (QSystemTrayIcon::isSystemTrayAvailable()) { // QApplication::setQuitOnLastWindowClosed(!ui->check_box_persistent->isChecked()); - Configurator &configurator = Configurator::Get(); - - const Environment &environment = configurator.environment; + const Environment &environment = Configurator::Get().environment; - const bool use_override = environment.GetMode() != LAYERS_MODE_BY_APPLICATIONS; - const bool active = configurator.configurations.HasActiveConfiguration(configurator.layers.selected_layers) && use_override; - - switch (environment.GetMode()) { + switch (environment.GetActiveConfigurationInfo().GetMode()) { default: - case LAYERS_MODE_BY_APPLICATIONS: + case LAYERS_CONTROLLED_BY_APPLICATIONS: this->_tray_layers_controlled_by_applications->setChecked(true); this->_tray_layers_controlled_by_configurator->setChecked(false); this->_tray_layers_disabled_by_configurator->setChecked(false); break; - case LAYERS_MODE_BY_CONFIGURATOR_RUNNING: + case LAYERS_CONTROLLED_BY_CONFIGURATOR: this->_tray_layers_controlled_by_applications->setChecked(false); this->_tray_layers_controlled_by_configurator->setChecked(true); this->_tray_layers_disabled_by_configurator->setChecked(false); break; - case LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED: + case LAYERS_DISABLED_BY_CONFIGURATOR: this->_tray_layers_controlled_by_applications->setChecked(false); this->_tray_layers_controlled_by_configurator->setChecked(false); this->_tray_layers_disabled_by_configurator->setChecked(true); break; } - if (active) { + if (environment.global_configuration.GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { const QIcon icon(":/resourcefiles/vkconfig-on.png"); this->setWindowIcon(icon); @@ -361,8 +463,13 @@ void MainWindow::trayActionRestore() { void MainWindow::trayActionControlledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.SetMode(LAYERS_MODE_BY_APPLICATIONS); - configurator.configurations.Configure(configurator.layers.selected_layers); + + if (configurator.environment.GetPerApplicationConfig()) { + configurator.environment.GetActiveApplication().configuration.SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); + } else { + configurator.environment.global_configuration.SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); + } + configurator.Override(); this->UpdateUI(); this->UpdateTray(); @@ -372,8 +479,12 @@ void MainWindow::trayActionControlledByApplications(bool checked) { void MainWindow::trayActionControlledByConfigurator(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.SetMode(LAYERS_MODE_BY_CONFIGURATOR_RUNNING); - configurator.configurations.Configure(configurator.layers.selected_layers); + + if (configurator.environment.GetPerApplicationConfig()) { + configurator.environment.GetActiveApplication().configuration.SetMode(LAYERS_CONTROLLED_BY_CONFIGURATOR); + } else { + configurator.environment.global_configuration.SetMode(LAYERS_CONTROLLED_BY_CONFIGURATOR); + } this->UpdateUI(); this->UpdateTray(); @@ -383,8 +494,14 @@ void MainWindow::trayActionControlledByConfigurator(bool checked) { void MainWindow::trayActionDisabledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.SetMode(LAYERS_MODE_BY_CONFIGURATOR_ALL_DISABLED); - configurator.configurations.Configure(configurator.layers.selected_layers); + + if (configurator.environment.GetPerApplicationConfig()) { + configurator.environment.GetActiveApplication().configuration.SetMode(LAYERS_DISABLED_BY_CONFIGURATOR); + } else { + configurator.environment.global_configuration.SetMode(LAYERS_DISABLED_BY_CONFIGURATOR); + } + + configurator.Override(); this->UpdateUI(); this->UpdateTray(); @@ -393,21 +510,14 @@ void MainWindow::trayActionDisabledByApplications(bool checked) { static std::string GetMainWindowTitle(bool active) { #if VKCONFIG_DATE - std::string title = format("%s %s-%s", VKCONFIG_NAME, Version::VKCONFIG3.str().c_str(), GetBuildDate().c_str()); + std::string title = format("%s %s-%s", VKCONFIG_NAME, Version::VKCONFIG.str().c_str(), GetBuildDate().c_str()); #else - std::string title = format("%s %s", VKCONFIG_NAME, Version::VKCONFIG3.str().c_str()); + std::string title = format("%s %s", VKCONFIG_NAME, Version::VKCONFIG.str().c_str()); #endif if (active) title += " "; return title; } -void MainWindow::InitUI() { - Configurator &configurator = Configurator::Get(); - const Environment &environment = configurator.environment; - - ui->combo_box_mode->setCurrentIndex(environment.GetMode()); -} - void MainWindow::AddLayerPathItem(const std::string &layer_path) { TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(layer_path.c_str()); @@ -421,7 +531,7 @@ void MainWindow::AddLayerPathItem(const std::string &layer_path) { ui->tree_layers_paths->setItemWidget(item_state, layer_path_widget); } -void MainWindow::AddLayerItem(const Parameter ¶meter) { +void MainWindow::AddLayerItem(Parameter ¶meter) { assert(!parameter.key.empty()); std::vector &available_layers = Configurator::Get().layers.selected_layers; @@ -438,15 +548,17 @@ void MainWindow::AddLayerItem(const Parameter ¶meter) { decorated_name += format(" (%s)", GetToken(layer->status)); } - if (IsDLL32Bit(layer->manifest_path)) { + if (IsDLL32Bit(layer->manifest_path.AbsolutePath())) { decorated_name += " (32-bit)"; } } else { // A layers configuration may have excluded layer that are misssing because they are not available on this platform // We simply hide these layers to avoid confusing the Vulkan developers - if (parameter.state == LAYER_STATE_EXCLUDED) return; + if (parameter.control == LAYER_CONTROL_OFF) { + return; + } - if (parameter.control != LAYER_STATE_APPLICATION_CONTROLLED && parameter.control != LAYER_CONTROL_UNORDERED) { + if (parameter.control != LAYER_CONTROL_APPLICATIONS && parameter.control != LAYER_CONTROL_UNORDERED) { decorated_name += " (Missing)"; } } @@ -462,47 +574,10 @@ void MainWindow::AddLayerItem(const Parameter ¶meter) { layers.push_back(layer); } - LayerWidget *layer_widget = new LayerWidget(layers, parameter, ui->layers_tree, item_state); + ConfigurationLayerWidget *layer_widget = new ConfigurationLayerWidget(layers, parameter); item_state->widget = layer_widget; ui->layers_tree->setItemWidget(item_state, layer_widget); - - // item_state->setDisabled(layer == nullptr); - - // item_state->layer_state->addItem(is_implicit_layer ? "Implicitly On" : "Application-Controlled"); - // item_state->layer_state->addItem("Forced On"); - // item_state->layer_state->addItem("Forced Off"); - - /* - const QFontMetrics fm = ui->tree_layers_list->fontMetrics(); - const QSize combo_name_size = fm.size(Qt::TextSingleLine, parameter.key.c_str()) * 1.2; - item_state->setSizeHint(0, combo_name_size); - - const QSize combo_version_size = fm.size(Qt::TextSingleLine, layer->api_version.str().c_str()); - item_state->setSizeHint(1, combo_version_size); - - const QSize combo_state_size = fm.size(Qt::TextSingleLine, "Application-Controlled"); - item_state->setSizeHint(2, combo_state_size); - */ - // Add the top level item - - // Add a combo box. Default has gray background which looks hidious - // WidgetTreeFriendlyComboBox *widget_version = new WidgetTreeFriendlyComboBox(item_state); - // ui->tree_layers_list->setItemWidget(item_state, 1, widget_version); - - // widget_version->addItem(layer->api_version.str().c_str()); - - // WidgetTreeFriendlyComboBox *widget_state = new WidgetTreeFriendlyComboBox(item_state); - // ui->tree_layers_list->setItemWidget(item_state, 2, widget_state); - - /* - widget_state->addItem(is_implicit_layer ? "Implicitly On" : "Application-Controlled"); - widget_state->addItem("Forced On"); - widget_state->addItem("Forced Off"); - widget_state->setCurrentIndex(parameter.state); - - connect(widget_state, SIGNAL(selectionMade(QListWidgetItem *, int)), this, SLOT(layerUseChanged(QListWidgetItem *, int))); - */ } void MainWindow::UpdateUI() { @@ -512,21 +587,24 @@ void MainWindow::UpdateUI() { Configurator &configurator = Configurator::Get(); const Environment &environment = Configurator::Get().environment; - const std::string &selected_contiguration_name = environment.GetSelectedConfiguration(); + const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); const bool has_selected_configuration = !selected_contiguration_name.empty(); this->blockSignals(true); ui->configurations_tree->blockSignals(true); // Add applications + ui->combo_box_applications->blockSignals(true); + ui->combo_box_applications->clear(); ui->combo_box_applications->setEnabled(ui->check_box_per_application->isChecked()); const std::vector &applications = environment.GetApplications(); for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - ui->combo_box_applications->addItem(ReplaceBuiltInVariable(applications[i].executable_path.c_str()).c_str()); + ui->combo_box_applications->addItem(applications[i].executable_path.AbsolutePath().c_str()); } ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); + ui->combo_box_applications->blockSignals(false); - const bool has_active_configuration = configurator.configurations.HasActiveConfiguration(configurator.layers.selected_layers); + const bool has_active_configuration = configurator.HasActiveConfiguration(); // Mode states this->UpdateTray(); @@ -606,18 +684,16 @@ void MainWindow::UpdateUI() { ui->push_button_settings->setEnabled(has_selected_configuration); ui->push_button_export->setEnabled(has_selected_configuration); - // Load Layers paths - std::vector layer_paths = configurator.layers.BuildPathList(); - // ui->tree_layers_paths->setEnabled(enable_layer_ui); ui->tree_layers_paths->clear(); + /* + std::vector layer_paths = configurator.layers.BuildPathList(); + for (std::size_t path_index = 0, count = layer_paths.size(); path_index < count; ++path_index) { + const std::string user_defined_path(layer_paths[path_index].RelativePath().c_str()); - for (std::size_t path_index = 0, count = layer_paths.size(); path_index < count; ++path_index) { - const std::string user_defined_path(ConvertNativeSeparators(layer_paths[path_index])); - - AddLayerPathItem(user_defined_path); - } - + AddLayerPathItem(user_defined_path); + } + */ ui->tree_layers_paths->update(); // Load Layers items @@ -676,7 +752,7 @@ void MainWindow::UpdateUI() { */ _launcher_apps_combo->blockSignals(true); _launcher_apps_combo->clear(); - + /* if (applications.empty()) { _launcher_executable->setText(""); _launcher_arguments->setText(""); @@ -694,7 +770,7 @@ void MainWindow::UpdateUI() { _launcher_working->setText(application.working_folder.c_str()); _launcher_log_file_edit->setText(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); } - + */ _launcher_apps_combo->blockSignals(false); // Handle persistent states @@ -740,7 +816,7 @@ void MainWindow::UpdateUI() { _launcher_log_file_edit->setEnabled(has_application_list); } - ui->settings_tree->setEnabled(environment.GetMode() == LAYERS_MODE_BY_CONFIGURATOR_RUNNING && has_selected_configuration); + // ui->settings_tree->setEnabled(environment.GetMode() == LAYERS_MODE_CONTROLLED_BY_CONFIGURATOR && has_selected_configuration); if (has_selected_configuration) { this->_settings_tree_manager.CreateGUI(ui->settings_tree); } else { @@ -913,15 +989,10 @@ void MainWindow::on_check_box_apply_list_clicked() { void MainWindow::on_combo_box_mode_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); - if (configurator.environment.GetPerApplicationConfig()) { - Application &application = configurator.environment.GetApplication(configurator.environment.GetActiveApplicationIndex()); - application.layers_mode = static_cast(index); - } else { - configurator.environment.SetMode(static_cast(index)); - configurator.ActivateConfiguration(configurator.environment.GetSelectedConfiguration()); - } + configurator.environment.GetActiveConfigurationInfo().SetMode(static_cast(index)); + configurator.Override(); - const bool enabled_ui = index == LAYERS_MODE_BY_CONFIGURATOR_RUNNING; + const bool enabled_ui = index == LAYERS_CONTROLLED_BY_CONFIGURATOR; ui->group_box_configurations->setEnabled(enabled_ui); ui->group_box_settings->setEnabled(enabled_ui); @@ -932,9 +1003,9 @@ void MainWindow::on_combo_box_applications_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); configurator.environment.SelectActiveApplication(index); - Application &application = configurator.environment.GetApplication(configurator.environment.GetActiveApplicationIndex()); - ui->combo_box_applications->setToolTip(ReplaceBuiltInVariable(application.executable_path.c_str()).c_str()); - ui->combo_box_mode->setCurrentIndex(application.layers_mode); + Application &application = configurator.environment.GetApplication(index); + ui->combo_box_applications->setToolTip(application.executable_path.AbsolutePath().c_str()); + ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); } void MainWindow::on_check_box_per_application_toggled(bool checked) { @@ -942,12 +1013,7 @@ void MainWindow::on_check_box_per_application_toggled(bool checked) { configurator.environment.SetPerApplicationConfig(checked); ui->combo_box_applications->setEnabled(configurator.environment.GetPerApplicationConfig()); - if (checked) { - Application &application = configurator.environment.GetApplication(configurator.environment.GetActiveApplicationIndex()); - ui->combo_box_mode->setCurrentIndex(application.layers_mode); - } else { - ui->combo_box_mode->setCurrentIndex(configurator.environment.GetMode()); - } + ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); } void MainWindow::on_check_box_clear_on_launch_clicked() { @@ -982,7 +1048,9 @@ void MainWindow::OnConfigurationItemClicked(bool checked) { // to ensure the new item is "selected" // ui->tree_configurations->setCurrentItem(item); - Configurator::Get().ActivateConfiguration(configuration_item->configuration_name); + Configurator &configurator = Configurator::Get(); + configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); + configurator.Override(); UpdateUI(); } @@ -990,9 +1058,12 @@ void MainWindow::OnConfigurationItemClicked(bool checked) { void MainWindow::OnConfigurationTreeClicked(QTreeWidgetItem *item, int column) { (void)column; + Configurator &configurator = Configurator::Get(); + ConfigurationListItem *configuration_item = dynamic_cast(item); if (configuration_item != nullptr) { - Configurator::Get().ActivateConfiguration(configuration_item->configuration_name); + configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); + configurator.Override(); } UpdateUI(); @@ -1043,9 +1114,8 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { // Rename configuration ; Remove old configuration file ; change the name of the configuration configurator.configurations.RemoveConfigurationFile(old_name); configuration->key = configuration_item->configuration_name = new_name; - configurator.configurations.SaveAllConfigurations(configurator.layers.selected_layers); - - configurator.ActivateConfiguration(new_name); + configurator.configurations.SaveAllConfigurations(); + configurator.environment.GetActiveConfigurationInfo().SetName(new_name); LoadConfigurationList(); } else { @@ -1055,9 +1125,11 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { item->setText(1, old_name.c_str()); ui->configurations_tree->blockSignals(false); - configurator.ActivateConfiguration(old_name); + configurator.environment.GetActiveConfigurationInfo().SetName(old_name); } + configurator.Override(); + this->UpdateUI(); } } @@ -1077,8 +1149,10 @@ void MainWindow::OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidge configuration_item->radio_button->setChecked(true); Configurator &configurator = Configurator::Get(); - if (configurator.environment.GetSelectedConfiguration() != configuration_item->configuration_name) { - configurator.ActivateConfiguration(configuration_item->configuration_name); + if (configurator.environment.GetActiveConfigurationInfo().GetName() != configuration_item->configuration_name) { + configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); + + configurator.Override(); this->UpdateUI(); } } @@ -1086,9 +1160,7 @@ void MainWindow::OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidge void MainWindow::StartTool(Tool tool) { Configurator &configurator = Configurator::Get(); - LayersMode saved_mode = configurator.environment.GetMode(); - configurator.environment.SetMode(LAYERS_MODE_BY_APPLICATIONS); - configurator.configurations.Configure(configurator.layers.selected_layers); + configurator.Surrender(); switch (tool) { case TOOL_VULKAN_INFO: @@ -1099,8 +1171,7 @@ void MainWindow::StartTool(Tool tool) { break; } - configurator.environment.SetMode(saved_mode); - configurator.configurations.Configure(configurator.layers.selected_layers); + configurator.Override(); } /// Create the VulkanInfo dialog if it doesn't already exits & show it. @@ -1161,11 +1232,10 @@ void MainWindow::closeEvent(QCloseEvent *event) { // Alert the user to the current state of the vulkan configurator and // give them the option to not shutdown. if (environment.GetUseSystemTray()) { - QSettings settings; - if (!settings.value("vkconfig_system_tray", false).toBool()) { + if (environment.hide_message_boxes_flags & GetBit(HIDE_MESSAGE_USE_SYSTEM_TRAY)) { std::string shut_down_state; - if (environment.GetMode() == LAYERS_MODE_BY_CONFIGURATOR_RUNNING) { + if (environment.GetActiveConfigurationInfo().GetMode() == LAYERS_CONTROLLED_BY_CONFIGURATOR) { shut_down_state = "Vulkan Layers override will remain in effect while Vulkan Configurator remain active in the system tray."; } else { @@ -1182,7 +1252,9 @@ void MainWindow::closeEvent(QCloseEvent *event) { alert.setInformativeText("Are you still ready to move Vulkan Configurator in the system tray?"); int ret_val = alert.exec(); - settings.setValue("vkconfig_system_tray", alert.checkBox()->isChecked()); + if (alert.checkBox()->isChecked()) { + environment.hide_message_boxes_flags |= GetBit(HIDE_MESSAGE_USE_SYSTEM_TRAY); + } if (ret_val == QMessageBox::No) { event->ignore(); @@ -1229,11 +1301,11 @@ void MainWindow::showEvent(QShowEvent *event) { /// Edit the list of apps that can be filtered. void MainWindow::on_push_button_applications_clicked() { - ApplicationsDialog dlg(this); - dlg.exec(); + // ApplicationsDialog dlg(this); + // dlg.exec(); Configurator &configurator = Configurator::Get(); - configurator.configurations.Configure(configurator.layers.selected_layers); + configurator.Override(); UpdateUI(); } @@ -1250,21 +1322,25 @@ void MainWindow::on_push_button_rename_clicked() { } void MainWindow::on_push_button_remove_clicked() { - Configurator &configurator = Configurator::Get(); + ConfigurationListItem *configuration_item = GetCheckedItem(); + if (configuration_item == nullptr) { + return; + } - this->RemoveConfiguration(configurator.environment.GetSelectedConfiguration()); + this->RemoveConfiguration(configuration_item->configuration_name); } void MainWindow::on_push_button_duplicate_clicked() { Configurator &configurator = Configurator::Get(); - Configuration *configutation = configurator.configurations.FindActiveConfiguration(); + const Configuration *configutation = configurator.GetActiveConfiguration(); assert(configutation != nullptr); const Configuration &duplicated_configuration = configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, configutation->key, true); - configurator.ActivateConfiguration(duplicated_configuration.key); + configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); + configurator.Override(); LoadConfigurationList(); @@ -1277,7 +1353,8 @@ void MainWindow::NewClicked() { Configuration &new_configuration = configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); - configurator.ActivateConfiguration(new_configuration.key); + configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); + configurator.Override(); LoadConfigurationList(); } @@ -1299,7 +1376,7 @@ void MainWindow::RemoveConfiguration(const std::string &configuration_name) { Configurator &configurator = Configurator::Get(); configurator.configurations.RemoveConfiguration(configurator.layers.selected_layers, configuration_name); - configurator.environment.SetSelectedConfiguration(""); + configurator.environment.GetActiveConfigurationInfo().SetName(""); LoadConfigurationList(); @@ -1341,7 +1418,7 @@ void MainWindow::ResetClicked(ConfigurationListItem *item) { alert.setIcon(QMessageBox::Warning); if (alert.exec() == QMessageBox::No) return; - configuration->Reset(configurator.layers.selected_layers, configurator.path); + configuration->Reset(configurator.layers.selected_layers); LoadConfigurationList(); } @@ -1362,7 +1439,8 @@ void MainWindow::DuplicateClicked(ConfigurationListItem *item) { item->configuration_name = duplicated_configuration.key; - configurator.ActivateConfiguration(duplicated_configuration.key); + configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); + configurator.Override(); LoadConfigurationList(); @@ -1387,10 +1465,15 @@ void MainWindow::ImportClicked(ConfigurationListItem *item) { Configurator &configurator = Configurator::Get(); - const std::string full_import_path = configurator.path.SelectPath(this, PATH_IMPORT_CONFIGURATION); - if (full_import_path.empty()) return; + const Path &path_import = configurator.environment.path_import; + /* + const Path full_import_path = configurator.path.SelectPath(this, PATH_IMPORT_CONFIGURATION); + if (full_import_path.Empty()) { + return; + } configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, full_import_path); + */ LoadConfigurationList(); } @@ -1399,25 +1482,16 @@ void MainWindow::ExportClicked(ConfigurationListItem *item) { Configurator &configurator = Configurator::Get(); - const std::string full_suggested_path = configurator.path.GetFullPath(PATH_EXPORT_CONFIGURATION, item->configuration_name); - const std::string full_export_path = configurator.path.SelectPath(this, PATH_EXPORT_CONFIGURATION, full_suggested_path); - if (full_export_path.empty()) return; + const Path &path_export = configurator.environment.path_export; + /* TODO + const Path full_export_path = configurator.path.SelectPath(this, PATH_EXPORT_CONFIGURATION, full_suggested_path); + if (full_export_path.Empty()) { + return; + } configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, full_export_path, item->configuration_name); -} - -void MainWindow::ReloadDefaultClicked(ConfigurationListItem *item) { - (void)item; - - if (Alert::ConfiguratorReloadDefault() == QMessageBox::Yes) { - _settings_tree_manager.CleanupGUI(); - - Configurator &configurator = Configurator::Get(); - configurator.configurations.ReloadDefaultsConfigurations(configurator.layers.selected_layers); - - LoadConfigurationList(); - } + */ } void MainWindow::editorExpanded(QTreeWidgetItem *item) { @@ -1436,7 +1510,8 @@ void MainWindow::OnSettingsTreeClicked(QTreeWidgetItem *item, int column) { (void)item; Configurator &configurator = Configurator::Get(); - configurator.configurations.Configure(configurator.layers.selected_layers); + configurator.environment.GetActiveConfigurationInfo().ForceUpdate(UPDATE_LAYERS_SETTINGS_BIT); + configurator.Override(); } void MainWindow::SetupLauncherTree() { @@ -1570,7 +1645,7 @@ void MainWindow::OnLauncherLoaderMessageChanged(int level) { Configurator &configurator = Configurator::Get(); // configurator.environment.SetLoaderMessage(static_cast(level)); - configurator.environment.SetLoaderMessageTypes(GetLoaderMessageFlags(static_cast(level))); + // configurator.environment.SetLoaderMessageFlags(GetBit(static_cast(level))); if (ui->check_box_clear_on_launch->isChecked()) { this->UpdateUI(); @@ -1583,13 +1658,17 @@ void MainWindow::launchSetExecutable() { Configurator &configurator = Configurator::Get(); Application &application = configurator.environment.GetApplication(current_application_index); - const std::string exe = configurator.path.SelectPath(this, PATH_EXECUTABLE, application.executable_path.c_str()); + /* TODO + const Path exe = configurator.path.SelectPath(this, PATH_EXECUTABLE, application.executable_path); // The user has cancel the operation - if (exe.empty()) return; + if (exe.Empty()) { + return; + } application.executable_path = exe; - _launcher_executable->setText(exe.c_str()); + */ + _launcher_executable->setText(application.executable_path.RelativePath().c_str()); } void MainWindow::launchSetLogFile() { @@ -1598,13 +1677,18 @@ void MainWindow::launchSetLogFile() { Configurator &configurator = Configurator::Get(); Application &application = configurator.environment.GetApplication(current_application_index); - const std::string path = configurator.path.SelectPath(this, PATH_LAUNCHER_LOG_FILE, application.log_file.c_str()); + ApplicationOptions &options = application.GetActiveOptions(); + /* TODO + const Path &path = configurator.path.SelectPath(this, PATH_LAUNCHER_LOG_FILE, options.log_file); // The user has cancel the operation - if (path.empty()) return; + if (path.Empty()) { + return; + } - application.log_file = path; - _launcher_log_file_edit->setText(path.c_str()); + options.log_file = path; + */ + _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); } void MainWindow::launchSetWorkingFolder() { @@ -1613,13 +1697,19 @@ void MainWindow::launchSetWorkingFolder() { Configurator &configurator = Configurator::Get(); Application &application = configurator.environment.GetApplication(current_application_index); - const std::string path = configurator.path.SelectPath(this, PATH_WORKING_DIR, application.working_folder.c_str()); + ApplicationOptions &options = application.GetActiveOptions(); + + /* TODO + const Path path = configurator.path.SelectPath(this, PATH_WORKING_DIR, options.working_folder); // The user has cancel the operation - if (path.empty()) return; + if (path.Empty()) { + return; + } - application.working_folder = path; - _launcher_working->setText(path.c_str()); + options.working_folder = path; + */ + _launcher_working->setText(options.working_folder.RelativePath().c_str()); } // Log file path edited manually. @@ -1628,7 +1718,8 @@ void MainWindow::launchChangeLogFile(const QString &log_file) { assert(current_application_index >= 0); Application &application = Configurator::Get().environment.GetApplication(current_application_index); - application.log_file = log_file.toStdString(); + ApplicationOptions &options = application.GetActiveOptions(); + options.log_file = log_file.toStdString(); } void MainWindow::launchChangeExecutable(const QString &exe) { @@ -1644,7 +1735,8 @@ void MainWindow::launchChangeWorkingFolder(const QString &working_folder) { assert(current_application_index >= 0); Application &application = Configurator::Get().environment.GetApplication(current_application_index); - application.working_folder = working_folder.toStdString(); + ApplicationOptions &options = application.GetActiveOptions(); + options.working_folder = working_folder.toStdString(); } // Launch app change @@ -1656,10 +1748,12 @@ void MainWindow::launchItemChanged(int application_index) { environment.SelectActiveApplication(application_index); Application &application = environment.GetApplication(application_index); - _launcher_executable->setText(application.executable_path.c_str()); - _launcher_working->setText(application.working_folder.c_str()); - _launcher_arguments->setText(application.arguments.c_str()); - _launcher_log_file_edit->setText(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); + ApplicationOptions &options = application.GetActiveOptions(); + + _launcher_executable->setText(application.executable_path.RelativePath().c_str()); + _launcher_working->setText(options.working_folder.RelativePath().c_str()); + _launcher_arguments->setText(Merge(options.arguments, " ").c_str()); + _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); } /// New command line arguments. Update them. @@ -1668,7 +1762,8 @@ void MainWindow::launchArgsEdited(const QString &arguments) { if (application_index < 0) return; Application &application = Configurator::Get().environment.GetApplication(application_index); - application.arguments = arguments.toStdString(); + ApplicationOptions &options = application.GetActiveOptions(); + options.arguments = SplitSpace(arguments.toStdString()); } // Clear the browser window @@ -1791,11 +1886,11 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { } else if (action == visit_layer_website_action) { QDesktopServices::openUrl(QUrl(layer->url.c_str())); } else if (action == export_html_action) { - const std::string path = format("%s/%s.html", GetPath(BUILTIN_PATH_APPDATA).c_str(), layer->key.c_str()); + const std::string path = format("%s/%s.html", AbsolutePath(Path::APPDATA).c_str(), layer->key.c_str()); ExportHtmlDoc(*layer, path); QDesktopServices::openUrl(QUrl(("file:///" + path).c_str())); } else if (action == export_markdown_action) { - const std::string path = format("%s/%s.md", GetPath(BUILTIN_PATH_APPDATA).c_str(), layer->key.c_str()); + const std::string path = format("%s/%s.md", AbsolutePath(Path::APPDATA).c_str(), layer->key.c_str()); ExportMarkdownDoc(*layer, path); QDesktopServices::openUrl(QUrl(("file:///" + path).c_str())); } @@ -1820,7 +1915,7 @@ QStringList MainWindow::BuildEnvVariables() const { Configurator &configurator = Configurator::Get(); QStringList env = QProcess::systemEnvironment(); - env << (QString("VK_LOADER_DEBUG=") + ::GetLoaderMessageTokens(configurator.environment.GetLoaderMessageTypes()).c_str()); + env << (QString("VK_LOADER_DEBUG=") + ::GetLogString(configurator.environment.GetLoaderMessageFlags()).c_str()); return env; } @@ -1854,37 +1949,37 @@ void MainWindow::on_push_button_launcher_clicked() { Configurator &configurator = Configurator::Get(); const Application &active_application = configurator.environment.GetActiveApplication(); - assert(!active_application.app_name.empty()); - launch_log += format("- Application: %s\n", active_application.app_name.c_str()); - assert(!active_application.executable_path.empty()); - - launch_log += format("- Executable: %s\n", ReplaceBuiltInVariable(_launcher_executable->text().toStdString()).c_str()); - if (!QFileInfo(ReplaceBuiltInVariable(_launcher_executable->text().toStdString()).c_str()).exists()) { - Alert::PathInvalid(ReplaceBuiltInVariable(_launcher_executable->text().toStdString()).c_str(), - format("The '%s' application will fail to launch.", active_application.app_name.c_str()).c_str()); + assert(!active_application.executable_path.Empty()); + launch_log += format("- Executable: %s\n", active_application.executable_path.AbsolutePath().c_str()); + if (!active_application.executable_path.Exists()) { + Alert::PathInvalid( + active_application.executable_path, + format("The '%s' application will fail to launch.", active_application.executable_path.AbsolutePath().c_str()).c_str()); } - launch_log += format("- Working Directory: %s\n", ReplaceBuiltInVariable(_launcher_working->text().toStdString()).c_str()); - if (!QFileInfo(ReplaceBuiltInVariable(_launcher_working->text().toStdString()).c_str()).exists()) { - Alert::PathInvalid(ReplaceBuiltInVariable(_launcher_working->text().toStdString()).c_str(), - format("The '%s' application will fail to launch.", active_application.app_name.c_str()).c_str()); + const ApplicationOptions &options = active_application.GetActiveOptions(); + + launch_log += format("- Working Directory: %s\n", options.working_folder.AbsolutePath().c_str()); + if (!options.working_folder.Exists()) { + Alert::PathInvalid( + options.working_folder, + format("The '%s' application will fail to launch.", active_application.executable_path.AbsolutePath().c_str()).c_str()); } if (!_launcher_arguments->text().isEmpty()) { launch_log += format("- Command-line Arguments: %s\n", _launcher_arguments->text().toStdString().c_str()); } - const std::string actual_log_file = ReplaceBuiltInVariable(active_application.log_file.c_str()); - if (!actual_log_file.empty()) { - launch_log += format("- Log file: %s\n", actual_log_file.c_str()); + if (!options.log_file.Empty()) { + launch_log += format("- Log file: %s\n", options.log_file.AbsolutePath().c_str()); } - if (!actual_log_file.empty()) { + if (!options.log_file.Empty()) { // Start logging // Make sure the log file is not already opened. This can occur if the // launched application is closed from the applicaiton. if (!_log_file.isOpen()) { - _log_file.setFileName(actual_log_file.c_str()); + _log_file.setFileName(options.log_file.AbsolutePath().c_str()); // Open and append, or open and truncate? QIODevice::OpenMode mode = QIODevice::WriteOnly | QIODevice::Text; @@ -1910,8 +2005,8 @@ void MainWindow::on_push_button_launcher_clicked() { _launch_application->setWorkingDirectory(ui->edit_dir->text()); _launch_application->setEnvironment(BuildEnvVariables() + ui->edit_env->text().split(",")); - if (!active_application.arguments.empty()) { - const QStringList args = ConvertString(SplitSpace(active_application.arguments)); + if (!options.arguments.empty()) { + const QStringList args = ConvertString(options.arguments); _launch_application->setArguments(args); } @@ -1924,7 +2019,8 @@ void MainWindow::on_push_button_launcher_clicked() { _launch_application->deleteLater(); _launch_application = nullptr; - const std::string failed_log = std::string("Failed to launch ") + active_application.executable_path.c_str() + "!\n"; + const std::string failed_log = + std::string("Failed to launch ") + active_application.executable_path.AbsolutePath().c_str() + "!\n"; Log(failed_log); } diff --git a/vkconfig/mainwindow.h b/vkconfig_gui/mainwindow.h similarity index 74% rename from vkconfig/mainwindow.h rename to vkconfig_gui/mainwindow.h index f24d152dde..a114b272fe 100644 --- a/vkconfig/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -21,14 +21,13 @@ #pragma once -#include "configurator.h" #include "settings_tree.h" +#include "configuration_layer_widget.h" #include "ui_mainwindow.h" #include #include -#include #include #include #include @@ -46,12 +45,62 @@ class ConfigurationListItem : public QTreeWidgetItem { ConfigurationListItem(const std::string &configuration_name) : configuration_name(configuration_name) {} std::string configuration_name; QRadioButton *radio_button; + QPushButton *push_button_reset; + QPushButton *push_button_duplicate; + QPushButton *push_button_remove; private: ConfigurationListItem(const ConfigurationListItem &) = delete; ConfigurationListItem &operator=(const ConfigurationListItem &) = delete; }; +class LayerPathWidget : public QLabel { + Q_OBJECT + + public: + LayerPathWidget(const std::string &layer_path, QListWidget *list, QListWidgetItem *item) : item(item) { + this->button_edit = new QPushButton(this); + this->button_edit->setText("..."); + this->button_edit->show(); + this->buttom_remove = new QPushButton(this); + this->buttom_remove->setText("x"); + this->buttom_remove->show(); + + this->setText(layer_path.c_str()); + + item->setSizeHint(QSize(0, ITEM_HEIGHT)); + } + + QPushButton *button_edit; + QPushButton *buttom_remove; + + protected: + void resizeEvent(QResizeEvent *event) override { + QSize size = event->size(); + + const QFontMetrics fm = this->button_edit->fontMetrics(); + const int button_width_state = 30; + + const QRect edit_button_rect = + QRect(size.width() - button_width_state - button_width_state, 0, button_width_state, size.height()); + this->button_edit->setGeometry(edit_button_rect); + + const QRect remove_button_rect = QRect(size.width() - button_width_state, 0, button_width_state, size.height()); + this->buttom_remove->setGeometry(remove_button_rect); + } + + public: + QListWidgetItem *item; +}; + +class TreeWidgetItemParameter : public QListWidgetItem { + public: + TreeWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } + + QWidget *widget; + std::string layer_name; +}; + enum Tool { TOOL_VULKAN_INFO, TOOL_VULKAN_INSTALL }; class MainWindow : public QMainWindow { @@ -62,7 +111,6 @@ class MainWindow : public QMainWindow { ~MainWindow(); void UpdateUI(); - void UpdateApplicationUI(const Application &application); private: SettingsTreeManager _settings_tree_manager; @@ -105,11 +153,13 @@ class MainWindow : public QMainWindow { void RemoveClicked(ConfigurationListItem *item); void ResetClicked(ConfigurationListItem *item); void RenameClicked(ConfigurationListItem *item); - void EditClicked(ConfigurationListItem *item); + void NewClicked(); void DuplicateClicked(ConfigurationListItem *item); void ExportClicked(ConfigurationListItem *item); void ImportClicked(ConfigurationListItem *item); - void ReloadDefaultClicked(ConfigurationListItem *item); + + void AddLayerPathItem(const std::string &layer_path); + void AddLayerItem(Parameter ¶meter); private slots: void trayActionRestore(); @@ -126,7 +176,6 @@ class MainWindow : public QMainWindow { void toolsResetToDefault(bool checked); void OnHelpFindLayers(bool checked); - void OnHelpAbout(bool checked); void OnHelpReadme(bool checked); void OnHelpChangelog(bool checked); void OnHelpVulkanSpec(bool checked); @@ -146,24 +195,25 @@ class MainWindow : public QMainWindow { void launchChangeWorkingFolder(const QString &new_text); void launchArgsEdited(const QString &new_text); + void on_tab_widget_currentChanged(int index); + void on_push_button_launcher_clicked(); void on_push_button_clear_log_clicked(); - void on_push_button_status_clicked(); - void on_check_box_apply_list_clicked(); - void on_check_box_persistent_clicked(); void on_check_box_clear_on_launch_clicked(); void on_push_button_applications_clicked(); - void on_push_button_edit_clicked(); void on_push_button_new_clicked(); + void on_push_button_rename_clicked(); void on_push_button_remove_clicked(); void on_push_button_duplicate_clicked(); - void OnComboBoxModeChanged(int index); + void on_check_box_per_application_toggled(bool checked); + void on_combo_box_mode_currentIndexChanged(int index); + void on_combo_box_applications_currentIndexChanged(int index); + void OnConfigurationItemExpanded(QTreeWidgetItem *item); void OnConfigurationItemClicked(bool checked); void OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); void OnConfigurationItemChanged(QTreeWidgetItem *item, int column); - void OnConfigurationItemDoubleClicked(QTreeWidgetItem *item, int column); void OnConfigurationTreeClicked(QTreeWidgetItem *item, int column); void OnSettingsTreeClicked(QTreeWidgetItem *item, int column); void OnLauncherLoaderMessageChanged(int level); @@ -180,16 +230,9 @@ class MainWindow : public QMainWindow { void UpdateTray(); void RemoveConfiguration(const std::string &configuration_name); - bool SelectConfigurationItem(const std::string &configuration_name); void ResetLaunchApplication(); void StartTool(Tool tool); QStringList BuildEnvVariables() const; - void UpdateStatus(); - - void ClearLog(); std::unique_ptr ui; - bool been_warned_about_old_loader; }; - -int run_gui(int argc, char *argv[]); diff --git a/vkconfig3/mainwindow.ui b/vkconfig_gui/mainwindow.ui similarity index 99% rename from vkconfig3/mainwindow.ui rename to vkconfig_gui/mainwindow.ui index 40a90ca474..a5943de9d9 100644 --- a/vkconfig3/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -615,6 +615,9 @@ Qt::Vertical + + false + @@ -669,7 +672,7 @@ - Layers Configuration Mode: + Layers Mode: @@ -701,7 +704,7 @@ - Per-Application Configuration: + Per-Application: @@ -711,6 +714,9 @@ + + false + 1 @@ -923,6 +929,9 @@ + + false + 0 @@ -1069,6 +1078,9 @@ Qt::Vertical + + false + 0 diff --git a/vkconfig/resourcefiles/lunarg_logo.png b/vkconfig_gui/resourcefiles/lunarg_logo.png similarity index 100% rename from vkconfig/resourcefiles/lunarg_logo.png rename to vkconfig_gui/resourcefiles/lunarg_logo.png diff --git a/vkconfig/resourcefiles/qt_logo.png b/vkconfig_gui/resourcefiles/qt_logo.png similarity index 100% rename from vkconfig/resourcefiles/qt_logo.png rename to vkconfig_gui/resourcefiles/qt_logo.png diff --git a/vkconfig/resourcefiles/vkconfig-off.png b/vkconfig_gui/resourcefiles/vkconfig-off.png similarity index 100% rename from vkconfig/resourcefiles/vkconfig-off.png rename to vkconfig_gui/resourcefiles/vkconfig-off.png diff --git a/vkconfig/resourcefiles/vkconfig-on.png b/vkconfig_gui/resourcefiles/vkconfig-on.png similarity index 100% rename from vkconfig/resourcefiles/vkconfig-on.png rename to vkconfig_gui/resourcefiles/vkconfig-on.png diff --git a/vkconfig/resourcefiles/vkconfig.aps b/vkconfig_gui/resourcefiles/vkconfig.aps similarity index 100% rename from vkconfig/resourcefiles/vkconfig.aps rename to vkconfig_gui/resourcefiles/vkconfig.aps diff --git a/vkconfig/resourcefiles/vkconfig.rc b/vkconfig_gui/resourcefiles/vkconfig.rc similarity index 100% rename from vkconfig/resourcefiles/vkconfig.rc rename to vkconfig_gui/resourcefiles/vkconfig.rc diff --git a/vkconfig/resourcefiles/vulkan.ico b/vkconfig_gui/resourcefiles/vulkan.ico similarity index 100% rename from vkconfig/resourcefiles/vulkan.ico rename to vkconfig_gui/resourcefiles/vulkan.ico diff --git a/vkconfig3/images/vulkan_configurator.png b/vkconfig_gui/resourcefiles/vulkan_configurator.png similarity index 100% rename from vkconfig3/images/vulkan_configurator.png rename to vkconfig_gui/resourcefiles/vulkan_configurator.png diff --git a/vkconfig_gui/resources.qrc b/vkconfig_gui/resources.qrc new file mode 100644 index 0000000000..f76bcea6a2 --- /dev/null +++ b/vkconfig_gui/resources.qrc @@ -0,0 +1,22 @@ + + + resourcefiles/vulkan_configurator.png + resourcefiles/lunarg_logo.png + resourcefiles/qt_logo.png + resourcefiles/vkconfig-off.png + resourcefiles/vkconfig-on.png + + + + ../vkconfig_core/configurations/3.0.0/API dump.json + ../vkconfig_core/configurations/3.0.0/Frame Capture.json + ../vkconfig_core/configurations/3.0.0/Portability.json + ../vkconfig_core/configurations/3.0.0/Synchronization.json + ../vkconfig_core/configurations/3.0.0/Validation.json + + + + ../vkconfig_core/layers/layers_schema.json + ../vkconfig_core/layers/validusage.json + + diff --git a/vkconfig3/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp similarity index 88% rename from vkconfig3/settings_tree.cpp rename to vkconfig_gui/settings_tree.cpp index 6c8149bdd5..7c0817998d 100644 --- a/vkconfig3/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -19,7 +19,6 @@ * - Christophe Riccio */ -#include "configurator.h" #include "settings_tree.h" #include "widget_setting.h" @@ -34,16 +33,17 @@ #include "widget_setting_list_element.h" #include "widget_setting_list.h" +#include "../vkconfig_core/configurator.h" #include "../vkconfig_core/alert.h" #include "../vkconfig_core/version.h" -#include "../vkconfig_core/platform.h" #include "../vkconfig_core/util.h" +#include "../vkconfig_core/type_platform.h" +#include "../vkconfig_core/type_hide_message.h" #include #include #include #include -#include #include @@ -62,7 +62,7 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { this->tree = build_tree; - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); + Configuration *configuration = configurator.GetActiveConfiguration(); if (configuration == nullptr) { return; } @@ -88,10 +88,14 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { // There will be one top level item for each layer for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { Parameter ¶meter = configuration->parameters[i]; - if (!IsPlatformSupported(parameter.platform_flags)) continue; - - if (parameter.state != LAYER_STATE_OVERRIDDEN) continue; - + if (!IsPlatformSupported(parameter.platform_flags)) { + continue; + } + /* + if (parameter.control != LAYER_STATE_OVERRIDDEN) { + continue; + } + */ const std::vector &selected_layers = configurator.layers.selected_layers; const Layer *layer = FindByKey(selected_layers, parameter.key.c_str()); @@ -146,12 +150,14 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { } void SettingsTreeManager::CleanupGUI() { - if (this->tree == nullptr) // Was not initialized + // Was not initialized + if (this->tree == nullptr) { return; + } Configurator &configurator = Configurator::Get(); - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); + Configuration *configuration = configurator.GetActiveConfiguration(); if (configuration != nullptr) { configuration->setting_tree_state.clear(); GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); @@ -164,39 +170,50 @@ void SettingsTreeManager::CleanupGUI() { void SettingsTreeManager::OnExpandedChanged(const QModelIndex &index) { (void)index; - if (this->tree == nullptr) // Was not initialized + // Was not initialized + if (this->tree == nullptr) { return; + } Configurator &configurator = Configurator::Get(); - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); - - return; + Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + configuration->setting_tree_state.clear(); + GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); + } } void SettingsTreeManager::OnCollapsedChanged(const QModelIndex &index) { (void)index; - if (this->tree == nullptr) // Was not initialized + // Was not initialized + if (this->tree == nullptr) { return; + } Configurator &configurator = Configurator::Get(); - Configuration *configuration = configurator.configurations.FindActiveConfiguration(); - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); - - return; + Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + configuration->setting_tree_state.clear(); + GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); + } } void SettingsTreeManager::BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶meter, const SettingMeta &meta_object) { - if (!IsPlatformSupported(meta_object.platform_flags)) return; - if (meta_object.view == SETTING_VIEW_HIDDEN) return; - if (meta_object.view == SETTING_VIEW_ADVANCED && - !Configurator::Get().configurations.FindActiveConfiguration()->view_advanced_settings) + if (!IsPlatformSupported(meta_object.platform_flags)) { return; + } + + if (meta_object.view == SETTING_VIEW_HIDDEN) { + return; + } + + Configurator &configurator = Configurator::Get(); + if (meta_object.view == SETTING_VIEW_ADVANCED && !configurator.GetActiveConfiguration()->view_advanced_settings) { + return; + } QTreeWidgetItem *item = new QTreeWidgetItem(); item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); @@ -356,6 +373,8 @@ void SettingsTreeManager::OnPresetChanged() { this->Refresh(REFRESH_ENABLE_AND_S void SettingsTreeManager::OnSettingChanged() { this->Refresh(REFRESH_ENABLE_ONLY); } void SettingsTreeManager::Refresh(RefreshAreas refresh_areas) { + Configurator &configurator = Configurator::Get(); + this->tree->blockSignals(true); QTreeWidgetItem *root_item = this->tree->invisibleRootItem(); @@ -366,17 +385,15 @@ void SettingsTreeManager::Refresh(RefreshAreas refresh_areas) { this->tree->blockSignals(false); if (this->launched_application) { - QSettings settings; - if (!settings.value(VKCONFIG_KEY_MESSAGE_NEED_APPLICATION_RESTART, false).toBool()) { - settings.setValue(VKCONFIG_KEY_MESSAGE_NEED_APPLICATION_RESTART, true); + if (!(configurator.environment.hide_message_boxes_flags & GetBit(HIDE_MESSAGE_NEED_APPLICATION_RESTART))) { + configurator.environment.hide_message_boxes_flags |= GetBit(HIDE_MESSAGE_NEED_APPLICATION_RESTART); Alert::ConfiguratorRestart(); } } // Refresh layer configuration - Configurator &configurator = Configurator::Get(); - configurator.configurations.Configure(configurator.layers.selected_layers); + configurator.Override(); } void SettingsTreeManager::RefreshItem(RefreshAreas refresh_areas, QTreeWidgetItem *parent) { diff --git a/vkconfig3/settings_tree.h b/vkconfig_gui/settings_tree.h similarity index 100% rename from vkconfig3/settings_tree.h rename to vkconfig_gui/settings_tree.h diff --git a/vkconfig/vkconfig.entitlements b/vkconfig_gui/vkconfig.entitlements similarity index 100% rename from vkconfig/vkconfig.entitlements rename to vkconfig_gui/vkconfig.entitlements diff --git a/vkconfig3/vkconfig.pro b/vkconfig_gui/vkconfig.pro similarity index 79% rename from vkconfig3/vkconfig.pro rename to vkconfig_gui/vkconfig.pro index 9d07202c31..c717a62471 100644 --- a/vkconfig3/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -2,7 +2,7 @@ QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets network -CONFIG += c++11 +CONFIG += c++17 CONFIG += sdk_no_version_check INCLUDEPATH += ../external/Vulkan-Headers/include @@ -30,11 +30,15 @@ SOURCES += \ ../vkconfig_core/alert.cpp \ ../vkconfig_core/application.cpp \ ../vkconfig_core/application_singleton.cpp \ + ../vkconfig_core/bitfield.cpp \ ../vkconfig_core/command_line.cpp \ ../vkconfig_core/configuration.cpp \ + ../vkconfig_core/configuration_info.cpp \ ../vkconfig_core/configuration_manager.cpp \ - ../vkconfig_core/doc.cpp \ + ../vkconfig_core/configurator.cpp \ + ../vkconfig_core/configurator_signal.cpp \ ../vkconfig_core/date.cpp \ + ../vkconfig_core/doc.cpp \ ../vkconfig_core/environment.cpp \ ../vkconfig_core/header.cpp \ ../vkconfig_core/help.cpp \ @@ -43,13 +47,8 @@ SOURCES += \ ../vkconfig_core/layer.cpp \ ../vkconfig_core/layer_manager.cpp \ ../vkconfig_core/layer_preset.cpp \ - ../vkconfig_core/layer_state.cpp \ - ../vkconfig_core/layer_type.cpp \ - ../vkconfig_core/override.cpp \ ../vkconfig_core/parameter.cpp \ ../vkconfig_core/path.cpp \ - ../vkconfig_core/path_manager.cpp \ - ../vkconfig_core/platform.cpp \ ../vkconfig_core/registry.cpp \ ../vkconfig_core/setting.cpp \ ../vkconfig_core/setting_bool.cpp \ @@ -61,9 +60,20 @@ SOURCES += \ ../vkconfig_core/setting_int.cpp \ ../vkconfig_core/setting_list.cpp \ ../vkconfig_core/setting_string.cpp \ + ../vkconfig_core/type_hide_message.cpp \ + ../vkconfig_core/type_layer_control.cpp \ + ../vkconfig_core/type_layer_type.cpp \ + ../vkconfig_core/type_layers_mode.cpp \ + ../vkconfig_core/type_log.cpp \ + ../vkconfig_core/type_platform.cpp \ + ../vkconfig_core/type_status.cpp \ + ../vkconfig_core/type_tab.cpp \ + ../vkconfig_core/type_update.cpp \ ../vkconfig_core/util.cpp \ ../vkconfig_core/version.cpp \ - vulkan_util.cpp \ + ../vkconfig_core/vulkan_info.cpp \ + ../vkconfig_core/vulkan_util.cpp \ + configuration_layer_widget.cpp \ widget_preset.cpp \ widget_setting.cpp \ widget_setting_bool.cpp \ @@ -77,28 +87,25 @@ SOURCES += \ widget_setting_list_element.cpp \ widget_setting_list.cpp \ widget_tree_friendly_combobox.cpp \ - dialog_applications.cpp \ dialog_vulkan_analysis.cpp \ dialog_vulkan_info.cpp \ main.cpp \ - main_gui.cpp \ - main_signal.cpp \ - main_reset.cpp \ - main_layers.cpp \ - main_doc.cpp \ mainwindow.cpp \ - settings_tree.cpp \ - configurator.cpp + settings_tree.cpp HEADERS += \ ../vkconfig_core/alert.h \ ../vkconfig_core/application.h \ ../vkconfig_core/application_singleton.h \ + ../vkconfig_core/bitfield.h \ ../vkconfig_core/command_line.h \ ../vkconfig_core/configuration.h \ + ../vkconfig_core/configuration_info.h \ ../vkconfig_core/configuration_manager.h \ - ../vkconfig_core/doc.h \ + ../vkconfig_core/configurator.h \ + ../vkconfig_core/configurator_signal.h \ ../vkconfig_core/date.h \ + ../vkconfig_core/doc.h \ ../vkconfig_core/environment.h \ ../vkconfig_core/header.h \ ../vkconfig_core/help.h \ @@ -107,13 +114,8 @@ HEADERS += \ ../vkconfig_core/layer.h \ ../vkconfig_core/layer_manager.h \ ../vkconfig_core/layer_preset.h \ - ../vkconfig_core/layer_state.h \ - ../vkconfig_core/layer_type.h \ - ../vkconfig_core/override.h \ ../vkconfig_core/parameter.h \ ../vkconfig_core/path.h \ - ../vkconfig_core/path_manager.h \ - ../vkconfig_core/platform.h \ ../vkconfig_core/registry.h \ ../vkconfig_core/setting.h \ ../vkconfig_core/setting_bool.h \ @@ -125,9 +127,20 @@ HEADERS += \ ../vkconfig_core/setting_int.h \ ../vkconfig_core/setting_list.h \ ../vkconfig_core/setting_string.h \ + ../vkconfig_core/type_hide_message.h \ + ../vkconfig_core/type_layer_control.h \ + ../vkconfig_core/type_layer_type.h \ + ../vkconfig_core/type_layers_mode.h \ + ../vkconfig_core/type_log.h \ + ../vkconfig_core/type_platform.h \ + ../vkconfig_core/type_status.h \ + ../vkconfig_core/type_tab.h \ + ../vkconfig_core/type_update.h \ ../vkconfig_core/util.h \ ../vkconfig_core/version.h \ - vulkan_util.h \ + ../vkconfig_core/vulkan_info.h \ + ../vkconfig_core/vulkan_util.h \ + configuration_layer_widget.h \ widget_preset.h \ widget_setting.h \ widget_setting_bool.h \ @@ -141,20 +154,12 @@ HEADERS += \ widget_setting_list_element.h \ widget_setting_list.h \ widget_tree_friendly_combobox.h \ - dialog_applications.h \ dialog_vulkan_analysis.h \ dialog_vulkan_info.h \ - main_gui.h \ - main_signal.h \ - main_reset.h \ - main_layers.h \ - main_doc.h \ mainwindow.h \ - settings_tree.h \ - configurator.h + settings_tree.h FORMS += \ - dialog_applications.ui \ dialog_vulkan_analysis.ui \ dialog_vulkan_info.ui \ mainwindow.ui diff --git a/vkconfig/widget_preset.cpp b/vkconfig_gui/widget_preset.cpp similarity index 100% rename from vkconfig/widget_preset.cpp rename to vkconfig_gui/widget_preset.cpp diff --git a/vkconfig/widget_preset.h b/vkconfig_gui/widget_preset.h similarity index 100% rename from vkconfig/widget_preset.h rename to vkconfig_gui/widget_preset.h diff --git a/vkconfig3/widget_setting.cpp b/vkconfig_gui/widget_setting.cpp similarity index 100% rename from vkconfig3/widget_setting.cpp rename to vkconfig_gui/widget_setting.cpp diff --git a/vkconfig/widget_setting.h b/vkconfig_gui/widget_setting.h similarity index 100% rename from vkconfig/widget_setting.h rename to vkconfig_gui/widget_setting.h diff --git a/vkconfig/widget_setting_bool.cpp b/vkconfig_gui/widget_setting_bool.cpp similarity index 100% rename from vkconfig/widget_setting_bool.cpp rename to vkconfig_gui/widget_setting_bool.cpp diff --git a/vkconfig/widget_setting_bool.h b/vkconfig_gui/widget_setting_bool.h similarity index 100% rename from vkconfig/widget_setting_bool.h rename to vkconfig_gui/widget_setting_bool.h diff --git a/vkconfig/widget_setting_enum.cpp b/vkconfig_gui/widget_setting_enum.cpp similarity index 84% rename from vkconfig/widget_setting_enum.cpp rename to vkconfig_gui/widget_setting_enum.cpp index 5a5143b73d..396e6ee6c8 100644 --- a/vkconfig/widget_setting_enum.cpp +++ b/vkconfig_gui/widget_setting_enum.cpp @@ -21,8 +21,8 @@ #include "widget_setting_enum.h" #include "widget_setting.h" -#include "configurator.h" +#include "../vkconfig_core/configurator.h" #include "../vkconfig_core/setting_filesystem.h" #include @@ -109,20 +109,20 @@ void WidgetSettingEnum::Refresh(RefreshAreas refresh_areas) { this->field->clear(); this->enum_indexes.clear(); - const std::vector& devices = Configurator::Get().GetDeviceNames(); + const std::vector& physical_device_infos = Configurator::Get().vulkan_system_info.physicalDevices; int selection = 0; const std::string value = this->data().GetValue(); - for (std::size_t i = 0, n = devices.size(); i < n; ++i) { - this->field->addItem(devices[i].c_str()); - if (devices[i] == value || "${VP_PHYSICAL_DEVICES}" == value) { - this->data().SetValue(devices[i].c_str()); + for (std::size_t i = 0, n = physical_device_infos.size(); i < n; ++i) { + this->field->addItem(physical_device_infos[i].deviceName.c_str()); + if (physical_device_infos[i].deviceName == value || "${VP_PHYSICAL_DEVICES}" == value) { + this->data().SetValue(physical_device_infos[i].deviceName.c_str()); selection = static_cast(this->enum_indexes.size()); } this->enum_indexes.push_back(i); } this->field->setCurrentIndex(selection); - if (!devices.empty()) { + if (!physical_device_infos.empty()) { OnIndexChanged(selection); } } else if (refresh_areas == REFRESH_ENABLE_AND_STATE) { @@ -137,7 +137,9 @@ void WidgetSettingEnum::Refresh(RefreshAreas refresh_areas) { const std::string value = this->data().GetValue(); for (std::size_t i = 0, n = this->meta.enum_values.size(); i < n; ++i) { - if (!IsSupported(&this->meta.enum_values[i])) continue; + if (!IsSupported(&this->meta.enum_values[i])) { + continue; + } this->field->addItem(this->meta.enum_values[i].label.c_str()); if (this->meta.enum_values[i].key == value) { @@ -168,9 +170,9 @@ void WidgetSettingEnum::Resize() { width = std::max(width, HorizontalAdvance(fm, (profiles[i] + "0000").c_str())); } } else if (meta.default_value == "${VP_PHYSICAL_DEVICES}") { - const std::vector& devices = Configurator::Get().GetDeviceNames(); - for (std::size_t i = 0, n = devices.size(); i < n; ++i) { - width = std::max(width, HorizontalAdvance(fm, (devices[i] + "000").c_str())); + const std::vector& physical_device_infos = Configurator::Get().vulkan_system_info.physicalDevices; + for (std::size_t i = 0, n = physical_device_infos.size(); i < n; ++i) { + width = std::max(width, HorizontalAdvance(fm, (physical_device_infos[i].deviceName + std::string("000")).c_str())); } } else { for (std::size_t i = 0, n = this->meta.enum_values.size(); i < n; ++i) { @@ -200,11 +202,11 @@ void WidgetSettingEnum::OnIndexChanged(int index) { this->data().SetValue(profiles[index].c_str()); this->setToolTip(profiles[index].c_str()); } else if (meta.default_value == "${VP_PHYSICAL_DEVICES}") { - const std::vector& devices = Configurator::Get().GetDeviceNames(); - assert(index >= 0 && index < static_cast(devices.size())); + const std::vector& physical_device_infos = Configurator::Get().vulkan_system_info.physicalDevices; + assert(index >= 0 && index < static_cast(physical_device_infos.size())); - this->data().SetValue(devices[index].c_str()); - this->setToolTip(devices[index].c_str()); + this->data().SetValue(physical_device_infos[index].deviceName.c_str()); + this->setToolTip(physical_device_infos[index].deviceName.c_str()); } else { assert(index >= 0 && index < static_cast(this->meta.enum_values.size())); diff --git a/vkconfig/widget_setting_enum.h b/vkconfig_gui/widget_setting_enum.h similarity index 100% rename from vkconfig/widget_setting_enum.h rename to vkconfig_gui/widget_setting_enum.h diff --git a/vkconfig/widget_setting_filesystem.cpp b/vkconfig_gui/widget_setting_filesystem.cpp similarity index 70% rename from vkconfig/widget_setting_filesystem.cpp rename to vkconfig_gui/widget_setting_filesystem.cpp index cade541594..6802684ebc 100644 --- a/vkconfig/widget_setting_filesystem.cpp +++ b/vkconfig_gui/widget_setting_filesystem.cpp @@ -24,7 +24,7 @@ #include "../vkconfig_core/path.h" #include "../vkconfig_core/alert.h" -#include "../vkconfig/configurator.h" +#include "../vkconfig_core/configurator.h" #include @@ -73,13 +73,11 @@ void WidgetSettingFilesystem::Refresh(RefreshAreas refresh_areas) { LoadPath(this->data().GetValue()); this->field->blockSignals(true); - this->field->setText(this->data().GetValue()); - this->field->setToolTip(ReplaceBuiltInVariable(this->data().GetValue()).c_str()); + this->field->setText(this->data().GetValue().RelativePath().c_str()); + this->field->setToolTip(this->data().GetValue().AbsolutePath().c_str()); if (::CheckSettingOverridden(this->meta)) { this->DisplayOverride(this->field, this->meta); - } else { - this->field->setToolTip(ReplaceBuiltInVariable(this->field->text().toStdString()).c_str()); } this->field->blockSignals(false); @@ -93,15 +91,17 @@ void WidgetSettingFilesystem::resizeEvent(QResizeEvent* event) { this->button->setGeometry(button_rect); } -void WidgetSettingFilesystem::LoadPath(const std::string& path) { +void WidgetSettingFilesystem::LoadPath(const Path& path) { switch (this->meta.type) { case SETTING_LOAD_FILE: { const SettingMetaFileLoad& setting_meta = static_cast(this->meta); if (setting_meta.format == "PROFILE") { - if (path.empty()) return; + if (path.Empty()) { + return; + } SettingDataFileLoad& file_setting_data = static_cast(this->data()); - file_setting_data.profile_names = GetProfileNamesFromFile(path); + file_setting_data.profile_names = CollectProfileNamesFromFile(path); SettingDataString* enum_setting_data = FindSetting(this->data_set, "profile_name"); if (!file_setting_data.profile_names.empty() && enum_setting_data != nullptr) { @@ -115,10 +115,12 @@ void WidgetSettingFilesystem::LoadPath(const std::string& path) { case SETTING_LOAD_FOLDER: { const SettingMetaFolderLoad& setting_meta = static_cast(this->meta); if (setting_meta.format == "PROFILE") { - if (path.empty()) return; + if (path.Empty()) { + return; + } SettingDataFolderLoad& setting_data = static_cast(this->data()); - setting_data.profile_names = GetProfileNamesFromDir(path); + setting_data.profile_names = CollectProfileNamesFromDir(path); SettingDataString* enum_setting_data = FindSetting(this->data_set, "profile_name"); if (enum_setting_data != nullptr) { @@ -136,30 +138,29 @@ void WidgetSettingFilesystem::LoadPath(const std::string& path) { } void WidgetSettingFilesystem::browseButtonClicked() { - std::string path = this->field->text().toStdString(); - - if (path.empty()) { - path = "${VK_LOCAL}"; - this->data().SetValue(path.c_str()); + Path path(this->field->text().toStdString()); + if (path.Empty()) { + path = Path("${VK_HOME}"); + this->data().SetValue(path); } switch (this->meta.type) { case SETTING_LOAD_FILE: case SETTING_SAVE_FILE: - if (!QFileInfo(ReplaceBuiltInVariable(path).c_str()).absoluteDir().exists()) { + if (!path.Exists()) { path = this->data().GetValue(); } - if (!QFileInfo(ReplaceBuiltInVariable(path).c_str()).absoluteDir().exists()) { - path.clear(); + if (!path.Exists()) { + path.Clear(); } break; case SETTING_LOAD_FOLDER: case SETTING_SAVE_FOLDER: - if (!QFileInfo(ReplaceBuiltInVariable(path).c_str()).exists()) { + if (!path.Exists()) { path = this->data().GetValue(); } - if (!QFileInfo(ReplaceBuiltInVariable(path).c_str()).exists()) { - path.clear(); + if (!path.Exists()) { + path.Clear(); } break; default: @@ -167,22 +168,22 @@ void WidgetSettingFilesystem::browseButtonClicked() { break; } - const std::string replaced_path = ReplaceBuiltInVariable(path); - const std::string dir = QFileInfo(replaced_path.c_str()).absoluteDir().absolutePath().toStdString(); + const std::string replaced_path = path.AbsolutePath(); + const std::string dir = path.AbsoluteDir(); const char* filter = this->meta.filter.c_str(); - std::string new_path; + Path new_path; switch (this->meta.type) { case SETTING_LOAD_FILE: - new_path = QFileDialog::getOpenFileName(this->button, "Select file", dir.c_str(), filter).toStdString(); + new_path = Path(QFileDialog::getOpenFileName(this->button, "Select file", dir.c_str(), filter).toStdString()); break; case SETTING_SAVE_FILE: - new_path = QFileDialog::getSaveFileName(this->button, "Select File", dir.c_str(), filter).toStdString(); + new_path = Path(QFileDialog::getSaveFileName(this->button, "Select File", dir.c_str(), filter).toStdString()); break; case SETTING_LOAD_FOLDER: case SETTING_SAVE_FOLDER: - new_path = QFileDialog::getExistingDirectory(this->button, "Select Folder", replaced_path.c_str()).toStdString(); + new_path = Path(QFileDialog::getExistingDirectory(this->button, "Select Folder", replaced_path.c_str()).toStdString()); break; default: assert(0); @@ -190,19 +191,17 @@ void WidgetSettingFilesystem::browseButtonClicked() { } // The user has cancel the operation - if (new_path.empty()) { + if (new_path.Empty()) { return; } - new_path = ConvertNativeSeparators(new_path); - // The path didn't change, preserve the built-in variables - if (replaced_path != new_path) { - this->data().SetValue(new_path.c_str()); + if (replaced_path != new_path.AbsolutePath().c_str()) { + this->data().SetValue(new_path); } - this->field->setText(this->data().GetValue()); - this->field->setToolTip(ReplaceBuiltInVariable(this->field->text().toStdString()).c_str()); + this->field->setText(this->data().GetValue().RelativePath().c_str()); + this->field->setToolTip(new_path.AbsolutePath().c_str()); this->LoadPath(new_path); @@ -210,25 +209,20 @@ void WidgetSettingFilesystem::browseButtonClicked() { } void WidgetSettingFilesystem::textFieldChanged(const QString& value) { - std::string path = ConvertNativeSeparators(value.toStdString()); - - if (path.empty()) { - path = "${VK_LOCAL}"; - this->data().SetValue(path.c_str()); - } + Path path(value.toStdString()); - this->data().SetValue(path.c_str()); - this->field->setToolTip(ReplaceBuiltInVariable(this->field->text().toStdString()).c_str()); + this->data().SetValue(path.RelativePath().c_str()); + this->field->setToolTip(path.AbsolutePath().c_str()); - if (QFileInfo(ReplaceBuiltInVariable(path).c_str()).exists()) { + if (path.Exists()) { this->LoadPath(path); } emit itemChanged(); } -SettingDataString& WidgetSettingFilesystem::data() { - SettingDataString* data = FindSetting(this->data_set, this->meta.key.c_str()); +SettingDataFilesystem& WidgetSettingFilesystem::data() { + SettingDataFilesystem* data = FindSetting(this->data_set, this->meta.key.c_str()); assert(data != nullptr); return *data; } diff --git a/vkconfig/widget_setting_filesystem.h b/vkconfig_gui/widget_setting_filesystem.h similarity index 88% rename from vkconfig/widget_setting_filesystem.h rename to vkconfig_gui/widget_setting_filesystem.h index 6d82e368da..6a60e9728c 100644 --- a/vkconfig/widget_setting_filesystem.h +++ b/vkconfig_gui/widget_setting_filesystem.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ #pragma once #include "../vkconfig_core/setting_filesystem.h" +#include "../vkconfig_core/path.h" #include "widget_setting.h" @@ -49,8 +50,8 @@ class WidgetSettingFilesystem : public WidgetSettingBase { void resizeEvent(QResizeEvent *event) override; private: - SettingDataString &data(); - void LoadPath(const std::string &path); + SettingDataFilesystem &data(); + void LoadPath(const Path &path); const SettingMetaFilesystem &meta; SettingDataSet &data_set; diff --git a/vkconfig/widget_setting_flags.cpp b/vkconfig_gui/widget_setting_flags.cpp similarity index 100% rename from vkconfig/widget_setting_flags.cpp rename to vkconfig_gui/widget_setting_flags.cpp diff --git a/vkconfig/widget_setting_flags.h b/vkconfig_gui/widget_setting_flags.h similarity index 100% rename from vkconfig/widget_setting_flags.h rename to vkconfig_gui/widget_setting_flags.h diff --git a/vkconfig3/widget_setting_float.cpp b/vkconfig_gui/widget_setting_float.cpp similarity index 94% rename from vkconfig3/widget_setting_float.cpp rename to vkconfig_gui/widget_setting_float.cpp index 2cab7e00c1..a9e4ae8eaa 100644 --- a/vkconfig3/widget_setting_float.cpp +++ b/vkconfig_gui/widget_setting_float.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,12 @@ #include "widget_setting_float.h" +#include "../vkconfig_core/configurator.h" +#include "../vkconfig_core/type_hide_message.h" + #include #include #include -#include #include @@ -96,8 +98,9 @@ void WidgetSettingFloat::OnErrorValue() { palette.setColor(QPalette::Base, QColor(255, 192, 192)); this->field->setPalette(palette); - QSettings settings; - if (settings.value("VKCONFIG_WIDGET_SETTING_FLOAT").toBool() == false) { + Environment& environment = Configurator::Get().environment; + + if (!(environment.hide_message_boxes_flags & GetBit(HIDE_MESSAGE_WIDGET_SETTING_FLOAT))) { const std::string float_format = this->meta.GetFloatFormat(); const std::string info = format("Do you want to reset to the setting default value? '%s'", float_format.c_str()); const std::string range = this->meta.HasRange() @@ -145,7 +148,7 @@ void WidgetSettingFloat::OnErrorValue() { this->Resize(); } if (alert.checkBox()->isChecked()) { - settings.setValue("VKCONFIG_WIDGET_SETTING_FLOAT", true); + environment.hide_message_boxes_flags |= GetBit(HIDE_MESSAGE_WIDGET_SETTING_FLOAT); } } diff --git a/vkconfig/widget_setting_float.h b/vkconfig_gui/widget_setting_float.h similarity index 100% rename from vkconfig/widget_setting_float.h rename to vkconfig_gui/widget_setting_float.h diff --git a/vkconfig3/widget_setting_frames.cpp b/vkconfig_gui/widget_setting_frames.cpp similarity index 92% rename from vkconfig3/widget_setting_frames.cpp rename to vkconfig_gui/widget_setting_frames.cpp index b9276dd73d..340fa12046 100644 --- a/vkconfig3/widget_setting_frames.cpp +++ b/vkconfig_gui/widget_setting_frames.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,14 +19,14 @@ */ #include "widget_setting_frames.h" -#include "widget_setting.h" +#include "../vkconfig_core/configurator.h" #include "../vkconfig_core/util.h" +#include "../vkconfig_core/type_hide_message.h" #include #include #include -#include #include @@ -94,8 +94,9 @@ void WidgetSettingFrames::OnErrorValue() { palette.setColor(QPalette::Base, QColor(255, 192, 192)); this->field->setPalette(palette); - QSettings settings; - if (settings.value("VKCONFIG_WIDGET_SETTING_FRAMES").toBool() == false) { + Environment& environment = Configurator::Get().environment; + + if (!(environment.hide_message_boxes_flags & GetBit(HIDE_MESSAGE_WIDGET_SETTING_FRAMES))) { const std::string text = format("The setting input '%s' is invalid. Use list of comma separated integer ranges. Example: '0-2,16'.", this->data().GetValue()); @@ -117,7 +118,7 @@ void WidgetSettingFrames::OnErrorValue() { this->Resize(); } if (alert.checkBox()->isChecked()) { - settings.setValue("VKCONFIG_WIDGET_SETTING_FRAMES", true); + environment.hide_message_boxes_flags |= GetBit(HIDE_MESSAGE_WIDGET_SETTING_FRAMES); } } diff --git a/vkconfig/widget_setting_frames.h b/vkconfig_gui/widget_setting_frames.h similarity index 100% rename from vkconfig/widget_setting_frames.h rename to vkconfig_gui/widget_setting_frames.h diff --git a/vkconfig3/widget_setting_int.cpp b/vkconfig_gui/widget_setting_int.cpp similarity index 93% rename from vkconfig3/widget_setting_int.cpp rename to vkconfig_gui/widget_setting_int.cpp index 63603d1c02..048a6e3563 100644 --- a/vkconfig3/widget_setting_int.cpp +++ b/vkconfig_gui/widget_setting_int.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,12 @@ #include "widget_setting_int.h" +#include "../vkconfig_core/configurator.h" +#include "../vkconfig_core/type_hide_message.h" + #include #include #include -#include #include @@ -93,8 +95,9 @@ void WidgetSettingInt::OnErrorValue() { palette.setColor(QPalette::Base, QColor(255, 192, 192)); this->field->setPalette(palette); - QSettings settings; - if (settings.value("VKCONFIG_WIDGET_SETTING_INT").toBool() == false) { + Environment& environment = Configurator::Get().environment; + + if (!(environment.hide_message_boxes_flags & GetBit(HIDE_MESSAGE_WIDGET_SETTING_INT))) { const std::string info = format("Do you want to reset to the setting default value? '%d'", this->meta.default_value); const std::string range = format("Enter a number in the range [%d, %d].", this->meta.min_value, this->meta.max_value); @@ -134,7 +137,7 @@ void WidgetSettingInt::OnErrorValue() { this->Resize(); } if (alert.checkBox()->isChecked()) { - settings.setValue("VKCONFIG_WIDGET_SETTING_INT", true); + environment.hide_message_boxes_flags |= GetBit(HIDE_MESSAGE_WIDGET_SETTING_INT); } } diff --git a/vkconfig/widget_setting_int.h b/vkconfig_gui/widget_setting_int.h similarity index 100% rename from vkconfig/widget_setting_int.h rename to vkconfig_gui/widget_setting_int.h diff --git a/vkconfig/widget_setting_list.cpp b/vkconfig_gui/widget_setting_list.cpp similarity index 100% rename from vkconfig/widget_setting_list.cpp rename to vkconfig_gui/widget_setting_list.cpp diff --git a/vkconfig/widget_setting_list.h b/vkconfig_gui/widget_setting_list.h similarity index 100% rename from vkconfig/widget_setting_list.h rename to vkconfig_gui/widget_setting_list.h diff --git a/vkconfig/widget_setting_list_element.cpp b/vkconfig_gui/widget_setting_list_element.cpp similarity index 100% rename from vkconfig/widget_setting_list_element.cpp rename to vkconfig_gui/widget_setting_list_element.cpp diff --git a/vkconfig/widget_setting_list_element.h b/vkconfig_gui/widget_setting_list_element.h similarity index 100% rename from vkconfig/widget_setting_list_element.h rename to vkconfig_gui/widget_setting_list_element.h diff --git a/vkconfig/widget_setting_string.cpp b/vkconfig_gui/widget_setting_string.cpp similarity index 100% rename from vkconfig/widget_setting_string.cpp rename to vkconfig_gui/widget_setting_string.cpp diff --git a/vkconfig/widget_setting_string.h b/vkconfig_gui/widget_setting_string.h similarity index 100% rename from vkconfig/widget_setting_string.h rename to vkconfig_gui/widget_setting_string.h diff --git a/vkconfig3/widget_tree_friendly_combobox.cpp b/vkconfig_gui/widget_tree_friendly_combobox.cpp similarity index 100% rename from vkconfig3/widget_tree_friendly_combobox.cpp rename to vkconfig_gui/widget_tree_friendly_combobox.cpp diff --git a/vkconfig3/widget_tree_friendly_combobox.h b/vkconfig_gui/widget_tree_friendly_combobox.h similarity index 100% rename from vkconfig3/widget_tree_friendly_combobox.h rename to vkconfig_gui/widget_tree_friendly_combobox.h From f3fae898544849390c19a9e32c5e1eed0b111665 Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 18 Jul 2024 13:14:59 +0200 Subject: [PATCH 02/33] vkconfig3: Improve SDK upgrade Change-Id: I8407f444a3e09f61b5de207720d1beb503c8dd2f --- vkconfig_core/environment.cpp | 6 +++--- vkconfig_gui/configuration_layer_widget.cpp | 16 +++++++++++++++- vkconfig_gui/mainwindow.cpp | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index 244db47449..78921ba4e3 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -293,16 +293,16 @@ bool Environment::Save() const { QJsonObject json_option_object; json_option_object.insert("label", options.label.c_str()); - json_option_object.insert("working_folder", options.working_folder.AbsolutePath().c_str()); + json_option_object.insert("working_folder", options.working_folder.RelativePath().c_str()); json_option_object.insert("arguments", json_arg_array); json_option_object.insert("environment_variables", json_env_array); - json_option_object.insert("log_file", options.log_file.AbsolutePath().c_str()); + json_option_object.insert("log_file", options.log_file.RelativePath().c_str()); json_options_array.append(json_option_object); } json_application_object.insert("options", json_options_array); - json_applications_list_object.insert(application.executable_path.AbsolutePath().c_str(), json_application_object); + json_applications_list_object.insert(application.executable_path.RelativePath().c_str(), json_application_object); } json_applications_object.insert("list", json_applications_list_object); diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/configuration_layer_widget.cpp index b057d5b7fd..113aa2c425 100644 --- a/vkconfig_gui/configuration_layer_widget.cpp +++ b/vkconfig_gui/configuration_layer_widget.cpp @@ -32,19 +32,33 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vectorlayer_version->addItem("Latest"); int version_index = 0; + const Layer *selected_layer = nullptr; + const Layer *latest_layer = nullptr; + for (std::size_t i = 0, n = layers.size(); i < n; ++i) { if (layers[i]->key != parameter.key) { continue; } + if (latest_layer == nullptr) { + latest_layer = layers[i]; + } + if (layers[i]->api_version == parameter.api_version) { - this->layer_version->setToolTip(layers[i]->manifest_path.AbsolutePath().c_str()); + selected_layer = layers[i]; version_index = this->layer_version->count(); + } else if (layers[i]->api_version > latest_layer->api_version) { + latest_layer = layers[i]; } this->layer_version->addItem(layers[i]->api_version.str().c_str()); } this->layer_version->setCurrentIndex(version_index); + if (selected_layer != nullptr) { + this->layer_version->setToolTip(selected_layer->manifest_path.AbsolutePath().c_str()); + } else if (latest_layer != nullptr) { + this->layer_version->setToolTip(latest_layer->manifest_path.AbsolutePath().c_str()); + } // this->layer_version->setEnabled(layers.size() > 1); this->connect(this->layer_version, SIGNAL(currentIndexChanged(int)), this, SLOT(on_layer_version_currentIndexChanged(int))); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 9192e78fed..2ec7e97f49 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -599,7 +599,7 @@ void MainWindow::UpdateUI() { ui->combo_box_applications->setEnabled(ui->check_box_per_application->isChecked()); const std::vector &applications = environment.GetApplications(); for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - ui->combo_box_applications->addItem(applications[i].executable_path.AbsolutePath().c_str()); + ui->combo_box_applications->addItem(applications[i].executable_path.RelativePath().c_str()); } ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); ui->combo_box_applications->blockSignals(false); From 12a2001c99f7ca82ad246dd738c4f1dc9fefadab Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 18 Jul 2024 17:10:52 +0200 Subject: [PATCH 03/33] vkconfig3: Full ordering of layers --- vkconfig_core/configurator.cpp | 8 +++++- vkconfig_core/parameter.cpp | 22 +++++++-------- vkconfig_core/type_layer_control.cpp | 1 + vkconfig_core/type_layer_control.h | 6 ++--- vkconfig_gui/configuration_layer_widget.cpp | 11 ++++---- vkconfig_gui/mainwindow.cpp | 29 +++++++++++++++----- vkconfig_gui/mainwindow.ui | 30 ++++++++++++++++----- 7 files changed, 74 insertions(+), 33 deletions(-) diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index 9e39aeff1c..eecce05139 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -387,4 +387,10 @@ const Configuration* Configurator::GetActiveConfiguration() const { return this->configurations.FindConfiguration(info.GetName()); } -bool Configurator::HasActiveConfiguration() const { return true; } +bool Configurator::HasActiveConfiguration() const { + if (this->environment.GetPerApplicationConfig()) { + return this->environment.HasOverriddenApplications(); + } else { + return this->environment.GetActiveConfigurationInfo().GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS; + } +} diff --git a/vkconfig_core/parameter.cpp b/vkconfig_core/parameter.cpp index 02c2d311c5..b36ae456b8 100644 --- a/vkconfig_core/parameter.cpp +++ b/vkconfig_core/parameter.cpp @@ -219,12 +219,6 @@ std::size_t CountExcludedLayers(const std::vector& parameters, const std::vector GatherParameters(const std::vector& parameters, const std::vector& available_layers) { std::vector gathered_parameters; - Parameter application_enabled_layers; - application_enabled_layers.key = "Application Enabled Layers"; - application_enabled_layers.control = LAYER_CONTROL_APPLICATIONS; - application_enabled_layers.overridden_rank = Parameter::NO_RANK; - gathered_parameters.push_back(application_enabled_layers); - // Loop through the layers. They are expected to be in order for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { const Parameter& parameter = parameters[i]; @@ -252,11 +246,17 @@ std::vector GatherParameters(const std::vector& parameters OrderParameter(gathered_parameters, available_layers); - Parameter unordered_layer_location; - unordered_layer_location.key = "Unordered Layers"; - unordered_layer_location.control = LAYER_CONTROL_UNORDERED; - unordered_layer_location.overridden_rank = 999; - gathered_parameters.push_back(unordered_layer_location); + Parameter applications_enabled_layers_api; + applications_enabled_layers_api.key = "Vulkan Application Layers from the Vulkan API"; + applications_enabled_layers_api.control = LAYER_CONTROL_APPLICATIONS_API; + applications_enabled_layers_api.overridden_rank = 998; + gathered_parameters.push_back(applications_enabled_layers_api); + + Parameter applications_enabled_layers_env; + applications_enabled_layers_env.key = "Vulkan Application Layers from Environment Variables"; + applications_enabled_layers_env.control = LAYER_CONTROL_APPLICATIONS_ENV; + applications_enabled_layers_env.overridden_rank = 999; + gathered_parameters.push_back(applications_enabled_layers_env); return gathered_parameters; } diff --git a/vkconfig_core/type_layer_control.cpp b/vkconfig_core/type_layer_control.cpp index 1753655894..a39065530c 100644 --- a/vkconfig_core/type_layer_control.cpp +++ b/vkconfig_core/type_layer_control.cpp @@ -23,6 +23,7 @@ #include #include +// These names are requied by the Vulkan Loader settings file const char* GetToken(LayerControl control) { static const char* TOKENS[] = { "auto", // LAYER_CONTROL_AUTO diff --git a/vkconfig_core/type_layer_control.h b/vkconfig_core/type_layer_control.h index 891fcbcfc1..e41bcd6717 100644 --- a/vkconfig_core/type_layer_control.h +++ b/vkconfig_core/type_layer_control.h @@ -24,11 +24,11 @@ enum LayerControl { LAYER_CONTROL_AUTO = 0, LAYER_CONTROL_ON, LAYER_CONTROL_OFF, - LAYER_CONTROL_APPLICATIONS, - LAYER_CONTROL_UNORDERED, + LAYER_CONTROL_APPLICATIONS_API, + LAYER_CONTROL_APPLICATIONS_ENV, LAYER_CONTROL_FIRST = LAYER_CONTROL_AUTO, - LAYER_CONTROL_LAST = LAYER_CONTROL_UNORDERED + LAYER_CONTROL_LAST = LAYER_CONTROL_APPLICATIONS_ENV }; enum { LAYER_CONTROL_COUNT = LAYER_CONTROL_LAST - LAYER_CONTROL_FIRST + 1 }; diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/configuration_layer_widget.cpp index 113aa2c425..8694fea46e 100644 --- a/vkconfig_gui/configuration_layer_widget.cpp +++ b/vkconfig_gui/configuration_layer_widget.cpp @@ -27,7 +27,7 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vectortype == LAYER_TYPE_IMPLICIT; - if (parameter.control != LAYER_CONTROL_APPLICATIONS && parameter.control != LAYER_CONTROL_UNORDERED) { + if (parameter.control != LAYER_CONTROL_APPLICATIONS_API && parameter.control != LAYER_CONTROL_APPLICATIONS_ENV) { this->layer_version = new QComboBox(this); this->layer_version->addItem("Latest"); int version_index = 0; @@ -83,7 +83,7 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vectorsetText(decorated_name.c_str()); + + this->setText((" = " + decorated_name).c_str()); } bool ConfigurationLayerWidget::eventFilter(QObject *target, QEvent *event) { @@ -111,8 +112,8 @@ void ConfigurationLayerWidget::resizeEvent(QResizeEvent *event) { if (this->layer_state != nullptr) { const QFontMetrics fm = this->layer_state->fontMetrics(); - const int width_state = std::max(HorizontalAdvance(fm, "Auto 000"), 80); - const int width_version = std::max(HorizontalAdvance(fm, "1.2.199 000"), 80); + const int width_state = HorizontalAdvance(fm, "Auto 000"); + const int width_version = HorizontalAdvance(fm, "1.2.199 000"); const QRect state_button_rect = QRect(size.width() - width_state, 0, width_state, size.height()); this->layer_state->setGeometry(state_button_rect); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 2ec7e97f49..aa36bd905d 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -47,9 +47,6 @@ #include -static const char *TEXT_EXECUTE_CLOSER_APPLICATION = "Execute Closer to the Vulkan Application"; -static const char *TEXT_EXECUTE_CLOSER_DRIVER = "Execute Closer to the Vulkan Driver"; - #if VKC_PLATFORM == VKC_PLATFORM_LINUX || VKC_PLATFORM == VKC_PLATFORM_MACOS #include @@ -278,6 +275,8 @@ MainWindow::MainWindow(QWidget *parent) connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); + this->InitTray(); + Configurator &configurator = Configurator::Get(); Environment &environment = configurator.environment; @@ -337,7 +336,6 @@ MainWindow::MainWindow(QWidget *parent) // ui->splitter_configurations->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER2)); // ui->splitter_settings->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER3)); - this->InitTray(); this->UpdateTray(); this->UpdateUI(); } @@ -410,7 +408,7 @@ void MainWindow::UpdateTray() { break; } - if (environment.global_configuration.GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { + if (environment.GetActiveConfigurationInfo().GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { const QIcon icon(":/resourcefiles/vkconfig-on.png"); this->setWindowIcon(icon); @@ -514,7 +512,9 @@ static std::string GetMainWindowTitle(bool active) { #else std::string title = format("%s %s", VKCONFIG_NAME, Version::VKCONFIG.str().c_str()); #endif - if (active) title += " "; + if (active) { + title += " "; + } return title; } @@ -558,7 +558,7 @@ void MainWindow::AddLayerItem(Parameter ¶meter) { return; } - if (parameter.control != LAYER_CONTROL_APPLICATIONS && parameter.control != LAYER_CONTROL_UNORDERED) { + if (parameter.control != LAYER_CONTROL_APPLICATIONS_API && parameter.control != LAYER_CONTROL_APPLICATIONS_ENV) { decorated_name += " (Missing)"; } } @@ -577,6 +577,12 @@ void MainWindow::AddLayerItem(Parameter ¶meter) { ConfigurationLayerWidget *layer_widget = new ConfigurationLayerWidget(layers, parameter); item_state->widget = layer_widget; + if (parameter.control == LAYER_CONTROL_APPLICATIONS_API) { + item_state->widget->setToolTip("Located and Enabled Layers using the Vulkan API by the Vulkan Application"); + } else if (parameter.control == LAYER_CONTROL_APPLICATIONS_ENV) { + item_state->widget->setToolTip("Located and Enabled Layers using Environment Variables by the Vulkan Application"); + } + ui->layers_tree->setItemWidget(item_state, layer_widget); } @@ -997,6 +1003,9 @@ void MainWindow::on_combo_box_mode_currentIndexChanged(int index) { ui->group_box_configurations->setEnabled(enabled_ui); ui->group_box_settings->setEnabled(enabled_ui); ui->group_box_layers->setEnabled(enabled_ui); + + this->UpdateTray(); + this->UpdateUI(); } void MainWindow::on_combo_box_applications_currentIndexChanged(int index) { @@ -1006,6 +1015,9 @@ void MainWindow::on_combo_box_applications_currentIndexChanged(int index) { Application &application = configurator.environment.GetApplication(index); ui->combo_box_applications->setToolTip(application.executable_path.AbsolutePath().c_str()); ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); + + this->UpdateTray(); + this->UpdateUI(); } void MainWindow::on_check_box_per_application_toggled(bool checked) { @@ -1014,6 +1026,9 @@ void MainWindow::on_check_box_per_application_toggled(bool checked) { ui->combo_box_applications->setEnabled(configurator.environment.GetPerApplicationConfig()); ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); + + this->UpdateTray(); + this->UpdateUI(); } void MainWindow::on_check_box_clear_on_launch_clicked() { diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index a5943de9d9..cd1e3f905e 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 1024 - 640 + 600 @@ -19,7 +19,7 @@ 1024 - 640 + 600 @@ -572,6 +572,12 @@ + + + 0 + 0 + + Configurations @@ -593,6 +599,12 @@ + + + 0 + 0 + + 0 @@ -609,6 +621,12 @@ false + + + 0 + 0 + + 0 @@ -935,7 +953,7 @@ 0 - 0 + 1 @@ -1066,8 +1084,8 @@ - - 0 + + 1 0 @@ -1084,7 +1102,7 @@ 0 - 1 + 0 From e2f3343651d9797af05406f56d354ed622d5f526 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 17 Jul 2024 14:44:38 +0200 Subject: [PATCH 04/33] vkconfig3: Add layer manifest validation caching --- vkconfig_core/configurator.cpp | 17 ++++++++++-- vkconfig_core/configurator.h | 2 ++ vkconfig_core/environment.cpp | 27 +++++++++++++++++++ vkconfig_core/environment.h | 1 + vkconfig_core/layer.cpp | 20 ++++++++------ vkconfig_core/layer.h | 6 ++++- vkconfig_core/layer_manager.cpp | 11 ++++---- vkconfig_core/layer_manager.h | 6 +++-- vkconfig_core/path.cpp | 19 ++++++++++--- vkconfig_core/path.h | 2 ++ .../test/test_configuration_built_in.cpp | 6 +++-- vkconfig_core/test/test_layer.cpp | 20 +++++++------- vkconfig_core/test/test_layer_manager.cpp | 23 ++++++++++------ 13 files changed, 119 insertions(+), 41 deletions(-) diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index eecce05139..fac7602744 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -302,15 +302,28 @@ Configurator& Configurator::Get() { Configurator::Configurator() : environment(), layers(), configurations() {} Configurator::~Configurator() { + this->UpdateLayersValidationCache(); + this->configurations.SaveAllConfigurations(); this->Surrender(); } +void Configurator::UpdateLayersValidationCache() { + this->environment.layers_validated.clear(); + + for (std::size_t i = 0, n = this->layers.Size(); i < n; ++i) { + const Layer& layer = this->layers.selected_layers[i]; + + this->environment.layers_validated.insert( + std::make_pair(layer.manifest_path.AbsolutePath(), layer.validated_last_modified)); + } +} + bool Configurator::Init() { // Load simple app settings, the additional search paths, and the // override app list. - this->layers.LoadAllInstalledLayers(); + this->layers.LoadAllInstalledLayers(environment.layers_validated); if (this->environment.has_crashed) { this->environment.has_crashed = false; @@ -373,7 +386,7 @@ bool Configurator::HasOverride() const { void Configurator::ResetToDefault(bool hard) { this->environment.Reset(Environment::CLEAR); - this->layers.LoadAllInstalledLayers(); + this->layers.LoadAllInstalledLayers(this->environment.layers_validated); this->configurations.Reset(this->layers.selected_layers); } diff --git a/vkconfig_core/configurator.h b/vkconfig_core/configurator.h index 0e50464f6d..bc5fe0117a 100644 --- a/vkconfig_core/configurator.h +++ b/vkconfig_core/configurator.h @@ -77,6 +77,8 @@ class Configurator { void BuildLoaderSettings(const ConfigurationInfo& info, const std::string& executable_path, std::vector& loader_settings_array) const; + void UpdateLayersValidationCache(); + public: Environment environment; LayerManager layers; diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index 78921ba4e3..594cc5e96c 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -37,6 +37,7 @@ #include #include +#include static const char* GetApplicationSuffix() { static const char* TABLE[] = { @@ -163,6 +164,18 @@ bool Environment::Load() { this->loader_message_types_flags |= GetLogBit(token.c_str()); } + // layers json object + const QJsonObject& json_layers_object = json_root_object.value("layers").toObject(); + const QJsonObject& json_layers_validated_object = json_layers_object.value("validated").toObject(); + + const QStringList& json_layers_validated_keys = json_layers_validated_object.keys(); + + for (int i = 0, n = json_layers_validated_keys.length(); i < n; ++i) { + const std::string& manifest_path = json_layers_validated_keys[i].toStdString(); + const std::string& last_modified = json_layers_validated_object.value(manifest_path.c_str()).toString().toStdString(); + layers_validated.insert(std::make_pair(manifest_path, last_modified)); + } + // applications json object const QJsonObject& json_applications_object = json_root_object.value("applications").toObject(); @@ -239,9 +252,17 @@ bool Environment::Load() { bool Environment::Save() const { const Path& vkconfig_init_path = ::Get(Path::INIT); + if (Path(vkconfig_init_path.AbsoluteDir()).Exists()) { + std::cout << Path(vkconfig_init_path).AbsoluteDir() << " exists." << std::endl; + } else { + std::cout << Path(vkconfig_init_path).AbsoluteDir() << " doesn't exist." << std::endl; + } QFile file(vkconfig_init_path.AbsolutePath().c_str()); const bool result = file.open(QIODevice::WriteOnly | QIODevice::Text); + if (result == false) { + std::cout << vkconfig_init_path.AbsolutePath().c_str() << std::endl; + } assert(result); QJsonObject json_root_object; @@ -309,7 +330,13 @@ bool Environment::Save() const { json_root_object.insert("applications", json_applications_object); + QJsonObject json_layers_paths_object; + for (auto it = this->layers_validated.begin(), end = this->layers_validated.end(); it != end; ++it) { + json_layers_paths_object.insert(it->first.c_str(), it->second.c_str()); + } + QJsonObject json_layers_object; + json_layers_object.insert("validated", json_layers_paths_object); json_root_object.insert("layers", json_layers_object); diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index e5856060d9..5122478527 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -115,6 +115,7 @@ class Environment { Path path_import; ConfigurationInfo global_configuration; + std::map layers_validated; private: Environment(const Environment&) = delete; diff --git a/vkconfig_core/layer.cpp b/vkconfig_core/layer.cpp index f0790aaaf2..d7c6ff9202 100644 --- a/vkconfig_core/layer.cpp +++ b/vkconfig_core/layer.cpp @@ -134,7 +134,7 @@ SettingMeta* Layer::Instantiate(SettingMetaSet& meta_set, const std::string& key return setting_meta; } -bool Layer::Load(const Path& full_path_to_file, LayerType type) { +bool Layer::Load(const Path& full_path_to_file, const std::map& layers_validated, LayerType type) { this->type = type; // Set layer type, no way to know this from the json file if (full_path_to_file.Empty()) { @@ -182,10 +182,7 @@ bool Layer::Load(const Path& full_path_to_file, LayerType type) { const QJsonObject& json_layer_object = ReadObject(json_root_object, "layer"); - std::string current_last_modified = full_path_to_file.LastModified(); - - QSettings settings; - std::string cached_last_modified = settings.value(full_path_to_file.AbsolutePath().c_str()).toString().toStdString(); + const std::string& last_modified = full_path_to_file.LastModified(); this->key = ReadStringValue(json_layer_object, "name"); @@ -197,11 +194,18 @@ bool Layer::Load(const Path& full_path_to_file, LayerType type) { JsonValidator validator; - const bool should_validate = current_last_modified != cached_last_modified; + std::string cached_last_modified; + auto it = layers_validated.find(this->manifest_path.AbsolutePath()); + if (it != layers_validated.end()) { + cached_last_modified = it->second; + } + const bool should_validate = !this->manifest_path.IsBuiltIn() && last_modified != cached_last_modified; const bool is_valid = should_validate ? validator.Check(json_text) : true; - if (should_validate && is_valid) { - settings.setValue(full_path_to_file.AbsolutePath().c_str(), current_last_modified.c_str()); + if (!is_valid) { + this->validated_last_modified.clear(); + } else { + this->validated_last_modified = last_modified; } const QJsonValue& json_library_path_value = json_layer_object.value("library_path"); diff --git a/vkconfig_core/layer.h b/vkconfig_core/layer.h index 9d049dbb75..871238dbde 100644 --- a/vkconfig_core/layer.h +++ b/vkconfig_core/layer.h @@ -59,6 +59,7 @@ class Layer { Path binary_path; Version api_version; std::string implementation_version; + std::string validated_last_modified; StatusType status; std::string description; std::string introduction; @@ -75,11 +76,14 @@ class Layer { std::vector settings; std::vector presets; - bool Load(const Path& full_path_to_file, LayerType type = LAYER_TYPE_EXPLICIT); + bool Load(const Path& full_path_to_file, const std::map& layers_validated, + LayerType type = LAYER_TYPE_EXPLICIT); private: Layer& operator=(const Layer&) = delete; + bool IsBuiltIn() const; + std::vector > memory; // Settings are deleted when all layers instances are deleted. }; diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 80776777fa..d284017598 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -124,8 +124,6 @@ LayerManager::LayerManager(const std::vector &user_defined_paths) { user_defined_paths.end()); this->paths[LAYERS_PATHS_SDK].push_back(::Get(Path::SDK_BIN)); - - this->LoadAllInstalledLayers(); } void LayerManager::Clear() { this->selected_layers.clear(); } @@ -147,7 +145,7 @@ const Layer *LayerManager::Find(const std::string &layer_name) const { } // Find all installed layers on the system. -void LayerManager::LoadAllInstalledLayers() { +void LayerManager::LoadAllInstalledLayers(const std::map &layers_validated) { this->selected_layers.clear(); for (std::size_t group_index = 0, group_count = this->paths.size(); group_index < group_count; ++group_index) { @@ -155,17 +153,18 @@ void LayerManager::LoadAllInstalledLayers() { const std::vector &paths_group = this->paths[group_index]; for (std::size_t i = 0, n = paths_group.size(); i < n; ++i) { - this->LoadLayersFromPath(paths_group[i], layer_type); + this->LoadLayersFromPath(paths_group[i], layers_validated, layer_type); } } } -void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { +void LayerManager::LoadLayersFromPath(const Path &layers_path, const std::map &layers_validated, + LayerType type) { const std::vector &layers_paths = layers_path.IsDir() ? CollectFilePaths(layers_path) : GetVector(layers_path); for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { Layer layer; - if (layer.Load(layers_paths[i], type)) { + if (layer.Load(layers_paths[i], layers_validated, type)) { if (this->IsAvailable(layer)) { continue; } diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index 339a286a65..a4a33ecf4c 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -54,8 +54,10 @@ class LayerManager { Layer* Find(const std::string& layer_name); const Layer* Find(const std::string& layer_name) const; - void LoadAllInstalledLayers(); - void LoadLayersFromPath(const Path& layers_path, LayerType type = LAYER_TYPE_EXPLICIT); + void LoadAllInstalledLayers(const std::map& layers_validated); + + void LoadLayersFromPath(const Path& layers_path, const std::map& layers_validated, + LayerType type = LAYER_TYPE_EXPLICIT); std::vector selected_layers; diff --git a/vkconfig_core/path.cpp b/vkconfig_core/path.cpp index 3b136a2064..6221650d15 100644 --- a/vkconfig_core/path.cpp +++ b/vkconfig_core/path.cpp @@ -112,6 +112,8 @@ bool Path::IsFile() const { return QFileInfo(this->data.c_str()).isFile(); } bool Path::IsDir() const { return QFileInfo(this->data.c_str()).isDir(); } +bool Path::IsBuiltIn() const { return this->data.find(":") == 0; } + Path& Path::operator=(const Path& path) { this->data = path.data; return *this; @@ -223,7 +225,6 @@ static const Path GetHomePath() { } Path path(result); - if (!path.Exists()) { path.Create(); } @@ -238,7 +239,12 @@ static const Path GetAppDataPath() { }; static_assert(std::size(TABLE) == ENVIRONMENT_COUNT); - return QDir().homePath().toStdString() + TABLE[VKC_ENV]; + Path path(QDir().homePath().toStdString() + TABLE[VKC_ENV]); + if (!path.Exists()) { + path.Create(); + } + + return path; } static const Path GetInitPath() { @@ -248,7 +254,14 @@ static const Path GetInitPath() { }; static_assert(std::size(TABLE) == ENVIRONMENT_COUNT); - return GetAppDataPath().RelativePath() + TABLE[VKC_ENV]; + Path path(GetAppDataPath().RelativePath() + TABLE[VKC_ENV]); + Path folder(path.AbsoluteDir()); + + if (!folder.Exists()) { + folder.Create(); + } + + return path; } static const Path GetConfigsPath() { diff --git a/vkconfig_core/path.h b/vkconfig_core/path.h index 9ddc71bc26..4babccdcf4 100644 --- a/vkconfig_core/path.h +++ b/vkconfig_core/path.h @@ -52,6 +52,8 @@ class Path { bool IsFile() const; bool IsDir() const; + bool IsBuiltIn() const; + void Clear(); bool Exists() const; bool Create(bool as_file = false) const; diff --git a/vkconfig_core/test/test_configuration_built_in.cpp b/vkconfig_core/test/test_configuration_built_in.cpp index ca3d0f7160..8185814f2a 100644 --- a/vkconfig_core/test/test_configuration_built_in.cpp +++ b/vkconfig_core/test/test_configuration_built_in.cpp @@ -60,9 +60,11 @@ static bool operator==(const Parameter& a, const Parameter& b) { static bool operator!=(const std::vector& a, const std::vector& b) { return !(a == b); } +std::map Dummy() { return std::map(); } + struct TestBuilin { - TestBuilin() : environment(), layer_manager() { - this->layer_manager.LoadLayersFromPath(":/sdk"); + TestBuilin() : environment(Environment::MODE_UNINITIALIZED), layer_manager() { + this->layer_manager.LoadLayersFromPath(":/sdk", Dummy()); EXPECT_TRUE(!this->layer_manager.selected_layers.empty()); } diff --git a/vkconfig_core/test/test_layer.cpp b/vkconfig_core/test/test_layer.cpp index cc61f0e102..23852f2fcb 100644 --- a/vkconfig_core/test/test_layer.cpp +++ b/vkconfig_core/test/test_layer.cpp @@ -36,6 +36,8 @@ inline SettingMetaString* InstantiateString(Layer& layer, const std::string& key return static_cast(layer.Instantiate(layer.settings, key, SETTING_STRING)); } +std::map Dummy() { return std::map(); } + TEST(test_layer, collect_settings) { Layer layer; @@ -58,7 +60,7 @@ TEST(test_layer, collect_settings) { TEST(test_layer, load_header_overridden) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_00.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_00.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -76,7 +78,7 @@ TEST(test_layer, load_header_overridden) { TEST(test_layer, load_header_default) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_01.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_01.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -94,7 +96,7 @@ TEST(test_layer, load_header_default) { TEST(test_layer, load_header_override) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_02.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_02.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -106,7 +108,7 @@ TEST(test_layer, load_header_override) { TEST(test_layer, load_setting_interit) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_03.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_03.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -128,7 +130,7 @@ TEST(test_layer, load_setting_interit) { TEST(test_layer, load_preset_interit) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_04.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_04.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -148,7 +150,7 @@ TEST(test_layer, load_preset_interit) { TEST(test_layer, load_setting_children_interit) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_05.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_05.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -170,7 +172,7 @@ TEST(test_layer, load_setting_children_interit) { TEST(test_layer, load_setting_enum_interit) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_06.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_test_06.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 2, 0), layer.file_format_version); @@ -212,7 +214,7 @@ TEST(test_layer, load_setting_enum_interit) { TEST(test_layer, load_1_1_0_header) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); EXPECT_EQ(Version(1, 1, 0), layer.file_format_version); @@ -230,7 +232,7 @@ TEST(test_layer, load_1_1_0_header) { TEST(test_layer, load_1_2_0_preset_and_setting_type) { Layer layer; - const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_reference_1_2_0.json", LAYER_TYPE_EXPLICIT); + const bool load_loaded = layer.Load(":/layers/VK_LAYER_LUNARG_reference_1_2_0.json", Dummy(), LAYER_TYPE_EXPLICIT); ASSERT_TRUE(load_loaded); // Preset Enum diff --git a/vkconfig_core/test/test_layer_manager.cpp b/vkconfig_core/test/test_layer_manager.cpp index b81e10f6c0..ce40a13157 100644 --- a/vkconfig_core/test/test_layer_manager.cpp +++ b/vkconfig_core/test/test_layer_manager.cpp @@ -19,12 +19,14 @@ */ #include "../layer_manager.h" +#include "../environment.h" #include +std::map Dummy() { return std::map(); } + TEST(test_layer_manager, clear) { LayerManager layer_manager; - layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); EXPECT_TRUE(layer_manager.Size() == 0); @@ -34,7 +36,10 @@ TEST(test_layer_manager, load_all) { std::vector user_defined_paths; user_defined_paths.push_back(":/layers"); + Environment environment; + LayerManager layer_manager(user_defined_paths); + layer_manager.LoadAllInstalledLayers(environment.layers_validated); EXPECT_TRUE(layer_manager.Size() >= 10); EXPECT_TRUE(!layer_manager.Empty()); @@ -45,10 +50,9 @@ TEST(test_layer_manager, load_all) { TEST(test_layer_manager, load_dir) { LayerManager layer_manager; - layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); - layer_manager.LoadLayersFromPath(":/layers"); + layer_manager.LoadLayersFromPath(":/layers", Dummy()); EXPECT_TRUE(!layer_manager.Empty()); EXPECT_EQ(10, layer_manager.Size()); @@ -61,10 +65,9 @@ TEST(test_layer_manager, load_dir) { TEST(test_layer_manager, load_file) { LayerManager layer_manager; - layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); - layer_manager.LoadLayersFromPath(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json"); + layer_manager.LoadLayersFromPath(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json", Dummy()); EXPECT_TRUE(!layer_manager.Empty()); EXPECT_EQ(1, layer_manager.Size()); @@ -79,7 +82,12 @@ TEST(test_layer_manager, find) { std::vector user_defined_paths; user_defined_paths.push_back(":/layers"); + Environment environment; + LayerManager layer_manager(user_defined_paths); + EXPECT_TRUE(layer_manager.Empty()); + + layer_manager.LoadAllInstalledLayers(environment.layers_validated); EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_test_03") != nullptr); @@ -87,12 +95,11 @@ TEST(test_layer_manager, find) { TEST(test_layer_manager, avoid_duplicate) { LayerManager layer_manager; - layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); - layer_manager.LoadLayersFromPath(":/layers"); + layer_manager.LoadLayersFromPath(":/layers", Dummy()); EXPECT_EQ(10, layer_manager.Size()); - layer_manager.LoadLayersFromPath(":/layers"); + layer_manager.LoadLayersFromPath(":/layers", Dummy()); EXPECT_EQ(10, layer_manager.Size()); } From 0c4dec0c766e61385f4490d0e15864856c7bcd81 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 23 Jul 2024 16:38:07 +0200 Subject: [PATCH 05/33] vkconfig3: Add full layer ordering support --- vkconfig_core/configuration.cpp | 32 +++++++++- vkconfig_core/configuration.h | 1 + vkconfig_core/configurator.cpp | 33 ++++++---- vkconfig_core/parameter.cpp | 27 ++++----- .../test/test_configuration_built_in.cpp | 15 +++-- vkconfig_gui/configuration_layer_widget.cpp | 9 ++- vkconfig_gui/mainwindow.cpp | 60 ++++++++----------- vkconfig_gui/mainwindow.h | 2 + vkconfig_gui/settings_tree.cpp | 51 ++++++++++++---- 9 files changed, 143 insertions(+), 87 deletions(-) diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index 94d5c0542d..eee54a5f77 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -39,9 +39,34 @@ #include #include +static void AddApplicationEnabledParameters(std::vector& parameters) { + Parameter applications_enabled_layers_api; + applications_enabled_layers_api.key = "Vulkan Layers from the Application Vulkan API"; + applications_enabled_layers_api.control = LAYER_CONTROL_APPLICATIONS_API; + applications_enabled_layers_api.overridden_rank = 998; + parameters.push_back(applications_enabled_layers_api); + + Parameter applications_enabled_layers_env; + applications_enabled_layers_env.key = "Vulkan Layers from Application Environment Variables"; + applications_enabled_layers_env.control = LAYER_CONTROL_APPLICATIONS_ENV; + applications_enabled_layers_env.overridden_rank = 999; + parameters.push_back(applications_enabled_layers_env); +} + Configuration::Configuration() : key("New Configuration"), version(1), platform_flags(PLATFORM_DESKTOP_BIT), view_advanced_settings(false) {} +Configuration Configuration::Create(const std::vector& available_layers, const std::string& key) { + Configuration result; + + result.key = key; + result.parameters = GatherParameters(result.parameters, available_layers); + + AddApplicationEnabledParameters(result.parameters); + + return result; +} + Configuration Configuration::CreateDisabled(const std::vector& available_layers) { Configuration result; result.key = "_DisablingConfiguration"; @@ -51,6 +76,8 @@ Configuration Configuration::CreateDisabled(const std::vector& available_ result.parameters[i].control = LAYER_CONTROL_OFF; } + AddApplicationEnabledParameters(result.parameters); + return result; } @@ -191,6 +218,8 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa this->parameters.push_back(parameter); } + this->parameters = GatherParameters(this->parameters, available_layers); + return true; } @@ -213,9 +242,6 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { for (std::size_t i = 0, n = this->parameters.size(); i < n; ++i) { const Parameter& parameter = this->parameters[i]; - if (parameter.control == LAYER_CONTROL_AUTO) { - continue; - } QJsonObject json_layer; json_layer.insert("name", parameter.key.c_str()); diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index fe89c3c0e3..4f0a29e8bc 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -33,6 +33,7 @@ class Configuration { Configuration(); static Configuration CreateDisabled(const std::vector& available_layers); + static Configuration Create(const std::vector& available_layers, const std::string& key); bool Load(const Path& full_path, const std::vector& available_layers); bool Save(const Path& full_path, bool exporter = false) const; diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index fac7602744..3bb0f1eb33 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -43,10 +43,13 @@ static QJsonObject CreateJsonSettingObject(const Configurator::LoaderSettings& l const Configurator::LoaderLayerSettings& layer = loader_settings.layers[j]; QJsonObject json_layer; - json_layer.insert("name", layer.key.c_str()); - json_layer.insert("path", layer.path.c_str()); + if (layer.control != LAYER_CONTROL_APPLICATIONS_API && layer.control != LAYER_CONTROL_APPLICATIONS_ENV) { + json_layer.insert("name", layer.key.c_str()); + json_layer.insert("path", layer.path.c_str()); + json_layer.insert("treat_as_implicit_manifest", layer.implicit); + } + json_layer.insert("control", ToLowerCase(::GetToken(layer.control)).c_str()); - json_layer.insert("treat_as_implicit_manifest", layer.implicit); json_layers.append(json_layer); } @@ -100,18 +103,22 @@ void Configurator::BuildLoaderSettings(const ConfigurationInfo& info, const std: continue; } - const Layer* layer = FindByKey(this->layers.selected_layers, parameter.key.c_str()); - if (layer == nullptr) { - continue; - } + if (parameter.control == LAYER_CONTROL_APPLICATIONS_API || parameter.control == LAYER_CONTROL_APPLICATIONS_ENV) { + loader_layer_settings.control = parameter.control; + } else { + const Layer* layer = FindByKey(this->layers.selected_layers, parameter.key.c_str()); + if (layer == nullptr) { + continue; + } - // Extract just the path - loader_layer_settings.key = parameter.key; - if (layer != nullptr) { - loader_layer_settings.path = layer->manifest_path.AbsolutePath(); + // Extract just the path + loader_layer_settings.key = parameter.key; + if (layer != nullptr) { + loader_layer_settings.path = layer->manifest_path.AbsolutePath(); + } + loader_layer_settings.control = parameter.control; + loader_layer_settings.implicit = layer != nullptr ? layer->type == LAYER_TYPE_IMPLICIT : false; } - loader_layer_settings.control = parameter.control; - loader_layer_settings.implicit = layer != nullptr ? layer->type == LAYER_TYPE_IMPLICIT : false; result.layers.push_back(loader_layer_settings); } diff --git a/vkconfig_core/parameter.cpp b/vkconfig_core/parameter.cpp index b36ae456b8..61328da85f 100644 --- a/vkconfig_core/parameter.cpp +++ b/vkconfig_core/parameter.cpp @@ -40,8 +40,13 @@ bool Parameter::ApplyPresetSettings(const LayerPreset& preset) { for (std::size_t i = 0, n = this->settings.size(); i < n; ++i) { SettingData* current_setting = this->settings[i]; - if (current_setting->key != preset_setting->key) continue; - if (current_setting->type != preset_setting->type) continue; + if (current_setting->key != preset_setting->key) { + continue; + } + + if (current_setting->type != preset_setting->type) { + continue; + } this->settings[i]->Copy(preset_setting); } @@ -238,25 +243,13 @@ std::vector GatherParameters(const std::vector& parameters Parameter parameter; parameter.key = layer.key; parameter.control = LAYER_CONTROL_AUTO; - // parameter.api_version = layer.api_version; - // CollectDefaultSettingData(layer.settings, parameter.settings); + parameter.api_version = Version::VERSION_NULL; + CollectDefaultSettingData(layer.settings, parameter.settings); gathered_parameters.push_back(parameter); } - OrderParameter(gathered_parameters, available_layers); - - Parameter applications_enabled_layers_api; - applications_enabled_layers_api.key = "Vulkan Application Layers from the Vulkan API"; - applications_enabled_layers_api.control = LAYER_CONTROL_APPLICATIONS_API; - applications_enabled_layers_api.overridden_rank = 998; - gathered_parameters.push_back(applications_enabled_layers_api); - - Parameter applications_enabled_layers_env; - applications_enabled_layers_env.key = "Vulkan Application Layers from Environment Variables"; - applications_enabled_layers_env.control = LAYER_CONTROL_APPLICATIONS_ENV; - applications_enabled_layers_env.overridden_rank = 999; - gathered_parameters.push_back(applications_enabled_layers_env); + // OrderParameter(gathered_parameters, available_layers); return gathered_parameters; } diff --git a/vkconfig_core/test/test_configuration_built_in.cpp b/vkconfig_core/test/test_configuration_built_in.cpp index 8185814f2a..3c74fa7880 100644 --- a/vkconfig_core/test/test_configuration_built_in.cpp +++ b/vkconfig_core/test/test_configuration_built_in.cpp @@ -101,35 +101,38 @@ TEST(test_built_in_load, sdk_layers_with_configuration) { { Configuration load_api_dump = test.Load("API dump"); - EXPECT_EQ(1, load_api_dump.Size()); Configuration save_api_dump = test.Restore(load_api_dump); - EXPECT_EQ(save_api_dump, load_api_dump); + EXPECT_STREQ(save_api_dump.key.c_str(), load_api_dump.key.c_str()); + EXPECT_STREQ(save_api_dump.description.c_str(), load_api_dump.description.c_str()); + EXPECT_EQ(save_api_dump.version, load_api_dump.version); + EXPECT_EQ(save_api_dump.platform_flags, load_api_dump.platform_flags); + EXPECT_EQ(save_api_dump.setting_tree_state, load_api_dump.setting_tree_state); + EXPECT_EQ(save_api_dump.parameters.size(), load_api_dump.parameters.size()); + for (std::size_t i = 0, n = save_api_dump.parameters.size(); i < n; ++i) { + EXPECT_EQ(save_api_dump.parameters[i], load_api_dump.parameters[i]); + } } { Configuration load_frame_capture = test.Load("Frame Capture"); - EXPECT_EQ(1, load_frame_capture.Size()); Configuration save_frame_capture = test.Restore(load_frame_capture); EXPECT_EQ(save_frame_capture, load_frame_capture); } { Configuration load_portability = test.Load("Portability"); - EXPECT_EQ(2, load_portability.Size()); Configuration save_portability = test.Restore(load_portability); EXPECT_EQ(save_portability, load_portability); } { Configuration load_synchronization = test.Load("Synchronization"); - EXPECT_EQ(2, load_synchronization.Size()); Configuration save_synchronization = test.Restore(load_synchronization); EXPECT_EQ(save_synchronization, load_synchronization); } { Configuration load_validation = test.Load("Validation"); - EXPECT_EQ(1, load_validation.Size()); Configuration save_validation = test.Restore(load_validation); EXPECT_EQ(save_validation, load_validation); } diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/configuration_layer_widget.cpp index 8694fea46e..b2a1a9ac87 100644 --- a/vkconfig_gui/configuration_layer_widget.cpp +++ b/vkconfig_gui/configuration_layer_widget.cpp @@ -100,7 +100,14 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vectortype() == QEvent::Wheel) { + QEvent::Type event_type = event->type(); + + if (event_type == QEvent::Wheel) { + return true; + } + + if (event_type == QEvent::DragEnter || event_type == QEvent::DragMove || event_type == QEvent::DragLeave || + event_type == QEvent::DragEnter) { return true; } diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index aa36bd905d..a221f84fc7 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -84,10 +84,14 @@ static PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) { /// Utility function to see if the file is 32-bit static bool IsDLL32Bit(const std::string full_path) { #if VKC_PLATFORM == VKC_PLATFORM_WINDOWS - if (full_path.empty()) return false; + if (full_path.empty()) { + return false; + } QFile file(full_path.c_str()); - if (!file.open(QIODevice::ReadOnly)) return false; // punt... + if (!file.open(QIODevice::ReadOnly)) { + return false; // punt... + } // Not gonna lie, just guessed 1024 and it was enough. // This is the minimum page size on any OS (I might be wrong, @@ -96,7 +100,9 @@ static bool IsDLL32Bit(const std::string full_path) { void *header = file.map(0, 4096, QFileDevice::MapPrivateOption); // Another punt as we may not be able to map the file - if (header == nullptr) return false; + if (header == nullptr) { + return false; + } PE_ARCHITECTURE arch = GetImageArchitecture(header); @@ -264,6 +270,11 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->configurations_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(OnConfigurationTreeClicked(QTreeWidgetItem *, int))); + connect(ui->layers_tree, SIGNAL(itemChanged(QListWidgetItem *, int)), this, SLOT(OnLayersItemChanged(QListWidgetItem *, int))); + connect(ui->layers_tree, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, + SLOT(OnLayersTreeChanged(QListWidgetItem *, QListWidgetItem *))); + connect(ui->layers_tree, SIGNAL(indexesMoved(int)), this, SLOT(OnLayersIndexesMoved(const QModelIndexList &))); + connect(ui->settings_tree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(editorExpanded(QTreeWidgetItem *))); connect(ui->settings_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(OnSettingsTreeClicked(QTreeWidgetItem *, int))); @@ -710,38 +721,9 @@ void MainWindow::UpdateUI() { Configuration *configuration = FindByKey(configurator.configurations.available_configurations, selected_contiguration_name.c_str()); if (configuration != nullptr) { - std::vector parameters = GatherParameters(configuration->parameters, configurator.layers.selected_layers); - /* - { - QListWidgetItem *item = new QListWidgetItem(); - ui->layers_tree->addItem(item); - item->setText(TEXT_EXECUTE_CLOSER_APPLICATION); - //item->setFlags(item->flags() & ~Qt::ItemIsSelectable); - item->setFlags(0); - item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); - QFont font = item->font(); - font.setItalic(true); - item->setFont(font); - // item->setDisabled(true); - } - */ - for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - AddLayerItem(parameters[i]); + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + AddLayerItem(configuration->parameters[i]); } - /* - { - QListWidgetItem *item = new QListWidgetItem(); - ui->layers_tree->addItem(item); - item->setText(TEXT_EXECUTE_CLOSER_DRIVER); - //item->setFlags(item->flags() & ~Qt::ItemIsSelectable); - item->setFlags(0); - item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); - QFont font = item->font(); - font.setItalic(true); - item->setFont(font); - // item->setDisabled(true); - } - */ resizeEvent(nullptr); ui->layers_tree->update(); @@ -1807,7 +1789,15 @@ static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { } bool MainWindow::eventFilter(QObject *target, QEvent *event) { - if (event->type() == QEvent::Wheel) { + QEvent::Type event_type = event->type(); + + if (event_type == QEvent::Wheel) { + return true; + } + + if (event_type == QEvent::ChildRemoved) { + // Layers were reordered, we need to update the configuration + Configurator::Get().Override(); return true; } diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index a114b272fe..f38d6e3014 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -215,7 +215,9 @@ class MainWindow : public QMainWindow { void OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); void OnConfigurationItemChanged(QTreeWidgetItem *item, int column); void OnConfigurationTreeClicked(QTreeWidgetItem *item, int column); + void OnSettingsTreeClicked(QTreeWidgetItem *item, int column); + void OnLauncherLoaderMessageChanged(int level); void standardOutputAvailable(); // stdout output is available diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 7c0817998d..e209f91fd1 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -91,11 +91,15 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { if (!IsPlatformSupported(parameter.platform_flags)) { continue; } - /* - if (parameter.control != LAYER_STATE_OVERRIDDEN) { + + if (parameter.control == LAYER_CONTROL_APPLICATIONS_API || parameter.control == LAYER_CONTROL_APPLICATIONS_ENV) { + continue; + } + + if (parameter.settings.empty()) { continue; } - */ + const std::vector &selected_layers = configurator.layers.selected_layers; const Layer *layer = FindByKey(selected_layers, parameter.key.c_str()); @@ -113,16 +117,12 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { layer_item->setText(0, layer_text.c_str()); layer_item->setFont(0, font_layer); layer_item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - if (layer != nullptr) layer_item->setToolTip(0, layer->description.c_str()); - layer_item->setExpanded(true); - - if (layer == nullptr) continue; + if (layer != nullptr) { + layer_item->setToolTip(0, layer->description.c_str()); + } + layer_item->setExpanded(parameter.control == LAYER_CONTROL_ON); - // Handle the case were we get off easy. No settings. - if (parameter.settings.empty()) { - QTreeWidgetItem *layer_child_item = new QTreeWidgetItem(); - layer_child_item->setText(0, "No User Settings"); - layer_item->addChild(layer_child_item); + if (layer == nullptr) { continue; } @@ -201,7 +201,34 @@ void SettingsTreeManager::OnCollapsedChanged(const QModelIndex &index) { } } +static bool IsBuiltinValidationSetting(const Parameter ¶meter, const std::string &key) { + if (parameter.key != "VK_LAYER_KHRONOS_validation") { + return false; + } + + std::vector keys; + keys.push_back("enables"); + keys.push_back("disables"); + + if (parameter.api_version.GetPatch() < 242) { + keys.push_back("printf_to_stdout"); + keys.push_back("printf_verbose"); + keys.push_back("printf_buffer_size"); + keys.push_back("gpuav_buffer_oob"); + keys.push_back("warn_on_robust_oob"); + keys.push_back("validate_draw_indirect"); + keys.push_back("vma_linear_output"); + keys.push_back("fine_grained_locking"); + } + + return IsStringFound(keys, key); +} + void SettingsTreeManager::BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶meter, const SettingMeta &meta_object) { + if (IsBuiltinValidationSetting(parameter, meta_object.key)) { + return; + } + if (!IsPlatformSupported(meta_object.platform_flags)) { return; } From 1865a1dc012af7083779d545ce862d3181a12724 Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 25 Jul 2024 20:46:03 +0200 Subject: [PATCH 06/33] vkconfig3: Configuration tab UI --- vkconfig_core/configuration.cpp | 56 +++-- vkconfig_core/configuration.h | 11 +- vkconfig_core/configurator.cpp | 2 +- vkconfig_core/environment.h | 2 + vkconfig_core/test/test_configuration.cpp | 2 +- vkconfig_core/type_layer_control.cpp | 9 +- vkconfig_core/type_layer_control.h | 5 +- vkconfig_gui/configuration_layer_widget.cpp | 18 +- vkconfig_gui/configuration_layer_widget.h | 2 +- vkconfig_gui/mainwindow.cpp | 221 ++++++++++++-------- vkconfig_gui/mainwindow.h | 9 +- vkconfig_gui/mainwindow.ui | 178 ++++++---------- vkconfig_gui/settings_tree.cpp | 21 +- vkconfig_gui/settings_tree.h | 2 +- 14 files changed, 285 insertions(+), 253 deletions(-) diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index eee54a5f77..3a69773c60 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -40,21 +40,42 @@ #include static void AddApplicationEnabledParameters(std::vector& parameters) { - Parameter applications_enabled_layers_api; - applications_enabled_layers_api.key = "Vulkan Layers from the Application Vulkan API"; - applications_enabled_layers_api.control = LAYER_CONTROL_APPLICATIONS_API; - applications_enabled_layers_api.overridden_rank = 998; - parameters.push_back(applications_enabled_layers_api); - - Parameter applications_enabled_layers_env; - applications_enabled_layers_env.key = "Vulkan Layers from Application Environment Variables"; - applications_enabled_layers_env.control = LAYER_CONTROL_APPLICATIONS_ENV; - applications_enabled_layers_env.overridden_rank = 999; - parameters.push_back(applications_enabled_layers_env); -} + bool found_applications_api = false; + for (auto paramater : parameters) { + if (paramater.control != LAYER_CONTROL_APPLICATIONS_API) { + continue; + } + + found_applications_api = true; + break; + } -Configuration::Configuration() - : key("New Configuration"), version(1), platform_flags(PLATFORM_DESKTOP_BIT), view_advanced_settings(false) {} + if (!found_applications_api) { + Parameter applications_enabled_layers_api; + applications_enabled_layers_api.key = "Vulkan Layers from the Application Vulkan API"; + applications_enabled_layers_api.control = LAYER_CONTROL_APPLICATIONS_API; + applications_enabled_layers_api.overridden_rank = 998; + parameters.push_back(applications_enabled_layers_api); + } + + bool found_applications_env = false; + for (auto paramater : parameters) { + if (paramater.control != LAYER_CONTROL_APPLICATIONS_ENV) { + continue; + } + + found_applications_env = true; + break; + } + + if (!found_applications_env) { + Parameter applications_enabled_layers_env; + applications_enabled_layers_env.key = "Vulkan Layers from Application Environment Variables"; + applications_enabled_layers_env.control = LAYER_CONTROL_APPLICATIONS_ENV; + applications_enabled_layers_env.overridden_rank = 999; + parameters.push_back(applications_enabled_layers_env); + } +} Configuration Configuration::Create(const std::vector& available_layers, const std::string& key) { Configuration result; @@ -129,6 +150,10 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa this->view_advanced_settings = ReadBoolValue(json_configuration_object, "view_advanced_settings"); } + if (json_configuration_object.value("view_advanced_layers") != QJsonValue::Undefined) { + this->view_advanced_layers = ReadBoolValue(json_configuration_object, "view_advanced_layers"); + } + if (json_configuration_object.value("platforms") != QJsonValue::Undefined) { this->platform_flags = GetPlatformFlags(ReadStringArray(json_configuration_object, "platforms")); } @@ -220,6 +245,8 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa this->parameters = GatherParameters(this->parameters, available_layers); + AddApplicationEnabledParameters(this->parameters); + return true; } @@ -282,6 +309,7 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { json_configuration.insert("expanded_states", this->setting_tree_state.data()); } json_configuration.insert("view_advanced_settings", this->view_advanced_settings); + json_configuration.insert("view_advanced_layers", this->view_advanced_layers); json_configuration.insert("layers", json_layers); QJsonArray json_paths; diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index 4f0a29e8bc..d7d23c1502 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -30,8 +30,6 @@ class Configuration { public: - Configuration(); - static Configuration CreateDisabled(const std::vector& available_layers); static Configuration Create(const std::vector& available_layers, const std::string& key); @@ -44,12 +42,13 @@ class Configuration { std::size_t Size() const { return this->parameters.size(); }; - std::string key; // User readable display of the configuration name (may contain spaces) - int version; - int platform_flags; + std::string key = "New Configuration"; // User readable display of the configuration name (may contain spaces) + int version = 1; + int platform_flags = PLATFORM_DESKTOP_BIT; std::string description; // A friendly description of what this profile does QByteArray setting_tree_state; // Recall editor tree state - bool view_advanced_settings; + bool view_advanced_settings = false; + bool view_advanced_layers = false; std::vector parameters; std::vector user_defined_paths; diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index 3bb0f1eb33..2ffd679fee 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -223,7 +223,7 @@ bool Configurator::WriteLayersSettings(const Path& layers_settings_path) { continue; } - const Layer* layer = FindByKey(this->layers.selected_layers, parameter.key.c_str()); + const Layer* layer = this->layers.Find(parameter.key.c_str()); if (layer == nullptr) { has_missing_layers = true; continue; diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index 5122478527..126610c11b 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -117,6 +117,8 @@ class Environment { ConfigurationInfo global_configuration; std::map layers_validated; + std::string selected_layer_name; + private: Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; diff --git a/vkconfig_core/test/test_configuration.cpp b/vkconfig_core/test/test_configuration.cpp index 16e306deed..964fe7849b 100644 --- a/vkconfig_core/test/test_configuration.cpp +++ b/vkconfig_core/test/test_configuration.cpp @@ -62,7 +62,7 @@ TEST(test_configuration, load_and_save) { Configuration configuration_loaded; const bool load_loaded = configuration_loaded.Load(":/test/Configuration 3.0.0.json", std::vector()); EXPECT_TRUE(load_loaded); - EXPECT_EQ(1, configuration_loaded.parameters.size()); + EXPECT_EQ(3, configuration_loaded.parameters.size()); EXPECT_TRUE(!configuration_loaded.description.empty()); Parameter* parameter = FindByKey(configuration_loaded.parameters, "VK_LAYER_LUNARG_reference_1_2_1"); diff --git a/vkconfig_core/type_layer_control.cpp b/vkconfig_core/type_layer_control.cpp index a39065530c..42c4675d72 100644 --- a/vkconfig_core/type_layer_control.cpp +++ b/vkconfig_core/type_layer_control.cpp @@ -19,6 +19,7 @@ */ #include "type_layer_control.h" +#include "util.h" #include #include @@ -26,9 +27,9 @@ // These names are requied by the Vulkan Loader settings file const char* GetToken(LayerControl control) { static const char* TOKENS[] = { - "auto", // LAYER_CONTROL_AUTO - "on", // LAYER_CONTROL_ON - "off", // LAYER_CONTROL_OFF + "Auto", // LAYER_CONTROL_AUTO + "On", // LAYER_CONTROL_ON + "Off", // LAYER_CONTROL_OFF "application_enabled_layers", // LAYER_CONTROL_APPLICATIONS "unordered_layer_location" // LAYER_CONTROL_UNORDERED }; @@ -40,7 +41,7 @@ const char* GetToken(LayerControl control) { LayerControl GetLayerControl(const char* token) { for (int i = LAYER_CONTROL_FIRST, l = LAYER_CONTROL_LAST; i <= l; ++i) { const LayerControl type = static_cast(i); - if (std::strcmp(::GetToken(type), token) == 0) { + if (ToLowerCase(::GetToken(type)) == ToLowerCase(token)) { return type; } } diff --git a/vkconfig_core/type_layer_control.h b/vkconfig_core/type_layer_control.h index e41bcd6717..2ca084da6c 100644 --- a/vkconfig_core/type_layer_control.h +++ b/vkconfig_core/type_layer_control.h @@ -28,7 +28,10 @@ enum LayerControl { LAYER_CONTROL_APPLICATIONS_ENV, LAYER_CONTROL_FIRST = LAYER_CONTROL_AUTO, - LAYER_CONTROL_LAST = LAYER_CONTROL_APPLICATIONS_ENV + LAYER_CONTROL_LAST = LAYER_CONTROL_APPLICATIONS_ENV, + + LAYER_CONTROL_UI_FIRST = LAYER_CONTROL_AUTO, + LAYER_CONTROL_UI_LAST = LAYER_CONTROL_OFF }; enum { LAYER_CONTROL_COUNT = LAYER_CONTROL_LAST - LAYER_CONTROL_FIRST + 1 }; diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/configuration_layer_widget.cpp index b2a1a9ac87..588fb00c52 100644 --- a/vkconfig_gui/configuration_layer_widget.cpp +++ b/vkconfig_gui/configuration_layer_widget.cpp @@ -23,12 +23,16 @@ #include "../vkconfig_core/configurator.h" -ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter) +ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter, + bool advanced_view) : layer_name(parameter.key) { // const bool is_implicit_layer = layers.empty() ? false : layers[0]->type == LAYER_TYPE_IMPLICIT; + Version api_version; + if (parameter.control != LAYER_CONTROL_APPLICATIONS_API && parameter.control != LAYER_CONTROL_APPLICATIONS_ENV) { this->layer_version = new QComboBox(this); + this->layer_version->setVisible(advanced_view); this->layer_version->addItem("Latest"); int version_index = 0; @@ -55,8 +59,10 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vectorlayer_version->setCurrentIndex(version_index); if (selected_layer != nullptr) { + api_version = selected_layer->api_version; this->layer_version->setToolTip(selected_layer->manifest_path.AbsolutePath().c_str()); } else if (latest_layer != nullptr) { + api_version = latest_layer->api_version; this->layer_version->setToolTip(latest_layer->manifest_path.AbsolutePath().c_str()); } @@ -65,9 +71,9 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vectorlayer_version->installEventFilter(this); this->layer_state = new QComboBox(this); - this->layer_state->addItem("Auto"); - this->layer_state->addItem("On"); - this->layer_state->addItem("Off"); + for (int i = LAYER_CONTROL_UI_FIRST; i <= LAYER_CONTROL_UI_LAST; ++i) { + this->layer_state->addItem(GetToken(static_cast(i))); + } this->layer_state->setEnabled(!layers.empty()); this->layer_state->setCurrentIndex(parameter.control); this->connect(this->layer_state, SIGNAL(currentIndexChanged(int)), this, SLOT(on_layer_state_currentIndexChanged(int))); @@ -87,6 +93,10 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vectorstatus != STATUS_STABLE) { decorated_name += format(" (%s)", GetToken(layers[0]->status)); } diff --git a/vkconfig_gui/configuration_layer_widget.h b/vkconfig_gui/configuration_layer_widget.h index 091d868df2..b674304654 100644 --- a/vkconfig_gui/configuration_layer_widget.h +++ b/vkconfig_gui/configuration_layer_widget.h @@ -32,7 +32,7 @@ class ConfigurationLayerWidget : public QLabel { Q_OBJECT public: - ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter); + ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter, bool advanced_view); protected: bool eventFilter(QObject *target, QEvent *event); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index a221f84fc7..fc8f58e547 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -239,6 +239,7 @@ MainWindow::MainWindow(QWidget *parent) ui->configurations_tree->installEventFilter(this); ui->layers_tree->installEventFilter(this); ui->settings_tree->installEventFilter(this); + // ui->splitter_settings->setVisible(false); SetupLauncherTree(); @@ -270,10 +271,11 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->configurations_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(OnConfigurationTreeClicked(QTreeWidgetItem *, int))); - connect(ui->layers_tree, SIGNAL(itemChanged(QListWidgetItem *, int)), this, SLOT(OnLayersItemChanged(QListWidgetItem *, int))); - connect(ui->layers_tree, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, - SLOT(OnLayersTreeChanged(QListWidgetItem *, QListWidgetItem *))); - connect(ui->layers_tree, SIGNAL(indexesMoved(int)), this, SLOT(OnLayersIndexesMoved(const QModelIndexList &))); + // connect(ui->layers_tree, SIGNAL(itemChanged(QListWidgetItem *, int)), this, SLOT(OnLayersItemChanged(QListWidgetItem *, + // int))); connect(ui->layers_tree, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, + // SLOT(OnLayersTreeChanged(QListWidgetItem *, QListWidgetItem *))); connect(ui->layers_tree, SIGNAL(indexesMoved(int)), this, + // SLOT(OnLayersIndexesMoved(const QModelIndexList &))); + connect(ui->layers_tree, SIGNAL(currentRowChanged(int)), this, SLOT(OnLayerCurrentRowChanged(int))); connect(ui->settings_tree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(editorExpanded(QTreeWidgetItem *))); connect(ui->settings_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, @@ -291,6 +293,8 @@ MainWindow::MainWindow(QWidget *parent) Configurator &configurator = Configurator::Get(); Environment &environment = configurator.environment; + ui->combo_box_layers_view->setCurrentIndex(configurator.GetActiveConfiguration()->view_advanced_layers); + ui->combo_box_mode->setCurrentIndex(environment.GetActiveConfigurationInfo().GetMode()); // Update configuration application area @@ -542,50 +546,23 @@ void MainWindow::AddLayerPathItem(const std::string &layer_path) { ui->tree_layers_paths->setItemWidget(item_state, layer_path_widget); } -void MainWindow::AddLayerItem(Parameter ¶meter) { +void MainWindow::AddLayerItem(Parameter ¶meter, bool advanced_view) { assert(!parameter.key.empty()); - std::vector &available_layers = Configurator::Get().layers.selected_layers; - - const Layer *layer = FindByKey(available_layers, parameter.key.c_str()); - - std::vector layers; - - std::string decorated_name(parameter.key); - - bool is_implicit_layer = false; - if (layer != nullptr) { - if (layer->status != STATUS_STABLE) { - decorated_name += format(" (%s)", GetToken(layer->status)); - } - - if (IsDLL32Bit(layer->manifest_path.AbsolutePath())) { - decorated_name += " (32-bit)"; - } - } else { - // A layers configuration may have excluded layer that are misssing because they are not available on this platform - // We simply hide these layers to avoid confusing the Vulkan developers - if (parameter.control == LAYER_CONTROL_OFF) { - return; - } + Configurator &configurator = Configurator::Get(); - if (parameter.control != LAYER_CONTROL_APPLICATIONS_API && parameter.control != LAYER_CONTROL_APPLICATIONS_ENV) { - decorated_name += " (Missing)"; - } - } + const Layer *layer = configurator.layers.Find(parameter.key); TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(parameter.key.c_str()); item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); ui->layers_tree->addItem(item_state); - // item_state->setText(decorated_name.c_str()); - // if (layer != nullptr) item_state->setToolTip(layer->manifest_path.c_str()); - + std::vector layers; if (layer != nullptr) { layers.push_back(layer); } - ConfigurationLayerWidget *layer_widget = new ConfigurationLayerWidget(layers, parameter); + ConfigurationLayerWidget *layer_widget = new ConfigurationLayerWidget(layers, parameter, advanced_view); item_state->widget = layer_widget; if (parameter.control == LAYER_CONTROL_APPLICATIONS_API) { @@ -595,6 +572,9 @@ void MainWindow::AddLayerItem(Parameter ¶meter) { } ui->layers_tree->setItemWidget(item_state, layer_widget); + if (configurator.environment.selected_layer_name.find(parameter.key) != std::string::npos) { + ui->layers_tree->setCurrentItem(item_state); + } } void MainWindow::UpdateUI() { @@ -679,9 +659,10 @@ void MainWindow::UpdateUI() { assert(item); assert(!item->configuration_name.empty()); - Configuration *configuration = - FindByKey(configurator.configurations.available_configurations, item->configuration_name.c_str()); - if (configuration == nullptr) continue; + Configuration *configuration = configurator.configurations.FindConfiguration(item->configuration_name); + if (configuration == nullptr) { + continue; + } item->radio_button->setToolTip(configuration->description.c_str()); item->radio_button->blockSignals(true); @@ -696,11 +677,6 @@ void MainWindow::UpdateUI() { item->radio_button->blockSignals(false); } - // Update settings - ui->push_button_rename->setEnabled(has_selected_configuration); - ui->push_button_settings->setEnabled(has_selected_configuration); - ui->push_button_export->setEnabled(has_selected_configuration); - // ui->tree_layers_paths->setEnabled(enable_layer_ui); ui->tree_layers_paths->clear(); /* @@ -718,11 +694,18 @@ void MainWindow::UpdateUI() { ui->layers_tree->clear(); if (has_selected_configuration) { - Configuration *configuration = - FindByKey(configurator.configurations.available_configurations, selected_contiguration_name.c_str()); + Configuration *configuration = configurator.configurations.FindConfiguration(selected_contiguration_name); if (configuration != nullptr) { for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { - AddLayerItem(configuration->parameters[i]); + Parameter ¶meter = configuration->parameters[i]; + + if (!configuration->view_advanced_layers) { + if (parameter.control == LAYER_CONTROL_AUTO) { + continue; + } + } + + this->AddLayerItem(parameter, configuration->view_advanced_layers); } resizeEvent(nullptr); @@ -835,10 +818,6 @@ void MainWindow::LoadConfigurationList() { for (std::size_t i = 0, n = configurator.configurations.available_configurations.size(); i < n; ++i) { const Configuration &configuration = configurator.configurations.available_configurations[i]; - // Hide built-in configuration when the layer is missing. The Vulkan user may have not installed the necessary layer - // if (configuration.IsBuiltIn() && HasMissingLayer(configuration.parameters, configurator.layers.available_layers)) - // continue; - ConfigurationListItem *item = new ConfigurationListItem(configuration.key); item->setText(1, item->configuration_name.c_str()); item->setToolTip(1, configuration.description.c_str()); @@ -847,27 +826,8 @@ void MainWindow::LoadConfigurationList() { item->radio_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); item->radio_button->setFixedSize(QSize(24, 24)); item->radio_button->setToolTip(configuration.description.c_str()); - item->push_button_reset = new QPushButton(); - item->push_button_reset->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - item->push_button_reset->setFixedSize(QSize(24, 24)); - item->push_button_reset->setText("^"); - item->push_button_reset->setToolTip(("Reset " + item->configuration_name + " configuration with saved file").c_str()); - item->push_button_duplicate = new QPushButton(); - item->push_button_duplicate->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - item->push_button_duplicate->setFixedSize(QSize(24, 24)); - item->push_button_duplicate->setText("+"); - item->push_button_duplicate->setToolTip(("Duplicate " + item->configuration_name + " configuration").c_str()); - item->push_button_remove = new QPushButton(); - item->push_button_remove->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - item->push_button_remove->setFixedSize(QSize(24, 24)); - item->push_button_remove->setText("x"); - item->push_button_remove->setToolTip(("Remove " + item->configuration_name + " configuration").c_str()); ui->configurations_tree->addTopLevelItem(item); ui->configurations_tree->setItemWidget(item, 0, item->radio_button); - ui->configurations_tree->setItemWidget(item, 2, item->push_button_reset); - ui->configurations_tree->setItemWidget(item, 3, item->push_button_duplicate); - ui->configurations_tree->setItemWidget(item, 4, item->push_button_remove); - // connect(item->radio_button, SIGNAL(clicked(bool)), this, SLOT(OnConfigurationItemClicked(bool))); connect(item->radio_button, SIGNAL(toggled(bool)), this, SLOT(OnConfigurationItemClicked(bool))); } @@ -1017,6 +977,15 @@ void MainWindow::on_check_box_clear_on_launch_clicked() { Configurator::Get().environment.Set(LAYOUT_LAUNCHER_NOT_CLEAR, ui->check_box_clear_on_launch->isChecked() ? "false" : "true"); } +void MainWindow::on_combo_box_layers_view_currentIndexChanged(int index) { + Configurator &configurator = Configurator::Get(); + + Configuration *configuration = configurator.GetActiveConfiguration(); + configuration->view_advanced_layers = index != 0; + + this->UpdateUI(); +} + void MainWindow::toolsResetToDefault(bool checked) { (void)checked; @@ -1502,6 +1471,18 @@ void MainWindow::OnConfigurationItemExpanded(QTreeWidgetItem *item) { ui->settings_tree->resizeColumnToContents(1); } +void MainWindow::OnLayerCurrentRowChanged(int currentRow) { + if (currentRow != -1) { + Configurator &configurator = Configurator::Get(); + QWidget *widget = ui->layers_tree->itemWidget(ui->layers_tree->item(currentRow)); + std::string layer_name = static_cast(widget)->text().toStdString(); + configurator.environment.selected_layer_name = layer_name; + } + + // ui->splitter_settings->setVisible(currentRow != -1); + this->_settings_tree_manager.CreateGUI(ui->settings_tree); +} + void MainWindow::OnSettingsTreeClicked(QTreeWidgetItem *item, int column) { (void)column; (void)item; @@ -1781,7 +1762,9 @@ static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { for (std::size_t i = 0, n = configurator.layers.selected_layers.size(); i < n; ++i) { const Layer &layer = configurator.layers.selected_layers[i]; - if (text.find(layer.key) != std::string::npos) return &layer; + if (text.find(layer.key) != std::string::npos) { + return &layer; + } } } @@ -1837,20 +1820,71 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { } else if (target == ui->configurations_tree) { QContextMenuEvent *right_click = dynamic_cast(event); if (right_click) { - QTreeWidgetItem *item = ui->configurations_tree->itemAt(right_click->pos()); + ConfigurationListItem *item = static_cast(ui->configurations_tree->itemAt(right_click->pos())); + + std::string name; + + if (item != nullptr) { + name = item->configuration_name; + } QMenu menu(ui->configurations_tree); QFont subtitle_font = menu.font(); subtitle_font.setBold(true); - QAction *title_action = new QAction("configurations context menu", nullptr); - title_action->setFont(subtitle_font); - menu.addAction(title_action); + QAction *action_new = new QAction("Create a new Configuration", nullptr); + action_new->setEnabled(true); + menu.addAction(action_new); + + QAction *action_import = new QAction("Import a new Configuration...", nullptr); + action_import->setEnabled(true); + menu.addAction(action_import); + + menu.addSeparator(); + + QAction *action_rename = new QAction("Rename the Configuration", nullptr); + action_rename->setEnabled(item != nullptr); + menu.addAction(action_rename); + + QAction *action_duplicate = new QAction("Duplicate the Configuration", nullptr); + action_duplicate->setEnabled(item != nullptr); + menu.addAction(action_duplicate); + + QAction *action_delete = new QAction("Delete the Configuration", nullptr); + action_delete->setEnabled(item != nullptr); + menu.addAction(action_delete); + + menu.addSeparator(); + + QAction *action_reset = new QAction("Reset the Configuration", nullptr); + action_reset->setEnabled(item != nullptr); + action_reset->setToolTip("Reset the Configuration using the built-in configuration"); + menu.addAction(action_reset); + + QAction *action_reload = new QAction("Reload the Configuration", nullptr); + action_reload->setEnabled(item != nullptr); + action_reset->setToolTip("Reload the Configuration, discarding all changes from this session"); + menu.addAction(action_reload); + + menu.addSeparator(); + + QAction *action_export = new QAction("Export the Configuration...", nullptr); + action_export->setEnabled(item != nullptr); + menu.addAction(action_export); + + QAction *action_export_settings = new QAction("Export the Layers Settings...", nullptr); + action_export_settings->setEnabled(item != nullptr); + menu.addAction(action_export_settings); QPoint point(right_click->globalX(), right_click->globalY()); QAction *action = menu.exec(point); - if (action == title_action) { + if (action == action_new) { + } else if (action == action_delete) { + } else if (action == action_duplicate) { + } else if (action == action_rename) { + } else if (action == action_import) { + } else if (action == action_export) { } } } else if (target == ui->layers_tree) { @@ -1859,34 +1893,37 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { QListWidgetItem *item = ui->layers_tree->itemAt(right_click->pos()); const Layer *layer = GetLayer(ui->layers_tree, item); - if (layer == nullptr) { - return false; - } QMenu menu(ui->layers_tree); - QFont subtitle_font = menu.font(); - subtitle_font.setBold(true); - QAction *title_action = new QAction(layer->key.c_str(), nullptr); - title_action->setFont(subtitle_font); - menu.addAction(title_action); + QAction *action_all = new QAction("Show All Layers", nullptr); + action_all->setEnabled(item != nullptr); + action_all->setCheckable(true); + action_all->setChecked(true); + menu.addAction(action_all); - QAction *visit_layer_website_action = new QAction("Visit Layer Website...", nullptr); - visit_layer_website_action->setEnabled(layer != nullptr ? !layer->url.empty() : false); - menu.addAction(visit_layer_website_action); + menu.addSeparator(); + + QAction *action_description = new QAction("Open the Layer Description...", nullptr); + action_description->setEnabled(item != nullptr); + menu.addAction(action_description); - QAction *export_html_action = new QAction("Open Layer HTML Documentation...", nullptr); - export_html_action->setEnabled(layer != nullptr); + QAction *export_html_action = new QAction("Open the Layer HTML Documentation...", nullptr); + export_html_action->setEnabled(item != nullptr); menu.addAction(export_html_action); - QAction *export_markdown_action = new QAction("Open Layer Markdown Documentation...", nullptr); - export_markdown_action->setEnabled(layer != nullptr); + QAction *export_markdown_action = new QAction("Open the Layer Markdown Documentation...", nullptr); + export_markdown_action->setEnabled(item != nullptr); menu.addAction(export_markdown_action); + QAction *visit_layer_website_action = new QAction("Visit the Layer Website...", nullptr); + visit_layer_website_action->setEnabled(layer != nullptr ? !layer->url.empty() : false); + menu.addAction(visit_layer_website_action); + QPoint point(right_click->globalX(), right_click->globalY()); QAction *action = menu.exec(point); - if (action == title_action) { + if (action == action_description) { Alert::LayerProperties(layer); } else if (action == visit_layer_website_action) { QDesktopServices::openUrl(QUrl(layer->url.c_str())); diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index f38d6e3014..5019fb7772 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -45,9 +45,6 @@ class ConfigurationListItem : public QTreeWidgetItem { ConfigurationListItem(const std::string &configuration_name) : configuration_name(configuration_name) {} std::string configuration_name; QRadioButton *radio_button; - QPushButton *push_button_reset; - QPushButton *push_button_duplicate; - QPushButton *push_button_remove; private: ConfigurationListItem(const ConfigurationListItem &) = delete; @@ -159,7 +156,7 @@ class MainWindow : public QMainWindow { void ImportClicked(ConfigurationListItem *item); void AddLayerPathItem(const std::string &layer_path); - void AddLayerItem(Parameter ¶meter); + void AddLayerItem(Parameter ¶meter, bool advanced_view); private slots: void trayActionRestore(); @@ -210,12 +207,16 @@ class MainWindow : public QMainWindow { void on_combo_box_mode_currentIndexChanged(int index); void on_combo_box_applications_currentIndexChanged(int index); + void on_combo_box_layers_view_currentIndexChanged(int index); + void OnConfigurationItemExpanded(QTreeWidgetItem *item); void OnConfigurationItemClicked(bool checked); void OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); void OnConfigurationItemChanged(QTreeWidgetItem *item, int column); void OnConfigurationTreeClicked(QTreeWidgetItem *item, int column); + void OnLayerCurrentRowChanged(int currentRow); + void OnSettingsTreeClicked(QTreeWidgetItem *item, int column); void OnLauncherLoaderMessageChanged(int level); diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index cd1e3f905e..d5992a2e51 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 1024 - 600 + 640 @@ -19,7 +19,7 @@ 1024 - 600 + 640 @@ -572,12 +572,6 @@ - - - 0 - 0 - - Configurations @@ -599,12 +593,6 @@ - - - 0 - 0 - - 0 @@ -621,21 +609,12 @@ false - - - 0 - 0 - - 0 Qt::Vertical - - false - @@ -685,10 +664,23 @@ 7 - + + + + 0 + 0 + + + + + + 0 + 0 + + Layers Mode: @@ -850,93 +842,6 @@ 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - New - - - - - - - Rename - - - - - - - Settings... - - - - - - - Export... - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - Arial - 10 - - - - Import... - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - @@ -953,7 +858,7 @@ 0 - 1 + 0 @@ -972,7 +877,7 @@ 0 - + @@ -1001,7 +906,7 @@ - + @@ -1047,7 +952,7 @@ - + @@ -1079,13 +984,50 @@ + + + + 0 + + + 7 + + + + + Layers Views: + + + + + + + + 0 + 0 + + + + + Overidden Layers Only + + + + + All Available Layers + + + + + + - - 1 + + 0 0 @@ -1102,7 +1044,7 @@ 0 - 0 + 1 diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index e209f91fd1..1c03d37367 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -63,7 +63,7 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { this->tree = build_tree; Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration == nullptr) { + if (configuration == nullptr || configurator.environment.selected_layer_name.empty()) { return; } @@ -88,6 +88,11 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { // There will be one top level item for each layer for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { Parameter ¶meter = configuration->parameters[i]; + + if (configurator.environment.selected_layer_name.find(parameter.key) == std::string::npos) { + continue; + } + if (!IsPlatformSupported(parameter.platform_flags)) { continue; } @@ -128,12 +133,12 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { if (!layer->presets.empty()) { QTreeWidgetItem *presets_item = new QTreeWidgetItem(); - layer_item->addChild(presets_item); + this->tree->addTopLevelItem(presets_item); WidgetPreset *presets_combobox = new WidgetPreset(this->tree, presets_item, *layer, parameter); this->connect(presets_combobox, SIGNAL(itemChanged()), this, SLOT(OnPresetChanged())); } - BuildGenericTree(layer_item, parameter); + BuildGenericTree(parameter); } } @@ -244,7 +249,11 @@ void SettingsTreeManager::BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶ QTreeWidgetItem *item = new QTreeWidgetItem(); item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - parent->addChild(item); + if (parent == nullptr) { + this->tree->addTopLevelItem(item); + } else { + parent->addChild(item); + } switch (meta_object.type) { case SETTING_GROUP: { @@ -360,12 +369,12 @@ void SettingsTreeManager::BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶ } } -void SettingsTreeManager::BuildGenericTree(QTreeWidgetItem *parent, Parameter ¶meter) { +void SettingsTreeManager::BuildGenericTree(Parameter ¶meter) { std::vector &available_layers = Configurator::Get().layers.selected_layers; const SettingMetaSet &settings = FindByKey(available_layers, parameter.key.c_str())->settings; for (std::size_t i = 0, n = settings.size(); i < n; ++i) { - this->BuildTreeItem(parent, parameter, *settings[i]); + this->BuildTreeItem(nullptr, parameter, *settings[i]); } } diff --git a/vkconfig_gui/settings_tree.h b/vkconfig_gui/settings_tree.h index b6850cb6e1..8a7c87bdeb 100644 --- a/vkconfig_gui/settings_tree.h +++ b/vkconfig_gui/settings_tree.h @@ -58,7 +58,7 @@ class SettingsTreeManager : QObject { SettingsTreeManager(const SettingsTreeManager &) = delete; SettingsTreeManager &operator=(const SettingsTreeManager &) = delete; - void BuildGenericTree(QTreeWidgetItem *parent, Parameter ¶meter); + void BuildGenericTree(Parameter ¶meter); void BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶meter, const SettingMeta &meta); void RefreshItem(RefreshAreas refresh_areas, QTreeWidgetItem *parent); From 37c48e674f4cb694a4009b4cfd6e800b69e5ee62 Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 30 Jul 2024 17:27:25 +0200 Subject: [PATCH 07/33] vkconfig3: Add settings tree state load and store --- vkconfig_core/configuration.cpp | 15 +++--- vkconfig_core/configuration.h | 3 +- vkconfig_core/parameter.h | 1 + vkconfig_core/test/test_configuration.cpp | 4 +- .../test/test_configuration_built_in.cpp | 5 +- vkconfig_gui/mainwindow.cpp | 28 ++++++++-- vkconfig_gui/mainwindow.ui | 2 +- vkconfig_gui/settings_tree.cpp | 54 +++++++++---------- vkconfig_gui/settings_tree.h | 1 - 9 files changed, 65 insertions(+), 48 deletions(-) diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index 3a69773c60..6cdd65ac16 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -142,10 +142,6 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa this->version = json_configuration_object.value("version").toVariant().toInt(); } - if (json_configuration_object.value("expanded_states") != QJsonValue::Undefined) { - this->setting_tree_state = json_configuration_object.value("expanded_states").toVariant().toByteArray(); - } - if (json_configuration_object.value("view_advanced_settings") != QJsonValue::Undefined) { this->view_advanced_settings = ReadBoolValue(json_configuration_object, "view_advanced_settings"); } @@ -197,6 +193,11 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa parameter.platform_flags = GetPlatformFlags(ReadStringArray(json_layer_object, "platforms")); } + const QJsonValue& json_expanded_value = json_layer_object.value("expanded_states"); + if (json_expanded_value != QJsonValue::Undefined) { + parameter.setting_tree_state = json_layer_object.value("expanded_states").toVariant().toByteArray(); + } + const Layer* layer = nullptr; for (std::size_t i = 0, n = available_layers.size(); i < n; ++i) { const Layer& current_layer = available_layers[i]; @@ -277,6 +278,9 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { json_layer.insert("version", parameter.api_version == Version::VERSION_NULL ? "latest" : parameter.api_version.str().c_str()); SaveStringArray(json_layer, "platforms", GetPlatformTokens(parameter.platform_flags)); + if (!exporter && !parameter.setting_tree_state.isEmpty()) { + json_layer.insert("expanded_states", parameter.setting_tree_state.data()); + } QJsonArray json_settings; for (std::size_t j = 0, m = parameter.settings.size(); j < m; ++j) { @@ -305,9 +309,6 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { json_configuration.insert("version", this->version); json_configuration.insert("description", this->description.c_str()); SaveStringArray(json_configuration, "platforms", GetPlatformTokens(this->platform_flags)); - if (!exporter && !this->setting_tree_state.isEmpty()) { - json_configuration.insert("expanded_states", this->setting_tree_state.data()); - } json_configuration.insert("view_advanced_settings", this->view_advanced_settings); json_configuration.insert("view_advanced_layers", this->view_advanced_layers); json_configuration.insert("layers", json_layers); diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index d7d23c1502..3b08973373 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -45,8 +45,7 @@ class Configuration { std::string key = "New Configuration"; // User readable display of the configuration name (may contain spaces) int version = 1; int platform_flags = PLATFORM_DESKTOP_BIT; - std::string description; // A friendly description of what this profile does - QByteArray setting_tree_state; // Recall editor tree state + std::string description; // A friendly description of what this profile does bool view_advanced_settings = false; bool view_advanced_layers = false; diff --git a/vkconfig_core/parameter.h b/vkconfig_core/parameter.h index ac291f8c83..3339f94b0f 100644 --- a/vkconfig_core/parameter.h +++ b/vkconfig_core/parameter.h @@ -50,6 +50,7 @@ struct Parameter { SettingDataSet settings; int overridden_rank = NO_RANK; Version api_version = Version::VERSION_NULL; + QByteArray setting_tree_state; // Recall editor tree state }; ParameterRank GetParameterOrdering(const std::vector& available_layers, const Parameter& parameter); diff --git a/vkconfig_core/test/test_configuration.cpp b/vkconfig_core/test/test_configuration.cpp index 964fe7849b..e1f8a8bc7d 100644 --- a/vkconfig_core/test/test_configuration.cpp +++ b/vkconfig_core/test/test_configuration.cpp @@ -33,8 +33,6 @@ static bool operator==(const Configuration& a, const Configuration& b) { return false; else if (a.description != b.description) return false; - else if (a.setting_tree_state != b.setting_tree_state) - return false; else if (a.parameters != b.parameters) return false; return true; @@ -49,6 +47,8 @@ static bool operator==(const Parameter& a, const Parameter& b) { if (a.settings.size() != b.settings.size()) return false; + if (a.setting_tree_state != b.setting_tree_state) return false; + for (std::size_t i = 0, n = a.settings.size(); i < n; ++i) { if (a.settings[i] != b.settings[i]) return false; } diff --git a/vkconfig_core/test/test_configuration_built_in.cpp b/vkconfig_core/test/test_configuration_built_in.cpp index 3c74fa7880..96d8ae39a4 100644 --- a/vkconfig_core/test/test_configuration_built_in.cpp +++ b/vkconfig_core/test/test_configuration_built_in.cpp @@ -35,8 +35,6 @@ static bool operator==(const Configuration& a, const Configuration& b) { return false; else if (a.description != b.description) return false; - else if (a.setting_tree_state != b.setting_tree_state) - return false; else if (a.parameters != b.parameters) return false; return true; @@ -51,6 +49,8 @@ static bool operator==(const Parameter& a, const Parameter& b) { if (a.settings.size() != b.settings.size()) return false; + if (a.setting_tree_state != b.setting_tree_state) return false; + for (std::size_t i = 0, n = a.settings.size(); i < n; ++i) { if (*a.settings[i] != *b.settings[i]) return false; } @@ -106,7 +106,6 @@ TEST(test_built_in_load, sdk_layers_with_configuration) { EXPECT_STREQ(save_api_dump.description.c_str(), load_api_dump.description.c_str()); EXPECT_EQ(save_api_dump.version, load_api_dump.version); EXPECT_EQ(save_api_dump.platform_flags, load_api_dump.platform_flags); - EXPECT_EQ(save_api_dump.setting_tree_state, load_api_dump.setting_tree_state); EXPECT_EQ(save_api_dump.parameters.size(), load_api_dump.parameters.size()); for (std::size_t i = 0, n = save_api_dump.parameters.size(); i < n; ++i) { EXPECT_EQ(save_api_dump.parameters[i], load_api_dump.parameters[i]); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index fc8f58e547..7a0a60b1c3 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -572,7 +572,7 @@ void MainWindow::AddLayerItem(Parameter ¶meter, bool advanced_view) { } ui->layers_tree->setItemWidget(item_state, layer_widget); - if (configurator.environment.selected_layer_name.find(parameter.key) != std::string::npos) { + if (configurator.environment.selected_layer_name == parameter.key) { ui->layers_tree->setCurrentItem(item_state); } } @@ -709,6 +709,8 @@ void MainWindow::UpdateUI() { } resizeEvent(nullptr); + ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); + ui->layers_tree->update(); } } @@ -1010,12 +1012,11 @@ void MainWindow::OnConfigurationItemClicked(bool checked) { return; } - // This appears redundant on Windows, but under linux it is needed - // to ensure the new item is "selected" - // ui->tree_configurations->setCurrentItem(item); + this->_settings_tree_manager.CleanupGUI(); Configurator &configurator = Configurator::Get(); configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); + configurator.environment.selected_layer_name.clear(); configurator.Override(); UpdateUI(); @@ -1028,7 +1029,10 @@ void MainWindow::OnConfigurationTreeClicked(QTreeWidgetItem *item, int column) { ConfigurationListItem *configuration_item = dynamic_cast(item); if (configuration_item != nullptr) { + this->_settings_tree_manager.CleanupGUI(); + configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); + configurator.environment.selected_layer_name.clear(); configurator.Override(); } @@ -1082,6 +1086,7 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { configuration->key = configuration_item->configuration_name = new_name; configurator.configurations.SaveAllConfigurations(); configurator.environment.GetActiveConfigurationInfo().SetName(new_name); + configurator.environment.selected_layer_name.clear(); LoadConfigurationList(); } else { @@ -1092,6 +1097,7 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { ui->configurations_tree->blockSignals(false); configurator.environment.GetActiveConfigurationInfo().SetName(old_name); + configurator.environment.selected_layer_name.clear(); } configurator.Override(); @@ -1116,6 +1122,8 @@ void MainWindow::OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidge Configurator &configurator = Configurator::Get(); if (configurator.environment.GetActiveConfigurationInfo().GetName() != configuration_item->configuration_name) { + this->_settings_tree_manager.CleanupGUI(); + configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); configurator.Override(); @@ -1472,11 +1480,21 @@ void MainWindow::OnConfigurationItemExpanded(QTreeWidgetItem *item) { } void MainWindow::OnLayerCurrentRowChanged(int currentRow) { + this->_settings_tree_manager.CleanupGUI(); + if (currentRow != -1) { Configurator &configurator = Configurator::Get(); QWidget *widget = ui->layers_tree->itemWidget(ui->layers_tree->item(currentRow)); std::string layer_name = static_cast(widget)->text().toStdString(); - configurator.environment.selected_layer_name = layer_name; + Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + Parameter ¶meter = configuration->parameters[i]; + if (layer_name.find(parameter.key) != std::string::npos) { + configurator.environment.selected_layer_name = parameter.key; + } + } + } } // ui->splitter_settings->setVisible(currentRow != -1); diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index d5992a2e51..1c73755f38 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -995,7 +995,7 @@ - Layers Views: + Layers Views: diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 1c03d37367..009f859a56 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -89,7 +89,7 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { Parameter ¶meter = configuration->parameters[i]; - if (configurator.environment.selected_layer_name.find(parameter.key) == std::string::npos) { + if (configurator.environment.selected_layer_name != parameter.key) { continue; } @@ -143,14 +143,10 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { } this->connect(this->tree, SIGNAL(expanded(const QModelIndex)), this, SLOT(OnExpandedChanged(const QModelIndex))); - this->connect(this->tree, SIGNAL(collapsed(const QModelIndex)), this, SLOT(OnCollapsedChanged(const QModelIndex))); + this->connect(this->tree, SIGNAL(collapsed(const QModelIndex)), this, SLOT(OnExpandedChanged(const QModelIndex))); this->tree->resizeColumnToContents(0); - if (!configuration->setting_tree_state.isEmpty()) { - this->SetTreeState(configuration->setting_tree_state, 0, this->tree->invisibleRootItem()); - } - this->tree->blockSignals(false); } @@ -161,11 +157,20 @@ void SettingsTreeManager::CleanupGUI() { } Configurator &configurator = Configurator::Get(); + if (!configurator.environment.selected_layer_name.empty()) { + Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + Parameter ¶meter = configuration->parameters[i]; + + if (parameter.key != configurator.environment.selected_layer_name) { + continue; + } - Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration != nullptr) { - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); + parameter.setting_tree_state.clear(); + GetTreeState(parameter.setting_tree_state, this->tree->invisibleRootItem()); + } + } } this->tree->clear(); @@ -184,25 +189,16 @@ void SettingsTreeManager::OnExpandedChanged(const QModelIndex &index) { Configuration *configuration = configurator.GetActiveConfiguration(); if (configuration != nullptr) { - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); - } -} - -void SettingsTreeManager::OnCollapsedChanged(const QModelIndex &index) { - (void)index; - - // Was not initialized - if (this->tree == nullptr) { - return; - } + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + Parameter ¶meter = configuration->parameters[i]; - Configurator &configurator = Configurator::Get(); + if (parameter.key != configurator.environment.selected_layer_name) { + continue; + } - Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration != nullptr) { - configuration->setting_tree_state.clear(); - GetTreeState(configuration->setting_tree_state, this->tree->invisibleRootItem()); + parameter.setting_tree_state.clear(); + GetTreeState(parameter.setting_tree_state, this->tree->invisibleRootItem()); + } } } @@ -376,6 +372,10 @@ void SettingsTreeManager::BuildGenericTree(Parameter ¶meter) { for (std::size_t i = 0, n = settings.size(); i < n; ++i) { this->BuildTreeItem(nullptr, parameter, *settings[i]); } + + if (!parameter.setting_tree_state.isEmpty()) { + this->SetTreeState(parameter.setting_tree_state, 0, this->tree->invisibleRootItem()); + } } void SettingsTreeManager::GetTreeState(QByteArray &byte_array, QTreeWidgetItem *top_item) { diff --git a/vkconfig_gui/settings_tree.h b/vkconfig_gui/settings_tree.h index 8a7c87bdeb..bea16593e2 100644 --- a/vkconfig_gui/settings_tree.h +++ b/vkconfig_gui/settings_tree.h @@ -52,7 +52,6 @@ class SettingsTreeManager : QObject { void OnSettingChanged(); void OnPresetChanged(); void OnExpandedChanged(const QModelIndex &index); - void OnCollapsedChanged(const QModelIndex &index); private: SettingsTreeManager(const SettingsTreeManager &) = delete; From 7bf4721603a6f5f74a0795dc34eb12a4a8daf7a2 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 31 Jul 2024 13:12:56 +0200 Subject: [PATCH 08/33] vkconfig3: Add configuration context menu --- vkconfig_core/configuration.h | 2 +- vkconfig_core/test/CMakeLists.txt | 1 + vkconfig_core/test/test_ui.cpp | 60 ++++++++ vkconfig_core/ui.cpp | 49 ++++++ vkconfig_core/ui.h | 27 ++++ vkconfig_gui/mainwindow.cpp | 246 +++++++++++++++--------------- vkconfig_gui/mainwindow.h | 21 ++- vkconfig_gui/vkconfig.pro | 2 + 8 files changed, 268 insertions(+), 140 deletions(-) create mode 100644 vkconfig_core/test/test_ui.cpp create mode 100644 vkconfig_core/ui.cpp create mode 100644 vkconfig_core/ui.h diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index 3b08973373..85355084cd 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -47,7 +47,7 @@ class Configuration { int platform_flags = PLATFORM_DESKTOP_BIT; std::string description; // A friendly description of what this profile does bool view_advanced_settings = false; - bool view_advanced_layers = false; + bool view_advanced_layers = true; std::vector parameters; std::vector user_defined_paths; diff --git a/vkconfig_core/test/CMakeLists.txt b/vkconfig_core/test/CMakeLists.txt index f817f49bbc..07133ae207 100644 --- a/vkconfig_core/test/CMakeLists.txt +++ b/vkconfig_core/test/CMakeLists.txt @@ -74,6 +74,7 @@ vkConfigTest(test_type_log) vkConfigTest(test_type_platform) vkConfigTest(test_type_status) vkConfigTest(test_type_tab) +vkConfigTest(test_ui) vkConfigTest(test_vulkan) diff --git a/vkconfig_core/test/test_ui.cpp b/vkconfig_core/test/test_ui.cpp new file mode 100644 index 0000000000..d46af29651 --- /dev/null +++ b/vkconfig_core/test/test_ui.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../ui.h" + +#include + +std::map Dummy() { return std::map(); } + +TEST(test_ui, ExtractLayerName_no_layer_loaded) { + LayerManager layer_manager; + + const std::string& not_found = ExtractLayerName(layer_manager, " = VK_LAYER_KHRONOS_validation"); + EXPECT_TRUE(not_found.empty()); +} + +TEST(test_ui, ExtractLayerName_no_found) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/sdk", Dummy()); + + const std::string& not_found = ExtractLayerName(layer_manager, " = VK_LAYER_KHRONOS_unkown"); + EXPECT_TRUE(not_found.empty()); +} + +TEST(test_ui, ExtractLayerName_found) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/sdk", Dummy()); + + const std::string& layer_found = ExtractLayerName(layer_manager, " = VK_LAYER_KHRONOS_validation"); + EXPECT_STREQ("VK_LAYER_KHRONOS_validation", layer_found.c_str()); +} + +TEST(test_ui, GetMainWindowTitle) { + std::string title = GetMainWindowTitle(false, false); + + EXPECT_STREQ(("Vulkan Configurator " + Version::VKCONFIG.str()).c_str(), title.c_str()); +} + +TEST(test_ui, GetMainWindowTitle_active) { + std::string title = GetMainWindowTitle(true, false); + + EXPECT_STREQ(("Vulkan Configurator " + Version::VKCONFIG.str() + " ").c_str(), title.c_str()); +} diff --git a/vkconfig_core/ui.cpp b/vkconfig_core/ui.cpp new file mode 100644 index 0000000000..43bae44dd1 --- /dev/null +++ b/vkconfig_core/ui.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "ui.h" +#include "date.h" + +std::string ExtractLayerName(const LayerManager& layer_manager, const std::string& layer_string) { + for (std::size_t i = 0, n = layer_manager.Size(); i < n; ++i) { + const Layer& layer = layer_manager.selected_layers[i]; + if (layer_string.find(layer.key) != std::string::npos) { + return layer.key; + } + } + + return std::string(); +} + +std::string GetMainWindowTitle(bool active, bool display_date) { + std::string title = format("%s %s", VKCONFIG_NAME, Version::VKCONFIG.str().c_str()); + +#if VKCONFIG_DATE + if (display_date) { + title += format("-%s", GetBuildDate().c_str()); + } +#endif + + if (active) { + title += " "; + } + + return title; +} diff --git a/vkconfig_core/ui.h b/vkconfig_core/ui.h new file mode 100644 index 0000000000..59e0d96e07 --- /dev/null +++ b/vkconfig_core/ui.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "layer_manager.h" + +std::string ExtractLayerName(const LayerManager& layer_manager, const std::string& layer_string); + +std::string GetMainWindowTitle(bool active, bool display_date); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 7a0a60b1c3..cfa47a0174 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -34,6 +34,7 @@ #include "../vkconfig_core/type_platform.h" #include "../vkconfig_core/type_log.h" #include "../vkconfig_core/type_hide_message.h" +#include "../vkconfig_core/ui.h" #include #include @@ -521,18 +522,6 @@ void MainWindow::trayActionDisabledByApplications(bool checked) { } } -static std::string GetMainWindowTitle(bool active) { -#if VKCONFIG_DATE - std::string title = format("%s %s-%s", VKCONFIG_NAME, Version::VKCONFIG.str().c_str(), GetBuildDate().c_str()); -#else - std::string title = format("%s %s", VKCONFIG_NAME, Version::VKCONFIG.str().c_str()); -#endif - if (active) { - title += " "; - } - return title; -} - void MainWindow::AddLayerPathItem(const std::string &layer_path) { TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(layer_path.c_str()); @@ -797,7 +786,13 @@ void MainWindow::UpdateUI() { } // Update title bar - this->setWindowTitle(GetMainWindowTitle(has_active_configuration).c_str()); +#ifdef VKCONFIG_DATE + bool display_date = true; +#else + bool display_date = false; +#endif + + this->setWindowTitle(GetMainWindowTitle(has_active_configuration, display_date).c_str()); ui->configurations_tree->blockSignals(false); this->blockSignals(false); @@ -831,6 +826,18 @@ void MainWindow::LoadConfigurationList() { ui->configurations_tree->addTopLevelItem(item); ui->configurations_tree->setItemWidget(item, 0, item->radio_button); connect(item->radio_button, SIGNAL(toggled(bool)), this, SLOT(OnConfigurationItemClicked(bool))); + + const Configuration *active_configuration = configurator.GetActiveConfiguration(); + if (active_configuration != nullptr) { + if (active_configuration->key == configuration.key) { + item->radio_button->blockSignals(true); + item->radio_button->setChecked(true); + + ui->configurations_tree->setCurrentItem(item); + + item->radio_button->blockSignals(false); + } + } } ui->configurations_tree->blockSignals(false); @@ -1284,62 +1291,80 @@ void MainWindow::on_push_button_applications_clicked() { UpdateUI(); } -void MainWindow::on_push_button_new_clicked() { this->NewClicked(); } +void MainWindow::OnContextMenuNewClicked(ConfigurationListItem *item) { + Configurator &configurator = Configurator::Get(); -void MainWindow::on_push_button_rename_clicked() { - ConfigurationListItem *configuration_item = GetCheckedItem(); - if (configuration_item == nullptr) { - return; - } + Configuration &new_configuration = + configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); - ui->configurations_tree->editItem(configuration_item, 1); + configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); + configurator.Override(); + + LoadConfigurationList(); } -void MainWindow::on_push_button_remove_clicked() { - ConfigurationListItem *configuration_item = GetCheckedItem(); - if (configuration_item == nullptr) { +void MainWindow::OnContextMenuImportClicked(ConfigurationListItem *item) { + (void)item; // We don't need this + + Configurator &configurator = Configurator::Get(); + + const Path &path_import = configurator.environment.path_import; + /* + const Path full_import_path = configurator.path.SelectPath(this, PATH_IMPORT_CONFIGURATION); + if (full_import_path.Empty()) { return; } - this->RemoveConfiguration(configuration_item->configuration_name); + configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, full_import_path); + */ + LoadConfigurationList(); } -void MainWindow::on_push_button_duplicate_clicked() { - Configurator &configurator = Configurator::Get(); +void MainWindow::OnContextMenuRenameClicked(ConfigurationListItem *item) { + assert(item); - const Configuration *configutation = configurator.GetActiveConfiguration(); - assert(configutation != nullptr); + ui->configurations_tree->editItem(item, 1); +} + +void MainWindow::OnContextMenuDuplicateClicked(ConfigurationListItem *item) { + assert(item); + assert(!item->configuration_name.empty()); + Configurator &configurator = Configurator::Get(); const Configuration &duplicated_configuration = - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, configutation->key, true); + configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, item->configuration_name, true); + + item->configuration_name = duplicated_configuration.key; configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); configurator.Override(); LoadConfigurationList(); - this->UpdateUI(); -} - -void MainWindow::NewClicked() { - Configurator &configurator = Configurator::Get(); - - Configuration &new_configuration = - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); + /* + ConfigurationListItem *new_item = nullptr; + for (int i = 0, n = ui->tree_configurations->topLevelItemCount(); i < n; ++i) { + ConfigurationListItem *searched_item = dynamic_cast(ui->tree_configurations->topLevelItem(i)); + assert(searched_item); - configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); - configurator.Override(); + if (searched_item->configuration_name != duplicated_configuration.key) continue; - LoadConfigurationList(); + new_item = searched_item; + break; + } + assert(new_item); + ui->tree_configurations->editItem(new_item, 1); + */ } -void MainWindow::RemoveConfiguration(const std::string &configuration_name) { - assert(!configuration_name.empty()); +void MainWindow::OnContextMenuDeleteClicked(ConfigurationListItem *item) { + assert(item); + assert(!item->configuration_name.empty()); // Let make sure... QMessageBox alert; - alert.setWindowTitle(format("Removing *%s* configuration...", configuration_name.c_str()).c_str()); - alert.setText(format("Are you sure you want to remove the *%s* configuration?", configuration_name.c_str()).c_str()); + alert.setWindowTitle(format("Removing *%s* configuration...", item->configuration_name.c_str()).c_str()); + alert.setText(format("Are you sure you want to remove the *%s* configuration?", item->configuration_name.c_str()).c_str()); alert.setInformativeText("All the data from this configuration will be lost."); alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); alert.setDefaultButton(QMessageBox::Yes); @@ -1349,7 +1374,7 @@ void MainWindow::RemoveConfiguration(const std::string &configuration_name) { } Configurator &configurator = Configurator::Get(); - configurator.configurations.RemoveConfiguration(configurator.layers.selected_layers, configuration_name); + configurator.configurations.RemoveConfiguration(configurator.layers.selected_layers, item->configuration_name); configurator.environment.GetActiveConfigurationInfo().SetName(""); LoadConfigurationList(); @@ -1357,13 +1382,7 @@ void MainWindow::RemoveConfiguration(const std::string &configuration_name) { this->UpdateUI(); } -void MainWindow::RemoveClicked(ConfigurationListItem *item) { - assert(item); - - this->RemoveConfiguration(item->configuration_name); -} - -void MainWindow::ResetClicked(ConfigurationListItem *item) { +void MainWindow::OnContextMenuResetClicked(ConfigurationListItem *item) { assert(item); assert(!item->configuration_name.empty()); @@ -1397,61 +1416,29 @@ void MainWindow::ResetClicked(ConfigurationListItem *item) { LoadConfigurationList(); } -void MainWindow::RenameClicked(ConfigurationListItem *item) { - assert(item); - - ui->configurations_tree->editItem(item, 1); -} - -void MainWindow::DuplicateClicked(ConfigurationListItem *item) { +void MainWindow::OnContextMenuReloadClicked(ConfigurationListItem *item) { assert(item); assert(!item->configuration_name.empty()); - - Configurator &configurator = Configurator::Get(); - const Configuration &duplicated_configuration = - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, item->configuration_name, true); - - item->configuration_name = duplicated_configuration.key; - - configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); - configurator.Override(); - - LoadConfigurationList(); - - /* - ConfigurationListItem *new_item = nullptr; - for (int i = 0, n = ui->tree_configurations->topLevelItemCount(); i < n; ++i) { - ConfigurationListItem *searched_item = dynamic_cast(ui->tree_configurations->topLevelItem(i)); - assert(searched_item); - - if (searched_item->configuration_name != duplicated_configuration.key) continue; - - new_item = searched_item; - break; - } - assert(new_item); - ui->tree_configurations->editItem(new_item, 1); - */ } -void MainWindow::ImportClicked(ConfigurationListItem *item) { - (void)item; // We don't need this +void MainWindow::OnContextMenuExportConfigsClicked(ConfigurationListItem *item) { + assert(item); Configurator &configurator = Configurator::Get(); - const Path &path_import = configurator.environment.path_import; - /* - const Path full_import_path = configurator.path.SelectPath(this, PATH_IMPORT_CONFIGURATION); - if (full_import_path.Empty()) { + const Path &path_export = configurator.environment.path_export; + /* TODO + const Path full_export_path = configurator.path.SelectPath(this, PATH_EXPORT_CONFIGURATION, full_suggested_path); + if (full_export_path.Empty()) { return; } - configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, full_import_path); + configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, full_export_path, + item->configuration_name); */ - LoadConfigurationList(); } -void MainWindow::ExportClicked(ConfigurationListItem *item) { +void MainWindow::OnContextMenuExportSettingsClicked(ConfigurationListItem *item) { assert(item); Configurator &configurator = Configurator::Get(); @@ -1483,18 +1470,23 @@ void MainWindow::OnLayerCurrentRowChanged(int currentRow) { this->_settings_tree_manager.CleanupGUI(); if (currentRow != -1) { - Configurator &configurator = Configurator::Get(); QWidget *widget = ui->layers_tree->itemWidget(ui->layers_tree->item(currentRow)); - std::string layer_name = static_cast(widget)->text().toStdString(); - Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration != nullptr) { - for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { - Parameter ¶meter = configuration->parameters[i]; - if (layer_name.find(parameter.key) != std::string::npos) { - configurator.environment.selected_layer_name = parameter.key; + const std::string &layer_string = static_cast(widget)->text().toStdString(); + + /* + Configurator &configurator = Configurator::Get(); + Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + Parameter ¶meter = configuration->parameters[i]; + if (layer_name.find(parameter.key) != std::string::npos) { + configurator.environment.selected_layer_name = parameter.key; + } + } } - } - } + */ + Configurator &configurator = Configurator::Get(); + configurator.environment.selected_layer_name = ExtractLayerName(configurator.layers, layer_string); } // ui->splitter_settings->setVisible(currentRow != -1); @@ -1774,16 +1766,12 @@ static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { TreeWidgetItemParameter *item_parameter = static_cast(item); - const std::string &text = item_parameter->layer_name; - if (!text.empty()) { + const std::string &layer_string = item_parameter->layer_name; + if (!layer_string.empty()) { Configurator &configurator = Configurator::Get(); - for (std::size_t i = 0, n = configurator.layers.selected_layers.size(); i < n; ++i) { - const Layer &layer = configurator.layers.selected_layers[i]; - if (text.find(layer.key) != std::string::npos) { - return &layer; - } - } + const std::string &layer_key = ExtractLayerName(configurator.layers, layer_string); + return configurator.layers.Find(layer_key); } return nullptr; @@ -1886,9 +1874,9 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { menu.addSeparator(); - QAction *action_export = new QAction("Export the Configuration...", nullptr); - action_export->setEnabled(item != nullptr); - menu.addAction(action_export); + QAction *action_export_config = new QAction("Export the Configuration...", nullptr); + action_export_config->setEnabled(item != nullptr); + menu.addAction(action_export_config); QAction *action_export_settings = new QAction("Export the Layers Settings...", nullptr); action_export_settings->setEnabled(item != nullptr); @@ -1898,11 +1886,23 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { QAction *action = menu.exec(point); if (action == action_new) { - } else if (action == action_delete) { - } else if (action == action_duplicate) { - } else if (action == action_rename) { + this->OnContextMenuNewClicked(item); } else if (action == action_import) { - } else if (action == action_export) { + this->OnContextMenuImportClicked(item); + } else if (action == action_rename) { + this->OnContextMenuRenameClicked(item); + } else if (action == action_duplicate) { + this->OnContextMenuDuplicateClicked(item); + } else if (action == action_delete) { + this->OnContextMenuDeleteClicked(item); + } else if (action == action_reset) { + this->OnContextMenuResetClicked(item); + } else if (action == action_reload) { + this->OnContextMenuReloadClicked(item); + } else if (action == action_export_config) { + this->OnContextMenuExportConfigsClicked(item); + } else if (action == action_export_settings) { + this->OnContextMenuExportSettingsClicked(item); } } } else if (target == ui->layers_tree) { @@ -1914,14 +1914,6 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { QMenu menu(ui->layers_tree); - QAction *action_all = new QAction("Show All Layers", nullptr); - action_all->setEnabled(item != nullptr); - action_all->setCheckable(true); - action_all->setChecked(true); - menu.addAction(action_all); - - menu.addSeparator(); - QAction *action_description = new QAction("Open the Layer Description...", nullptr); action_description->setEnabled(item != nullptr); menu.addAction(action_description); diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 5019fb7772..1160f142b8 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -147,13 +147,15 @@ class MainWindow : public QMainWindow { QAction *_tray_layers_disabled_by_configurator; QAction *_tray_quit_action; - void RemoveClicked(ConfigurationListItem *item); - void ResetClicked(ConfigurationListItem *item); - void RenameClicked(ConfigurationListItem *item); - void NewClicked(); - void DuplicateClicked(ConfigurationListItem *item); - void ExportClicked(ConfigurationListItem *item); - void ImportClicked(ConfigurationListItem *item); + void OnContextMenuNewClicked(ConfigurationListItem *item); + void OnContextMenuImportClicked(ConfigurationListItem *item); + void OnContextMenuRenameClicked(ConfigurationListItem *item); + void OnContextMenuDuplicateClicked(ConfigurationListItem *item); + void OnContextMenuDeleteClicked(ConfigurationListItem *item); + void OnContextMenuResetClicked(ConfigurationListItem *item); + void OnContextMenuReloadClicked(ConfigurationListItem *item); + void OnContextMenuExportConfigsClicked(ConfigurationListItem *item); + void OnContextMenuExportSettingsClicked(ConfigurationListItem *item); void AddLayerPathItem(const std::string &layer_path); void AddLayerItem(Parameter ¶meter, bool advanced_view); @@ -198,10 +200,6 @@ class MainWindow : public QMainWindow { void on_push_button_clear_log_clicked(); void on_check_box_clear_on_launch_clicked(); void on_push_button_applications_clicked(); - void on_push_button_new_clicked(); - void on_push_button_rename_clicked(); - void on_push_button_remove_clicked(); - void on_push_button_duplicate_clicked(); void on_check_box_per_application_toggled(bool checked); void on_combo_box_mode_currentIndexChanged(int index); @@ -232,7 +230,6 @@ class MainWindow : public QMainWindow { void InitTray(); void UpdateTray(); - void RemoveConfiguration(const std::string &configuration_name); void ResetLaunchApplication(); void StartTool(Tool tool); QStringList BuildEnvVariables() const; diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index c717a62471..4d4d7878e2 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -70,6 +70,7 @@ SOURCES += \ ../vkconfig_core/type_tab.cpp \ ../vkconfig_core/type_update.cpp \ ../vkconfig_core/util.cpp \ + ../vkconfig_core/ui.cpp \ ../vkconfig_core/version.cpp \ ../vkconfig_core/vulkan_info.cpp \ ../vkconfig_core/vulkan_util.cpp \ @@ -137,6 +138,7 @@ HEADERS += \ ../vkconfig_core/type_tab.h \ ../vkconfig_core/type_update.h \ ../vkconfig_core/util.h \ + ../vkconfig_core/ui.h \ ../vkconfig_core/version.h \ ../vkconfig_core/vulkan_info.h \ ../vkconfig_core/vulkan_util.h \ From 44619cbe99ad88a76a4bcaf96fcef114b0d48f6b Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 31 Jul 2024 19:09:09 +0200 Subject: [PATCH 09/33] vkconfig3: Only update changed system files --- vkconfig_cmd/main_layers.cpp | 4 +- vkconfig_core/configuration_info.h | 12 - vkconfig_core/configurator.cpp | 302 +++++++------ vkconfig_core/configurator.h | 9 +- vkconfig_core/configurator_signal.cpp | 2 +- vkconfig_core/environment.cpp | 76 ++-- vkconfig_core/environment.h | 36 +- ...type_update.cpp => type_override_area.cpp} | 2 +- .../{type_update.h => type_override_area.h} | 10 +- vkconfig_gui/main.cpp | 2 +- vkconfig_gui/mainwindow.cpp | 415 +++++------------- vkconfig_gui/mainwindow.h | 1 - vkconfig_gui/settings_tree.cpp | 2 +- vkconfig_gui/vkconfig.pro | 4 +- 14 files changed, 346 insertions(+), 531 deletions(-) rename vkconfig_core/{type_update.cpp => type_override_area.cpp} (95%) rename vkconfig_core/{type_update.h => type_override_area.h} (75%) diff --git a/vkconfig_cmd/main_layers.cpp b/vkconfig_cmd/main_layers.cpp index 50cbae543b..cd19a58a84 100644 --- a/vkconfig_cmd/main_layers.cpp +++ b/vkconfig_cmd/main_layers.cpp @@ -37,7 +37,7 @@ static int RunLayersOverride(const CommandLine& command_line) { return -1; } - const bool override_result = configurator.Override(); + const bool override_result = configurator.Override(OVERRIDE_AREA_ALL); configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit @@ -64,7 +64,7 @@ static int RunLayersSurrender(const CommandLine& command_line) { Configurator& configurator = Configurator::Get(); const bool has_overridden_layers = configurator.HasOverride(); - const bool surrender_result = configurator.Surrender(); + const bool surrender_result = configurator.Surrender(OVERRIDE_AREA_ALL); configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit diff --git a/vkconfig_core/configuration_info.h b/vkconfig_core/configuration_info.h index 21f05cf7de..5cfec51410 100644 --- a/vkconfig_core/configuration_info.h +++ b/vkconfig_core/configuration_info.h @@ -20,7 +20,6 @@ #pragma once -#include "type_update.h" #include "type_layers_mode.h" #include @@ -29,7 +28,6 @@ class ConfigurationInfo { private: std::string name = "Validation"; LayersMode mode = LAYERS_CONTROLLED_BY_APPLICATIONS; - UpdateBits area = UPDATE_NONE; public: const char* GetName() const { return this->name.c_str(); } @@ -37,7 +35,6 @@ class ConfigurationInfo { void SetName(const std::string& new_configuration_name) { if (this->name != new_configuration_name) { this->name = new_configuration_name; - this->area = UPDATE_ALL; } } @@ -46,15 +43,6 @@ class ConfigurationInfo { void SetMode(LayersMode new_configuration_mode) { if (this->mode != new_configuration_mode) { this->mode = new_configuration_mode; - this->area = UPDATE_ALL; - } - } - - void ForceUpdate(UpdateBits area_bits) { - if (area_bits == UPDATE_NONE) { - this->area = area_bits; - } else { - this->area = static_cast(this->area | area_bits); } } }; diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index 2ffd679fee..003634adb6 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -127,178 +127,193 @@ void Configurator::BuildLoaderSettings(const ConfigurationInfo& info, const std: } // Create and write vk_loader_settings.json file -bool Configurator::WriteLoaderSettings(const Path& loader_settings_path) { +bool Configurator::WriteLoaderSettings(OverrideArea override_area, const Path& loader_settings_path) { assert(!loader_settings_path.Empty()); - std::vector loader_settings_array; + if (override_area & OVERRIDE_AREA_LOADER_SETTINGS_BIT) { + std::vector loader_settings_array; - if (this->environment.GetPerApplicationConfig()) { - for (std::size_t i = 0, n = this->environment.GetApplications().size(); i < n; ++i) { - const Application& application = this->environment.GetApplication(i); + if (this->environment.GetPerApplicationConfig()) { + for (std::size_t i = 0, n = this->environment.GetApplications().size(); i < n; ++i) { + const Application& application = this->environment.GetApplication(i); - this->BuildLoaderSettings(application.configuration, application.executable_path.AbsolutePath(), loader_settings_array); + this->BuildLoaderSettings(application.configuration, application.executable_path.AbsolutePath(), + loader_settings_array); + } + } else { + BuildLoaderSettings(this->environment.global_configuration, "", loader_settings_array); } - } else { - BuildLoaderSettings(this->environment.global_configuration, "", loader_settings_array); - } - if (loader_settings_array.empty()) { - return this->Surrender(); - } else { - QJsonObject root; - root.insert("file_format_version", "1.0.0"); - if (loader_settings_array.size() > 1) { - QJsonArray json_settings_array; - for (std::size_t i = 0, n = loader_settings_array.size(); i < n; ++i) { - json_settings_array.append(CreateJsonSettingObject(loader_settings_array[i])); + if (!loader_settings_array.empty()) { + QJsonObject root; + root.insert("file_format_version", "1.0.0"); + if (loader_settings_array.size() > 1) { + QJsonArray json_settings_array; + for (std::size_t i = 0, n = loader_settings_array.size(); i < n; ++i) { + json_settings_array.append(CreateJsonSettingObject(loader_settings_array[i])); + } + root.insert("settings_array", json_settings_array); + } else if (!loader_settings_array.empty()) { + root.insert("settings", CreateJsonSettingObject(loader_settings_array[0])); } - root.insert("settings_array", json_settings_array); - } else if (!loader_settings_array.empty()) { - root.insert("settings", CreateJsonSettingObject(loader_settings_array[0])); - } - QJsonDocument doc(root); + QJsonDocument doc(root); - QFile json_file(loader_settings_path.AbsolutePath().c_str()); - const bool result_layers_file = json_file.open(QIODevice::WriteOnly | QIODevice::Text); - assert(result_layers_file); - json_file.write(doc.toJson()); - json_file.close(); + QFile json_file(loader_settings_path.AbsolutePath().c_str()); + const bool result_layers_file = json_file.open(QIODevice::WriteOnly | QIODevice::Text); + assert(result_layers_file); + json_file.write(doc.toJson()); + json_file.close(); - return result_layers_file; + return result_layers_file; + } + return true; + } else { + return true; } } // Create and write vk_layer_settings.txt file -bool Configurator::WriteLayersSettings(const Path& layers_settings_path) { - std::vector layers_settings_array; - - if (this->environment.GetPerApplicationConfig()) { - const std::vector& applications = this->environment.GetApplications(); - - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { +bool Configurator::WriteLayersSettings(OverrideArea override_area, const Path& layers_settings_path) { + if (override_area & OVERRIDE_AREA_LAYERS_SETTINGS_BIT) { + std::vector layers_settings_array; + + if (this->environment.GetPerApplicationConfig()) { + const std::vector& applications = this->environment.GetApplications(); + + for (std::size_t i = 0, n = applications.size(); i < n; ++i) { + LayersSettings settings; + settings.configuration_name = applications[i].configuration.GetName(); + settings.executable_path = applications[i].executable_path; + settings.settings_path = applications[i].GetActiveOptions().working_folder; + layers_settings_array.push_back(settings); + } + } else { LayersSettings settings; - settings.configuration_name = applications[i].configuration.GetName(); - settings.executable_path = applications[i].executable_path; - settings.settings_path = applications[i].GetActiveOptions().working_folder; + settings.configuration_name = this->environment.global_configuration.GetName(); + settings.settings_path = layers_settings_path; layers_settings_array.push_back(settings); } - } else { - LayersSettings settings; - settings.configuration_name = this->environment.global_configuration.GetName(); - settings.settings_path = layers_settings_path; - layers_settings_array.push_back(settings); - } - bool has_missing_layers = false; - bool result_settings_file = true; + bool has_missing_layers = false; + bool result_settings_file = true; - for (std::size_t i = 0, n = layers_settings_array.size(); i < n; ++i) { - const LayersSettings& layers_settings = layers_settings_array[i]; - - Configuration* configuration = this->configurations.FindConfiguration(layers_settings.configuration_name); - if (configuration == nullptr) { - if (layers_settings.executable_path.Empty()) { - fprintf(stderr, "Fail to apply unknown '%s' global configuration\n", layers_settings.configuration_name.c_str()); - } else { - fprintf(stderr, "Fail to apply unknown '%s' configuration to '%s'\n", layers_settings.configuration_name.c_str(), - layers_settings.executable_path.AbsolutePath().c_str()); - } - - result_settings_file = false; - continue; - } + for (std::size_t i = 0, n = layers_settings_array.size(); i < n; ++i) { + const LayersSettings& layers_settings = layers_settings_array[i]; - QFile file(layers_settings.settings_path.AbsolutePath().c_str()); - result_settings_file = result_settings_file && file.open(QIODevice::WriteOnly | QIODevice::Text); - if (!result_settings_file) { - fprintf(stderr, "Cannot open file %s\n", layers_settings.settings_path.AbsolutePath().c_str()); - continue; - } - QTextStream stream(&file); + Configuration* configuration = this->configurations.FindConfiguration(layers_settings.configuration_name); + if (configuration == nullptr) { + if (layers_settings.executable_path.Empty()) { + fprintf(stderr, "Fail to apply unknown '%s' global configuration\n", + layers_settings.configuration_name.c_str()); + } else { + fprintf(stderr, "Fail to apply unknown '%s' configuration to '%s'\n", + layers_settings.configuration_name.c_str(), layers_settings.executable_path.AbsolutePath().c_str()); + } - // Loop through all the layers - for (std::size_t j = 0, n = configuration->parameters.size(); j < n; ++j) { - const Parameter& parameter = configuration->parameters[j]; - if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { + result_settings_file = false; continue; } - const Layer* layer = this->layers.Find(parameter.key.c_str()); - if (layer == nullptr) { - has_missing_layers = true; - continue; + if (layers_settings.settings_path.Exists()) { + if (this->GetActiveConfiguration()->key != configuration->key) { + continue; + } } - if (parameter.control != LAYER_CONTROL_ON) { + QFile file(layers_settings.settings_path.AbsolutePath().c_str()); + result_settings_file = result_settings_file && file.open(QIODevice::WriteOnly | QIODevice::Text); + if (!result_settings_file) { + fprintf(stderr, "Cannot open file %s\n", layers_settings.settings_path.AbsolutePath().c_str()); continue; } + QTextStream stream(&file); - stream << "\n"; - stream << "# " << layer->key.c_str() << "\n\n"; - - std::string lc_layer_name = GetLayerSettingPrefix(layer->key); - - for (std::size_t i = 0, m = parameter.settings.size(); i < m; ++i) { - const SettingData* setting_data = parameter.settings[i]; - - // Skip groups - they aren't settings, so not relevant in this output - if (setting_data->type == SETTING_GROUP) { + // Loop through all the layers + for (std::size_t j = 0, n = configuration->parameters.size(); j < n; ++j) { + const Parameter& parameter = configuration->parameters[j]; + if (!(parameter.platform_flags & (1 << VKC_PLATFORM))) { continue; } - // Skip missing settings - const SettingMeta* meta = FindSetting(layer->settings, setting_data->key.c_str()); - if (meta == nullptr) { + const Layer* layer = this->layers.Find(parameter.key.c_str()); + if (layer == nullptr) { + has_missing_layers = true; continue; } - // Skip overriden settings - if (::CheckSettingOverridden(*meta)) { + if (parameter.control != LAYER_CONTROL_ON) { continue; } - stream << "# "; - stream << meta->label.c_str(); - stream << "\n# =====================\n# ."; - stream << meta->key.c_str() << "\n"; - - // Break up description into smaller words - std::string description = meta->description; - std::vector words; - std::size_t pos; - while ((pos = description.find(" ")) != std::string::npos) { - words.push_back(description.substr(0, pos)); - description.erase(0, pos + 1); - } - if (description.size() > 0) words.push_back(description); - if (words.size() > 0) { - stream << "#"; - std::size_t nchars = 2; - for (auto word : words) { - if (word.size() + nchars > 80) { - stream << "\n#"; - nchars = 2; + stream << "\n"; + stream << "# " << layer->key.c_str() << "\n\n"; + + std::string lc_layer_name = GetLayerSettingPrefix(layer->key); + + for (std::size_t i = 0, m = parameter.settings.size(); i < m; ++i) { + const SettingData* setting_data = parameter.settings[i]; + + // Skip groups - they aren't settings, so not relevant in this output + if (setting_data->type == SETTING_GROUP) { + continue; + } + + // Skip missing settings + const SettingMeta* meta = FindSetting(layer->settings, setting_data->key.c_str()); + if (meta == nullptr) { + continue; + } + + // Skip overriden settings + if (::CheckSettingOverridden(*meta)) { + continue; + } + + stream << "# "; + stream << meta->label.c_str(); + stream << "\n# =====================\n# ."; + stream << meta->key.c_str() << "\n"; + + // Break up description into smaller words + std::string description = meta->description; + std::vector words; + std::size_t pos; + while ((pos = description.find(" ")) != std::string::npos) { + words.push_back(description.substr(0, pos)); + description.erase(0, pos + 1); + } + if (description.size() > 0) words.push_back(description); + if (words.size() > 0) { + stream << "#"; + std::size_t nchars = 2; + for (auto word : words) { + if (word.size() + nchars > 80) { + stream << "\n#"; + nchars = 2; + } + stream << " " << word.c_str(); + nchars += (word.size() + 1); } - stream << " " << word.c_str(); - nchars += (word.size() + 1); } - } - stream << "\n"; + stream << "\n"; - // If feature has unmet dependency, output it but comment it out - if (::CheckDependence(*meta, parameter.settings) != SETTING_DEPENDENCE_ENABLE) { - stream << "#"; - } + // If feature has unmet dependency, output it but comment it out + if (::CheckDependence(*meta, parameter.settings) != SETTING_DEPENDENCE_ENABLE) { + stream << "#"; + } - stream << lc_layer_name.c_str() << setting_data->key.c_str() << " = "; - stream << setting_data->Export(EXPORT_MODE_OVERRIDE).c_str(); - stream << "\n\n"; + stream << lc_layer_name.c_str() << setting_data->key.c_str() << " = "; + stream << setting_data->Export(EXPORT_MODE_OVERRIDE).c_str(); + stream << "\n\n"; + } } + file.close(); } - file.close(); - } - return result_settings_file && !has_missing_layers; + return result_settings_file && !has_missing_layers; + } else { + return true; + } } Configurator& Configurator::Get() { @@ -313,7 +328,7 @@ Configurator::~Configurator() { this->configurations.SaveAllConfigurations(); - this->Surrender(); + this->Surrender(OVERRIDE_AREA_ALL); } void Configurator::UpdateLayersValidationCache() { @@ -342,45 +357,52 @@ bool Configurator::Init() { this->configurations.LoadAllConfigurations(this->layers.selected_layers); } - this->Override(); + this->Override(OVERRIDE_AREA_ALL); return true; } -bool Configurator::Override() { +bool Configurator::Override(OverrideArea override_area) { const Path& loader_settings_path = ::Get(Path::LOADER_SETTINGS); const Path& layers_settings_path = ::Get(Path::LAYERS_SETTINGS); // Clean up - this->Surrender(); + this->Surrender(override_area); // vk_loader_settings.json - const bool result_layers = this->WriteLoaderSettings(loader_settings_path); + bool result_loader_settings = this->WriteLoaderSettings(override_area, loader_settings_path); + // TODO, Add per application layer_settings file // vk_layer_settings.txt - const bool result_settings = this->WriteLayersSettings(layers_settings_path); + bool result_layers_settings = this->WriteLayersSettings(override_area, layers_settings_path); // On Windows only, we need to write these values to the registry #if VKC_PLATFORM == VKC_PLATFORM_WINDOWS AppendRegistryEntriesForLayers(loader_settings_path.AbsolutePath().c_str(), layers_settings_path.AbsolutePath().c_str()); #endif - return result_settings && result_layers; + return result_loader_settings && result_layers_settings; } -bool Configurator::Surrender() { +bool Configurator::Surrender(OverrideArea override_area) { const Path& loader_settings_path = ::Get(Path::LOADER_SETTINGS); const Path& layers_settings_path = ::Get(Path::LAYERS_SETTINGS); - const bool result_loader_settings = loader_settings_path.Remove(); - const bool result_layers_settings = layers_settings_path.Remove(); + bool result_loader_settings = true; + if (override_area & OVERRIDE_AREA_LOADER_SETTINGS_BIT) { + result_loader_settings = loader_settings_path.Remove(); + } + + // TODO, Remove per application layer_settings file + bool result_layers_settings = true; + if (override_area & OVERRIDE_AREA_LAYERS_SETTINGS_BIT) { + result_layers_settings = layers_settings_path.Remove(); + } #if VKC_PLATFORM == VKC_PLATFORM_WINDOWS RemoveRegistryEntriesForLayers(loader_settings_path.AbsolutePath().c_str(), layers_settings_path.AbsolutePath().c_str()); #endif - this->environment.global_configuration.ForceUpdate(UPDATE_ALL); - return result_loader_settings && result_layers_settings; } diff --git a/vkconfig_core/configurator.h b/vkconfig_core/configurator.h index bc5fe0117a..2f07e397be 100644 --- a/vkconfig_core/configurator.h +++ b/vkconfig_core/configurator.h @@ -27,6 +27,7 @@ #include "../vkconfig_core/environment.h" #include "../vkconfig_core/configuration_manager.h" #include "../vkconfig_core/type_platform.h" +#include "../vkconfig_core/type_override_area.h" #include "../vkconfig_core/vulkan_info.h" class Configurator { @@ -54,8 +55,8 @@ class Configurator { bool Init(); public: - bool Surrender(); - bool Override(); + bool Surrender(OverrideArea override_area); + bool Override(OverrideArea override_area); bool HasOverride() const; void ResetToDefault(bool hard); @@ -71,8 +72,8 @@ class Configurator { Configurator(const Configurator&) = delete; Configurator& operator=(const Configurator&) = delete; - bool WriteLayersSettings(const Path& layers_settings_path); - bool WriteLoaderSettings(const Path& loader_settings_path); + bool WriteLayersSettings(OverrideArea override_area, const Path& layers_settings_path); + bool WriteLoaderSettings(OverrideArea override_area, const Path& loader_settings_path); void BuildLoaderSettings(const ConfigurationInfo& info, const std::string& executable_path, std::vector& loader_settings_array) const; diff --git a/vkconfig_core/configurator_signal.cpp b/vkconfig_core/configurator_signal.cpp index 21cf767614..6b2ab407a9 100644 --- a/vkconfig_core/configurator_signal.cpp +++ b/vkconfig_core/configurator_signal.cpp @@ -33,7 +33,7 @@ void SurrenderConfiguration(int signal) { configurator.environment.has_crashed = true; // Delete the layers configurations files - configurator.Surrender(); + configurator.Surrender(OVERRIDE_AREA_ALL); } void InitSignals() { diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index 594cc5e96c..cc3e5fd4b9 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -51,30 +51,6 @@ static const char* GetApplicationSuffix() { return TABLE[VKC_PLATFORM]; } -static const char* GetLayoutStateToken(LayoutState state) { - assert(state >= LAYOUT_FIRST && state <= LAYOUT_LAST); - - static const char* table[] = { - "geometry", // LAYOUT_GEOMETRY - "windowState", // LAYOUT_WINDOW_STATE - "splitter1State", // LAYOUT_MAIN_SPLITTER1 - "splitter2State", // LAYOUT_MAIN_SPLITTER2 - "splitter3State", // LAYOUT_MAIN_SPLITTER3 - "vkconfig2_6_geometry", // VKCONFIG3_LAYOUT_GEOMETRY - "vkconfig2_6_windowState", // VKCONFIG3_LAYOUT_WINDOW_STATE - "vkconfig2_6_splitter1State", // VKCONFIG3_LAYOUT_MAIN_SPLITTER1 - "vkconfig2_6_splitter2State", // VKCONFIG3_LAYOUT_MAIN_SPLITTER2 - "vkconfig2_6_splitter3State", // VKCONFIG3_LAYOUT_MAIN_SPLITTER3 - "layerGeometry", // LAYOUT_GEOMETRY_SPLITTER - "splitterLayerState", // LAYOUT_LAYER_SPLITTER - "launcherCollapsed", // LAYOUT_LAUNCHER_COLLAPSED - "launcherOnClear" // LAYOUT_LAUNCHER_CLEAR_ON - }; - static_assert(std::size(table) == LAYOUT_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return table[state]; -} - Environment::Environment(Mode mode) : mode(mode), loader_message_types_flags(::GetLogFlags(qgetenv("VK_LOADER_DEBUG").toStdString())) { if (mode == MODE_AUTO_LOAD_SAVE) { @@ -239,6 +215,29 @@ bool Environment::Load() { this->home_sdk_path = ::Get(Path::HOME); } + if (json_preferences_object.value("layout") != QJsonValue::Undefined) { + const QJsonObject& json_layout_object = json_preferences_object.value("layout").toObject(); + + if (json_layout_object.value("main_geometry") != QJsonValue::Undefined) { + this->layout.main_geometry = json_layout_object.value("main_geometry").toVariant().toByteArray(); + } + if (json_layout_object.value("main_window_state") != QJsonValue::Undefined) { + this->layout.main_window_state = json_layout_object.value("main_window_state").toVariant().toByteArray(); + } + if (json_layout_object.value("main_splitter_main_state") != QJsonValue::Undefined) { + this->layout.main_splitter_main_state = + json_layout_object.value("main_splitter_main_state").toVariant().toByteArray(); + } + if (json_layout_object.value("main_splitter_configurations_state") != QJsonValue::Undefined) { + this->layout.main_splitter_configurations_state = + json_layout_object.value("main_splitter_configurations_state").toVariant().toByteArray(); + } + if (json_layout_object.value("main_splitter_settings_state") != QJsonValue::Undefined) { + this->layout.main_splitter_settings_state = + json_layout_object.value("main_splitter_settings_state").toVariant().toByteArray(); + } + } + const QJsonArray& json_hide_message_boxes_array = json_preferences_object.value("hide_message_boxes").toArray(); this->hide_message_boxes_flags = 0; for (int i = 0, n = json_hide_message_boxes_array.size(); i < n; ++i) { @@ -351,6 +350,25 @@ bool Environment::Save() const { json_preferences_object.insert("use_system_tray", this->use_system_tray); json_preferences_object.insert("VK_HOME", this->home_sdk_path.RelativePath().c_str()); + // TODO: layout is not stored correctly + QJsonObject json_layout_object; + if (!this->layout.main_geometry.isEmpty()) { + json_layout_object.insert("main_geometry", this->layout.main_geometry.data()); + } + if (!this->layout.main_window_state.isEmpty()) { + json_layout_object.insert("main_window_state", this->layout.main_window_state.data()); + } + if (!this->layout.main_splitter_main_state.isEmpty()) { + json_layout_object.insert("main_splitter_main_state", this->layout.main_splitter_main_state.data()); + } + if (!this->layout.main_splitter_configurations_state.isEmpty()) { + json_layout_object.insert("main_splitter_configurations_state", this->layout.main_splitter_configurations_state.data()); + } + if (!this->layout.main_splitter_settings_state.isEmpty()) { + json_layout_object.insert("main_splitter_settings_state", this->layout.main_splitter_settings_state.data()); + } + json_preferences_object.insert("layout", json_layout_object); + QJsonArray json_hide_message_boxes_array; for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { LogType type = static_cast(i); @@ -460,16 +478,6 @@ bool Environment::GetPerApplicationConfig() const { return this->use_per_applica void Environment::SetPerApplicationConfig(bool enable) { this->use_per_application_configuration = enable; } -void Environment::Set(LayoutState state, const QByteArray& data) { - assert(state >= LAYOUT_FIRST && state <= LAYOUT_LAST); - this->layout_states[state] = data; -} - -const QByteArray& Environment::Get(LayoutState state) const { - assert(state >= LAYOUT_FIRST && state <= LAYOUT_LAST); - return this->layout_states[state]; -} - /////////////////////////////////////////////////////////////////////////// /// This is only used on macOS to extract the executable from the bundle. /// You have to look at the plist.info file, you can't just assume whatever diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index 126610c11b..77d74b6547 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -31,28 +31,6 @@ #include #include -enum LayoutState { - VKCONFIG2_LAYOUT_MAIN_GEOMETRY = 0, - VKCONFIG2_LAYOUT_MAIN_WINDOW_STATE, - VKCONFIG2_LAYOUT_MAIN_SPLITTER1, - VKCONFIG2_LAYOUT_MAIN_SPLITTER2, - VKCONFIG2_LAYOUT_MAIN_SPLITTER3, - VKCONFIG3_LAYOUT_MAIN_GEOMETRY, - VKCONFIG3_LAYOUT_MAIN_WINDOW_STATE, - VKCONFIG3_LAYOUT_MAIN_SPLITTER1, - VKCONFIG3_LAYOUT_MAIN_SPLITTER2, - VKCONFIG3_LAYOUT_MAIN_SPLITTER3, - LAYOUT_LAYER_GEOMETRY, - LAYOUT_LAYER_SPLITTER, - LAYOUT_LAUNCHER_COLLAPSED, - LAYOUT_LAUNCHER_NOT_CLEAR, - - LAYOUT_FIRST = VKCONFIG2_LAYOUT_MAIN_GEOMETRY, - LAYOUT_LAST = LAYOUT_LAUNCHER_NOT_CLEAR, -}; - -enum { LAYOUT_COUNT = LAYOUT_LAST - LAYOUT_FIRST + 1 }; - struct DefaultApplication { std::string name; std::string key; @@ -93,9 +71,6 @@ class Environment { const Application& GetApplication(std::size_t application_index) const; Application& GetApplication(std::size_t application_index); - const QByteArray& Get(LayoutState state) const; - void Set(LayoutState state, const QByteArray& data); - bool GetPerApplicationConfig() const; void SetPerApplicationConfig(bool enable); @@ -119,6 +94,16 @@ class Environment { std::string selected_layer_name; + struct Layout { + QByteArray main_geometry; + QByteArray main_window_state; + QByteArray main_splitter_main_state; + QByteArray main_splitter_configurations_state; + QByteArray main_splitter_settings_state; + } layout; + + bool launcher_clear_on_launch = true; + private: Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; @@ -132,7 +117,6 @@ class Environment { Path home_sdk_path; int active_executable_index; - std::array layout_states; std::vector applications; // Update default applications path to use relative path (really useful only on Windows) diff --git a/vkconfig_core/type_update.cpp b/vkconfig_core/type_override_area.cpp similarity index 95% rename from vkconfig_core/type_update.cpp rename to vkconfig_core/type_override_area.cpp index 572d5cf9c9..4bab00ef7e 100644 --- a/vkconfig_core/type_update.cpp +++ b/vkconfig_core/type_override_area.cpp @@ -18,4 +18,4 @@ * - Christophe Riccio */ -#include "type_update.h" +#include "type_override_area.h" diff --git a/vkconfig_core/type_update.h b/vkconfig_core/type_override_area.h similarity index 75% rename from vkconfig_core/type_update.h rename to vkconfig_core/type_override_area.h index 8fc9f6ce7f..5b947c05cd 100644 --- a/vkconfig_core/type_update.h +++ b/vkconfig_core/type_override_area.h @@ -20,9 +20,9 @@ #pragma once -enum UpdateBits { - UPDATE_NONE = 0, - UPDATE_LOADER_SETTINGS_BIT = (1 << 0), - UPDATE_LAYERS_SETTINGS_BIT = (1 << 1), - UPDATE_ALL = UPDATE_LOADER_SETTINGS_BIT | UPDATE_LAYERS_SETTINGS_BIT +enum OverrideArea { + OVERRIDE_AREA_NONE = 0, + OVERRIDE_AREA_LOADER_SETTINGS_BIT = (1 << 0), + OVERRIDE_AREA_LAYERS_SETTINGS_BIT = (1 << 1), + OVERRIDE_AREA_ALL = OVERRIDE_AREA_LOADER_SETTINGS_BIT | OVERRIDE_AREA_LAYERS_SETTINGS_BIT }; diff --git a/vkconfig_gui/main.cpp b/vkconfig_gui/main.cpp index 1333595342..fe0244b6ce 100644 --- a/vkconfig_gui/main.cpp +++ b/vkconfig_gui/main.cpp @@ -69,7 +69,7 @@ int main(int argc, char* argv[]) { Configurator& configurator = Configurator::Get(); // Make sure layers configuration is deleted otherwise BuildVulkanSystemInfo() will crash... (unexplained) - configurator.Surrender(); + configurator.Surrender(OVERRIDE_AREA_ALL); const VulkanSystemInfo& vulkan_info = BuildVulkanSystemInfo(); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index cfa47a0174..21d03f370d 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -127,91 +128,47 @@ static const int LAUNCH_ROW_HEIGHT = 28; #endif /* TODO + case PATH_EXECUTABLE: { + static const char* TABLE[] = { + "Applications (*.exe)", // PLATFORM_WINDOWS + "Applications (*)", // PLATFORM_LINUX + "Applications (*.app, *)", // PLATFORM_MACOS + "N/A" // PLATFORM_ANDROID + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT, + "The tranlation table size doesn't match the enum number of elements"); + + const std::string filter = TABLE[VKC_PLATFORM]; + const std::string selected_path = QFileDialog::getOpenFileName(parent, "Select a Vulkan Executable...", + suggested_path.AbsolutePath().c_str(), filter.c_str()) + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); -Path PathManager::SelectPathImpl(QWidget* parent, PathType path, const Path& suggested_path) { - assert(parent); - assert(path >= PATH_FIRST && path <= PATH_LAST); - assert(!suggested_path.Empty()); - - switch (path) { - case PATH_LAUNCHER_LOG_FILE: { - const std::string selected_path = - QFileDialog::getSaveFileName(parent, "Set Log File To...", suggested_path.AbsolutePath().c_str(), "Log text(*.txt)") - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return GetFullPath(path, QFileInfo(selected_path.c_str()).baseName().toStdString()); - } break; - case PATH_EXECUTABLE: { - static const char* TABLE[] = { - "Applications (*.exe)", // PLATFORM_WINDOWS - "Applications (*)", // PLATFORM_LINUX - "Applications (*.app, *)", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID - }; - static_assert(std::size(TABLE) == PLATFORM_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - const std::string filter = TABLE[VKC_PLATFORM]; - const std::string selected_path = QFileDialog::getOpenFileName(parent, "Select a Vulkan Executable...", - suggested_path.AbsolutePath().c_str(), filter.c_str()) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return GetFullPath(path, QFileInfo(selected_path.c_str()).fileName().toStdString()); - } - case PATH_WORKING_DIR: { - const std::string selected_path = - QFileDialog::getExistingDirectory(parent, "Set Working Folder To...", suggested_path.AbsolutePath().c_str()) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, selected_path); - return Path(GetPath(path)); - } - case PATH_USER_DEFINED_LAYERS_GUI: { - const std::string selected_path = - QFileDialog::getExistingDirectory(parent, "Add User-Defined Layers Folder...", - suggested_path.AbsolutePath().c_str(), QFileDialog::DontUseNativeDialog) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, selected_path); - return Path(GetPath(path)); - } - case PATH_IMPORT_CONFIGURATION: { - const std::string selected_path = - QFileDialog::getOpenFileName(parent, "Import Layers Configuration File", suggested_path.AbsolutePath().c_str(), - "JSON configuration(*.json)") - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return Path(selected_path); - } - case PATH_EXPORT_CONFIGURATION: { - const std::string selected_path = - QFileDialog::getSaveFileName(parent, "Export Layers Configuration File", suggested_path.AbsolutePath().c_str(), - "JSON configuration(*.json)") - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return Path(selected_path); - } - default: - assert(0); + SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); + return GetFullPath(path, QFileInfo(selected_path.c_str()).fileName().toStdString()); + } + case PATH_WORKING_DIR: { + const std::string selected_path = + QFileDialog::getExistingDirectory(parent, "Set Working Folder To...", suggested_path.AbsolutePath().c_str()) + .toStdString(); + if (selected_path.empty()) // The user cancelled return Path(""); + + SetPath(path, selected_path); + return Path(GetPath(path)); + } + case PATH_USER_DEFINED_LAYERS_GUI: { + const std::string selected_path = + QFileDialog::getExistingDirectory(parent, "Add User-Defined Layers Folder...", + suggested_path.AbsolutePath().c_str(), QFileDialog::DontUseNativeDialog) + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, selected_path); + return Path(GetPath(path)); } -} */ MainWindow::MainWindow(QWidget *parent) @@ -294,8 +251,6 @@ MainWindow::MainWindow(QWidget *parent) Configurator &configurator = Configurator::Get(); Environment &environment = configurator.environment; - ui->combo_box_layers_view->setCurrentIndex(configurator.GetActiveConfiguration()->view_advanced_layers); - ui->combo_box_mode->setCurrentIndex(environment.GetActiveConfigurationInfo().GetMode()); // Update configuration application area @@ -336,7 +291,7 @@ MainWindow::MainWindow(QWidget *parent) // ui->check_box_persistent->setToolTip("Keep Vulkan Configurator running in system tray when closing the main window"); // ui->check_box_persistent->setVisible(QSystemTrayIcon::isSystemTrayAvailable()); - LoadConfigurationList(); + this->LoadConfigurationList(); // Resetting this from the default prevents the log window (a QTextEdit) from overflowing. // Whenever the control surpasses this block count, old blocks are discarded. @@ -346,11 +301,11 @@ MainWindow::MainWindow(QWidget *parent) // ui->configuration_tree->scrollToItem(ui->configuration_tree->topLevelItem(0), QAbstractItemView::PositionAtTop); // Restore window geometry from last launch - // restoreGeometry(environment.Get(VKCONFIG3_LAYOUT_MAIN_GEOMETRY)); - // restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_WINDOW_STATE)); - // ui->splitter_main->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER1)); - // ui->splitter_configurations->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER2)); - // ui->splitter_settings->restoreState(environment.Get(VKCONFIG3_LAYOUT_MAIN_SPLITTER3)); + this->restoreGeometry(environment.layout.main_geometry); + this->restoreState(environment.layout.main_window_state); + this->ui->splitter_main->restoreState(environment.layout.main_splitter_main_state); + this->ui->splitter_configurations->restoreState(environment.layout.main_splitter_configurations_state); + this->ui->splitter_settings->restoreState(environment.layout.main_splitter_settings_state); this->UpdateTray(); this->UpdateUI(); @@ -478,12 +433,8 @@ void MainWindow::trayActionControlledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - if (configurator.environment.GetPerApplicationConfig()) { - configurator.environment.GetActiveApplication().configuration.SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); - } else { - configurator.environment.global_configuration.SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); - } - configurator.Override(); + configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); this->UpdateTray(); @@ -494,11 +445,8 @@ void MainWindow::trayActionControlledByConfigurator(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - if (configurator.environment.GetPerApplicationConfig()) { - configurator.environment.GetActiveApplication().configuration.SetMode(LAYERS_CONTROLLED_BY_CONFIGURATOR); - } else { - configurator.environment.global_configuration.SetMode(LAYERS_CONTROLLED_BY_CONFIGURATOR); - } + configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_CONTROLLED_BY_CONFIGURATOR); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); this->UpdateTray(); @@ -509,13 +457,8 @@ void MainWindow::trayActionDisabledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - if (configurator.environment.GetPerApplicationConfig()) { - configurator.environment.GetActiveApplication().configuration.SetMode(LAYERS_DISABLED_BY_CONFIGURATOR); - } else { - configurator.environment.global_configuration.SetMode(LAYERS_DISABLED_BY_CONFIGURATOR); - } - - configurator.Override(); + configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_DISABLED_BY_CONFIGURATOR); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); this->UpdateTray(); @@ -659,6 +602,7 @@ void MainWindow::UpdateUI() { if (item->configuration_name == selected_contiguration_name) { item->radio_button->setChecked(true); ui->configurations_tree->setCurrentItem(item); + ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); } else { // item->radio_button->setChecked(false); } @@ -749,7 +693,7 @@ void MainWindow::UpdateUI() { const bool has_application_list = !environment.GetApplications().empty(); // ui->push_button_launcher->setEnabled(ui->check_box_apply_list->isChecked()); ui->push_button_launcher->setText(_launch_application ? "Terminate" : "Launch"); - ui->check_box_clear_on_launch->setChecked(environment.Get(LAYOUT_LAUNCHER_NOT_CLEAR) != "true"); + ui->check_box_clear_on_launch->setChecked(environment.launcher_clear_on_launch); // ui->launcher_loader_debug->setCurrentIndex(environment.GetLoaderMessage()); // ui->launcher_loader_debug @@ -847,42 +791,6 @@ void MainWindow::LoadConfigurationList() { ui->configurations_tree->setColumnWidth(4, 24); } -/* -// Load or refresh the list of configuration. Any configuration that uses a layer that -// is not detected on the system is disabled. -void MainWindow::LoadConfigurationList() { - // There are lots of ways into this, and in none of them - // can we have an active editor running. - _settings_tree_manager.CleanupGUI(); - // ui->tree_configurations->blockSignals(true); // No signals firing off while we do this - // ui->tree_configurations->clear(); - - Configurator &configurator = Configurator::Get(); - - for (std::size_t i = 0, n = configurator.configurations.available_configurations.size(); i < n; ++i) { - const Configuration &configuration = configurator.configurations.available_configurations[i]; - - // Hide built-in configuration when the layer is missing. The Vulkan user may have not installed the necessary layer - // if (configuration.IsBuiltIn() && HasMissingLayer(configuration.parameters, configurator.layers.available_layers)) - // continue; - - ConfigurationListItem *item = new ConfigurationListItem(configuration.key); - item->setToolTip(0, configuration.description.c_str()); - item->radio_button = new QRadioButton(); - item->radio_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - item->radio_button->setFixedSize(QSize(24, 24)); - item->radio_button->setToolTip(configuration.description.c_str()); - item->setFlags(item->flags() | Qt::ItemIsEditable); - // ui->tree_configurations->addTopLevelItem(item); - // ui->tree_configurations->setItemWidget(item, 0, item->radio_button); - connect(item->radio_button, SIGNAL(clicked(bool)), this, SLOT(OnConfigurationItemClicked(bool))); - } - - // ui->tree_configurations->blockSignals(false); - // ui->tree_configurations->resizeColumnToContents(0); - // ui->tree_configurations->resizeColumnToContents(1); -} -*/ /// Okay, because we are using custom controls, some of /// the signaling is not happening as expected. So, we cannot /// always get an accurate answer to the currently selected @@ -904,50 +812,11 @@ ConfigurationListItem *MainWindow::GetCheckedItem() { return nullptr; } -/* -// We want to apply to just the app list... hang on there. Doe we have the new loader? -void MainWindow::on_check_box_apply_list_clicked() { - Configurator &configurator = Configurator::Get(); - - // Handle old loader case - Version loader_version; - if (!configurator.SupportApplicationList(&loader_version)) { - const std::string version = loader_version.str(); - const std::string message = - format("The detected Vulkan loader version is %s but version 1.2.141 or newer is required", version.c_str()); - ui->check_box_apply_list->setToolTip(message.c_str()); - - Alert::ApplicationListUnsupported(message.c_str()); - - ui->check_box_apply_list->setEnabled(false); - ui->check_box_apply_list->setChecked(false); - ui->push_button_applications->setEnabled(false); - configurator.environment.SetUseApplicationList(false); - been_warned_about_old_loader = true; - - return; - } - - configurator.environment.SetUseApplicationList(ui->check_box_apply_list->isChecked()); - - // Handle the case where no application with active override is present - const bool application_list_requires_update = !configurator.environment.HasOverriddenApplications(); - if (ui->check_box_apply_list->isChecked() && application_list_requires_update) { - ApplicationsDialog dialog(this); - dialog.exec(); - } - - configurator.configurations.Configure(configurator.layers.available_layers); - - UpdateUI(); -} -*/ - void MainWindow::on_combo_box_mode_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); configurator.environment.GetActiveConfigurationInfo().SetMode(static_cast(index)); - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); const bool enabled_ui = index == LAYERS_CONTROLLED_BY_CONFIGURATOR; @@ -983,7 +852,7 @@ void MainWindow::on_check_box_per_application_toggled(bool checked) { } void MainWindow::on_check_box_clear_on_launch_clicked() { - Configurator::Get().environment.Set(LAYOUT_LAUNCHER_NOT_CLEAR, ui->check_box_clear_on_launch->isChecked() ? "false" : "true"); + Configurator::Get().environment.launcher_clear_on_launch = ui->check_box_clear_on_launch->isChecked(); } void MainWindow::on_combo_box_layers_view_currentIndexChanged(int index) { @@ -998,7 +867,9 @@ void MainWindow::on_combo_box_layers_view_currentIndexChanged(int index) { void MainWindow::toolsResetToDefault(bool checked) { (void)checked; - if (Alert::ConfiguratorResetAll() == QMessageBox::No) return; + if (Alert::ConfiguratorResetAll() == QMessageBox::No) { + return; + } Configurator &configurator = Configurator::Get(); configurator.ResetToDefault(true); @@ -1024,9 +895,9 @@ void MainWindow::OnConfigurationItemClicked(bool checked) { Configurator &configurator = Configurator::Get(); configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); configurator.environment.selected_layer_name.clear(); - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - UpdateUI(); + this->UpdateUI(); } void MainWindow::OnConfigurationTreeClicked(QTreeWidgetItem *item, int column) { @@ -1040,10 +911,10 @@ void MainWindow::OnConfigurationTreeClicked(QTreeWidgetItem *item, int column) { configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); configurator.environment.selected_layer_name.clear(); - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); } - UpdateUI(); + this->UpdateUI(); } /// An item has been changed. Check for edit of the items name (configuration name) @@ -1076,7 +947,7 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { Alert::ConfigurationNameInvalid(); } - Configuration *duplicate_configuration = FindByKey(configurator.configurations.available_configurations, new_name.c_str()); + Configuration *duplicate_configuration = configurator.configurations.FindConfiguration(new_name); if (duplicate_configuration != nullptr) { valid_new_name = false; @@ -1084,8 +955,8 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { } // Find existing configuration using it's old name - const std::string old_name = configuration_item->configuration_name; - Configuration *configuration = FindByKey(configurator.configurations.available_configurations, old_name.c_str()); + const std::string &old_name = configuration_item->configuration_name; + Configuration *configuration = configurator.configurations.FindConfiguration(old_name); if (valid_new_name) { // Rename configuration ; Remove old configuration file ; change the name of the configuration @@ -1107,7 +978,7 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { configurator.environment.selected_layer_name.clear(); } - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); } @@ -1133,7 +1004,7 @@ void MainWindow::OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidge configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); } } @@ -1141,7 +1012,9 @@ void MainWindow::OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidge void MainWindow::StartTool(Tool tool) { Configurator &configurator = Configurator::Get(); - configurator.Surrender(); + if (!configurator.environment.GetPerApplicationConfig()) { + configurator.Surrender(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + } switch (tool) { case TOOL_VULKAN_INFO: @@ -1152,7 +1025,9 @@ void MainWindow::StartTool(Tool tool) { break; } - configurator.Override(); + if (!configurator.environment.GetPerApplicationConfig()) { + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + } } /// Create the VulkanInfo dialog if it doesn't already exits & show it. @@ -1251,11 +1126,11 @@ void MainWindow::closeEvent(QCloseEvent *event) { _settings_tree_manager.CleanupGUI(); - environment.Set(VKCONFIG3_LAYOUT_MAIN_GEOMETRY, saveGeometry()); - environment.Set(VKCONFIG3_LAYOUT_MAIN_WINDOW_STATE, saveState()); - environment.Set(VKCONFIG3_LAYOUT_MAIN_SPLITTER1, ui->splitter_main->saveState()); - environment.Set(VKCONFIG3_LAYOUT_MAIN_SPLITTER2, ui->splitter_configurations->saveState()); - environment.Set(VKCONFIG3_LAYOUT_MAIN_SPLITTER3, ui->splitter_settings->saveState()); + environment.layout.main_geometry = this->saveGeometry(); + environment.layout.main_window_state = this->saveState(); + environment.layout.main_splitter_main_state = ui->splitter_main->saveState(); + environment.layout.main_splitter_configurations_state = ui->splitter_configurations->saveState(); + environment.layout.main_splitter_settings_state = ui->splitter_settings->saveState(); QMainWindow::closeEvent(event); } @@ -1263,7 +1138,9 @@ void MainWindow::closeEvent(QCloseEvent *event) { /// Resizing needs a little help. Yes please, there has to be /// a better way of doing this. void MainWindow::resizeEvent(QResizeEvent *event) { - if (event != nullptr) event->accept(); + if (event != nullptr) { + event->accept(); + } const QFontMetrics fm = ui->layers_tree->fontMetrics(); const int combo_width = (fm.size(Qt::TextSingleLine, "Auto").width() * 1.6); @@ -1280,17 +1157,6 @@ void MainWindow::showEvent(QShowEvent *event) { event->accept(); } -/// Edit the list of apps that can be filtered. -void MainWindow::on_push_button_applications_clicked() { - // ApplicationsDialog dlg(this); - // dlg.exec(); - - Configurator &configurator = Configurator::Get(); - configurator.Override(); - - UpdateUI(); -} - void MainWindow::OnContextMenuNewClicked(ConfigurationListItem *item) { Configurator &configurator = Configurator::Get(); @@ -1298,9 +1164,9 @@ void MainWindow::OnContextMenuNewClicked(ConfigurationListItem *item) { configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); - configurator.Override(); + configurator.Override(OVERRIDE_AREA_ALL); - LoadConfigurationList(); + this->LoadConfigurationList(); } void MainWindow::OnContextMenuImportClicked(ConfigurationListItem *item) { @@ -1309,15 +1175,22 @@ void MainWindow::OnContextMenuImportClicked(ConfigurationListItem *item) { Configurator &configurator = Configurator::Get(); const Path &path_import = configurator.environment.path_import; - /* - const Path full_import_path = configurator.path.SelectPath(this, PATH_IMPORT_CONFIGURATION); - if (full_import_path.Empty()) { + const std::string selected_path = QFileDialog::getOpenFileName(this, "Import Layers Configuration File", + path_import.AbsolutePath().c_str(), "JSON configuration(*.json)") + .toStdString(); + + if (selected_path.empty()) { return; } - configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, full_import_path); - */ - LoadConfigurationList(); + configurator.environment.path_import = selected_path; + std::string imported_configuration = + configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, selected_path); + + configurator.environment.GetActiveConfigurationInfo().SetName(imported_configuration); + configurator.Override(OVERRIDE_AREA_ALL); + + this->LoadConfigurationList(); } void MainWindow::OnContextMenuRenameClicked(ConfigurationListItem *item) { @@ -1337,24 +1210,9 @@ void MainWindow::OnContextMenuDuplicateClicked(ConfigurationListItem *item) { item->configuration_name = duplicated_configuration.key; configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); LoadConfigurationList(); - - /* - ConfigurationListItem *new_item = nullptr; - for (int i = 0, n = ui->tree_configurations->topLevelItemCount(); i < n; ++i) { - ConfigurationListItem *searched_item = dynamic_cast(ui->tree_configurations->topLevelItem(i)); - assert(searched_item); - - if (searched_item->configuration_name != duplicated_configuration.key) continue; - - new_item = searched_item; - break; - } - assert(new_item); - ui->tree_configurations->editItem(new_item, 1); - */ } void MainWindow::OnContextMenuDeleteClicked(ConfigurationListItem *item) { @@ -1379,7 +1237,7 @@ void MainWindow::OnContextMenuDeleteClicked(ConfigurationListItem *item) { LoadConfigurationList(); - this->UpdateUI(); + // this->UpdateUI(); } void MainWindow::OnContextMenuResetClicked(ConfigurationListItem *item) { @@ -1419,6 +1277,8 @@ void MainWindow::OnContextMenuResetClicked(ConfigurationListItem *item) { void MainWindow::OnContextMenuReloadClicked(ConfigurationListItem *item) { assert(item); assert(!item->configuration_name.empty()); + + // TODO } void MainWindow::OnContextMenuExportConfigsClicked(ConfigurationListItem *item) { @@ -1427,32 +1287,23 @@ void MainWindow::OnContextMenuExportConfigsClicked(ConfigurationListItem *item) Configurator &configurator = Configurator::Get(); const Path &path_export = configurator.environment.path_export; - /* TODO - const Path full_export_path = configurator.path.SelectPath(this, PATH_EXPORT_CONFIGURATION, full_suggested_path); - if (full_export_path.Empty()) { + const std::string &selected_path = + QFileDialog::getSaveFileName(this, "Export Layers Configuration File", path_export.AbsolutePath().c_str(), + "JSON configuration(*.json)") + .toStdString(); + + if (selected_path.empty()) { return; } - configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, full_export_path, - item->configuration_name); - */ + configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, selected_path, item->configuration_name); } void MainWindow::OnContextMenuExportSettingsClicked(ConfigurationListItem *item) { assert(item); Configurator &configurator = Configurator::Get(); - - const Path &path_export = configurator.environment.path_export; - /* TODO - const Path full_export_path = configurator.path.SelectPath(this, PATH_EXPORT_CONFIGURATION, full_suggested_path); - if (full_export_path.Empty()) { - return; - } - - configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, full_export_path, - item->configuration_name); - */ + // TODO } void MainWindow::editorExpanded(QTreeWidgetItem *item) { @@ -1473,23 +1324,10 @@ void MainWindow::OnLayerCurrentRowChanged(int currentRow) { QWidget *widget = ui->layers_tree->itemWidget(ui->layers_tree->item(currentRow)); const std::string &layer_string = static_cast(widget)->text().toStdString(); - /* - Configurator &configurator = Configurator::Get(); - Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration != nullptr) { - for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { - Parameter ¶meter = configuration->parameters[i]; - if (layer_name.find(parameter.key) != std::string::npos) { - configurator.environment.selected_layer_name = parameter.key; - } - } - } - */ Configurator &configurator = Configurator::Get(); configurator.environment.selected_layer_name = ExtractLayerName(configurator.layers, layer_string); } - // ui->splitter_settings->setVisible(currentRow != -1); this->_settings_tree_manager.CreateGUI(ui->settings_tree); } @@ -1498,8 +1336,7 @@ void MainWindow::OnSettingsTreeClicked(QTreeWidgetItem *item, int column) { (void)item; Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().ForceUpdate(UPDATE_LAYERS_SETTINGS_BIT); - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LAYERS_SETTINGS_BIT); } void MainWindow::SetupLauncherTree() { @@ -1604,11 +1441,6 @@ void MainWindow::SetupLauncherTree() { 1, ui->launcher_tree->rect().width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); - if (Configurator::Get().environment.Get(LAYOUT_LAUNCHER_COLLAPSED) == "true") - launchItemCollapsed(nullptr); - else - ui->launcher_tree->expandItem(launcher_parent); - ui->launcher_tree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->launcher_tree->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } @@ -1618,7 +1450,6 @@ void MainWindow::launchItemExpanded(QTreeWidgetItem *item) { (void)item; ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - Configurator::Get().environment.Set(LAYOUT_LAUNCHER_COLLAPSED, QByteArray("false")); } // Collapsing the tree also shrinks the tree to match and show only the first line @@ -1626,7 +1457,6 @@ void MainWindow::launchItemCollapsed(QTreeWidgetItem *item) { (void)item; ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT + 6); ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT + 6); - Configurator::Get().environment.Set(LAYOUT_LAUNCHER_COLLAPSED, QByteArray("true")); } void MainWindow::OnLauncherLoaderMessageChanged(int level) { @@ -1762,7 +1592,9 @@ void MainWindow::on_push_button_clear_log_clicked() { } static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { - if (item == nullptr) return nullptr; + if (item == nullptr) { + return nullptr; + } TreeWidgetItemParameter *item_parameter = static_cast(item); @@ -1786,7 +1618,7 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { if (event_type == QEvent::ChildRemoved) { // Layers were reordered, we need to update the configuration - Configurator::Get().Override(); + Configurator::Get().Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); return true; } @@ -1804,26 +1636,7 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { } */ - if (target == ui->settings_tree) { - QContextMenuEvent *right_click = dynamic_cast(event); - if (right_click) { - QTreeWidgetItem *item = ui->settings_tree->itemAt(right_click->pos()); - - QMenu menu(ui->settings_tree); - QFont subtitle_font = menu.font(); - subtitle_font.setBold(true); - - QAction *title_action = new QAction("settings context menu", nullptr); - title_action->setFont(subtitle_font); - menu.addAction(title_action); - - QPoint point(right_click->globalX(), right_click->globalY()); - QAction *action = menu.exec(point); - - if (action == title_action) { - } - } - } else if (target == ui->configurations_tree) { + if (target == ui->configurations_tree) { QContextMenuEvent *right_click = dynamic_cast(event); if (right_click) { ConfigurationListItem *item = static_cast(ui->configurations_tree->itemAt(right_click->pos())); diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 1160f142b8..bc066dcdb2 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -199,7 +199,6 @@ class MainWindow : public QMainWindow { void on_push_button_launcher_clicked(); void on_push_button_clear_log_clicked(); void on_check_box_clear_on_launch_clicked(); - void on_push_button_applications_clicked(); void on_check_box_per_application_toggled(bool checked); void on_combo_box_mode_currentIndexChanged(int index); diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 009f859a56..fffe01e252 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -429,7 +429,7 @@ void SettingsTreeManager::Refresh(RefreshAreas refresh_areas) { } // Refresh layer configuration - configurator.Override(); + configurator.Override(OVERRIDE_AREA_LAYERS_SETTINGS_BIT); } void SettingsTreeManager::RefreshItem(RefreshAreas refresh_areas, QTreeWidgetItem *parent) { diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index 4d4d7878e2..0cc711ed58 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -68,7 +68,7 @@ SOURCES += \ ../vkconfig_core/type_platform.cpp \ ../vkconfig_core/type_status.cpp \ ../vkconfig_core/type_tab.cpp \ - ../vkconfig_core/type_update.cpp \ + ../vkconfig_core/type_override_area.cpp \ ../vkconfig_core/util.cpp \ ../vkconfig_core/ui.cpp \ ../vkconfig_core/version.cpp \ @@ -136,7 +136,7 @@ HEADERS += \ ../vkconfig_core/type_platform.h \ ../vkconfig_core/type_status.h \ ../vkconfig_core/type_tab.h \ - ../vkconfig_core/type_update.h \ + ../vkconfig_core/type_override_area.h \ ../vkconfig_core/util.h \ ../vkconfig_core/ui.h \ ../vkconfig_core/version.h \ From 37af2406adbd80417cf2262f283d042629642923 Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 1 Aug 2024 17:14:17 +0200 Subject: [PATCH 10/33] vkconfig3: Save and load mainwindow geometry between sessions Change-Id: I1f26f12908c9f273fc1a2287760ef1da76ebaeca --- vkconfig_core/environment.cpp | 42 ----------------------------------- vkconfig_core/environment.h | 8 ------- vkconfig_gui/mainwindow.cpp | 33 ++++++++++++++++++--------- vkconfig_gui/mainwindow.h | 3 +++ 4 files changed, 25 insertions(+), 61 deletions(-) diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index cc3e5fd4b9..4f7841d508 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -215,29 +215,6 @@ bool Environment::Load() { this->home_sdk_path = ::Get(Path::HOME); } - if (json_preferences_object.value("layout") != QJsonValue::Undefined) { - const QJsonObject& json_layout_object = json_preferences_object.value("layout").toObject(); - - if (json_layout_object.value("main_geometry") != QJsonValue::Undefined) { - this->layout.main_geometry = json_layout_object.value("main_geometry").toVariant().toByteArray(); - } - if (json_layout_object.value("main_window_state") != QJsonValue::Undefined) { - this->layout.main_window_state = json_layout_object.value("main_window_state").toVariant().toByteArray(); - } - if (json_layout_object.value("main_splitter_main_state") != QJsonValue::Undefined) { - this->layout.main_splitter_main_state = - json_layout_object.value("main_splitter_main_state").toVariant().toByteArray(); - } - if (json_layout_object.value("main_splitter_configurations_state") != QJsonValue::Undefined) { - this->layout.main_splitter_configurations_state = - json_layout_object.value("main_splitter_configurations_state").toVariant().toByteArray(); - } - if (json_layout_object.value("main_splitter_settings_state") != QJsonValue::Undefined) { - this->layout.main_splitter_settings_state = - json_layout_object.value("main_splitter_settings_state").toVariant().toByteArray(); - } - } - const QJsonArray& json_hide_message_boxes_array = json_preferences_object.value("hide_message_boxes").toArray(); this->hide_message_boxes_flags = 0; for (int i = 0, n = json_hide_message_boxes_array.size(); i < n; ++i) { @@ -350,25 +327,6 @@ bool Environment::Save() const { json_preferences_object.insert("use_system_tray", this->use_system_tray); json_preferences_object.insert("VK_HOME", this->home_sdk_path.RelativePath().c_str()); - // TODO: layout is not stored correctly - QJsonObject json_layout_object; - if (!this->layout.main_geometry.isEmpty()) { - json_layout_object.insert("main_geometry", this->layout.main_geometry.data()); - } - if (!this->layout.main_window_state.isEmpty()) { - json_layout_object.insert("main_window_state", this->layout.main_window_state.data()); - } - if (!this->layout.main_splitter_main_state.isEmpty()) { - json_layout_object.insert("main_splitter_main_state", this->layout.main_splitter_main_state.data()); - } - if (!this->layout.main_splitter_configurations_state.isEmpty()) { - json_layout_object.insert("main_splitter_configurations_state", this->layout.main_splitter_configurations_state.data()); - } - if (!this->layout.main_splitter_settings_state.isEmpty()) { - json_layout_object.insert("main_splitter_settings_state", this->layout.main_splitter_settings_state.data()); - } - json_preferences_object.insert("layout", json_layout_object); - QJsonArray json_hide_message_boxes_array; for (int i = LOG_FIRST, n = LOG_COUNT; i < n; ++i) { LogType type = static_cast(i); diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index 77d74b6547..eb2caaf47e 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -94,14 +94,6 @@ class Environment { std::string selected_layer_name; - struct Layout { - QByteArray main_geometry; - QByteArray main_window_state; - QByteArray main_splitter_main_state; - QByteArray main_splitter_configurations_state; - QByteArray main_splitter_settings_state; - } layout; - bool launcher_clear_on_launch = true; private: diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 21d03f370d..e2c5ea9c2b 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -300,12 +301,8 @@ MainWindow::MainWindow(QWidget *parent) ui->log_browser->document()->setMaximumBlockCount(2048); // ui->configuration_tree->scrollToItem(ui->configuration_tree->topLevelItem(0), QAbstractItemView::PositionAtTop); - // Restore window geometry from last launch - this->restoreGeometry(environment.layout.main_geometry); - this->restoreState(environment.layout.main_window_state); - this->ui->splitter_main->restoreState(environment.layout.main_splitter_main_state); - this->ui->splitter_configurations->restoreState(environment.layout.main_splitter_configurations_state); - this->ui->splitter_settings->restoreState(environment.layout.main_splitter_settings_state); + // Restore UI geometry from last launch + this->LoadUIGeometry(); this->UpdateTray(); this->UpdateUI(); @@ -1126,15 +1123,29 @@ void MainWindow::closeEvent(QCloseEvent *event) { _settings_tree_manager.CleanupGUI(); - environment.layout.main_geometry = this->saveGeometry(); - environment.layout.main_window_state = this->saveState(); - environment.layout.main_splitter_main_state = ui->splitter_main->saveState(); - environment.layout.main_splitter_configurations_state = ui->splitter_configurations->saveState(); - environment.layout.main_splitter_settings_state = ui->splitter_settings->saveState(); + this->SaveUIGeometry(); QMainWindow::closeEvent(event); } +void MainWindow::LoadUIGeometry() { + QSettings settings("LunarG", VKCONFIG_SHORT_NAME); + this->restoreGeometry(settings.value("mainwindow/geometry").toByteArray()); + this->restoreState(settings.value("mainwindow/state").toByteArray()); + this->ui->splitter_main->restoreState(settings.value("mainwindow/splitter_main_state").toByteArray()); + this->ui->splitter_configurations->restoreState(settings.value("mainwindow/splitter_configurations_state").toByteArray()); + this->ui->splitter_settings->restoreState(settings.value("mainwindow/splitter_settings_state").toByteArray()); +} + +void MainWindow::SaveUIGeometry() { + QSettings settings("LunarG", VKCONFIG_SHORT_NAME); + settings.setValue("mainwindow/geometry", this->saveGeometry()); + settings.setValue("mainwindow/state", this->saveState()); + settings.setValue("mainwindow/splitter_main_state", ui->splitter_main->saveState()); + settings.setValue("mainwindow/splitter_configurations_state", ui->splitter_configurations->saveState()); + settings.setValue("mainwindow/splitter_settings_state", ui->splitter_settings->saveState()); +} + /// Resizing needs a little help. Yes please, there has to be /// a better way of doing this. void MainWindow::resizeEvent(QResizeEvent *event) { diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index bc066dcdb2..bcb59af0f3 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -226,6 +226,9 @@ class MainWindow : public QMainWindow { MainWindow(const MainWindow &) = delete; MainWindow &operator=(const MainWindow &) = delete; + void LoadUIGeometry(); + void SaveUIGeometry(); + void InitTray(); void UpdateTray(); From 0a740b7cc4652acbfa2fef9f3a37eeafe12d288f Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 1 Aug 2024 18:21:39 +0200 Subject: [PATCH 11/33] vkconfig3: Improve UI update --- vkconfig_core/configuration_info.h | 2 +- vkconfig_gui/mainwindow.cpp | 156 ++++++++++++++++------------- vkconfig_gui/mainwindow.h | 5 +- 3 files changed, 90 insertions(+), 73 deletions(-) diff --git a/vkconfig_core/configuration_info.h b/vkconfig_core/configuration_info.h index 5cfec51410..73460fed92 100644 --- a/vkconfig_core/configuration_info.h +++ b/vkconfig_core/configuration_info.h @@ -27,7 +27,7 @@ class ConfigurationInfo { private: std::string name = "Validation"; - LayersMode mode = LAYERS_CONTROLLED_BY_APPLICATIONS; + LayersMode mode = LAYERS_CONTROLLED_BY_CONFIGURATOR; public: const char* GetName() const { return this->name.c_str(); } diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index e2c5ea9c2b..ab956cc4dd 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -198,7 +198,6 @@ MainWindow::MainWindow(QWidget *parent) ui->configurations_tree->installEventFilter(this); ui->layers_tree->installEventFilter(this); ui->settings_tree->installEventFilter(this); - // ui->splitter_settings->setVisible(false); SetupLauncherTree(); @@ -213,14 +212,7 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->actionVulkan_Installation, SIGNAL(triggered(bool)), this, SLOT(toolsVulkanInstallation(bool))); connect(ui->actionRestore_Default_Configurations, SIGNAL(triggered(bool)), this, SLOT(toolsResetToDefault(bool))); - /* - connect(ui->comboBox_configurations, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, - SLOT(OnConfigurationItemChanged(QTreeWidgetItem *, int))); - connect(ui->comboBox_configurations, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, - SLOT(OnConfigurationTreeChanged(QTreeWidgetItem *, QTreeWidgetItem *))); - connect(ui->comboBox_configurations, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, - SLOT(OnConfigurationTreeClicked(QTreeWidgetItem *, int))); - */ + connect(ui->configurations_tree, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(OnConfigurationItemChanged(QTreeWidgetItem *, int))); connect(ui->configurations_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, @@ -230,10 +222,6 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->configurations_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(OnConfigurationTreeClicked(QTreeWidgetItem *, int))); - // connect(ui->layers_tree, SIGNAL(itemChanged(QListWidgetItem *, int)), this, SLOT(OnLayersItemChanged(QListWidgetItem *, - // int))); connect(ui->layers_tree, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, - // SLOT(OnLayersTreeChanged(QListWidgetItem *, QListWidgetItem *))); connect(ui->layers_tree, SIGNAL(indexesMoved(int)), this, - // SLOT(OnLayersIndexesMoved(const QModelIndexList &))); connect(ui->layers_tree, SIGNAL(currentRowChanged(int)), this, SLOT(OnLayerCurrentRowChanged(int))); connect(ui->settings_tree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(editorExpanded(QTreeWidgetItem *))); @@ -279,32 +267,20 @@ MainWindow::MainWindow(QWidget *parent) ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); } - // ui->edit_executable->setText(application.executable_path.c_str()); - /* - ui->edit_dir->setText(application.working_folder.c_str()); - ui->edit_arguments->setText(application.arguments.c_str()); - ui->edit_env->setText(application.env.c_str()); - ui->edit_log->setText(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); - */ ui->execute_closer_application_label->setVisible(true); ui->execute_closer_driver_label->setVisible(true); - // ui->check_box_persistent->setToolTip("Keep Vulkan Configurator running in system tray when closing the main window"); - // ui->check_box_persistent->setVisible(QSystemTrayIcon::isSystemTrayAvailable()); - - this->LoadConfigurationList(); - // Resetting this from the default prevents the log window (a QTextEdit) from overflowing. // Whenever the control surpasses this block count, old blocks are discarded. // Note: We could make this a user configurable setting down the road should this be // insufficinet. ui->log_browser->document()->setMaximumBlockCount(2048); - // ui->configuration_tree->scrollToItem(ui->configuration_tree->topLevelItem(0), QAbstractItemView::PositionAtTop); // Restore UI geometry from last launch this->LoadUIGeometry(); - this->UpdateTray(); + this->UpdateUI_Configurations(); + this->UpdateUI_Status(); this->UpdateUI(); } @@ -344,19 +320,31 @@ void MainWindow::InitTray() { this->_tray_icon = new QSystemTrayIcon(this); this->_tray_icon->setContextMenu(this->_tray_icon_menu); - this->UpdateTray(); + this->UpdateUI_Status(); this->_tray_icon->show(); this->connect(this->_tray_icon, &QSystemTrayIcon::activated, this, &MainWindow::iconActivated); } } -void MainWindow::UpdateTray() { - if (QSystemTrayIcon::isSystemTrayAvailable()) { - // QApplication::setQuitOnLastWindowClosed(!ui->check_box_persistent->isChecked()); +void MainWindow::UpdateUI_Status() { + const Configurator &configurator = Configurator::Get(); + const Environment &environment = configurator.environment; + + const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); + const bool has_selected_configuration = !selected_contiguration_name.empty(); + const bool has_active_configuration = configurator.HasActiveConfiguration() && has_selected_configuration; - const Environment &environment = Configurator::Get().environment; + // Update title bar +#ifdef VKCONFIG_DATE + bool display_date = true; +#else + bool display_date = false; +#endif + this->setWindowTitle(GetMainWindowTitle(has_active_configuration, display_date).c_str()); + + if (QSystemTrayIcon::isSystemTrayAvailable()) { switch (environment.GetActiveConfigurationInfo().GetMode()) { default: case LAYERS_CONTROLLED_BY_APPLICATIONS: @@ -375,17 +363,23 @@ void MainWindow::UpdateTray() { this->_tray_layers_disabled_by_configurator->setChecked(true); break; } + } - if (environment.GetActiveConfigurationInfo().GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { - const QIcon icon(":/resourcefiles/vkconfig-on.png"); + if (has_active_configuration && environment.GetActiveConfigurationInfo().GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { + const QIcon icon(":/resourcefiles/vkconfig-on.png"); - this->setWindowIcon(icon); + this->setWindowIcon(icon); + + if (QSystemTrayIcon::isSystemTrayAvailable()) { this->_tray_icon->setIcon(icon); this->_tray_icon->setToolTip("Layers controlled by the Vulkan Configurator"); - } else { - const QIcon icon(":/resourcefiles/vkconfig-off.png"); + } + } else { + const QIcon icon(":/resourcefiles/vkconfig-off.png"); - this->setWindowIcon(icon); + this->setWindowIcon(icon); + + if (QSystemTrayIcon::isSystemTrayAvailable()) { this->_tray_icon->setIcon(icon); this->_tray_icon->setToolTip("Layers controlled by the Vulkan Applications"); } @@ -413,7 +407,7 @@ void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { this->hide(); } - this->UpdateTray(); + this->UpdateUI_Status(); break; } } @@ -423,7 +417,7 @@ void MainWindow::trayActionRestore() { this->showNormal(); this->UpdateUI(); - this->UpdateTray(); + this->UpdateUI_Status(); } void MainWindow::trayActionControlledByApplications(bool checked) { @@ -434,7 +428,7 @@ void MainWindow::trayActionControlledByApplications(bool checked) { configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); - this->UpdateTray(); + this->UpdateUI_Status(); } } @@ -446,7 +440,7 @@ void MainWindow::trayActionControlledByConfigurator(bool checked) { configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); - this->UpdateTray(); + this->UpdateUI_Status(); } } @@ -458,7 +452,7 @@ void MainWindow::trayActionDisabledByApplications(bool checked) { configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); - this->UpdateTray(); + this->UpdateUI_Status(); } } @@ -530,10 +524,10 @@ void MainWindow::UpdateUI() { ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); ui->combo_box_applications->blockSignals(false); - const bool has_active_configuration = configurator.HasActiveConfiguration(); + const bool has_active_configuration = configurator.HasActiveConfiguration() && has_selected_configuration; // Mode states - this->UpdateTray(); + this->UpdateUI_Status(); // ui->tree_layers_paths->blockSignals(true); // Update configurations @@ -726,15 +720,6 @@ void MainWindow::UpdateUI() { this->_settings_tree_manager.CleanupGUI(); } - // Update title bar -#ifdef VKCONFIG_DATE - bool display_date = true; -#else - bool display_date = false; -#endif - - this->setWindowTitle(GetMainWindowTitle(has_active_configuration, display_date).c_str()); - ui->configurations_tree->blockSignals(false); this->blockSignals(false); @@ -743,7 +728,7 @@ void MainWindow::UpdateUI() { // Load or refresh the list of configuration. Any configuration that uses a layer that // is not detected on the system is disabled. -void MainWindow::LoadConfigurationList() { +void MainWindow::UpdateUI_Configurations() { // There are lots of ways into this, and in none of them // can we have an active editor running. _settings_tree_manager.CleanupGUI(); @@ -788,6 +773,36 @@ void MainWindow::LoadConfigurationList() { ui->configurations_tree->setColumnWidth(4, 24); } +void MainWindow::UpdateUI_Layers() { + ui->layers_tree->clear(); + + Configurator &configurator = Configurator::Get(); + const std::string &selected_contiguration_name = configurator.environment.GetActiveConfigurationInfo().GetName(); + const bool has_selected_configuration = !selected_contiguration_name.empty(); + + if (has_selected_configuration) { + Configuration *configuration = configurator.configurations.FindConfiguration(selected_contiguration_name); + if (configuration != nullptr) { + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + Parameter ¶meter = configuration->parameters[i]; + + if (!configuration->view_advanced_layers) { + if (parameter.control == LAYER_CONTROL_AUTO) { + continue; + } + } + + this->AddLayerItem(parameter, configuration->view_advanced_layers); + } + resizeEvent(nullptr); + + ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); + + ui->layers_tree->update(); + } + } +} + /// Okay, because we are using custom controls, some of /// the signaling is not happening as expected. So, we cannot /// always get an accurate answer to the currently selected @@ -821,7 +836,7 @@ void MainWindow::on_combo_box_mode_currentIndexChanged(int index) { ui->group_box_settings->setEnabled(enabled_ui); ui->group_box_layers->setEnabled(enabled_ui); - this->UpdateTray(); + this->UpdateUI_Status(); this->UpdateUI(); } @@ -833,7 +848,7 @@ void MainWindow::on_combo_box_applications_currentIndexChanged(int index) { ui->combo_box_applications->setToolTip(application.executable_path.AbsolutePath().c_str()); ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); - this->UpdateTray(); + this->UpdateUI_Status(); this->UpdateUI(); } @@ -844,7 +859,7 @@ void MainWindow::on_check_box_per_application_toggled(bool checked) { ui->combo_box_applications->setEnabled(configurator.environment.GetPerApplicationConfig()); ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); - this->UpdateTray(); + this->UpdateUI_Status(); this->UpdateUI(); } @@ -871,9 +886,8 @@ void MainWindow::toolsResetToDefault(bool checked) { Configurator &configurator = Configurator::Get(); configurator.ResetToDefault(true); - LoadConfigurationList(); - - UpdateUI(); + this->UpdateUI_Configurations(); + this->UpdateUI(); } // Thist signal actually comes from the radio button @@ -963,7 +977,7 @@ void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { configurator.environment.GetActiveConfigurationInfo().SetName(new_name); configurator.environment.selected_layer_name.clear(); - LoadConfigurationList(); + this->UpdateUI_Configurations(); } else { // If the configurate name is empty or the configuration name is taken, keep old configuration name @@ -1177,7 +1191,7 @@ void MainWindow::OnContextMenuNewClicked(ConfigurationListItem *item) { configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); configurator.Override(OVERRIDE_AREA_ALL); - this->LoadConfigurationList(); + this->UpdateUI_Configurations(); } void MainWindow::OnContextMenuImportClicked(ConfigurationListItem *item) { @@ -1201,7 +1215,7 @@ void MainWindow::OnContextMenuImportClicked(ConfigurationListItem *item) { configurator.environment.GetActiveConfigurationInfo().SetName(imported_configuration); configurator.Override(OVERRIDE_AREA_ALL); - this->LoadConfigurationList(); + this->UpdateUI_Configurations(); } void MainWindow::OnContextMenuRenameClicked(ConfigurationListItem *item) { @@ -1223,7 +1237,7 @@ void MainWindow::OnContextMenuDuplicateClicked(ConfigurationListItem *item) { configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - LoadConfigurationList(); + this->UpdateUI_Configurations(); } void MainWindow::OnContextMenuDeleteClicked(ConfigurationListItem *item) { @@ -1246,9 +1260,9 @@ void MainWindow::OnContextMenuDeleteClicked(ConfigurationListItem *item) { configurator.configurations.RemoveConfiguration(configurator.layers.selected_layers, item->configuration_name); configurator.environment.GetActiveConfigurationInfo().SetName(""); - LoadConfigurationList(); - - // this->UpdateUI(); + this->UpdateUI_Configurations(); + this->UpdateUI_Layers(); + this->UpdateUI_Status(); } void MainWindow::OnContextMenuResetClicked(ConfigurationListItem *item) { @@ -1278,11 +1292,13 @@ void MainWindow::OnContextMenuResetClicked(ConfigurationListItem *item) { alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); alert.setDefaultButton(QMessageBox::Yes); alert.setIcon(QMessageBox::Warning); - if (alert.exec() == QMessageBox::No) return; + if (alert.exec() == QMessageBox::No) { + return; + } configuration->Reset(configurator.layers.selected_layers); - LoadConfigurationList(); + this->UpdateUI_Configurations(); } void MainWindow::OnContextMenuReloadClicked(ConfigurationListItem *item) { diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index bcb59af0f3..0c6392c74a 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -115,7 +115,6 @@ class MainWindow : public QMainWindow { std::unique_ptr _launch_application; // Keeps track of the monitored app QFile _log_file; // Log file for layer output - void LoadConfigurationList(); void SetupLauncherTree(); void closeEvent(QCloseEvent *event) override; @@ -230,7 +229,9 @@ class MainWindow : public QMainWindow { void SaveUIGeometry(); void InitTray(); - void UpdateTray(); + void UpdateUI_Status(); + void UpdateUI_Configurations(); + void UpdateUI_Layers(); void ResetLaunchApplication(); void StartTool(Tool tool); From 0004667d8fba340c2334cde9106ae232d234c64c Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 12 Aug 2024 17:03:42 +0200 Subject: [PATCH 12/33] vkconfig3: No need for builtin settings manual hiding Change-Id: I77c20e6969d80dbefd2fb38c30beddaf399c8a3a --- vkconfig_gui/settings_tree.cpp | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index fffe01e252..84e4cbaa68 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -202,34 +202,7 @@ void SettingsTreeManager::OnExpandedChanged(const QModelIndex &index) { } } -static bool IsBuiltinValidationSetting(const Parameter ¶meter, const std::string &key) { - if (parameter.key != "VK_LAYER_KHRONOS_validation") { - return false; - } - - std::vector keys; - keys.push_back("enables"); - keys.push_back("disables"); - - if (parameter.api_version.GetPatch() < 242) { - keys.push_back("printf_to_stdout"); - keys.push_back("printf_verbose"); - keys.push_back("printf_buffer_size"); - keys.push_back("gpuav_buffer_oob"); - keys.push_back("warn_on_robust_oob"); - keys.push_back("validate_draw_indirect"); - keys.push_back("vma_linear_output"); - keys.push_back("fine_grained_locking"); - } - - return IsStringFound(keys, key); -} - void SettingsTreeManager::BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶meter, const SettingMeta &meta_object) { - if (IsBuiltinValidationSetting(parameter, meta_object.key)) { - return; - } - if (!IsPlatformSupported(meta_object.platform_flags)) { return; } From 93423ceb562b43c5e00d955194cc89e671a1d4e9 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 14 Aug 2024 18:31:59 +0200 Subject: [PATCH 13/33] vkconfig3: Add loader messages types per configuration --- vkconfig_core/configuration.cpp | 7 + vkconfig_core/configuration.h | 2 + vkconfig_core/configurator.cpp | 2 + vkconfig_gui/mainwindow.cpp | 440 +++++++++-------- vkconfig_gui/mainwindow.h | 25 +- vkconfig_gui/mainwindow.ui | 828 +++++++++++++++----------------- 6 files changed, 654 insertions(+), 650 deletions(-) diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index 6cdd65ac16..07bcd71aa7 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -24,6 +24,7 @@ #include "path.h" #include "json.h" #include "type_platform.h" +#include "type_log.h" #include "version.h" #include @@ -150,6 +151,11 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa this->view_advanced_layers = ReadBoolValue(json_configuration_object, "view_advanced_layers"); } + if (json_configuration_object.value("loader_message_types") != QJsonValue::Undefined) { + const std::vector& loader_messsage_types = ReadStringArray(json_configuration_object, "loader_message_types"); + this->loader_log_messages_flags = GetLogFlags(loader_messsage_types); + } + if (json_configuration_object.value("platforms") != QJsonValue::Undefined) { this->platform_flags = GetPlatformFlags(ReadStringArray(json_configuration_object, "platforms")); } @@ -311,6 +317,7 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { SaveStringArray(json_configuration, "platforms", GetPlatformTokens(this->platform_flags)); json_configuration.insert("view_advanced_settings", this->view_advanced_settings); json_configuration.insert("view_advanced_layers", this->view_advanced_layers); + SaveStringArray(json_configuration, "loader_message_types", GetLogTokens(this->loader_log_messages_flags)); json_configuration.insert("layers", json_layers); QJsonArray json_paths; diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index 85355084cd..f232c4d708 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -22,6 +22,7 @@ #pragma once #include "parameter.h" +#include "type_log.h" #include @@ -48,6 +49,7 @@ class Configuration { std::string description; // A friendly description of what this profile does bool view_advanced_settings = false; bool view_advanced_layers = true; + int loader_log_messages_flags = GetBit(LOG_ERROR) | GetBit(LOG_WARN); std::vector parameters; std::vector user_defined_paths; diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index 003634adb6..ff66dd36f4 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -95,6 +95,8 @@ void Configurator::BuildLoaderSettings(const ConfigurationInfo& info, const std: } assert(configuration != nullptr); + result.stderr_log_flags = configuration->loader_log_messages_flags; + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { LoaderLayerSettings loader_layer_settings; diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index ab956cc4dd..3c63c69b98 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -175,16 +175,6 @@ static const int LAUNCH_ROW_HEIGHT = 28; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _launch_application(nullptr), - _log_file(nullptr), - _launcher_apps_combo(nullptr), - _launcher_executable(nullptr), - _launcher_arguments(nullptr), - _launcher_working(nullptr), - _launcher_log_file_edit(nullptr), - _launcher_apps_browse_button(nullptr), - _launcher_executable_browse_button(nullptr), - _launcher_working_browse_button(nullptr), - _launcher_log_file_browse_button(nullptr), _tray_icon(nullptr), _tray_icon_menu(nullptr), _tray_restore_action(nullptr), @@ -194,7 +184,7 @@ MainWindow::MainWindow(QWidget *parent) _tray_quit_action(nullptr), ui(new Ui::MainWindow) { ui->setupUi(this); - ui->launcher_tree->installEventFilter(this); + ui->application_list->installEventFilter(this); ui->configurations_tree->installEventFilter(this); ui->layers_tree->installEventFilter(this); ui->settings_tree->installEventFilter(this); @@ -228,12 +218,9 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->settings_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(OnSettingsTreeClicked(QTreeWidgetItem *, int))); - connect(ui->launcher_tree, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this, SLOT(launchItemCollapsed(QTreeWidgetItem *))); - connect(ui->launcher_tree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(launchItemExpanded(QTreeWidgetItem *))); + // connect(ui->launcher_loader_debug, SIGNAL(currentIndexChanged(int)), this, SLOT(OnLauncherLoaderMessageChanged(int))); - connect(ui->launcher_loader_debug, SIGNAL(currentIndexChanged(int)), this, SLOT(OnLauncherLoaderMessageChanged(int))); - - connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); + // connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); this->InitTray(); @@ -615,29 +602,8 @@ void MainWindow::UpdateUI() { // Load Layers items // ui->layers_tree->setEnabled(enable_layer_ui); - ui->layers_tree->clear(); - - if (has_selected_configuration) { - Configuration *configuration = configurator.configurations.FindConfiguration(selected_contiguration_name); - if (configuration != nullptr) { - for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { - Parameter ¶meter = configuration->parameters[i]; - - if (!configuration->view_advanced_layers) { - if (parameter.control == LAYER_CONTROL_AUTO) { - continue; - } - } - - this->AddLayerItem(parameter, configuration->view_advanced_layers); - } - resizeEvent(nullptr); - - ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); - - ui->layers_tree->update(); - } - } + this->UpdateUI_LoaderMessages(); + this->UpdateUI_Layers(); // Handle application lists states /* @@ -647,8 +613,8 @@ void MainWindow::UpdateUI() { ui->push_button_applications->setEnabled(!been_warned_about_old_loader && ui->combo_box_mode->currentIndex() != LAYERS_MODE_BY_APPLICATIONS); */ - _launcher_apps_combo->blockSignals(true); - _launcher_apps_combo->clear(); + //_launcher_apps_combo->blockSignals(true); + //_launcher_apps_combo->clear(); /* if (applications.empty()) { _launcher_executable->setText(""); @@ -668,7 +634,7 @@ void MainWindow::UpdateUI() { _launcher_log_file_edit->setText(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); } */ - _launcher_apps_combo->blockSignals(false); + //_launcher_apps_combo->blockSignals(false); // Handle persistent states /* @@ -687,32 +653,6 @@ void MainWindow::UpdateUI() { ui->check_box_clear_on_launch->setChecked(environment.launcher_clear_on_launch); // ui->launcher_loader_debug->setCurrentIndex(environment.GetLoaderMessage()); - // ui->launcher_loader_debug - if (_launcher_executable_browse_button) { - _launcher_executable_browse_button->setEnabled(has_application_list); - } - if (_launcher_working_browse_button) { - _launcher_working_browse_button->setEnabled(has_application_list); - } - if (_launcher_log_file_browse_button) { - _launcher_log_file_browse_button->setEnabled(has_application_list); - } - if (_launcher_apps_combo) { - _launcher_apps_combo->setEnabled(has_application_list); - } - if (_launcher_executable) { - _launcher_executable->setEnabled(has_application_list); - } - if (_launcher_arguments) { - _launcher_arguments->setEnabled(has_application_list); - } - if (_launcher_working) { - _launcher_working->setEnabled(has_application_list); - } - if (_launcher_log_file_edit) { - _launcher_log_file_edit->setEnabled(has_application_list); - } - // ui->settings_tree->setEnabled(environment.GetMode() == LAYERS_MODE_CONTROLLED_BY_CONFIGURATOR && has_selected_configuration); if (has_selected_configuration) { this->_settings_tree_manager.CreateGUI(ui->settings_tree); @@ -773,6 +713,32 @@ void MainWindow::UpdateUI_Configurations() { ui->configurations_tree->setColumnWidth(4, 24); } +void MainWindow::UpdateUI_LoaderMessages() { + const Configurator &configurator = Configurator::Get(); + + const Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + ui->configuration_loader_errors_checkBox->blockSignals(true); + ui->configuration_loader_errors_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_ERROR)); + ui->configuration_loader_errors_checkBox->blockSignals(false); + ui->configuration_loader_warns_checkBox->blockSignals(true); + ui->configuration_loader_warns_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_WARN)); + ui->configuration_loader_warns_checkBox->blockSignals(false); + ui->configuration_loader_infos_checkBox->blockSignals(true); + ui->configuration_loader_infos_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_INFO)); + ui->configuration_loader_infos_checkBox->blockSignals(false); + ui->configuration_loader_debug_checkBox->blockSignals(true); + ui->configuration_loader_debug_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_DEBUG)); + ui->configuration_loader_debug_checkBox->blockSignals(false); + ui->configuration_loader_layers_checkBox->blockSignals(true); + ui->configuration_loader_layers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_LAYER)); + ui->configuration_loader_layers_checkBox->blockSignals(false); + ui->configuration_loader_drivers_checkBox->blockSignals(true); + ui->configuration_loader_drivers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_IMPLEM)); + ui->configuration_loader_drivers_checkBox->blockSignals(false); + } +} + void MainWindow::UpdateUI_Layers() { ui->layers_tree->clear(); @@ -832,7 +798,7 @@ void MainWindow::on_combo_box_mode_currentIndexChanged(int index) { const bool enabled_ui = index == LAYERS_CONTROLLED_BY_CONFIGURATOR; - ui->group_box_configurations->setEnabled(enabled_ui); + ui->configurations_tree->setEnabled(enabled_ui); ui->group_box_settings->setEnabled(enabled_ui); ui->group_box_layers->setEnabled(enabled_ui); @@ -863,6 +829,50 @@ void MainWindow::on_check_box_per_application_toggled(bool checked) { this->UpdateUI(); } +void MainWindow::OnConfigurationLoaderMessageCheckBox_toggled(bool checked) { + (void)checked; + + Configurator &configurator = Configurator::Get(); + + Configuration *active_configuration = configurator.GetActiveConfiguration(); + if (active_configuration != nullptr) { + int loader_log_messages_bits = 0; + + loader_log_messages_bits |= ui->configuration_loader_errors_checkBox->isChecked() ? GetBit(LOG_ERROR) : 0; + loader_log_messages_bits |= ui->configuration_loader_warns_checkBox->isChecked() ? GetBit(LOG_WARN) : 0; + loader_log_messages_bits |= ui->configuration_loader_infos_checkBox->isChecked() ? GetBit(LOG_INFO) : 0; + loader_log_messages_bits |= ui->configuration_loader_debug_checkBox->isChecked() ? GetBit(LOG_DEBUG) : 0; + loader_log_messages_bits |= ui->configuration_loader_layers_checkBox->isChecked() ? GetBit(LOG_LAYER) : 0; + loader_log_messages_bits |= ui->configuration_loader_drivers_checkBox->isChecked() ? GetBit(LOG_IMPLEM) : 0; + + active_configuration->loader_log_messages_flags = loader_log_messages_bits; + } +} + +void MainWindow::on_configuration_loader_errors_checkBox_toggled(bool checked) { + OnConfigurationLoaderMessageCheckBox_toggled(checked); +} + +void MainWindow::on_configuration_loader_warns_checkBox_toggled(bool checked) { + OnConfigurationLoaderMessageCheckBox_toggled(checked); +} + +void MainWindow::on_configuration_loader_infos_checkBox_toggled(bool checked) { + OnConfigurationLoaderMessageCheckBox_toggled(checked); +} + +void MainWindow::on_configuration_loader_debug_checkBox_toggled(bool checked) { + OnConfigurationLoaderMessageCheckBox_toggled(checked); +} + +void MainWindow::on_configuration_loader_layers_checkBox_toggled(bool checked) { + OnConfigurationLoaderMessageCheckBox_toggled(checked); +} + +void MainWindow::on_configuration_loader_drivers_checkBox_toggled(bool checked) { + OnConfigurationLoaderMessageCheckBox_toggled(checked); +} + void MainWindow::on_check_box_clear_on_launch_clicked() { Configurator::Get().environment.launcher_clear_on_launch = ui->check_box_clear_on_launch->isChecked(); } @@ -1261,6 +1271,7 @@ void MainWindow::OnContextMenuDeleteClicked(ConfigurationListItem *item) { configurator.environment.GetActiveConfigurationInfo().SetName(""); this->UpdateUI_Configurations(); + this->UpdateUI_LoaderMessages(); this->UpdateUI_Layers(); this->UpdateUI_Status(); } @@ -1367,111 +1378,131 @@ void MainWindow::OnSettingsTreeClicked(QTreeWidgetItem *item, int column) { } void MainWindow::SetupLauncherTree() { - // App Name - QTreeWidgetItem *launcher_parent = new QTreeWidgetItem(); - launcher_parent->setText(0, "Application"); - ui->launcher_tree->addTopLevelItem(launcher_parent); - - _launcher_apps_combo = new QComboBox(); - _launcher_apps_combo->setFocusPolicy(Qt::StrongFocus); - _launcher_apps_combo->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_apps_combo->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_parent, 1, _launcher_apps_combo); - - _launcher_apps_browse_button = new QPushButton(); - _launcher_apps_browse_button->setText("..."); - _launcher_apps_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_apps_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_apps_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_apps_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_parent, 2, _launcher_apps_browse_button); - connect(_launcher_apps_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(launchItemChanged(int))); - connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); - - // Executable - QTreeWidgetItem *launcher_executable_item = new QTreeWidgetItem(); - launcher_executable_item->setText(0, "Executable"); - launcher_parent->addChild(launcher_executable_item); - - _launcher_executable = new QLineEdit(); - _launcher_executable->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_executable->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_executable_item, 1, _launcher_executable); - _launcher_executable->setReadOnly(false); - - _launcher_executable_browse_button = new QPushButton(); - _launcher_executable_browse_button->setText("..."); - _launcher_executable_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_executable_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_executable_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_executable_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_executable_item, 2, _launcher_executable_browse_button); - connect(_launcher_executable, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeExecutable(const QString &))); - connect(_launcher_executable_browse_button, SIGNAL(clicked()), this, SLOT(launchSetExecutable())); - - // Working folder - QTreeWidgetItem *launcher_folder_item = new QTreeWidgetItem(); - launcher_folder_item->setText(0, "Working Directory"); - launcher_parent->addChild(launcher_folder_item); - - _launcher_working = new QLineEdit(); - _launcher_working->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_working->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_folder_item, 1, _launcher_working); - _launcher_working->setReadOnly(false); - - _launcher_working_browse_button = new QPushButton(); - _launcher_working_browse_button->setText("..."); - _launcher_working_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_working_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_working_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_working_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_folder_item, 2, _launcher_working_browse_button); - connect(_launcher_working, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeWorkingFolder(const QString &))); - connect(_launcher_working_browse_button, SIGNAL(clicked()), this, SLOT(launchSetWorkingFolder())); - - // Command line arguments - QTreeWidgetItem *launcher_arguments_item = new QTreeWidgetItem(); - launcher_arguments_item->setText(0, "Command-line Arguments"); - launcher_parent->addChild(launcher_arguments_item); - - _launcher_arguments = new QLineEdit(); - _launcher_arguments->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_arguments->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_arguments_item, 1, _launcher_arguments); - connect(_launcher_arguments, SIGNAL(textEdited(const QString &)), this, SLOT(launchArgsEdited(const QString &))); - - // Log file - QTreeWidgetItem *launcher_log_file_item = new QTreeWidgetItem(); - launcher_log_file_item->setText(0, "Output Log"); - launcher_parent->addChild(launcher_log_file_item); - - _launcher_log_file_edit = new QLineEdit(); - _launcher_log_file_edit->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_log_file_edit->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_log_file_item, 1, _launcher_log_file_edit); - connect(_launcher_log_file_edit, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeLogFile(const QString &))); - - _launcher_log_file_browse_button = new QPushButton(); - _launcher_log_file_browse_button->setText("..."); - _launcher_log_file_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_log_file_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - ui->launcher_tree->setItemWidget(launcher_log_file_item, 2, _launcher_log_file_browse_button); - connect(_launcher_log_file_browse_button, SIGNAL(clicked()), this, SLOT(launchSetLogFile())); - - // Launcher tree - ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); + const Configurator &configurator = Configurator::Get(); - ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); - ui->launcher_tree->setColumnWidth( - 1, ui->launcher_tree->rect().width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); - ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); + const std::vector &applications = configurator.environment.GetApplications(); + ui->application_list->clear(); + for (std::size_t i = 0, n = applications.size(); i < n; ++i) { + QListWidgetItem *application_item = new QListWidgetItem(); + application_item->setText(applications[i].executable_path.RelativePath().c_str()); + application_item->setToolTip(applications[i].executable_path.AbsolutePath().c_str()); + ui->application_list->addItem(application_item); + } + + const std::vector &configurations = configurator.configurations.available_configurations; + ui->application_configuration_comboBox->clear(); + for (std::size_t i = 0, n = configurations.size(); i < n; ++i) { + ui->application_configuration_comboBox->addItem(configurations[i].key.c_str()); + } - ui->launcher_tree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->launcher_tree->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + /* + // App Name + QTreeWidgetItem *launcher_parent = new QTreeWidgetItem(); + launcher_parent->setText(0, "Application"); + ui->application_list->addTopLevelItem(launcher_parent); + + _launcher_apps_combo = new QComboBox(); + _launcher_apps_combo->setFocusPolicy(Qt::StrongFocus); + _launcher_apps_combo->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_apps_combo->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->application_list->setItemWidget(launcher_parent, 1, _launcher_apps_combo); + + _launcher_apps_browse_button = new QPushButton(); + _launcher_apps_browse_button->setText("..."); + _launcher_apps_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_apps_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + _launcher_apps_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_apps_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_parent, 2, _launcher_apps_browse_button); + connect(_launcher_apps_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(launchItemChanged(int))); + connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); + + // Executable + QTreeWidgetItem *launcher_executable_item = new QTreeWidgetItem(); + launcher_executable_item->setText(0, "Executable"); + launcher_parent->addChild(launcher_executable_item); + + _launcher_executable = new QLineEdit(); + _launcher_executable->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_executable->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->application_list->setItemWidget(launcher_executable_item, 1, _launcher_executable); + _launcher_executable->setReadOnly(false); + + _launcher_executable_browse_button = new QPushButton(); + _launcher_executable_browse_button->setText("..."); + _launcher_executable_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_executable_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + _launcher_executable_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_executable_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_executable_item, 2, _launcher_executable_browse_button); + connect(_launcher_executable, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeExecutable(const QString &))); + connect(_launcher_executable_browse_button, SIGNAL(clicked()), this, SLOT(launchSetExecutable())); + + // Working folder + QTreeWidgetItem *launcher_folder_item = new QTreeWidgetItem(); + launcher_folder_item->setText(0, "Working Directory"); + launcher_parent->addChild(launcher_folder_item); + + _launcher_working = new QLineEdit(); + _launcher_working->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_working->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_folder_item, 1, _launcher_working); + _launcher_working->setReadOnly(false); + + _launcher_working_browse_button = new QPushButton(); + _launcher_working_browse_button->setText("..."); + _launcher_working_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_working_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + _launcher_working_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_working_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_folder_item, 2, _launcher_working_browse_button); + connect(_launcher_working, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeWorkingFolder(const QString &))); + connect(_launcher_working_browse_button, SIGNAL(clicked()), this, SLOT(launchSetWorkingFolder())); + + // Command line arguments + QTreeWidgetItem *launcher_arguments_item = new QTreeWidgetItem(); + launcher_arguments_item->setText(0, "Command-line Arguments"); + launcher_parent->addChild(launcher_arguments_item); + + _launcher_arguments = new QLineEdit(); + _launcher_arguments->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_arguments->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_arguments_item, 1, _launcher_arguments); + connect(_launcher_arguments, SIGNAL(textEdited(const QString &)), this, SLOT(launchArgsEdited(const QString &))); + + // Log file + QTreeWidgetItem *launcher_log_file_item = new QTreeWidgetItem(); + launcher_log_file_item->setText(0, "Output Log"); + launcher_parent->addChild(launcher_log_file_item); + + _launcher_log_file_edit = new QLineEdit(); + _launcher_log_file_edit->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_log_file_edit->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_log_file_item, 1, _launcher_log_file_edit); + connect(_launcher_log_file_edit, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeLogFile(const QString &))); + + _launcher_log_file_browse_button = new QPushButton(); + _launcher_log_file_browse_button->setText("..."); + _launcher_log_file_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_log_file_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + ui->launcher_tree->setItemWidget(launcher_log_file_item, 2, _launcher_log_file_browse_button); + connect(_launcher_log_file_browse_button, SIGNAL(clicked()), this, SLOT(launchSetLogFile())); + + // Launcher tree + ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); + ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); + + ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); + ui->launcher_tree->setColumnWidth( + 1, ui->launcher_tree->rect().width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); + ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); + + ui->launcher_tree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui->launcher_tree->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + */ } +/* // Expanding the tree also grows the tree to match void MainWindow::launchItemExpanded(QTreeWidgetItem *item) { (void)item; @@ -1485,7 +1516,9 @@ void MainWindow::launchItemCollapsed(QTreeWidgetItem *item) { ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT + 6); ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT + 6); } +*/ +/* void MainWindow::OnLauncherLoaderMessageChanged(int level) { Configurator &configurator = Configurator::Get(); @@ -1503,19 +1536,20 @@ void MainWindow::launchSetExecutable() { Configurator &configurator = Configurator::Get(); Application &application = configurator.environment.GetApplication(current_application_index); - /* TODO - const Path exe = configurator.path.SelectPath(this, PATH_EXECUTABLE, application.executable_path); - // The user has cancel the operation - if (exe.Empty()) { - return; - } + //const Path exe = configurator.path.SelectPath(this, PATH_EXECUTABLE, application.executable_path); + + //// The user has cancel the operation + //if (exe.Empty()) { + // return; + //} + + //application.executable_path = exe; - application.executable_path = exe; - */ _launcher_executable->setText(application.executable_path.RelativePath().c_str()); } - +*/ +/* void MainWindow::launchSetLogFile() { int current_application_index = _launcher_apps_combo->currentIndex(); assert(current_application_index >= 0); @@ -1523,19 +1557,20 @@ void MainWindow::launchSetLogFile() { Configurator &configurator = Configurator::Get(); Application &application = configurator.environment.GetApplication(current_application_index); ApplicationOptions &options = application.GetActiveOptions(); - /* TODO - const Path &path = configurator.path.SelectPath(this, PATH_LAUNCHER_LOG_FILE, options.log_file); + // TODO + //const Path &path = configurator.path.SelectPath(this, PATH_LAUNCHER_LOG_FILE, options.log_file); - // The user has cancel the operation - if (path.Empty()) { - return; - } + //// The user has cancel the operation + //if (path.Empty()) { + // return; + //} + + //options.log_file = path; - options.log_file = path; - */ _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); } - +*/ +/* void MainWindow::launchSetWorkingFolder() { int current_application_index = _launcher_apps_combo->currentIndex(); assert(current_application_index >= 0); @@ -1544,19 +1579,21 @@ void MainWindow::launchSetWorkingFolder() { Application &application = configurator.environment.GetApplication(current_application_index); ApplicationOptions &options = application.GetActiveOptions(); - /* TODO - const Path path = configurator.path.SelectPath(this, PATH_WORKING_DIR, options.working_folder); + // TODO + //const Path path = configurator.path.SelectPath(this, PATH_WORKING_DIR, options.working_folder); - // The user has cancel the operation - if (path.Empty()) { - return; - } + //// The user has cancel the operation + //if (path.Empty()) { + // return; + //} + + //options.working_folder = path; - options.working_folder = path; - */ _launcher_working->setText(options.working_folder.RelativePath().c_str()); } +*/ +/* // Log file path edited manually. void MainWindow::launchChangeLogFile(const QString &log_file) { int current_application_index = _launcher_apps_combo->currentIndex(); @@ -1610,6 +1647,7 @@ void MainWindow::launchArgsEdited(const QString &arguments) { ApplicationOptions &options = application.GetActiveOptions(); options.arguments = SplitSpace(arguments.toStdString()); } +*/ // Clear the browser window void MainWindow::on_push_button_clear_log_clicked() { @@ -1857,11 +1895,11 @@ void MainWindow::on_push_button_launcher_clicked() { options.working_folder, format("The '%s' application will fail to launch.", active_application.executable_path.AbsolutePath().c_str()).c_str()); } - + /* if (!_launcher_arguments->text().isEmpty()) { launch_log += format("- Command-line Arguments: %s\n", _launcher_arguments->text().toStdString().c_str()); } - + */ if (!options.log_file.Empty()) { launch_log += format("- Log file: %s\n", options.log_file.AbsolutePath().c_str()); } @@ -1893,9 +1931,9 @@ void MainWindow::on_push_button_launcher_clicked() { connect(_launch_application.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processClosed(int, QProcess::ExitStatus))); - _launch_application->setProgram(ui->edit_executable->text()); - _launch_application->setWorkingDirectory(ui->edit_dir->text()); - _launch_application->setEnvironment(BuildEnvVariables() + ui->edit_env->text().split(",")); + //_launch_application->setProgram(ui->edit_executable->text()); + //_launch_application->setWorkingDirectory(ui->edit_dir->text()); + //_launch_application->setEnvironment(BuildEnvVariables() + ui->edit_env->text().split(",")); if (!options.arguments.empty()) { const QStringList args = ConvertString(options.arguments); diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 0c6392c74a..3e8d188f68 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -129,15 +129,6 @@ class MainWindow : public QMainWindow { ConfigurationListItem *GetCheckedItem(); - QComboBox *_launcher_apps_combo; - QLineEdit *_launcher_executable; - QLineEdit *_launcher_arguments; - QLineEdit *_launcher_working; - QLineEdit *_launcher_log_file_edit; - QPushButton *_launcher_apps_browse_button; - QPushButton *_launcher_executable_browse_button; - QPushButton *_launcher_working_browse_button; - QPushButton *_launcher_log_file_browse_button; QSystemTrayIcon *_tray_icon; QMenu *_tray_icon_menu; QAction *_tray_restore_action; @@ -181,7 +172,7 @@ class MainWindow : public QMainWindow { void OnHelpGPUInfo(bool checked); void editorExpanded(QTreeWidgetItem *item); - + /* void launchItemExpanded(QTreeWidgetItem *item); void launchItemCollapsed(QTreeWidgetItem *item); void launchItemChanged(int index); @@ -192,7 +183,7 @@ class MainWindow : public QMainWindow { void launchChangeExecutable(const QString &new_text); void launchChangeWorkingFolder(const QString &new_text); void launchArgsEdited(const QString &new_text); - + */ void on_tab_widget_currentChanged(int index); void on_push_button_launcher_clicked(); @@ -205,6 +196,15 @@ class MainWindow : public QMainWindow { void on_combo_box_layers_view_currentIndexChanged(int index); + void OnConfigurationLoaderMessageCheckBox_toggled(bool checked); + + void on_configuration_loader_errors_checkBox_toggled(bool checked); + void on_configuration_loader_warns_checkBox_toggled(bool checked); + void on_configuration_loader_infos_checkBox_toggled(bool checked); + void on_configuration_loader_debug_checkBox_toggled(bool checked); + void on_configuration_loader_layers_checkBox_toggled(bool checked); + void on_configuration_loader_drivers_checkBox_toggled(bool checked); + void OnConfigurationItemExpanded(QTreeWidgetItem *item); void OnConfigurationItemClicked(bool checked); void OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); @@ -215,7 +215,7 @@ class MainWindow : public QMainWindow { void OnSettingsTreeClicked(QTreeWidgetItem *item, int column); - void OnLauncherLoaderMessageChanged(int level); + // void OnLauncherLoaderMessageChanged(int level); void standardOutputAvailable(); // stdout output is available void errorOutputAvailable(); // Layeroutput is available @@ -231,6 +231,7 @@ class MainWindow : public QMainWindow { void InitTray(); void UpdateUI_Status(); void UpdateUI_Configurations(); + void UpdateUI_LoaderMessages(); void UpdateUI_Layers(); void ResetLaunchApplication(); diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index 1c73755f38..913891f8cd 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -128,102 +128,110 @@ 6 - - - 0 - + 0 - - 0 - 0 - - - 0 + + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked - + + + + + 0 0 - - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 120 - - - - - Arial - 10 - - - - Qt::ScrollBarAlwaysOff - - - false - - - QAbstractItemView::NoEditTriggers + + + 0 - - true + + 0 - - 3 + + 0 - - false - - - true - - - false - - - - - - - - - 2 - - - - - 3 - - - + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 32 + 16777215 + + + + + + + + + + + + + 0 + 0 + + + + + 32 + 0 + + + + + 32 + 16777215 + + + + - + + + + .. + + + false + + + + - + 0 @@ -236,153 +244,138 @@ 0 - - + + 7 + + + 0 + + + - + + Layers Mode: - - + + - - + Arguments: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - + + + + 0 + + + + + + + + + 32 + 16777215 + + + + ... + + + + + + + + + 0 + + + + + + + + + 32 + 16777215 + + + + ... + + + + + + + + + + + + + - ... + Output Log: - - + + - * + Env Variables: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + Working Dir: + + + + + + + 0 + + + + + + Layers Controlled by Vulkan Applications + + + + + Layers Controlled by Vulkan Configurator + + + + + Layers Disabled by Vulkan Configurator + + + + + + + + + - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - Executable: - - - - - - - - - - - - - - - - - - 32 - 16777215 - - - - ... - - - - - - - Output Log: - - - - - - - - - - Working Dir: - - - - - - - - 0 - 0 - - - - - 32 - 16777215 - - - - ... - - - - - - - Arguments: - - - - - - - Env Variables: - - - - - - - - 32 - 16777215 - - - - ... - - - - - @@ -415,6 +408,19 @@ 0 + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -445,79 +451,6 @@ - - - - 0 - 0 - - - - <html><head/><body><p>Vulkan loader debug messages level used by the VK_LOADER_DEBUG environment variable on launch. <br/><br/>Levels are:<br/>- error<br/>- warn (warnings)<br/>- info (information)<br/>- debug<br/>- layer (layer information)<br/>- implem (implementation/icd information)<br/>- all (report out all messages)</p></body></html> - - - - none - - - - - error - - - - - warn - - - - - info - - - - - debug - - - - - layer - - - - - implem - - - - - all - - - - - - - - Vulkan Loader Messages: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - @@ -535,6 +468,12 @@ + + + 0 + 0 + + Consolas @@ -632,100 +571,10 @@ 0 - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 7 - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Layers Mode: - - - - - - - - 0 - 0 - - - - - Layers Controlled by Vulkan Applications - - - - - Layers Controlled by Vulkan Configurator - - - - - Layers Disabled by Vulkan Configurator - - - - - - - - Per-Application: - - - - - - - - false + true @@ -752,6 +601,71 @@ 0 + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + Per-Application: + + + + + + + + 0 + 0 + + + + Layers Mode: + + + + + + + + 0 + 0 + + + + + Layers Controlled by Vulkan Applications + + + + + Layers Controlled by Vulkan Configurator + + + + + Layers Disabled by Vulkan Configurator + + + + + + @@ -825,25 +739,6 @@ - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - @@ -877,7 +772,7 @@ 0 - + @@ -906,53 +801,7 @@ - - - - - 0 - 0 - - - - - Arial - 10 - - - - QFrame::Box - - - QFrame::Sunken - - - 0 - - - Qt::ScrollBarAlwaysOn - - - 0 - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::DragDrop - - - Qt::MoveAction - - - true - - - - + @@ -984,13 +833,13 @@ - + 0 - 7 + 0 @@ -1021,6 +870,111 @@ + + + + + 0 + 0 + + + + + Arial + 10 + + + + QFrame::Box + + + QFrame::Sunken + + + 0 + + + Qt::ScrollBarAlwaysOn + + + 0 + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + true + + + + + + + 0 + + + 7 + + + + + Loader Messages: + + + + + + + Errors + + + + + + + Warnings + + + + + + + Informations + + + + + + + Debug + + + + + + + Layers + + + + + + + Drivers + + + + + From 0f0972429eadf8c6fce9e8fb09c5248a8b781589 Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 15 Aug 2024 14:21:06 +0200 Subject: [PATCH 14/33] vkconfig3: Infrastructure to handle per tab UI update --- vkconfig_core/configuration.cpp | 5 + vkconfig_core/configuration.h | 1 + vkconfig_core/environment.h | 2 - vkconfig_gui/CMakeLists.txt | 1 + vkconfig_gui/configuration_layer_widget.cpp | 69 + vkconfig_gui/mainwindow.cpp | 1399 +---------------- vkconfig_gui/mainwindow.h | 76 +- vkconfig_gui/mainwindow.ui | 53 +- vkconfig_gui/resourcefiles/config-invalid.png | Bin 0 -> 1885 bytes vkconfig_gui/resourcefiles/config-off.png | Bin 0 -> 1348 bytes vkconfig_gui/resourcefiles/config-on.png | Bin 0 -> 1698 bytes vkconfig_gui/resources.qrc | 3 + vkconfig_gui/settings_tree.cpp | 16 +- vkconfig_gui/tab.cpp | 26 + vkconfig_gui/tab.h | 52 + vkconfig_gui/tab_applications.cpp | 338 ++++ vkconfig_gui/tab_applications.h | 32 + vkconfig_gui/tab_configurations.cpp | 711 +++++++++ vkconfig_gui/tab_configurations.h | 74 + vkconfig_gui/tab_diagnostics.cpp | 32 + vkconfig_gui/tab_diagnostics.h | 32 + vkconfig_gui/tab_help.cpp | 32 + vkconfig_gui/tab_help.h | 32 + vkconfig_gui/tab_layers.cpp | 32 + vkconfig_gui/tab_layers.h | 32 + vkconfig_gui/tab_preferences.cpp | 32 + vkconfig_gui/tab_preferences.h | 32 + vkconfig_gui/vkconfig.pro | 14 + 28 files changed, 1691 insertions(+), 1437 deletions(-) create mode 100644 vkconfig_gui/resourcefiles/config-invalid.png create mode 100644 vkconfig_gui/resourcefiles/config-off.png create mode 100644 vkconfig_gui/resourcefiles/config-on.png create mode 100644 vkconfig_gui/tab.cpp create mode 100644 vkconfig_gui/tab.h create mode 100644 vkconfig_gui/tab_applications.cpp create mode 100644 vkconfig_gui/tab_applications.h create mode 100644 vkconfig_gui/tab_configurations.cpp create mode 100644 vkconfig_gui/tab_configurations.h create mode 100644 vkconfig_gui/tab_diagnostics.cpp create mode 100644 vkconfig_gui/tab_diagnostics.h create mode 100644 vkconfig_gui/tab_help.cpp create mode 100644 vkconfig_gui/tab_help.h create mode 100644 vkconfig_gui/tab_layers.cpp create mode 100644 vkconfig_gui/tab_layers.h create mode 100644 vkconfig_gui/tab_preferences.cpp create mode 100644 vkconfig_gui/tab_preferences.h diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index 07bcd71aa7..eb82e4a65e 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -151,6 +151,10 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa this->view_advanced_layers = ReadBoolValue(json_configuration_object, "view_advanced_layers"); } + if (json_configuration_object.value("selected_layer_name") != QJsonValue::Undefined) { + this->selected_layer_name = ReadString(json_configuration_object, "selected_layer_name"); + } + if (json_configuration_object.value("loader_message_types") != QJsonValue::Undefined) { const std::vector& loader_messsage_types = ReadStringArray(json_configuration_object, "loader_message_types"); this->loader_log_messages_flags = GetLogFlags(loader_messsage_types); @@ -317,6 +321,7 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { SaveStringArray(json_configuration, "platforms", GetPlatformTokens(this->platform_flags)); json_configuration.insert("view_advanced_settings", this->view_advanced_settings); json_configuration.insert("view_advanced_layers", this->view_advanced_layers); + json_configuration.insert("selected_layer_name", this->selected_layer_name.c_str()); SaveStringArray(json_configuration, "loader_message_types", GetLogTokens(this->loader_log_messages_flags)); json_configuration.insert("layers", json_layers); diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index f232c4d708..58e11f157d 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -50,6 +50,7 @@ class Configuration { bool view_advanced_settings = false; bool view_advanced_layers = true; int loader_log_messages_flags = GetBit(LOG_ERROR) | GetBit(LOG_WARN); + std::string selected_layer_name; std::vector parameters; std::vector user_defined_paths; diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index eb2caaf47e..51a50a7a2f 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -92,8 +92,6 @@ class Environment { ConfigurationInfo global_configuration; std::map layers_validated; - std::string selected_layer_name; - bool launcher_clear_on_launch = true; private: diff --git a/vkconfig_gui/CMakeLists.txt b/vkconfig_gui/CMakeLists.txt index 9468a70df6..fa31687fdc 100644 --- a/vkconfig_gui/CMakeLists.txt +++ b/vkconfig_gui/CMakeLists.txt @@ -54,3 +54,4 @@ else() include(macOS/vkconfig.cmake) endif() endif() + diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/configuration_layer_widget.cpp index 588fb00c52..4388749542 100644 --- a/vkconfig_gui/configuration_layer_widget.cpp +++ b/vkconfig_gui/configuration_layer_widget.cpp @@ -23,6 +23,75 @@ #include "../vkconfig_core/configurator.h" +#if VKC_PLATFORM == VKC_PLATFORM_LINUX || VKC_PLATFORM == VKC_PLATFORM_MACOS +#include + +#elif VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#include + +// From Stack Overflow. +#define MKPTR(p1, p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2)) + +typedef enum _pe_architecture { + PE_ARCHITECTURE_UNKNOWN = 0x0000, + PE_ARCHITECTURE_ANYCPU = 0x0001, + PE_ARCHITECTURE_X86 = 0x010B, + PE_ARCHITECTURE_x64 = 0x020B +} PE_ARCHITECTURE; + +static PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) { + // Parse and validate the DOS header + IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER *)pImageBase; + if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; + + // Parse and validate the NT header + IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS *)MKPTR(pDosHd, pDosHd->e_lfanew); + if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; + + // First, naive, check based on the 'Magic' number in the Optional Header. + PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic; + + return architecture; +} + +// End Stack Overflow +#endif // VKC_PLATFORM + +/// Utility function to see if the file is 32-bit +static bool IsDLL32Bit(const std::string full_path) { +#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS + if (full_path.empty()) { + return false; + } + + QFile file(full_path.c_str()); + if (!file.open(QIODevice::ReadOnly)) { + return false; // punt... + } + + // Not gonna lie, just guessed 1024 and it was enough. + // This is the minimum page size on any OS (I might be wrong, + // it could be 4096), so going lower is not really helpful. + // Changed to 4096 on a whim; looking for crashing bug I can't debug + void *header = file.map(0, 4096, QFileDevice::MapPrivateOption); + + // Another punt as we may not be able to map the file + if (header == nullptr) { + return false; + } + + PE_ARCHITECTURE arch = GetImageArchitecture(header); + + file.unmap((uchar *)header); + file.close(); + + return (PE_ARCHITECTURE_X86 == arch); +#else + (void)full_path; + return false; +#endif +} + ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter, bool advanced_view) : layer_name(parameter.key) { diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 3c63c69b98..19aa0cacb0 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -27,14 +27,13 @@ #include "../vkconfig_core/configurator.h" #include "../vkconfig_core/alert.h" #include "../vkconfig_core/util.h" +#include "../vkconfig_core/ui.h" #include "../vkconfig_core/version.h" #include "../vkconfig_core/help.h" -#include "../vkconfig_core/doc.h" #include "../vkconfig_core/date.h" #include "../vkconfig_core/type_platform.h" #include "../vkconfig_core/type_log.h" #include "../vkconfig_core/type_hide_message.h" -#include "../vkconfig_core/ui.h" #include #include @@ -50,128 +49,6 @@ #include -#if VKC_PLATFORM == VKC_PLATFORM_LINUX || VKC_PLATFORM == VKC_PLATFORM_MACOS -#include - -#elif VKC_PLATFORM == VKC_PLATFORM_WINDOWS -#include - -// From Stack Overflow. -#define MKPTR(p1, p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2)) - -typedef enum _pe_architecture { - PE_ARCHITECTURE_UNKNOWN = 0x0000, - PE_ARCHITECTURE_ANYCPU = 0x0001, - PE_ARCHITECTURE_X86 = 0x010B, - PE_ARCHITECTURE_x64 = 0x020B -} PE_ARCHITECTURE; - -static PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) { - // Parse and validate the DOS header - IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER *)pImageBase; - if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; - - // Parse and validate the NT header - IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS *)MKPTR(pDosHd, pDosHd->e_lfanew); - if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; - - // First, naive, check based on the 'Magic' number in the Optional Header. - PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic; - - return architecture; -} - -// End Stack Overflow -#endif // VKC_PLATFORM - -/// Utility function to see if the file is 32-bit -static bool IsDLL32Bit(const std::string full_path) { -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS - if (full_path.empty()) { - return false; - } - - QFile file(full_path.c_str()); - if (!file.open(QIODevice::ReadOnly)) { - return false; // punt... - } - - // Not gonna lie, just guessed 1024 and it was enough. - // This is the minimum page size on any OS (I might be wrong, - // it could be 4096), so going lower is not really helpful. - // Changed to 4096 on a whim; looking for crashing bug I can't debug - void *header = file.map(0, 4096, QFileDevice::MapPrivateOption); - - // Another punt as we may not be able to map the file - if (header == nullptr) { - return false; - } - - PE_ARCHITECTURE arch = GetImageArchitecture(header); - - file.unmap((uchar *)header); - file.close(); - - return (PE_ARCHITECTURE_X86 == arch); -#else - (void)full_path; - return false; -#endif -} - -static const int LAUNCH_COLUMN0_SIZE = 220; -static const int LAUNCH_COLUMN2_SIZE = 32; -static const int LAUNCH_SPACING_SIZE = 2; -#if VKC_PLATFORM == VKC_PLATFORM_MACOS -static const int LAUNCH_ROW_HEIGHT = 26; -#else -static const int LAUNCH_ROW_HEIGHT = 28; -#endif - -/* TODO - case PATH_EXECUTABLE: { - static const char* TABLE[] = { - "Applications (*.exe)", // PLATFORM_WINDOWS - "Applications (*)", // PLATFORM_LINUX - "Applications (*.app, *)", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID - }; - static_assert(std::size(TABLE) == PLATFORM_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - const std::string filter = TABLE[VKC_PLATFORM]; - const std::string selected_path = QFileDialog::getOpenFileName(parent, "Select a Vulkan Executable...", - suggested_path.AbsolutePath().c_str(), filter.c_str()) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return GetFullPath(path, QFileInfo(selected_path.c_str()).fileName().toStdString()); - } - case PATH_WORKING_DIR: { - const std::string selected_path = - QFileDialog::getExistingDirectory(parent, "Set Working Folder To...", suggested_path.AbsolutePath().c_str()) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, selected_path); - return Path(GetPath(path)); - } - case PATH_USER_DEFINED_LAYERS_GUI: { - const std::string selected_path = - QFileDialog::getExistingDirectory(parent, "Add User-Defined Layers Folder...", - suggested_path.AbsolutePath().c_str(), QFileDialog::DontUseNativeDialog) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, selected_path); - return Path(GetPath(path)); - } -*/ - MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _launch_application(nullptr), @@ -185,11 +62,22 @@ MainWindow::MainWindow(QWidget *parent) ui(new Ui::MainWindow) { ui->setupUi(this); ui->application_list->installEventFilter(this); - ui->configurations_tree->installEventFilter(this); - ui->layers_tree->installEventFilter(this); - ui->settings_tree->installEventFilter(this); - SetupLauncherTree(); + this->InitTray(); + + this->tab_diagnostic.reset(new TabDiagnostics(*this, ui)); + this->tab_applications.reset(new TabApplications(*this, ui)); + this->tab_layers.reset(new TabLayers(*this, ui)); + this->tab_configurations.reset(new TabConfigurations(*this, ui)); + this->tab_preferences.reset(new TabPreferences(*this, ui)); + this->tab_help.reset(new TabHelp(*this, ui)); + + this->tabs[TAB_DIAGNOSTIC] = this->tab_diagnostic; + this->tabs[TAB_APPLICATIONS] = this->tab_applications; + this->tabs[TAB_LAYERS] = this->tab_layers; + this->tabs[TAB_CONFIGURATIONS] = this->tab_configurations; + this->tabs[TAB_PREFERENCES] = this->tab_preferences; + this->tabs[TAB_HELP] = this->tab_help; connect(ui->action_find_more_layers, SIGNAL(triggered(bool)), this, SLOT(OnHelpFindLayers(bool))); connect(ui->actionAbout, SIGNAL(triggered(bool)), this, SLOT(OnHelpAbout(bool))); @@ -203,75 +91,26 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->actionVulkan_Installation, SIGNAL(triggered(bool)), this, SLOT(toolsVulkanInstallation(bool))); connect(ui->actionRestore_Default_Configurations, SIGNAL(triggered(bool)), this, SLOT(toolsResetToDefault(bool))); - connect(ui->configurations_tree, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, - SLOT(OnConfigurationItemChanged(QTreeWidgetItem *, int))); - connect(ui->configurations_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, - SLOT(OnConfigurationItemDoubleClicked(QTreeWidgetItem *, int))); - connect(ui->configurations_tree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, - SLOT(OnConfigurationTreeChanged(QTreeWidgetItem *, QTreeWidgetItem *))); - connect(ui->configurations_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, - SLOT(OnConfigurationTreeClicked(QTreeWidgetItem *, int))); - - connect(ui->layers_tree, SIGNAL(currentRowChanged(int)), this, SLOT(OnLayerCurrentRowChanged(int))); - - connect(ui->settings_tree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(editorExpanded(QTreeWidgetItem *))); - connect(ui->settings_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, - SLOT(OnSettingsTreeClicked(QTreeWidgetItem *, int))); - // connect(ui->launcher_loader_debug, SIGNAL(currentIndexChanged(int)), this, SLOT(OnLauncherLoaderMessageChanged(int))); // connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); - this->InitTray(); - - Configurator &configurator = Configurator::Get(); - Environment &environment = configurator.environment; - - ui->combo_box_mode->setCurrentIndex(environment.GetActiveConfigurationInfo().GetMode()); - - // Update configuration application area - - if (environment.GetApplications().empty()) { - environment.SetPerApplicationConfig(false); - - ui->check_box_per_application->setEnabled(false); - ui->check_box_per_application->setVisible(false); - ui->combo_box_applications->setVisible(false); - } else { - ui->check_box_per_application->setEnabled(true); - - ui->combo_box_applications->blockSignals(true); - ui->combo_box_applications->clear(); - for (std::size_t i = 0, n = environment.GetApplications().size(); i < n; ++i) { - const Application &application = environment.GetApplications()[i]; - - ui->combo_box_applications->addItem(application.executable_path.RelativePath().c_str()); - } - ui->combo_box_applications->blockSignals(false); - - this->on_check_box_per_application_toggled(environment.GetPerApplicationConfig()); - this->on_combo_box_applications_currentIndexChanged(environment.GetActiveApplicationIndex()); - ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); - } - - ui->execute_closer_application_label->setVisible(true); - ui->execute_closer_driver_label->setVisible(true); - // Resetting this from the default prevents the log window (a QTextEdit) from overflowing. // Whenever the control surpasses this block count, old blocks are discarded. // Note: We could make this a user configurable setting down the road should this be // insufficinet. ui->log_browser->document()->setMaximumBlockCount(2048); - // Restore UI geometry from last launch - this->LoadUIGeometry(); + QSettings settings("LunarG", VKCONFIG_SHORT_NAME); + this->restoreGeometry(settings.value("mainwindow/geometry").toByteArray()); + this->restoreState(settings.value("mainwindow/state").toByteArray()); - this->UpdateUI_Configurations(); + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); this->UpdateUI_Status(); this->UpdateUI(); } -MainWindow::~MainWindow() { ResetLaunchApplication(); } +MainWindow::~MainWindow() { this->ResetLaunchApplication(); } void MainWindow::InitTray() { if (QSystemTrayIcon::isSystemTrayAvailable()) { @@ -456,41 +295,10 @@ void MainWindow::AddLayerPathItem(const std::string &layer_path) { ui->tree_layers_paths->setItemWidget(item_state, layer_path_widget); } -void MainWindow::AddLayerItem(Parameter ¶meter, bool advanced_view) { - assert(!parameter.key.empty()); - - Configurator &configurator = Configurator::Get(); - - const Layer *layer = configurator.layers.Find(parameter.key); - - TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(parameter.key.c_str()); - item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); - ui->layers_tree->addItem(item_state); - - std::vector layers; - if (layer != nullptr) { - layers.push_back(layer); - } - - ConfigurationLayerWidget *layer_widget = new ConfigurationLayerWidget(layers, parameter, advanced_view); - item_state->widget = layer_widget; - - if (parameter.control == LAYER_CONTROL_APPLICATIONS_API) { - item_state->widget->setToolTip("Located and Enabled Layers using the Vulkan API by the Vulkan Application"); - } else if (parameter.control == LAYER_CONTROL_APPLICATIONS_ENV) { - item_state->widget->setToolTip("Located and Enabled Layers using Environment Variables by the Vulkan Application"); - } - - ui->layers_tree->setItemWidget(item_state, layer_widget); - if (configurator.environment.selected_layer_name == parameter.key) { - ui->layers_tree->setCurrentItem(item_state); - } -} - void MainWindow::UpdateUI() { static int check_recurse = 0; ++check_recurse; - // assert(check_recurse <= 1); + assert(check_recurse <= 1); Configurator &configurator = Configurator::Get(); const Environment &environment = Configurator::Get().environment; @@ -498,309 +306,30 @@ void MainWindow::UpdateUI() { const bool has_selected_configuration = !selected_contiguration_name.empty(); this->blockSignals(true); - ui->configurations_tree->blockSignals(true); - - // Add applications - ui->combo_box_applications->blockSignals(true); - ui->combo_box_applications->clear(); - ui->combo_box_applications->setEnabled(ui->check_box_per_application->isChecked()); - const std::vector &applications = environment.GetApplications(); - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - ui->combo_box_applications->addItem(applications[i].executable_path.RelativePath().c_str()); - } - ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); - ui->combo_box_applications->blockSignals(false); + ui->configurations_list->blockSignals(true); const bool has_active_configuration = configurator.HasActiveConfiguration() && has_selected_configuration; - // Mode states - this->UpdateUI_Status(); - // ui->tree_layers_paths->blockSignals(true); - - // Update configurations - // ui->layout_layers_buttons->setEnabled(ui->radio_vulkan_configurator->isChecked() && !environment.mode_disable_layers); - /* - ui->configuration_tree->setEnabled(enable_layer_ui); - ui->configuration_tree->clear(); - for (std::size_t i = 0, n = configurator.configurations.available_configurations.size(); i < n; ++i) { - Configuration *configuration = &configurator.configurations.available_configurations[i]; - - ui->comboBox_configurations->addItem(configuration->key.c_str()); - - if (configuration->key == selected_contiguration_name) { - ui->comboBox_configurations->setCurrentIndex(static_cast(i)); - } - } - */ - /* - ui->tree_configurations->setEnabled(ui->radio_vulkan_configurator->isChecked() && !environment.mode_disable_layers); - ui->tree_configurations->setCurrentItem(nullptr); - ui->tree_configurations->setSelectionMode(ui->radio_vulkan_configurator->isChecked() ? QAbstractItemView::SingleSelection - : QAbstractItemView::NoSelection); - - for (int i = 0, n = ui->tree_configurations->topLevelItemCount(); i < n; ++i) { - ConfigurationListItem *item = dynamic_cast(ui->tree_configurations->topLevelItem(i)); - - assert(item); - assert(!item->configuration_name.empty()); - - Configuration *configuration = - FindByKey(configurator.configurations.available_configurations, item->configuration_name.c_str()); - if (configuration == nullptr) continue; - - item->setText(1, item->configuration_name.c_str()); - item->setToolTip(1, configuration->description.c_str()); - item->radio_button->setToolTip(configuration->description.c_str()); - - if (item->configuration_name == active_contiguration_name) { - ui->tree_configurations->setCurrentItem(item); - item->radio_button->setChecked(true); - } else { - item->radio_button->setChecked(false); - } - } - */ - - // Update configurations - ui->configurations_tree->setCurrentItem(nullptr); - - for (int i = 0, n = ui->configurations_tree->topLevelItemCount(); i < n; ++i) { - ConfigurationListItem *item = dynamic_cast(ui->configurations_tree->topLevelItem(i)); - assert(item); - assert(!item->configuration_name.empty()); - - Configuration *configuration = configurator.configurations.FindConfiguration(item->configuration_name); - if (configuration == nullptr) { - continue; - } - - item->radio_button->setToolTip(configuration->description.c_str()); - item->radio_button->blockSignals(true); - - if (item->configuration_name == selected_contiguration_name) { - item->radio_button->setChecked(true); - ui->configurations_tree->setCurrentItem(item); - ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); - } else { - // item->radio_button->setChecked(false); - } - - item->radio_button->blockSignals(false); - } - - // ui->tree_layers_paths->setEnabled(enable_layer_ui); - ui->tree_layers_paths->clear(); - /* - std::vector layer_paths = configurator.layers.BuildPathList(); - for (std::size_t path_index = 0, count = layer_paths.size(); path_index < count; ++path_index) { - const std::string user_defined_path(layer_paths[path_index].RelativePath().c_str()); - - AddLayerPathItem(user_defined_path); - } - */ - ui->tree_layers_paths->update(); - - // Load Layers items - // ui->layers_tree->setEnabled(enable_layer_ui); - this->UpdateUI_LoaderMessages(); - this->UpdateUI_Layers(); - - // Handle application lists states - /* - ui->check_box_apply_list->setEnabled(!been_warned_about_old_loader && - ui->combo_box_mode->currentIndex() != LAYERS_MODE_BY_APPLICATIONS); - ui->check_box_apply_list->setChecked(!been_warned_about_old_loader && environment.GetUseApplicationList()); - ui->push_button_applications->setEnabled(!been_warned_about_old_loader && - ui->combo_box_mode->currentIndex() != LAYERS_MODE_BY_APPLICATIONS); - */ - //_launcher_apps_combo->blockSignals(true); - //_launcher_apps_combo->clear(); - /* - if (applications.empty()) { - _launcher_executable->setText(""); - _launcher_arguments->setText(""); - _launcher_working->setText(""); - _launcher_log_file_edit->setText(""); - } else { - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - _launcher_apps_combo->addItem(applications[i].app_name.c_str()); - } - _launcher_apps_combo->setCurrentIndex(environment.GetActiveApplicationIndex()); - - const Application &application = environment.GetActiveApplication(); - _launcher_executable->setText(application.executable_path.c_str()); - _launcher_arguments->setText(application.arguments.c_str()); - _launcher_working->setText(application.working_folder.c_str()); - _launcher_log_file_edit->setText(ReplaceBuiltInVariable(application.log_file.c_str()).c_str()); - } - */ - //_launcher_apps_combo->blockSignals(false); - - // Handle persistent states - /* - ui->tree_layers_paths->setEnabled(!environment.mode_disable_layers); - ui->tree_layers_list->setEnabled(!environment.mode_disable_layers); - ui->push_button_new->setEnabled(!environment.mode_disable_layers); - ui->push_button_edit->setEnabled(!environment.mode_disable_layers); - ui->push_button_duplicate->setEnabled(!environment.mode_disable_layers); - ui->push_button_remove->setEnabled(!environment.mode_disable_layers); - */ - - // Launcher states const bool has_application_list = !environment.GetApplications().empty(); - // ui->push_button_launcher->setEnabled(ui->check_box_apply_list->isChecked()); ui->push_button_launcher->setText(_launch_application ? "Terminate" : "Launch"); ui->check_box_clear_on_launch->setChecked(environment.launcher_clear_on_launch); - // ui->launcher_loader_debug->setCurrentIndex(environment.GetLoaderMessage()); - // ui->settings_tree->setEnabled(environment.GetMode() == LAYERS_MODE_CONTROLLED_BY_CONFIGURATOR && has_selected_configuration); - if (has_selected_configuration) { - this->_settings_tree_manager.CreateGUI(ui->settings_tree); - } else { - this->_settings_tree_manager.CleanupGUI(); - } + // Mode states + this->UpdateUI_Status(); - ui->configurations_tree->blockSignals(false); + ui->configurations_list->blockSignals(false); this->blockSignals(false); --check_recurse; } -// Load or refresh the list of configuration. Any configuration that uses a layer that -// is not detected on the system is disabled. -void MainWindow::UpdateUI_Configurations() { - // There are lots of ways into this, and in none of them - // can we have an active editor running. - _settings_tree_manager.CleanupGUI(); - ui->configurations_tree->blockSignals(true); // No signals firing off while we do this - ui->configurations_tree->clear(); - ui->configurations_tree->header()->setSectionResizeMode(1, QHeaderView::Stretch); - - Configurator &configurator = Configurator::Get(); - - for (std::size_t i = 0, n = configurator.configurations.available_configurations.size(); i < n; ++i) { - const Configuration &configuration = configurator.configurations.available_configurations[i]; - - ConfigurationListItem *item = new ConfigurationListItem(configuration.key); - item->setText(1, item->configuration_name.c_str()); - item->setToolTip(1, configuration.description.c_str()); - item->setFlags(item->flags() | Qt::ItemIsEditable); - item->radio_button = new QRadioButton(); - item->radio_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - item->radio_button->setFixedSize(QSize(24, 24)); - item->radio_button->setToolTip(configuration.description.c_str()); - ui->configurations_tree->addTopLevelItem(item); - ui->configurations_tree->setItemWidget(item, 0, item->radio_button); - connect(item->radio_button, SIGNAL(toggled(bool)), this, SLOT(OnConfigurationItemClicked(bool))); - - const Configuration *active_configuration = configurator.GetActiveConfiguration(); - if (active_configuration != nullptr) { - if (active_configuration->key == configuration.key) { - item->radio_button->blockSignals(true); - item->radio_button->setChecked(true); - - ui->configurations_tree->setCurrentItem(item); - - item->radio_button->blockSignals(false); - } - } - } - - ui->configurations_tree->blockSignals(false); - ui->configurations_tree->setColumnWidth(0, 24); - ui->configurations_tree->setColumnWidth(2, 24); - ui->configurations_tree->setColumnWidth(3, 24); - ui->configurations_tree->setColumnWidth(4, 24); -} - -void MainWindow::UpdateUI_LoaderMessages() { - const Configurator &configurator = Configurator::Get(); - - const Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration != nullptr) { - ui->configuration_loader_errors_checkBox->blockSignals(true); - ui->configuration_loader_errors_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_ERROR)); - ui->configuration_loader_errors_checkBox->blockSignals(false); - ui->configuration_loader_warns_checkBox->blockSignals(true); - ui->configuration_loader_warns_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_WARN)); - ui->configuration_loader_warns_checkBox->blockSignals(false); - ui->configuration_loader_infos_checkBox->blockSignals(true); - ui->configuration_loader_infos_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_INFO)); - ui->configuration_loader_infos_checkBox->blockSignals(false); - ui->configuration_loader_debug_checkBox->blockSignals(true); - ui->configuration_loader_debug_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_DEBUG)); - ui->configuration_loader_debug_checkBox->blockSignals(false); - ui->configuration_loader_layers_checkBox->blockSignals(true); - ui->configuration_loader_layers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_LAYER)); - ui->configuration_loader_layers_checkBox->blockSignals(false); - ui->configuration_loader_drivers_checkBox->blockSignals(true); - ui->configuration_loader_drivers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_IMPLEM)); - ui->configuration_loader_drivers_checkBox->blockSignals(false); - } -} - -void MainWindow::UpdateUI_Layers() { - ui->layers_tree->clear(); - - Configurator &configurator = Configurator::Get(); - const std::string &selected_contiguration_name = configurator.environment.GetActiveConfigurationInfo().GetName(); - const bool has_selected_configuration = !selected_contiguration_name.empty(); - - if (has_selected_configuration) { - Configuration *configuration = configurator.configurations.FindConfiguration(selected_contiguration_name); - if (configuration != nullptr) { - for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { - Parameter ¶meter = configuration->parameters[i]; - - if (!configuration->view_advanced_layers) { - if (parameter.control == LAYER_CONTROL_AUTO) { - continue; - } - } - - this->AddLayerItem(parameter, configuration->view_advanced_layers); - } - resizeEvent(nullptr); - - ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); - - ui->layers_tree->update(); - } - } -} - -/// Okay, because we are using custom controls, some of -/// the signaling is not happening as expected. So, we cannot -/// always get an accurate answer to the currently selected -/// item, but we do often need to know what has been checked -/// when an event occurs. This unambigously answers that question. -ConfigurationListItem *MainWindow::GetCheckedItem() { - // Just go through all the top level items - for (int i = 0, n = ui->configurations_tree->topLevelItemCount(); i < n; ++i) { - ConfigurationListItem *item = dynamic_cast(ui->configurations_tree->topLevelItem(i)); - - if (item == nullptr) { - continue; - } - if (item->radio_button->isChecked()) { - return item; - } - } - - return nullptr; -} - void MainWindow::on_combo_box_mode_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); configurator.environment.GetActiveConfigurationInfo().SetMode(static_cast(index)); configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - const bool enabled_ui = index == LAYERS_CONTROLLED_BY_CONFIGURATOR; - - ui->configurations_tree->setEnabled(enabled_ui); - ui->group_box_settings->setEnabled(enabled_ui); - ui->group_box_layers->setEnabled(enabled_ui); + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); this->UpdateUI_Status(); this->UpdateUI(); @@ -810,9 +339,7 @@ void MainWindow::on_combo_box_applications_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); configurator.environment.SelectActiveApplication(index); - Application &application = configurator.environment.GetApplication(index); - ui->combo_box_applications->setToolTip(application.executable_path.AbsolutePath().c_str()); - ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); this->UpdateUI_Status(); this->UpdateUI(); @@ -820,57 +347,44 @@ void MainWindow::on_combo_box_applications_currentIndexChanged(int index) { void MainWindow::on_check_box_per_application_toggled(bool checked) { Configurator &configurator = Configurator::Get(); + configurator.environment.SetPerApplicationConfig(checked); + configurator.Override(OVERRIDE_AREA_ALL); - ui->combo_box_applications->setEnabled(configurator.environment.GetPerApplicationConfig()); - ui->combo_box_mode->setCurrentIndex(configurator.environment.GetActiveConfigurationInfo().GetMode()); + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); this->UpdateUI_Status(); this->UpdateUI(); } -void MainWindow::OnConfigurationLoaderMessageCheckBox_toggled(bool checked) { - (void)checked; - - Configurator &configurator = Configurator::Get(); - - Configuration *active_configuration = configurator.GetActiveConfiguration(); - if (active_configuration != nullptr) { - int loader_log_messages_bits = 0; - - loader_log_messages_bits |= ui->configuration_loader_errors_checkBox->isChecked() ? GetBit(LOG_ERROR) : 0; - loader_log_messages_bits |= ui->configuration_loader_warns_checkBox->isChecked() ? GetBit(LOG_WARN) : 0; - loader_log_messages_bits |= ui->configuration_loader_infos_checkBox->isChecked() ? GetBit(LOG_INFO) : 0; - loader_log_messages_bits |= ui->configuration_loader_debug_checkBox->isChecked() ? GetBit(LOG_DEBUG) : 0; - loader_log_messages_bits |= ui->configuration_loader_layers_checkBox->isChecked() ? GetBit(LOG_LAYER) : 0; - loader_log_messages_bits |= ui->configuration_loader_drivers_checkBox->isChecked() ? GetBit(LOG_IMPLEM) : 0; - - active_configuration->loader_log_messages_flags = loader_log_messages_bits; - } -} - void MainWindow::on_configuration_loader_errors_checkBox_toggled(bool checked) { - OnConfigurationLoaderMessageCheckBox_toggled(checked); + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnCheckedLoaderMessageTypes(checked); } void MainWindow::on_configuration_loader_warns_checkBox_toggled(bool checked) { - OnConfigurationLoaderMessageCheckBox_toggled(checked); + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnCheckedLoaderMessageTypes(checked); } void MainWindow::on_configuration_loader_infos_checkBox_toggled(bool checked) { - OnConfigurationLoaderMessageCheckBox_toggled(checked); + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnCheckedLoaderMessageTypes(checked); } void MainWindow::on_configuration_loader_debug_checkBox_toggled(bool checked) { - OnConfigurationLoaderMessageCheckBox_toggled(checked); + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnCheckedLoaderMessageTypes(checked); } void MainWindow::on_configuration_loader_layers_checkBox_toggled(bool checked) { - OnConfigurationLoaderMessageCheckBox_toggled(checked); + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnCheckedLoaderMessageTypes(checked); } void MainWindow::on_configuration_loader_drivers_checkBox_toggled(bool checked) { - OnConfigurationLoaderMessageCheckBox_toggled(checked); + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnCheckedLoaderMessageTypes(checked); } void MainWindow::on_check_box_clear_on_launch_clicked() { @@ -878,12 +392,14 @@ void MainWindow::on_check_box_clear_on_launch_clicked() { } void MainWindow::on_combo_box_layers_view_currentIndexChanged(int index) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + Configurator &configurator = Configurator::Get(); Configuration *configuration = configurator.GetActiveConfiguration(); configuration->view_advanced_layers = index != 0; - this->UpdateUI(); + this->tab_configurations->UpdateUI_Layers(UPDATE_REBUILD_UI); } void MainWindow::toolsResetToDefault(bool checked) { @@ -896,140 +412,10 @@ void MainWindow::toolsResetToDefault(bool checked) { Configurator &configurator = Configurator::Get(); configurator.ResetToDefault(true); - this->UpdateUI_Configurations(); + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); this->UpdateUI(); } -// Thist signal actually comes from the radio button -void MainWindow::OnConfigurationItemClicked(bool checked) { - (void)checked; - // Someone just got checked, they are now the current profile - // This pointer will only be valid if it's one of the elements with - // the radio button - ConfigurationListItem *configuration_item = GetCheckedItem(); - if (configuration_item == nullptr) { - return; - } - - this->_settings_tree_manager.CleanupGUI(); - - Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); - configurator.environment.selected_layer_name.clear(); - configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - - this->UpdateUI(); -} - -void MainWindow::OnConfigurationTreeClicked(QTreeWidgetItem *item, int column) { - (void)column; - - Configurator &configurator = Configurator::Get(); - - ConfigurationListItem *configuration_item = dynamic_cast(item); - if (configuration_item != nullptr) { - this->_settings_tree_manager.CleanupGUI(); - - configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); - configurator.environment.selected_layer_name.clear(); - configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - } - - this->UpdateUI(); -} - -/// An item has been changed. Check for edit of the items name (configuration name) -void MainWindow::OnConfigurationItemChanged(QTreeWidgetItem *item, int column) { - // This pointer will only be valid if it's one of the elements with - // the radio button - ConfigurationListItem *configuration_item = dynamic_cast(item); - if (configuration_item == nullptr) { - return; - } - - if (column == 1) { // configuration name - _settings_tree_manager.CleanupGUI(); - Configurator &configurator = Configurator::Get(); - - // We are renaming the file. Things can go wrong here... - // This is the name of the configuratin we are changing - // const std::string full_path = - // ConvertNativeSeparators(GetPath(BUILTIN_PATH_CONFIG_LAST) + "/" + configuration_item->configuration_name + ".json"); - - // This is the new name we want to use for the configuration - const std::string &new_name = configuration_item->text(1).toStdString(); - bool valid_new_name = true; - - if (new_name.empty()) { - valid_new_name = false; - Alert::ConfigurationNameEmpty(); - } else if (!IsPortableFilename(new_name)) { - valid_new_name = false; - Alert::ConfigurationNameInvalid(); - } - - Configuration *duplicate_configuration = configurator.configurations.FindConfiguration(new_name); - - if (duplicate_configuration != nullptr) { - valid_new_name = false; - Alert::ConfigurationRenamingFailed(); - } - - // Find existing configuration using it's old name - const std::string &old_name = configuration_item->configuration_name; - Configuration *configuration = configurator.configurations.FindConfiguration(old_name); - - if (valid_new_name) { - // Rename configuration ; Remove old configuration file ; change the name of the configuration - configurator.configurations.RemoveConfigurationFile(old_name); - configuration->key = configuration_item->configuration_name = new_name; - configurator.configurations.SaveAllConfigurations(); - configurator.environment.GetActiveConfigurationInfo().SetName(new_name); - configurator.environment.selected_layer_name.clear(); - - this->UpdateUI_Configurations(); - } else { - // If the configurate name is empty or the configuration name is taken, keep old configuration name - - ui->configurations_tree->blockSignals(true); - item->setText(1, old_name.c_str()); - ui->configurations_tree->blockSignals(false); - - configurator.environment.GetActiveConfigurationInfo().SetName(old_name); - configurator.environment.selected_layer_name.clear(); - } - - configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - - this->UpdateUI(); - } -} - -/// This gets called with keyboard selections and clicks that do not necessarily -/// result in a radio button change (but it may). So we need to do two checks here, one -/// for the radio button, and one to change the editor/information at lower right. -void MainWindow::OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { - (void)previous; - - // This pointer will only be valid if it's one of the elements with - // the radio button - ConfigurationListItem *configuration_item = dynamic_cast(current); - if (configuration_item == nullptr) { - return; - } - configuration_item->radio_button->setChecked(true); - - Configurator &configurator = Configurator::Get(); - if (configurator.environment.GetActiveConfigurationInfo().GetName() != configuration_item->configuration_name) { - this->_settings_tree_manager.CleanupGUI(); - - configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); - - configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - this->UpdateUI(); - } -} - void MainWindow::StartTool(Tool tool) { Configurator &configurator = Configurator::Get(); @@ -1054,50 +440,42 @@ void MainWindow::StartTool(Tool tool) { /// Create the VulkanInfo dialog if it doesn't already exits & show it. void MainWindow::toolsVulkanInfo(bool checked) { (void)checked; - this->StartTool(TOOL_VULKAN_INFO); } /// Create the VulkanTools dialog if it doesn't already exist & show it. void MainWindow::toolsVulkanInstallation(bool checked) { (void)checked; - this->StartTool(TOOL_VULKAN_INSTALL); } void MainWindow::OnHelpFindLayers(bool checked) { (void)checked; - ShowDoc(DOC_FIND_LAYERS); } void MainWindow::OnHelpReadme(bool checked) { (void)checked; - ShowDoc(DOC_VKCONFIG_README); } void MainWindow::OnHelpChangelog(bool checked) { (void)checked; - ShowDoc(DOC_VKCONFIG_CHANGELOG); } void MainWindow::OnHelpVulkanSpec(bool checked) { (void)checked; - ShowDoc(DOC_VULKAN_SPEC); } void MainWindow::OnHelpLayerSpec(bool checked) { (void)checked; - ShowDoc(DOC_VULKAN_LAYERS); } void MainWindow::OnHelpGPUInfo(bool checked) { (void)checked; - ShowDoc(DOC_GPU_INFO); } @@ -1145,31 +523,15 @@ void MainWindow::closeEvent(QCloseEvent *event) { ResetLaunchApplication(); } - _settings_tree_manager.CleanupGUI(); - - this->SaveUIGeometry(); - - QMainWindow::closeEvent(event); -} + this->tabs[this->ui->tab_widget->currentIndex()]->CleanUI(); -void MainWindow::LoadUIGeometry() { - QSettings settings("LunarG", VKCONFIG_SHORT_NAME); - this->restoreGeometry(settings.value("mainwindow/geometry").toByteArray()); - this->restoreState(settings.value("mainwindow/state").toByteArray()); - this->ui->splitter_main->restoreState(settings.value("mainwindow/splitter_main_state").toByteArray()); - this->ui->splitter_configurations->restoreState(settings.value("mainwindow/splitter_configurations_state").toByteArray()); - this->ui->splitter_settings->restoreState(settings.value("mainwindow/splitter_settings_state").toByteArray()); -} - -void MainWindow::SaveUIGeometry() { QSettings settings("LunarG", VKCONFIG_SHORT_NAME); settings.setValue("mainwindow/geometry", this->saveGeometry()); settings.setValue("mainwindow/state", this->saveState()); - settings.setValue("mainwindow/splitter_main_state", ui->splitter_main->saveState()); - settings.setValue("mainwindow/splitter_configurations_state", ui->splitter_configurations->saveState()); - settings.setValue("mainwindow/splitter_settings_state", ui->splitter_settings->saveState()); -} + QMainWindow::closeEvent(event); +} +/* /// Resizing needs a little help. Yes please, there has to be /// a better way of doing this. void MainWindow::resizeEvent(QResizeEvent *event) { @@ -1177,477 +539,36 @@ void MainWindow::resizeEvent(QResizeEvent *event) { event->accept(); } - const QFontMetrics fm = ui->layers_tree->fontMetrics(); + const QFontMetrics fm = ui->layers_list->fontMetrics(); const int combo_width = (fm.size(Qt::TextSingleLine, "Auto").width() * 1.6); - const int width = ui->layers_tree->width() - combo_width; + const int width = ui->layers_list->width() - combo_width; // ui->tree_layers_list->setColumnWidth(0, width); } - +*/ void MainWindow::showEvent(QShowEvent *event) { (void)event; - UpdateUI(); + this->UpdateUI(); event->accept(); } -void MainWindow::OnContextMenuNewClicked(ConfigurationListItem *item) { - Configurator &configurator = Configurator::Get(); - - Configuration &new_configuration = - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); - - configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); - configurator.Override(OVERRIDE_AREA_ALL); - - this->UpdateUI_Configurations(); -} - -void MainWindow::OnContextMenuImportClicked(ConfigurationListItem *item) { - (void)item; // We don't need this - - Configurator &configurator = Configurator::Get(); - - const Path &path_import = configurator.environment.path_import; - const std::string selected_path = QFileDialog::getOpenFileName(this, "Import Layers Configuration File", - path_import.AbsolutePath().c_str(), "JSON configuration(*.json)") - .toStdString(); - - if (selected_path.empty()) { - return; - } - - configurator.environment.path_import = selected_path; - std::string imported_configuration = - configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, selected_path); - - configurator.environment.GetActiveConfigurationInfo().SetName(imported_configuration); - configurator.Override(OVERRIDE_AREA_ALL); - - this->UpdateUI_Configurations(); -} - -void MainWindow::OnContextMenuRenameClicked(ConfigurationListItem *item) { - assert(item); - - ui->configurations_tree->editItem(item, 1); -} - -void MainWindow::OnContextMenuDuplicateClicked(ConfigurationListItem *item) { - assert(item); - assert(!item->configuration_name.empty()); - - Configurator &configurator = Configurator::Get(); - const Configuration &duplicated_configuration = - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, item->configuration_name, true); - - item->configuration_name = duplicated_configuration.key; - - configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); - configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - - this->UpdateUI_Configurations(); -} - -void MainWindow::OnContextMenuDeleteClicked(ConfigurationListItem *item) { - assert(item); - assert(!item->configuration_name.empty()); - - // Let make sure... - QMessageBox alert; - alert.setWindowTitle(format("Removing *%s* configuration...", item->configuration_name.c_str()).c_str()); - alert.setText(format("Are you sure you want to remove the *%s* configuration?", item->configuration_name.c_str()).c_str()); - alert.setInformativeText("All the data from this configuration will be lost."); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setIcon(QMessageBox::Warning); - if (alert.exec() == QMessageBox::No) { - return; - } - - Configurator &configurator = Configurator::Get(); - configurator.configurations.RemoveConfiguration(configurator.layers.selected_layers, item->configuration_name); - configurator.environment.GetActiveConfigurationInfo().SetName(""); - - this->UpdateUI_Configurations(); - this->UpdateUI_LoaderMessages(); - this->UpdateUI_Layers(); - this->UpdateUI_Status(); -} - -void MainWindow::OnContextMenuResetClicked(ConfigurationListItem *item) { - assert(item); - assert(!item->configuration_name.empty()); - - Configurator &configurator = Configurator::Get(); - Configuration *configuration = - FindByKey(configurator.configurations.available_configurations, item->configuration_name.c_str()); - assert(configuration != nullptr); - - QMessageBox alert; - alert.setWindowTitle(format("Resetting *%s* configuration...", configuration->key.c_str()).c_str()); - alert.setText(format("Are you sure you want to reset the *%s* configuration?", configuration->key.c_str()).c_str()); - if (configuration->IsBuiltIn()) - alert.setInformativeText( - format("The configuration layers and settings will be restored to default built-in *%s* configuration.", - configuration->key.c_str()) - .c_str()); - else if (configurator.configurations.HasFile(*configuration)) - alert.setInformativeText( - format("The configuration layers and settings will be reloaded using the *%s* saved file from previous %s run.", - configuration->key.c_str(), VKCONFIG_NAME) - .c_str()); - else - alert.setInformativeText("The configuration layers and settings will be reset to zero."); - alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - alert.setDefaultButton(QMessageBox::Yes); - alert.setIcon(QMessageBox::Warning); - if (alert.exec() == QMessageBox::No) { - return; - } - - configuration->Reset(configurator.layers.selected_layers); - - this->UpdateUI_Configurations(); -} - -void MainWindow::OnContextMenuReloadClicked(ConfigurationListItem *item) { - assert(item); - assert(!item->configuration_name.empty()); - - // TODO -} - -void MainWindow::OnContextMenuExportConfigsClicked(ConfigurationListItem *item) { - assert(item); - - Configurator &configurator = Configurator::Get(); - - const Path &path_export = configurator.environment.path_export; - const std::string &selected_path = - QFileDialog::getSaveFileName(this, "Export Layers Configuration File", path_export.AbsolutePath().c_str(), - "JSON configuration(*.json)") - .toStdString(); - - if (selected_path.empty()) { - return; - } - - configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, selected_path, item->configuration_name); -} - -void MainWindow::OnContextMenuExportSettingsClicked(ConfigurationListItem *item) { - assert(item); - - Configurator &configurator = Configurator::Get(); - // TODO -} - -void MainWindow::editorExpanded(QTreeWidgetItem *item) { - (void)item; - ui->settings_tree->resizeColumnToContents(0); -} - -void MainWindow::OnConfigurationItemExpanded(QTreeWidgetItem *item) { - (void)item; - ui->settings_tree->resizeColumnToContents(0); - ui->settings_tree->resizeColumnToContents(1); -} - -void MainWindow::OnLayerCurrentRowChanged(int currentRow) { - this->_settings_tree_manager.CleanupGUI(); - - if (currentRow != -1) { - QWidget *widget = ui->layers_tree->itemWidget(ui->layers_tree->item(currentRow)); - const std::string &layer_string = static_cast(widget)->text().toStdString(); - - Configurator &configurator = Configurator::Get(); - configurator.environment.selected_layer_name = ExtractLayerName(configurator.layers, layer_string); - } - - this->_settings_tree_manager.CreateGUI(ui->settings_tree); -} - -void MainWindow::OnSettingsTreeClicked(QTreeWidgetItem *item, int column) { - (void)column; - (void)item; - - Configurator &configurator = Configurator::Get(); - configurator.Override(OVERRIDE_AREA_LAYERS_SETTINGS_BIT); -} - -void MainWindow::SetupLauncherTree() { - const Configurator &configurator = Configurator::Get(); - - const std::vector &applications = configurator.environment.GetApplications(); - ui->application_list->clear(); - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - QListWidgetItem *application_item = new QListWidgetItem(); - application_item->setText(applications[i].executable_path.RelativePath().c_str()); - application_item->setToolTip(applications[i].executable_path.AbsolutePath().c_str()); - ui->application_list->addItem(application_item); - } - - const std::vector &configurations = configurator.configurations.available_configurations; - ui->application_configuration_comboBox->clear(); - for (std::size_t i = 0, n = configurations.size(); i < n; ++i) { - ui->application_configuration_comboBox->addItem(configurations[i].key.c_str()); - } - - /* - // App Name - QTreeWidgetItem *launcher_parent = new QTreeWidgetItem(); - launcher_parent->setText(0, "Application"); - ui->application_list->addTopLevelItem(launcher_parent); - - _launcher_apps_combo = new QComboBox(); - _launcher_apps_combo->setFocusPolicy(Qt::StrongFocus); - _launcher_apps_combo->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_apps_combo->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->application_list->setItemWidget(launcher_parent, 1, _launcher_apps_combo); - - _launcher_apps_browse_button = new QPushButton(); - _launcher_apps_browse_button->setText("..."); - _launcher_apps_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_apps_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_apps_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_apps_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_parent, 2, _launcher_apps_browse_button); - connect(_launcher_apps_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(launchItemChanged(int))); - connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); - - // Executable - QTreeWidgetItem *launcher_executable_item = new QTreeWidgetItem(); - launcher_executable_item->setText(0, "Executable"); - launcher_parent->addChild(launcher_executable_item); - - _launcher_executable = new QLineEdit(); - _launcher_executable->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_executable->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->application_list->setItemWidget(launcher_executable_item, 1, _launcher_executable); - _launcher_executable->setReadOnly(false); - - _launcher_executable_browse_button = new QPushButton(); - _launcher_executable_browse_button->setText("..."); - _launcher_executable_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_executable_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_executable_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_executable_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_executable_item, 2, _launcher_executable_browse_button); - connect(_launcher_executable, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeExecutable(const QString &))); - connect(_launcher_executable_browse_button, SIGNAL(clicked()), this, SLOT(launchSetExecutable())); - - // Working folder - QTreeWidgetItem *launcher_folder_item = new QTreeWidgetItem(); - launcher_folder_item->setText(0, "Working Directory"); - launcher_parent->addChild(launcher_folder_item); - - _launcher_working = new QLineEdit(); - _launcher_working->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_working->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_folder_item, 1, _launcher_working); - _launcher_working->setReadOnly(false); - - _launcher_working_browse_button = new QPushButton(); - _launcher_working_browse_button->setText("..."); - _launcher_working_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_working_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_working_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_working_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_folder_item, 2, _launcher_working_browse_button); - connect(_launcher_working, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeWorkingFolder(const QString &))); - connect(_launcher_working_browse_button, SIGNAL(clicked()), this, SLOT(launchSetWorkingFolder())); - - // Command line arguments - QTreeWidgetItem *launcher_arguments_item = new QTreeWidgetItem(); - launcher_arguments_item->setText(0, "Command-line Arguments"); - launcher_parent->addChild(launcher_arguments_item); - - _launcher_arguments = new QLineEdit(); - _launcher_arguments->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_arguments->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_arguments_item, 1, _launcher_arguments); - connect(_launcher_arguments, SIGNAL(textEdited(const QString &)), this, SLOT(launchArgsEdited(const QString &))); - - // Log file - QTreeWidgetItem *launcher_log_file_item = new QTreeWidgetItem(); - launcher_log_file_item->setText(0, "Output Log"); - launcher_parent->addChild(launcher_log_file_item); - - _launcher_log_file_edit = new QLineEdit(); - _launcher_log_file_edit->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_log_file_edit->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_log_file_item, 1, _launcher_log_file_edit); - connect(_launcher_log_file_edit, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeLogFile(const QString &))); - - _launcher_log_file_browse_button = new QPushButton(); - _launcher_log_file_browse_button->setText("..."); - _launcher_log_file_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_log_file_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - ui->launcher_tree->setItemWidget(launcher_log_file_item, 2, _launcher_log_file_browse_button); - connect(_launcher_log_file_browse_button, SIGNAL(clicked()), this, SLOT(launchSetLogFile())); - - // Launcher tree - ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - - ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); - ui->launcher_tree->setColumnWidth( - 1, ui->launcher_tree->rect().width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); - ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); - - ui->launcher_tree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->launcher_tree->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - */ -} - -/* -// Expanding the tree also grows the tree to match -void MainWindow::launchItemExpanded(QTreeWidgetItem *item) { - (void)item; - ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); -} - -// Collapsing the tree also shrinks the tree to match and show only the first line -void MainWindow::launchItemCollapsed(QTreeWidgetItem *item) { - (void)item; - ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT + 6); - ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT + 6); -} -*/ - -/* -void MainWindow::OnLauncherLoaderMessageChanged(int level) { - Configurator &configurator = Configurator::Get(); - - // configurator.environment.SetLoaderMessage(static_cast(level)); - // configurator.environment.SetLoaderMessageFlags(GetBit(static_cast(level))); - - if (ui->check_box_clear_on_launch->isChecked()) { - this->UpdateUI(); - } -} - -void MainWindow::launchSetExecutable() { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); - - Configurator &configurator = Configurator::Get(); - Application &application = configurator.environment.GetApplication(current_application_index); - - //const Path exe = configurator.path.SelectPath(this, PATH_EXECUTABLE, application.executable_path); - - //// The user has cancel the operation - //if (exe.Empty()) { - // return; - //} - - //application.executable_path = exe; - - _launcher_executable->setText(application.executable_path.RelativePath().c_str()); -} -*/ -/* -void MainWindow::launchSetLogFile() { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); - - Configurator &configurator = Configurator::Get(); - Application &application = configurator.environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); - // TODO - //const Path &path = configurator.path.SelectPath(this, PATH_LAUNCHER_LOG_FILE, options.log_file); - - //// The user has cancel the operation - //if (path.Empty()) { - // return; - //} - - //options.log_file = path; - - _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); -} -*/ -/* -void MainWindow::launchSetWorkingFolder() { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); - - Configurator &configurator = Configurator::Get(); - Application &application = configurator.environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); - - // TODO - //const Path path = configurator.path.SelectPath(this, PATH_WORKING_DIR, options.working_folder); - - //// The user has cancel the operation - //if (path.Empty()) { - // return; - //} - - //options.working_folder = path; - - _launcher_working->setText(options.working_folder.RelativePath().c_str()); -} -*/ - -/* -// Log file path edited manually. -void MainWindow::launchChangeLogFile(const QString &log_file) { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); - - Application &application = Configurator::Get().environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); - options.log_file = log_file.toStdString(); -} - -void MainWindow::launchChangeExecutable(const QString &exe) { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); - - Application &application = Configurator::Get().environment.GetApplication(current_application_index); - application.executable_path = exe.toStdString(); -} - -void MainWindow::launchChangeWorkingFolder(const QString &working_folder) { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); - - Application &application = Configurator::Get().environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); - options.working_folder = working_folder.toStdString(); +/// An item has been changed. Check for edit of the items name (configuration name) +void MainWindow::on_configurations_list_itemChanged(QListWidgetItem *item) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnRenameConfiguration(item); } -// Launch app change -void MainWindow::launchItemChanged(int application_index) { - if (application_index < 0) return; - - Environment &environment = Configurator::Get().environment; - - environment.SelectActiveApplication(application_index); - - Application &application = environment.GetApplication(application_index); - ApplicationOptions &options = application.GetActiveOptions(); - - _launcher_executable->setText(application.executable_path.RelativePath().c_str()); - _launcher_working->setText(options.working_folder.RelativePath().c_str()); - _launcher_arguments->setText(Merge(options.arguments, " ").c_str()); - _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); +void MainWindow::on_configurations_list_currentRowChanged(int currentRow) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnSelectConfiguration(currentRow); } -/// New command line arguments. Update them. -void MainWindow::launchArgsEdited(const QString &arguments) { - int application_index = _launcher_apps_combo->currentIndex(); - if (application_index < 0) return; - - Application &application = Configurator::Get().environment.GetApplication(application_index); - ApplicationOptions &options = application.GetActiveOptions(); - options.arguments = SplitSpace(arguments.toStdString()); +void MainWindow::on_layers_list_currentRowChanged(int currentRow) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->tab_configurations->OnSelectLayer(currentRow); } -*/ // Clear the browser window void MainWindow::on_push_button_clear_log_clicked() { @@ -1656,179 +577,8 @@ void MainWindow::on_push_button_clear_log_clicked() { ui->push_button_clear_log->setEnabled(false); } -static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { - if (item == nullptr) { - return nullptr; - } - - TreeWidgetItemParameter *item_parameter = static_cast(item); - - const std::string &layer_string = item_parameter->layer_name; - if (!layer_string.empty()) { - Configurator &configurator = Configurator::Get(); - - const std::string &layer_key = ExtractLayerName(configurator.layers, layer_string); - return configurator.layers.Find(layer_key); - } - - return nullptr; -} - bool MainWindow::eventFilter(QObject *target, QEvent *event) { - QEvent::Type event_type = event->type(); - - if (event_type == QEvent::Wheel) { - return true; - } - - if (event_type == QEvent::ChildRemoved) { - // Layers were reordered, we need to update the configuration - Configurator::Get().Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - return true; - } - - // Launch tree does some fancy resizing and since it's down in - // layouts and splitters, we can't just rely on the resize method - // of this window. Any resize coming through needs to trigger this - // or we get drawing artifacts on macOS. - /* - if (event->type() == QEvent::Resize) { - const QRect rect = ui->launcher_tree->rect(); - ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); - ui->launcher_tree->setColumnWidth(1, rect.width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); - ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); - return false; - } - */ - - if (target == ui->configurations_tree) { - QContextMenuEvent *right_click = dynamic_cast(event); - if (right_click) { - ConfigurationListItem *item = static_cast(ui->configurations_tree->itemAt(right_click->pos())); - - std::string name; - - if (item != nullptr) { - name = item->configuration_name; - } - - QMenu menu(ui->configurations_tree); - QFont subtitle_font = menu.font(); - subtitle_font.setBold(true); - - QAction *action_new = new QAction("Create a new Configuration", nullptr); - action_new->setEnabled(true); - menu.addAction(action_new); - - QAction *action_import = new QAction("Import a new Configuration...", nullptr); - action_import->setEnabled(true); - menu.addAction(action_import); - - menu.addSeparator(); - - QAction *action_rename = new QAction("Rename the Configuration", nullptr); - action_rename->setEnabled(item != nullptr); - menu.addAction(action_rename); - - QAction *action_duplicate = new QAction("Duplicate the Configuration", nullptr); - action_duplicate->setEnabled(item != nullptr); - menu.addAction(action_duplicate); - - QAction *action_delete = new QAction("Delete the Configuration", nullptr); - action_delete->setEnabled(item != nullptr); - menu.addAction(action_delete); - - menu.addSeparator(); - - QAction *action_reset = new QAction("Reset the Configuration", nullptr); - action_reset->setEnabled(item != nullptr); - action_reset->setToolTip("Reset the Configuration using the built-in configuration"); - menu.addAction(action_reset); - - QAction *action_reload = new QAction("Reload the Configuration", nullptr); - action_reload->setEnabled(item != nullptr); - action_reset->setToolTip("Reload the Configuration, discarding all changes from this session"); - menu.addAction(action_reload); - - menu.addSeparator(); - - QAction *action_export_config = new QAction("Export the Configuration...", nullptr); - action_export_config->setEnabled(item != nullptr); - menu.addAction(action_export_config); - - QAction *action_export_settings = new QAction("Export the Layers Settings...", nullptr); - action_export_settings->setEnabled(item != nullptr); - menu.addAction(action_export_settings); - - QPoint point(right_click->globalX(), right_click->globalY()); - QAction *action = menu.exec(point); - - if (action == action_new) { - this->OnContextMenuNewClicked(item); - } else if (action == action_import) { - this->OnContextMenuImportClicked(item); - } else if (action == action_rename) { - this->OnContextMenuRenameClicked(item); - } else if (action == action_duplicate) { - this->OnContextMenuDuplicateClicked(item); - } else if (action == action_delete) { - this->OnContextMenuDeleteClicked(item); - } else if (action == action_reset) { - this->OnContextMenuResetClicked(item); - } else if (action == action_reload) { - this->OnContextMenuReloadClicked(item); - } else if (action == action_export_config) { - this->OnContextMenuExportConfigsClicked(item); - } else if (action == action_export_settings) { - this->OnContextMenuExportSettingsClicked(item); - } - } - } else if (target == ui->layers_tree) { - QContextMenuEvent *right_click = dynamic_cast(event); - if (right_click) { - QListWidgetItem *item = ui->layers_tree->itemAt(right_click->pos()); - - const Layer *layer = GetLayer(ui->layers_tree, item); - - QMenu menu(ui->layers_tree); - - QAction *action_description = new QAction("Open the Layer Description...", nullptr); - action_description->setEnabled(item != nullptr); - menu.addAction(action_description); - - QAction *export_html_action = new QAction("Open the Layer HTML Documentation...", nullptr); - export_html_action->setEnabled(item != nullptr); - menu.addAction(export_html_action); - - QAction *export_markdown_action = new QAction("Open the Layer Markdown Documentation...", nullptr); - export_markdown_action->setEnabled(item != nullptr); - menu.addAction(export_markdown_action); - - QAction *visit_layer_website_action = new QAction("Visit the Layer Website...", nullptr); - visit_layer_website_action->setEnabled(layer != nullptr ? !layer->url.empty() : false); - menu.addAction(visit_layer_website_action); - - QPoint point(right_click->globalX(), right_click->globalY()); - QAction *action = menu.exec(point); - - if (action == action_description) { - Alert::LayerProperties(layer); - } else if (action == visit_layer_website_action) { - QDesktopServices::openUrl(QUrl(layer->url.c_str())); - } else if (action == export_html_action) { - const std::string path = format("%s/%s.html", AbsolutePath(Path::APPDATA).c_str(), layer->key.c_str()); - ExportHtmlDoc(*layer, path); - QDesktopServices::openUrl(QUrl(("file:///" + path).c_str())); - } else if (action == export_markdown_action) { - const std::string path = format("%s/%s.md", AbsolutePath(Path::APPDATA).c_str(), layer->key.c_str()); - ExportMarkdownDoc(*layer, path); - QDesktopServices::openUrl(QUrl(("file:///" + path).c_str())); - } - } - } - - // Pass it on - return false; + return this->tabs[this->ui->tab_widget->currentIndex()]->EventFilter(target, event); } void MainWindow::ResetLaunchApplication() { @@ -1849,22 +599,7 @@ QStringList MainWindow::BuildEnvVariables() const { return env; } -void MainWindow::on_tab_widget_currentChanged(int index) { - switch (index) { - case TAB_DIAGNOSTIC: { - } break; - case TAB_APPLICATIONS: { - } break; - case TAB_LAYERS: { - } break; - case TAB_CONFIGURATIONS: { - } break; - case TAB_PREFERENCES: { - } break; - case TAB_HELP: { - } break; - } -} +void MainWindow::on_tab_widget_currentChanged(int index) { this->tabs[index]->UpdateUI(UPDATE_REBUILD_UI); } void MainWindow::on_push_button_launcher_clicked() { // Are we already monitoring a running app? If so, terminate it diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 3e8d188f68..772da0e472 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -21,8 +21,13 @@ #pragma once -#include "settings_tree.h" #include "configuration_layer_widget.h" +#include "tab_applications.h" +#include "tab_configurations.h" +#include "tab_diagnostics.h" +#include "tab_help.h" +#include "tab_layers.h" +#include "tab_preferences.h" #include "ui_mainwindow.h" @@ -38,19 +43,6 @@ #include #include -/// This just allows me to associate a specific profile definition -/// with a list widget item. -class ConfigurationListItem : public QTreeWidgetItem { - public: - ConfigurationListItem(const std::string &configuration_name) : configuration_name(configuration_name) {} - std::string configuration_name; - QRadioButton *radio_button; - - private: - ConfigurationListItem(const ConfigurationListItem &) = delete; - ConfigurationListItem &operator=(const ConfigurationListItem &) = delete; -}; - class LayerPathWidget : public QLabel { Q_OBJECT @@ -94,8 +86,12 @@ class TreeWidgetItemParameter : public QListWidgetItem { public: TreeWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } - QWidget *widget; std::string layer_name; + QWidget *widget; + + private: + TreeWidgetItemParameter(const TreeWidgetItemParameter &) = delete; + TreeWidgetItemParameter &operator=(const TreeWidgetItemParameter &) = delete; }; enum Tool { TOOL_VULKAN_INFO, TOOL_VULKAN_INSTALL }; @@ -110,16 +106,11 @@ class MainWindow : public QMainWindow { void UpdateUI(); private: - SettingsTreeManager _settings_tree_manager; - std::unique_ptr _launch_application; // Keeps track of the monitored app QFile _log_file; // Log file for layer output - void SetupLauncherTree(); - void closeEvent(QCloseEvent *event) override; void showEvent(QShowEvent *event) override; - void resizeEvent(QResizeEvent *event) override; bool eventFilter(QObject *target, QEvent *event) override; std::unique_ptr vk_info_dialog; @@ -127,8 +118,6 @@ class MainWindow : public QMainWindow { void Log(const std::string &log); - ConfigurationListItem *GetCheckedItem(); - QSystemTrayIcon *_tray_icon; QMenu *_tray_icon_menu; QAction *_tray_restore_action; @@ -137,18 +126,7 @@ class MainWindow : public QMainWindow { QAction *_tray_layers_disabled_by_configurator; QAction *_tray_quit_action; - void OnContextMenuNewClicked(ConfigurationListItem *item); - void OnContextMenuImportClicked(ConfigurationListItem *item); - void OnContextMenuRenameClicked(ConfigurationListItem *item); - void OnContextMenuDuplicateClicked(ConfigurationListItem *item); - void OnContextMenuDeleteClicked(ConfigurationListItem *item); - void OnContextMenuResetClicked(ConfigurationListItem *item); - void OnContextMenuReloadClicked(ConfigurationListItem *item); - void OnContextMenuExportConfigsClicked(ConfigurationListItem *item); - void OnContextMenuExportSettingsClicked(ConfigurationListItem *item); - void AddLayerPathItem(const std::string &layer_path); - void AddLayerItem(Parameter ¶meter, bool advanced_view); private slots: void trayActionRestore(); @@ -171,7 +149,6 @@ class MainWindow : public QMainWindow { void OnHelpLayerSpec(bool checked); void OnHelpGPUInfo(bool checked); - void editorExpanded(QTreeWidgetItem *item); /* void launchItemExpanded(QTreeWidgetItem *item); void launchItemCollapsed(QTreeWidgetItem *item); @@ -196,8 +173,6 @@ class MainWindow : public QMainWindow { void on_combo_box_layers_view_currentIndexChanged(int index); - void OnConfigurationLoaderMessageCheckBox_toggled(bool checked); - void on_configuration_loader_errors_checkBox_toggled(bool checked); void on_configuration_loader_warns_checkBox_toggled(bool checked); void on_configuration_loader_infos_checkBox_toggled(bool checked); @@ -205,17 +180,9 @@ class MainWindow : public QMainWindow { void on_configuration_loader_layers_checkBox_toggled(bool checked); void on_configuration_loader_drivers_checkBox_toggled(bool checked); - void OnConfigurationItemExpanded(QTreeWidgetItem *item); - void OnConfigurationItemClicked(bool checked); - void OnConfigurationTreeChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); - void OnConfigurationItemChanged(QTreeWidgetItem *item, int column); - void OnConfigurationTreeClicked(QTreeWidgetItem *item, int column); - - void OnLayerCurrentRowChanged(int currentRow); - - void OnSettingsTreeClicked(QTreeWidgetItem *item, int column); - - // void OnLauncherLoaderMessageChanged(int level); + void on_configurations_list_itemChanged(QListWidgetItem *item); + void on_configurations_list_currentRowChanged(int currentRow); + void on_layers_list_currentRowChanged(int currentRow); void standardOutputAvailable(); // stdout output is available void errorOutputAvailable(); // Layeroutput is available @@ -225,18 +192,19 @@ class MainWindow : public QMainWindow { MainWindow(const MainWindow &) = delete; MainWindow &operator=(const MainWindow &) = delete; - void LoadUIGeometry(); - void SaveUIGeometry(); - void InitTray(); void UpdateUI_Status(); - void UpdateUI_Configurations(); - void UpdateUI_LoaderMessages(); - void UpdateUI_Layers(); void ResetLaunchApplication(); void StartTool(Tool tool); QStringList BuildEnvVariables() const; - std::unique_ptr ui; + std::shared_ptr ui; + std::array, TAB_COUNT> tabs; + std::shared_ptr tab_diagnostic; + std::shared_ptr tab_applications; + std::shared_ptr tab_layers; + std::shared_ptr tab_configurations; + std::shared_ptr tab_preferences; + std::shared_ptr tab_help; }; diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index 913891f8cd..358e98c47f 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -621,6 +621,12 @@ + + + 0 + 0 + + Per-Application: @@ -672,13 +678,16 @@ 0 - + Arial 10 + + false + QFrame::Box @@ -697,46 +706,6 @@ false - - 5 - - - 5 - - - false - - - 20 - - - false - - - - 1 - - - - - 2 - - - - - 3 - - - - - 4 - - - - - 5 - - @@ -871,7 +840,7 @@ - + 0 diff --git a/vkconfig_gui/resourcefiles/config-invalid.png b/vkconfig_gui/resourcefiles/config-invalid.png new file mode 100644 index 0000000000000000000000000000000000000000..102dfd640ffe8b5e916014e78ecf5e4576532704 GIT binary patch literal 1885 zcmV-j2cr0iP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2J%TnK~#8N<(olh z990;{lhlULL}{VL9z66=p+bd<9=r-3BDPpc3m!Zuco0!gC~7s7NT~H9DvBOFRIngY zDV0_%c<`WL4~l|<1q*r*R1_jM){wP{|KIfcmf4wac4u~HH=E`Me`em>xAWfj&6_uG zzIijcva&L=o*A?4x~1D?KHBCUHzZ z{(Dl_$4x8DEGw~DdR6*YB7^O5X=_xz7jaB!R=O;afkWPqwnyd5D$Fb+aj!HlkwEl- z9Z}gjCAdW1k-SIXko{5FG72+0NjxTb1L*2|qH_I|V0`#QB7tV2a-9@r7D;eRd)q2R zbL2&32PH9MZ9$9;6H&P$g_)5A*ZZdu3A)|EsN8Bu?6o$L_);o8E`*s`3C_G5|D&`! zDz}=VP1ZJdLaCk*W@aV4+fza9BYa&F43O@G6H%G0!pyV;10Fkcv7tNjS&3cNRuYG! zGHHdGF2SwNNBg0<<~vC+CeUs)9hGr~nMg3``F(yaDl^Oyes{oz%~2Ut_$;7#Ju^I} zpQWdSYT?(tc`TadGh{k8j$vX`5x2;>wjPe{9^i@h$0O zJ4dv00H}RTn;(@zTXGK2A9$qwM&jA~HvLYJqL3m7VEn?u!r7^*DMsb4(J?OR821%9 zp@ajtHU1=py*YBgDQyl)FYC7>NoE_e4#04_ySno;I_nIiJ)>h?9v>e+9$gll8~|z~ zQ+5W$4^{q9l4-QW1Xa)@Ib1WZkXIFqS3_T_%XrY3aU;j%*p^k5*ClM4HXEB{gQ6bE zAr?nCsuG-i&b%dSXK88aIqI-vY0Q=j61HJuldJ=X;lW3?Ee#Fhny>TBXHieMi8{J* zf^eJM#)PH=)HQhEA%F=4A}hgY-|K)^2I`c+HbZdq9)D8Ee>G903NF^1znNpttAHrb#^frrr$#(q#eNPD&U1h6%G{5?fZ$K2jskS9g^$iX$R!4kL!@!IG1*SKlfL4 zz-b~mwm&ee&ePXYrE%MuF^--u0o{u)5yrCQz@Sd*wq#k_UIMvUQdx-M+3vvTvd-LW zH|+q{iWUELjD&>5SQ$knRD%YAkrbwx!{W5WOXU zX<4UYF1Ksx0rms8G(twa7OM<{)AI82^Ez99TUO6-<}rT5h7BKB zR#l#muqn6Ju-%Ih*5%!*-<$W$h-?pV)J=!!#R#v*2-fCajAX|E4oCq88A8asQ0NL9 z6ZSP4jTgJQMe-m1+ru^QJS$=R$*l2^>j5CIam&DKfY-ja{TxL-APv2N7~U$r90gwU z<&GCR0Q6@TA#&}UQ<;59WX}gLv%uGx8QWHG6D=ITgqK(#860=d6 zw8G4+1S>GvSxd|0PDN$13Ny13%nVt4=uQ~Ao-9a$g`+!G`pwyXng_)fs_!7h`Whq)MUvE?qbxPdl zNuZ7cUZgOyj0D}z7gFL3R%7+_^+p*{hr}92KLK?8!G18|63nr)pUm+5(9ch1(oSE! zPiE2*bjLOM(Ny8HKsRXaz2-iftJMLH9KqcJ1J>7vlM!+Tk(l-M>Fin}7ZF-tjEwvb Xd=9KK9MOWK00000NkvXXu0mjf2cvn` literal 0 HcmV?d00001 diff --git a/vkconfig_gui/resourcefiles/config-off.png b/vkconfig_gui/resourcefiles/config-off.png new file mode 100644 index 0000000000000000000000000000000000000000..e00718efca5e09df37879269595f78cfb20f19a5 GIT binary patch literal 1348 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 literal 0 HcmV?d00001 diff --git a/vkconfig_gui/resources.qrc b/vkconfig_gui/resources.qrc index f76bcea6a2..f28d38f02e 100644 --- a/vkconfig_gui/resources.qrc +++ b/vkconfig_gui/resources.qrc @@ -5,6 +5,9 @@ resourcefiles/qt_logo.png resourcefiles/vkconfig-off.png resourcefiles/vkconfig-on.png + resourcefiles/config-off.png + resourcefiles/config-on.png + resourcefiles/config-invalid.png diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 84e4cbaa68..fe389dc849 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -63,7 +63,9 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { this->tree = build_tree; Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration == nullptr || configurator.environment.selected_layer_name.empty()) { + if (configuration == nullptr) { + return; + } else if (configuration->selected_layer_name.empty()) { return; } @@ -89,7 +91,7 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { Parameter ¶meter = configuration->parameters[i]; - if (configurator.environment.selected_layer_name != parameter.key) { + if (configuration->selected_layer_name != parameter.key) { continue; } @@ -157,13 +159,13 @@ void SettingsTreeManager::CleanupGUI() { } Configurator &configurator = Configurator::Get(); - if (!configurator.environment.selected_layer_name.empty()) { - Configuration *configuration = configurator.GetActiveConfiguration(); - if (configuration != nullptr) { + Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + if (!configuration->selected_layer_name.empty()) { for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { Parameter ¶meter = configuration->parameters[i]; - if (parameter.key != configurator.environment.selected_layer_name) { + if (parameter.key != configuration->selected_layer_name) { continue; } @@ -192,7 +194,7 @@ void SettingsTreeManager::OnExpandedChanged(const QModelIndex &index) { for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { Parameter ¶meter = configuration->parameters[i]; - if (parameter.key != configurator.environment.selected_layer_name) { + if (parameter.key != configuration->selected_layer_name) { continue; } diff --git a/vkconfig_gui/tab.cpp b/vkconfig_gui/tab.cpp new file mode 100644 index 0000000000..2ab64f10dd --- /dev/null +++ b/vkconfig_gui/tab.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab.h" +#include "mainwindow.h" + +Tab::Tab(TabType type, MainWindow& window, std::shared_ptr ui) : type(type), window(window), ui(ui) {} + +Tab::~Tab() {} diff --git a/vkconfig_gui/tab.h b/vkconfig_gui/tab.h new file mode 100644 index 0000000000..cbadc50f0c --- /dev/null +++ b/vkconfig_gui/tab.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include + +#include "../vkconfig_core/type_tab.h" + +#include "ui_mainwindow.h" + +class MainWindow; + +enum UpdateUIMode { + UPDATE_REBUILD_UI = 0, + UPDATE_REFRESH_UI, +}; + +struct Tab { + Tab(TabType type, MainWindow& window, std::shared_ptr ui); + virtual ~Tab(); + + Tab(const Tab&) = delete; + Tab& operator=(const Tab&) = delete; + + const TabType type; + + virtual void UpdateUI(UpdateUIMode mode) = 0; + virtual void CleanUI() = 0; + virtual bool EventFilter(QObject* target, QEvent* event) = 0; + + protected: + std::shared_ptr ui; + MainWindow& window; +}; diff --git a/vkconfig_gui/tab_applications.cpp b/vkconfig_gui/tab_applications.cpp new file mode 100644 index 0000000000..cb9225de60 --- /dev/null +++ b/vkconfig_gui/tab_applications.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab_applications.h" +#include "mainwindow.h" + +#include "../vkconfig_core/configurator.h" + +/* + case PATH_EXECUTABLE: { + static const char* TABLE[] = { + "Applications (*.exe)", // PLATFORM_WINDOWS + "Applications (*)", // PLATFORM_LINUX + "Applications (*.app, *)", // PLATFORM_MACOS + "N/A" // PLATFORM_ANDROID + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT, + "The tranlation table size doesn't match the enum number of elements"); + + const std::string filter = TABLE[VKC_PLATFORM]; + const std::string selected_path = QFileDialog::getOpenFileName(parent, "Select a Vulkan Executable...", + suggested_path.AbsolutePath().c_str(), filter.c_str()) + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); + return GetFullPath(path, QFileInfo(selected_path.c_str()).fileName().toStdString()); + } + case PATH_WORKING_DIR: { + const std::string selected_path = + QFileDialog::getExistingDirectory(parent, "Set Working Folder To...", suggested_path.AbsolutePath().c_str()) + .toStdString(); + if (selected_path.empty()) // The user cancelled + return Path(""); + + SetPath(path, selected_path); + return Path(GetPath(path)); + } +*/ + +TabApplications::TabApplications(MainWindow &window, std::shared_ptr ui) : Tab(TAB_APPLICATIONS, window, ui) {} + +TabApplications::~TabApplications() {} + +void TabApplications::UpdateUI(UpdateUIMode mode) { + const Configurator &configurator = Configurator::Get(); + const Environment &environment = Configurator::Get().environment; + + const std::vector &applications = configurator.environment.GetApplications(); + ui->application_list->clear(); + for (std::size_t i = 0, n = applications.size(); i < n; ++i) { + QListWidgetItem *application_item = new QListWidgetItem(); + application_item->setText(applications[i].executable_path.RelativePath().c_str()); + application_item->setToolTip(applications[i].executable_path.AbsolutePath().c_str()); + ui->application_list->addItem(application_item); + } + + const std::vector &configurations = configurator.configurations.available_configurations; + ui->application_configuration_comboBox->clear(); + for (std::size_t i = 0, n = configurations.size(); i < n; ++i) { + ui->application_configuration_comboBox->addItem(configurations[i].key.c_str()); + } + + /* + // App Name + QTreeWidgetItem *launcher_parent = new QTreeWidgetItem(); + launcher_parent->setText(0, "Application"); + ui->application_list->addTopLevelItem(launcher_parent); + + _launcher_apps_combo = new QComboBox(); + _launcher_apps_combo->setFocusPolicy(Qt::StrongFocus); + _launcher_apps_combo->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_apps_combo->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->application_list->setItemWidget(launcher_parent, 1, _launcher_apps_combo); + + _launcher_apps_browse_button = new QPushButton(); + _launcher_apps_browse_button->setText("..."); + _launcher_apps_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_apps_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + _launcher_apps_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_apps_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_parent, 2, _launcher_apps_browse_button); + connect(_launcher_apps_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(launchItemChanged(int))); + connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); + + // Executable + QTreeWidgetItem *launcher_executable_item = new QTreeWidgetItem(); + launcher_executable_item->setText(0, "Executable"); + launcher_parent->addChild(launcher_executable_item); + + _launcher_executable = new QLineEdit(); + _launcher_executable->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_executable->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->application_list->setItemWidget(launcher_executable_item, 1, _launcher_executable); + _launcher_executable->setReadOnly(false); + + _launcher_executable_browse_button = new QPushButton(); + _launcher_executable_browse_button->setText("..."); + _launcher_executable_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_executable_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + _launcher_executable_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_executable_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_executable_item, 2, _launcher_executable_browse_button); + connect(_launcher_executable, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeExecutable(const QString &))); + connect(_launcher_executable_browse_button, SIGNAL(clicked()), this, SLOT(launchSetExecutable())); + + // Working folder + QTreeWidgetItem *launcher_folder_item = new QTreeWidgetItem(); + launcher_folder_item->setText(0, "Working Directory"); + launcher_parent->addChild(launcher_folder_item); + + _launcher_working = new QLineEdit(); + _launcher_working->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_working->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_folder_item, 1, _launcher_working); + _launcher_working->setReadOnly(false); + + _launcher_working_browse_button = new QPushButton(); + _launcher_working_browse_button->setText("..."); + _launcher_working_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_working_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + _launcher_working_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_working_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_folder_item, 2, _launcher_working_browse_button); + connect(_launcher_working, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeWorkingFolder(const QString &))); + connect(_launcher_working_browse_button, SIGNAL(clicked()), this, SLOT(launchSetWorkingFolder())); + + // Command line arguments + QTreeWidgetItem *launcher_arguments_item = new QTreeWidgetItem(); + launcher_arguments_item->setText(0, "Command-line Arguments"); + launcher_parent->addChild(launcher_arguments_item); + + _launcher_arguments = new QLineEdit(); + _launcher_arguments->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_arguments->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_arguments_item, 1, _launcher_arguments); + connect(_launcher_arguments, SIGNAL(textEdited(const QString &)), this, SLOT(launchArgsEdited(const QString &))); + + // Log file + QTreeWidgetItem *launcher_log_file_item = new QTreeWidgetItem(); + launcher_log_file_item->setText(0, "Output Log"); + launcher_parent->addChild(launcher_log_file_item); + + _launcher_log_file_edit = new QLineEdit(); + _launcher_log_file_edit->setMinimumHeight(LAUNCH_ROW_HEIGHT); + _launcher_log_file_edit->setMaximumHeight(LAUNCH_ROW_HEIGHT); + ui->launcher_tree->setItemWidget(launcher_log_file_item, 1, _launcher_log_file_edit); + connect(_launcher_log_file_edit, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeLogFile(const QString &))); + + _launcher_log_file_browse_button = new QPushButton(); + _launcher_log_file_browse_button->setText("..."); + _launcher_log_file_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + _launcher_log_file_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); + ui->launcher_tree->setItemWidget(launcher_log_file_item, 2, _launcher_log_file_browse_button); + connect(_launcher_log_file_browse_button, SIGNAL(clicked()), this, SLOT(launchSetLogFile())); + + // Launcher tree + ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); + ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); + + ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); + ui->launcher_tree->setColumnWidth( + 1, ui->launcher_tree->rect().width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); + ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); + + ui->launcher_tree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui->launcher_tree->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + */ +} + +void TabApplications::CleanUI() {} + +bool TabApplications::EventFilter(QObject *target, QEvent *event) { return false; } + +/* +// Expanding the tree also grows the tree to match +void MainWindow::launchItemExpanded(QTreeWidgetItem *item) { + (void)item; + ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); + ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); +} + +// Collapsing the tree also shrinks the tree to match and show only the first line +void MainWindow::launchItemCollapsed(QTreeWidgetItem *item) { + (void)item; + ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT + 6); + ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT + 6); +} +*/ + +/* +void MainWindow::OnLauncherLoaderMessageChanged(int level) { + Configurator &configurator = Configurator::Get(); + + // configurator.environment.SetLoaderMessage(static_cast(level)); + // configurator.environment.SetLoaderMessageFlags(GetBit(static_cast(level))); + + if (ui->check_box_clear_on_launch->isChecked()) { + this->UpdateUI(); + } +} + +void MainWindow::launchSetExecutable() { + int current_application_index = _launcher_apps_combo->currentIndex(); + assert(current_application_index >= 0); + + Configurator &configurator = Configurator::Get(); + Application &application = configurator.environment.GetApplication(current_application_index); + + //const Path exe = configurator.path.SelectPath(this, PATH_EXECUTABLE, application.executable_path); + + //// The user has cancel the operation + //if (exe.Empty()) { + // return; + //} + + //application.executable_path = exe; + + _launcher_executable->setText(application.executable_path.RelativePath().c_str()); +} +*/ +/* +void MainWindow::launchSetLogFile() { + int current_application_index = _launcher_apps_combo->currentIndex(); + assert(current_application_index >= 0); + + Configurator &configurator = Configurator::Get(); + Application &application = configurator.environment.GetApplication(current_application_index); + ApplicationOptions &options = application.GetActiveOptions(); + // TODO + //const Path &path = configurator.path.SelectPath(this, PATH_LAUNCHER_LOG_FILE, options.log_file); + + //// The user has cancel the operation + //if (path.Empty()) { + // return; + //} + + //options.log_file = path; + + _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); +} +*/ +/* +void MainWindow::launchSetWorkingFolder() { + int current_application_index = _launcher_apps_combo->currentIndex(); + assert(current_application_index >= 0); + + Configurator &configurator = Configurator::Get(); + Application &application = configurator.environment.GetApplication(current_application_index); + ApplicationOptions &options = application.GetActiveOptions(); + + // TODO + //const Path path = configurator.path.SelectPath(this, PATH_WORKING_DIR, options.working_folder); + + //// The user has cancel the operation + //if (path.Empty()) { + // return; + //} + + //options.working_folder = path; + + _launcher_working->setText(options.working_folder.RelativePath().c_str()); +} +*/ + +/* +// Log file path edited manually. +void MainWindow::launchChangeLogFile(const QString &log_file) { + int current_application_index = _launcher_apps_combo->currentIndex(); + assert(current_application_index >= 0); + + Application &application = Configurator::Get().environment.GetApplication(current_application_index); + ApplicationOptions &options = application.GetActiveOptions(); + options.log_file = log_file.toStdString(); +} + +void MainWindow::launchChangeExecutable(const QString &exe) { + int current_application_index = _launcher_apps_combo->currentIndex(); + assert(current_application_index >= 0); + + Application &application = Configurator::Get().environment.GetApplication(current_application_index); + application.executable_path = exe.toStdString(); +} + +void MainWindow::launchChangeWorkingFolder(const QString &working_folder) { + int current_application_index = _launcher_apps_combo->currentIndex(); + assert(current_application_index >= 0); + + Application &application = Configurator::Get().environment.GetApplication(current_application_index); + ApplicationOptions &options = application.GetActiveOptions(); + options.working_folder = working_folder.toStdString(); +} + +// Launch app change +void MainWindow::launchItemChanged(int application_index) { + if (application_index < 0) return; + + Environment &environment = Configurator::Get().environment; + + environment.SelectActiveApplication(application_index); + + Application &application = environment.GetApplication(application_index); + ApplicationOptions &options = application.GetActiveOptions(); + + _launcher_executable->setText(application.executable_path.RelativePath().c_str()); + _launcher_working->setText(options.working_folder.RelativePath().c_str()); + _launcher_arguments->setText(Merge(options.arguments, " ").c_str()); + _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); +} + +/// New command line arguments. Update them. +void MainWindow::launchArgsEdited(const QString &arguments) { + int application_index = _launcher_apps_combo->currentIndex(); + if (application_index < 0) return; + + Application &application = Configurator::Get().environment.GetApplication(application_index); + ApplicationOptions &options = application.GetActiveOptions(); + options.arguments = SplitSpace(arguments.toStdString()); +} +*/ diff --git a/vkconfig_gui/tab_applications.h b/vkconfig_gui/tab_applications.h new file mode 100644 index 0000000000..917fc86a41 --- /dev/null +++ b/vkconfig_gui/tab_applications.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "tab.h" + +struct TabApplications : public Tab { + TabApplications(MainWindow& window, std::shared_ptr ui); + virtual ~TabApplications(); + + virtual void UpdateUI(UpdateUIMode mode) override; + virtual void CleanUI() override; + virtual bool EventFilter(QObject* target, QEvent* event) override; +}; diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp new file mode 100644 index 0000000000..dc2d1aee38 --- /dev/null +++ b/vkconfig_gui/tab_configurations.cpp @@ -0,0 +1,711 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab_configurations.h" +#include "mainwindow.h" + +#include "../vkconfig_core/alert.h" +#include "../vkconfig_core/configurator.h" +#include "../vkconfig_core/ui.h" +#include "../vkconfig_core/doc.h" + +#include +#include +#include +#include + +TabConfigurations::TabConfigurations(MainWindow &window, std::shared_ptr ui) : Tab(TAB_CONFIGURATIONS, window, ui) { + ui->configurations_list->installEventFilter(&window); + ui->layers_list->installEventFilter(&window); + ui->settings_tree->installEventFilter(&window); + + QSettings settings("LunarG", VKCONFIG_SHORT_NAME); + this->ui->splitter_main->restoreState(settings.value("mainwindow/splitter_main_state").toByteArray()); + this->ui->splitter_configurations->restoreState(settings.value("mainwindow/splitter_configurations_state").toByteArray()); + this->ui->splitter_settings->restoreState(settings.value("mainwindow/splitter_settings_state").toByteArray()); +} + +TabConfigurations::~TabConfigurations() { + QSettings settings("LunarG", VKCONFIG_SHORT_NAME); + settings.setValue("mainwindow/splitter_main_state", ui->splitter_main->saveState()); + settings.setValue("mainwindow/splitter_configurations_state", ui->splitter_configurations->saveState()); + settings.setValue("mainwindow/splitter_settings_state", ui->splitter_settings->saveState()); +} + +void TabConfigurations::UpdateUI_Configurations(UpdateUIMode ui_update_mode) { + Configurator &configurator = Configurator::Get(); + Environment &environment = configurator.environment; + + LayersMode mode = environment.GetActiveConfigurationInfo().GetMode(); + const bool enabled_ui = mode == LAYERS_CONTROLLED_BY_CONFIGURATOR; + + const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); + const bool has_selected_configuration = !selected_contiguration_name.empty(); + + ui->combo_box_mode->blockSignals(true); + ui->combo_box_mode->setCurrentIndex(mode); + ui->combo_box_mode->blockSignals(false); + + ui->configurations_list->blockSignals(true); + + ui->configurations_list->setEnabled(enabled_ui); + ui->group_box_settings->setEnabled(enabled_ui); + ui->group_box_layers->setEnabled(enabled_ui); + + if (ui_update_mode == UPDATE_REBUILD_UI) { + ui->configurations_list->clear(); + + for (std::size_t i = 0, n = configurator.configurations.available_configurations.size(); i < n; ++i) { + const Configuration &configuration = configurator.configurations.available_configurations[i]; + + // Hide built-in configuration when the layer is missing. The Vulkan user may have not installed the necessary layer + // if (configuration.IsBuiltIn() && HasMissingLayer(configuration.parameters, configurator.layers.available_layers)) + // continue; + + ConfigurationListItem *item = new ConfigurationListItem(configuration.key.c_str()); + item->setFlags(item->flags() | Qt::ItemIsEditable); + item->setText(configuration.key.c_str()); + item->setToolTip(configuration.description.c_str()); + ui->configurations_list->addItem(item); + } + } + + for (int i = 0, n = ui->configurations_list->count(); i < n; ++i) { + ConfigurationListItem *item = dynamic_cast(ui->configurations_list->item(i)); + assert(item); + assert(!item->configuration_name.empty()); + + Configuration *configuration = configurator.configurations.FindConfiguration(item->configuration_name); + assert(configuration != nullptr); + + if (item->configuration_name == selected_contiguration_name) { + // TODO: add PartiallyChecked when the configuration is not working + // HasMissingLayer(configuration.parameters, configurator.layers.available_layers) + // item->setIcon(QIcon(":/resourcefiles/config-invalid.png")); + ui->configurations_list->setCurrentItem(item); + // ui->configurations_list->setCurrentRow(i); + item->setIcon(QIcon(":/resourcefiles/config-on.png")); + } else { + item->setIcon(QIcon(":/resourcefiles/config-off.png")); + } + } + + ui->configurations_list->blockSignals(false); + + if (has_selected_configuration) { + this->_settings_tree_manager.CreateGUI(ui->settings_tree); + } else { + this->_settings_tree_manager.CleanupGUI(); + } +} + +void TabConfigurations::UpdateUI_Applications(UpdateUIMode ui_update_mode) { + Configurator &configurator = Configurator::Get(); + Environment &environment = configurator.environment; + + if (environment.GetApplications().empty()) { + ui->check_box_per_application->setEnabled(false); + ui->check_box_per_application->setVisible(false); + ui->combo_box_applications->setVisible(false); + } else { + ui->check_box_per_application->setEnabled(true); + ui->check_box_per_application->setChecked(configurator.environment.GetPerApplicationConfig()); + + ui->combo_box_applications->setEnabled(configurator.environment.GetPerApplicationConfig()); + + ui->combo_box_applications->blockSignals(true); + + if (ui_update_mode == UPDATE_REBUILD_UI) { + ui->combo_box_applications->clear(); + for (std::size_t i = 0, n = environment.GetApplications().size(); i < n; ++i) { + const Application &application = environment.GetApplications()[i]; + + ui->combo_box_applications->addItem(application.executable_path.RelativePath().c_str()); + } + } + + Application &application = configurator.environment.GetActiveApplication(); + ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); + ui->combo_box_applications->setToolTip(application.executable_path.AbsolutePath().c_str()); + ui->combo_box_applications->blockSignals(false); + } +} + +void TabConfigurations::UpdateUI_LoaderMessages() { + const Configurator &configurator = Configurator::Get(); + + const Configuration *configuration = configurator.GetActiveConfiguration(); + if (configuration != nullptr) { + ui->configuration_loader_errors_checkBox->blockSignals(true); + ui->configuration_loader_errors_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_ERROR)); + ui->configuration_loader_errors_checkBox->blockSignals(false); + ui->configuration_loader_warns_checkBox->blockSignals(true); + ui->configuration_loader_warns_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_WARN)); + ui->configuration_loader_warns_checkBox->blockSignals(false); + ui->configuration_loader_infos_checkBox->blockSignals(true); + ui->configuration_loader_infos_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_INFO)); + ui->configuration_loader_infos_checkBox->blockSignals(false); + ui->configuration_loader_debug_checkBox->blockSignals(true); + ui->configuration_loader_debug_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_DEBUG)); + ui->configuration_loader_debug_checkBox->blockSignals(false); + ui->configuration_loader_layers_checkBox->blockSignals(true); + ui->configuration_loader_layers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_LAYER)); + ui->configuration_loader_layers_checkBox->blockSignals(false); + ui->configuration_loader_drivers_checkBox->blockSignals(true); + ui->configuration_loader_drivers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_IMPLEM)); + ui->configuration_loader_drivers_checkBox->blockSignals(false); + } +} + +void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { + ui->layers_list->clear(); + + Configurator &configurator = Configurator::Get(); + const std::string &selected_contiguration_name = configurator.environment.GetActiveConfigurationInfo().GetName(); + const bool has_selected_configuration = !selected_contiguration_name.empty(); + + if (has_selected_configuration) { + Configuration *configuration = configurator.configurations.FindConfiguration(selected_contiguration_name); + if (configuration != nullptr) { + for (std::size_t i = 0, n = configuration->parameters.size(); i < n; ++i) { + Parameter ¶meter = configuration->parameters[i]; + + if (!configuration->view_advanced_layers) { + if (parameter.control == LAYER_CONTROL_AUTO) { + continue; + } + } + + const Layer *layer = configurator.layers.Find(parameter.key); + + TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(parameter.key.c_str()); + item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); + ui->layers_list->addItem(item_state); + + std::vector layers; + if (layer != nullptr) { + layers.push_back(layer); + } + + ConfigurationLayerWidget *layer_widget = + new ConfigurationLayerWidget(layers, parameter, configuration->view_advanced_layers); + item_state->widget = layer_widget; + + if (parameter.control == LAYER_CONTROL_APPLICATIONS_API) { + item_state->widget->setToolTip("Located and Enabled Layers using the Vulkan API by the Vulkan Application"); + } else if (parameter.control == LAYER_CONTROL_APPLICATIONS_ENV) { + item_state->widget->setToolTip( + "Located and Enabled Layers using Environment Variables by the Vulkan Application"); + } + + ui->layers_list->setItemWidget(item_state, layer_widget); + if (configuration->selected_layer_name == parameter.key) { + ui->layers_list->setCurrentItem(item_state); + } + } + // resizeEvent(nullptr); + + ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); + + ui->layers_list->update(); + } + } + + ui->execute_closer_application_label->setVisible(true); + ui->execute_closer_driver_label->setVisible(true); +} + +void TabConfigurations::UpdateUI_Settings(UpdateUIMode mode) {} + +void TabConfigurations::UpdateUI(UpdateUIMode ui_update_mode) { + this->UpdateUI_Configurations(ui_update_mode); + this->UpdateUI_Applications(ui_update_mode); + this->UpdateUI_LoaderMessages(); + this->UpdateUI_Layers(ui_update_mode); + this->UpdateUI_Settings(ui_update_mode); + + Configurator &configurator = Configurator::Get(); + Environment &environment = configurator.environment; + + // Update the layers configuration area + LayersMode mode = environment.GetActiveConfigurationInfo().GetMode(); + const bool enabled_ui = mode == LAYERS_CONTROLLED_BY_CONFIGURATOR; + + ui->combo_box_mode->setCurrentIndex(mode); + ui->configurations_list->setEnabled(enabled_ui); + ui->group_box_settings->setEnabled(enabled_ui); + ui->group_box_layers->setEnabled(enabled_ui); +} + +void TabConfigurations::CleanUI() { this->_settings_tree_manager.CleanupGUI(); } + +static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { + if (item == nullptr) { + return nullptr; + } + + TreeWidgetItemParameter *item_parameter = static_cast(item); + + const std::string &layer_string = item_parameter->layer_name; + if (!layer_string.empty()) { + Configurator &configurator = Configurator::Get(); + + const std::string &layer_key = ExtractLayerName(configurator.layers, layer_string); + return configurator.layers.Find(layer_key); + } + + return nullptr; +} + +bool TabConfigurations::EventFilter(QObject *target, QEvent *event) { + QEvent::Type event_type = event->type(); + + if (event_type == QEvent::Wheel) { + return true; + } + + if (event_type == QEvent::ChildRemoved) { + // Layers were reordered, we need to update the configuration + Configurator::Get().Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + return true; + } + + // Launch tree does some fancy resizing and since it's down in + // layouts and splitters, we can't just rely on the resize method + // of this window. Any resize coming through needs to trigger this + // or we get drawing artifacts on macOS. + /* + if (event->type() == QEvent::Resize) { + const QRect rect = ui->launcher_tree->rect(); + ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); + ui->launcher_tree->setColumnWidth(1, rect.width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); + ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); + return false; + } + */ + + if (target == ui->configurations_list) { + QContextMenuEvent *right_click = dynamic_cast(event); + if (right_click) { + ConfigurationListItem *item = static_cast(ui->configurations_list->itemAt(right_click->pos())); + + std::string name; + + if (item != nullptr) { + name = item->configuration_name; + } + + QMenu menu(ui->configurations_list); + QFont subtitle_font = menu.font(); + subtitle_font.setBold(true); + + QAction *action_new = new QAction("Create a new Configuration", nullptr); + action_new->setEnabled(true); + menu.addAction(action_new); + + QAction *action_import = new QAction("Import a new Configuration...", nullptr); + action_import->setEnabled(true); + menu.addAction(action_import); + + menu.addSeparator(); + + QAction *action_rename = new QAction("Rename the Configuration", nullptr); + action_rename->setEnabled(item != nullptr); + menu.addAction(action_rename); + + QAction *action_duplicate = new QAction("Duplicate the Configuration", nullptr); + action_duplicate->setEnabled(item != nullptr); + menu.addAction(action_duplicate); + + QAction *action_delete = new QAction("Delete the Configuration", nullptr); + action_delete->setEnabled(item != nullptr); + menu.addAction(action_delete); + + menu.addSeparator(); + + QAction *action_reset = new QAction("Reset the Configuration", nullptr); + action_reset->setEnabled(item != nullptr); + action_reset->setToolTip("Reset the Configuration using the built-in configuration"); + menu.addAction(action_reset); + + QAction *action_reload = new QAction("Reload the Configuration", nullptr); + action_reload->setEnabled(item != nullptr); + action_reset->setToolTip("Reload the Configuration, discarding all changes from this session"); + menu.addAction(action_reload); + + menu.addSeparator(); + + QAction *action_export_config = new QAction("Export the Configuration...", nullptr); + action_export_config->setEnabled(item != nullptr); + menu.addAction(action_export_config); + + QAction *action_export_settings = new QAction("Export the Layers Settings...", nullptr); + action_export_settings->setEnabled(item != nullptr); + menu.addAction(action_export_settings); + + QPoint point(right_click->globalX(), right_click->globalY()); + QAction *action = menu.exec(point); + + if (action == action_new) { + this->OnContextMenuNewClicked(item); + } else if (action == action_import) { + this->OnContextMenuImportClicked(item); + } else if (action == action_rename) { + this->OnContextMenuRenameClicked(item); + } else if (action == action_duplicate) { + this->OnContextMenuDuplicateClicked(item); + } else if (action == action_delete) { + this->OnContextMenuDeleteClicked(item); + } else if (action == action_reset) { + this->OnContextMenuResetClicked(item); + } else if (action == action_reload) { + this->OnContextMenuReloadClicked(item); + } else if (action == action_export_config) { + this->OnContextMenuExportConfigsClicked(item); + } else if (action == action_export_settings) { + this->OnContextMenuExportSettingsClicked(item); + } + } + } else if (target == ui->layers_list) { + QContextMenuEvent *right_click = dynamic_cast(event); + if (right_click) { + QListWidgetItem *item = ui->layers_list->itemAt(right_click->pos()); + + const Layer *layer = GetLayer(ui->layers_list, item); + + QMenu menu(ui->layers_list); + + QAction *action_description = new QAction("Open the Layer Description...", nullptr); + action_description->setEnabled(item != nullptr); + menu.addAction(action_description); + + QAction *export_html_action = new QAction("Open the Layer HTML Documentation...", nullptr); + export_html_action->setEnabled(item != nullptr); + menu.addAction(export_html_action); + + QAction *export_markdown_action = new QAction("Open the Layer Markdown Documentation...", nullptr); + export_markdown_action->setEnabled(item != nullptr); + menu.addAction(export_markdown_action); + + QAction *visit_layer_website_action = new QAction("Visit the Layer Website...", nullptr); + visit_layer_website_action->setEnabled(layer != nullptr ? !layer->url.empty() : false); + menu.addAction(visit_layer_website_action); + + QPoint point(right_click->globalX(), right_click->globalY()); + QAction *action = menu.exec(point); + + if (action == action_description) { + Alert::LayerProperties(layer); + } else if (action == visit_layer_website_action) { + QDesktopServices::openUrl(QUrl(layer->url.c_str())); + } else if (action == export_html_action) { + const std::string path = format("%s/%s.html", AbsolutePath(Path::APPDATA).c_str(), layer->key.c_str()); + ExportHtmlDoc(*layer, path); + QDesktopServices::openUrl(QUrl(("file:///" + path).c_str())); + } else if (action == export_markdown_action) { + const std::string path = format("%s/%s.md", AbsolutePath(Path::APPDATA).c_str(), layer->key.c_str()); + ExportMarkdownDoc(*layer, path); + QDesktopServices::openUrl(QUrl(("file:///" + path).c_str())); + } + } + } + + // Pass it on + return false; +} + +void TabConfigurations::OnSelectConfiguration(int currentRow) { + this->_settings_tree_manager.CleanupGUI(); + + if (currentRow == -1) { + return; // No row selected + } + + QListWidgetItem *item = ui->configurations_list->item(currentRow); + ConfigurationListItem *configuration_item = dynamic_cast(item); + + if (configuration_item == nullptr) { + return; + } + + Configurator &configurator = Configurator::Get(); + if (configurator.environment.GetActiveConfigurationInfo().GetName() != configuration_item->configuration_name) { + configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); + // configurator.environment.selected_layer_name.clear(); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + + this->UpdateUI_Configurations(UPDATE_REFRESH_UI); + this->UpdateUI_LoaderMessages(); + this->UpdateUI_Layers(UPDATE_REBUILD_UI); + } +} + +void TabConfigurations::OnRenameConfiguration(QListWidgetItem *item) { + ConfigurationListItem *configuration_item = dynamic_cast(item); + if (configuration_item == nullptr) { + return; + } + + Configurator &configurator = Configurator::Get(); + + // We are renaming the file. Things can go wrong here... + // This is the name of the configuratin we are changing + // const std::string full_path = + // ConvertNativeSeparators(GetPath(BUILTIN_PATH_CONFIG_LAST) + "/" + configuration_item->configuration_name + ".json"); + + // This is the new name we want to use for the configuration + const std::string &new_name = configuration_item->text().toStdString(); + bool valid_new_name = true; + + if (new_name.empty()) { + valid_new_name = false; + Alert::ConfigurationNameEmpty(); + } else if (!IsPortableFilename(new_name)) { + valid_new_name = false; + Alert::ConfigurationNameInvalid(); + } + + Configuration *duplicate_configuration = configurator.configurations.FindConfiguration(new_name); + + if (duplicate_configuration != nullptr) { + valid_new_name = false; + Alert::ConfigurationRenamingFailed(); + } + + // Find existing configuration using it's old name + const std::string &old_name = configuration_item->configuration_name; + Configuration *configuration = configurator.configurations.FindConfiguration(old_name); + + if (valid_new_name) { + // Rename configuration ; Remove old configuration file ; change the name of the configuration + configurator.configurations.RemoveConfigurationFile(old_name); + configuration->key = configuration_item->configuration_name = new_name; + configurator.configurations.SaveAllConfigurations(); + configurator.environment.GetActiveConfigurationInfo().SetName(new_name); + + this->UpdateUI_Configurations(UPDATE_REBUILD_UI); + this->UpdateUI_LoaderMessages(); + this->UpdateUI_Layers(UPDATE_REBUILD_UI); + } else { + // If the configurate name is empty or the configuration name is taken, keep old configuration name + ui->configurations_list->blockSignals(true); + item->setText(old_name.c_str()); + ui->configurations_list->blockSignals(false); + + configurator.environment.GetActiveConfigurationInfo().SetName(old_name); + } + + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); +} + +void TabConfigurations::OnSelectLayer(int currentRow) { + this->_settings_tree_manager.CleanupGUI(); + + if (currentRow == -1) { + return; // No row selected + } + + QWidget *widget = ui->layers_list->itemWidget(ui->layers_list->item(currentRow)); + const std::string &layer_string = static_cast(widget)->text().toStdString(); + + Configurator &configurator = Configurator::Get(); + configurator.GetActiveConfiguration()->selected_layer_name = ExtractLayerName(configurator.layers, layer_string); + + this->_settings_tree_manager.CreateGUI(ui->settings_tree); +} + +void TabConfigurations::OnCheckedLoaderMessageTypes(bool checked) { + (void)checked; + + Configurator &configurator = Configurator::Get(); + + Configuration *active_configuration = configurator.GetActiveConfiguration(); + if (active_configuration != nullptr) { + int loader_log_messages_bits = 0; + + loader_log_messages_bits |= ui->configuration_loader_errors_checkBox->isChecked() ? GetBit(LOG_ERROR) : 0; + loader_log_messages_bits |= ui->configuration_loader_warns_checkBox->isChecked() ? GetBit(LOG_WARN) : 0; + loader_log_messages_bits |= ui->configuration_loader_infos_checkBox->isChecked() ? GetBit(LOG_INFO) : 0; + loader_log_messages_bits |= ui->configuration_loader_debug_checkBox->isChecked() ? GetBit(LOG_DEBUG) : 0; + loader_log_messages_bits |= ui->configuration_loader_layers_checkBox->isChecked() ? GetBit(LOG_LAYER) : 0; + loader_log_messages_bits |= ui->configuration_loader_drivers_checkBox->isChecked() ? GetBit(LOG_IMPLEM) : 0; + + active_configuration->loader_log_messages_flags = loader_log_messages_bits; + } +} + +void TabConfigurations::OnContextMenuNewClicked(ConfigurationListItem *item) { + Configurator &configurator = Configurator::Get(); + + Configuration &new_configuration = + configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); + + configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); + configurator.Override(OVERRIDE_AREA_ALL); + + this->UpdateUI_Configurations(UPDATE_REBUILD_UI); +} + +void TabConfigurations::OnContextMenuImportClicked(ConfigurationListItem *item) { + (void)item; // We don't need this + + Configurator &configurator = Configurator::Get(); + + const Path &path_import = configurator.environment.path_import; + const std::string selected_path = QFileDialog::getOpenFileName(&this->window, "Import Layers Configuration File", + path_import.AbsolutePath().c_str(), "JSON configuration(*.json)") + .toStdString(); + + if (selected_path.empty()) { + return; + } + + configurator.environment.path_import = selected_path; + std::string imported_configuration = + configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, selected_path); + + configurator.environment.GetActiveConfigurationInfo().SetName(imported_configuration); + configurator.Override(OVERRIDE_AREA_ALL); + + this->UpdateUI_Configurations(UPDATE_REBUILD_UI); +} + +void TabConfigurations::OnContextMenuRenameClicked(ConfigurationListItem *item) { + assert(item); + + // ui->configurations_list->blockSignals(true); + + // item->widget->setVisible(false); + // item->setText(item->widget->text()); + + // ui->configurations_list->blockSignals(false); + + ui->configurations_list->editItem(item); +} + +void TabConfigurations::OnContextMenuDuplicateClicked(ConfigurationListItem *item) { + assert(item); + assert(!item->configuration_name.empty()); + + Configurator &configurator = Configurator::Get(); + const Configuration &duplicated_configuration = + configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, item->configuration_name, true); + + item->configuration_name = duplicated_configuration.key; + + configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + + this->UpdateUI_Configurations(UPDATE_REBUILD_UI); +} + +void TabConfigurations::OnContextMenuDeleteClicked(ConfigurationListItem *item) { + assert(item); + assert(!item->configuration_name.empty()); + + // Let make sure... + QMessageBox alert; + alert.setWindowTitle(format("Removing *%s* configuration...", item->configuration_name.c_str()).c_str()); + alert.setText(format("Are you sure you want to remove the *%s* configuration?", item->configuration_name.c_str()).c_str()); + alert.setInformativeText("All the data from this configuration will be lost."); + alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + alert.setDefaultButton(QMessageBox::Yes); + alert.setIcon(QMessageBox::Warning); + if (alert.exec() == QMessageBox::No) { + return; + } + + Configurator &configurator = Configurator::Get(); + configurator.configurations.RemoveConfiguration(configurator.layers.selected_layers, item->configuration_name); + configurator.environment.GetActiveConfigurationInfo().SetName(""); + + this->UpdateUI_Configurations(UPDATE_REBUILD_UI); + this->UpdateUI_Applications(UPDATE_REFRESH_UI); + this->UpdateUI_LoaderMessages(); + this->UpdateUI_Layers(UPDATE_REBUILD_UI); +} + +void TabConfigurations::OnContextMenuResetClicked(ConfigurationListItem *item) { + assert(item); + assert(!item->configuration_name.empty()); + + Configurator &configurator = Configurator::Get(); + Configuration *configuration = + FindByKey(configurator.configurations.available_configurations, item->configuration_name.c_str()); + assert(configuration != nullptr); + + QMessageBox alert; + alert.setWindowTitle(format("Resetting *%s* configuration...", configuration->key.c_str()).c_str()); + alert.setText(format("Are you sure you want to reset the *%s* configuration?", configuration->key.c_str()).c_str()); + if (configuration->IsBuiltIn()) + alert.setInformativeText( + format("The configuration layers and settings will be restored to default built-in *%s* configuration.", + configuration->key.c_str()) + .c_str()); + else if (configurator.configurations.HasFile(*configuration)) + alert.setInformativeText( + format("The configuration layers and settings will be reloaded using the *%s* saved file from previous %s run.", + configuration->key.c_str(), VKCONFIG_NAME) + .c_str()); + else + alert.setInformativeText("The configuration layers and settings will be reset to zero."); + alert.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + alert.setDefaultButton(QMessageBox::Yes); + alert.setIcon(QMessageBox::Warning); + if (alert.exec() == QMessageBox::No) { + return; + } + + configuration->Reset(configurator.layers.selected_layers); + + this->UpdateUI_Configurations(UPDATE_REFRESH_UI); +} + +void TabConfigurations::OnContextMenuReloadClicked(ConfigurationListItem *item) { + assert(item); + assert(!item->configuration_name.empty()); + + // TODO +} + +void TabConfigurations::OnContextMenuExportConfigsClicked(ConfigurationListItem *item) { + assert(item); + + Configurator &configurator = Configurator::Get(); + + const Path &path_export = configurator.environment.path_export; + const std::string &selected_path = + QFileDialog::getSaveFileName(&this->window, "Export Layers Configuration File", path_export.AbsolutePath().c_str(), + "JSON configuration(*.json)") + .toStdString(); + + if (selected_path.empty()) { + return; + } + + configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, selected_path, item->configuration_name); +} + +void TabConfigurations::OnContextMenuExportSettingsClicked(ConfigurationListItem *item) { + assert(item); + + Configurator &configurator = Configurator::Get(); + // TODO +} diff --git a/vkconfig_gui/tab_configurations.h b/vkconfig_gui/tab_configurations.h new file mode 100644 index 0000000000..1f4b09b97d --- /dev/null +++ b/vkconfig_gui/tab_configurations.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "tab.h" +#include "settings_tree.h" + +#include + +/// This just allows me to associate a specific profile definition +/// with a list widget item. +class ConfigurationListItem : public QListWidgetItem { + public: + ConfigurationListItem(const char *configuration_name) : configuration_name(configuration_name) { + assert(configuration_name != nullptr); + } + + std::string configuration_name; + + private: + ConfigurationListItem(const ConfigurationListItem &) = delete; + ConfigurationListItem &operator=(const ConfigurationListItem &) = delete; +}; + +struct TabConfigurations : public Tab { + TabConfigurations(MainWindow &window, std::shared_ptr ui); + virtual ~TabConfigurations(); + + virtual void UpdateUI(UpdateUIMode ui_update_mode) override; + virtual void CleanUI() override; + virtual bool EventFilter(QObject *target, QEvent *event) override; + + void OnSelectConfiguration(int currentRow); + void OnRenameConfiguration(QListWidgetItem *item); + void OnSelectLayer(int currentRow); + void OnCheckedLoaderMessageTypes(bool checked); + + void UpdateUI_Configurations(UpdateUIMode ui_update_mode); + void UpdateUI_Applications(UpdateUIMode ui_update_mode); + void UpdateUI_LoaderMessages(); + void UpdateUI_Layers(UpdateUIMode ui_update_mode); + void UpdateUI_Settings(UpdateUIMode ui_update_mode); + + private: + SettingsTreeManager _settings_tree_manager; + + void OnContextMenuNewClicked(ConfigurationListItem *item); + void OnContextMenuImportClicked(ConfigurationListItem *item); + void OnContextMenuRenameClicked(ConfigurationListItem *item); + void OnContextMenuDuplicateClicked(ConfigurationListItem *item); + void OnContextMenuDeleteClicked(ConfigurationListItem *item); + void OnContextMenuResetClicked(ConfigurationListItem *item); + void OnContextMenuReloadClicked(ConfigurationListItem *item); + void OnContextMenuExportConfigsClicked(ConfigurationListItem *item); + void OnContextMenuExportSettingsClicked(ConfigurationListItem *item); +}; diff --git a/vkconfig_gui/tab_diagnostics.cpp b/vkconfig_gui/tab_diagnostics.cpp new file mode 100644 index 0000000000..d86abeaec2 --- /dev/null +++ b/vkconfig_gui/tab_diagnostics.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab_diagnostics.h" +#include "mainwindow.h" + +TabDiagnostics::TabDiagnostics(MainWindow &window, std::shared_ptr ui) : Tab(TAB_DIAGNOSTIC, window, ui) {} + +TabDiagnostics::~TabDiagnostics() {} + +void TabDiagnostics::UpdateUI(UpdateUIMode mode) {} + +void TabDiagnostics::CleanUI() {} + +bool TabDiagnostics::EventFilter(QObject *target, QEvent *event) { return false; } diff --git a/vkconfig_gui/tab_diagnostics.h b/vkconfig_gui/tab_diagnostics.h new file mode 100644 index 0000000000..128043ca3e --- /dev/null +++ b/vkconfig_gui/tab_diagnostics.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "tab.h" + +struct TabDiagnostics : public Tab { + TabDiagnostics(MainWindow& window, std::shared_ptr ui); + virtual ~TabDiagnostics(); + + virtual void UpdateUI(UpdateUIMode mode) override; + virtual void CleanUI() override; + virtual bool EventFilter(QObject* target, QEvent* event) override; +}; diff --git a/vkconfig_gui/tab_help.cpp b/vkconfig_gui/tab_help.cpp new file mode 100644 index 0000000000..11a10f8af0 --- /dev/null +++ b/vkconfig_gui/tab_help.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab_help.h" +#include "mainwindow.h" + +TabHelp::TabHelp(MainWindow &window, std::shared_ptr ui) : Tab(TAB_HELP, window, ui) {} + +TabHelp::~TabHelp() {} + +void TabHelp::UpdateUI(UpdateUIMode mode) {} + +void TabHelp::CleanUI() {} + +bool TabHelp::EventFilter(QObject *target, QEvent *event) { return false; } diff --git a/vkconfig_gui/tab_help.h b/vkconfig_gui/tab_help.h new file mode 100644 index 0000000000..8938c09c4e --- /dev/null +++ b/vkconfig_gui/tab_help.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "tab.h" + +struct TabHelp : public Tab { + TabHelp(MainWindow& window, std::shared_ptr ui); + virtual ~TabHelp(); + + virtual void UpdateUI(UpdateUIMode mode) override; + virtual void CleanUI() override; + virtual bool EventFilter(QObject* target, QEvent* event) override; +}; diff --git a/vkconfig_gui/tab_layers.cpp b/vkconfig_gui/tab_layers.cpp new file mode 100644 index 0000000000..8b81bbe69f --- /dev/null +++ b/vkconfig_gui/tab_layers.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab_layers.h" +#include "mainwindow.h" + +TabLayers::TabLayers(MainWindow &window, std::shared_ptr ui) : Tab(TAB_LAYERS, window, ui) {} + +TabLayers::~TabLayers() {} + +void TabLayers::UpdateUI(UpdateUIMode mode) {} + +void TabLayers::CleanUI() {} + +bool TabLayers::EventFilter(QObject *target, QEvent *event) { return false; } diff --git a/vkconfig_gui/tab_layers.h b/vkconfig_gui/tab_layers.h new file mode 100644 index 0000000000..5851aca1e4 --- /dev/null +++ b/vkconfig_gui/tab_layers.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "tab.h" + +struct TabLayers : public Tab { + TabLayers(MainWindow& window, std::shared_ptr ui); + virtual ~TabLayers(); + + virtual void UpdateUI(UpdateUIMode mode) override; + virtual void CleanUI() override; + virtual bool EventFilter(QObject* target, QEvent* event) override; +}; diff --git a/vkconfig_gui/tab_preferences.cpp b/vkconfig_gui/tab_preferences.cpp new file mode 100644 index 0000000000..d471103408 --- /dev/null +++ b/vkconfig_gui/tab_preferences.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab_preferences.h" +#include "mainwindow.h" + +TabPreferences::TabPreferences(MainWindow &window, std::shared_ptr ui) : Tab(TAB_PREFERENCES, window, ui) {} + +TabPreferences::~TabPreferences() {} + +void TabPreferences::UpdateUI(UpdateUIMode mode) {} + +void TabPreferences::CleanUI() {} + +bool TabPreferences::EventFilter(QObject *target, QEvent *event) { return false; } diff --git a/vkconfig_gui/tab_preferences.h b/vkconfig_gui/tab_preferences.h new file mode 100644 index 0000000000..b3cb0566c1 --- /dev/null +++ b/vkconfig_gui/tab_preferences.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "tab.h" + +struct TabPreferences : public Tab { + TabPreferences(MainWindow& window, std::shared_ptr ui); + virtual ~TabPreferences(); + + virtual void UpdateUI(UpdateUIMode mode) override; + virtual void CleanUI() override; + virtual bool EventFilter(QObject* target, QEvent* event) override; +}; diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index 0cc711ed58..a1624348b9 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -92,6 +92,13 @@ SOURCES += \ dialog_vulkan_info.cpp \ main.cpp \ mainwindow.cpp \ + tab.cpp \ + tab_applications.cpp \ + tab_configurations.cpp \ + tab_diagnostics.cpp \ + tab_help.cpp \ + tab_layers.cpp \ + tab_preferences.cpp \ settings_tree.cpp HEADERS += \ @@ -159,6 +166,13 @@ HEADERS += \ dialog_vulkan_analysis.h \ dialog_vulkan_info.h \ mainwindow.h \ + tab.h \ + tab_applications.h \ + tab_configurations.h \ + tab_diagnostics.h \ + tab_help.h \ + tab_layers.h \ + tab_preferences.h \ settings_tree.h FORMS += \ From 2271b040d38c221bd22986247e361782abf7b568 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 19 Aug 2024 17:09:38 +0200 Subject: [PATCH 15/33] vkconfig3: Disable settings UI when layer is off --- vkconfig_gui/configuration_layer_widget.cpp | 9 +- vkconfig_gui/configuration_layer_widget.h | 10 ++- vkconfig_gui/mainwindow.cpp | 8 +- vkconfig_gui/mainwindow.h | 45 +++++----- vkconfig_gui/mainwindow.ui | 98 +++++++++++++++++---- vkconfig_gui/settings_tree.cpp | 6 ++ vkconfig_gui/tab_configurations.cpp | 68 ++++++-------- vkconfig_gui/tab_configurations.h | 12 +++ 8 files changed, 172 insertions(+), 84 deletions(-) diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/configuration_layer_widget.cpp index 4388749542..c4fe4ee081 100644 --- a/vkconfig_gui/configuration_layer_widget.cpp +++ b/vkconfig_gui/configuration_layer_widget.cpp @@ -20,6 +20,7 @@ #include "configuration_layer_widget.h" #include "widget_setting.h" +#include "tab_configurations.h" #include "../vkconfig_core/configurator.h" @@ -92,9 +93,9 @@ static bool IsDLL32Bit(const std::string full_path) { #endif } -ConfigurationLayerWidget::ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter, - bool advanced_view) - : layer_name(parameter.key) { +ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const std::vector &layers, + const Parameter ¶meter, bool advanced_view) + : tab(tab), layer_name(parameter.key) { // const bool is_implicit_layer = layers.empty() ? false : layers[0]->type == LAYER_TYPE_IMPLICIT; Version api_version; @@ -226,4 +227,6 @@ void ConfigurationLayerWidget::on_layer_state_currentIndexChanged(int index) { Configuration *configuration = Configurator::Get().GetActiveConfiguration(); Parameter *parameter = configuration->Find(this->layer_name); parameter->control = GetLayerControl(text.c_str()); + + this->tab->UpdateUI_Settings(UPDATE_REFRESH_UI); } diff --git a/vkconfig_gui/configuration_layer_widget.h b/vkconfig_gui/configuration_layer_widget.h index b674304654..8b40a963d4 100644 --- a/vkconfig_gui/configuration_layer_widget.h +++ b/vkconfig_gui/configuration_layer_widget.h @@ -23,16 +23,23 @@ #include "../vkconfig_core/parameter.h" #include "../vkconfig_core/layer.h" +#include "ui_mainwindow.h" + #include #include #include #include +#include + +class TabConfigurations; + class ConfigurationLayerWidget : public QLabel { Q_OBJECT public: - ConfigurationLayerWidget(const std::vector &layers, const Parameter ¶meter, bool advanced_view); + ConfigurationLayerWidget(TabConfigurations *tab, const std::vector &layers, const Parameter ¶meter, + bool advanced_view); protected: bool eventFilter(QObject *target, QEvent *event); @@ -43,6 +50,7 @@ class ConfigurationLayerWidget : public QLabel { void on_layer_state_currentIndexChanged(int index); private: + TabConfigurations *tab; std::string layer_name; QComboBox *layer_version = nullptr; diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 19aa0cacb0..460c9a6b98 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -286,13 +286,13 @@ void MainWindow::AddLayerPathItem(const std::string &layer_path) { TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(layer_path.c_str()); item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); - LayerPathWidget *layer_path_widget = new LayerPathWidget(layer_path, ui->tree_layers_paths, item_state); + LayerPathWidget *layer_path_widget = new LayerPathWidget(layer_path, ui->layers_tree, item_state); item_state->widget = layer_path_widget; // Add the top level item - ui->tree_layers_paths->addItem(item_state); - ui->tree_layers_paths->setItemWidget(item_state, layer_path_widget); + ui->layers_tree->addTopLevelItem(item_state); + ui->layers_tree->setItemWidget(item_state, 0, layer_path_widget); } void MainWindow::UpdateUI() { @@ -565,7 +565,7 @@ void MainWindow::on_configurations_list_currentRowChanged(int currentRow) { this->tab_configurations->OnSelectConfiguration(currentRow); } -void MainWindow::on_layers_list_currentRowChanged(int currentRow) { +void MainWindow::on_configurations_layers_list_currentRowChanged(int currentRow) { assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); this->tab_configurations->OnSelectLayer(currentRow); } diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 772da0e472..4fe4233eb4 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -47,7 +47,7 @@ class LayerPathWidget : public QLabel { Q_OBJECT public: - LayerPathWidget(const std::string &layer_path, QListWidget *list, QListWidgetItem *item) : item(item) { + LayerPathWidget(const std::string &layer_path, QTreeWidget *list, QTreeWidgetItem *item) : item(item) { this->button_edit = new QPushButton(this); this->button_edit->setText("..."); this->button_edit->show(); @@ -57,7 +57,7 @@ class LayerPathWidget : public QLabel { this->setText(layer_path.c_str()); - item->setSizeHint(QSize(0, ITEM_HEIGHT)); + item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); } QPushButton *button_edit; @@ -79,10 +79,10 @@ class LayerPathWidget : public QLabel { } public: - QListWidgetItem *item; + QTreeWidgetItem *item; }; -class TreeWidgetItemParameter : public QListWidgetItem { +class TreeWidgetItemParameter : public QTreeWidgetItem { public: TreeWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } @@ -149,24 +149,9 @@ class MainWindow : public QMainWindow { void OnHelpLayerSpec(bool checked); void OnHelpGPUInfo(bool checked); - /* - void launchItemExpanded(QTreeWidgetItem *item); - void launchItemCollapsed(QTreeWidgetItem *item); - void launchItemChanged(int index); - void launchSetLogFile(); - void launchSetExecutable(); - void launchSetWorkingFolder(); - void launchChangeLogFile(const QString &new_text); - void launchChangeExecutable(const QString &new_text); - void launchChangeWorkingFolder(const QString &new_text); - void launchArgsEdited(const QString &new_text); - */ void on_tab_widget_currentChanged(int index); - void on_push_button_launcher_clicked(); - void on_push_button_clear_log_clicked(); - void on_check_box_clear_on_launch_clicked(); - + // Configurations tabs void on_check_box_per_application_toggled(bool checked); void on_combo_box_mode_currentIndexChanged(int index); void on_combo_box_applications_currentIndexChanged(int index); @@ -182,12 +167,30 @@ class MainWindow : public QMainWindow { void on_configurations_list_itemChanged(QListWidgetItem *item); void on_configurations_list_currentRowChanged(int currentRow); - void on_layers_list_currentRowChanged(int currentRow); + void on_configurations_layers_list_currentRowChanged(int currentRow); + + // Applications tabs + void on_push_button_launcher_clicked(); + void on_push_button_clear_log_clicked(); + void on_check_box_clear_on_launch_clicked(); void standardOutputAvailable(); // stdout output is available void errorOutputAvailable(); // Layeroutput is available void processClosed(int exitCode, QProcess::ExitStatus status); // app died + /* + void launchItemExpanded(QTreeWidgetItem *item); + void launchItemCollapsed(QTreeWidgetItem *item); + void launchItemChanged(int index); + void launchSetLogFile(); + void launchSetExecutable(); + void launchSetWorkingFolder(); + void launchChangeLogFile(const QString &new_text); + void launchChangeExecutable(const QString &new_text); + void launchChangeWorkingFolder(const QString &new_text); + void launchArgsEdited(const QString &new_text); + */ + private: MainWindow(const MainWindow &) = delete; MainWindow &operator=(const MainWindow &) = delete; diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index 358e98c47f..af95938c7a 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -492,21 +492,87 @@ Layers + + 5 + + + 5 + + + 5 + + + 0 + - - - - 0 - 0 - - - - Qt::ScrollBarAlwaysOn - - - true - - + + + + + 0 + + + 0 + + + 0 + + + + + + + + + 32 + 16777215 + + + + ... + + + + + + + + 32 + 16777215 + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + true + + + false + + + + 1 + + + + + @@ -840,7 +906,7 @@ - + 0 @@ -1014,7 +1080,7 @@ 0 - + Arial diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index fe389dc849..6c9754b2b5 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -103,6 +103,12 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { continue; } + if (parameter.control == LAYER_CONTROL_OFF) { + this->tree->setEnabled(false); + } else { + this->tree->setEnabled(true); + } + if (parameter.settings.empty()) { continue; } diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index dc2d1aee38..58f718eb92 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -33,8 +33,8 @@ TabConfigurations::TabConfigurations(MainWindow &window, std::shared_ptr ui) : Tab(TAB_CONFIGURATIONS, window, ui) { ui->configurations_list->installEventFilter(&window); - ui->layers_list->installEventFilter(&window); - ui->settings_tree->installEventFilter(&window); + ui->configurations_layers_list->installEventFilter(&window); + ui->configurations_settings_tree->installEventFilter(&window); QSettings settings("LunarG", VKCONFIG_SHORT_NAME); this->ui->splitter_main->restoreState(settings.value("mainwindow/splitter_main_state").toByteArray()); @@ -57,7 +57,6 @@ void TabConfigurations::UpdateUI_Configurations(UpdateUIMode ui_update_mode) { const bool enabled_ui = mode == LAYERS_CONTROLLED_BY_CONFIGURATOR; const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); - const bool has_selected_configuration = !selected_contiguration_name.empty(); ui->combo_box_mode->blockSignals(true); ui->combo_box_mode->setCurrentIndex(mode); @@ -108,12 +107,6 @@ void TabConfigurations::UpdateUI_Configurations(UpdateUIMode ui_update_mode) { } ui->configurations_list->blockSignals(false); - - if (has_selected_configuration) { - this->_settings_tree_manager.CreateGUI(ui->settings_tree); - } else { - this->_settings_tree_manager.CleanupGUI(); - } } void TabConfigurations::UpdateUI_Applications(UpdateUIMode ui_update_mode) { @@ -175,7 +168,7 @@ void TabConfigurations::UpdateUI_LoaderMessages() { } void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { - ui->layers_list->clear(); + ui->configurations_layers_list->clear(); Configurator &configurator = Configurator::Get(); const std::string &selected_contiguration_name = configurator.environment.GetActiveConfigurationInfo().GetName(); @@ -195,9 +188,9 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { const Layer *layer = configurator.layers.Find(parameter.key); - TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(parameter.key.c_str()); + ListWidgetItemParameter *item_state = new ListWidgetItemParameter(parameter.key.c_str()); item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); - ui->layers_list->addItem(item_state); + ui->configurations_layers_list->addItem(item_state); std::vector layers; if (layer != nullptr) { @@ -205,7 +198,7 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { } ConfigurationLayerWidget *layer_widget = - new ConfigurationLayerWidget(layers, parameter, configuration->view_advanced_layers); + new ConfigurationLayerWidget(this, layers, parameter, configuration->view_advanced_layers); item_state->widget = layer_widget; if (parameter.control == LAYER_CONTROL_APPLICATIONS_API) { @@ -215,16 +208,16 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { "Located and Enabled Layers using Environment Variables by the Vulkan Application"); } - ui->layers_list->setItemWidget(item_state, layer_widget); + ui->configurations_layers_list->setItemWidget(item_state, layer_widget); if (configuration->selected_layer_name == parameter.key) { - ui->layers_list->setCurrentItem(item_state); + ui->configurations_layers_list->setCurrentItem(item_state); } } // resizeEvent(nullptr); ui->combo_box_layers_view->setCurrentIndex(configuration->view_advanced_layers); - ui->layers_list->update(); + ui->configurations_layers_list->update(); } } @@ -232,7 +225,19 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { ui->execute_closer_driver_label->setVisible(true); } -void TabConfigurations::UpdateUI_Settings(UpdateUIMode mode) {} +void TabConfigurations::UpdateUI_Settings(UpdateUIMode mode) { + Configurator &configurator = Configurator::Get(); + Environment &environment = configurator.environment; + + const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); + const bool has_selected_configuration = !selected_contiguration_name.empty(); + + if (has_selected_configuration) { + this->_settings_tree_manager.CreateGUI(ui->configurations_settings_tree); + } else { + this->_settings_tree_manager.CleanupGUI(); + } +} void TabConfigurations::UpdateUI(UpdateUIMode ui_update_mode) { this->UpdateUI_Configurations(ui_update_mode); @@ -261,7 +266,7 @@ static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { return nullptr; } - TreeWidgetItemParameter *item_parameter = static_cast(item); + ListWidgetItemParameter *item_parameter = static_cast(item); const std::string &layer_string = item_parameter->layer_name; if (!layer_string.empty()) { @@ -287,20 +292,6 @@ bool TabConfigurations::EventFilter(QObject *target, QEvent *event) { return true; } - // Launch tree does some fancy resizing and since it's down in - // layouts and splitters, we can't just rely on the resize method - // of this window. Any resize coming through needs to trigger this - // or we get drawing artifacts on macOS. - /* - if (event->type() == QEvent::Resize) { - const QRect rect = ui->launcher_tree->rect(); - ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); - ui->launcher_tree->setColumnWidth(1, rect.width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); - ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); - return false; - } - */ - if (target == ui->configurations_list) { QContextMenuEvent *right_click = dynamic_cast(event); if (right_click) { @@ -383,14 +374,14 @@ bool TabConfigurations::EventFilter(QObject *target, QEvent *event) { this->OnContextMenuExportSettingsClicked(item); } } - } else if (target == ui->layers_list) { + } else if (target == ui->configurations_layers_list) { QContextMenuEvent *right_click = dynamic_cast(event); if (right_click) { - QListWidgetItem *item = ui->layers_list->itemAt(right_click->pos()); + QListWidgetItem *item = ui->configurations_layers_list->itemAt(right_click->pos()); - const Layer *layer = GetLayer(ui->layers_list, item); + const Layer *layer = GetLayer(ui->configurations_layers_list, item); - QMenu menu(ui->layers_list); + QMenu menu(ui->configurations_layers_list); QAction *action_description = new QAction("Open the Layer Description...", nullptr); action_description->setEnabled(item != nullptr); @@ -497,7 +488,6 @@ void TabConfigurations::OnRenameConfiguration(QListWidgetItem *item) { // Rename configuration ; Remove old configuration file ; change the name of the configuration configurator.configurations.RemoveConfigurationFile(old_name); configuration->key = configuration_item->configuration_name = new_name; - configurator.configurations.SaveAllConfigurations(); configurator.environment.GetActiveConfigurationInfo().SetName(new_name); this->UpdateUI_Configurations(UPDATE_REBUILD_UI); @@ -522,13 +512,13 @@ void TabConfigurations::OnSelectLayer(int currentRow) { return; // No row selected } - QWidget *widget = ui->layers_list->itemWidget(ui->layers_list->item(currentRow)); + QWidget *widget = ui->configurations_layers_list->itemWidget(ui->configurations_layers_list->item(currentRow)); const std::string &layer_string = static_cast(widget)->text().toStdString(); Configurator &configurator = Configurator::Get(); configurator.GetActiveConfiguration()->selected_layer_name = ExtractLayerName(configurator.layers, layer_string); - this->_settings_tree_manager.CreateGUI(ui->settings_tree); + this->_settings_tree_manager.CreateGUI(ui->configurations_settings_tree); } void TabConfigurations::OnCheckedLoaderMessageTypes(bool checked) { diff --git a/vkconfig_gui/tab_configurations.h b/vkconfig_gui/tab_configurations.h index 1f4b09b97d..4e3936b36a 100644 --- a/vkconfig_gui/tab_configurations.h +++ b/vkconfig_gui/tab_configurations.h @@ -25,6 +25,18 @@ #include +class ListWidgetItemParameter : public QListWidgetItem { + public: + ListWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } + + std::string layer_name; + QWidget *widget; + + private: + ListWidgetItemParameter(const ListWidgetItemParameter &) = delete; + ListWidgetItemParameter &operator=(const ListWidgetItemParameter &) = delete; +}; + /// This just allows me to associate a specific profile definition /// with a list widget item. class ConfigurationListItem : public QListWidgetItem { From 5ebc595e8baed47dfcc9f05e108e5f294a6b1965 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 19 Aug 2024 18:33:56 +0200 Subject: [PATCH 16/33] vkconfig3: Extract layer preset from settings Change-Id: Ic6112434e96a302d75fe17bda2e47c7c7d777aec --- vkconfig_gui/mainwindow.ui | 3 + vkconfig_gui/settings_tree.cpp | 94 ++++++++++++++++++++--------- vkconfig_gui/settings_tree.h | 6 +- vkconfig_gui/tab_configurations.cpp | 4 +- 4 files changed, 76 insertions(+), 31 deletions(-) diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index af95938c7a..ff8b7e5f22 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -1136,6 +1136,9 @@ + + + diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 6c9754b2b5..074ebbdec1 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -50,9 +50,9 @@ static const char *TOOLTIP_ORDER = "Layers are executed between the Vulkan application and driver in the specific order represented here"; -SettingsTreeManager::SettingsTreeManager() : launched_application(false), tree(nullptr) {} +SettingsTreeManager::SettingsTreeManager() : launched_application(false), tree(nullptr), parameter(nullptr) {} -void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { +void SettingsTreeManager::CreateGUI(QComboBox *preset_combobox, QTreeWidget *build_tree) { assert(build_tree); // Do this first to make absolutely sure if these is an old configuration still active it's state gets saved. @@ -113,38 +113,64 @@ void SettingsTreeManager::CreateGUI(QTreeWidget *build_tree) { continue; } + this->parameter = ¶meter; + const std::vector &selected_layers = configurator.layers.selected_layers; const Layer *layer = FindByKey(selected_layers, parameter.key.c_str()); - - QTreeWidgetItem *layer_item = new QTreeWidgetItem(); - this->tree->addTopLevelItem(layer_item); - - std::string layer_text = parameter.key; - if (layer == nullptr) { - layer_text += " (Missing)"; - } else if (layer->status != STATUS_STABLE) { - layer_text += std::string(" (") + GetToken(layer->status) + ")"; - } - - layer_item->setToolTip(0, parameter.key.c_str()); // Hack for the context menu to find the layer - layer_item->setText(0, layer_text.c_str()); - layer_item->setFont(0, font_layer); - layer_item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - if (layer != nullptr) { - layer_item->setToolTip(0, layer->description.c_str()); - } - layer_item->setExpanded(parameter.control == LAYER_CONTROL_ON); - + /* + QTreeWidgetItem *layer_item = new QTreeWidgetItem(); + this->tree->addTopLevelItem(layer_item); + + std::string layer_text = parameter.key; + if (layer == nullptr) { + layer_text += " (Missing)"; + } else if (layer->status != STATUS_STABLE) { + layer_text += std::string(" (") + GetToken(layer->status) + ")"; + } + + layer_item->setToolTip(0, parameter.key.c_str()); // Hack for the context menu to find the layer + layer_item->setText(0, layer_text.c_str()); + layer_item->setFont(0, font_layer); + layer_item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); + if (layer != nullptr) { + layer_item->setToolTip(0, layer->description.c_str()); + } + layer_item->setExpanded(parameter.control == LAYER_CONTROL_ON); + */ if (layer == nullptr) { continue; } + preset_combobox->blockSignals(true); + preset_combobox->clear(); + preset_labels.clear(); if (!layer->presets.empty()) { - QTreeWidgetItem *presets_item = new QTreeWidgetItem(); - this->tree->addTopLevelItem(presets_item); - WidgetPreset *presets_combobox = new WidgetPreset(this->tree, presets_item, *layer, parameter); - this->connect(presets_combobox, SIGNAL(itemChanged()), this, SLOT(OnPresetChanged())); + preset_combobox->addItem(Layer::NO_PRESET); + preset_labels.push_back(Layer::NO_PRESET); + + for (std::size_t i = 0, n = layer->presets.size(); i < n; ++i) { + const LayerPreset &layer_preset = layer->presets[i]; + + if (!IsPlatformSupported(layer_preset.platform_flags)) { + continue; + } + if (layer_preset.view == SETTING_VIEW_HIDDEN) { + continue; + } + + preset_combobox->addItem((layer_preset.label + " Preset").c_str()); + preset_labels.push_back(layer_preset.label); + } + + // QTreeWidgetItem *presets_item = new QTreeWidgetItem(); + // this->tree->addTopLevelItem(presets_item); + // WidgetPreset *presets_combobox = new WidgetPreset(this->tree, presets_item, *layer, parameter); + this->connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPresetChanged(int))); + preset_combobox->setVisible(true); + } else { + preset_combobox->setVisible(false); } + preset_combobox->blockSignals(false); BuildGenericTree(parameter); } @@ -385,7 +411,21 @@ int SettingsTreeManager::SetTreeState(QByteArray &byte_array, int index, QTreeWi return index; } -void SettingsTreeManager::OnPresetChanged() { this->Refresh(REFRESH_ENABLE_AND_STATE); } +void SettingsTreeManager::OnPresetChanged(int combox_preset_index) { + assert(combox_preset_index >= 0 && static_cast(combox_preset_index) < preset_labels.size()); + const std::string &preset_label = preset_labels[combox_preset_index]; + + if (preset_label == Layer::NO_PRESET) return; + + Configurator &configurator = Configurator::Get(); + const Layer *layer = configurator.layers.Find(this->parameter->key.c_str()); + + const LayerPreset *preset = GetPreset(layer->presets, preset_label.c_str()); + assert(preset != nullptr); + this->parameter->ApplyPresetSettings(*preset); + + this->Refresh(REFRESH_ENABLE_AND_STATE); +} void SettingsTreeManager::OnSettingChanged() { this->Refresh(REFRESH_ENABLE_ONLY); } diff --git a/vkconfig_gui/settings_tree.h b/vkconfig_gui/settings_tree.h index bea16593e2..602d3beb61 100644 --- a/vkconfig_gui/settings_tree.h +++ b/vkconfig_gui/settings_tree.h @@ -40,7 +40,7 @@ class SettingsTreeManager : QObject { bool launched_application; - void CreateGUI(QTreeWidget *build_tree); + void CreateGUI(QComboBox *preset_combobox, QTreeWidget *build_tree); void CleanupGUI(); void GetTreeState(QByteArray &byte_array, QTreeWidgetItem *top_item); @@ -50,7 +50,7 @@ class SettingsTreeManager : QObject { public Q_SLOTS: void OnSettingChanged(); - void OnPresetChanged(); + void OnPresetChanged(int combox_preset_index); void OnExpandedChanged(const QModelIndex &index); private: @@ -62,5 +62,7 @@ class SettingsTreeManager : QObject { void RefreshItem(RefreshAreas refresh_areas, QTreeWidgetItem *parent); + std::vector preset_labels; // The preset in the combobox QTreeWidget *tree; + Parameter *parameter; }; diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index 58f718eb92..4ddae4a4fb 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -233,7 +233,7 @@ void TabConfigurations::UpdateUI_Settings(UpdateUIMode mode) { const bool has_selected_configuration = !selected_contiguration_name.empty(); if (has_selected_configuration) { - this->_settings_tree_manager.CreateGUI(ui->configurations_settings_tree); + this->_settings_tree_manager.CreateGUI(ui->configurations_presets_comboBox, ui->configurations_settings_tree); } else { this->_settings_tree_manager.CleanupGUI(); } @@ -518,7 +518,7 @@ void TabConfigurations::OnSelectLayer(int currentRow) { Configurator &configurator = Configurator::Get(); configurator.GetActiveConfiguration()->selected_layer_name = ExtractLayerName(configurator.layers, layer_string); - this->_settings_tree_manager.CreateGUI(ui->configurations_settings_tree); + this->_settings_tree_manager.CreateGUI(ui->configurations_presets_comboBox, ui->configurations_settings_tree); } void TabConfigurations::OnCheckedLoaderMessageTypes(bool checked) { From 201f7e52143f6b54dde6ff3ada755789fbced73e Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 19 Aug 2024 19:45:31 +0200 Subject: [PATCH 17/33] vkconfig3: Signal are handled by each tab Change-Id: I7ef7c99e4722827018f27b72e94a34f4ee3d8939 --- vkconfig_gui/mainwindow.cpp | 147 +++++----------------------- vkconfig_gui/mainwindow.h | 28 +----- vkconfig_gui/tab.cpp | 5 + vkconfig_gui/tab.h | 8 +- vkconfig_gui/tab_configurations.cpp | 115 ++++++++++++++++++++++ vkconfig_gui/tab_configurations.h | 21 ++++ 6 files changed, 173 insertions(+), 151 deletions(-) diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 460c9a6b98..25fa4f7279 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -65,19 +65,12 @@ MainWindow::MainWindow(QWidget *parent) this->InitTray(); - this->tab_diagnostic.reset(new TabDiagnostics(*this, ui)); - this->tab_applications.reset(new TabApplications(*this, ui)); - this->tab_layers.reset(new TabLayers(*this, ui)); - this->tab_configurations.reset(new TabConfigurations(*this, ui)); - this->tab_preferences.reset(new TabPreferences(*this, ui)); - this->tab_help.reset(new TabHelp(*this, ui)); - - this->tabs[TAB_DIAGNOSTIC] = this->tab_diagnostic; - this->tabs[TAB_APPLICATIONS] = this->tab_applications; - this->tabs[TAB_LAYERS] = this->tab_layers; - this->tabs[TAB_CONFIGURATIONS] = this->tab_configurations; - this->tabs[TAB_PREFERENCES] = this->tab_preferences; - this->tabs[TAB_HELP] = this->tab_help; + this->tabs[TAB_DIAGNOSTIC].reset(new TabDiagnostics(*this, ui)); + this->tabs[TAB_APPLICATIONS].reset(new TabApplications(*this, ui)); + this->tabs[TAB_LAYERS].reset(new TabLayers(*this, ui)); + this->tabs[TAB_CONFIGURATIONS].reset(new TabConfigurations(*this, ui)); + this->tabs[TAB_PREFERENCES].reset(new TabPreferences(*this, ui)); + this->tabs[TAB_HELP].reset(new TabHelp(*this, ui)); connect(ui->action_find_more_layers, SIGNAL(triggered(bool)), this, SLOT(OnHelpFindLayers(bool))); connect(ui->actionAbout, SIGNAL(triggered(bool)), this, SLOT(OnHelpAbout(bool))); @@ -106,6 +99,7 @@ MainWindow::MainWindow(QWidget *parent) this->restoreState(settings.value("mainwindow/state").toByteArray()); this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); + this->UpdateUI_Status(); this->UpdateUI(); } @@ -116,25 +110,20 @@ void MainWindow::InitTray() { if (QSystemTrayIcon::isSystemTrayAvailable()) { this->_tray_quit_action = new QAction("&Quit", this); connect(this->_tray_quit_action, &QAction::triggered, qApp, &QCoreApplication::quit); - this->_tray_restore_action = new QAction("Open &Vulkan Configurator", this); connect(this->_tray_restore_action, &QAction::triggered, this, &MainWindow::trayActionRestore); - this->_tray_layers_controlled_by_applications = new QAction("Layers Controlled by the Vulkan Applications", this); this->_tray_layers_controlled_by_applications->setCheckable(true); connect(this->_tray_layers_controlled_by_applications, &QAction::toggled, this, &MainWindow::trayActionControlledByApplications); - this->_tray_layers_controlled_by_configurator = new QAction("Layers Controlled by the Vulkan Configurator", this); this->_tray_layers_controlled_by_configurator->setCheckable(true); connect(this->_tray_layers_controlled_by_configurator, &QAction::toggled, this, &MainWindow::trayActionControlledByConfigurator); - this->_tray_layers_disabled_by_configurator = new QAction("Layers Disabled by the Vulkan Configurator", this); this->_tray_layers_disabled_by_configurator->setCheckable(true); connect(this->_tray_layers_disabled_by_configurator, &QAction::toggled, this, &MainWindow::trayActionDisabledByApplications); - this->_tray_icon_menu = new QMenu(this); this->_tray_icon_menu->addAction(this->_tray_restore_action); this->_tray_icon_menu->addSeparator(); @@ -143,12 +132,10 @@ void MainWindow::InitTray() { this->_tray_icon_menu->addAction(this->_tray_layers_disabled_by_configurator); this->_tray_icon_menu->addSeparator(); this->_tray_icon_menu->addAction(this->_tray_quit_action); - this->_tray_icon = new QSystemTrayIcon(this); this->_tray_icon->setContextMenu(this->_tray_icon_menu); this->UpdateUI_Status(); this->_tray_icon->show(); - this->connect(this->_tray_icon, &QSystemTrayIcon::activated, this, &MainWindow::iconActivated); } } @@ -156,7 +143,6 @@ void MainWindow::InitTray() { void MainWindow::UpdateUI_Status() { const Configurator &configurator = Configurator::Get(); const Environment &environment = configurator.environment; - const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); const bool has_selected_configuration = !selected_contiguration_name.empty(); const bool has_active_configuration = configurator.HasActiveConfiguration() && has_selected_configuration; @@ -169,7 +155,6 @@ void MainWindow::UpdateUI_Status() { #endif this->setWindowTitle(GetMainWindowTitle(has_active_configuration, display_date).c_str()); - if (QSystemTrayIcon::isSystemTrayAvailable()) { switch (environment.GetActiveConfigurationInfo().GetMode()) { default: @@ -193,18 +178,14 @@ void MainWindow::UpdateUI_Status() { if (has_active_configuration && environment.GetActiveConfigurationInfo().GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { const QIcon icon(":/resourcefiles/vkconfig-on.png"); - this->setWindowIcon(icon); - if (QSystemTrayIcon::isSystemTrayAvailable()) { this->_tray_icon->setIcon(icon); this->_tray_icon->setToolTip("Layers controlled by the Vulkan Configurator"); } } else { const QIcon icon(":/resourcefiles/vkconfig-off.png"); - this->setWindowIcon(icon); - if (QSystemTrayIcon::isSystemTrayAvailable()) { this->_tray_icon->setIcon(icon); this->_tray_icon->setToolTip("Layers controlled by the Vulkan Applications"); @@ -220,11 +201,9 @@ void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { break; case QSystemTrayIcon::DoubleClick: Qt::WindowStates window_states = this->windowState(); - const bool is_minimized = this->isMinimized(); const bool is_visible = this->isVisible(); const bool is_hidden = this->isHidden(); - if (this->isMinimized() || this->isHidden()) { this->setVisible(true); this->showNormal(); @@ -233,6 +212,7 @@ void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { this->hide(); } + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); this->UpdateUI_Status(); break; } @@ -241,19 +221,21 @@ void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { void MainWindow::trayActionRestore() { this->hide(); this->showNormal(); - this->UpdateUI(); + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); this->UpdateUI_Status(); } void MainWindow::trayActionControlledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); + if (this->tabs[this->ui->tab_widget->currentIndex()] != nullptr) { + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); + } this->UpdateUI_Status(); } } @@ -261,11 +243,13 @@ void MainWindow::trayActionControlledByApplications(bool checked) { void MainWindow::trayActionControlledByConfigurator(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_CONTROLLED_BY_CONFIGURATOR); configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); + if (this->tabs[this->ui->tab_widget->currentIndex()] != nullptr) { + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); + } this->UpdateUI_Status(); } } @@ -273,11 +257,13 @@ void MainWindow::trayActionControlledByConfigurator(bool checked) { void MainWindow::trayActionDisabledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_DISABLED_BY_CONFIGURATOR); configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); + if (this->tabs[this->ui->tab_widget->currentIndex()] != nullptr) { + this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); + } this->UpdateUI_Status(); } } @@ -315,7 +301,7 @@ void MainWindow::UpdateUI() { ui->check_box_clear_on_launch->setChecked(environment.launcher_clear_on_launch); // Mode states - this->UpdateUI_Status(); + // this->UpdateUI_Status(); ui->configurations_list->blockSignals(false); this->blockSignals(false); @@ -323,85 +309,10 @@ void MainWindow::UpdateUI() { --check_recurse; } -void MainWindow::on_combo_box_mode_currentIndexChanged(int index) { - Configurator &configurator = Configurator::Get(); - - configurator.environment.GetActiveConfigurationInfo().SetMode(static_cast(index)); - configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); - - this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); - - this->UpdateUI_Status(); - this->UpdateUI(); -} - -void MainWindow::on_combo_box_applications_currentIndexChanged(int index) { - Configurator &configurator = Configurator::Get(); - configurator.environment.SelectActiveApplication(index); - - this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); - - this->UpdateUI_Status(); - this->UpdateUI(); -} - -void MainWindow::on_check_box_per_application_toggled(bool checked) { - Configurator &configurator = Configurator::Get(); - - configurator.environment.SetPerApplicationConfig(checked); - configurator.Override(OVERRIDE_AREA_ALL); - - this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); - - this->UpdateUI_Status(); - this->UpdateUI(); -} - -void MainWindow::on_configuration_loader_errors_checkBox_toggled(bool checked) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnCheckedLoaderMessageTypes(checked); -} - -void MainWindow::on_configuration_loader_warns_checkBox_toggled(bool checked) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnCheckedLoaderMessageTypes(checked); -} - -void MainWindow::on_configuration_loader_infos_checkBox_toggled(bool checked) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnCheckedLoaderMessageTypes(checked); -} - -void MainWindow::on_configuration_loader_debug_checkBox_toggled(bool checked) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnCheckedLoaderMessageTypes(checked); -} - -void MainWindow::on_configuration_loader_layers_checkBox_toggled(bool checked) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnCheckedLoaderMessageTypes(checked); -} - -void MainWindow::on_configuration_loader_drivers_checkBox_toggled(bool checked) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnCheckedLoaderMessageTypes(checked); -} - void MainWindow::on_check_box_clear_on_launch_clicked() { Configurator::Get().environment.launcher_clear_on_launch = ui->check_box_clear_on_launch->isChecked(); } -void MainWindow::on_combo_box_layers_view_currentIndexChanged(int index) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - - Configurator &configurator = Configurator::Get(); - - Configuration *configuration = configurator.GetActiveConfiguration(); - configuration->view_advanced_layers = index != 0; - - this->tab_configurations->UpdateUI_Layers(UPDATE_REBUILD_UI); -} - void MainWindow::toolsResetToDefault(bool checked) { (void)checked; @@ -554,22 +465,6 @@ void MainWindow::showEvent(QShowEvent *event) { event->accept(); } -/// An item has been changed. Check for edit of the items name (configuration name) -void MainWindow::on_configurations_list_itemChanged(QListWidgetItem *item) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnRenameConfiguration(item); -} - -void MainWindow::on_configurations_list_currentRowChanged(int currentRow) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnSelectConfiguration(currentRow); -} - -void MainWindow::on_configurations_layers_list_currentRowChanged(int currentRow) { - assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); - this->tab_configurations->OnSelectLayer(currentRow); -} - // Clear the browser window void MainWindow::on_push_button_clear_log_clicked() { ui->log_browser->clear(); @@ -578,6 +473,10 @@ void MainWindow::on_push_button_clear_log_clicked() { } bool MainWindow::eventFilter(QObject *target, QEvent *event) { + if (this->tabs[this->ui->tab_widget->currentIndex()] == nullptr) { + return false; + } + return this->tabs[this->ui->tab_widget->currentIndex()]->EventFilter(target, event); } diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 4fe4233eb4..2d238c88bc 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -151,24 +151,6 @@ class MainWindow : public QMainWindow { void on_tab_widget_currentChanged(int index); - // Configurations tabs - void on_check_box_per_application_toggled(bool checked); - void on_combo_box_mode_currentIndexChanged(int index); - void on_combo_box_applications_currentIndexChanged(int index); - - void on_combo_box_layers_view_currentIndexChanged(int index); - - void on_configuration_loader_errors_checkBox_toggled(bool checked); - void on_configuration_loader_warns_checkBox_toggled(bool checked); - void on_configuration_loader_infos_checkBox_toggled(bool checked); - void on_configuration_loader_debug_checkBox_toggled(bool checked); - void on_configuration_loader_layers_checkBox_toggled(bool checked); - void on_configuration_loader_drivers_checkBox_toggled(bool checked); - - void on_configurations_list_itemChanged(QListWidgetItem *item); - void on_configurations_list_currentRowChanged(int currentRow); - void on_configurations_layers_list_currentRowChanged(int currentRow); - // Applications tabs void on_push_button_launcher_clicked(); void on_push_button_clear_log_clicked(); @@ -191,23 +173,17 @@ class MainWindow : public QMainWindow { void launchArgsEdited(const QString &new_text); */ + void UpdateUI_Status(); + private: MainWindow(const MainWindow &) = delete; MainWindow &operator=(const MainWindow &) = delete; void InitTray(); - void UpdateUI_Status(); - void ResetLaunchApplication(); void StartTool(Tool tool); QStringList BuildEnvVariables() const; std::shared_ptr ui; std::array, TAB_COUNT> tabs; - std::shared_ptr tab_diagnostic; - std::shared_ptr tab_applications; - std::shared_ptr tab_layers; - std::shared_ptr tab_configurations; - std::shared_ptr tab_preferences; - std::shared_ptr tab_help; }; diff --git a/vkconfig_gui/tab.cpp b/vkconfig_gui/tab.cpp index 2ab64f10dd..da75be4d6b 100644 --- a/vkconfig_gui/tab.cpp +++ b/vkconfig_gui/tab.cpp @@ -21,6 +21,11 @@ #include "tab.h" #include "mainwindow.h" +#include "../vkconfig_core/configurator.h" +#include "../vkconfig_core/ui.h" + +#include + Tab::Tab(TabType type, MainWindow& window, std::shared_ptr ui) : type(type), window(window), ui(ui) {} Tab::~Tab() {} diff --git a/vkconfig_gui/tab.h b/vkconfig_gui/tab.h index cbadc50f0c..0741f62bf9 100644 --- a/vkconfig_gui/tab.h +++ b/vkconfig_gui/tab.h @@ -26,6 +26,9 @@ #include "ui_mainwindow.h" +#include +#include + class MainWindow; enum UpdateUIMode { @@ -33,7 +36,10 @@ enum UpdateUIMode { UPDATE_REFRESH_UI, }; -struct Tab { +struct Tab : public QObject { + Q_OBJECT + + public: Tab(TabType type, MainWindow& window, std::shared_ptr ui); virtual ~Tab(); diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index 4ddae4a4fb..b995667f94 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -36,6 +36,36 @@ TabConfigurations::TabConfigurations(MainWindow &window, std::shared_ptrconfigurations_layers_list->installEventFilter(&window); ui->configurations_settings_tree->installEventFilter(&window); + this->connect(this->ui->check_box_per_application, SIGNAL(toggled(bool)), this, + SLOT(on_check_box_per_application_toggled(bool))); + this->connect(this->ui->combo_box_mode, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_combo_box_mode_currentIndexChanged(int))); + this->connect(this->ui->combo_box_applications, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_combo_box_applications_currentIndexChanged(int))); + + this->connect(this->ui->combo_box_layers_view, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_combo_box_layers_view_currentIndexChanged(int))); + + this->connect(this->ui->configuration_loader_errors_checkBox, SIGNAL(toggled(bool)), this, + SLOT(on_configuration_loader_errors_checkBox_toggled(bool))); + this->connect(this->ui->configuration_loader_warns_checkBox, SIGNAL(toggled(bool)), this, + SLOT(on_configuration_loader_warns_checkBox_toggled(bool))); + this->connect(this->ui->configuration_loader_infos_checkBox, SIGNAL(toggled(bool)), this, + SLOT(on_configuration_loader_infos_checkBox_toggled(bool))); + this->connect(this->ui->configuration_loader_debug_checkBox, SIGNAL(toggled(bool)), this, + SLOT(on_configuration_loader_debug_checkBox_toggled(bool))); + this->connect(this->ui->configuration_loader_layers_checkBox, SIGNAL(toggled(bool)), this, + SLOT(on_configuration_loader_layers_checkBox_toggled(bool))); + this->connect(this->ui->configuration_loader_drivers_checkBox, SIGNAL(toggled(bool)), this, + SLOT(on_configuration_loader_drivers_checkBox_toggled(bool))); + + this->connect(this->ui->configurations_list, SIGNAL(itemChanged(QListWidgetItem *)), this, + SLOT(on_configurations_list_itemChanged(QListWidgetItem *))); + this->connect(this->ui->configurations_list, SIGNAL(currentRowChanged(int)), this, + SLOT(on_configurations_list_currentRowChanged(int))); + this->connect(this->ui->configurations_layers_list, SIGNAL(currentRowChanged(int)), this, + SLOT(on_configurations_layers_list_currentRowChanged(int))); + QSettings settings("LunarG", VKCONFIG_SHORT_NAME); this->ui->splitter_main->restoreState(settings.value("mainwindow/splitter_main_state").toByteArray()); this->ui->splitter_configurations->restoreState(settings.value("mainwindow/splitter_configurations_state").toByteArray()); @@ -699,3 +729,88 @@ void TabConfigurations::OnContextMenuExportSettingsClicked(ConfigurationListItem Configurator &configurator = Configurator::Get(); // TODO } + +void TabConfigurations::on_combo_box_mode_currentIndexChanged(int index) { + Configurator &configurator = Configurator::Get(); + + configurator.environment.GetActiveConfigurationInfo().SetMode(static_cast(index)); + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + + this->UpdateUI(UPDATE_REFRESH_UI); + this->window.UpdateUI_Status(); +} + +void TabConfigurations::on_combo_box_applications_currentIndexChanged(int index) { + Configurator &configurator = Configurator::Get(); + configurator.environment.SelectActiveApplication(index); + + this->UpdateUI(UPDATE_REFRESH_UI); + this->window.UpdateUI_Status(); +} + +void TabConfigurations::on_check_box_per_application_toggled(bool checked) { + Configurator &configurator = Configurator::Get(); + + configurator.environment.SetPerApplicationConfig(checked); + configurator.Override(OVERRIDE_AREA_ALL); + + this->UpdateUI(UPDATE_REFRESH_UI); + this->window.UpdateUI_Status(); +} + +void TabConfigurations::on_configuration_loader_errors_checkBox_toggled(bool checked) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnCheckedLoaderMessageTypes(checked); +} + +void TabConfigurations::on_configuration_loader_warns_checkBox_toggled(bool checked) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnCheckedLoaderMessageTypes(checked); +} + +void TabConfigurations::on_configuration_loader_infos_checkBox_toggled(bool checked) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnCheckedLoaderMessageTypes(checked); +} + +void TabConfigurations::on_configuration_loader_debug_checkBox_toggled(bool checked) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnCheckedLoaderMessageTypes(checked); +} + +void TabConfigurations::on_configuration_loader_layers_checkBox_toggled(bool checked) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnCheckedLoaderMessageTypes(checked); +} + +void TabConfigurations::on_configuration_loader_drivers_checkBox_toggled(bool checked) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnCheckedLoaderMessageTypes(checked); +} + +void TabConfigurations::on_combo_box_layers_view_currentIndexChanged(int index) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + + Configurator &configurator = Configurator::Get(); + + Configuration *configuration = configurator.GetActiveConfiguration(); + configuration->view_advanced_layers = index != 0; + + this->UpdateUI_Layers(UPDATE_REBUILD_UI); +} + +/// An item has been changed. Check for edit of the items name (configuration name) +void TabConfigurations::on_configurations_list_itemChanged(QListWidgetItem *item) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnRenameConfiguration(item); +} + +void TabConfigurations::on_configurations_list_currentRowChanged(int currentRow) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnSelectConfiguration(currentRow); +} + +void TabConfigurations::on_configurations_layers_list_currentRowChanged(int currentRow) { + assert(this->ui->tab_widget->currentIndex() == TAB_CONFIGURATIONS); + this->OnSelectLayer(currentRow); +} diff --git a/vkconfig_gui/tab_configurations.h b/vkconfig_gui/tab_configurations.h index 4e3936b36a..ce81312f68 100644 --- a/vkconfig_gui/tab_configurations.h +++ b/vkconfig_gui/tab_configurations.h @@ -53,6 +53,9 @@ class ConfigurationListItem : public QListWidgetItem { }; struct TabConfigurations : public Tab { + Q_OBJECT + + public: TabConfigurations(MainWindow &window, std::shared_ptr ui); virtual ~TabConfigurations(); @@ -71,6 +74,24 @@ struct TabConfigurations : public Tab { void UpdateUI_Layers(UpdateUIMode ui_update_mode); void UpdateUI_Settings(UpdateUIMode ui_update_mode); + public Q_SLOTS: + void on_check_box_per_application_toggled(bool checked); + void on_combo_box_mode_currentIndexChanged(int index); + void on_combo_box_applications_currentIndexChanged(int index); + + void on_combo_box_layers_view_currentIndexChanged(int index); + + void on_configuration_loader_errors_checkBox_toggled(bool checked); + void on_configuration_loader_warns_checkBox_toggled(bool checked); + void on_configuration_loader_infos_checkBox_toggled(bool checked); + void on_configuration_loader_debug_checkBox_toggled(bool checked); + void on_configuration_loader_layers_checkBox_toggled(bool checked); + void on_configuration_loader_drivers_checkBox_toggled(bool checked); + + void on_configurations_list_itemChanged(QListWidgetItem *item); + void on_configurations_list_currentRowChanged(int currentRow); + void on_configurations_layers_list_currentRowChanged(int currentRow); + private: SettingsTreeManager _settings_tree_manager; From ddc10d2392218270b80f57580d75a5332adda586 Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 23 Aug 2024 18:14:41 +0200 Subject: [PATCH 18/33] vkconfig3: Implement layers paths tab --- vkconfig_cmd/main_layers.cpp | 41 +-- vkconfig_cmd/main_reset.cpp | 4 +- vkconfig_core/application.h | 2 - vkconfig_core/configuration_info.h | 20 +- vkconfig_core/configuration_manager.cpp | 161 +++++++++- vkconfig_core/configuration_manager.h | 34 ++- vkconfig_core/configurator.cpp | 180 +++++++----- vkconfig_core/configurator.h | 9 +- vkconfig_core/environment.cpp | 274 +++++------------- vkconfig_core/environment.h | 33 +-- vkconfig_core/layer_manager.cpp | 132 ++++++++- vkconfig_core/layer_manager.h | 31 +- vkconfig_core/path.cpp | 20 +- vkconfig_core/serialization.h | 29 ++ .../test/test_configuration_built_in.cpp | 8 +- .../test/test_configuration_manager.cpp | 8 +- vkconfig_core/test/test_environment.cpp | 14 +- vkconfig_core/test/test_layer_manager.cpp | 30 +- vkconfig_core/test/test_ui.cpp | 6 +- vkconfig_core/type_layer_type.cpp | 2 +- vkconfig_gui/main.cpp | 4 +- vkconfig_gui/mainwindow.cpp | 49 +--- vkconfig_gui/mainwindow.h | 55 +--- vkconfig_gui/mainwindow.ui | 4 +- vkconfig_gui/tab.h | 5 +- vkconfig_gui/tab_applications.h | 7 + vkconfig_gui/tab_configurations.cpp | 68 ++--- vkconfig_gui/tab_diagnostics.h | 7 + vkconfig_gui/tab_help.h | 7 + vkconfig_gui/tab_layers.cpp | 66 ++++- vkconfig_gui/tab_layers.h | 9 +- vkconfig_gui/tab_preferences.h | 7 + ...pp => widget_tab_configurations_layer.cpp} | 56 ++-- ...et.h => widget_tab_configurations_layer.h} | 3 +- vkconfig_gui/widget_tab_layers_path.cpp | 68 +++++ vkconfig_gui/widget_tab_layers_path.h | 44 +++ 36 files changed, 877 insertions(+), 620 deletions(-) create mode 100644 vkconfig_core/serialization.h rename vkconfig_gui/{configuration_layer_widget.cpp => widget_tab_configurations_layer.cpp} (81%) rename vkconfig_gui/{configuration_layer_widget.h => widget_tab_configurations_layer.h} (90%) create mode 100644 vkconfig_gui/widget_tab_layers_path.cpp create mode 100644 vkconfig_gui/widget_tab_layers_path.h diff --git a/vkconfig_cmd/main_layers.cpp b/vkconfig_cmd/main_layers.cpp index cd19a58a84..f4f8fc983a 100644 --- a/vkconfig_cmd/main_layers.cpp +++ b/vkconfig_cmd/main_layers.cpp @@ -26,9 +26,7 @@ #include -static int RunLayersOverride(const CommandLine& command_line) { - Configurator& configurator = Configurator::Get(); - +static int RunLayersOverride(Configurator& configurator, const CommandLine& command_line) { Configuration configuration; const bool load_result = configuration.Load(command_line.layers_configuration_path.c_str(), configurator.layers.selected_layers); @@ -39,8 +37,6 @@ static int RunLayersOverride(const CommandLine& command_line) { const bool override_result = configurator.Override(OVERRIDE_AREA_ALL); - configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit - if (override_result) { printf("\nLayers configuration \"%s\" applied to all Vulkan Applications, including Vulkan layers:\n", command_line.layers_configuration_path.c_str()); @@ -60,14 +56,10 @@ static int RunLayersOverride(const CommandLine& command_line) { return override_result ? 0 : -1; } -static int RunLayersSurrender(const CommandLine& command_line) { - Configurator& configurator = Configurator::Get(); - +static int RunLayersSurrender(Configurator& configurator, const CommandLine& command_line) { const bool has_overridden_layers = configurator.HasOverride(); const bool surrender_result = configurator.Surrender(OVERRIDE_AREA_ALL); - configurator.environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit - if (has_overridden_layers) { if (surrender_result) { printf("\nFull Vulkan layers control returned to Vulkan applications.\n"); @@ -82,14 +74,12 @@ static int RunLayersSurrender(const CommandLine& command_line) { return surrender_result ? 0 : -1; } -static int RunLayersList(const CommandLine& command_line) { - LayerManager layers; - - if (layers.selected_layers.empty()) { +static int RunLayersList(Configurator& configurator, const CommandLine& command_line) { + if (configurator.layers.selected_layers.empty()) { printf("No Vulkan layer found\n"); } else { - for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { - const Layer& layer = layers.selected_layers[i]; + for (std::size_t i = 0, n = configurator.layers.selected_layers.size(); i < n; ++i) { + const Layer& layer = configurator.layers.selected_layers[i]; printf("%s\n", layer.key.c_str()); } @@ -98,11 +88,9 @@ static int RunLayersList(const CommandLine& command_line) { return 0; } -static int RunLayersVerbose(const CommandLine& command_line) { - LayerManager layers; - - for (std::size_t i = 0, n = layers.selected_layers.size(); i < n; ++i) { - const Layer& layer = layers.selected_layers[i]; +static int RunLayersVerbose(Configurator& configurator, const CommandLine& command_line) { + for (std::size_t i = 0, n = configurator.layers.selected_layers.size(); i < n; ++i) { + const Layer& layer = configurator.layers.selected_layers[i]; printf("%s (%s) %s-%s\n", layer.key.c_str(), GetToken(layer.type), layer.api_version.str().c_str(), layer.implementation_version.c_str()); @@ -118,18 +106,21 @@ int run_layers(const CommandLine& command_line) { assert(command_line.command == COMMAND_LAYERS); assert(command_line.error == ERROR_NONE); + Configurator& configurator = Configurator::Get(); + configurator.Init(Configurator::CMD); + switch (command_line.command_layers_arg) { case COMMAND_LAYERS_OVERRIDE: { - return RunLayersOverride(command_line); + return RunLayersOverride(configurator, command_line); } case COMMAND_LAYERS_SURRENDER: { - return RunLayersSurrender(command_line); + return RunLayersSurrender(configurator, command_line); } case COMMAND_LAYERS_LIST: { - return RunLayersList(command_line); + return RunLayersList(configurator, command_line); } case COMMAND_LAYERS_VERBOSE: { - return RunLayersVerbose(command_line); + return RunLayersVerbose(configurator, command_line); } default: { assert(0); diff --git a/vkconfig_cmd/main_reset.cpp b/vkconfig_cmd/main_reset.cpp index e3f342a84d..cd9a85adc3 100644 --- a/vkconfig_cmd/main_reset.cpp +++ b/vkconfig_cmd/main_reset.cpp @@ -52,7 +52,9 @@ static int RunReset(int argc, char* argv[], bool hard) { QApplication app(argc, argv); - Configurator::Get().ResetToDefault(hard); + Configurator& configurator = Configurator::Get(); + configurator.Init(Configurator::CMD); + configurator.Reset(); return 0; } diff --git a/vkconfig_core/application.h b/vkconfig_core/application.h index 3486813625..e230db59ff 100644 --- a/vkconfig_core/application.h +++ b/vkconfig_core/application.h @@ -22,7 +22,6 @@ #include "type_layers_mode.h" #include "path.h" -#include "configuration_info.h" #include #include @@ -37,7 +36,6 @@ struct ApplicationOptions { struct Application { Path executable_path; - ConfigurationInfo configuration; int active_option_index = 0; std::vector options; diff --git a/vkconfig_core/configuration_info.h b/vkconfig_core/configuration_info.h index 73460fed92..63852d83f9 100644 --- a/vkconfig_core/configuration_info.h +++ b/vkconfig_core/configuration_info.h @@ -24,25 +24,7 @@ #include -class ConfigurationInfo { - private: +struct ConfigurationInfo { std::string name = "Validation"; LayersMode mode = LAYERS_CONTROLLED_BY_CONFIGURATOR; - - public: - const char* GetName() const { return this->name.c_str(); } - - void SetName(const std::string& new_configuration_name) { - if (this->name != new_configuration_name) { - this->name = new_configuration_name; - } - } - - LayersMode GetMode() const { return this->mode; } - - void SetMode(LayersMode new_configuration_mode) { - if (this->mode != new_configuration_mode) { - this->mode = new_configuration_mode; - } - } }; diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index a9e22509e3..d936a528d4 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -23,10 +23,94 @@ #include "configurator.h" #include "alert.h" +const char *GLOBAL_CONFIGURATION_TOKEN = "GLOBAL"; + ConfigurationManager::ConfigurationManager() {} ConfigurationManager::~ConfigurationManager() {} +bool ConfigurationManager::Load(const QJsonObject &json_root_object) { + // configurations json object + if (json_root_object.value("configurations") != QJsonValue::Undefined) { + const QJsonObject &json_configurations_object = json_root_object.value("configurations").toObject(); + this->use_per_application_configuration = json_configurations_object.value("use_per_application").toBool(); + this->use_system_tray = json_configurations_object.value("use_system_tray").toBool(); + this->active_application = json_configurations_object.value("active_application").toString().toStdString(); + + if (json_configurations_object.value("infos") != QJsonValue::Undefined) { + const QJsonObject &json_infos_object = json_configurations_object.value("infos").toObject(); + const QStringList &json_infos_keys = json_infos_object.keys(); + for (int i = 0, n = json_infos_keys.length(); i < n; ++i) { + const std::string &key = json_infos_keys[i].toStdString(); + const QJsonObject &json_info_object = json_infos_object.value(key.c_str()).toObject(); + ConfigurationInfo info; + info.name = json_info_object.value("name").toString().toStdString(); + info.mode = ::GetLayersMode(json_info_object.value("mode").toString().toStdString().c_str()); + this->configuration_infos.insert(std::make_pair(key, info)); + } + } + + if (json_configurations_object.value("removed_builtin") != QJsonValue::Undefined) { + const QJsonObject &json_removed_builtin_object = json_configurations_object.value("removed_builtin").toObject(); + const QStringList &json_removed_builtin_keys = json_removed_builtin_object.keys(); + + for (int i = 0, n = json_removed_builtin_keys.length(); i < n; ++i) { + const std::string &key = json_removed_builtin_keys[i].toStdString(); + const int version = json_removed_builtin_object.value(key.c_str()).toInt(); + this->removed_built_in_configuration.insert(std::make_pair(key, version)); + } + } + } + + this->LoadAllConfigurations(Configurator::Get().layers.selected_layers); + + return true; +} + +bool ConfigurationManager::Save(QJsonObject &json_root_object) const { + this->SaveAllConfigurations(); + + QJsonObject json_removed_builtin_configurations_object; + for (auto it = this->removed_built_in_configuration.begin(), end = this->removed_built_in_configuration.end(); it != end; + ++it) { + json_removed_builtin_configurations_object.insert(it->first.c_str(), it->second); + } + + QJsonObject json_infos_object; + for (auto it = this->configuration_infos.begin(), end = this->configuration_infos.end(); it != end; ++it) { + QJsonObject json_info_object; + json_info_object.insert("name", it->second.name.c_str()); + json_info_object.insert("mode", GetToken(it->second.mode)); + json_infos_object.insert(it->first.c_str(), json_info_object); + } + + QJsonObject json_configurations_object; + json_configurations_object.insert("use_per_application", this->use_per_application_configuration); + json_configurations_object.insert("use_system_tray", this->use_system_tray); + json_configurations_object.insert("active_application", this->active_application.c_str()); + json_configurations_object.insert("infos", json_infos_object); + json_configurations_object.insert("removed_builtin", json_removed_builtin_configurations_object); + + json_root_object.insert("configurations", json_configurations_object); + + return true; +} + +void ConfigurationManager::Reset() { + this->removed_built_in_configuration.clear(); + this->use_per_application_configuration = false; + this->use_system_tray = false; + this->active_application.clear(); + this->configuration_infos.clear(); + this->available_configurations.clear(); + + this->LoadDefaultConfigurations(Configurator::Get().layers.selected_layers); + this->SortConfigurations(); + + ConfigurationInfo info; + this->configuration_infos.insert(std::make_pair(GLOBAL_CONFIGURATION_TOKEN, info)); +} + void ConfigurationManager::LoadAllConfigurations(const std::vector &available_layers) { this->available_configurations.clear(); @@ -71,7 +155,7 @@ void ConfigurationManager::LoadDefaultConfigurations(const std::vector &a } } else if (found_configuration->version < configuration.version) { // Replaced the old configuration by the new one - this->RemoveConfiguration(available_layers, found_configuration->key); + this->RemoveConfiguration(found_configuration->key); this->available_configurations.push_back(configuration); } } @@ -115,13 +199,57 @@ static Path MakeConfigurationPath(const std::string &key) { return path.AbsolutePath(); } -void ConfigurationManager::SaveAllConfigurations() { +void ConfigurationManager::SaveAllConfigurations() const { for (std::size_t i = 0, n = available_configurations.size(); i < n; ++i) { const Path &path(MakeConfigurationPath(available_configurations[i].key)); available_configurations[i].Save(path); } } +const ConfigurationInfo *ConfigurationManager::GetActiveConfigurationInfo() const { + if (this->use_per_application_configuration) { + return &this->configuration_infos.find(this->active_application.c_str())->second; + } else { + return &this->configuration_infos.find(GLOBAL_CONFIGURATION_TOKEN)->second; + } +} + +ConfigurationInfo *ConfigurationManager::GetActiveConfigurationInfo() { + if (this->use_per_application_configuration) { + return &this->configuration_infos.find(this->active_application.c_str())->second; + } else { + return &this->configuration_infos.find(GLOBAL_CONFIGURATION_TOKEN)->second; + } +} + +const ConfigurationInfo *ConfigurationManager::FindConfigurationInfo(const std::string &key) const { + for (auto it = this->configuration_infos.begin(), end = this->configuration_infos.end(); it != end; ++it) { + if (it->first == key) { + return &it->second; + } + } + + return nullptr; +} + +const std::map &ConfigurationManager::GetConfigurationInfos() const { + return this->configuration_infos; +} + +bool ConfigurationManager::HasActiveConfiguration() const { + if (this->GetActiveConfigurationInfo() == nullptr) { + return false; + } + + for (auto it = configuration_infos.begin(), end = configuration_infos.end(); it != end; ++it) { + if (it->second.mode != LAYERS_CONTROLLED_BY_APPLICATIONS) { + return true; + } + } + + return false; +} + Configuration &ConfigurationManager::CreateConfiguration(const std::vector &available_layers, const std::string &configuration_name, bool duplicate) { Configuration *duplicate_configuration = FindByKey(available_configurations, configuration_name.c_str()); @@ -140,6 +268,8 @@ Configuration &ConfigurationManager::CreateConfiguration(const std::vectoravailable_configurations.push_back(configuration); this->SortConfigurations(); + this->GetActiveConfigurationInfo()->name = configuration.key; + return *FindByKey(this->available_configurations, configuration.key.c_str()); } @@ -173,7 +303,7 @@ void ConfigurationManager::RemoveConfigurationFile(const std::string &key) { } } -void ConfigurationManager::RemoveConfiguration(const std::vector &available_layers, const std::string &configuration_name) { +void ConfigurationManager::RemoveConfiguration(const std::string &configuration_name) { assert(!configuration_name.empty()); RemoveConfigurationFile(configuration_name.c_str()); @@ -196,6 +326,10 @@ void ConfigurationManager::RemoveConfiguration(const std::vector &availab std::swap(updated_configurations, this->available_configurations); this->SortConfigurations(); + + if (this->GetActiveConfigurationInfo()->name == configuration_name) { + this->GetActiveConfigurationInfo()->name.clear(); + } } Configuration *ConfigurationManager::FindConfiguration(const std::string &configuration_name) { @@ -222,7 +356,7 @@ const Configuration *ConfigurationManager::FindConfiguration(const std::string & return FindByKey(this->available_configurations, configuration_name.c_str()); } -std::string ConfigurationManager::ImportConfiguration(const std::vector &available_layers, const Path &full_import_path) { +void ConfigurationManager::ImportConfiguration(const std::vector &available_layers, const Path &full_import_path) { assert(!full_import_path.Empty()); Configuration configuration; @@ -233,14 +367,14 @@ std::string ConfigurationManager::ImportConfiguration(const std::vector & msg.setText("Cannot access the source configuration file."); msg.setInformativeText(full_import_path.AbsolutePath().c_str()); msg.exec(); - return ""; + return; } configuration.key = MakeConfigurationName(this->available_configurations, configuration.key + " (Imported)"); this->available_configurations.push_back(configuration); this->SortConfigurations(); - return configuration.key; + this->GetActiveConfigurationInfo()->name = configuration.key; } void ConfigurationManager::ExportConfiguration(const std::vector &available_layers, const Path &full_export_path, @@ -261,13 +395,6 @@ void ConfigurationManager::ExportConfiguration(const std::vector &availab } } -void ConfigurationManager::Reset(const std::vector &available_layers) { - // Now we need to kind of restart everything - this->LoadDefaultConfigurations(available_layers); - - this->SortConfigurations(); -} - bool ConfigurationManager::CheckApiVersions(const std::vector &available_layers, Configuration *selected_configuration, std::string &log_versions) const { return this->CompareLayersVersions(available_layers, selected_configuration, Version::VKCONFIG, log_versions, true); @@ -315,3 +442,11 @@ bool ConfigurationManager::CompareLayersVersions(const std::vector &avail return result; } + +bool ConfigurationManager::GetPerApplicationConfig() const { return this->use_per_application_configuration; } + +void ConfigurationManager::SetPerApplicationConfig(bool enabled) { this->use_per_application_configuration = enabled; } + +bool ConfigurationManager::GetUseSystemTray() const { return this->use_system_tray; } + +void ConfigurationManager::SetUseSystemTray(bool enabled) { this->use_system_tray = enabled; } diff --git a/vkconfig_core/configuration_manager.h b/vkconfig_core/configuration_manager.h index 4ed37c4de8..005b6e15e1 100644 --- a/vkconfig_core/configuration_manager.h +++ b/vkconfig_core/configuration_manager.h @@ -21,34 +21,45 @@ #pragma once #include "configuration.h" +#include "configuration_info.h" #include "path.h" +#include "serialization.h" #include #include -class ConfigurationManager { +extern const char* GLOBAL_CONFIGURATION_TOKEN; + +class ConfigurationManager : public Serialize { public: ConfigurationManager(); ~ConfigurationManager(); + bool Load(const QJsonObject& json_root_object) override; + bool Save(QJsonObject& json_root_object) const override; + void Reset() override; + void LoadAllConfigurations(const std::vector& available_layers); + void SaveAllConfigurations() const; - void SaveAllConfigurations(); + const ConfigurationInfo* GetActiveConfigurationInfo() const; + ConfigurationInfo* GetActiveConfigurationInfo(); + const ConfigurationInfo* FindConfigurationInfo(const std::string& key) const; + const std::map& GetConfigurationInfos() const; + bool HasActiveConfiguration() const; Configuration& CreateConfiguration(const std::vector& available_layers, const std::string& configuration_name, bool duplicate = false); - void RemoveConfiguration(const std::vector& available_layers, const std::string& configuration_name); + void RemoveConfiguration(const std::string& configuration_name); - std::string ImportConfiguration(const std::vector& available_layers, const Path& full_import_path); + void ImportConfiguration(const std::vector& available_layers, const Path& full_import_path); void ExportConfiguration(const std::vector& available_layers, const Path& full_export_path, const std::string& configuration_name); const Configuration* FindConfiguration(const std::string& configuration_name) const; Configuration* FindConfiguration(const std::string& configuration_name); - void Reset(const std::vector& available_layers); - void SortConfigurations(); bool CheckLayersVersions(const std::vector& available_layers, Configuration* selected_configuration, @@ -61,6 +72,12 @@ class ConfigurationManager { bool HasFile(const Configuration& configuration) const; void RemoveConfigurationFile(const std::string& key); + bool GetPerApplicationConfig() const; + void SetPerApplicationConfig(bool enabled); + + bool GetUseSystemTray() const; + void SetUseSystemTray(bool enabled); + std::vector available_configurations; private: @@ -72,6 +89,9 @@ class ConfigurationManager { void LoadConfigurationsPath(const std::vector& available_layers); void LoadDefaultConfigurations(const std::vector& available_layers); - std::vector default_configuration_filenames; std::map removed_built_in_configuration; + bool use_system_tray = false; + bool use_per_application_configuration = false; + std::string active_application; + std::map configuration_infos; }; diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index ff66dd36f4..fe34dd8391 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -37,6 +37,84 @@ #include #include +Configurator& Configurator::Get() { + static Configurator configurator; + return configurator; +} + +Configurator::Configurator() {} + +Configurator::~Configurator() { + QJsonObject json_root_object; + + this->environment.Save(json_root_object); + this->configurations.Save(json_root_object); + this->layers.Save(json_root_object); + + QJsonDocument json_doc(json_root_object); + + const Path& vkconfig_init_path = ::Get(Path::INIT); + QFile file(vkconfig_init_path.AbsolutePath().c_str()); + const bool result = file.open(QIODevice::WriteOnly | QIODevice::Text); + assert(result); + + file.write(json_doc.toJson()); + file.close(); + + if (this->mode == GUI) { + this->Surrender(OVERRIDE_AREA_ALL); + } +} + +bool Configurator::Init(Mode mode) { + this->mode = mode; + + const Path& vkconfig_init_path = ::Get(Path::INIT); + + QString init_data; + + QFile file(vkconfig_init_path.AbsolutePath().c_str()); + const bool has_init_file = file.open(QIODevice::ReadOnly | QIODevice::Text); + + if (has_init_file) { + init_data = file.readAll(); + file.close(); + + const QJsonDocument& json_doc = QJsonDocument::fromJson(init_data.toLocal8Bit()); + const QJsonObject& json_root_object = json_doc.object(); + + this->environment.Load(json_root_object); + + bool request_reset = false; + if (this->environment.has_crashed) { + this->environment.has_crashed = false; + + if (Alert::ConfiguratorCrashed() == QMessageBox::Yes) { + request_reset = true; + } + } + + if (request_reset) { + this->Surrender(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + + this->environment.Reset(); + this->layers.Reset(); + this->configurations.Reset(); + } else { + this->layers.Load(json_root_object); + this->configurations.Load(json_root_object); + } + + this->Override(OVERRIDE_AREA_ALL); + } else { + this->environment.Reset(); + this->layers.Reset(); + this->configurations.Reset(); + } + + return true; +} + static QJsonObject CreateJsonSettingObject(const Configurator::LoaderSettings& loader_settings) { QJsonArray json_layers; for (std::size_t j = 0, o = loader_settings.layers.size(); j < o; ++j) { @@ -80,11 +158,11 @@ void Configurator::BuildLoaderSettings(const ConfigurationInfo& info, const std: static Configuration disbled_configuration = Configuration::CreateDisabled(this->layers.selected_layers); const Configuration* configuration = nullptr; - switch (info.GetMode()) { + switch (info.mode) { case LAYERS_CONTROLLED_BY_APPLICATIONS: return; case LAYERS_CONTROLLED_BY_CONFIGURATOR: { - configuration = this->configurations.FindConfiguration(info.GetName()); + configuration = this->configurations.FindConfiguration(info.name); if (configuration == nullptr) { return; } @@ -135,15 +213,22 @@ bool Configurator::WriteLoaderSettings(OverrideArea override_area, const Path& l if (override_area & OVERRIDE_AREA_LOADER_SETTINGS_BIT) { std::vector loader_settings_array; - if (this->environment.GetPerApplicationConfig()) { - for (std::size_t i = 0, n = this->environment.GetApplications().size(); i < n; ++i) { - const Application& application = this->environment.GetApplication(i); + const std::map& infos = this->configurations.GetConfigurationInfos(); + for (auto it = infos.begin(), end = infos.end(); it != end; ++it) { + if (this->configurations.GetPerApplicationConfig()) { + if (it->first == GLOBAL_CONFIGURATION_TOKEN) { + continue; + } + + this->BuildLoaderSettings(it->second, it->first, loader_settings_array); + } else { + if (it->first != GLOBAL_CONFIGURATION_TOKEN) { + continue; + } - this->BuildLoaderSettings(application.configuration, application.executable_path.AbsolutePath(), - loader_settings_array); + this->BuildLoaderSettings(it->second, "", loader_settings_array); + break; } - } else { - BuildLoaderSettings(this->environment.global_configuration, "", loader_settings_array); } if (!loader_settings_array.empty()) { @@ -179,19 +264,20 @@ bool Configurator::WriteLayersSettings(OverrideArea override_area, const Path& l if (override_area & OVERRIDE_AREA_LAYERS_SETTINGS_BIT) { std::vector layers_settings_array; - if (this->environment.GetPerApplicationConfig()) { + if (this->configurations.GetPerApplicationConfig()) { const std::vector& applications = this->environment.GetApplications(); for (std::size_t i = 0, n = applications.size(); i < n; ++i) { LayersSettings settings; - settings.configuration_name = applications[i].configuration.GetName(); + settings.configuration_name = + this->configurations.FindConfigurationInfo(applications[i].executable_path.AbsolutePath())->name; settings.executable_path = applications[i].executable_path; settings.settings_path = applications[i].GetActiveOptions().working_folder; layers_settings_array.push_back(settings); } } else { LayersSettings settings; - settings.configuration_name = this->environment.global_configuration.GetName(); + settings.configuration_name = this->configurations.FindConfigurationInfo(GLOBAL_CONFIGURATION_TOKEN)->name; settings.settings_path = layers_settings_path; layers_settings_array.push_back(settings); } @@ -318,52 +404,6 @@ bool Configurator::WriteLayersSettings(OverrideArea override_area, const Path& l } } -Configurator& Configurator::Get() { - static Configurator configurator; - return configurator; -} - -Configurator::Configurator() : environment(), layers(), configurations() {} - -Configurator::~Configurator() { - this->UpdateLayersValidationCache(); - - this->configurations.SaveAllConfigurations(); - - this->Surrender(OVERRIDE_AREA_ALL); -} - -void Configurator::UpdateLayersValidationCache() { - this->environment.layers_validated.clear(); - - for (std::size_t i = 0, n = this->layers.Size(); i < n; ++i) { - const Layer& layer = this->layers.selected_layers[i]; - - this->environment.layers_validated.insert( - std::make_pair(layer.manifest_path.AbsolutePath(), layer.validated_last_modified)); - } -} - -bool Configurator::Init() { - // Load simple app settings, the additional search paths, and the - // override app list. - this->layers.LoadAllInstalledLayers(environment.layers_validated); - - if (this->environment.has_crashed) { - this->environment.has_crashed = false; - - if (Alert::ConfiguratorCrashed() == QMessageBox::No) { - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - } else { - this->configurations.LoadAllConfigurations(this->layers.selected_layers); - } - - this->Override(OVERRIDE_AREA_ALL); - - return true; -} - bool Configurator::Override(OverrideArea override_area) { const Path& loader_settings_path = ::Get(Path::LOADER_SETTINGS); const Path& layers_settings_path = ::Get(Path::LAYERS_SETTINGS); @@ -415,26 +455,20 @@ bool Configurator::HasOverride() const { return loader_settings_path.Exists() || layers_settings_path.Exists(); } -void Configurator::ResetToDefault(bool hard) { - this->environment.Reset(Environment::CLEAR); - this->layers.LoadAllInstalledLayers(this->environment.layers_validated); - this->configurations.Reset(this->layers.selected_layers); +void Configurator::Reset() { + this->environment.Reset(); + this->layers.Reset(); + this->configurations.Reset(); } Configuration* Configurator::GetActiveConfiguration() { - const ConfigurationInfo& info = this->environment.GetActiveConfigurationInfo(); - return this->configurations.FindConfiguration(info.GetName()); + const ConfigurationInfo* info = this->configurations.GetActiveConfigurationInfo(); + return this->configurations.FindConfiguration(info->name); } const Configuration* Configurator::GetActiveConfiguration() const { - const ConfigurationInfo& info = this->environment.GetActiveConfigurationInfo(); - return this->configurations.FindConfiguration(info.GetName()); + const ConfigurationInfo* info = this->configurations.GetActiveConfigurationInfo(); + return this->configurations.FindConfiguration(info->name); } -bool Configurator::HasActiveConfiguration() const { - if (this->environment.GetPerApplicationConfig()) { - return this->environment.HasOverriddenApplications(); - } else { - return this->environment.GetActiveConfigurationInfo().GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS; - } -} +bool Configurator::HasActiveConfiguration() const { return this->configurations.HasActiveConfiguration(); } diff --git a/vkconfig_core/configurator.h b/vkconfig_core/configurator.h index 2f07e397be..65dfef3e73 100644 --- a/vkconfig_core/configurator.h +++ b/vkconfig_core/configurator.h @@ -32,6 +32,8 @@ class Configurator { public: + enum Mode { CMD, GUI }; + struct LayersSettings { std::string configuration_name; Path executable_path; @@ -52,14 +54,14 @@ class Configurator { }; static Configurator& Get(); - bool Init(); + bool Init(Mode mode = GUI); public: bool Surrender(OverrideArea override_area); bool Override(OverrideArea override_area); bool HasOverride() const; - void ResetToDefault(bool hard); + void Reset(); Configuration* GetActiveConfiguration(); const Configuration* GetActiveConfiguration() const; @@ -78,9 +80,8 @@ class Configurator { void BuildLoaderSettings(const ConfigurationInfo& info, const std::string& executable_path, std::vector& loader_settings_array) const; - void UpdateLayersValidationCache(); - public: + Mode mode; Environment environment; LayerManager layers; ConfigurationManager configurations; diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index 4f7841d508..d8e2ca7c06 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -51,51 +51,14 @@ static const char* GetApplicationSuffix() { return TABLE[VKC_PLATFORM]; } -Environment::Environment(Mode mode) - : mode(mode), loader_message_types_flags(::GetLogFlags(qgetenv("VK_LOADER_DEBUG").toStdString())) { - if (mode == MODE_AUTO_LOAD_SAVE) { - const bool result = Load(); - assert(result); - } +Environment::Environment() {} - if (this->applications.empty()) { - this->applications = CreateDefaultApplications(); - } -} +Environment::~Environment() {} -Environment::~Environment() { - if (mode == MODE_AUTO_LOAD_SAVE) { - const bool result = Save(); - assert(result); - } -} - -void Environment::Reset(ResetMode mode) { - switch (mode) { - case DEFAULT: { - this->global_configuration = ConfigurationInfo(); - this->use_per_application_configuration = false; - this->use_system_tray = false; - this->active_executable_index = 0; - - this->applications = CreateDefaultApplications(); - break; - } - case CLEAR: { - this->Reset(DEFAULT); - - break; - } - case SYSTEM: { - const bool result_env = Load(); - assert(result_env); - break; - } - default: { - assert(0); - break; - } - } +void Environment::Reset() { + this->loader_message_types_flags = ::GetLogFlags(qgetenv("VK_LOADER_DEBUG").toStdString()); + this->active_executable_index = 0; + this->applications = CreateDefaultApplications(); } std::string GetPath() { @@ -109,139 +72,92 @@ std::string GetPath() { return home + TABLE[VKC_ENV]; } -bool Environment::Load() { - Reset(DEFAULT); - - const Path& vkconfig_init_path = ::Get(Path::INIT); - QFile file(vkconfig_init_path.AbsolutePath().c_str()); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QString data = file.readAll(); - file.close(); - - const QJsonDocument& json_doc = QJsonDocument::fromJson(data.toLocal8Bit()); - const QJsonObject& json_root_object = json_doc.object(); - - const Version file_format_version = Version(json_root_object.value("file_format_version").toString().toStdString()); - if (file_format_version > Version::VKCONFIG) { - return false; // Vulkan Configurator needs to be updated - } - - // interface json object - const QJsonObject& json_interface_object = json_root_object.value("interface").toObject(); - this->active_tab = GetTabType(json_interface_object.value("active_tab").toString().toStdString().c_str()); - this->has_crashed = json_interface_object.value("has_crashed").toBool(); - - // diagnostic json object - const QJsonObject& json_diagnostic_object = json_root_object.value("diagnostic").toObject(); - const QJsonArray& json_loader_messages_array = json_diagnostic_object.value("loader_messages").toArray(); - this->loader_message_types_flags = 0; - for (int i = 0, n = json_loader_messages_array.size(); i < n; ++i) { - const std::string& token = json_loader_messages_array[i].toString().toStdString(); - this->loader_message_types_flags |= GetLogBit(token.c_str()); - } - - // layers json object - const QJsonObject& json_layers_object = json_root_object.value("layers").toObject(); - const QJsonObject& json_layers_validated_object = json_layers_object.value("validated").toObject(); - - const QStringList& json_layers_validated_keys = json_layers_validated_object.keys(); - - for (int i = 0, n = json_layers_validated_keys.length(); i < n; ++i) { - const std::string& manifest_path = json_layers_validated_keys[i].toStdString(); - const std::string& last_modified = json_layers_validated_object.value(manifest_path.c_str()).toString().toStdString(); - layers_validated.insert(std::make_pair(manifest_path, last_modified)); - } - - // applications json object - const QJsonObject& json_applications_object = json_root_object.value("applications").toObject(); +bool Environment::Load(const QJsonObject& json_root_object) { + const Version file_format_version = Version(json_root_object.value("file_format_version").toString().toStdString()); + if (file_format_version > Version::VKCONFIG) { + return false; // Vulkan Configurator needs to be updated + } - this->active_executable_index = json_applications_object.value("active_executable_index").toInt(); + // interface json object + const QJsonObject& json_interface_object = json_root_object.value("interface").toObject(); + this->active_tab = GetTabType(json_interface_object.value("active_tab").toString().toStdString().c_str()); + this->has_crashed = json_interface_object.value("has_crashed").toBool(); + + // diagnostic json object + const QJsonObject& json_diagnostic_object = json_root_object.value("diagnostic").toObject(); + const QJsonArray& json_loader_messages_array = json_diagnostic_object.value("loader_messages").toArray(); + this->loader_message_types_flags = 0; + for (int i = 0, n = json_loader_messages_array.size(); i < n; ++i) { + const std::string& token = json_loader_messages_array[i].toString().toStdString(); + this->loader_message_types_flags |= GetLogBit(token.c_str()); + } - const QJsonObject& json_list_object = json_applications_object.value("list").toObject(); + // applications json object + const QJsonObject& json_applications_object = json_root_object.value("applications").toObject(); - const QStringList& json_list_keys = json_list_object.keys(); + this->active_executable_index = json_applications_object.value("active_executable_index").toInt(); - this->applications.clear(); - for (int i = 0, n = json_list_keys.length(); i < n; ++i) { - Application application; + const QJsonObject& json_list_object = json_applications_object.value("list").toObject(); - const QJsonObject& json_application_object = json_list_object.value(json_list_keys[i]).toObject(); - application.executable_path = json_list_keys[i].toStdString(); - application.configuration.SetName(json_application_object.value("configuration").toString().toStdString()); - application.configuration.SetMode( - ::GetLayersMode(json_application_object.value("mode").toString().toStdString().c_str())); - application.active_option_index = json_application_object.value("active_option_index").toInt(); + const QStringList& json_list_keys = json_list_object.keys(); - const QJsonArray& json_options_array = json_application_object.value("options").toArray(); - for (int j = 0, o = json_options_array.size(); j < o; ++j) { - const QJsonObject& json_options_object = json_options_array[j].toObject(); + this->applications.clear(); + for (int i = 0, n = json_list_keys.length(); i < n; ++i) { + Application application; - ApplicationOptions application_options; + const QJsonObject& json_application_object = json_list_object.value(json_list_keys[i]).toObject(); + application.executable_path = json_list_keys[i].toStdString(); + application.active_option_index = json_application_object.value("active_option_index").toInt(); - application_options.label = json_options_object.value("label").toString().toStdString(); - application_options.working_folder = json_options_object.value("working_folder").toString().toStdString(); + const QJsonArray& json_options_array = json_application_object.value("options").toArray(); + for (int j = 0, o = json_options_array.size(); j < o; ++j) { + const QJsonObject& json_options_object = json_options_array[j].toObject(); - const QJsonArray& json_command_lines_array = json_options_object.value("arguments").toArray(); - for (int k = 0, p = json_command_lines_array.size(); k < p; ++k) { - application_options.arguments.push_back(json_command_lines_array[k].toString().toStdString()); - } + ApplicationOptions application_options; - const QJsonArray& json_environment_variables_array = json_options_object.value("environment_variables").toArray(); - for (int k = 0, p = json_environment_variables_array.size(); k < p; ++k) { - application_options.environment_variables.push_back( - json_environment_variables_array[k].toString().toStdString()); - } + application_options.label = json_options_object.value("label").toString().toStdString(); + application_options.working_folder = json_options_object.value("working_folder").toString().toStdString(); - application_options.log_file = json_options_array[j].toObject().value("log_file").toString().toStdString(); + const QJsonArray& json_command_lines_array = json_options_object.value("arguments").toArray(); + for (int k = 0, p = json_command_lines_array.size(); k < p; ++k) { + application_options.arguments.push_back(json_command_lines_array[k].toString().toStdString()); + } - application.options.push_back(application_options); + const QJsonArray& json_environment_variables_array = json_options_object.value("environment_variables").toArray(); + for (int k = 0, p = json_environment_variables_array.size(); k < p; ++k) { + application_options.environment_variables.push_back(json_environment_variables_array[k].toString().toStdString()); } - this->applications.push_back(application); - } + application_options.log_file = json_options_array[j].toObject().value("log_file").toString().toStdString(); - // configurations json object - const QJsonObject& json_configurations_object = json_root_object.value("configurations").toObject(); - this->use_per_application_configuration = json_configurations_object.value("use_per_application").toBool(); - this->global_configuration.SetName(json_configurations_object.value("configuration").toString().toStdString()); - this->global_configuration.SetMode( - ::GetLayersMode(json_configurations_object.value("mode").toString().toStdString().c_str())); - - // preferences json object - const QJsonObject& json_preferences_object = json_root_object.value("preferences").toObject(); - this->use_system_tray = json_preferences_object.value("use_system_tray").toBool(); - this->home_sdk_path = json_preferences_object.value("VK_HOME").toString().toStdString(); - if (this->home_sdk_path.Empty()) { - this->home_sdk_path = ::Get(Path::HOME); + application.options.push_back(application_options); } - const QJsonArray& json_hide_message_boxes_array = json_preferences_object.value("hide_message_boxes").toArray(); - this->hide_message_boxes_flags = 0; - for (int i = 0, n = json_hide_message_boxes_array.size(); i < n; ++i) { - const std::string& token = json_hide_message_boxes_array[i].toString().toStdString(); - this->hide_message_boxes_flags |= GetLogBit(token.c_str()); - } + this->applications.push_back(application); } - return true; -} + // preferences json object + const QJsonObject& json_preferences_object = json_root_object.value("preferences").toObject(); + this->home_sdk_path = json_preferences_object.value("VK_HOME").toString().toStdString(); + if (this->home_sdk_path.Empty()) { + this->home_sdk_path = ::Get(Path::HOME); + } -bool Environment::Save() const { - const Path& vkconfig_init_path = ::Get(Path::INIT); - if (Path(vkconfig_init_path.AbsoluteDir()).Exists()) { - std::cout << Path(vkconfig_init_path).AbsoluteDir() << " exists." << std::endl; - } else { - std::cout << Path(vkconfig_init_path).AbsoluteDir() << " doesn't exist." << std::endl; + const QJsonArray& json_hide_message_boxes_array = json_preferences_object.value("hide_message_boxes").toArray(); + this->hide_message_boxes_flags = 0; + for (int i = 0, n = json_hide_message_boxes_array.size(); i < n; ++i) { + const std::string& token = json_hide_message_boxes_array[i].toString().toStdString(); + this->hide_message_boxes_flags |= GetLogBit(token.c_str()); } - QFile file(vkconfig_init_path.AbsolutePath().c_str()); - const bool result = file.open(QIODevice::WriteOnly | QIODevice::Text); - if (result == false) { - std::cout << vkconfig_init_path.AbsolutePath().c_str() << std::endl; + if (this->applications.empty()) { + this->applications = CreateDefaultApplications(); } - assert(result); - QJsonObject json_root_object; + return true; +} + +bool Environment::Save(QJsonObject& json_root_object) const { json_root_object.insert("file_format_version", Version::VKCONFIG.str().c_str()); QJsonObject json_interface_object; @@ -270,8 +186,6 @@ bool Environment::Save() const { const Application& application = this->applications[i]; QJsonObject json_application_object; - json_application_object.insert("configuration", application.configuration.GetName()); - json_application_object.insert("mode", ::GetToken(application.configuration.GetMode())); json_application_object.insert("active_option", application.active_option_index); QJsonArray json_options_array; @@ -306,25 +220,7 @@ bool Environment::Save() const { json_root_object.insert("applications", json_applications_object); - QJsonObject json_layers_paths_object; - for (auto it = this->layers_validated.begin(), end = this->layers_validated.end(); it != end; ++it) { - json_layers_paths_object.insert(it->first.c_str(), it->second.c_str()); - } - - QJsonObject json_layers_object; - json_layers_object.insert("validated", json_layers_paths_object); - - json_root_object.insert("layers", json_layers_object); - - QJsonObject json_configurations_object; - json_configurations_object.insert("use_per_application", this->use_per_application_configuration); - json_configurations_object.insert("configuration", this->global_configuration.GetName()); - json_configurations_object.insert("mode", ::GetToken(this->global_configuration.GetMode())); - - json_root_object.insert("configurations", json_configurations_object); - QJsonObject json_preferences_object; - json_preferences_object.insert("use_system_tray", this->use_system_tray); json_preferences_object.insert("VK_HOME", this->home_sdk_path.RelativePath().c_str()); QJsonArray json_hide_message_boxes_array; @@ -338,10 +234,6 @@ bool Environment::Save() const { json_root_object.insert("preferences", json_preferences_object); - QJsonDocument json_doc(json_root_object); - file.write(json_doc.toJson()); - file.close(); - return true; } @@ -354,16 +246,6 @@ int Environment::GetActiveApplicationIndex() const { return this->active_executable_index; // Not found, but the list is present, so return the first item. } -bool Environment::HasOverriddenApplications() const { - for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { - if (this->applications[i].configuration.GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { - return true; - } - } - - return false; -} - bool Environment::AppendApplication(const Application& application) { this->applications.push_back(application); return true; @@ -392,22 +274,6 @@ bool Environment::RemoveApplication(std::size_t application_index) { return true; } -const ConfigurationInfo& Environment::GetActiveConfigurationInfo() const { - if (this->GetPerApplicationConfig()) { - return this->GetActiveApplication().configuration; - } else { - return this->global_configuration; - } -} - -ConfigurationInfo& Environment::GetActiveConfigurationInfo() { - if (this->GetPerApplicationConfig()) { - return this->GetActiveApplication().configuration; - } else { - return this->global_configuration; - } -} - const Application& Environment::GetActiveApplication() const { assert(!this->applications.empty()); @@ -432,10 +298,6 @@ Application& Environment::GetApplication(std::size_t application_index) { return this->applications[application_index]; } -bool Environment::GetPerApplicationConfig() const { return this->use_per_application_configuration; } - -void Environment::SetPerApplicationConfig(bool enable) { this->use_per_application_configuration = enable; } - /////////////////////////////////////////////////////////////////////////// /// This is only used on macOS to extract the executable from the bundle. /// You have to look at the plist.info file, you can't just assume whatever diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index 51a50a7a2f..730e49f0e1 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -24,6 +24,7 @@ #include "application.h" #include "type_tab.h" #include "type_log.h" +#include "serialization.h" #include @@ -42,41 +43,26 @@ struct DefaultPath { Path working_folder; }; -class Environment { +class Environment : public Serialize { public: - enum Mode { MODE_AUTO_LOAD_SAVE = 0, MODE_UNINITIALIZED }; - - Environment(Mode mode = MODE_AUTO_LOAD_SAVE); + Environment(); ~Environment(); - enum ResetMode { DEFAULT = 0, CLEAR, SYSTEM }; - - void Reset(ResetMode mode); - - bool Load(); - bool Save() const; + bool Load(const QJsonObject& json_root_object) override; + bool Save(QJsonObject& json_root_object) const override; + void Reset() override; void SelectActiveApplication(std::size_t application_index); int GetActiveApplicationIndex() const; - bool HasOverriddenApplications() const; bool AppendApplication(const Application& application); bool RemoveApplication(std::size_t application_index); - const ConfigurationInfo& GetActiveConfigurationInfo() const; - ConfigurationInfo& GetActiveConfigurationInfo(); - const std::vector& GetApplications() const { return applications; } const Application& GetActiveApplication() const; Application& GetActiveApplication(); const Application& GetApplication(std::size_t application_index) const; Application& GetApplication(std::size_t application_index); - bool GetPerApplicationConfig() const; - void SetPerApplicationConfig(bool enable); - - bool GetUseSystemTray() const { return this->use_system_tray; } - void SetUseSystemTray(bool enable) { this->use_system_tray = enable; } - LogFlags GetLoaderMessageFlags() const { return this->loader_message_types_flags; } void SetLoaderMessageFlags(LogFlags flags) { this->loader_message_types_flags = flags; } @@ -89,20 +75,13 @@ class Environment { Path path_export; Path path_import; - ConfigurationInfo global_configuration; - std::map layers_validated; - bool launcher_clear_on_launch = true; private: Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; - const Mode mode; - TabType active_tab = TAB_DIAGNOSTIC; - bool use_system_tray = false; - bool use_per_application_configuration = false; LogFlags loader_message_types_flags; Path home_sdk_path; diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index d284017598..91aed7a71b 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -23,6 +23,8 @@ #include "type_platform.h" #include "registry.h" +#include + LayerType GetLayerType(LayersPaths Layers_paths_type) { if (Layers_paths_type == LAYERS_PATHS_IMPLICIT) { return LAYER_TYPE_IMPLICIT; @@ -103,7 +105,11 @@ std::vector GetExplicitLayerPaths() { return result; } -LayerManager::LayerManager(const std::vector &user_defined_paths) { +LayerManager::LayerManager() {} + +LayerManager::~LayerManager() {} + +bool LayerManager::Load(const QJsonObject &json_root_object) { this->paths[LAYERS_PATHS_IMPLICIT] = GetImplicitLayerPaths(); this->paths[LAYERS_PATHS_EXPLICIT] = GetExplicitLayerPaths(); @@ -120,10 +126,63 @@ LayerManager::LayerManager(const std::vector &user_defined_paths) { this->paths[LAYERS_PATHS_ENV_SET].push_back(VK_ADD_LAYER_PATH[i]); } - this->paths[LAYERS_PATHS_GUI].insert(this->paths[LAYERS_PATHS_GUI].begin(), user_defined_paths.begin(), - user_defined_paths.end()); - this->paths[LAYERS_PATHS_SDK].push_back(::Get(Path::SDK_BIN)); + + if (json_root_object.value("layers") != QJsonValue::Undefined) { + const QJsonObject &json_layers_object = json_root_object.value("layers").toObject(); + + if (json_layers_object.value("validated") != QJsonValue::Undefined) { + const QJsonObject &json_layers_validated_object = json_layers_object.value("validated").toObject(); + + const QStringList &json_layers_validated_keys = json_layers_validated_object.keys(); + + for (int i = 0, n = json_layers_validated_keys.length(); i < n; ++i) { + const std::string &manifest_path = json_layers_validated_keys[i].toStdString(); + const std::string &last_modified = + json_layers_validated_object.value(manifest_path.c_str()).toString().toStdString(); + this->layers_validated.insert(std::make_pair(manifest_path, last_modified)); + } + } + + if (json_layers_object.value("user_defined_paths") != QJsonValue::Undefined) { + const QJsonArray &json_array = json_layers_object.value("user_defined_paths").toArray(); + + for (int i = 0, n = json_array.size(); i < n; ++i) { + this->paths[LAYERS_PATHS_GUI].push_back(json_array[i].toString().toStdString()); + } + } + } + + this->LoadAllInstalledLayers(); + + return true; +} + +bool LayerManager::Save(QJsonObject &json_root_object) const { + QJsonObject json_layers_paths_object; + for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + const Layer &layer = this->selected_layers[i]; + + json_layers_paths_object.insert(layer.manifest_path.AbsolutePath().c_str(), layer.validated_last_modified.c_str()); + } + + QJsonArray json_user_defined_paths_array; + for (std::size_t i = 0, n = this->paths[LAYERS_PATHS_GUI].size(); i < n; ++i) { + json_user_defined_paths_array.append(this->paths[LAYERS_PATHS_GUI][i].RelativePath().c_str()); + } + + QJsonObject json_layers_object; + json_layers_object.insert("validated", json_layers_paths_object); + json_layers_object.insert("user_defined_paths", json_user_defined_paths_array); + + json_root_object.insert("layers", json_layers_object); + + return true; +} + +void LayerManager::Reset() { + this->layers_validated.clear(); + this->paths[LAYERS_PATHS_SDK].clear(); } void LayerManager::Clear() { this->selected_layers.clear(); } @@ -144,8 +203,64 @@ const Layer *LayerManager::Find(const std::string &layer_name) const { return FindByKey(this->selected_layers, layer_name.c_str()); } +std::vector LayerManager::GatherVersions(const std::string &layer_name) const { + std::vector result; + + for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (this->selected_layers[i].key == layer_name) { + result.push_back(this->selected_layers[i].api_version); + } + } + + return result; +} + +const Layer *LayerManager::FindFromVersion(const std::string &layer_name, const Version &layer_version) const { + // Version::VERSION_NULL refer to latest version + if (layer_version == Version::VERSION_NULL) { + const std::vector &version = this->GatherVersions(layer_name); + if (version.empty()) { + return nullptr; + } + + Version latest = Version::VERSION_NULL; + for (std::size_t i = 0, n = version.size(); i < n; ++i) { + if (latest == Version::VERSION_NULL) { + latest = version[i]; + } else if (version[i] > latest) { + latest = version[i]; + } + } + assert(latest != Version::VERSION_NULL); + + return FindFromVersion(layer_name, latest); + } else { + for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (this->selected_layers[i].key != layer_name) { + continue; + } + if (this->selected_layers[i].api_version != layer_version) { + continue; + } + + return &this->selected_layers[i]; + } + } + + return nullptr; +} + +const Layer *LayerManager::FindFromManifest(const Path &manifest_path) const { + for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (this->selected_layers[i].manifest_path == manifest_path) { + return &this->selected_layers[i]; + } + } + return nullptr; +} + // Find all installed layers on the system. -void LayerManager::LoadAllInstalledLayers(const std::map &layers_validated) { +void LayerManager::LoadAllInstalledLayers() { this->selected_layers.clear(); for (std::size_t group_index = 0, group_count = this->paths.size(); group_index < group_count; ++group_index) { @@ -153,18 +268,17 @@ void LayerManager::LoadAllInstalledLayers(const std::map &paths_group = this->paths[group_index]; for (std::size_t i = 0, n = paths_group.size(); i < n; ++i) { - this->LoadLayersFromPath(paths_group[i], layers_validated, layer_type); + this->LoadLayersFromPath(paths_group[i], layer_type); } } } -void LayerManager::LoadLayersFromPath(const Path &layers_path, const std::map &layers_validated, - LayerType type) { +void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { const std::vector &layers_paths = layers_path.IsDir() ? CollectFilePaths(layers_path) : GetVector(layers_path); for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { Layer layer; - if (layer.Load(layers_paths[i], layers_validated, type)) { + if (layer.Load(layers_paths[i], this->layers_validated, type)) { if (this->IsAvailable(layer)) { continue; } diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index a4a33ecf4c..4a02d347eb 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -22,6 +22,7 @@ #include "layer.h" #include "path.h" +#include "serialization.h" #include #include @@ -43,9 +44,21 @@ enum { LAYERS_PATHS_COUNT = LAYERS_PATHS_LAST - LAYERS_PATHS_FIRST + 1 }; LayerType GetLayerType(LayersPaths Layers_paths_type); -class LayerManager { +struct LayersPathInfo { + Path path; + std::vector layers; + + bool enabled = true; +}; + +class LayerManager : public Serialize { public: - LayerManager(const std::vector& user_defined_paths = std::vector()); + LayerManager(); + ~LayerManager(); + + bool Load(const QJsonObject& json_root_object) override; + bool Save(QJsonObject& json_root_object) const override; + void Reset() override; void Clear(); bool Empty() const; @@ -54,15 +67,19 @@ class LayerManager { Layer* Find(const std::string& layer_name); const Layer* Find(const std::string& layer_name) const; - void LoadAllInstalledLayers(const std::map& layers_validated); + std::vector GatherVersions(const std::string& layer_name) const; + const Layer* FindFromVersion(const std::string& layer_name, const Version& version) const; + const Layer* FindFromManifest(const Path& manifest_path) const; + + void LoadAllInstalledLayers(); - void LoadLayersFromPath(const Path& layers_path, const std::map& layers_validated, - LayerType type = LAYER_TYPE_EXPLICIT); + void LoadLayersFromPath(const Path& layers_path, LayerType type = LAYER_TYPE_EXPLICIT); std::vector selected_layers; + std::array, LAYERS_PATHS_COUNT> paths; private: - bool IsAvailable(const Layer& layer) const; + std::map layers_validated; - std::array, LAYERS_PATHS_COUNT> paths; + bool IsAvailable(const Layer& layer) const; }; diff --git a/vkconfig_core/path.cpp b/vkconfig_core/path.cpp index 6221650d15..6690d9048b 100644 --- a/vkconfig_core/path.cpp +++ b/vkconfig_core/path.cpp @@ -417,16 +417,22 @@ std::string AbsolutePath(Path::Builtin path) { return Get(path).AbsolutePath(); std::string RelativePath(Path::Builtin path) { return Get(path).RelativePath(); } -std::vector CollectFilePaths(const Path& directory, const char* filter) { - const std::string& absolute_path = directory.AbsolutePath(); +std::vector CollectFilePaths(const Path& path, const char* filter) { + std::vector result; - const QDir dir(absolute_path.c_str()); - const QFileInfoList& list = dir.entryInfoList(QStringList() << filter, QDir::Files | QDir::NoSymLinks); + if (path.IsDir()) { + const std::string& absolute_path = path.AbsolutePath(); - std::vector result; - for (int i = 0, n = list.size(); i < n; ++i) { - result.push_back(list[i].absoluteFilePath().toStdString()); + const QDir dir(absolute_path.c_str()); + const QFileInfoList& list = dir.entryInfoList(QStringList() << filter, QDir::Files | QDir::NoSymLinks); + + for (int i = 0, n = list.size(); i < n; ++i) { + result.push_back(list[i].absoluteFilePath().toStdString()); + } + } else if (path.IsFile()) { + result.push_back(path); } + return result; } diff --git a/vkconfig_core/serialization.h b/vkconfig_core/serialization.h new file mode 100644 index 0000000000..4202cfac1c --- /dev/null +++ b/vkconfig_core/serialization.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include + +struct Serialize { + virtual bool Load(const QJsonObject& json_root_object) = 0; + virtual bool Save(QJsonObject& json_root_object) const = 0; + virtual void Reset() = 0; +}; diff --git a/vkconfig_core/test/test_configuration_built_in.cpp b/vkconfig_core/test/test_configuration_built_in.cpp index 96d8ae39a4..e840ff10eb 100644 --- a/vkconfig_core/test/test_configuration_built_in.cpp +++ b/vkconfig_core/test/test_configuration_built_in.cpp @@ -63,14 +63,12 @@ static bool operator!=(const std::vector& a, const std::vector Dummy() { return std::map(); } struct TestBuilin { - TestBuilin() : environment(Environment::MODE_UNINITIALIZED), layer_manager() { - this->layer_manager.LoadLayersFromPath(":/sdk", Dummy()); + TestBuilin() : environment(), layer_manager() { + this->layer_manager.LoadLayersFromPath(":/sdk"); EXPECT_TRUE(!this->layer_manager.selected_layers.empty()); } - ~TestBuilin() { - environment.Reset(Environment::SYSTEM); // Don't change the system settings on exit - } + ~TestBuilin() {} Configuration Load(const char* configuration_name) { Configuration configuration_loaded; diff --git a/vkconfig_core/test/test_configuration_manager.cpp b/vkconfig_core/test/test_configuration_manager.cpp index 58a4fcb9d7..e96415a51d 100644 --- a/vkconfig_core/test/test_configuration_manager.cpp +++ b/vkconfig_core/test/test_configuration_manager.cpp @@ -43,17 +43,17 @@ TEST(test_configuration_manager, create_remove) { EXPECT_STREQ("Configuration A (2)", configuration_duplicate_key.c_str()); // Remove configurations - configuration_manager.RemoveConfiguration(available_layers, "Configuration A"); + configuration_manager.RemoveConfiguration("Configuration A"); EXPECT_EQ(2, configuration_manager.available_configurations.size()); - configuration_manager.RemoveConfiguration(available_layers, "Configuration B"); + configuration_manager.RemoveConfiguration("Configuration B"); EXPECT_EQ(1, configuration_manager.available_configurations.size()); // Already deleted - configuration_manager.RemoveConfiguration(available_layers, "Configuration A"); + configuration_manager.RemoveConfiguration("Configuration A"); EXPECT_EQ(1, configuration_manager.available_configurations.size()); // Remove configuration - configuration_manager.RemoveConfiguration(available_layers, configuration_duplicate_key.c_str()); + configuration_manager.RemoveConfiguration(configuration_duplicate_key.c_str()); EXPECT_EQ(true, configuration_manager.Empty()); } diff --git a/vkconfig_core/test/test_environment.cpp b/vkconfig_core/test/test_environment.cpp index 158153bc28..2776b33b35 100644 --- a/vkconfig_core/test/test_environment.cpp +++ b/vkconfig_core/test/test_environment.cpp @@ -27,8 +27,8 @@ #include TEST(test_environment, reset_default_applications_sdk_found) { - Environment environment(Environment::MODE_UNINITIALIZED); - environment.Reset(Environment::DEFAULT); + Environment environment; + environment.Reset(); const std::vector& applications = environment.GetApplications(); @@ -45,15 +45,13 @@ TEST(test_environment, reset_default_applications_sdk_found) { EXPECT_TRUE(applications[1].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); EXPECT_TRUE(applications[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); } - - environment.Reset(Environment::SYSTEM); } TEST(test_environment, reset_default_applications_no_sdk) { qunsetenv("VULKAN_SDK"); - Environment environment(Environment::MODE_UNINITIALIZED); - environment.Reset(Environment::DEFAULT); + Environment environment; + environment.Reset(); const std::vector& applications = environment.GetApplications(); @@ -66,12 +64,10 @@ TEST(test_environment, reset_default_applications_no_sdk) { EXPECT_TRUE(applications[1].executable_path.RelativePath().find("vkcubepp") != std::string::npos); EXPECT_TRUE(applications[1].options[0].working_folder.RelativePath().find(".") != std::string::npos); EXPECT_TRUE(applications[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); - - environment.Reset(Environment::SYSTEM); } TEST(test_environment, remove_missing_applications) { - Environment environment(Environment::MODE_UNINITIALIZED); + Environment environment; const Path& path_missing = ::Get(Path::HOME) + "my_missing_executable"; const Path& path_exciting = ::Get(Path::HOME) + "my_exciting_executable"; diff --git a/vkconfig_core/test/test_layer_manager.cpp b/vkconfig_core/test/test_layer_manager.cpp index ce40a13157..6b96fc156a 100644 --- a/vkconfig_core/test/test_layer_manager.cpp +++ b/vkconfig_core/test/test_layer_manager.cpp @@ -23,8 +23,6 @@ #include -std::map Dummy() { return std::map(); } - TEST(test_layer_manager, clear) { LayerManager layer_manager; @@ -33,13 +31,9 @@ TEST(test_layer_manager, clear) { } TEST(test_layer_manager, load_all) { - std::vector user_defined_paths; - user_defined_paths.push_back(":/layers"); - - Environment environment; - - LayerManager layer_manager(user_defined_paths); - layer_manager.LoadAllInstalledLayers(environment.layers_validated); + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + layer_manager.LoadAllInstalledLayers(); EXPECT_TRUE(layer_manager.Size() >= 10); EXPECT_TRUE(!layer_manager.Empty()); @@ -52,7 +46,7 @@ TEST(test_layer_manager, load_dir) { LayerManager layer_manager; EXPECT_TRUE(layer_manager.Empty()); - layer_manager.LoadLayersFromPath(":/layers", Dummy()); + layer_manager.LoadLayersFromPath(":/layers"); EXPECT_TRUE(!layer_manager.Empty()); EXPECT_EQ(10, layer_manager.Size()); @@ -67,7 +61,7 @@ TEST(test_layer_manager, load_file) { LayerManager layer_manager; EXPECT_TRUE(layer_manager.Empty()); - layer_manager.LoadLayersFromPath(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json", Dummy()); + layer_manager.LoadLayersFromPath(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json"); EXPECT_TRUE(!layer_manager.Empty()); EXPECT_EQ(1, layer_manager.Size()); @@ -79,16 +73,10 @@ TEST(test_layer_manager, load_file) { } TEST(test_layer_manager, find) { - std::vector user_defined_paths; - user_defined_paths.push_back(":/layers"); - - Environment environment; - - LayerManager layer_manager(user_defined_paths); + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); EXPECT_TRUE(layer_manager.Empty()); - layer_manager.LoadAllInstalledLayers(environment.layers_validated); - EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_test_03") != nullptr); } @@ -97,9 +85,9 @@ TEST(test_layer_manager, avoid_duplicate) { LayerManager layer_manager; EXPECT_TRUE(layer_manager.Empty()); - layer_manager.LoadLayersFromPath(":/layers", Dummy()); + layer_manager.LoadLayersFromPath(":/layers"); EXPECT_EQ(10, layer_manager.Size()); - layer_manager.LoadLayersFromPath(":/layers", Dummy()); + layer_manager.LoadLayersFromPath(":/layers"); EXPECT_EQ(10, layer_manager.Size()); } diff --git a/vkconfig_core/test/test_ui.cpp b/vkconfig_core/test/test_ui.cpp index d46af29651..92ca01d870 100644 --- a/vkconfig_core/test/test_ui.cpp +++ b/vkconfig_core/test/test_ui.cpp @@ -22,8 +22,6 @@ #include -std::map Dummy() { return std::map(); } - TEST(test_ui, ExtractLayerName_no_layer_loaded) { LayerManager layer_manager; @@ -33,7 +31,7 @@ TEST(test_ui, ExtractLayerName_no_layer_loaded) { TEST(test_ui, ExtractLayerName_no_found) { LayerManager layer_manager; - layer_manager.LoadLayersFromPath(":/sdk", Dummy()); + layer_manager.LoadLayersFromPath(":/sdk"); const std::string& not_found = ExtractLayerName(layer_manager, " = VK_LAYER_KHRONOS_unkown"); EXPECT_TRUE(not_found.empty()); @@ -41,7 +39,7 @@ TEST(test_ui, ExtractLayerName_no_found) { TEST(test_ui, ExtractLayerName_found) { LayerManager layer_manager; - layer_manager.LoadLayersFromPath(":/sdk", Dummy()); + layer_manager.LoadLayersFromPath(":/sdk"); const std::string& layer_found = ExtractLayerName(layer_manager, " = VK_LAYER_KHRONOS_validation"); EXPECT_STREQ("VK_LAYER_KHRONOS_validation", layer_found.c_str()); diff --git a/vkconfig_core/type_layer_type.cpp b/vkconfig_core/type_layer_type.cpp index 9a34437a08..da8351dddf 100644 --- a/vkconfig_core/type_layer_type.cpp +++ b/vkconfig_core/type_layer_type.cpp @@ -25,8 +25,8 @@ const char* GetToken(LayerType type) { static const char* TOKENS[] = { - "Explicit", // LAYER_TYPE_EXPLICIT "Implicit", // LAYER_TYPE_IMPLICIT + "Explicit", // LAYER_TYPE_EXPLICIT }; static_assert(std::size(TOKENS) == LAYER_TYPE_COUNT); diff --git a/vkconfig_gui/main.cpp b/vkconfig_gui/main.cpp index fe0244b6ce..37383ac999 100644 --- a/vkconfig_gui/main.cpp +++ b/vkconfig_gui/main.cpp @@ -67,9 +67,7 @@ int main(int argc, char* argv[]) { } Configurator& configurator = Configurator::Get(); - - // Make sure layers configuration is deleted otherwise BuildVulkanSystemInfo() will crash... (unexplained) - configurator.Surrender(OVERRIDE_AREA_ALL); + // configurator.Surrender(OVERRIDE_AREA_LOADER_SETTINGS_BIT); const VulkanSystemInfo& vulkan_info = BuildVulkanSystemInfo(); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 25fa4f7279..6352426a2f 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -134,7 +134,6 @@ void MainWindow::InitTray() { this->_tray_icon_menu->addAction(this->_tray_quit_action); this->_tray_icon = new QSystemTrayIcon(this); this->_tray_icon->setContextMenu(this->_tray_icon_menu); - this->UpdateUI_Status(); this->_tray_icon->show(); this->connect(this->_tray_icon, &QSystemTrayIcon::activated, this, &MainWindow::iconActivated); } @@ -142,10 +141,7 @@ void MainWindow::InitTray() { void MainWindow::UpdateUI_Status() { const Configurator &configurator = Configurator::Get(); - const Environment &environment = configurator.environment; - const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); - const bool has_selected_configuration = !selected_contiguration_name.empty(); - const bool has_active_configuration = configurator.HasActiveConfiguration() && has_selected_configuration; + const bool has_active_configuration = configurator.HasActiveConfiguration(); // Update title bar #ifdef VKCONFIG_DATE @@ -154,9 +150,12 @@ void MainWindow::UpdateUI_Status() { bool display_date = false; #endif + const ConfigurationInfo *configuration_info = configurator.configurations.GetActiveConfigurationInfo(); + const LayersMode mode = configuration_info == nullptr ? LAYERS_CONTROLLED_BY_APPLICATIONS : configuration_info->mode; + this->setWindowTitle(GetMainWindowTitle(has_active_configuration, display_date).c_str()); if (QSystemTrayIcon::isSystemTrayAvailable()) { - switch (environment.GetActiveConfigurationInfo().GetMode()) { + switch (mode) { default: case LAYERS_CONTROLLED_BY_APPLICATIONS: this->_tray_layers_controlled_by_applications->setChecked(true); @@ -176,7 +175,7 @@ void MainWindow::UpdateUI_Status() { } } - if (has_active_configuration && environment.GetActiveConfigurationInfo().GetMode() != LAYERS_CONTROLLED_BY_APPLICATIONS) { + if (has_active_configuration && mode != LAYERS_CONTROLLED_BY_APPLICATIONS) { const QIcon icon(":/resourcefiles/vkconfig-on.png"); this->setWindowIcon(icon); if (QSystemTrayIcon::isSystemTrayAvailable()) { @@ -229,7 +228,7 @@ void MainWindow::trayActionRestore() { void MainWindow::trayActionControlledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_CONTROLLED_BY_APPLICATIONS); + configurator.configurations.GetActiveConfigurationInfo()->mode = LAYERS_CONTROLLED_BY_APPLICATIONS; configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); @@ -243,7 +242,7 @@ void MainWindow::trayActionControlledByApplications(bool checked) { void MainWindow::trayActionControlledByConfigurator(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_CONTROLLED_BY_CONFIGURATOR); + configurator.configurations.GetActiveConfigurationInfo()->mode = LAYERS_CONTROLLED_BY_CONFIGURATOR; configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); @@ -257,7 +256,7 @@ void MainWindow::trayActionControlledByConfigurator(bool checked) { void MainWindow::trayActionDisabledByApplications(bool checked) { if (checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetMode(LAYERS_DISABLED_BY_CONFIGURATOR); + configurator.configurations.GetActiveConfigurationInfo()->mode = LAYERS_DISABLED_BY_CONFIGURATOR; configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(); @@ -268,19 +267,6 @@ void MainWindow::trayActionDisabledByApplications(bool checked) { } } -void MainWindow::AddLayerPathItem(const std::string &layer_path) { - TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(layer_path.c_str()); - - item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); - LayerPathWidget *layer_path_widget = new LayerPathWidget(layer_path, ui->layers_tree, item_state); - - item_state->widget = layer_path_widget; - - // Add the top level item - ui->layers_tree->addTopLevelItem(item_state); - ui->layers_tree->setItemWidget(item_state, 0, layer_path_widget); -} - void MainWindow::UpdateUI() { static int check_recurse = 0; ++check_recurse; @@ -288,14 +274,10 @@ void MainWindow::UpdateUI() { Configurator &configurator = Configurator::Get(); const Environment &environment = Configurator::Get().environment; - const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); - const bool has_selected_configuration = !selected_contiguration_name.empty(); this->blockSignals(true); ui->configurations_list->blockSignals(true); - const bool has_active_configuration = configurator.HasActiveConfiguration() && has_selected_configuration; - const bool has_application_list = !environment.GetApplications().empty(); ui->push_button_launcher->setText(_launch_application ? "Terminate" : "Launch"); ui->check_box_clear_on_launch->setChecked(environment.launcher_clear_on_launch); @@ -321,7 +303,7 @@ void MainWindow::toolsResetToDefault(bool checked) { } Configurator &configurator = Configurator::Get(); - configurator.ResetToDefault(true); + configurator.Reset(); this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REFRESH_UI); this->UpdateUI(); @@ -330,7 +312,7 @@ void MainWindow::toolsResetToDefault(bool checked) { void MainWindow::StartTool(Tool tool) { Configurator &configurator = Configurator::Get(); - if (!configurator.environment.GetPerApplicationConfig()) { + if (!configurator.configurations.GetPerApplicationConfig()) { configurator.Surrender(OVERRIDE_AREA_LOADER_SETTINGS_BIT); } @@ -343,7 +325,7 @@ void MainWindow::StartTool(Tool tool) { break; } - if (!configurator.environment.GetPerApplicationConfig()) { + if (!configurator.configurations.GetPerApplicationConfig()) { configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); } } @@ -393,15 +375,16 @@ void MainWindow::OnHelpGPUInfo(bool checked) { /// The only thing we need to do here is clear the configuration if /// the user does not want it active. void MainWindow::closeEvent(QCloseEvent *event) { - Environment &environment = Configurator::Get().environment; + Configurator &configurator = Configurator::Get(); + Environment &environment = configurator.environment; // Alert the user to the current state of the vulkan configurator and // give them the option to not shutdown. - if (environment.GetUseSystemTray()) { + if (configurator.configurations.GetUseSystemTray()) { if (environment.hide_message_boxes_flags & GetBit(HIDE_MESSAGE_USE_SYSTEM_TRAY)) { std::string shut_down_state; - if (environment.GetActiveConfigurationInfo().GetMode() == LAYERS_CONTROLLED_BY_CONFIGURATOR) { + if (configurator.configurations.GetActiveConfigurationInfo()->mode == LAYERS_CONTROLLED_BY_CONFIGURATOR) { shut_down_state = "Vulkan Layers override will remain in effect while Vulkan Configurator remain active in the system tray."; } else { diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 2d238c88bc..7e266e2e75 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -21,7 +21,7 @@ #pragma once -#include "configuration_layer_widget.h" +//#include "configuration_layer_widget.h" #include "tab_applications.h" #include "tab_configurations.h" #include "tab_diagnostics.h" @@ -43,57 +43,6 @@ #include #include -class LayerPathWidget : public QLabel { - Q_OBJECT - - public: - LayerPathWidget(const std::string &layer_path, QTreeWidget *list, QTreeWidgetItem *item) : item(item) { - this->button_edit = new QPushButton(this); - this->button_edit->setText("..."); - this->button_edit->show(); - this->buttom_remove = new QPushButton(this); - this->buttom_remove->setText("x"); - this->buttom_remove->show(); - - this->setText(layer_path.c_str()); - - item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - } - - QPushButton *button_edit; - QPushButton *buttom_remove; - - protected: - void resizeEvent(QResizeEvent *event) override { - QSize size = event->size(); - - const QFontMetrics fm = this->button_edit->fontMetrics(); - const int button_width_state = 30; - - const QRect edit_button_rect = - QRect(size.width() - button_width_state - button_width_state, 0, button_width_state, size.height()); - this->button_edit->setGeometry(edit_button_rect); - - const QRect remove_button_rect = QRect(size.width() - button_width_state, 0, button_width_state, size.height()); - this->buttom_remove->setGeometry(remove_button_rect); - } - - public: - QTreeWidgetItem *item; -}; - -class TreeWidgetItemParameter : public QTreeWidgetItem { - public: - TreeWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } - - std::string layer_name; - QWidget *widget; - - private: - TreeWidgetItemParameter(const TreeWidgetItemParameter &) = delete; - TreeWidgetItemParameter &operator=(const TreeWidgetItemParameter &) = delete; -}; - enum Tool { TOOL_VULKAN_INFO, TOOL_VULKAN_INSTALL }; class MainWindow : public QMainWindow { @@ -126,8 +75,6 @@ class MainWindow : public QMainWindow { QAction *_tray_layers_disabled_by_configurator; QAction *_tray_quit_action; - void AddLayerPathItem(const std::string &layer_path); - private slots: void trayActionRestore(); void trayActionControlledByApplications(bool checked); diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index ff8b7e5f22..c3f12f9b96 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -72,7 +72,7 @@ QTabWidget::Rounded - 3 + 2 @@ -549,7 +549,7 @@ - + 0 diff --git a/vkconfig_gui/tab.h b/vkconfig_gui/tab.h index 0741f62bf9..0cead4fad0 100644 --- a/vkconfig_gui/tab.h +++ b/vkconfig_gui/tab.h @@ -20,8 +20,6 @@ #pragma once -#include - #include "../vkconfig_core/type_tab.h" #include "ui_mainwindow.h" @@ -29,6 +27,9 @@ #include #include +#include +#include + class MainWindow; enum UpdateUIMode { diff --git a/vkconfig_gui/tab_applications.h b/vkconfig_gui/tab_applications.h index 917fc86a41..e5cb295be4 100644 --- a/vkconfig_gui/tab_applications.h +++ b/vkconfig_gui/tab_applications.h @@ -23,10 +23,17 @@ #include "tab.h" struct TabApplications : public Tab { + Q_OBJECT + + public: TabApplications(MainWindow& window, std::shared_ptr ui); virtual ~TabApplications(); virtual void UpdateUI(UpdateUIMode mode) override; virtual void CleanUI() override; virtual bool EventFilter(QObject* target, QEvent* event) override; + + public Q_SLOTS: + + private: }; diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index b995667f94..09e757e9a4 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -18,6 +18,7 @@ * - Christophe Riccio */ +#include "widget_tab_configurations_layer.h" #include "tab_configurations.h" #include "mainwindow.h" @@ -83,13 +84,13 @@ void TabConfigurations::UpdateUI_Configurations(UpdateUIMode ui_update_mode) { Configurator &configurator = Configurator::Get(); Environment &environment = configurator.environment; - LayersMode mode = environment.GetActiveConfigurationInfo().GetMode(); - const bool enabled_ui = mode == LAYERS_CONTROLLED_BY_CONFIGURATOR; + const ConfigurationInfo *configuration_info = configurator.configurations.GetActiveConfigurationInfo(); + assert(configuration_info != nullptr); - const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); + const bool enabled_ui = configuration_info->mode == LAYERS_CONTROLLED_BY_CONFIGURATOR; ui->combo_box_mode->blockSignals(true); - ui->combo_box_mode->setCurrentIndex(mode); + ui->combo_box_mode->setCurrentIndex(configuration_info->mode); ui->combo_box_mode->blockSignals(false); ui->configurations_list->blockSignals(true); @@ -124,7 +125,7 @@ void TabConfigurations::UpdateUI_Configurations(UpdateUIMode ui_update_mode) { Configuration *configuration = configurator.configurations.FindConfiguration(item->configuration_name); assert(configuration != nullptr); - if (item->configuration_name == selected_contiguration_name) { + if (item->configuration_name == configuration_info->name) { // TODO: add PartiallyChecked when the configuration is not working // HasMissingLayer(configuration.parameters, configurator.layers.available_layers) // item->setIcon(QIcon(":/resourcefiles/config-invalid.png")); @@ -149,9 +150,9 @@ void TabConfigurations::UpdateUI_Applications(UpdateUIMode ui_update_mode) { ui->combo_box_applications->setVisible(false); } else { ui->check_box_per_application->setEnabled(true); - ui->check_box_per_application->setChecked(configurator.environment.GetPerApplicationConfig()); + ui->check_box_per_application->setChecked(configurator.configurations.GetPerApplicationConfig()); - ui->combo_box_applications->setEnabled(configurator.environment.GetPerApplicationConfig()); + ui->combo_box_applications->setEnabled(configurator.configurations.GetPerApplicationConfig()); ui->combo_box_applications->blockSignals(true); @@ -201,7 +202,7 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { ui->configurations_layers_list->clear(); Configurator &configurator = Configurator::Get(); - const std::string &selected_contiguration_name = configurator.environment.GetActiveConfigurationInfo().GetName(); + const std::string &selected_contiguration_name = configurator.configurations.GetActiveConfigurationInfo()->name; const bool has_selected_configuration = !selected_contiguration_name.empty(); if (has_selected_configuration) { @@ -216,19 +217,14 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { } } - const Layer *layer = configurator.layers.Find(parameter.key); - ListWidgetItemParameter *item_state = new ListWidgetItemParameter(parameter.key.c_str()); item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); ui->configurations_layers_list->addItem(item_state); - std::vector layers; - if (layer != nullptr) { - layers.push_back(layer); - } + const std::vector &layer_versions = configurator.layers.GatherVersions(parameter.key); ConfigurationLayerWidget *layer_widget = - new ConfigurationLayerWidget(this, layers, parameter, configuration->view_advanced_layers); + new ConfigurationLayerWidget(this, parameter, layer_versions, configuration->view_advanced_layers); item_state->widget = layer_widget; if (parameter.control == LAYER_CONTROL_APPLICATIONS_API) { @@ -257,15 +253,11 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { void TabConfigurations::UpdateUI_Settings(UpdateUIMode mode) { Configurator &configurator = Configurator::Get(); - Environment &environment = configurator.environment; - - const std::string &selected_contiguration_name = environment.GetActiveConfigurationInfo().GetName(); - const bool has_selected_configuration = !selected_contiguration_name.empty(); - if (has_selected_configuration) { - this->_settings_tree_manager.CreateGUI(ui->configurations_presets_comboBox, ui->configurations_settings_tree); - } else { + if (configurator.configurations.GetActiveConfigurationInfo() == nullptr) { this->_settings_tree_manager.CleanupGUI(); + } else { + this->_settings_tree_manager.CreateGUI(ui->configurations_presets_comboBox, ui->configurations_settings_tree); } } @@ -277,10 +269,9 @@ void TabConfigurations::UpdateUI(UpdateUIMode ui_update_mode) { this->UpdateUI_Settings(ui_update_mode); Configurator &configurator = Configurator::Get(); - Environment &environment = configurator.environment; // Update the layers configuration area - LayersMode mode = environment.GetActiveConfigurationInfo().GetMode(); + LayersMode mode = configurator.configurations.GetActiveConfigurationInfo()->mode; const bool enabled_ui = mode == LAYERS_CONTROLLED_BY_CONFIGURATOR; ui->combo_box_mode->setCurrentIndex(mode); @@ -467,9 +458,9 @@ void TabConfigurations::OnSelectConfiguration(int currentRow) { } Configurator &configurator = Configurator::Get(); - if (configurator.environment.GetActiveConfigurationInfo().GetName() != configuration_item->configuration_name) { - configurator.environment.GetActiveConfigurationInfo().SetName(configuration_item->configuration_name); - // configurator.environment.selected_layer_name.clear(); + if (configurator.configurations.GetActiveConfigurationInfo()->name != configuration_item->configuration_name) { + configurator.configurations.GetActiveConfigurationInfo()->name = configuration_item->configuration_name; + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI_Configurations(UPDATE_REFRESH_UI); @@ -518,7 +509,7 @@ void TabConfigurations::OnRenameConfiguration(QListWidgetItem *item) { // Rename configuration ; Remove old configuration file ; change the name of the configuration configurator.configurations.RemoveConfigurationFile(old_name); configuration->key = configuration_item->configuration_name = new_name; - configurator.environment.GetActiveConfigurationInfo().SetName(new_name); + configurator.configurations.GetActiveConfigurationInfo()->name = new_name; this->UpdateUI_Configurations(UPDATE_REBUILD_UI); this->UpdateUI_LoaderMessages(); @@ -529,7 +520,7 @@ void TabConfigurations::OnRenameConfiguration(QListWidgetItem *item) { item->setText(old_name.c_str()); ui->configurations_list->blockSignals(false); - configurator.environment.GetActiveConfigurationInfo().SetName(old_name); + configurator.configurations.GetActiveConfigurationInfo()->name = old_name; } configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); @@ -543,7 +534,7 @@ void TabConfigurations::OnSelectLayer(int currentRow) { } QWidget *widget = ui->configurations_layers_list->itemWidget(ui->configurations_layers_list->item(currentRow)); - const std::string &layer_string = static_cast(widget)->text().toStdString(); + const std::string &layer_string = static_cast(widget)->text().toStdString(); Configurator &configurator = Configurator::Get(); configurator.GetActiveConfiguration()->selected_layer_name = ExtractLayerName(configurator.layers, layer_string); @@ -574,10 +565,7 @@ void TabConfigurations::OnCheckedLoaderMessageTypes(bool checked) { void TabConfigurations::OnContextMenuNewClicked(ConfigurationListItem *item) { Configurator &configurator = Configurator::Get(); - Configuration &new_configuration = - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); - - configurator.environment.GetActiveConfigurationInfo().SetName(new_configuration.key); + configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); configurator.Override(OVERRIDE_AREA_ALL); this->UpdateUI_Configurations(UPDATE_REBUILD_UI); @@ -598,10 +586,8 @@ void TabConfigurations::OnContextMenuImportClicked(ConfigurationListItem *item) } configurator.environment.path_import = selected_path; - std::string imported_configuration = - configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, selected_path); + configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, selected_path); - configurator.environment.GetActiveConfigurationInfo().SetName(imported_configuration); configurator.Override(OVERRIDE_AREA_ALL); this->UpdateUI_Configurations(UPDATE_REBUILD_UI); @@ -630,7 +616,6 @@ void TabConfigurations::OnContextMenuDuplicateClicked(ConfigurationListItem *ite item->configuration_name = duplicated_configuration.key; - configurator.environment.GetActiveConfigurationInfo().SetName(duplicated_configuration.key); configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI_Configurations(UPDATE_REBUILD_UI); @@ -653,8 +638,7 @@ void TabConfigurations::OnContextMenuDeleteClicked(ConfigurationListItem *item) } Configurator &configurator = Configurator::Get(); - configurator.configurations.RemoveConfiguration(configurator.layers.selected_layers, item->configuration_name); - configurator.environment.GetActiveConfigurationInfo().SetName(""); + configurator.configurations.RemoveConfiguration(item->configuration_name); this->UpdateUI_Configurations(UPDATE_REBUILD_UI); this->UpdateUI_Applications(UPDATE_REFRESH_UI); @@ -733,7 +717,7 @@ void TabConfigurations::OnContextMenuExportSettingsClicked(ConfigurationListItem void TabConfigurations::on_combo_box_mode_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); - configurator.environment.GetActiveConfigurationInfo().SetMode(static_cast(index)); + configurator.configurations.GetActiveConfigurationInfo()->mode = static_cast(index); configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->UpdateUI(UPDATE_REFRESH_UI); @@ -751,7 +735,7 @@ void TabConfigurations::on_combo_box_applications_currentIndexChanged(int index) void TabConfigurations::on_check_box_per_application_toggled(bool checked) { Configurator &configurator = Configurator::Get(); - configurator.environment.SetPerApplicationConfig(checked); + configurator.configurations.SetPerApplicationConfig(checked); configurator.Override(OVERRIDE_AREA_ALL); this->UpdateUI(UPDATE_REFRESH_UI); diff --git a/vkconfig_gui/tab_diagnostics.h b/vkconfig_gui/tab_diagnostics.h index 128043ca3e..f9950f6e51 100644 --- a/vkconfig_gui/tab_diagnostics.h +++ b/vkconfig_gui/tab_diagnostics.h @@ -23,10 +23,17 @@ #include "tab.h" struct TabDiagnostics : public Tab { + Q_OBJECT + + public: TabDiagnostics(MainWindow& window, std::shared_ptr ui); virtual ~TabDiagnostics(); virtual void UpdateUI(UpdateUIMode mode) override; virtual void CleanUI() override; virtual bool EventFilter(QObject* target, QEvent* event) override; + + public Q_SLOTS: + + private: }; diff --git a/vkconfig_gui/tab_help.h b/vkconfig_gui/tab_help.h index 8938c09c4e..6b786c26a9 100644 --- a/vkconfig_gui/tab_help.h +++ b/vkconfig_gui/tab_help.h @@ -23,10 +23,17 @@ #include "tab.h" struct TabHelp : public Tab { + Q_OBJECT + + public: TabHelp(MainWindow& window, std::shared_ptr ui); virtual ~TabHelp(); virtual void UpdateUI(UpdateUIMode mode) override; virtual void CleanUI() override; virtual bool EventFilter(QObject* target, QEvent* event) override; + + public Q_SLOTS: + + private: }; diff --git a/vkconfig_gui/tab_layers.cpp b/vkconfig_gui/tab_layers.cpp index 8b81bbe69f..d175d38471 100644 --- a/vkconfig_gui/tab_layers.cpp +++ b/vkconfig_gui/tab_layers.cpp @@ -18,14 +18,78 @@ * - Christophe Riccio */ +#include "widget_tab_layers_path.h" #include "tab_layers.h" #include "mainwindow.h" +#include "../vkconfig_core/configurator.h" + +class TreeWidgetItemParameter : public QTreeWidgetItem { + public: + TreeWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } + + std::string layer_name; + QWidget *widget; + + private: + TreeWidgetItemParameter(const TreeWidgetItemParameter &) = delete; + TreeWidgetItemParameter &operator=(const TreeWidgetItemParameter &) = delete; +}; + TabLayers::TabLayers(MainWindow &window, std::shared_ptr ui) : Tab(TAB_LAYERS, window, ui) {} TabLayers::~TabLayers() {} -void TabLayers::UpdateUI(UpdateUIMode mode) {} +void TabLayers::UpdateUI_LayersPaths(UpdateUIMode ui_update_mode) { + Configurator &configurator = Configurator::Get(); + + ui->layers_paths_tree->blockSignals(true); + ui->layers_paths_tree->clear(); + + for (std::size_t group_index = 0, group_count = configurator.layers.paths.size(); group_index < group_count; ++group_index) { + const LayerType layer_type = ::GetLayerType(static_cast(group_index)); + + const std::vector &paths_group = configurator.layers.paths[group_index]; + for (std::size_t i = 0, n = paths_group.size(); i < n; ++i) { + TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(paths_group[i].RelativePath().c_str()); + + item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); + item_state->setSizeHint(0, QSize(0, ITEM_HEIGHT)); + LayersPathWidget *layer_path_widget = new LayersPathWidget(paths_group[i].RelativePath()); + + layer_path_widget->setChecked(true); + + item_state->widget = layer_path_widget; + + ui->layers_paths_tree->addTopLevelItem(item_state); + ui->layers_paths_tree->setItemWidget(item_state, 0, layer_path_widget); + + const std::string &layer_path = paths_group[i].AbsolutePath(); + const std::vector &manifest_paths = CollectFilePaths(layer_path); + + for (std::size_t manifest_index = 0, manifest_count = manifest_paths.size(); manifest_index < manifest_count; + ++manifest_index) { + const Layer *layer = configurator.layers.FindFromManifest(manifest_paths[manifest_index]); + + QTreeWidgetItem *item = new QTreeWidgetItem; + + std::string label = + layer->key + " - " + layer->api_version.str() + " - " + format("%s layer", GetToken(layer->type)); + if (layer->status != STATUS_STABLE) { + label += format(" (%s)", GetToken(layer->status)); + } + item->setText(0, label.c_str()); + item->setToolTip(0, layer->manifest_path.AbsolutePath().c_str()); + item_state->addChild(item); + } + } + } + + ui->layers_paths_tree->expandAll(); + ui->layers_paths_tree->blockSignals(false); +} + +void TabLayers::UpdateUI(UpdateUIMode ui_update_mode) { this->UpdateUI_LayersPaths(ui_update_mode); } void TabLayers::CleanUI() {} diff --git a/vkconfig_gui/tab_layers.h b/vkconfig_gui/tab_layers.h index 5851aca1e4..0d9fc09906 100644 --- a/vkconfig_gui/tab_layers.h +++ b/vkconfig_gui/tab_layers.h @@ -23,10 +23,15 @@ #include "tab.h" struct TabLayers : public Tab { - TabLayers(MainWindow& window, std::shared_ptr ui); + Q_OBJECT + + public: + TabLayers(MainWindow &window, std::shared_ptr ui); virtual ~TabLayers(); virtual void UpdateUI(UpdateUIMode mode) override; virtual void CleanUI() override; - virtual bool EventFilter(QObject* target, QEvent* event) override; + virtual bool EventFilter(QObject *target, QEvent *event) override; + + void UpdateUI_LayersPaths(UpdateUIMode ui_update_mode); }; diff --git a/vkconfig_gui/tab_preferences.h b/vkconfig_gui/tab_preferences.h index b3cb0566c1..3e1a5f1db1 100644 --- a/vkconfig_gui/tab_preferences.h +++ b/vkconfig_gui/tab_preferences.h @@ -23,10 +23,17 @@ #include "tab.h" struct TabPreferences : public Tab { + Q_OBJECT + + public: TabPreferences(MainWindow& window, std::shared_ptr ui); virtual ~TabPreferences(); virtual void UpdateUI(UpdateUIMode mode) override; virtual void CleanUI() override; virtual bool EventFilter(QObject* target, QEvent* event) override; + + public Q_SLOTS: + + private: }; diff --git a/vkconfig_gui/configuration_layer_widget.cpp b/vkconfig_gui/widget_tab_configurations_layer.cpp similarity index 81% rename from vkconfig_gui/configuration_layer_widget.cpp rename to vkconfig_gui/widget_tab_configurations_layer.cpp index c4fe4ee081..4ffe606851 100644 --- a/vkconfig_gui/configuration_layer_widget.cpp +++ b/vkconfig_gui/widget_tab_configurations_layer.cpp @@ -18,7 +18,7 @@ * - Christophe Riccio */ -#include "configuration_layer_widget.h" +#include "widget_tab_configurations_layer.h" #include "widget_setting.h" #include "tab_configurations.h" @@ -93,48 +93,32 @@ static bool IsDLL32Bit(const std::string full_path) { #endif } -ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const std::vector &layers, - const Parameter ¶meter, bool advanced_view) +ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const Parameter ¶meter, + const std::vector &layer_versions, bool advanced_view) : tab(tab), layer_name(parameter.key) { // const bool is_implicit_layer = layers.empty() ? false : layers[0]->type == LAYER_TYPE_IMPLICIT; - Version api_version; + const Configurator &configurator = Configurator::Get(); + const Layer *layer = configurator.layers.FindFromVersion(parameter.key, parameter.api_version); if (parameter.control != LAYER_CONTROL_APPLICATIONS_API && parameter.control != LAYER_CONTROL_APPLICATIONS_ENV) { + assert(layer != nullptr); + this->layer_version = new QComboBox(this); this->layer_version->setVisible(advanced_view); this->layer_version->addItem("Latest"); - int version_index = 0; - - const Layer *selected_layer = nullptr; - const Layer *latest_layer = nullptr; - for (std::size_t i = 0, n = layers.size(); i < n; ++i) { - if (layers[i]->key != parameter.key) { - continue; - } - - if (latest_layer == nullptr) { - latest_layer = layers[i]; - } - - if (layers[i]->api_version == parameter.api_version) { - selected_layer = layers[i]; + int version_index = 0; + for (std::size_t i = 0, n = layer_versions.size(); i < n; ++i) { + if (layer_versions[i] == parameter.api_version) { version_index = this->layer_version->count(); - } else if (layers[i]->api_version > latest_layer->api_version) { - latest_layer = layers[i]; + + this->layer_version->setToolTip(layer->manifest_path.AbsolutePath().c_str()); } - this->layer_version->addItem(layers[i]->api_version.str().c_str()); + this->layer_version->addItem(layer_versions[i].str().c_str()); } this->layer_version->setCurrentIndex(version_index); - if (selected_layer != nullptr) { - api_version = selected_layer->api_version; - this->layer_version->setToolTip(selected_layer->manifest_path.AbsolutePath().c_str()); - } else if (latest_layer != nullptr) { - api_version = latest_layer->api_version; - this->layer_version->setToolTip(latest_layer->manifest_path.AbsolutePath().c_str()); - } // this->layer_version->setEnabled(layers.size() > 1); this->connect(this->layer_version, SIGNAL(currentIndexChanged(int)), this, SLOT(on_layer_version_currentIndexChanged(int))); @@ -144,7 +128,7 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const for (int i = LAYER_CONTROL_UI_FIRST; i <= LAYER_CONTROL_UI_LAST; ++i) { this->layer_state->addItem(GetToken(static_cast(i))); } - this->layer_state->setEnabled(!layers.empty()); + this->layer_state->setEnabled(!layer_versions.empty()); this->layer_state->setCurrentIndex(parameter.control); this->connect(this->layer_state, SIGNAL(currentIndexChanged(int)), this, SLOT(on_layer_state_currentIndexChanged(int))); // this->layer_state->installEventFilter(this); @@ -152,7 +136,7 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const std::string decorated_name = parameter.key; - if (layers.empty()) { + if (layer_versions.empty()) { // A layers configuration may have excluded layer that are misssing because they are not available on this platform // We simply hide these layers to avoid confusing the Vulkan developers if (parameter.control == LAYER_CONTROL_OFF) { @@ -163,12 +147,14 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const decorated_name += " (Missing)"; } } else { - if (!advanced_view && api_version != Version::VERSION_NULL) { - decorated_name += format(" - %s", api_version.str().c_str()); + assert(layer != nullptr); + + if (!advanced_view && parameter.api_version != Version::VERSION_NULL) { + decorated_name += format(" - %s", parameter.api_version.str().c_str()); } - if (layers[0]->status != STATUS_STABLE) { - decorated_name += format(" (%s)", GetToken(layers[0]->status)); + if (layer->status != STATUS_STABLE) { + decorated_name += format(" (%s)", GetToken(layer->status)); } // if (IsDLL32Bit(layer->manifest_path)) { diff --git a/vkconfig_gui/configuration_layer_widget.h b/vkconfig_gui/widget_tab_configurations_layer.h similarity index 90% rename from vkconfig_gui/configuration_layer_widget.h rename to vkconfig_gui/widget_tab_configurations_layer.h index 8b40a963d4..c7cccf7b10 100644 --- a/vkconfig_gui/configuration_layer_widget.h +++ b/vkconfig_gui/widget_tab_configurations_layer.h @@ -21,7 +21,6 @@ #pragma once #include "../vkconfig_core/parameter.h" -#include "../vkconfig_core/layer.h" #include "ui_mainwindow.h" @@ -38,7 +37,7 @@ class ConfigurationLayerWidget : public QLabel { Q_OBJECT public: - ConfigurationLayerWidget(TabConfigurations *tab, const std::vector &layers, const Parameter ¶meter, + ConfigurationLayerWidget(TabConfigurations *tab, const Parameter ¶meter, const std::vector &layer_version, bool advanced_view); protected: diff --git a/vkconfig_gui/widget_tab_layers_path.cpp b/vkconfig_gui/widget_tab_layers_path.cpp new file mode 100644 index 0000000000..021f683591 --- /dev/null +++ b/vkconfig_gui/widget_tab_layers_path.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "widget_tab_layers_path.h" + +#include + +LayersPathWidget::LayersPathWidget(const std::string &layer_path) { + this->button_edit = new QPushButton(this); + this->button_edit->setText("..."); + this->button_edit->show(); + this->buttom_remove = new QPushButton(this); + this->buttom_remove->setText("x"); + this->buttom_remove->show(); + + this->setText(layer_path.c_str()); + this->setToolTip("Load layers in this location"); + + this->connect(this->button_edit, SIGNAL(clicked(bool)), this, SLOT(on_button_edit_clicked(bool))); + this->connect(this->button_edit, SIGNAL(clicked(bool)), this, SLOT(on_button_edit_clicked(bool))); + this->connect(this->buttom_remove, SIGNAL(clicked(bool)), this, SLOT(on_buttom_remove_clicked(bool))); +} + +void LayersPathWidget::resizeEvent(QResizeEvent *event) { + QSize size = event->size(); + + const QFontMetrics fm = this->button_edit->fontMetrics(); + const int button_width_state = 30; + + const QRect edit_button_rect = + QRect(size.width() - button_width_state - button_width_state, 0, button_width_state, size.height()); + this->button_edit->setGeometry(edit_button_rect); + + const QRect remove_button_rect = QRect(size.width() - button_width_state, 0, button_width_state, size.height()); + this->buttom_remove->setGeometry(remove_button_rect); +} + +void LayersPathWidget::on_button_edit_clicked(bool checked) { + (void)checked; + + const std::string selected_path = + QFileDialog::getExistingDirectory(this->button_edit, "Select Folder", this->text()).toStdString(); +} + +void LayersPathWidget::on_buttom_remove_clicked(bool checked) { + (void)checked; + + // emit itemChanged(); +} + +void LayersPathWidget::on_checkStateChanged(Qt::CheckState state) {} diff --git a/vkconfig_gui/widget_tab_layers_path.h b/vkconfig_gui/widget_tab_layers_path.h new file mode 100644 index 0000000000..0350d08db6 --- /dev/null +++ b/vkconfig_gui/widget_tab_layers_path.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include +#include +#include + +class LayersPathWidget : public QCheckBox { + Q_OBJECT + + public: + LayersPathWidget(const std::string &layer_path); + + protected: + void resizeEvent(QResizeEvent *event) override; + + public Q_SLOTS: + void on_button_edit_clicked(bool checked = false); + void on_buttom_remove_clicked(bool checked = false); + void on_checkStateChanged(Qt::CheckState state); + + public: + QPushButton *button_edit = nullptr; + QPushButton *buttom_remove = nullptr; +}; From 1089bccc851527456f6a9953ebc1711d044bf878 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 2 Sep 2024 15:36:27 +0200 Subject: [PATCH 19/33] vkconfig3: Add Layer manager unit tests --- vkconfig_cmd/main_doc.cpp | 2 +- vkconfig_core/configuration.cpp | 4 +- vkconfig_core/configuration_manager.cpp | 13 ++- vkconfig_core/configurator.cpp | 2 +- vkconfig_core/layer_manager.cpp | 54 +++++----- vkconfig_core/layer_manager.h | 8 +- .../layers/VK_LAYER_LUNARG_version_135.json | 20 ++++ .../layers/VK_LAYER_LUNARG_version_193.json | 20 ++++ .../layers/VK_LAYER_LUNARG_version_204.json | 20 ++++ .../layers/VK_LAYER_LUNARG_version_290.json | 20 ++++ vkconfig_core/test/resources.qrc | 5 + vkconfig_core/test/test_layer_manager.cpp | 100 +++++++++++++++--- vkconfig_core/test/test_path.cpp | 2 +- vkconfig_gui/settings_tree.cpp | 2 +- vkconfig_gui/tab_configurations.cpp | 4 +- vkconfig_gui/vkconfig.pro | 10 +- 16 files changed, 225 insertions(+), 61 deletions(-) create mode 100644 vkconfig_core/test/layers/VK_LAYER_LUNARG_version_135.json create mode 100644 vkconfig_core/test/layers/VK_LAYER_LUNARG_version_193.json create mode 100644 vkconfig_core/test/layers/VK_LAYER_LUNARG_version_204.json create mode 100644 vkconfig_core/test/layers/VK_LAYER_LUNARG_version_290.json diff --git a/vkconfig_cmd/main_doc.cpp b/vkconfig_cmd/main_doc.cpp index 29e145db3f..9ffd483370 100644 --- a/vkconfig_cmd/main_doc.cpp +++ b/vkconfig_cmd/main_doc.cpp @@ -65,7 +65,7 @@ int run_doc_settings(const CommandLine& command_line) { LayerManager layers; - Layer* layer = layers.Find(command_line.doc_layer_name.c_str()); + const Layer* layer = layers.FindFromVersion(command_line.doc_layer_name.c_str(), Version::VERSION_NULL); if (!layer) { fprintf(stderr, "vkconfig: Could not load layer %s\n", command_line.doc_layer_name.c_str()); fprintf(stderr, "Run \"vkconfig layers --list\" to get list of available layers\n"); diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index eb82e4a65e..ae55285b9b 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -366,7 +366,7 @@ Parameter* Configuration::Find(std::string parameter_key) { void Configuration::Reset(const std::vector& available_layers) { // Case 1: reset using built-in configuration files const std::vector& builtin_configuration_files = CollectFilePaths(":/configurations/"); - for (int i = 0, n = builtin_configuration_files.size(); i < n; ++i) { + for (std::size_t i = 0, n = builtin_configuration_files.size(); i < n; ++i) { const std::string& basename = builtin_configuration_files[i].Basename(); if (this->key == basename) { @@ -421,7 +421,7 @@ bool Configuration::HasOverride() const { bool Configuration::IsBuiltIn() const { const std::vector& builtin_configuration_files = CollectFilePaths(":/configurations/"); - for (int i = 0, n = builtin_configuration_files.size(); i < n; ++i) { + for (std::size_t i = 0, n = builtin_configuration_files.size(); i < n; ++i) { const std::string& basename = builtin_configuration_files[i].Basename(); if (basename == this->key) { diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index d936a528d4..a819636f0c 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -25,7 +25,10 @@ const char *GLOBAL_CONFIGURATION_TOKEN = "GLOBAL"; -ConfigurationManager::ConfigurationManager() {} +ConfigurationManager::ConfigurationManager() { + ConfigurationInfo info; + this->configuration_infos.insert(std::make_pair(GLOBAL_CONFIGURATION_TOKEN, info)); +} ConfigurationManager::~ConfigurationManager() {} @@ -125,7 +128,7 @@ void ConfigurationManager::LoadAllConfigurations(const std::vector &avail void ConfigurationManager::LoadDefaultConfigurations(const std::vector &available_layers) { const std::vector &configuration_files = CollectFilePaths(":/configurations/"); - for (int i = 0, n = configuration_files.size(); i < n; ++i) { + for (std::size_t i = 0, n = configuration_files.size(); i < n; ++i) { Configuration configuration; const bool result = configuration.Load(configuration_files[i], available_layers); assert(result); @@ -174,7 +177,7 @@ void ConfigurationManager::SortConfigurations() { void ConfigurationManager::LoadConfigurationsPath(const std::vector &available_layers) { const std::vector &configuration_files = CollectFilePaths(Get(Path::CONFIGS)); - for (int i = 0, n = configuration_files.size(); i < n; ++i) { + for (std::size_t i = 0, n = configuration_files.size(); i < n; ++i) { Configuration configuration; const bool result = configuration.Load(configuration_files[i], available_layers); if (!result) { @@ -289,14 +292,14 @@ bool ConfigurationManager::HasFile(const Configuration &configuration) const { void ConfigurationManager::RemoveConfigurationFiles() { const std::vector &configuration_files = CollectFilePaths(Get(Path::CONFIGS)); - for (int i = 0, n = configuration_files.size(); i < n; ++i) { + for (std::size_t i = 0, n = configuration_files.size(); i < n; ++i) { configuration_files[i].Remove(); } } void ConfigurationManager::RemoveConfigurationFile(const std::string &key) { const std::vector &configuration_files = CollectFilePaths(Get(Path::CONFIGS)); - for (int j = 0, o = configuration_files.size(); j < o; ++j) { + for (std::size_t j = 0, o = configuration_files.size(); j < o; ++j) { if (configuration_files[j].Basename() == key) { configuration_files[j].Remove(); } diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index fe34dd8391..ef0eac581c 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -323,7 +323,7 @@ bool Configurator::WriteLayersSettings(OverrideArea override_area, const Path& l continue; } - const Layer* layer = this->layers.Find(parameter.key.c_str()); + const Layer* layer = this->layers.FindFromVersion(parameter.key.c_str(), parameter.api_version); if (layer == nullptr) { has_missing_layers = true; continue; diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 91aed7a71b..1139577467 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -181,6 +181,7 @@ bool LayerManager::Save(QJsonObject &json_root_object) const { } void LayerManager::Reset() { + this->selected_layers.clear(); this->layers_validated.clear(); this->paths[LAYERS_PATHS_SDK].clear(); } @@ -191,18 +192,6 @@ bool LayerManager::Empty() const { return this->selected_layers.empty(); } std::size_t LayerManager::Size() const { return this->selected_layers.size(); } -Layer *LayerManager::Find(const std::string &layer_name) { - assert(!layer_name.empty()); - - return FindByKey(this->selected_layers, layer_name.c_str()); -} - -const Layer *LayerManager::Find(const std::string &layer_name) const { - assert(!layer_name.empty()); - - return FindByKey(this->selected_layers, layer_name.c_str()); -} - std::vector LayerManager::GatherVersions(const std::string &layer_name) const { std::vector result; @@ -259,6 +248,15 @@ const Layer *LayerManager::FindFromManifest(const Path &manifest_path) const { return nullptr; } +Layer *LayerManager::FindFromManifest(const Path &manifest_path) { + for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (this->selected_layers[i].manifest_path == manifest_path) { + return &this->selected_layers[i]; + } + } + return nullptr; +} + // Find all installed layers on the system. void LayerManager::LoadAllInstalledLayers() { this->selected_layers.clear(); @@ -277,23 +275,25 @@ void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { const std::vector &layers_paths = layers_path.IsDir() ? CollectFilePaths(layers_path) : GetVector(layers_path); for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { - Layer layer; - if (layer.Load(layers_paths[i], this->layers_validated, type)) { - if (this->IsAvailable(layer)) { - continue; + const std::string &last_modified = layers_paths[i].LastModified(); + + Layer *already_loaded_layer = this->FindFromManifest(layers_paths[i]); + if (already_loaded_layer != nullptr) { + // Already loaded + auto it = this->layers_validated.find(layers_paths[i].AbsolutePath()); + if (it != layers_validated.end()) { + if (last_modified == it->second) { + continue; // Already loaded and up to date + } } - this->selected_layers.push_back(layer); - } - } -} - -bool LayerManager::IsAvailable(const Layer &layer) const { - for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { - if (this->selected_layers[i].key == layer.key && this->selected_layers[i].api_version == layer.api_version) { - return true; + // Reload + already_loaded_layer->Load(layers_paths[i], this->layers_validated, type); + } else { + Layer layer; + if (layer.Load(layers_paths[i], this->layers_validated, type)) { + this->selected_layers.push_back(layer); + } } } - - return false; } diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index 4a02d347eb..c8c20c4174 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -64,15 +64,15 @@ class LayerManager : public Serialize { bool Empty() const; std::size_t Size() const; - Layer* Find(const std::string& layer_name); - const Layer* Find(const std::string& layer_name) const; + // Layer* Find(const std::string& layer_name); + // const Layer* Find(const std::string& layer_name) const; std::vector GatherVersions(const std::string& layer_name) const; const Layer* FindFromVersion(const std::string& layer_name, const Version& version) const; const Layer* FindFromManifest(const Path& manifest_path) const; + Layer* FindFromManifest(const Path& manifest_path); void LoadAllInstalledLayers(); - void LoadLayersFromPath(const Path& layers_path, LayerType type = LAYER_TYPE_EXPLICIT); std::vector selected_layers; @@ -80,6 +80,4 @@ class LayerManager : public Serialize { private: std::map layers_validated; - - bool IsAvailable(const Layer& layer) const; }; diff --git a/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_135.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_135.json new file mode 100644 index 0000000000..ae39debb75 --- /dev/null +++ b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_135.json @@ -0,0 +1,20 @@ +{ + "file_format_version" : "1.1.0", + "layer": { + "name": "VK_LAYER_LUNARG_version", + "type": "GLOBAL", + "library_path": ".\\VkLayer_version.dll", + "api_version": "1.1.135", + "implementation_version": "Build 64", + "description": "version layer", + "device_extensions": [ + { + "name": "VK_EXT_tooling_info", + "spec_version": "1", + "entrypoints": [ + "vkGetPhysicalDeviceToolPropertiesEXT" + ] + } + ] + } +} diff --git a/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_193.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_193.json new file mode 100644 index 0000000000..08ccd2effa --- /dev/null +++ b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_193.json @@ -0,0 +1,20 @@ +{ + "file_format_version" : "1.1.0", + "layer": { + "name": "VK_LAYER_LUNARG_version", + "type": "GLOBAL", + "library_path": ".\\VkLayer_version.dll", + "api_version": "1.2.193", + "implementation_version": "Build 64", + "description": "version layer", + "device_extensions": [ + { + "name": "VK_EXT_tooling_info", + "spec_version": "1", + "entrypoints": [ + "vkGetPhysicalDeviceToolPropertiesEXT" + ] + } + ] + } +} diff --git a/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_204.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_204.json new file mode 100644 index 0000000000..a90ecacf22 --- /dev/null +++ b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_204.json @@ -0,0 +1,20 @@ +{ + "file_format_version" : "1.1.0", + "layer": { + "name": "VK_LAYER_LUNARG_version", + "type": "GLOBAL", + "library_path": ".\\VkLayer_version.dll", + "api_version": "1.3.204", + "implementation_version": "Build 75", + "description": "version layer", + "device_extensions": [ + { + "name": "VK_EXT_tooling_info", + "spec_version": "1", + "entrypoints": [ + "vkGetPhysicalDeviceToolPropertiesEXT" + ] + } + ] + } +} diff --git a/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_290.json b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_290.json new file mode 100644 index 0000000000..c7dfca6d2b --- /dev/null +++ b/vkconfig_core/test/layers/VK_LAYER_LUNARG_version_290.json @@ -0,0 +1,20 @@ +{ + "file_format_version" : "1.1.0", + "layer": { + "name": "VK_LAYER_LUNARG_version", + "type": "GLOBAL", + "library_path": ".\\VkLayer_version.dll", + "api_version": "1.3.290", + "implementation_version": "Build 90", + "description": "version layer", + "device_extensions": [ + { + "name": "VK_EXT_tooling_info", + "spec_version": "1", + "entrypoints": [ + "vkGetPhysicalDeviceToolPropertiesEXT" + ] + } + ] + } +} diff --git a/vkconfig_core/test/resources.qrc b/vkconfig_core/test/resources.qrc index c3de24915b..ccdf627cea 100644 --- a/vkconfig_core/test/resources.qrc +++ b/vkconfig_core/test/resources.qrc @@ -34,6 +34,11 @@ ./layers/VK_LAYER_LUNARG_test_04.json ./layers/VK_LAYER_LUNARG_test_05.json ./layers/VK_LAYER_LUNARG_test_06.json + + ./layers/VK_LAYER_LUNARG_version_135.json + ./layers/VK_LAYER_LUNARG_version_193.json + ./layers/VK_LAYER_LUNARG_version_204.json + ./layers/VK_LAYER_LUNARG_version_290.json diff --git a/vkconfig_core/test/test_layer_manager.cpp b/vkconfig_core/test/test_layer_manager.cpp index 6b96fc156a..2dee7287b0 100644 --- a/vkconfig_core/test/test_layer_manager.cpp +++ b/vkconfig_core/test/test_layer_manager.cpp @@ -33,9 +33,8 @@ TEST(test_layer_manager, clear) { TEST(test_layer_manager, load_all) { LayerManager layer_manager; layer_manager.LoadLayersFromPath(":/layers"); - layer_manager.LoadAllInstalledLayers(); - EXPECT_TRUE(layer_manager.Size() >= 10); + EXPECT_EQ(14, layer_manager.Size()); EXPECT_TRUE(!layer_manager.Empty()); layer_manager.Clear(); @@ -47,11 +46,7 @@ TEST(test_layer_manager, load_dir) { EXPECT_TRUE(layer_manager.Empty()); layer_manager.LoadLayersFromPath(":/layers"); - - EXPECT_TRUE(!layer_manager.Empty()); - EXPECT_EQ(10, layer_manager.Size()); - - EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); + EXPECT_TRUE(layer_manager.FindFromVersion("VK_LAYER_LUNARG_reference_1_1_0", Version::VERSION_NULL) != nullptr); layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); @@ -66,19 +61,96 @@ TEST(test_layer_manager, load_file) { EXPECT_TRUE(!layer_manager.Empty()); EXPECT_EQ(1, layer_manager.Size()); - EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); + EXPECT_TRUE(layer_manager.FindFromVersion("VK_LAYER_LUNARG_reference_1_1_0", Version::VERSION_NULL) != nullptr); layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); } -TEST(test_layer_manager, find) { +TEST(test_layer_manager, reset) { LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + EXPECT_FALSE(layer_manager.Empty()); + + layer_manager.Reset(); EXPECT_TRUE(layer_manager.Empty()); +} + +TEST(test_layer_manager, find) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + EXPECT_TRUE(layer_manager.FindFromVersion("VK_LAYER_LUNARG_test_03", Version::VERSION_NULL) != nullptr); + + const Layer* layer = layer_manager.FindFromVersion("VK_LAYER_LUNARG_reference_1_1_0", Version::VERSION_NULL); + EXPECT_TRUE(layer != nullptr); + EXPECT_STREQ(layer->key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); +} + +TEST(test_layer_manager, FindFromVersion) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + const Layer* layer135 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 1, 135)); + EXPECT_TRUE(layer135 != nullptr); + EXPECT_STREQ(layer135->key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_EQ(layer135->api_version, Version(1, 1, 135)); - EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0") != nullptr); - EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_test_03") != nullptr); + const Layer* layer193 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 2, 193)); + EXPECT_TRUE(layer193 != nullptr); + EXPECT_STREQ(layer193->key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_EQ(layer193->api_version, Version(1, 2, 193)); + + const Layer* layer204 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 3, 204)); + EXPECT_TRUE(layer204 != nullptr); + EXPECT_STREQ(layer204->key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_EQ(layer204->api_version, Version(1, 3, 204)); + + const Layer* layer290 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 3, 290)); + EXPECT_TRUE(layer290 != nullptr); + EXPECT_STREQ(layer290->key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_EQ(layer290->api_version, Version(1, 3, 290)); + + const Layer* layer_latest = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version::VERSION_NULL); + EXPECT_TRUE(layer_latest != nullptr); + EXPECT_STREQ(layer_latest->key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_EQ(layer_latest->api_version, Version(1, 3, 290)); + + const Layer* layer_not_found_version = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 3, 208)); + EXPECT_TRUE(layer_not_found_version == nullptr); + + const Layer* layer_not_found_key = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version_not_found", Version(1, 3, 290)); + EXPECT_TRUE(layer_not_found_key == nullptr); +} + +TEST(test_layer_manager, FindFromManifest) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + const Layer* layer204 = layer_manager.FindFromManifest(":/layers/VK_LAYER_LUNARG_version_204.json"); + EXPECT_TRUE(layer204 != nullptr); + EXPECT_STREQ(layer204->key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_EQ(layer204->api_version, Version(1, 3, 204)); + + const Layer* layer208 = layer_manager.FindFromManifest(":/layers/VK_LAYER_LUNARG_version_208.json"); + EXPECT_TRUE(layer208 == nullptr); +} + +TEST(test_layer_manager, GatherVersions) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + const std::vector& versions_found = layer_manager.GatherVersions("VK_LAYER_LUNARG_version"); + EXPECT_FALSE(versions_found.empty()); + EXPECT_EQ(versions_found.size(), 4); + EXPECT_EQ(versions_found[0], Version(1, 1, 135)); + EXPECT_EQ(versions_found[1], Version(1, 2, 193)); + EXPECT_EQ(versions_found[2], Version(1, 3, 204)); + EXPECT_EQ(versions_found[3], Version(1, 3, 290)); + + const std::vector& versions_notfound = layer_manager.GatherVersions("VK_LAYER_LUNARG_version_not_found"); + EXPECT_TRUE(versions_notfound.empty()); } TEST(test_layer_manager, avoid_duplicate) { @@ -86,8 +158,10 @@ TEST(test_layer_manager, avoid_duplicate) { EXPECT_TRUE(layer_manager.Empty()); layer_manager.LoadLayersFromPath(":/layers"); - EXPECT_EQ(10, layer_manager.Size()); + std::size_t first_load_count = layer_manager.Size(); layer_manager.LoadLayersFromPath(":/layers"); - EXPECT_EQ(10, layer_manager.Size()); + std::size_t second_load_count = layer_manager.Size(); + + EXPECT_EQ(first_load_count, second_load_count); } diff --git a/vkconfig_core/test/test_path.cpp b/vkconfig_core/test/test_path.cpp index e18c85cb92..321d3d68cf 100644 --- a/vkconfig_core/test/test_path.cpp +++ b/vkconfig_core/test/test_path.cpp @@ -276,7 +276,7 @@ TEST(test_path, collect_file_paths_success_set1) { TEST(test_path, collect_file_paths_success_set2) { const std::vector& paths = CollectFilePaths(":/layers/"); - EXPECT_EQ(paths.size(), 10); + EXPECT_EQ(paths.size(), 14); EXPECT_STREQ(Path(":/layers/VK_LAYER_LUNARG_reference_1_1_0.json").AbsolutePath().c_str(), paths[0].AbsolutePath().c_str()); } diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 074ebbdec1..2a43a0c014 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -418,7 +418,7 @@ void SettingsTreeManager::OnPresetChanged(int combox_preset_index) { if (preset_label == Layer::NO_PRESET) return; Configurator &configurator = Configurator::Get(); - const Layer *layer = configurator.layers.Find(this->parameter->key.c_str()); + const Layer *layer = configurator.layers.FindFromVersion(this->parameter->key.c_str(), Version::VERSION_NULL); const LayerPreset *preset = GetPreset(layer->presets, preset_label.c_str()); assert(preset != nullptr); diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index 09e757e9a4..1067e1ac2c 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -294,7 +294,7 @@ static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { Configurator &configurator = Configurator::Get(); const std::string &layer_key = ExtractLayerName(configurator.layers, layer_string); - return configurator.layers.Find(layer_key); + return configurator.layers.FindFromVersion(layer_key, Version::VERSION_NULL); } return nullptr; @@ -563,6 +563,8 @@ void TabConfigurations::OnCheckedLoaderMessageTypes(bool checked) { } void TabConfigurations::OnContextMenuNewClicked(ConfigurationListItem *item) { + (void)item; // We don't need this + Configurator &configurator = Configurator::Get(); configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index a1624348b9..d0632752c8 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -74,7 +74,9 @@ SOURCES += \ ../vkconfig_core/version.cpp \ ../vkconfig_core/vulkan_info.cpp \ ../vkconfig_core/vulkan_util.cpp \ - configuration_layer_widget.cpp \ + widget_tab_configurations_layer.cpp \ + widget_tab_layers_path.cpp \ + widget_tree_friendly_combobox.cpp \ widget_preset.cpp \ widget_setting.cpp \ widget_setting_bool.cpp \ @@ -87,7 +89,6 @@ SOURCES += \ widget_setting_string.cpp \ widget_setting_list_element.cpp \ widget_setting_list.cpp \ - widget_tree_friendly_combobox.cpp \ dialog_vulkan_analysis.cpp \ dialog_vulkan_info.cpp \ main.cpp \ @@ -149,7 +150,9 @@ HEADERS += \ ../vkconfig_core/version.h \ ../vkconfig_core/vulkan_info.h \ ../vkconfig_core/vulkan_util.h \ - configuration_layer_widget.h \ + widget_tab_configurations_layer.h \ + widget_tab_layers_path.h \ + widget_tree_friendly_combobox.h \ widget_preset.h \ widget_setting.h \ widget_setting_bool.h \ @@ -162,7 +165,6 @@ HEADERS += \ widget_setting_string.h \ widget_setting_list_element.h \ widget_setting_list.h \ - widget_tree_friendly_combobox.h \ dialog_vulkan_analysis.h \ dialog_vulkan_info.h \ mainwindow.h \ From 97eea7354cb08615d91174fd8c49a0e67a26b421 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 2 Sep 2024 18:59:04 +0200 Subject: [PATCH 20/33] vkconfig3: Layers Paths tab UI --- vkconfig_cmd/main_doc.cpp | 6 +- vkconfig_cmd/main_layers.cpp | 3 +- vkconfig_core/configuration.cpp | 48 ++--- vkconfig_core/configuration.h | 10 +- vkconfig_core/configuration_manager.cpp | 40 ++-- vkconfig_core/configuration_manager.h | 14 +- vkconfig_core/configurator.cpp | 4 +- vkconfig_core/layer.cpp | 6 +- vkconfig_core/layer.h | 9 +- vkconfig_core/layer_manager.cpp | 189 ++++++++++++++---- vkconfig_core/layer_manager.h | 23 +-- vkconfig_core/parameter.cpp | 32 ++- vkconfig_core/parameter.h | 6 +- vkconfig_core/path.cpp | 2 + vkconfig_core/path.h | 2 +- vkconfig_core/registry.cpp | 10 +- vkconfig_core/registry.h | 2 +- vkconfig_core/test/test_configuration.cpp | 6 +- .../test/test_configuration_built_in.cpp | 7 +- .../test/test_configuration_manager.cpp | 14 +- vkconfig_core/test/test_layer.cpp | 2 +- vkconfig_core/test/test_layer_manager.cpp | 61 ++++-- vkconfig_core/test/test_vulkan.cpp | 2 +- vkconfig_core/version.cpp | 3 +- vkconfig_core/version.h | 3 +- vkconfig_core/vulkan_info.h | 2 +- vkconfig_gui/main.cpp | 2 +- vkconfig_gui/settings_tree.cpp | 2 +- vkconfig_gui/tab_configurations.cpp | 15 +- vkconfig_gui/tab_layers.cpp | 79 ++++++-- vkconfig_gui/tab_layers.h | 6 + .../widget_tab_configurations_layer.cpp | 6 +- vkconfig_gui/widget_tab_layers_path.cpp | 39 ++-- vkconfig_gui/widget_tab_layers_path.h | 9 +- 34 files changed, 422 insertions(+), 242 deletions(-) diff --git a/vkconfig_cmd/main_doc.cpp b/vkconfig_cmd/main_doc.cpp index 9ffd483370..6a39c120fb 100644 --- a/vkconfig_cmd/main_doc.cpp +++ b/vkconfig_cmd/main_doc.cpp @@ -65,7 +65,7 @@ int run_doc_settings(const CommandLine& command_line) { LayerManager layers; - const Layer* layer = layers.FindFromVersion(command_line.doc_layer_name.c_str(), Version::VERSION_NULL); + const Layer* layer = layers.Find(command_line.doc_layer_name.c_str(), Version::LATEST); if (!layer) { fprintf(stderr, "vkconfig: Could not load layer %s\n", command_line.doc_layer_name.c_str()); fprintf(stderr, "Run \"vkconfig layers --list\" to get list of available layers\n"); @@ -73,8 +73,8 @@ int run_doc_settings(const CommandLine& command_line) { } ConfigurationManager configuration_manager; - Configuration config = configuration_manager.CreateConfiguration(layers.selected_layers, "Config"); - config.parameters = GatherParameters(config.parameters, layers.selected_layers); + Configuration config = configuration_manager.CreateConfiguration(layers, "Config"); + config.parameters = GatherParameters(config.parameters, layers); config.parameters[0].control = LAYER_CONTROL_ON; ExportSettingsDoc(layers.selected_layers, config, command_line.doc_out_dir + "/vk_layer_settings.txt"); diff --git a/vkconfig_cmd/main_layers.cpp b/vkconfig_cmd/main_layers.cpp index f4f8fc983a..6368bfcc67 100644 --- a/vkconfig_cmd/main_layers.cpp +++ b/vkconfig_cmd/main_layers.cpp @@ -28,8 +28,7 @@ static int RunLayersOverride(Configurator& configurator, const CommandLine& command_line) { Configuration configuration; - const bool load_result = - configuration.Load(command_line.layers_configuration_path.c_str(), configurator.layers.selected_layers); + const bool load_result = configuration.Load(command_line.layers_configuration_path.c_str(), configurator.layers); if (!load_result) { printf("\nFailed to load the layers configuration file...\n"); return -1; diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index ae55285b9b..f1cd2adab5 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -20,6 +20,7 @@ */ #include "configuration.h" +#include "layer_manager.h" #include "util.h" #include "path.h" #include "json.h" @@ -78,21 +79,21 @@ static void AddApplicationEnabledParameters(std::vector& parameters) } } -Configuration Configuration::Create(const std::vector& available_layers, const std::string& key) { +Configuration Configuration::Create(const LayerManager& layers, const std::string& key) { Configuration result; result.key = key; - result.parameters = GatherParameters(result.parameters, available_layers); + result.parameters = GatherParameters(result.parameters, layers); AddApplicationEnabledParameters(result.parameters); return result; } -Configuration Configuration::CreateDisabled(const std::vector& available_layers) { +Configuration Configuration::CreateDisabled(const LayerManager& layers) { Configuration result; result.key = "_DisablingConfiguration"; - result.parameters = GatherParameters(result.parameters, available_layers); + result.parameters = GatherParameters(result.parameters, layers); for (std::size_t i = 0, n = result.parameters.size(); i < n; ++i) { result.parameters[i].control = LAYER_CONTROL_OFF; @@ -103,7 +104,7 @@ Configuration Configuration::CreateDisabled(const std::vector& available_ return result; } -bool Configuration::Load(const Path& full_path, const std::vector& available_layers) { +bool Configuration::Load(const Path& full_path, const LayerManager& layers) { assert(!full_path.Empty()); this->parameters.clear(); @@ -196,7 +197,7 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa parameter.overridden_rank = ReadIntValue(json_layer_object, "rank"); parameter.control = GetLayerControl(ReadStringValue(json_layer_object, "control").c_str()); const std::string& version = ReadStringValue(json_layer_object, "version"); - parameter.api_version = version == "latest" ? Version::VERSION_NULL : Version(version.c_str()); + parameter.api_version = version == "latest" ? Version::LATEST : Version(version.c_str()); const QJsonValue& json_platform_value = json_layer_object.value("platforms"); if (json_platform_value != QJsonValue::Undefined) { @@ -208,23 +209,7 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa parameter.setting_tree_state = json_layer_object.value("expanded_states").toVariant().toByteArray(); } - const Layer* layer = nullptr; - for (std::size_t i = 0, n = available_layers.size(); i < n; ++i) { - const Layer& current_layer = available_layers[i]; - if (current_layer.key != parameter.key) { - continue; - } - - if (parameter.api_version == Version::VERSION_NULL) { - if (layer == nullptr) { - layer = ¤t_layer; - } else if (layer->api_version < current_layer.api_version) { - layer = ¤t_layer; - } - } else if (parameter.api_version == current_layer.api_version) { - layer = ¤t_layer; - } - } + const Layer* layer = layers.Find(parameter.key, parameter.api_version); if (layer != nullptr) { CollectDefaultSettingData(layer->settings, parameter.settings); @@ -254,7 +239,7 @@ bool Configuration::Load(const Path& full_path, const std::vector& availa this->parameters.push_back(parameter); } - this->parameters = GatherParameters(this->parameters, available_layers); + this->parameters = GatherParameters(this->parameters, layers); AddApplicationEnabledParameters(this->parameters); @@ -285,8 +270,7 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { json_layer.insert("name", parameter.key.c_str()); json_layer.insert("rank", parameter.overridden_rank); json_layer.insert("control", GetToken(parameter.control)); - json_layer.insert("version", - parameter.api_version == Version::VERSION_NULL ? "latest" : parameter.api_version.str().c_str()); + json_layer.insert("version", parameter.api_version == Version::LATEST ? "latest" : parameter.api_version.str().c_str()); SaveStringArray(json_layer, "platforms", GetPlatformTokens(parameter.platform_flags)); if (!exporter && !parameter.setting_tree_state.isEmpty()) { json_layer.insert("expanded_states", parameter.setting_tree_state.data()); @@ -363,17 +347,17 @@ Parameter* Configuration::Find(std::string parameter_key) { return nullptr; } -void Configuration::Reset(const std::vector& available_layers) { +void Configuration::Reset(const LayerManager& layers) { // Case 1: reset using built-in configuration files const std::vector& builtin_configuration_files = CollectFilePaths(":/configurations/"); for (std::size_t i = 0, n = builtin_configuration_files.size(); i < n; ++i) { const std::string& basename = builtin_configuration_files[i].Basename(); if (this->key == basename) { - const bool result = this->Load(builtin_configuration_files[i], available_layers); + const bool result = this->Load(builtin_configuration_files[i], layers); assert(result); - OrderParameter(this->parameters, available_layers); + OrderParameter(this->parameters, layers.selected_layers); return; } } @@ -384,10 +368,10 @@ void Configuration::Reset(const std::vector& available_layers) { std::FILE* file = std::fopen(full_path.AbsolutePath().c_str(), "r"); if (file) { std::fclose(file); - const bool result = this->Load(full_path, available_layers); + const bool result = this->Load(full_path, layers); assert(result); - OrderParameter(this->parameters, available_layers); + OrderParameter(this->parameters, layers.selected_layers); return; } @@ -401,7 +385,7 @@ void Configuration::Reset(const std::vector& available_layers) { } } - OrderParameter(this->parameters, available_layers); + OrderParameter(this->parameters, layers.selected_layers); } } diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index 58e11f157d..c7060799b7 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -29,17 +29,19 @@ #include #include +class LayerManager; + class Configuration { public: - static Configuration CreateDisabled(const std::vector& available_layers); - static Configuration Create(const std::vector& available_layers, const std::string& key); + static Configuration CreateDisabled(const LayerManager& layers); + static Configuration Create(const LayerManager& layers, const std::string& key); - bool Load(const Path& full_path, const std::vector& available_layers); + bool Load(const Path& full_path, const LayerManager& layers); bool Save(const Path& full_path, bool exporter = false) const; bool HasOverride() const; Parameter* Find(std::string parameter_key); - void Reset(const std::vector& available_layers); + void Reset(const LayerManager& layers); std::size_t Size() const { return this->parameters.size(); }; diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index a819636f0c..46c232afac 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -65,7 +65,7 @@ bool ConfigurationManager::Load(const QJsonObject &json_root_object) { } } - this->LoadAllConfigurations(Configurator::Get().layers.selected_layers); + this->LoadAllConfigurations(Configurator::Get().layers); return true; } @@ -107,30 +107,30 @@ void ConfigurationManager::Reset() { this->configuration_infos.clear(); this->available_configurations.clear(); - this->LoadDefaultConfigurations(Configurator::Get().layers.selected_layers); + this->LoadDefaultConfigurations(Configurator::Get().layers); this->SortConfigurations(); ConfigurationInfo info; this->configuration_infos.insert(std::make_pair(GLOBAL_CONFIGURATION_TOKEN, info)); } -void ConfigurationManager::LoadAllConfigurations(const std::vector &available_layers) { +void ConfigurationManager::LoadAllConfigurations(const LayerManager &layers) { this->available_configurations.clear(); - this->LoadConfigurationsPath(available_layers); + this->LoadConfigurationsPath(layers); // If built-in configurations were updated, replace the stored configuration - this->LoadDefaultConfigurations(available_layers); + this->LoadDefaultConfigurations(layers); this->SortConfigurations(); } -void ConfigurationManager::LoadDefaultConfigurations(const std::vector &available_layers) { +void ConfigurationManager::LoadDefaultConfigurations(const LayerManager &layers) { const std::vector &configuration_files = CollectFilePaths(":/configurations/"); for (std::size_t i = 0, n = configuration_files.size(); i < n; ++i) { Configuration configuration; - const bool result = configuration.Load(configuration_files[i], available_layers); + const bool result = configuration.Load(configuration_files[i], layers); assert(result); if (!IsPlatformSupported(configuration.platform_flags)) { @@ -145,7 +145,7 @@ void ConfigurationManager::LoadDefaultConfigurations(const std::vector &a } #endif - OrderParameter(configuration.parameters, available_layers); + OrderParameter(configuration.parameters, layers.selected_layers); Configuration *found_configuration = this->FindConfiguration(configuration.key); if (found_configuration == nullptr) { @@ -175,11 +175,11 @@ void ConfigurationManager::SortConfigurations() { std::sort(this->available_configurations.begin(), this->available_configurations.end(), Compare()); } -void ConfigurationManager::LoadConfigurationsPath(const std::vector &available_layers) { +void ConfigurationManager::LoadConfigurationsPath(const LayerManager &layers) { const std::vector &configuration_files = CollectFilePaths(Get(Path::CONFIGS)); for (std::size_t i = 0, n = configuration_files.size(); i < n; ++i) { Configuration configuration; - const bool result = configuration.Load(configuration_files[i], available_layers); + const bool result = configuration.Load(configuration_files[i], layers); if (!result) { continue; } @@ -189,8 +189,8 @@ void ConfigurationManager::LoadConfigurationsPath(const std::vector &avai } std::string missing_layer; - if (!HasMissingLayer(configuration.parameters, available_layers, missing_layer)) { - OrderParameter(configuration.parameters, available_layers); + if (!HasMissingLayer(configuration.parameters, layers.selected_layers, missing_layer)) { + OrderParameter(configuration.parameters, layers.selected_layers); } available_configurations.push_back(configuration); @@ -253,8 +253,8 @@ bool ConfigurationManager::HasActiveConfiguration() const { return false; } -Configuration &ConfigurationManager::CreateConfiguration(const std::vector &available_layers, - const std::string &configuration_name, bool duplicate) { +Configuration &ConfigurationManager::CreateConfiguration(const LayerManager &layers, const std::string &configuration_name, + bool duplicate) { Configuration *duplicate_configuration = FindByKey(available_configurations, configuration_name.c_str()); Configuration new_configuration = duplicate_configuration != nullptr && duplicate ? *duplicate_configuration : Configuration(); @@ -265,7 +265,7 @@ Configuration &ConfigurationManager::CreateConfiguration(const std::vectoravailable_configurations.push_back(configuration); @@ -359,11 +359,11 @@ const Configuration *ConfigurationManager::FindConfiguration(const std::string & return FindByKey(this->available_configurations, configuration_name.c_str()); } -void ConfigurationManager::ImportConfiguration(const std::vector &available_layers, const Path &full_import_path) { +void ConfigurationManager::ImportConfiguration(const LayerManager &layers, const Path &full_import_path) { assert(!full_import_path.Empty()); Configuration configuration; - if (!configuration.Load(full_import_path, available_layers)) { + if (!configuration.Load(full_import_path, layers)) { QMessageBox msg; msg.setIcon(QMessageBox::Critical); msg.setWindowTitle("Import of Layers Configuration error"); @@ -380,7 +380,7 @@ void ConfigurationManager::ImportConfiguration(const std::vector &availab this->GetActiveConfigurationInfo()->name = configuration.key; } -void ConfigurationManager::ExportConfiguration(const std::vector &available_layers, const Path &full_export_path, +void ConfigurationManager::ExportConfiguration(const LayerManager &layers, const Path &full_export_path, const std::string &configuration_name) { assert(!configuration_name.empty()); assert(!full_export_path.Empty()); @@ -405,7 +405,7 @@ bool ConfigurationManager::CheckApiVersions(const std::vector &available_ bool ConfigurationManager::CheckLayersVersions(const std::vector &available_layers, Configuration *selected_configuration, std::string &log_versions) const { - return this->CompareLayersVersions(available_layers, selected_configuration, Version::VERSION_NULL, log_versions, false); + return this->CompareLayersVersions(available_layers, selected_configuration, Version::NONE, log_versions, false); } bool ConfigurationManager::CompareLayersVersions(const std::vector &available_layers, Configuration *selected_configuration, @@ -428,7 +428,7 @@ bool ConfigurationManager::CompareLayersVersions(const std::vector &avail const Layer &layer = available_layers[layer_index]; if (layer.key == parameter.key) { - if (current_version == Version::VERSION_NULL) { + if (current_version == Version::NONE) { current_version = layer.api_version; } diff --git a/vkconfig_core/configuration_manager.h b/vkconfig_core/configuration_manager.h index 005b6e15e1..fdf54bbc49 100644 --- a/vkconfig_core/configuration_manager.h +++ b/vkconfig_core/configuration_manager.h @@ -39,7 +39,7 @@ class ConfigurationManager : public Serialize { bool Save(QJsonObject& json_root_object) const override; void Reset() override; - void LoadAllConfigurations(const std::vector& available_layers); + void LoadAllConfigurations(const LayerManager& layers); void SaveAllConfigurations() const; const ConfigurationInfo* GetActiveConfigurationInfo() const; @@ -48,14 +48,12 @@ class ConfigurationManager : public Serialize { const std::map& GetConfigurationInfos() const; bool HasActiveConfiguration() const; - Configuration& CreateConfiguration(const std::vector& available_layers, const std::string& configuration_name, - bool duplicate = false); + Configuration& CreateConfiguration(const LayerManager& layers, const std::string& configuration_name, bool duplicate = false); void RemoveConfiguration(const std::string& configuration_name); - void ImportConfiguration(const std::vector& available_layers, const Path& full_import_path); - void ExportConfiguration(const std::vector& available_layers, const Path& full_export_path, - const std::string& configuration_name); + void ImportConfiguration(const LayerManager& layers, const Path& full_import_path); + void ExportConfiguration(const LayerManager& layers, const Path& full_export_path, const std::string& configuration_name); const Configuration* FindConfiguration(const std::string& configuration_name) const; Configuration* FindConfiguration(const std::string& configuration_name); @@ -86,8 +84,8 @@ class ConfigurationManager : public Serialize { void RemoveConfigurationFiles(); - void LoadConfigurationsPath(const std::vector& available_layers); - void LoadDefaultConfigurations(const std::vector& available_layers); + void LoadConfigurationsPath(const LayerManager& layers); + void LoadDefaultConfigurations(const LayerManager& layers); std::map removed_built_in_configuration; bool use_system_tray = false; diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index ef0eac581c..fd34cec15e 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -155,7 +155,7 @@ void Configurator::BuildLoaderSettings(const ConfigurationInfo& info, const std: LoaderSettings result; result.executable_path = executable_path; - static Configuration disbled_configuration = Configuration::CreateDisabled(this->layers.selected_layers); + static Configuration disbled_configuration = Configuration::CreateDisabled(this->layers); const Configuration* configuration = nullptr; switch (info.mode) { @@ -323,7 +323,7 @@ bool Configurator::WriteLayersSettings(OverrideArea override_area, const Path& l continue; } - const Layer* layer = this->layers.FindFromVersion(parameter.key.c_str(), parameter.api_version); + const Layer* layer = this->layers.Find(parameter.key.c_str(), parameter.api_version); if (layer == nullptr) { has_missing_layers = true; continue; diff --git a/vkconfig_core/layer.cpp b/vkconfig_core/layer.cpp index d7c6ff9202..eba7b9caca 100644 --- a/vkconfig_core/layer.cpp +++ b/vkconfig_core/layer.cpp @@ -65,8 +65,8 @@ Layer::Layer(const std::string& key, const Version& file_format_version, const V // Todo: Load the layer with Vulkan API bool Layer::IsValid() const { - return file_format_version != Version::VERSION_NULL && !key.empty() && !binary_path.Empty() && - api_version != Version::VERSION_NULL && !implementation_version.empty(); + return file_format_version != Version::NONE && !key.empty() && !binary_path.Empty() && api_version != Version::NONE && + !implementation_version.empty(); } std::string Layer::FindPresetLabel(const SettingDataSet& settings) const { @@ -134,7 +134,7 @@ SettingMeta* Layer::Instantiate(SettingMetaSet& meta_set, const std::string& key return setting_meta; } -bool Layer::Load(const Path& full_path_to_file, const std::map& layers_validated, LayerType type) { +bool Layer::Load(const Path& full_path_to_file, const std::map& layers_validated, LayerType type) { this->type = type; // Set layer type, no way to know this from the json file if (full_path_to_file.Empty()) { diff --git a/vkconfig_core/layer.h b/vkconfig_core/layer.h index 871238dbde..afc0e35d8d 100644 --- a/vkconfig_core/layer.h +++ b/vkconfig_core/layer.h @@ -34,6 +34,12 @@ #include #include +struct LayersPathInfo { + Path path; + LayerType type = LAYER_TYPE_EXPLICIT; + bool enabled = true; +}; + class Layer { public: static const char* NO_PRESET; @@ -72,11 +78,12 @@ class Layer { std::string enable_env; bool disable_value; bool enable_value; + bool visible = true; std::vector settings; std::vector presets; - bool Load(const Path& full_path_to_file, const std::map& layers_validated, + bool Load(const Path& full_path_to_file, const std::map& layers_validated, LayerType type = LAYER_TYPE_EXPLICIT); private: diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 1139577467..5b6f7f3d24 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -33,8 +33,8 @@ LayerType GetLayerType(LayersPaths Layers_paths_type) { } } -std::vector GetImplicitLayerPaths() { - std::vector result; +std::vector GetImplicitLayerPaths() { + std::vector result; #if VKC_PLATFORM == VKC_PLATFORM_WINDOWS static const char *REGISTRY_PATHS[] = { @@ -43,7 +43,7 @@ std::vector GetImplicitLayerPaths() { "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Class\\...\\VulkanImplicitLayers"}; for (std::size_t i = 0, n = std::size(REGISTRY_PATHS); i < n; ++i) { - const std::vector ®istry_paths = LoadRegistryLayers(REGISTRY_PATHS[i]); + const std::vector ®istry_paths = LoadRegistryLayers(REGISTRY_PATHS[i]); result.insert(result.begin(), registry_paths.begin(), registry_paths.end()); } #else @@ -62,15 +62,17 @@ std::vector GetImplicitLayerPaths() { }; for (std::size_t i = 0, n = std::size(LAYERS_PATHS); i < n; ++i) { - result.push_back(LAYERS_PATHS[i]); + LayersPathInfo info; + info.path = LAYERS_PATHS[i]; + result.push_back(info); } #endif return result; } -std::vector GetExplicitLayerPaths() { - std::vector result; +std::vector GetExplicitLayerPaths() { + std::vector result; #if VKC_PLATFORM == VKC_PLATFORM_WINDOWS static const char *REGISTRY_PATHS[] = { @@ -79,7 +81,7 @@ std::vector GetExplicitLayerPaths() { "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Class\\...\\VulkanExplicitLayers"}; for (std::size_t i = 0, n = std::size(REGISTRY_PATHS); i < n; ++i) { - const std::vector ®istry_paths = LoadRegistryLayers(REGISTRY_PATHS[i]); + const std::vector ®istry_paths = LoadRegistryLayers(REGISTRY_PATHS[i]); result.insert(result.begin(), registry_paths.begin(), registry_paths.end()); } #else @@ -98,13 +100,27 @@ std::vector GetExplicitLayerPaths() { }; for (std::size_t i = 0, n = std::size(LAYERS_PATHS); i < n; ++i) { - result.push_back(LAYERS_PATHS[i]); + LayersPathInfo info; + info.path = LAYERS_PATHS[i]; + result.push_back(info); } #endif return result; } +static LayersPathInfo *FindPathInfo(std::array, LAYERS_PATHS_COUNT> &paths, const std::string &path) { + for (int paths_type_index = LAYERS_PATHS_FIRST; paths_type_index <= LAYERS_PATHS_LAST; ++paths_type_index) { + for (int i = 0, n = paths[paths_type_index].size(); i < n; ++i) { + if (paths[paths_type_index][i].path == path) { + return &paths[paths_type_index][i]; + } + } + } + + return nullptr; +} + LayerManager::LayerManager() {} LayerManager::~LayerManager() {} @@ -116,39 +132,59 @@ bool LayerManager::Load(const QJsonObject &json_root_object) { const char *SEPARATOR = GetToken(PARSE_ENV_VAR); - const std::vector &VK_LAYER_PATH = UniqueStrings(Split(qgetenv("VK_LAYER_PATH").toStdString(), SEPARATOR)); - for (std::size_t i = 0, n = VK_LAYER_PATH.size(); i < n; ++i) { - this->paths[LAYERS_PATHS_ENV_SET].push_back(VK_LAYER_PATH[i]); + // LAYERS_PATHS_ENV_SET: VK_LAYER_PATH env variables + { + const std::vector &VK_LAYER_PATH = UniqueStrings(Split(qgetenv("VK_LAYER_PATH").toStdString(), SEPARATOR)); + this->paths[LAYERS_PATHS_ENV_SET].resize(VK_LAYER_PATH.size()); + for (std::size_t i = 0, n = VK_LAYER_PATH.size(); i < n; ++i) { + this->paths[LAYERS_PATHS_ENV_SET][i].path = VK_LAYER_PATH[i]; + this->paths[LAYERS_PATHS_ENV_SET][i].enabled = true; + } } - const std::vector &VK_ADD_LAYER_PATH = UniqueStrings(Split(qgetenv("VK_ADD_LAYER_PATH").toStdString(), SEPARATOR)); - for (std::size_t i = 0, n = VK_ADD_LAYER_PATH.size(); i < n; ++i) { - this->paths[LAYERS_PATHS_ENV_SET].push_back(VK_ADD_LAYER_PATH[i]); + // LAYERS_PATHS_ENV_ADD: VK_ADD_LAYER_PATH env variables + { + const std::vector &VK_ADD_LAYER_PATH = UniqueStrings(Split(qgetenv("VK_ADD_LAYER_PATH").toStdString(), SEPARATOR)); + this->paths[LAYERS_PATHS_ENV_ADD].resize(VK_ADD_LAYER_PATH.size()); + for (std::size_t i = 0, n = VK_ADD_LAYER_PATH.size(); i < n; ++i) { + this->paths[LAYERS_PATHS_ENV_ADD][i].path = VK_ADD_LAYER_PATH[i]; + this->paths[LAYERS_PATHS_ENV_ADD][i].enabled = true; + } } - this->paths[LAYERS_PATHS_SDK].push_back(::Get(Path::SDK_BIN)); + // LAYERS_PATHS_SDK + { + LayersPathInfo info; + info.path = ::Get(Path::SDK_BIN); + info.enabled = true; + this->paths[LAYERS_PATHS_SDK].push_back(info); + } + // LAYERS_PATHS_GUI if (json_root_object.value("layers") != QJsonValue::Undefined) { const QJsonObject &json_layers_object = json_root_object.value("layers").toObject(); if (json_layers_object.value("validated") != QJsonValue::Undefined) { const QJsonObject &json_layers_validated_object = json_layers_object.value("validated").toObject(); - const QStringList &json_layers_validated_keys = json_layers_validated_object.keys(); for (int i = 0, n = json_layers_validated_keys.length(); i < n; ++i) { - const std::string &manifest_path = json_layers_validated_keys[i].toStdString(); + const Path &manifest_path = json_layers_validated_keys[i].toStdString(); const std::string &last_modified = - json_layers_validated_object.value(manifest_path.c_str()).toString().toStdString(); + json_layers_validated_object.value(json_layers_validated_keys[i]).toString().toStdString(); this->layers_validated.insert(std::make_pair(manifest_path, last_modified)); } } - if (json_layers_object.value("user_defined_paths") != QJsonValue::Undefined) { - const QJsonArray &json_array = json_layers_object.value("user_defined_paths").toArray(); + if (json_layers_object.value("paths") != QJsonValue::Undefined) { + const QJsonObject &json_paths_object = json_layers_object.value("paths").toObject(); + const QStringList &json_paths_keys = json_paths_object.keys(); - for (int i = 0, n = json_array.size(); i < n; ++i) { - this->paths[LAYERS_PATHS_GUI].push_back(json_array[i].toString().toStdString()); + for (int i = 0, n = json_paths_keys.length(); i < n; ++i) { + LayersPathInfo info; + info.path = json_paths_keys[i].toStdString(); + info.enabled = json_paths_object.value(json_paths_keys[i].toStdString().c_str()).toBool(); + this->AddPath(info); } } } @@ -166,14 +202,23 @@ bool LayerManager::Save(QJsonObject &json_root_object) const { json_layers_paths_object.insert(layer.manifest_path.AbsolutePath().c_str(), layer.validated_last_modified.c_str()); } - QJsonArray json_user_defined_paths_array; - for (std::size_t i = 0, n = this->paths[LAYERS_PATHS_GUI].size(); i < n; ++i) { - json_user_defined_paths_array.append(this->paths[LAYERS_PATHS_GUI][i].RelativePath().c_str()); + QJsonObject json_paths_object; + for (int paths_type_index = LAYERS_PATHS_FIRST; paths_type_index <= LAYERS_PATHS_LAST; ++paths_type_index) { + for (std::size_t i = 0, n = this->paths[paths_type_index].size(); i < n; ++i) { + json_paths_object.insert(this->paths[paths_type_index][i].path.RelativePath().c_str(), + this->paths[paths_type_index][i].enabled); + } + } + + QJsonArray json_removed_paths_array; + for (std::size_t i = 0, n = this->removed_paths.size(); i < n; ++i) { + json_removed_paths_array.append(this->removed_paths[i].RelativePath().c_str()); } QJsonObject json_layers_object; json_layers_object.insert("validated", json_layers_paths_object); - json_layers_object.insert("user_defined_paths", json_user_defined_paths_array); + json_layers_object.insert("paths", json_paths_object); + json_layers_object.insert("removed_paths", json_removed_paths_array); json_root_object.insert("layers", json_layers_object); @@ -196,33 +241,39 @@ std::vector LayerManager::GatherVersions(const std::string &layer_name) std::vector result; for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (!this->selected_layers[i].visible) { + continue; + } + if (this->selected_layers[i].key == layer_name) { result.push_back(this->selected_layers[i].api_version); } } + std::sort(result.rbegin(), result.rend()); + return result; } -const Layer *LayerManager::FindFromVersion(const std::string &layer_name, const Version &layer_version) const { +const Layer *LayerManager::Find(const std::string &layer_name, const Version &layer_version) const { // Version::VERSION_NULL refer to latest version - if (layer_version == Version::VERSION_NULL) { + if (layer_version == Version::LATEST) { const std::vector &version = this->GatherVersions(layer_name); if (version.empty()) { return nullptr; } - Version latest = Version::VERSION_NULL; + Version latest = Version::NONE; for (std::size_t i = 0, n = version.size(); i < n; ++i) { - if (latest == Version::VERSION_NULL) { + if (latest == Version::NONE) { latest = version[i]; } else if (version[i] > latest) { latest = version[i]; } } - assert(latest != Version::VERSION_NULL); + assert(latest != Version::NONE); - return FindFromVersion(layer_name, latest); + return this->Find(layer_name, latest); } else { for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { if (this->selected_layers[i].key != layer_name) { @@ -234,6 +285,9 @@ const Layer *LayerManager::FindFromVersion(const std::string &layer_name, const return &this->selected_layers[i]; } + + // Version not found, search for the latest available + return this->Find(layer_name, Version::LATEST); } return nullptr; @@ -264,15 +318,15 @@ void LayerManager::LoadAllInstalledLayers() { for (std::size_t group_index = 0, group_count = this->paths.size(); group_index < group_count; ++group_index) { const LayerType layer_type = ::GetLayerType(static_cast(group_index)); - const std::vector &paths_group = this->paths[group_index]; + const std::vector &paths_group = this->paths[group_index]; for (std::size_t i = 0, n = paths_group.size(); i < n; ++i) { - this->LoadLayersFromPath(paths_group[i], layer_type); + this->LoadLayersFromPath(paths_group[i].path, layer_type); } } } void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { - const std::vector &layers_paths = layers_path.IsDir() ? CollectFilePaths(layers_path) : GetVector(layers_path); + const std::vector &layers_paths = CollectFilePaths(layers_path); for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { const std::string &last_modified = layers_paths[i].LastModified(); @@ -280,7 +334,7 @@ void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { Layer *already_loaded_layer = this->FindFromManifest(layers_paths[i]); if (already_loaded_layer != nullptr) { // Already loaded - auto it = this->layers_validated.find(layers_paths[i].AbsolutePath()); + auto it = this->layers_validated.find(layers_paths[i]); if (it != layers_validated.end()) { if (last_modified == it->second) { continue; // Already loaded and up to date @@ -297,3 +351,66 @@ void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { } } } + +void LayerManager::AddPath(const LayersPathInfo &info) { + LayersPathInfo *existing_info = FindPathInfo(this->paths, info.path.RelativePath()); + if (existing_info != nullptr) { + existing_info->enabled = info.enabled; + } else { + this->paths[LAYERS_PATHS_GUI].push_back(info); + } +} + +void LayerManager::RemovePath(const LayersPathInfo &path_info) { + this->removed_paths.push_back(path_info.path); + + const std::vector &layers_paths = CollectFilePaths(path_info.path); + + for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { + Layer *layer = this->FindFromManifest(layers_paths[i]); + if (layer == nullptr) { + continue; + } + + layer->visible = false; + } + + for (int paths_type_index = LAYERS_PATHS_FIRST; paths_type_index <= LAYERS_PATHS_LAST; ++paths_type_index) { + std::vector new_path_list; + for (std::size_t i = 0, n = this->paths[paths_type_index].size(); i < n; ++i) { + if (path_info.path == this->paths[paths_type_index][i].path) { + continue; + } + + new_path_list.push_back(this->paths[paths_type_index][i]); + } + this->paths[paths_type_index] = new_path_list; + } +} + +void LayerManager::UpdatePath(const LayersPathInfo &path_info) { + const std::vector &layers_paths = CollectFilePaths(path_info.path); + + for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { + Layer *layer = this->FindFromManifest(layers_paths[i]); + if (layer == nullptr) { + continue; + } + + layer->visible = path_info.enabled; + } +} + +std::vector LayerManager::BuildLayerNameList() const { + std::vector result; + + for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (std::find(result.begin(), result.end(), this->selected_layers[i].key) != result.end()) { + continue; + } + + result.push_back(this->selected_layers[i].key); + } + + return result; +} diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index c8c20c4174..864b9126cc 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -44,13 +44,6 @@ enum { LAYERS_PATHS_COUNT = LAYERS_PATHS_LAST - LAYERS_PATHS_FIRST + 1 }; LayerType GetLayerType(LayersPaths Layers_paths_type); -struct LayersPathInfo { - Path path; - std::vector layers; - - bool enabled = true; -}; - class LayerManager : public Serialize { public: LayerManager(); @@ -64,20 +57,24 @@ class LayerManager : public Serialize { bool Empty() const; std::size_t Size() const; - // Layer* Find(const std::string& layer_name); - // const Layer* Find(const std::string& layer_name) const; - std::vector GatherVersions(const std::string& layer_name) const; - const Layer* FindFromVersion(const std::string& layer_name, const Version& version) const; + const Layer* Find(const std::string& layer_name, const Version& version = Version::LATEST) const; const Layer* FindFromManifest(const Path& manifest_path) const; Layer* FindFromManifest(const Path& manifest_path); void LoadAllInstalledLayers(); void LoadLayersFromPath(const Path& layers_path, LayerType type = LAYER_TYPE_EXPLICIT); + void AddPath(const LayersPathInfo& path_info); + void RemovePath(const LayersPathInfo& path_info); + void UpdatePath(const LayersPathInfo& path_info); + + std::vector BuildLayerNameList() const; + std::vector selected_layers; - std::array, LAYERS_PATHS_COUNT> paths; + std::array, LAYERS_PATHS_COUNT> paths; + std::vector removed_paths; private: - std::map layers_validated; + std::map layers_validated; }; diff --git a/vkconfig_core/parameter.cpp b/vkconfig_core/parameter.cpp index 61328da85f..82d3a6e174 100644 --- a/vkconfig_core/parameter.cpp +++ b/vkconfig_core/parameter.cpp @@ -79,18 +79,26 @@ ParameterRank GetParameterOrdering(const std::vector& available_layers, c Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const std::vector& layers) { - if (parameters.empty()) return Version::VERSION_NULL; + if (parameters.empty()) { + return Version::NONE; + } Version min_version = api_version; for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { const Layer* layer = FindByKey(layers, parameters[i].key.c_str()); - if (layer == nullptr) continue; + if (layer == nullptr) { + continue; + } const ParameterRank state = GetParameterOrdering(layers, parameters[i]); - if (state == PARAMETER_RANK_EXCLUDED) continue; - if (state == PARAMETER_RANK_MISSING) continue; + if (state == PARAMETER_RANK_EXCLUDED) { + continue; + } + if (state == PARAMETER_RANK_MISSING) { + continue; + } min_version = min_version < layer->api_version ? min_version : layer->api_version; } @@ -221,7 +229,7 @@ std::size_t CountExcludedLayers(const std::vector& parameters, const return count; } -std::vector GatherParameters(const std::vector& parameters, const std::vector& available_layers) { +std::vector GatherParameters(const std::vector& parameters, const LayerManager& layers) { std::vector gathered_parameters; // Loop through the layers. They are expected to be in order @@ -232,19 +240,21 @@ std::vector GatherParameters(const std::vector& parameters gathered_parameters.push_back(parameter); } - for (std::size_t i = 0, n = available_layers.size(); i < n; ++i) { - const Layer& layer = available_layers[i]; + const std::vector& list = layers.BuildLayerNameList(); + + for (std::size_t i = 0, n = list.size(); i < n; ++i) { + const Layer* layer = layers.Find(list[i], Version::LATEST); // The layer is already in the layer tree - if (IsFound(parameters, layer.key.c_str())) { + if (IsFound(parameters, layer->key.c_str())) { continue; } Parameter parameter; - parameter.key = layer.key; + parameter.key = layer->key; parameter.control = LAYER_CONTROL_AUTO; - parameter.api_version = Version::VERSION_NULL; - CollectDefaultSettingData(layer.settings, parameter.settings); + parameter.api_version = Version::LATEST; + CollectDefaultSettingData(layer->settings, parameter.settings); gathered_parameters.push_back(parameter); } diff --git a/vkconfig_core/parameter.h b/vkconfig_core/parameter.h index 3339f94b0f..5bf3fb0565 100644 --- a/vkconfig_core/parameter.h +++ b/vkconfig_core/parameter.h @@ -20,7 +20,7 @@ #pragma once -#include "layer.h" +#include "layer_manager.h" #include "setting.h" #include "type_layer_control.h" @@ -49,7 +49,7 @@ struct Parameter { int platform_flags = PLATFORM_DESKTOP_BIT; SettingDataSet settings; int overridden_rank = NO_RANK; - Version api_version = Version::VERSION_NULL; + Version api_version = Version::LATEST; QByteArray setting_tree_state; // Recall editor tree state }; @@ -57,7 +57,7 @@ ParameterRank GetParameterOrdering(const std::vector& available_layers, c Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const std::vector& layers); void OrderParameter(std::vector& parameters, const std::vector& layers); void FilterParameters(std::vector& parameters, const LayerControl control); -std::vector GatherParameters(const std::vector& parameters, const std::vector& available_layers); +std::vector GatherParameters(const std::vector& parameters, const LayerManager& layers); bool HasMissingLayer(const std::vector& parameters, const std::vector& layers, std::string& missing_layer); diff --git a/vkconfig_core/path.cpp b/vkconfig_core/path.cpp index 6690d9048b..f6fb5be082 100644 --- a/vkconfig_core/path.cpp +++ b/vkconfig_core/path.cpp @@ -217,6 +217,8 @@ bool operator==(const Path& a, const Path& b) { return a.AbsolutePath() == b.Abs Path operator+(const Path& path, const std::string& extend) { return Path(path.data + extend); } +bool operator<(const Path& a, const Path& b) { return a.RelativePath() < b.RelativePath(); } + static const Path GetHomePath() { std::string result = qgetenv("VK_HOME").toStdString(); diff --git a/vkconfig_core/path.h b/vkconfig_core/path.h index 4babccdcf4..0ca021d335 100644 --- a/vkconfig_core/path.h +++ b/vkconfig_core/path.h @@ -79,8 +79,8 @@ std::string AbsolutePath(Path::Builtin path); std::string RelativePath(Path::Builtin path); bool operator==(const Path& a, const Path& b); - Path operator+(const Path& path, const std::string& extend); +bool operator<(const Path& a, const Path& b); std::vector CollectFilePaths(const Path& directory, const char* filter = "*json"); diff --git a/vkconfig_core/registry.cpp b/vkconfig_core/registry.cpp index b2accffa16..0b80ade1b7 100644 --- a/vkconfig_core/registry.cpp +++ b/vkconfig_core/registry.cpp @@ -83,7 +83,7 @@ void RemoveRegistryEntriesForLayers(QString loader_settings_file, QString layers } /// Look for device specific layers -static void LoadDeviceRegistry(DEVINST id, const QString &entry, std::vector &layers_paths) { +static void LoadDeviceRegistry(DEVINST id, const QString &entry, std::vector &layers_paths) { HKEY key; if (CM_Open_DevNode_Key(id, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &key, CM_REGISTRY_SOFTWARE) != CR_SUCCESS) return; @@ -103,7 +103,9 @@ static void LoadDeviceRegistry(DEVINST id, const QString &entry, std::vector LoadRegistryLayers(const QString &path) { - std::vector layers_paths; +std::vector LoadRegistryLayers(const QString &path) { + std::vector layers_paths; QString root_string = path.section('\\', 0, 0); static QHash root_keys = { diff --git a/vkconfig_core/registry.h b/vkconfig_core/registry.h index 2b587180f8..7696fc8401 100644 --- a/vkconfig_core/registry.h +++ b/vkconfig_core/registry.h @@ -33,6 +33,6 @@ void AppendRegistryEntriesForLayers(QString override_file, QString settings_file void RemoveRegistryEntriesForLayers(QString override_file, QString settings_file); -std::vector LoadRegistryLayers(const QString &path); +std::vector LoadRegistryLayers(const QString &path); #endif // VKC_PLATFORM == VKC_PLATFORM_WINDOWS diff --git a/vkconfig_core/test/test_configuration.cpp b/vkconfig_core/test/test_configuration.cpp index e1f8a8bc7d..b90d369d66 100644 --- a/vkconfig_core/test/test_configuration.cpp +++ b/vkconfig_core/test/test_configuration.cpp @@ -59,8 +59,10 @@ static bool operator==(const Parameter& a, const Parameter& b) { static bool operator!=(const std::vector& a, const std::vector& b) { return !(a == b); } TEST(test_configuration, load_and_save) { + LayerManager layers; + Configuration configuration_loaded; - const bool load_loaded = configuration_loaded.Load(":/test/Configuration 3.0.0.json", std::vector()); + const bool load_loaded = configuration_loaded.Load(":/test/Configuration 3.0.0.json", layers); EXPECT_TRUE(load_loaded); EXPECT_EQ(3, configuration_loaded.parameters.size()); EXPECT_TRUE(!configuration_loaded.description.empty()); @@ -72,7 +74,7 @@ TEST(test_configuration, load_and_save) { configuration_loaded.Save("test_layer_1_2_1.json"); Configuration configuration_saved; - configuration_saved.Load("test_layer_1_2_1.json", std::vector()); + configuration_saved.Load("test_layer_1_2_1.json", layers); EXPECT_EQ(configuration_loaded, configuration_saved); } diff --git a/vkconfig_core/test/test_configuration_built_in.cpp b/vkconfig_core/test/test_configuration_built_in.cpp index e840ff10eb..e400b00861 100644 --- a/vkconfig_core/test/test_configuration_built_in.cpp +++ b/vkconfig_core/test/test_configuration_built_in.cpp @@ -71,9 +71,10 @@ struct TestBuilin { ~TestBuilin() {} Configuration Load(const char* configuration_name) { + const std::string& path = format(":/configurations/%s.json", configuration_name); + Configuration configuration_loaded; - const bool result = configuration_loaded.Load(format(":/configurations/%s.json", configuration_name).c_str(), - layer_manager.selected_layers); + const bool result = configuration_loaded.Load(path.c_str(), this->layer_manager); return result ? configuration_loaded : Configuration(); } @@ -83,7 +84,7 @@ struct TestBuilin { EXPECT_TRUE(saved); Configuration configuration_saved; - EXPECT_TRUE(configuration_saved.Load(filename.c_str(), this->layer_manager.selected_layers)); + EXPECT_TRUE(configuration_saved.Load(filename.c_str(), this->layer_manager)); return configuration_saved; } diff --git a/vkconfig_core/test/test_configuration_manager.cpp b/vkconfig_core/test/test_configuration_manager.cpp index e96415a51d..067210f934 100644 --- a/vkconfig_core/test/test_configuration_manager.cpp +++ b/vkconfig_core/test/test_configuration_manager.cpp @@ -23,22 +23,18 @@ #include TEST(test_configuration_manager, create_remove) { - std::vector available_layers; - Layer layer; - layer.key = "VK_LAYER_KHRONOS_validation"; - layer.manifest_path = "VK_LAYER_KHRONOS_validation.dummy_path"; - available_layers.push_back(layer); + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); ConfigurationManager configuration_manager; // Create configuration - configuration_manager.CreateConfiguration(available_layers, "Configuration A"); - configuration_manager.CreateConfiguration(available_layers, "Configuration B"); + configuration_manager.CreateConfiguration(layer_manager, "Configuration A"); + configuration_manager.CreateConfiguration(layer_manager, "Configuration B"); EXPECT_EQ(2, configuration_manager.available_configurations.size()); // Create configuration with the same name, updating the name - const std::string configuration_duplicate_key = - configuration_manager.CreateConfiguration(available_layers, "Configuration A").key; + const std::string configuration_duplicate_key = configuration_manager.CreateConfiguration(layer_manager, "Configuration A").key; EXPECT_EQ(3, configuration_manager.available_configurations.size()); EXPECT_STREQ("Configuration A (2)", configuration_duplicate_key.c_str()); diff --git a/vkconfig_core/test/test_layer.cpp b/vkconfig_core/test/test_layer.cpp index 23852f2fcb..a6d10ca250 100644 --- a/vkconfig_core/test/test_layer.cpp +++ b/vkconfig_core/test/test_layer.cpp @@ -36,7 +36,7 @@ inline SettingMetaString* InstantiateString(Layer& layer, const std::string& key return static_cast(layer.Instantiate(layer.settings, key, SETTING_STRING)); } -std::map Dummy() { return std::map(); } +std::map Dummy() { return std::map(); } TEST(test_layer, collect_settings) { Layer layer; diff --git a/vkconfig_core/test/test_layer_manager.cpp b/vkconfig_core/test/test_layer_manager.cpp index 2dee7287b0..e987c32ee1 100644 --- a/vkconfig_core/test/test_layer_manager.cpp +++ b/vkconfig_core/test/test_layer_manager.cpp @@ -46,7 +46,7 @@ TEST(test_layer_manager, load_dir) { EXPECT_TRUE(layer_manager.Empty()); layer_manager.LoadLayersFromPath(":/layers"); - EXPECT_TRUE(layer_manager.FindFromVersion("VK_LAYER_LUNARG_reference_1_1_0", Version::VERSION_NULL) != nullptr); + EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0", Version::LATEST) != nullptr); layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); @@ -61,7 +61,7 @@ TEST(test_layer_manager, load_file) { EXPECT_TRUE(!layer_manager.Empty()); EXPECT_EQ(1, layer_manager.Size()); - EXPECT_TRUE(layer_manager.FindFromVersion("VK_LAYER_LUNARG_reference_1_1_0", Version::VERSION_NULL) != nullptr); + EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0", Version::LATEST) != nullptr); layer_manager.Clear(); EXPECT_TRUE(layer_manager.Empty()); @@ -77,50 +77,51 @@ TEST(test_layer_manager, reset) { EXPECT_TRUE(layer_manager.Empty()); } -TEST(test_layer_manager, find) { +TEST(test_layer_manager, find_single) { LayerManager layer_manager; layer_manager.LoadLayersFromPath(":/layers"); - EXPECT_TRUE(layer_manager.FindFromVersion("VK_LAYER_LUNARG_test_03", Version::VERSION_NULL) != nullptr); + EXPECT_TRUE(layer_manager.Find("VK_LAYER_LUNARG_test_03", Version::LATEST) != nullptr); - const Layer* layer = layer_manager.FindFromVersion("VK_LAYER_LUNARG_reference_1_1_0", Version::VERSION_NULL); + const Layer* layer = layer_manager.Find("VK_LAYER_LUNARG_reference_1_1_0", Version::LATEST); EXPECT_TRUE(layer != nullptr); EXPECT_STREQ(layer->key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); } -TEST(test_layer_manager, FindFromVersion) { +TEST(test_layer_manager, find_multiple) { LayerManager layer_manager; layer_manager.LoadLayersFromPath(":/layers"); - const Layer* layer135 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 1, 135)); + const Layer* layer135 = layer_manager.Find("VK_LAYER_LUNARG_version", Version(1, 1, 135)); EXPECT_TRUE(layer135 != nullptr); EXPECT_STREQ(layer135->key.c_str(), "VK_LAYER_LUNARG_version"); EXPECT_EQ(layer135->api_version, Version(1, 1, 135)); - const Layer* layer193 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 2, 193)); + const Layer* layer193 = layer_manager.Find("VK_LAYER_LUNARG_version", Version(1, 2, 193)); EXPECT_TRUE(layer193 != nullptr); EXPECT_STREQ(layer193->key.c_str(), "VK_LAYER_LUNARG_version"); EXPECT_EQ(layer193->api_version, Version(1, 2, 193)); - const Layer* layer204 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 3, 204)); + const Layer* layer204 = layer_manager.Find("VK_LAYER_LUNARG_version", Version(1, 3, 204)); EXPECT_TRUE(layer204 != nullptr); EXPECT_STREQ(layer204->key.c_str(), "VK_LAYER_LUNARG_version"); EXPECT_EQ(layer204->api_version, Version(1, 3, 204)); - const Layer* layer290 = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 3, 290)); + const Layer* layer290 = layer_manager.Find("VK_LAYER_LUNARG_version", Version(1, 3, 290)); EXPECT_TRUE(layer290 != nullptr); EXPECT_STREQ(layer290->key.c_str(), "VK_LAYER_LUNARG_version"); EXPECT_EQ(layer290->api_version, Version(1, 3, 290)); - const Layer* layer_latest = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version::VERSION_NULL); + const Layer* layer_latest = layer_manager.Find("VK_LAYER_LUNARG_version", Version::LATEST); EXPECT_TRUE(layer_latest != nullptr); EXPECT_STREQ(layer_latest->key.c_str(), "VK_LAYER_LUNARG_version"); EXPECT_EQ(layer_latest->api_version, Version(1, 3, 290)); - const Layer* layer_not_found_version = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version", Version(1, 3, 208)); - EXPECT_TRUE(layer_not_found_version == nullptr); + const Layer* layer_version_not_found = layer_manager.Find("VK_LAYER_LUNARG_version", Version(1, 3, 208)); + EXPECT_TRUE(layer_version_not_found != nullptr); + EXPECT_TRUE(layer_version_not_found == layer_latest); - const Layer* layer_not_found_key = layer_manager.FindFromVersion("VK_LAYER_LUNARG_version_not_found", Version(1, 3, 290)); + const Layer* layer_not_found_key = layer_manager.Find("VK_LAYER_LUNARG_version_not_found", Version(1, 3, 290)); EXPECT_TRUE(layer_not_found_key == nullptr); } @@ -141,16 +142,36 @@ TEST(test_layer_manager, GatherVersions) { LayerManager layer_manager; layer_manager.LoadLayersFromPath(":/layers"); + const std::vector& versions_notfound = layer_manager.GatherVersions("VK_LAYER_LUNARG_version_not_found"); + EXPECT_TRUE(versions_notfound.empty()); + const std::vector& versions_found = layer_manager.GatherVersions("VK_LAYER_LUNARG_version"); EXPECT_FALSE(versions_found.empty()); EXPECT_EQ(versions_found.size(), 4); - EXPECT_EQ(versions_found[0], Version(1, 1, 135)); - EXPECT_EQ(versions_found[1], Version(1, 2, 193)); - EXPECT_EQ(versions_found[2], Version(1, 3, 204)); - EXPECT_EQ(versions_found[3], Version(1, 3, 290)); + EXPECT_EQ(versions_found[0], Version(1, 3, 290)); + EXPECT_EQ(versions_found[1], Version(1, 3, 204)); + EXPECT_EQ(versions_found[2], Version(1, 2, 193)); + EXPECT_EQ(versions_found[3], Version(1, 1, 135)); - const std::vector& versions_notfound = layer_manager.GatherVersions("VK_LAYER_LUNARG_version_not_found"); - EXPECT_TRUE(versions_notfound.empty()); + const Layer* layer193 = layer_manager.Find("VK_LAYER_LUNARG_version", Version(1, 2, 193)); + EXPECT_TRUE(layer193 != nullptr); + + Layer* layer_edit = layer_manager.FindFromManifest(layer193->manifest_path); + layer_edit->visible = false; + + const std::vector& versions_found_b = layer_manager.GatherVersions("VK_LAYER_LUNARG_version"); + EXPECT_FALSE(versions_found_b.empty()); + EXPECT_EQ(versions_found_b.size(), 3); + EXPECT_EQ(versions_found_b[0], Version(1, 3, 290)); + EXPECT_EQ(versions_found_b[1], Version(1, 3, 204)); + EXPECT_EQ(versions_found_b[2], Version(1, 1, 135)); +} + +TEST(test_layer_manager, BuildLayerNameList) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + EXPECT_EQ(layer_manager.BuildLayerNameList().size(), 11); } TEST(test_layer_manager, avoid_duplicate) { diff --git a/vkconfig_core/test/test_vulkan.cpp b/vkconfig_core/test/test_vulkan.cpp index 1cec145661..eb561156fc 100644 --- a/vkconfig_core/test/test_vulkan.cpp +++ b/vkconfig_core/test/test_vulkan.cpp @@ -27,7 +27,7 @@ TEST(test_vulkan, system_info) { const VulkanSystemInfo& vulkan_system_info = BuildVulkanSystemInfo(); - EXPECT_TRUE(vulkan_system_info.loaderVersion != Version::VERSION_NULL); + EXPECT_TRUE(vulkan_system_info.loaderVersion != Version::NONE); EXPECT_TRUE(!vulkan_system_info.instanceLayerProperties.empty()); EXPECT_TRUE(!vulkan_system_info.instanceExtensionPropertie.empty()); EXPECT_TRUE(!vulkan_system_info.physicalDevices.empty()); diff --git a/vkconfig_core/version.cpp b/vkconfig_core/version.cpp index 9326cfd176..a74c67dc30 100644 --- a/vkconfig_core/version.cpp +++ b/vkconfig_core/version.cpp @@ -30,7 +30,8 @@ const Version Version::VKCONFIG(3, 0, 0); const Version Version::VKHEADER(VK_HEADER_VERSION_COMPLETE); -const Version Version::VERSION_NULL(0u); +const Version Version::NONE(0, 0, 0); +const Version Version::LATEST(~0, ~0, ~0); const char *VKCONFIG_NAME = "Vulkan Configurator"; const char *VKCONFIG_SHORT_NAME = "vkconfig"; diff --git a/vkconfig_core/version.h b/vkconfig_core/version.h index 9fe42287a2..af057b03f8 100644 --- a/vkconfig_core/version.h +++ b/vkconfig_core/version.h @@ -32,7 +32,8 @@ class Version { public: static const Version VKCONFIG; static const Version VKHEADER; - static const Version VERSION_NULL; + static const Version NONE; + static const Version LATEST; explicit Version() : _major(0), _minor(0), _patch(0) {} explicit Version(uint32_t version_complete); diff --git a/vkconfig_core/vulkan_info.h b/vkconfig_core/vulkan_info.h index 8578e795c5..0a9890b56e 100644 --- a/vkconfig_core/vulkan_info.h +++ b/vkconfig_core/vulkan_info.h @@ -34,7 +34,7 @@ struct VulkanPhysicalDeviceInfo { }; struct VulkanSystemInfo { - Version loaderVersion; + Version loaderVersion = Version::NONE; std::vector instanceLayerProperties; std::vector instanceExtensionPropertie; std::vector physicalDevices; diff --git a/vkconfig_gui/main.cpp b/vkconfig_gui/main.cpp index 37383ac999..c04daae456 100644 --- a/vkconfig_gui/main.cpp +++ b/vkconfig_gui/main.cpp @@ -71,7 +71,7 @@ int main(int argc, char* argv[]) { const VulkanSystemInfo& vulkan_info = BuildVulkanSystemInfo(); - if (vulkan_info.loaderVersion == Version::VERSION_NULL) { + if (vulkan_info.loaderVersion == Version::NONE) { Alert::StartLoaderFailure(); return -1; } diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 2a43a0c014..325d808185 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -418,7 +418,7 @@ void SettingsTreeManager::OnPresetChanged(int combox_preset_index) { if (preset_label == Layer::NO_PRESET) return; Configurator &configurator = Configurator::Get(); - const Layer *layer = configurator.layers.FindFromVersion(this->parameter->key.c_str(), Version::VERSION_NULL); + const Layer *layer = configurator.layers.Find(this->parameter->key.c_str(), this->parameter->api_version); const LayerPreset *preset = GetPreset(layer->presets, preset_label.c_str()); assert(preset != nullptr); diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index 1067e1ac2c..ef2782f595 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -199,6 +199,7 @@ void TabConfigurations::UpdateUI_LoaderMessages() { } void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { + ui->configurations_layers_list->blockSignals(true); ui->configurations_layers_list->clear(); Configurator &configurator = Configurator::Get(); @@ -249,6 +250,8 @@ void TabConfigurations::UpdateUI_Layers(UpdateUIMode mode) { ui->execute_closer_application_label->setVisible(true); ui->execute_closer_driver_label->setVisible(true); + + ui->configurations_layers_list->blockSignals(false); } void TabConfigurations::UpdateUI_Settings(UpdateUIMode mode) { @@ -294,7 +297,7 @@ static const Layer *GetLayer(QListWidget *tree, QListWidgetItem *item) { Configurator &configurator = Configurator::Get(); const std::string &layer_key = ExtractLayerName(configurator.layers, layer_string); - return configurator.layers.FindFromVersion(layer_key, Version::VERSION_NULL); + return configurator.layers.Find(layer_key, Version::LATEST); } return nullptr; @@ -567,7 +570,7 @@ void TabConfigurations::OnContextMenuNewClicked(ConfigurationListItem *item) { Configurator &configurator = Configurator::Get(); - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, "New Configuration"); + configurator.configurations.CreateConfiguration(configurator.layers, "New Configuration"); configurator.Override(OVERRIDE_AREA_ALL); this->UpdateUI_Configurations(UPDATE_REBUILD_UI); @@ -588,7 +591,7 @@ void TabConfigurations::OnContextMenuImportClicked(ConfigurationListItem *item) } configurator.environment.path_import = selected_path; - configurator.configurations.ImportConfiguration(configurator.layers.selected_layers, selected_path); + configurator.configurations.ImportConfiguration(configurator.layers, selected_path); configurator.Override(OVERRIDE_AREA_ALL); @@ -614,7 +617,7 @@ void TabConfigurations::OnContextMenuDuplicateClicked(ConfigurationListItem *ite Configurator &configurator = Configurator::Get(); const Configuration &duplicated_configuration = - configurator.configurations.CreateConfiguration(configurator.layers.selected_layers, item->configuration_name, true); + configurator.configurations.CreateConfiguration(configurator.layers, item->configuration_name, true); item->configuration_name = duplicated_configuration.key; @@ -679,7 +682,7 @@ void TabConfigurations::OnContextMenuResetClicked(ConfigurationListItem *item) { return; } - configuration->Reset(configurator.layers.selected_layers); + configuration->Reset(configurator.layers); this->UpdateUI_Configurations(UPDATE_REFRESH_UI); } @@ -706,7 +709,7 @@ void TabConfigurations::OnContextMenuExportConfigsClicked(ConfigurationListItem return; } - configurator.configurations.ExportConfiguration(configurator.layers.selected_layers, selected_path, item->configuration_name); + configurator.configurations.ExportConfiguration(configurator.layers, selected_path, item->configuration_name); } void TabConfigurations::OnContextMenuExportSettingsClicked(ConfigurationListItem *item) { diff --git a/vkconfig_gui/tab_layers.cpp b/vkconfig_gui/tab_layers.cpp index d175d38471..18e4552b14 100644 --- a/vkconfig_gui/tab_layers.cpp +++ b/vkconfig_gui/tab_layers.cpp @@ -24,19 +24,16 @@ #include "../vkconfig_core/configurator.h" -class TreeWidgetItemParameter : public QTreeWidgetItem { - public: - TreeWidgetItemParameter(const char *layer_name) : widget(nullptr), layer_name(layer_name) { assert(layer_name != nullptr); } +#include - std::string layer_name; - QWidget *widget; +TabLayers::TabLayers(MainWindow &window, std::shared_ptr ui) : Tab(TAB_LAYERS, window, ui) { + this->connect(this->ui->layers_lineEdit, SIGNAL(textEdited(QString)), this, SLOT(on_layers_lineEdit_textEdited(QString))); + this->connect(this->ui->layers_lineEdit, SIGNAL(returnPressed()), this, SLOT(on_layers_add_pushButton_pressed())); + this->connect(this->ui->layers_add_pushButton, SIGNAL(pressed()), this, SLOT(on_layers_add_pushButton_pressed())); + this->connect(this->ui->layers_browse_pushButton, SIGNAL(pressed()), this, SLOT(on_layers_browse_pushButton_pressed())); - private: - TreeWidgetItemParameter(const TreeWidgetItemParameter &) = delete; - TreeWidgetItemParameter &operator=(const TreeWidgetItemParameter &) = delete; -}; - -TabLayers::TabLayers(MainWindow &window, std::shared_ptr ui) : Tab(TAB_LAYERS, window, ui) {} + this->on_layers_lineEdit_textEdited(""); +} TabLayers::~TabLayers() {} @@ -49,37 +46,37 @@ void TabLayers::UpdateUI_LayersPaths(UpdateUIMode ui_update_mode) { for (std::size_t group_index = 0, group_count = configurator.layers.paths.size(); group_index < group_count; ++group_index) { const LayerType layer_type = ::GetLayerType(static_cast(group_index)); - const std::vector &paths_group = configurator.layers.paths[group_index]; + std::vector &paths_group = configurator.layers.paths[group_index]; for (std::size_t i = 0, n = paths_group.size(); i < n; ++i) { - TreeWidgetItemParameter *item_state = new TreeWidgetItemParameter(paths_group[i].RelativePath().c_str()); - + QTreeWidgetItem *item_state = new QTreeWidgetItem; item_state->setFlags(item_state->flags() | Qt::ItemIsSelectable); item_state->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - LayersPathWidget *layer_path_widget = new LayersPathWidget(paths_group[i].RelativePath()); - - layer_path_widget->setChecked(true); - - item_state->widget = layer_path_widget; + LayersPathWidget *layer_path_widget = new LayersPathWidget(&paths_group[i]); + this->connect(layer_path_widget, SIGNAL(toggled(bool)), this, SLOT(on_check_box_paths_toggled(bool))); ui->layers_paths_tree->addTopLevelItem(item_state); ui->layers_paths_tree->setItemWidget(item_state, 0, layer_path_widget); - const std::string &layer_path = paths_group[i].AbsolutePath(); + const std::string &layer_path = paths_group[i].path.AbsolutePath(); const std::vector &manifest_paths = CollectFilePaths(layer_path); for (std::size_t manifest_index = 0, manifest_count = manifest_paths.size(); manifest_index < manifest_count; ++manifest_index) { const Layer *layer = configurator.layers.FindFromManifest(manifest_paths[manifest_index]); - - QTreeWidgetItem *item = new QTreeWidgetItem; + if (layer == nullptr) { + continue; // When the directory has JSON files that are not layer manifest + } std::string label = layer->key + " - " + layer->api_version.str() + " - " + format("%s layer", GetToken(layer->type)); if (layer->status != STATUS_STABLE) { label += format(" (%s)", GetToken(layer->status)); } + + QTreeWidgetItem *item = new QTreeWidgetItem; item->setText(0, label.c_str()); item->setToolTip(0, layer->manifest_path.AbsolutePath().c_str()); + item->setDisabled(!layer_path_widget->isChecked()); item_state->addChild(item); } } @@ -94,3 +91,41 @@ void TabLayers::UpdateUI(UpdateUIMode ui_update_mode) { this->UpdateUI_LayersPat void TabLayers::CleanUI() {} bool TabLayers::EventFilter(QObject *target, QEvent *event) { return false; } + +void TabLayers::on_check_box_paths_toggled(bool checked) { + (void)checked; + + this->UpdateUI_LayersPaths(UPDATE_REBUILD_UI); +} + +void TabLayers::on_layers_lineEdit_textEdited(const QString &text) { + // Path new_path(ui->layers_lineEdit->text().toStdString()); + Path new_path(text.toStdString()); + ui->layers_add_pushButton->setEnabled(new_path.Exists()); +} + +void TabLayers::on_layers_add_pushButton_pressed() { + Configurator &configurator = Configurator::Get(); + LayersPathInfo info; + info.path = ui->layers_lineEdit->text().toStdString(); + configurator.layers.AddPath(info); + + this->UpdateUI_LayersPaths(UPDATE_REBUILD_UI); +} + +void TabLayers::on_layers_browse_pushButton_pressed() { + const QString selected_path = QFileDialog::getExistingDirectory(this->ui->layers_browse_pushButton, "Select Folder...", + this->ui->layers_lineEdit->text()); + + if (!selected_path.isEmpty()) { + this->ui->layers_lineEdit->setText(selected_path); + + LayersPathInfo info; + info.path = selected_path.toStdString(); + + Configurator &configurator = Configurator::Get(); + configurator.layers.AddPath(info); + + this->UpdateUI_LayersPaths(UPDATE_REBUILD_UI); + } +} diff --git a/vkconfig_gui/tab_layers.h b/vkconfig_gui/tab_layers.h index 0d9fc09906..065feda5e4 100644 --- a/vkconfig_gui/tab_layers.h +++ b/vkconfig_gui/tab_layers.h @@ -34,4 +34,10 @@ struct TabLayers : public Tab { virtual bool EventFilter(QObject *target, QEvent *event) override; void UpdateUI_LayersPaths(UpdateUIMode ui_update_mode); + + public Q_SLOTS: + void on_check_box_paths_toggled(bool checked); + void on_layers_lineEdit_textEdited(const QString &text); + void on_layers_add_pushButton_pressed(); + void on_layers_browse_pushButton_pressed(); }; diff --git a/vkconfig_gui/widget_tab_configurations_layer.cpp b/vkconfig_gui/widget_tab_configurations_layer.cpp index 4ffe606851..7b02399ba3 100644 --- a/vkconfig_gui/widget_tab_configurations_layer.cpp +++ b/vkconfig_gui/widget_tab_configurations_layer.cpp @@ -99,7 +99,7 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const // const bool is_implicit_layer = layers.empty() ? false : layers[0]->type == LAYER_TYPE_IMPLICIT; const Configurator &configurator = Configurator::Get(); - const Layer *layer = configurator.layers.FindFromVersion(parameter.key, parameter.api_version); + const Layer *layer = configurator.layers.Find(parameter.key, parameter.api_version); if (parameter.control != LAYER_CONTROL_APPLICATIONS_API && parameter.control != LAYER_CONTROL_APPLICATIONS_ENV) { assert(layer != nullptr); @@ -149,7 +149,7 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const } else { assert(layer != nullptr); - if (!advanced_view && parameter.api_version != Version::VERSION_NULL) { + if (!advanced_view && parameter.api_version != Version::LATEST) { decorated_name += format(" - %s", parameter.api_version.str().c_str()); } @@ -199,7 +199,7 @@ void ConfigurationLayerWidget::resizeEvent(QResizeEvent *event) { void ConfigurationLayerWidget::on_layer_version_currentIndexChanged(int index) { assert(index >= 0); const std::string &text = this->layer_version->itemText(index).toStdString(); - Version version = text == "latest" ? Version::VERSION_NULL : Version(text.c_str()); + Version version = text == "latest" ? Version::LATEST : Version(text.c_str()); Configuration *configuration = Configurator::Get().GetActiveConfiguration(); Parameter *parameter = configuration->Find(this->layer_name); diff --git a/vkconfig_gui/widget_tab_layers_path.cpp b/vkconfig_gui/widget_tab_layers_path.cpp index 021f683591..c05c1f9208 100644 --- a/vkconfig_gui/widget_tab_layers_path.cpp +++ b/vkconfig_gui/widget_tab_layers_path.cpp @@ -20,49 +20,44 @@ #include "widget_tab_layers_path.h" +#include "../vkconfig_core/configurator.h" + #include -LayersPathWidget::LayersPathWidget(const std::string &layer_path) { - this->button_edit = new QPushButton(this); - this->button_edit->setText("..."); - this->button_edit->show(); +LayersPathWidget::LayersPathWidget(LayersPathInfo* path_info) : path_info(path_info) { + this->setChecked(this->path_info->enabled); + this->buttom_remove = new QPushButton(this); this->buttom_remove->setText("x"); this->buttom_remove->show(); - this->setText(layer_path.c_str()); + this->setText(path_info->path.RelativePath().c_str()); this->setToolTip("Load layers in this location"); - this->connect(this->button_edit, SIGNAL(clicked(bool)), this, SLOT(on_button_edit_clicked(bool))); - this->connect(this->button_edit, SIGNAL(clicked(bool)), this, SLOT(on_button_edit_clicked(bool))); + this->connect(this, SIGNAL(toggled(bool)), this, SLOT(on_toggled(bool))); this->connect(this->buttom_remove, SIGNAL(clicked(bool)), this, SLOT(on_buttom_remove_clicked(bool))); } -void LayersPathWidget::resizeEvent(QResizeEvent *event) { +void LayersPathWidget::resizeEvent(QResizeEvent* event) { QSize size = event->size(); - const QFontMetrics fm = this->button_edit->fontMetrics(); + const QFontMetrics fm = this->buttom_remove->fontMetrics(); const int button_width_state = 30; - const QRect edit_button_rect = - QRect(size.width() - button_width_state - button_width_state, 0, button_width_state, size.height()); - this->button_edit->setGeometry(edit_button_rect); - const QRect remove_button_rect = QRect(size.width() - button_width_state, 0, button_width_state, size.height()); this->buttom_remove->setGeometry(remove_button_rect); } -void LayersPathWidget::on_button_edit_clicked(bool checked) { - (void)checked; +void LayersPathWidget::on_buttom_remove_clicked(bool checked) { + Configurator& configurator = Configurator::Get(); + configurator.layers.RemovePath(*this->path_info); - const std::string selected_path = - QFileDialog::getExistingDirectory(this->button_edit, "Select Folder", this->text()).toStdString(); + emit toggled(checked); } -void LayersPathWidget::on_buttom_remove_clicked(bool checked) { - (void)checked; +void LayersPathWidget::on_toggled(bool checked) { + this->path_info->enabled = checked; - // emit itemChanged(); + Configurator& configurator = Configurator::Get(); + configurator.layers.UpdatePath(*this->path_info); } - -void LayersPathWidget::on_checkStateChanged(Qt::CheckState state) {} diff --git a/vkconfig_gui/widget_tab_layers_path.h b/vkconfig_gui/widget_tab_layers_path.h index 0350d08db6..77fcbb64dc 100644 --- a/vkconfig_gui/widget_tab_layers_path.h +++ b/vkconfig_gui/widget_tab_layers_path.h @@ -20,6 +20,8 @@ #pragma once +#include "../vkconfig_core/layer.h" + #include #include #include @@ -28,17 +30,16 @@ class LayersPathWidget : public QCheckBox { Q_OBJECT public: - LayersPathWidget(const std::string &layer_path); + LayersPathWidget(LayersPathInfo *path_info); protected: void resizeEvent(QResizeEvent *event) override; public Q_SLOTS: - void on_button_edit_clicked(bool checked = false); void on_buttom_remove_clicked(bool checked = false); - void on_checkStateChanged(Qt::CheckState state); + void on_toggled(bool checked); public: - QPushButton *button_edit = nullptr; + LayersPathInfo *path_info = nullptr; QPushButton *buttom_remove = nullptr; }; From c8afa328d471b94d7585f18a317f81e92ca2cfca Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 6 Sep 2024 12:42:34 +0200 Subject: [PATCH 21/33] vkconfig3: Implement layer version switching --- vkconfig_cmd/main_doc.cpp | 2 +- vkconfig_core/configuration.cpp | 104 ++++++++++++++++-- vkconfig_core/configuration.h | 11 +- vkconfig_core/configuration_manager.cpp | 40 +++++-- vkconfig_core/configurator.cpp | 2 +- vkconfig_core/parameter.cpp | 58 ++-------- vkconfig_core/parameter.h | 11 +- vkconfig_core/test/test_configuration.cpp | 2 +- vkconfig_core/test/test_util.cpp | 29 +++++ vkconfig_core/util.h | 4 +- vkconfig_gui/settings_tree.cpp | 14 ++- vkconfig_gui/tab_configurations.cpp | 18 ++- vkconfig_gui/widget_setting_flags.cpp | 12 ++ .../widget_tab_configurations_layer.cpp | 9 +- .../widget_tab_configurations_layer.h | 3 +- vkconfig_gui/widget_tab_layers_path.cpp | 2 +- 16 files changed, 224 insertions(+), 97 deletions(-) diff --git a/vkconfig_cmd/main_doc.cpp b/vkconfig_cmd/main_doc.cpp index 6a39c120fb..ef1d52047b 100644 --- a/vkconfig_cmd/main_doc.cpp +++ b/vkconfig_cmd/main_doc.cpp @@ -74,7 +74,7 @@ int run_doc_settings(const CommandLine& command_line) { ConfigurationManager configuration_manager; Configuration config = configuration_manager.CreateConfiguration(layers, "Config"); - config.parameters = GatherParameters(config.parameters, layers); + config.GatherParameters(layers); config.parameters[0].control = LAYER_CONTROL_ON; ExportSettingsDoc(layers.selected_layers, config, command_line.doc_out_dir + "/vk_layer_settings.txt"); diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index f1cd2adab5..8947aa7d39 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -83,7 +83,7 @@ Configuration Configuration::Create(const LayerManager& layers, const std::strin Configuration result; result.key = key; - result.parameters = GatherParameters(result.parameters, layers); + result.GatherParameters(layers); AddApplicationEnabledParameters(result.parameters); @@ -93,7 +93,7 @@ Configuration Configuration::Create(const LayerManager& layers, const std::strin Configuration Configuration::CreateDisabled(const LayerManager& layers) { Configuration result; result.key = "_DisablingConfiguration"; - result.parameters = GatherParameters(result.parameters, layers); + result.GatherParameters(layers); for (std::size_t i = 0, n = result.parameters.size(); i < n; ++i) { result.parameters[i].control = LAYER_CONTROL_OFF; @@ -239,7 +239,7 @@ bool Configuration::Load(const Path& full_path, const LayerManager& layers) { this->parameters.push_back(parameter); } - this->parameters = GatherParameters(this->parameters, layers); + this->GatherParameters(layers); AddApplicationEnabledParameters(this->parameters); @@ -337,9 +337,9 @@ bool Configuration::Save(const Path& full_path, bool exporter) const { } } -Parameter* Configuration::Find(std::string parameter_key) { +Parameter* Configuration::Find(const std::string& layer_key) { for (std::size_t i = 0, n = this->parameters.size(); i < n; ++i) { - if (this->parameters[i].key == parameter_key) { + if (this->parameters[i].key == layer_key) { return &this->parameters[i]; } } @@ -357,7 +357,7 @@ void Configuration::Reset(const LayerManager& layers) { const bool result = this->Load(builtin_configuration_files[i], layers); assert(result); - OrderParameter(this->parameters, layers.selected_layers); + OrderParameter(this->parameters, layers); return; } } @@ -371,7 +371,7 @@ void Configuration::Reset(const LayerManager& layers) { const bool result = this->Load(full_path, layers); assert(result); - OrderParameter(this->parameters, layers.selected_layers); + OrderParameter(this->parameters, layers); return; } @@ -385,7 +385,7 @@ void Configuration::Reset(const LayerManager& layers) { } } - OrderParameter(this->parameters, layers.selected_layers); + OrderParameter(this->parameters, layers); } } @@ -403,6 +403,82 @@ bool Configuration::HasOverride() const { return false; } +void Configuration::SwitchLayerVersion(const LayerManager& layers, const std::string& layer_key, const Version& version) { + Parameter* parameter = this->Find(layer_key); + assert(parameter != nullptr); + + const Layer* new_layer = layers.Find(layer_key, version); + + parameter->api_version = version; + CollectDefaultSettingData(new_layer->settings, parameter->settings); +} + +void Configuration::GatherParameters(const LayerManager& layers) { + const std::vector& previous_parameters = this->parameters; + + std::vector gathered_parameters; + + // Loop through the layers. They are expected to be in order + for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { + const Parameter& parameter = parameters[i]; + assert(!parameter.key.empty()); + + gathered_parameters.push_back(parameter); + } + + const std::vector& list = layers.BuildLayerNameList(); + + for (std::size_t i = 0, n = list.size(); i < n; ++i) { + const Layer* layer = layers.Find(list[i], Version::LATEST); + + // The layer is already in the layer tree + if (this->Find(layer->key.c_str())) { + continue; + } + + Parameter parameter; + parameter.key = layer->key; + parameter.control = LAYER_CONTROL_AUTO; + parameter.api_version = Version::LATEST; + CollectDefaultSettingData(layer->settings, parameter.settings); + + gathered_parameters.push_back(parameter); + } + + // OrderParameter(gathered_parameters, layers); + + this->parameters = gathered_parameters; +} + +void Configuration::Reorder(const std::vector& layer_names) { + std::vector ordered_parameters; + + for (std::size_t i = 0, n = layer_names.size(); i < n; ++i) { + Parameter* parameter = this->Find(layer_names[i]); + assert(parameter != nullptr); + ordered_parameters.push_back(*parameter); + } + + if (!this->view_advanced_layers) { + for (std::size_t i = 0, n = this->parameters.size(); i < n; ++i) { + Parameter& parameter = this->parameters[i]; + + bool found = false; + for (std::size_t j = 0, o = ordered_parameters.size(); j < o; ++j) { + if (ordered_parameters[j].key == parameter.key) { + found = true; + } + } + + if (!found) { + ordered_parameters.push_back(parameter); + } + } + } + + this->parameters = ordered_parameters; +} + bool Configuration::IsBuiltIn() const { const std::vector& builtin_configuration_files = CollectFilePaths(":/configurations/"); for (std::size_t i = 0, n = builtin_configuration_files.size(); i < n; ++i) { @@ -420,13 +496,19 @@ static const size_t NOT_FOUND = static_cast(-1); static std::size_t ExtractDuplicateNumber(const std::string& configuration_name) { const std::size_t name_open = configuration_name.find_last_of("("); - if (name_open == NOT_FOUND) return NOT_FOUND; + if (name_open == NOT_FOUND) { + return NOT_FOUND; + } const std::size_t name_close = configuration_name.find_last_of(")"); - if (name_close == NOT_FOUND) return NOT_FOUND; + if (name_close == NOT_FOUND) { + return NOT_FOUND; + } const std::string number = configuration_name.substr(name_open + 1, name_close - (name_open + 1)); - if (!IsNumber(number)) return NOT_FOUND; + if (!IsNumber(number)) { + return NOT_FOUND; + } return std::stoi(number); } diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index c7060799b7..b0c0dc97ec 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -34,17 +34,20 @@ class LayerManager; class Configuration { public: static Configuration CreateDisabled(const LayerManager& layers); - static Configuration Create(const LayerManager& layers, const std::string& key); + static Configuration Create(const LayerManager& layers, const std::string& layer_key); bool Load(const Path& full_path, const LayerManager& layers); bool Save(const Path& full_path, bool exporter = false) const; - bool HasOverride() const; - Parameter* Find(std::string parameter_key); - void Reset(const LayerManager& layers); + bool HasOverride() const; + Parameter* Find(const std::string& layer_key); std::size_t Size() const { return this->parameters.size(); }; + void SwitchLayerVersion(const LayerManager& layers, const std::string& layer_key, const Version& version); + void GatherParameters(const LayerManager& layers); + void Reorder(const std::vector& layer_names); + std::string key = "New Configuration"; // User readable display of the configuration name (may contain spaces) int version = 1; int platform_flags = PLATFORM_DESKTOP_BIT; diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index 46c232afac..0505520e78 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -41,6 +41,8 @@ bool ConfigurationManager::Load(const QJsonObject &json_root_object) { this->active_application = json_configurations_object.value("active_application").toString().toStdString(); if (json_configurations_object.value("infos") != QJsonValue::Undefined) { + this->configuration_infos.clear(); + const QJsonObject &json_infos_object = json_configurations_object.value("infos").toObject(); const QStringList &json_infos_keys = json_infos_object.keys(); for (int i = 0, n = json_infos_keys.length(); i < n; ++i) { @@ -145,7 +147,7 @@ void ConfigurationManager::LoadDefaultConfigurations(const LayerManager &layers) } #endif - OrderParameter(configuration.parameters, layers.selected_layers); + OrderParameter(configuration.parameters, layers); Configuration *found_configuration = this->FindConfiguration(configuration.key); if (found_configuration == nullptr) { @@ -184,13 +186,13 @@ void ConfigurationManager::LoadConfigurationsPath(const LayerManager &layers) { continue; } - if (FindByKey(available_configurations, configuration.key.c_str()) != nullptr) { + if (this->FindConfiguration(configuration.key) != nullptr) { continue; } std::string missing_layer; - if (!HasMissingLayer(configuration.parameters, layers.selected_layers, missing_layer)) { - OrderParameter(configuration.parameters, layers.selected_layers); + if (!HasMissingLayer(configuration.parameters, layers, missing_layer)) { + OrderParameter(configuration.parameters, layers); } available_configurations.push_back(configuration); @@ -255,7 +257,7 @@ bool ConfigurationManager::HasActiveConfiguration() const { Configuration &ConfigurationManager::CreateConfiguration(const LayerManager &layers, const std::string &configuration_name, bool duplicate) { - Configuration *duplicate_configuration = FindByKey(available_configurations, configuration_name.c_str()); + Configuration *duplicate_configuration = this->FindConfiguration(configuration_name); Configuration new_configuration = duplicate_configuration != nullptr && duplicate ? *duplicate_configuration : Configuration(); new_configuration.key = MakeConfigurationName(available_configurations, configuration_name); @@ -273,7 +275,7 @@ Configuration &ConfigurationManager::CreateConfiguration(const LayerManager &lay this->GetActiveConfigurationInfo()->name = configuration.key; - return *FindByKey(this->available_configurations, configuration.key.c_str()); + return *this->FindConfiguration(configuration.key); } bool ConfigurationManager::HasFile(const Configuration &configuration) const { @@ -314,8 +316,10 @@ void ConfigurationManager::RemoveConfiguration(const std::string &configuration_ // Update the configuration in the list std::vector updated_configurations; + const std::string key = ToLowerCase(std::string(configuration_name)); + for (std::size_t i = 0, n = this->available_configurations.size(); i < n; ++i) { - if (this->available_configurations[i].key == configuration_name) { + if (ToLowerCase(this->available_configurations[i].key) == key) { int version = this->available_configurations[i].version; auto result = this->removed_built_in_configuration.insert(std::make_pair(configuration_name, version)); @@ -344,7 +348,15 @@ Configuration *ConfigurationManager::FindConfiguration(const std::string &config return nullptr; } - return FindByKey(this->available_configurations, configuration_name.c_str()); + const std::string key = ToLowerCase(std::string(configuration_name)); + + for (std::size_t i = 0, n = this->available_configurations.size(); i < n; ++i) { + if (ToLowerCase(this->available_configurations[i].key) == key) { + return &this->available_configurations[i]; + } + } + + return nullptr; } const Configuration *ConfigurationManager::FindConfiguration(const std::string &configuration_name) const { @@ -356,7 +368,15 @@ const Configuration *ConfigurationManager::FindConfiguration(const std::string & return nullptr; } - return FindByKey(this->available_configurations, configuration_name.c_str()); + const std::string key = ToLowerCase(std::string(configuration_name)); + + for (std::size_t i = 0, n = this->available_configurations.size(); i < n; ++i) { + if (ToLowerCase(this->available_configurations[i].key) == key) { + return &this->available_configurations[i]; + } + } + + return nullptr; } void ConfigurationManager::ImportConfiguration(const LayerManager &layers, const Path &full_import_path) { @@ -385,7 +405,7 @@ void ConfigurationManager::ExportConfiguration(const LayerManager &layers, const assert(!configuration_name.empty()); assert(!full_export_path.Empty()); - Configuration *configuration = FindByKey(available_configurations, configuration_name.c_str()); + Configuration *configuration = this->FindConfiguration(configuration_name); assert(configuration); if (!configuration->Save(full_export_path, true)) { diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index fd34cec15e..61fd06eba4 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -186,7 +186,7 @@ void Configurator::BuildLoaderSettings(const ConfigurationInfo& info, const std: if (parameter.control == LAYER_CONTROL_APPLICATIONS_API || parameter.control == LAYER_CONTROL_APPLICATIONS_ENV) { loader_layer_settings.control = parameter.control; } else { - const Layer* layer = FindByKey(this->layers.selected_layers, parameter.key.c_str()); + const Layer* layer = this->layers.Find(parameter.key, parameter.api_version); if (layer == nullptr) { continue; } diff --git a/vkconfig_core/parameter.cpp b/vkconfig_core/parameter.cpp index 82d3a6e174..1294d525bc 100644 --- a/vkconfig_core/parameter.cpp +++ b/vkconfig_core/parameter.cpp @@ -55,10 +55,10 @@ bool Parameter::ApplyPresetSettings(const LayerPreset& preset) { return true; } -ParameterRank GetParameterOrdering(const std::vector& available_layers, const Parameter& parameter) { +ParameterRank GetParameterOrdering(const LayerManager& layers, const Parameter& parameter) { assert(!parameter.key.empty()); - const Layer* layer = FindByKey(available_layers, parameter.key.c_str()); + const Layer* layer = layers.Find(parameter.key, parameter.api_version); if (layer == nullptr) { return PARAMETER_RANK_MISSING; } else if (parameter.control == LAYER_CONTROL_OFF) { @@ -77,8 +77,7 @@ ParameterRank GetParameterOrdering(const std::vector& available_layers, c } } -Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, - const std::vector& layers) { +Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const LayerManager& layers) { if (parameters.empty()) { return Version::NONE; } @@ -86,7 +85,7 @@ Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const std::vector& layers) { +void OrderParameter(std::vector& parameters, const LayerManager& layers) { struct ParameterCompare { - ParameterCompare(const std::vector& layers) : layers(layers) {} + ParameterCompare(const LayerManager& layers) : layers(layers) {} bool operator()(const Parameter& a, const Parameter& b) const { const ParameterRank rankA = GetParameterOrdering(layers, a); @@ -141,7 +140,7 @@ void OrderParameter(std::vector& parameters, const std::vector return a.key < b.key; } - const std::vector& layers; + const LayerManager& layers; }; std::sort(parameters.begin(), parameters.end(), ParameterCompare(layers)); @@ -168,7 +167,7 @@ void FilterParameters(std::vector& parameters, const LayerControl con parameters = filtered_parameters; } -bool HasMissingLayer(const std::vector& parameters, const std::vector& layers, std::string& missing_layer) { +bool HasMissingLayer(const std::vector& parameters, const LayerManager& layers, std::string& missing_layer) { for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it) { if (it->control == LAYER_CONTROL_OFF) { continue; // If excluded are missing, it doesn't matter @@ -178,7 +177,7 @@ bool HasMissingLayer(const std::vector& parameters, const std::vector continue; // If unsupported are missing, it doesn't matter } - if (!IsFound(layers, it->key.c_str())) { + if (layers.Find(it->key, it->api_version) == nullptr) { missing_layer = it->key; return true; } @@ -205,7 +204,7 @@ std::size_t CountOverriddenLayers(const std::vector& parameters) { return count; } -std::size_t CountExcludedLayers(const std::vector& parameters, const std::vector& layers) { +std::size_t CountExcludedLayers(const std::vector& parameters, const LayerManager& layers) { std::size_t count = 0; for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { @@ -218,7 +217,7 @@ std::size_t CountExcludedLayers(const std::vector& parameters, const continue; } - const Layer* layer = FindByKey(layers, parameter.key.c_str()); + const Layer* layer = layers.Find(parameter.key, parameter.api_version); if (layer == nullptr) { continue; // Do not display missing excluded layers } @@ -228,38 +227,3 @@ std::size_t CountExcludedLayers(const std::vector& parameters, const return count; } - -std::vector GatherParameters(const std::vector& parameters, const LayerManager& layers) { - std::vector gathered_parameters; - - // Loop through the layers. They are expected to be in order - for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - const Parameter& parameter = parameters[i]; - assert(!parameter.key.empty()); - - gathered_parameters.push_back(parameter); - } - - const std::vector& list = layers.BuildLayerNameList(); - - for (std::size_t i = 0, n = list.size(); i < n; ++i) { - const Layer* layer = layers.Find(list[i], Version::LATEST); - - // The layer is already in the layer tree - if (IsFound(parameters, layer->key.c_str())) { - continue; - } - - Parameter parameter; - parameter.key = layer->key; - parameter.control = LAYER_CONTROL_AUTO; - parameter.api_version = Version::LATEST; - CollectDefaultSettingData(layer->settings, parameter.settings); - - gathered_parameters.push_back(parameter); - } - - // OrderParameter(gathered_parameters, available_layers); - - return gathered_parameters; -} diff --git a/vkconfig_core/parameter.h b/vkconfig_core/parameter.h index 5bf3fb0565..c1bd2424bb 100644 --- a/vkconfig_core/parameter.h +++ b/vkconfig_core/parameter.h @@ -53,13 +53,12 @@ struct Parameter { QByteArray setting_tree_state; // Recall editor tree state }; -ParameterRank GetParameterOrdering(const std::vector& available_layers, const Parameter& parameter); -Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const std::vector& layers); -void OrderParameter(std::vector& parameters, const std::vector& layers); +ParameterRank GetParameterOrdering(const LayerManager& layers, const Parameter& parameter); +Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const LayerManager& layers); +void OrderParameter(std::vector& parameters, const LayerManager& layers); void FilterParameters(std::vector& parameters, const LayerControl control); -std::vector GatherParameters(const std::vector& parameters, const LayerManager& layers); -bool HasMissingLayer(const std::vector& parameters, const std::vector& layers, std::string& missing_layer); +bool HasMissingLayer(const std::vector& parameters, const LayerManager& layers, std::string& missing_layer); std::size_t CountOverriddenLayers(const std::vector& parameters); -std::size_t CountExcludedLayers(const std::vector& parameters, const std::vector& layers); +std::size_t CountExcludedLayers(const std::vector& parameters, const LayerManager& layers); diff --git a/vkconfig_core/test/test_configuration.cpp b/vkconfig_core/test/test_configuration.cpp index b90d369d66..8c457dd198 100644 --- a/vkconfig_core/test/test_configuration.cpp +++ b/vkconfig_core/test/test_configuration.cpp @@ -67,7 +67,7 @@ TEST(test_configuration, load_and_save) { EXPECT_EQ(3, configuration_loaded.parameters.size()); EXPECT_TRUE(!configuration_loaded.description.empty()); - Parameter* parameter = FindByKey(configuration_loaded.parameters, "VK_LAYER_LUNARG_reference_1_2_1"); + Parameter* parameter = configuration_loaded.Find("VK_LAYER_LUNARG_reference_1_2_1"); EXPECT_TRUE(parameter != nullptr); EXPECT_EQ(LAYER_CONTROL_ON, parameter->control); diff --git a/vkconfig_core/test/test_util.cpp b/vkconfig_core/test/test_util.cpp index 24e6133548..60c97bf1a2 100644 --- a/vkconfig_core/test/test_util.cpp +++ b/vkconfig_core/test/test_util.cpp @@ -27,6 +27,35 @@ #include +template +T* FindByKey(std::vector& container, const char* key) { + assert(key != nullptr); + assert(std::strcmp(key, "") != 0); + + for (std::size_t i = 0, n = container.size(); i < n; ++i) { + if (container[i].key == key) return &container[i]; + } + + return nullptr; +} + +template +const T* FindByKey(const std::vector& container, const char* key) { + assert(key != nullptr); + assert(std::strcmp(key, "") != 0); + + for (std::size_t i = 0, n = container.size(); i < n; ++i) { + if (container[i].key == key) return &container[i]; + } + + return nullptr; +} + +template +bool IsFound(const std::vector& container, const char* key) { + return FindByKey(container, key) != nullptr; +} + TEST(test_util, format_int_1) { EXPECT_EQ("Test 1", format("Test %d", 1)); } TEST(test_util, format_strings_list) { diff --git a/vkconfig_core/util.h b/vkconfig_core/util.h index 0e51644639..ea89c4dc46 100644 --- a/vkconfig_core/util.h +++ b/vkconfig_core/util.h @@ -121,7 +121,7 @@ bool IsValueFound(const std::vector& list, const NumberOr QStringList ConvertValues(const std::vector& values); std::string GetLayerSettingPrefix(const std::string& key); - +/* template T* FindByKey(std::vector& container, const char* key) { assert(key != nullptr); @@ -158,7 +158,7 @@ template bool IsFound(const std::vector& container, const char* key) { return FindByKey(container, key) != nullptr; } - +*/ template std::vector GetVector(const T& value) { std::vector result; diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 325d808185..72e43c4c68 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -64,8 +64,10 @@ void SettingsTreeManager::CreateGUI(QComboBox *preset_combobox, QTreeWidget *bui Configuration *configuration = configurator.GetActiveConfiguration(); if (configuration == nullptr) { + preset_combobox->setVisible(false); return; } else if (configuration->selected_layer_name.empty()) { + preset_combobox->setVisible(false); return; } @@ -115,8 +117,7 @@ void SettingsTreeManager::CreateGUI(QComboBox *preset_combobox, QTreeWidget *bui this->parameter = ¶meter; - const std::vector &selected_layers = configurator.layers.selected_layers; - const Layer *layer = FindByKey(selected_layers, parameter.key.c_str()); + const Layer *layer = configurator.layers.Find(parameter.key, parameter.api_version); /* QTreeWidgetItem *layer_item = new QTreeWidgetItem(); this->tree->addTopLevelItem(layer_item); @@ -373,11 +374,12 @@ void SettingsTreeManager::BuildTreeItem(QTreeWidgetItem *parent, Parameter ¶ } void SettingsTreeManager::BuildGenericTree(Parameter ¶meter) { - std::vector &available_layers = Configurator::Get().layers.selected_layers; + Configurator &configurator = Configurator::Get(); + const Layer *layer = configurator.layers.Find(parameter.key, parameter.api_version); + assert(layer != nullptr); - const SettingMetaSet &settings = FindByKey(available_layers, parameter.key.c_str())->settings; - for (std::size_t i = 0, n = settings.size(); i < n; ++i) { - this->BuildTreeItem(nullptr, parameter, *settings[i]); + for (std::size_t i = 0, n = layer->settings.size(); i < n; ++i) { + this->BuildTreeItem(nullptr, parameter, *layer->settings[i]); } if (!parameter.setting_tree_state.isEmpty()) { diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index ef2782f595..5ef56d0b73 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -259,6 +259,7 @@ void TabConfigurations::UpdateUI_Settings(UpdateUIMode mode) { if (configurator.configurations.GetActiveConfigurationInfo() == nullptr) { this->_settings_tree_manager.CleanupGUI(); + ui->configurations_presets_comboBox->setVisible(false); } else { this->_settings_tree_manager.CreateGUI(ui->configurations_presets_comboBox, ui->configurations_settings_tree); } @@ -312,7 +313,18 @@ bool TabConfigurations::EventFilter(QObject *target, QEvent *event) { if (event_type == QEvent::ChildRemoved) { // Layers were reordered, we need to update the configuration - Configurator::Get().Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); + Configurator &configurator = Configurator::Get(); + Configuration *configuration = configurator.GetActiveConfiguration(); + + std::vector layer_names; + for (int i = 0, n = ui->configurations_layers_list->count(); i < n; ++i) { + QWidget *widget = ui->configurations_layers_list->itemWidget(ui->configurations_layers_list->item(i)); + const std::string &layer_name = static_cast(widget)->layer_name; + layer_names.push_back(layer_name); + } + configuration->Reorder(layer_names); + + configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); return true; } @@ -469,6 +481,7 @@ void TabConfigurations::OnSelectConfiguration(int currentRow) { this->UpdateUI_Configurations(UPDATE_REFRESH_UI); this->UpdateUI_LoaderMessages(); this->UpdateUI_Layers(UPDATE_REBUILD_UI); + this->UpdateUI_Settings(UPDATE_REBUILD_UI); } } @@ -656,8 +669,7 @@ void TabConfigurations::OnContextMenuResetClicked(ConfigurationListItem *item) { assert(!item->configuration_name.empty()); Configurator &configurator = Configurator::Get(); - Configuration *configuration = - FindByKey(configurator.configurations.available_configurations, item->configuration_name.c_str()); + Configuration *configuration = configurator.configurations.FindConfiguration(item->configuration_name); assert(configuration != nullptr); QMessageBox alert; diff --git a/vkconfig_gui/widget_setting_flags.cpp b/vkconfig_gui/widget_setting_flags.cpp index e47396b57b..faff74a7a4 100644 --- a/vkconfig_gui/widget_setting_flags.cpp +++ b/vkconfig_gui/widget_setting_flags.cpp @@ -29,6 +29,18 @@ #include +template +static const T* FindByKey(const std::vector& container, const char* key) { + assert(key != nullptr); + assert(std::strcmp(key, "") != 0); + + for (std::size_t i = 0, n = container.size(); i < n; ++i) { + if (container[i].key == key) return &container[i]; + } + + return nullptr; +} + WidgetSettingFlag::WidgetSettingFlag(QTreeWidget* tree, QTreeWidgetItem* item, const SettingMetaFlags& meta, SettingDataSet& data_set, const std::string& flag) : WidgetSettingBase(tree, item), meta(meta), data_set(data_set), flag(flag), field(new QCheckBox(this)) { diff --git a/vkconfig_gui/widget_tab_configurations_layer.cpp b/vkconfig_gui/widget_tab_configurations_layer.cpp index 7b02399ba3..75df1cc620 100644 --- a/vkconfig_gui/widget_tab_configurations_layer.cpp +++ b/vkconfig_gui/widget_tab_configurations_layer.cpp @@ -201,9 +201,12 @@ void ConfigurationLayerWidget::on_layer_version_currentIndexChanged(int index) { const std::string &text = this->layer_version->itemText(index).toStdString(); Version version = text == "latest" ? Version::LATEST : Version(text.c_str()); - Configuration *configuration = Configurator::Get().GetActiveConfiguration(); - Parameter *parameter = configuration->Find(this->layer_name); - parameter->api_version = version; + Configurator &configurator = Configurator::Get(); + + Configuration *configuration = configurator.GetActiveConfiguration(); + configuration->SwitchLayerVersion(configurator.layers, this->layer_name, version); + + this->tab->UpdateUI_Settings(UPDATE_REBUILD_UI); } void ConfigurationLayerWidget::on_layer_state_currentIndexChanged(int index) { diff --git a/vkconfig_gui/widget_tab_configurations_layer.h b/vkconfig_gui/widget_tab_configurations_layer.h index c7cccf7b10..d8d60041ab 100644 --- a/vkconfig_gui/widget_tab_configurations_layer.h +++ b/vkconfig_gui/widget_tab_configurations_layer.h @@ -40,6 +40,8 @@ class ConfigurationLayerWidget : public QLabel { ConfigurationLayerWidget(TabConfigurations *tab, const Parameter ¶meter, const std::vector &layer_version, bool advanced_view); + std::string layer_name; + protected: bool eventFilter(QObject *target, QEvent *event); void resizeEvent(QResizeEvent *event) override; @@ -50,7 +52,6 @@ class ConfigurationLayerWidget : public QLabel { private: TabConfigurations *tab; - std::string layer_name; QComboBox *layer_version = nullptr; QComboBox *layer_state = nullptr; diff --git a/vkconfig_gui/widget_tab_layers_path.cpp b/vkconfig_gui/widget_tab_layers_path.cpp index c05c1f9208..48986020f5 100644 --- a/vkconfig_gui/widget_tab_layers_path.cpp +++ b/vkconfig_gui/widget_tab_layers_path.cpp @@ -28,7 +28,7 @@ LayersPathWidget::LayersPathWidget(LayersPathInfo* path_info) : path_info(path_i this->setChecked(this->path_info->enabled); this->buttom_remove = new QPushButton(this); - this->buttom_remove->setText("x"); + this->buttom_remove->setText("-"); this->buttom_remove->show(); this->setText(path_info->path.RelativePath().c_str()); From 7b818ca7c877abd0ba93c234e3b603b6631a0ccc Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 9 Sep 2024 17:46:53 +0200 Subject: [PATCH 22/33] vkconfig3: Various clean up --- vkconfig_core/application_manager.cpp | 21 ++++++ vkconfig_core/application_manager.h | 26 ++++++++ vkconfig_core/configuration_manager.cpp | 12 ++-- vkconfig_core/configurator.cpp | 4 +- vkconfig_core/environment.cpp | 14 ++-- vkconfig_core/help.cpp | 9 ++- vkconfig_core/layer_manager.cpp | 4 +- vkconfig_core/layer_preset.cpp | 16 +++-- vkconfig_core/layer_preset.h | 4 +- vkconfig_core/parameter.cpp | 66 ------------------- vkconfig_core/parameter.h | 3 - vkconfig_core/path.cpp | 14 ++-- vkconfig_core/registry.cpp | 4 +- vkconfig_core/registry.h | 4 +- vkconfig_core/test/test_command_line.cpp | 6 +- vkconfig_core/test/test_path.cpp | 4 +- vkconfig_core/test/test_type_platform.cpp | 49 ++++---------- vkconfig_core/type_platform.cpp | 53 +++++++-------- vkconfig_core/type_platform.h | 44 +++++++------ vkconfig_core/vulkan_util.cpp | 4 +- vkconfig_gui/dialog_vulkan_analysis.cpp | 2 +- vkconfig_gui/dialog_vulkan_info.cpp | 4 +- vkconfig_gui/vkconfig.pro | 2 + .../widget_tab_configurations_layer.cpp | 10 +-- 24 files changed, 172 insertions(+), 207 deletions(-) create mode 100644 vkconfig_core/application_manager.cpp create mode 100644 vkconfig_core/application_manager.h diff --git a/vkconfig_core/application_manager.cpp b/vkconfig_core/application_manager.cpp new file mode 100644 index 0000000000..974198f104 --- /dev/null +++ b/vkconfig_core/application_manager.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "application_manager.h" diff --git a/vkconfig_core/application_manager.h b/vkconfig_core/application_manager.h new file mode 100644 index 0000000000..8264ae2b2a --- /dev/null +++ b/vkconfig_core/application_manager.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +class ApplicationManager { + public: + private: +}; diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index 0505520e78..5125f5d335 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -139,13 +139,13 @@ void ConfigurationManager::LoadDefaultConfigurations(const LayerManager &layers) continue; } -#ifdef _M_ARM64 - if (configuration.key == "Frame Capture") { - continue; - } else if (configuration.key == "Crash Diagnostic") { - continue; + if (VKC_PLATFORM == PLATFORM_WINDOWS_ARM) { + if (configuration.key == "Frame Capture") { + continue; + } else if (configuration.key == "Crash Diagnostic") { + continue; + } } -#endif OrderParameter(configuration.parameters, layers); diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index 61fd06eba4..844b9f255f 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -419,7 +419,7 @@ bool Configurator::Override(OverrideArea override_area) { bool result_layers_settings = this->WriteLayersSettings(override_area, layers_settings_path); // On Windows only, we need to write these values to the registry -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#if VKC_ENV == VKC_ENV_WIN32 AppendRegistryEntriesForLayers(loader_settings_path.AbsolutePath().c_str(), layers_settings_path.AbsolutePath().c_str()); #endif @@ -441,7 +441,7 @@ bool Configurator::Surrender(OverrideArea override_area) { result_layers_settings = layers_settings_path.Remove(); } -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#if VKC_ENV == VKC_ENV_WIN32 RemoveRegistryEntriesForLayers(loader_settings_path.AbsolutePath().c_str(), layers_settings_path.AbsolutePath().c_str()); #endif diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index d8e2ca7c06..f0c4b9d9dd 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -41,10 +41,12 @@ static const char* GetApplicationSuffix() { static const char* TABLE[] = { - ".exe", // PLATFORM_WINDOWS + ".exe", // PLATFORM_WINDOWS_X86 + ".exe", // PLATFORM_WINDOWS_ARM "", // PLATFORM_LINUX ".app", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID + "N/A", // PLATFORM_ANDROID + "N/A" // PLATFORM_IOS }; static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); @@ -356,7 +358,7 @@ bool ExactExecutableFromAppBundle(Path& app_path) { } DefaultPath Environment::GetDefaultExecutablePath(const std::string& executable_name) const { - static const char* DEFAULT_PATH = VKC_PLATFORM == VKC_PLATFORM_MACOS ? "/../.." : ""; + static const char* DEFAULT_PATH = VKC_PLATFORM == PLATFORM_MACOS ? "/../.." : ""; DefaultPath default_path{"." + executable_name, "."}; @@ -372,14 +374,14 @@ DefaultPath Environment::GetDefaultExecutablePath(const std::string& executable_ } // Search the default applications from package installation (Linux) - if (VKC_PLATFORM == VKC_PLATFORM_LINUX) { + if (VKC_PLATFORM == PLATFORM_LINUX) { const Path search_path(std::string("/usr/bin") + DEFAULT_PATH + executable_name); if (search_path.Exists()) { default_path.executable_path = Path(search_path.AbsolutePath(), true); default_path.working_folder = Path(search_path.AbsoluteDir(), true); return default_path; } - } else if (VKC_PLATFORM == VKC_PLATFORM_MACOS) { + } else if (VKC_PLATFORM == PLATFORM_MACOS) { Path search_path(std::string("/Applications") + executable_name); if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { default_path.executable_path = Path(search_path.AbsolutePath(), true); @@ -389,7 +391,7 @@ DefaultPath Environment::GetDefaultExecutablePath(const std::string& executable_ } // Using relative path to vkconfig in case SDK is not "installed" - if (VKC_PLATFORM == VKC_PLATFORM_MACOS) { + if (VKC_PLATFORM == PLATFORM_MACOS) { Path search_path(std::string("..") + DEFAULT_PATH + executable_name); if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { default_path.executable_path = Path(search_path.AbsolutePath(), true); diff --git a/vkconfig_core/help.cpp b/vkconfig_core/help.cpp index 41933a8925..c04e80375b 100644 --- a/vkconfig_core/help.cpp +++ b/vkconfig_core/help.cpp @@ -31,10 +31,15 @@ void ShowDoc(DocType doc_type) { static const char* PLATFORM_STRING[] = { - "windows", // PLATFORM_WINDOWS + "windows", // PLATFORM_WINDOWS_X86 + "windows", // PLATFORM_WINDOWS_ARM "linux", // PLATFORM_LINUX - "mac" // PLATFORM_MACOS + "mac", // PLATFORM_MACOS + "android", // PLATFORM_ANDROID + "ios" // PLATFORM_ANDROID }; + static_assert(std::size(PLATFORM_STRING) == PLATFORM_COUNT, + "The tranlation table size doesn't match the enum number of elements"); const char* platform = PLATFORM_STRING[VKC_PLATFORM]; diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 5b6f7f3d24..72492b57de 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -36,7 +36,7 @@ LayerType GetLayerType(LayersPaths Layers_paths_type) { std::vector GetImplicitLayerPaths() { std::vector result; -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#if VKC_ENV == VKC_ENV_WIN32 static const char *REGISTRY_PATHS[] = { "HKEY_LOCAL_MACHINE\\Software\\Khronos\\Vulkan\\ImplicitLayers", "HKEY_CURRENT_USER\\Software\\Khronos\\Vulkan\\ImplicitLayers", @@ -74,7 +74,7 @@ std::vector GetImplicitLayerPaths() { std::vector GetExplicitLayerPaths() { std::vector result; -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#if VKC_ENV == VKC_ENV_WIN32 static const char *REGISTRY_PATHS[] = { "HKEY_LOCAL_MACHINE\\Software\\Khronos\\Vulkan\\ExplicitLayers", "HKEY_CURRENT_USER\\Software\\Khronos\\Vulkan\\ExplicitLayers", diff --git a/vkconfig_core/layer_preset.cpp b/vkconfig_core/layer_preset.cpp index 8631174625..285129dd1d 100644 --- a/vkconfig_core/layer_preset.cpp +++ b/vkconfig_core/layer_preset.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,13 +38,19 @@ const LayerPreset* GetPreset(const std::vector& presets, const char } bool HasPreset(const SettingDataSet& layer_settings, const SettingDataSetConst& preset_settings) { - if (preset_settings.empty()) return false; + if (preset_settings.empty()) { + return false; + } for (std::size_t preset_index = 0, preset_count = preset_settings.size(); preset_index < preset_count; ++preset_index) { const SettingData* layer_setting = FindSetting(layer_settings, preset_settings[preset_index]->key.c_str()); - if (layer_setting == nullptr) return false; + if (layer_setting == nullptr) { + return false; + } - if (*preset_settings[preset_index] != *layer_setting) return false; + if (*preset_settings[preset_index] != *layer_setting) { + return false; + } } return true; diff --git a/vkconfig_core/layer_preset.h b/vkconfig_core/layer_preset.h index 61463391d9..24d148bb50 100644 --- a/vkconfig_core/layer_preset.h +++ b/vkconfig_core/layer_preset.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/vkconfig_core/parameter.cpp b/vkconfig_core/parameter.cpp index 1294d525bc..cbd72f034d 100644 --- a/vkconfig_core/parameter.cpp +++ b/vkconfig_core/parameter.cpp @@ -77,34 +77,6 @@ ParameterRank GetParameterOrdering(const LayerManager& layers, const Parameter& } } -Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const LayerManager& layers) { - if (parameters.empty()) { - return Version::NONE; - } - - Version min_version = api_version; - - for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - const Layer* layer = layers.Find(parameters[i].key, parameters[i].api_version); - if (layer == nullptr) { - continue; - } - - const ParameterRank state = GetParameterOrdering(layers, parameters[i]); - - if (state == PARAMETER_RANK_EXCLUDED) { - continue; - } - if (state == PARAMETER_RANK_MISSING) { - continue; - } - - min_version = min_version < layer->api_version ? min_version : layer->api_version; - } - - return min_version; -} - void OrderParameter(std::vector& parameters, const LayerManager& layers) { struct ParameterCompare { ParameterCompare(const LayerManager& layers) : layers(layers) {} @@ -153,20 +125,6 @@ void OrderParameter(std::vector& parameters, const LayerManager& laye } } -void FilterParameters(std::vector& parameters, const LayerControl control) { - std::vector filtered_parameters; - - for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - if (parameters[i].control == control) { - continue; - } - - filtered_parameters.push_back(parameters[i]); - } - - parameters = filtered_parameters; -} - bool HasMissingLayer(const std::vector& parameters, const LayerManager& layers, std::string& missing_layer) { for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it) { if (it->control == LAYER_CONTROL_OFF) { @@ -203,27 +161,3 @@ std::size_t CountOverriddenLayers(const std::vector& parameters) { return count; } - -std::size_t CountExcludedLayers(const std::vector& parameters, const LayerManager& layers) { - std::size_t count = 0; - - for (std::size_t i = 0, n = parameters.size(); i < n; ++i) { - const Parameter& parameter = parameters[i]; - if (!IsPlatformSupported(parameter.platform_flags)) { - continue; - } - - if (parameter.control != LAYER_CONTROL_OFF) { - continue; - } - - const Layer* layer = layers.Find(parameter.key, parameter.api_version); - if (layer == nullptr) { - continue; // Do not display missing excluded layers - } - - ++count; - } - - return count; -} diff --git a/vkconfig_core/parameter.h b/vkconfig_core/parameter.h index c1bd2424bb..cab1afd6fc 100644 --- a/vkconfig_core/parameter.h +++ b/vkconfig_core/parameter.h @@ -54,11 +54,8 @@ struct Parameter { }; ParameterRank GetParameterOrdering(const LayerManager& layers, const Parameter& parameter); -Version ComputeMinApiVersion(const Version api_version, const std::vector& parameters, const LayerManager& layers); void OrderParameter(std::vector& parameters, const LayerManager& layers); -void FilterParameters(std::vector& parameters, const LayerControl control); bool HasMissingLayer(const std::vector& parameters, const LayerManager& layers, std::string& missing_layer); std::size_t CountOverriddenLayers(const std::vector& parameters); -std::size_t CountExcludedLayers(const std::vector& parameters, const LayerManager& layers); diff --git a/vkconfig_core/path.cpp b/vkconfig_core/path.cpp index f6fb5be082..2e37b8cda1 100644 --- a/vkconfig_core/path.cpp +++ b/vkconfig_core/path.cpp @@ -336,10 +336,12 @@ static const Path GetLoaderSettingsPath() { static const Path GetSDKPath() { const char* TABLE[] = { - "", // PLATFORM_WINDOWS + "", // PLATFORM_WINDOWS_X86 + "", // PLATFORM_WINDOWS_ARM "/usr", // PLATFORM_LINUX "/usr/local/share/vulkan", // PLATFORM_MACOS - "" // PLATFORM_ANDROID + "", // PLATFORM_ANDROID + "" // PLATFORM_IOS }; static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); @@ -347,7 +349,7 @@ static const Path GetSDKPath() { if (result.empty()) { result = TABLE[VKC_PLATFORM]; } else { // VULKAN_SDK may be set on macOS - if (VKC_PLATFORM == VKC_PLATFORM_MACOS) { + if (VKC_PLATFORM == PLATFORM_MACOS) { result += "/share/vulkan"; } } @@ -377,10 +379,12 @@ static const Path GetExplicitLayersPath() { static const Path GetVulkanContentPath() { static const std::string TABLE[] = { - "/Config", // PLATFORM_WINDOWS + "/Config", // PLATFORM_WINDOWS_86 + "/Config", // PLATFORM_WINDOWS_ARM "/share/vulkan/config", // PLATFORM_LINUX "/config", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID + "N/A", // PLATFORM_ANDROID + "N/A" // PLATFORM_IOS }; static_assert(std::size(TABLE) == PLATFORM_COUNT); diff --git a/vkconfig_core/registry.cpp b/vkconfig_core/registry.cpp index 0b80ade1b7..5b4f368ec1 100644 --- a/vkconfig_core/registry.cpp +++ b/vkconfig_core/registry.cpp @@ -22,7 +22,7 @@ #include -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#if VKC_ENV == VKC_ENV_WIN32 #include #include #include @@ -200,4 +200,4 @@ std::vector LoadRegistryLayers(const QString &path) { return layers_paths; } -#endif // VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#endif // VKC_ENV == VKC_ENV_WIN32 diff --git a/vkconfig_core/registry.h b/vkconfig_core/registry.h index 7696fc8401..a40fcc1198 100644 --- a/vkconfig_core/registry.h +++ b/vkconfig_core/registry.h @@ -23,7 +23,7 @@ #include "type_platform.h" #include "layer.h" -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#if VKC_ENV == VKC_ENV_WIN32 #include @@ -35,4 +35,4 @@ void RemoveRegistryEntriesForLayers(QString override_file, QString settings_file std::vector LoadRegistryLayers(const QString &path); -#endif // VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#endif // VKC_ENV == VKC_ENV_WIN32 diff --git a/vkconfig_core/test/test_command_line.cpp b/vkconfig_core/test/test_command_line.cpp index 2358c1f75d..125392e300 100644 --- a/vkconfig_core/test/test_command_line.cpp +++ b/vkconfig_core/test/test_command_line.cpp @@ -23,10 +23,9 @@ #include "../util.h" #include "../type_platform.h" -#if VKC_PLATFORM == VKC_PLATFORM_LINUX +#if VKC_ENV == VKC_ENV_UNIX #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wwrite-strings" -#elif VKC_PLATFORM == VKC_PLATFORM_MACOS #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wwrite-strings" #endif @@ -203,8 +202,7 @@ TEST(test_command_line, usage_mode_layers_override_invalid_args) { EXPECT_TRUE(command_line.layers_configuration_path.empty()); } -#if VKC_PLATFORM == VKC_PLATFORM_LINUX +#if VKC_ENV == VKC_ENV_UNIX #pragma GCC diagnostic pop -#elif VKC_PLATFORM == VKC_PLATFORM_MACOS #pragma clang diagnostic pop #endif diff --git a/vkconfig_core/test/test_path.cpp b/vkconfig_core/test/test_path.cpp index 321d3d68cf..6111e29406 100644 --- a/vkconfig_core/test/test_path.cpp +++ b/vkconfig_core/test/test_path.cpp @@ -37,7 +37,7 @@ TEST(test_path, native_path) { for (std::size_t i = 0, n = std::size(table); i < n; ++i) { const std::string test_case = table[i]; - if (VKC_PLATFORM == VKC_PLATFORM_WINDOWS) { + if (VKC_ENV == VKC_ENV_WIN32) { EXPECT_STREQ("\\vkconfig\\test\\path\\format", Path(test_case).RelativePath().c_str()); } else { EXPECT_STREQ("/vkconfig/test/path/format", Path(test_case).RelativePath().c_str()); @@ -51,7 +51,7 @@ TEST(test_path, native_path_with_file) { for (std::size_t i = 0, n = std::size(table); i < n; ++i) { const std::string test_case = table[i]; - if (VKC_PLATFORM == VKC_PLATFORM_WINDOWS) { + if (VKC_ENV == VKC_ENV_WIN32) { EXPECT_STREQ("\\vkconfig\\test\\path\\format\\file.txt", Path(test_case).RelativePath().c_str()); } else { EXPECT_STREQ("/vkconfig/test/path/format/file.txt", Path(test_case).RelativePath().c_str()); diff --git a/vkconfig_core/test/test_type_platform.cpp b/vkconfig_core/test/test_type_platform.cpp index 01a893b7d3..f3306c9610 100644 --- a/vkconfig_core/test/test_type_platform.cpp +++ b/vkconfig_core/test/test_type_platform.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,28 +25,21 @@ #include TEST(test_platform, platform_flags_one) { - std::vector platform_strings; - platform_strings.push_back(GetToken(PLATFORM_LINUX)); - - EXPECT_EQ(PLATFORM_LINUX_BIT, GetPlatformFlags(platform_strings)); + std::vector platform_strings = GetPlatformTokens(PLATFORM_LINUX_BIT); + int flags = GetPlatformFlags(platform_strings); + EXPECT_EQ(PLATFORM_LINUX_BIT, flags); } TEST(test_platform, platform_flags_some) { - std::vector platform_strings; - platform_strings.push_back(GetToken(PLATFORM_LINUX)); - platform_strings.push_back(GetToken(PLATFORM_MACOS)); - - EXPECT_EQ(PLATFORM_LINUX_BIT | PLATFORM_MACOS_BIT, GetPlatformFlags(platform_strings)); + std::vector platform_strings = GetPlatformTokens(PLATFORM_LINUX_BIT | PLATFORM_MACOS_BIT); + int flags = GetPlatformFlags(platform_strings); + EXPECT_EQ(PLATFORM_LINUX_BIT | PLATFORM_MACOS_BIT, flags); } TEST(test_platform, platform_flags_all) { - std::vector platform_strings; - for (std::size_t i = 0, n = PLATFORM_COUNT; i < n; ++i) { - const PlatformType platform_type = static_cast(i); - platform_strings.push_back(GetToken(platform_type)); - } - - EXPECT_EQ(PLATFORM_DESKTOP_BIT | PLATFORM_ANDROID_BIT, GetPlatformFlags(platform_strings)); + std::vector platform_strings = GetPlatformTokens(PLATFORM_DESKTOP_BIT | PLATFORM_MOBILE_BIT); + int flags = GetPlatformFlags(platform_strings); + EXPECT_EQ(PLATFORM_DESKTOP_BIT | PLATFORM_MOBILE_BIT, flags); } TEST(test_platform, platform_to_tokens) { @@ -54,23 +47,3 @@ TEST(test_platform, platform_to_tokens) { EXPECT_EQ(PLATFORM_LINUX_BIT, GetPlatformFlags(GetPlatformTokens(PLATFORM_LINUX_BIT))); EXPECT_EQ(PLATFORM_DESKTOP_BIT, GetPlatformFlags(GetPlatformTokens(PLATFORM_DESKTOP_BIT))); } - -TEST(test_platform, platform_type_windows) { - EXPECT_STREQ("WINDOWS", GetToken(PLATFORM_WINDOWS)); - EXPECT_EQ(PLATFORM_WINDOWS, GetPlatformType("WINDOWS")); -} - -TEST(test_platform, platform_type_linux) { - EXPECT_STREQ("LINUX", GetToken(PLATFORM_LINUX)); - EXPECT_EQ(PLATFORM_LINUX, GetPlatformType("LINUX")); -} - -TEST(test_platform, platform_type_macos) { - EXPECT_STREQ("MACOS", GetToken(PLATFORM_MACOS)); - EXPECT_EQ(PLATFORM_MACOS, GetPlatformType("MACOS")); -} - -TEST(test_platform, platform_type_android) { - EXPECT_STREQ("ANDROID", GetToken(PLATFORM_ANDROID)); - EXPECT_EQ(PLATFORM_ANDROID, GetPlatformType("ANDROID")); -} diff --git a/vkconfig_core/type_platform.cpp b/vkconfig_core/type_platform.cpp index fb49df030f..679eb2e2b5 100644 --- a/vkconfig_core/type_platform.cpp +++ b/vkconfig_core/type_platform.cpp @@ -18,23 +18,27 @@ * - Christophe Riccio */ -#include "path.h" #include "util.h" #include "type_platform.h" -#include -#include -#include -#include -#include +#include -#include +static std::map const translation = {std::pair("WINDOWS_X86", PLATFORM_WINDOWS_X86_BIT), + std::pair("WINDOWS_ARM", PLATFORM_WINDOWS_ARM_BIT), + std::pair("WINDOWS", PLATFORM_WINDOWS_X86_BIT | PLATFORM_WINDOWS_ARM_BIT), + std::pair("LINUX", PLATFORM_LINUX_BIT), + std::pair("MACOS", PLATFORM_MACOS_BIT), + std::pair("ANDROID", PLATFORM_ANDROID_BIT), + std::pair("IOS", PLATFORM_IOS_BIT)}; int GetPlatformFlags(const std::vector& platform_strings) { int result = 0; for (std::size_t i = 0, n = platform_strings.size(); i < n; ++i) { - result |= (1 << GetPlatformType(platform_strings[i].c_str())); + auto it = translation.find(platform_strings[i]); + if (it != translation.end()) { + result |= it->second; + } } return result; @@ -44,34 +48,21 @@ std::vector GetPlatformTokens(int platform_flags) { std::vector result; for (std::size_t i = 0, n = PLATFORM_COUNT; i < n; ++i) { - if (platform_flags & (1 << i)) { - result.push_back(GetToken(static_cast(i))); + const int flag = platform_flags & (1 << i); + if (!flag) { + continue; } - } - - return result; -} -const char* GetToken(PlatformType type) { - static const char* table[] = { - "WINDOWS", // PLATFORM_WINDOWS - "LINUX", // PLATFORM_LINUX - "MACOS", // PLATFORM_MACOS - "ANDROID", // PLATFORM_ANDROID - }; - static_assert(std::size(table) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); + for (auto it = translation.begin(), end = translation.end(); it != end; ++it) { + if (it->second != flag) { + continue; + } - return table[type]; -} - -PlatformType GetPlatformType(const char* token) { - for (std::size_t i = 0, n = PLATFORM_COUNT; i < n; ++i) { - const PlatformType platform_type = static_cast(i); - if (std::strcmp(GetToken(platform_type), token) == 0) return platform_type; + result.push_back(it->first); + } } - assert(0); - return static_cast(-1); + return result; } bool IsPlatformSupported(int platform_flags) { return platform_flags & (1 << VKC_PLATFORM); } diff --git a/vkconfig_core/type_platform.h b/vkconfig_core/type_platform.h index 6d0ec0105e..d7750ca601 100644 --- a/vkconfig_core/type_platform.h +++ b/vkconfig_core/type_platform.h @@ -23,12 +23,6 @@ #include #include -#define VKC_PLATFORM_WINDOWS 0 -#define VKC_PLATFORM_LINUX 1 -#define VKC_PLATFORM_MACOS 2 -#define VKC_PLATFORM_ANDROID 3 -#define VKC_PLATFORM_IOS 4 - #define VKC_ENV_WIN32 0 #define VKC_ENV_UNIX 1 @@ -43,43 +37,51 @@ enum EnviromentType { enum { ENVIRONMENT_COUNT = ENVIRONMENT_LAST - ENVIRONMENT_FIRST + 1 }; enum PlatformType { - PLATFORM_WINDOWS = VKC_PLATFORM_WINDOWS, - PLATFORM_LINUX = VKC_PLATFORM_LINUX, - PLATFORM_MACOS = VKC_PLATFORM_MACOS, - PLATFORM_ANDROID = VKC_PLATFORM_ANDROID, - - PLATFORM_FIRST = PLATFORM_WINDOWS, - PLATFORM_LAST = PLATFORM_ANDROID + PLATFORM_WINDOWS_X86 = 0, + PLATFORM_WINDOWS_ARM = 1, + PLATFORM_LINUX = 2, + PLATFORM_MACOS = 3, + PLATFORM_ANDROID = 4, + PLATFORM_IOS = 5, + + PLATFORM_FIRST = PLATFORM_WINDOWS_X86, + PLATFORM_LAST = PLATFORM_IOS }; enum { PLATFORM_COUNT = PLATFORM_LAST - PLATFORM_FIRST + 1 }; enum PlatformFlags { - PLATFORM_WINDOWS_BIT = (1 << PLATFORM_WINDOWS), + PLATFORM_WINDOWS_X86_BIT = (1 << PLATFORM_WINDOWS_X86), + PLATFORM_WINDOWS_ARM_BIT = (1 << PLATFORM_WINDOWS_ARM), PLATFORM_LINUX_BIT = (1 << PLATFORM_LINUX), PLATFORM_MACOS_BIT = (1 << PLATFORM_MACOS), PLATFORM_ANDROID_BIT = (1 << PLATFORM_ANDROID), + PLATFORM_IOS_BIT = (1 << PLATFORM_IOS), + + PLATFORM_WINDOWS_BIT = PLATFORM_WINDOWS_X86_BIT | PLATFORM_WINDOWS_ARM_BIT, - PLATFORM_DESKTOP_BIT = PLATFORM_WINDOWS_BIT | PLATFORM_LINUX_BIT | PLATFORM_MACOS_BIT + PLATFORM_DESKTOP_BIT = PLATFORM_WINDOWS_BIT | PLATFORM_LINUX_BIT | PLATFORM_MACOS_BIT, + PLATFORM_MOBILE_BIT = PLATFORM_ANDROID_BIT | PLATFORM_IOS_BIT }; int GetPlatformFlags(const std::vector& platform_strings); std::vector GetPlatformTokens(int platform_flags); -PlatformType GetPlatformType(const char* token); -const char* GetToken(PlatformType type); - #ifdef _WIN32 -#define VKC_PLATFORM VKC_PLATFORM_WINDOWS +#ifdef _M_ARM64 +#define VKC_PLATFORM PLATFORM_WINDOWS_ARM +#else +#define VKC_PLATFORM PLATFORM_WINDOWS_X86 +#endif #define VKC_ENV VKC_ENV_WIN32 #elif defined(__linux__) -#define VKC_PLATFORM VKC_PLATFORM_LINUX +#define VKC_PLATFORM PLATFORM_LINUX #define VKC_ENV VKC_ENV_UNIX #elif defined(__APPLE__) -#define VKC_PLATFORM VKC_PLATFORM_MACOS +#define VKC_PLATFORM PLATFORM_MACOS #define VKC_ENV VKC_ENV_UNIX #else diff --git a/vkconfig_core/vulkan_util.cpp b/vkconfig_core/vulkan_util.cpp index e9309e6573..a336a9c45f 100644 --- a/vkconfig_core/vulkan_util.cpp +++ b/vkconfig_core/vulkan_util.cpp @@ -53,10 +53,12 @@ struct VulkanFunctions { static const char *GetVulkanLibrary() { static const char *TABLE[] = { - "vulkan-1.dll", // PLATFORM_WINDOWS + "vulkan-1.dll", // PLATFORM_WINDOWS_X86 + "vulkan-1.dll", // PLATFORM_WINDOWS_ARM "libvulkan", // PLATFORM_LINUX "/usr/local/lib/libvulkan", // PLATFORM_MACOS "N/A", // PLATFORM_ANDROID + "N/A", // PLATFORM_IOS }; static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); diff --git a/vkconfig_gui/dialog_vulkan_analysis.cpp b/vkconfig_gui/dialog_vulkan_analysis.cpp index 585af580f2..b16cfc5634 100644 --- a/vkconfig_gui/dialog_vulkan_analysis.cpp +++ b/vkconfig_gui/dialog_vulkan_analysis.cpp @@ -58,7 +58,7 @@ void VulkanAnalysisDialog::Run() { ui->physicalDevicesTable->clear(); QProcess *via = new QProcess(this); -#if VKC_PLATFORM == VKC_PLATFORM_MACOS +#if VKC_PLATFORM == PLATFORM_MACOS via->setProgram("/usr/local/bin/vkvia"); #else via->setProgram("vkvia"); diff --git a/vkconfig_gui/dialog_vulkan_info.cpp b/vkconfig_gui/dialog_vulkan_info.cpp index a6698be1b8..88335e5b98 100644 --- a/vkconfig_gui/dialog_vulkan_info.cpp +++ b/vkconfig_gui/dialog_vulkan_info.cpp @@ -49,10 +49,12 @@ VulkanInfoDialog::VulkanInfoDialog(QWidget *parent) : QDialog(parent), ui(new Ui void VulkanInfoDialog::Run() { static const char *VULKAN_INFO_PATH[] = { - "vulkaninfoSDK", // PLATFORM_WINDOWS + "vulkaninfoSDK", // PLATFORM_WINDOWS_X86 + "vulkaninfoSDK", // PLATFORM_WINDOWS_ARM "vulkaninfo", // PLATFORM_LINUX "/usr/local/bin/vulkaninfo", // PLATFORM_MACOS "N/A", // PLATFORM_ANDROID + "N/A", // PLATFORM_IOS }; static_assert(std::size(VULKAN_INFO_PATH) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index d0632752c8..576febeaa6 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -29,6 +29,7 @@ linux: QMAKE_CXXFLAGS += -Wunused-variable SOURCES += \ ../vkconfig_core/alert.cpp \ ../vkconfig_core/application.cpp \ + ../vkconfig_core/application_manager.cpp \ ../vkconfig_core/application_singleton.cpp \ ../vkconfig_core/bitfield.cpp \ ../vkconfig_core/command_line.cpp \ @@ -105,6 +106,7 @@ SOURCES += \ HEADERS += \ ../vkconfig_core/alert.h \ ../vkconfig_core/application.h \ + ../vkconfig_core/application_manager.h \ ../vkconfig_core/application_singleton.h \ ../vkconfig_core/bitfield.h \ ../vkconfig_core/command_line.h \ diff --git a/vkconfig_gui/widget_tab_configurations_layer.cpp b/vkconfig_gui/widget_tab_configurations_layer.cpp index 75df1cc620..ce42789dbd 100644 --- a/vkconfig_gui/widget_tab_configurations_layer.cpp +++ b/vkconfig_gui/widget_tab_configurations_layer.cpp @@ -24,10 +24,10 @@ #include "../vkconfig_core/configurator.h" -#if VKC_PLATFORM == VKC_PLATFORM_LINUX || VKC_PLATFORM == VKC_PLATFORM_MACOS +#if VKC_ENV == VKC_ENV_UNIX #include -#elif VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#elif VKC_ENV == VKC_ENV_WIN32 #include // From Stack Overflow. @@ -56,11 +56,11 @@ static PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) { } // End Stack Overflow -#endif // VKC_PLATFORM +#endif // VKC_ENV /// Utility function to see if the file is 32-bit static bool IsDLL32Bit(const std::string full_path) { -#if VKC_PLATFORM == VKC_PLATFORM_WINDOWS +#if VKC_ENV == VKC_ENV_WIN32 if (full_path.empty()) { return false; } @@ -90,7 +90,7 @@ static bool IsDLL32Bit(const std::string full_path) { #else (void)full_path; return false; -#endif +#endif // VKC_ENV } ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const Parameter ¶meter, From 83f48ac497339fc2f344d6d8612cac4579e4be7d Mon Sep 17 00:00:00 2001 From: Christophe Date: Tue, 10 Sep 2024 18:06:37 +0200 Subject: [PATCH 23/33] vkconfig: Fix switching of missing layer --- vkconfig_core/layer.cpp | 2 + vkconfig_core/layer.h | 2 + vkconfig_core/layer_manager.cpp | 5 + vkconfig_core/type_tab.cpp | 4 +- vkconfig_core/type_tab.h | 4 +- vkconfig_gui/mainwindow.cpp | 5 +- vkconfig_gui/mainwindow.ui | 1642 ++++++++--------- vkconfig_gui/settings_tree.cpp | 8 +- vkconfig_gui/settings_tree.h | 2 +- vkconfig_gui/tab_layers.cpp | 4 +- vkconfig_gui/vkconfig.pro | 2 - vkconfig_gui/widget_preset.cpp | 91 - vkconfig_gui/widget_preset.h | 57 - .../widget_tab_configurations_layer.cpp | 8 +- 14 files changed, 853 insertions(+), 983 deletions(-) delete mode 100644 vkconfig_gui/widget_preset.cpp delete mode 100644 vkconfig_gui/widget_preset.h diff --git a/vkconfig_core/layer.cpp b/vkconfig_core/layer.cpp index eba7b9caca..9cde463285 100644 --- a/vkconfig_core/layer.cpp +++ b/vkconfig_core/layer.cpp @@ -49,6 +49,8 @@ const char* Layer::NO_PRESET = "User-Defined Settings"; +bool operator<(const LayersPathInfo& a, const LayersPathInfo& b) { return a.path.RelativePath() < b.path.RelativePath(); } + Layer::Layer() : status(STATUS_STABLE), platforms(PLATFORM_DESKTOP_BIT) {} Layer::Layer(const std::string& key) : key(key), status(STATUS_STABLE), platforms(PLATFORM_DESKTOP_BIT) {} diff --git a/vkconfig_core/layer.h b/vkconfig_core/layer.h index afc0e35d8d..16696bd0c1 100644 --- a/vkconfig_core/layer.h +++ b/vkconfig_core/layer.h @@ -40,6 +40,8 @@ struct LayersPathInfo { bool enabled = true; }; +bool operator<(const LayersPathInfo& a, const LayersPathInfo& b); + class Layer { public: static const char* NO_PRESET; diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 72492b57de..53ec7a1dc7 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -276,6 +276,9 @@ const Layer *LayerManager::Find(const std::string &layer_name, const Version &la return this->Find(layer_name, latest); } else { for (std::size_t i = 0, n = this->selected_layers.size(); i < n; ++i) { + if (this->selected_layers[i].visible == false) { + continue; + } if (this->selected_layers[i].key != layer_name) { continue; } @@ -359,6 +362,8 @@ void LayerManager::AddPath(const LayersPathInfo &info) { } else { this->paths[LAYERS_PATHS_GUI].push_back(info); } + + std::sort(this->paths[LAYERS_PATHS_GUI].begin(), this->paths[LAYERS_PATHS_GUI].end()); } void LayerManager::RemovePath(const LayersPathInfo &path_info) { diff --git a/vkconfig_core/type_tab.cpp b/vkconfig_core/type_tab.cpp index 82df19a0a1..00689e1aa3 100644 --- a/vkconfig_core/type_tab.cpp +++ b/vkconfig_core/type_tab.cpp @@ -26,9 +26,9 @@ const char* GetToken(TabType type) { static const char* TOKENS[]{ "DIAGNOSTIC", // TAB_DIAGNOSTIC - "APPLICATIONS", // TAB_APPLICATIONS - "LAYERS", // TAB_LAYERS "CONFIGURATIONS", // TAB_CONFIGURATIONS + "LAYERS", // TAB_LAYERS + "APPLICATIONS", // TAB_APPLICATIONS "PREFERENCES", // TAB_PREFERENCES "HELP" // TAB_HELP }; diff --git a/vkconfig_core/type_tab.h b/vkconfig_core/type_tab.h index b1bb250674..18c9e40b59 100644 --- a/vkconfig_core/type_tab.h +++ b/vkconfig_core/type_tab.h @@ -22,9 +22,9 @@ enum TabType { TAB_DIAGNOSTIC = 0, - TAB_APPLICATIONS, - TAB_LAYERS, TAB_CONFIGURATIONS, + TAB_LAYERS, + TAB_APPLICATIONS, TAB_PREFERENCES, TAB_HELP, diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 6352426a2f..c7402c4405 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -481,7 +481,10 @@ QStringList MainWindow::BuildEnvVariables() const { return env; } -void MainWindow::on_tab_widget_currentChanged(int index) { this->tabs[index]->UpdateUI(UPDATE_REBUILD_UI); } +void MainWindow::on_tab_widget_currentChanged(int index) { + assert(index >= 0); + this->tabs[index]->UpdateUI(UPDATE_REBUILD_UI); +} void MainWindow::on_push_button_launcher_clicked() { // Are we already monitoring a running app? If so, terminate it diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index c3f12f9b96..e6e9aa9ed7 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -72,7 +72,7 @@ QTabWidget::Rounded - 2 + 1 @@ -104,752 +104,280 @@ - - - - 0 - 0 - - + - Applications + Configurations - - - 6 + + + 5 - 6 + 5 - 6 + 5 - 6 + 0 - - - + + 0 + + + + 0 - - 0 + + Qt::Horizontal - - - - QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked - - - - - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 32 - 16777215 - - - - + - - - - - - - - 0 - 0 - - - - - 32 - 0 - - - - - 32 - 16777215 - - - - - - - - - .. - - - false - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 7 - - - 0 - - - - - Layers Mode: + + true + + + 5 + + + false + + + + 0 + + + Qt::Vertical + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + 1 + 0 + + + + + + + + 6 - - - - - - Arguments: + + 0 - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + 0 - - - - - + 0 - - - - - - - - 32 - 16777215 - - - - ... - - - - - - - - + 0 - - - - - - - 32 - 16777215 - + + + 0 - - ... + + 0 - - - - - - - - - - - - - - Output Log: - - - - - - - Env Variables: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - Working Dir: - - - - - - - 0 - - - - - - Layers Controlled by Vulkan Applications - + + + + + 0 + 0 + + + - - - Layers Controlled by Vulkan Configurator - + + + + + 0 + 0 + + + + Per-Application: + + - - - Layers Disabled by Vulkan Configurator - + + + + + 0 + 0 + + + + Layers Mode: + + - + + + + + 0 + 0 + + + + + Layers Controlled by Vulkan Applications + + + + + Layers Controlled by Vulkan Configurator + + + + + Layers Disabled by Vulkan Configurator + + + + + - + + + 0 + + + + + + Arial + 10 + + + + false + + + QFrame::Box + + + QFrame::Sunken + + + 0 + + + Qt::ScrollBarAlwaysOn + + + QAbstractItemView::NoEditTriggers + + + false + + + + - - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 32 - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - Arial - 10 - + + + + + + + false + + + + 0 + 0 + + + + + 0 - - Clear + + 0 - - - - - - - Arial - 10 - + + 0 - - Clear log at launch + + 0 - - true + + 0 - - - - - - - Arial - 10 - - - - Launch - - - - - - - - - - - 0 - 0 - - - - - Consolas - 9 - - - - 1 - - - - - - - - Layers - - - - 5 - - - 5 - - - 5 - - - 0 - - - - - - - 0 - - - 0 - - - 0 - - - - - - - - - 32 - 16777215 - - - - ... - - - - - - - - 32 - 16777215 - - - - + - - - - - - - - - - 0 - 0 - - - - Qt::ScrollBarAlwaysOn - - - true - - - false - - - - 1 - - - - - - - - - - - Configurations - - - - 5 - - - 5 - - - 5 - - - 0 - - - 0 - - - - - 0 - - - Qt::Horizontal - - - true - - - 5 - - - false - - - - 0 - - - Qt::Vertical - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - + + + + + 0 + 0 + + + + + Arial + 9 + true + + + true + + 0 + + + Execute Closer to the Vulkan Application + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + - - 1 + + 0 0 - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Per-Application: - - - - - - - - 0 - 0 - - - - Layers Mode: - - - - - - - - 0 - 0 - - - - - Layers Controlled by Vulkan Applications - - - - - Layers Controlled by Vulkan Configurator - - - - - Layers Disabled by Vulkan Configurator - - - - - - - - - - 0 - - - - - - Arial - 10 - - - - false - - - QFrame::Box - - - QFrame::Sunken - - - 0 - - - Qt::ScrollBarAlwaysOn - - - QAbstractItemView::NoEditTriggers - - - false - - - - - - - - - - - - - false - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - Arial - 9 - true - - - - true - - - 0 - - - Execute Closer to the Vulkan Application - - - Qt::AlignBottom|Qt::AlignHCenter - - - - - - - - 0 - 0 - - - - - Arial - 9 - true - + + + Arial + 9 + true + true @@ -1020,128 +548,600 @@ 0 - + + 0 + + + Qt::Vertical + + + + false + + + + 0 + 1 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 400 + 0 + + + + + + + false + + + false + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Arial + 10 + + + + QFrame::Box + + + QFrame::Plain + + + 0 + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContentsOnFirstShow + + + 0 + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + false + + + 1 + + + false + + + 160 + + + 200 + + + + + + + + + + + + + + + + + + + + + Layers + + + + 5 + + + 5 + + + 5 + + + 0 + + + + + + + 0 + + + 0 + + + 0 + + + + + + + + + 32 + 16777215 + + + + ... + + + + + + + + 32 + 16777215 + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + true + + + false + + + + 1 + + + + + + + + + + + + 0 + 0 + + + + Applications + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 0 + + + 0 + + + + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + + + + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 32 + 16777215 + + + + + + + + + + + + + 0 + 0 + + + + + 32 + 0 + + + + + 32 + 16777215 + + + + - + + + + .. + + + false + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 7 + + + 0 + + + + + Layers Mode: + + + + + + + Arguments: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + 0 + + + + + + + + + 32 + 16777215 + + + + ... + + + + + + + + + 0 + + + + + + + + + 32 + 16777215 + + + + ... + + + + + + + + + + + + + + + Output Log: + + + + + + + Env Variables: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Working Dir: + + + + + + + 0 + + + + + + Layers Controlled by Vulkan Applications + + + + + Layers Controlled by Vulkan Configurator + + + + + Layers Disabled by Vulkan Configurator + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 32 + + + + + + + + 0 + + 0 - - Qt::Vertical + + 0 - - - false - - - - 0 - 1 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - 400 - 0 - - - - - - - false - - - false - - - - 0 + + 0 + + + + + Qt::Horizontal - - 0 + + + 40 + 20 + - - 0 + + + + + + + Arial + 10 + - - 0 + + Clear - - 0 + + + + + + + Arial + 10 + - - - - - Arial - 10 - - - - QFrame::Box - - - QFrame::Plain - - - 0 - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - - - 0 - - - QAbstractItemView::NoEditTriggers - - - true - - - false - - - false - - - 1 - - - false - - - 160 - - - 200 - - - - - - - - - - - - - - + + Clear log at launch + + + true + + + + + + + + Arial + 10 + + + + Launch + + + + + + + + + + + 0 + 0 + + + + + Consolas + 9 + + + + 1 + diff --git a/vkconfig_gui/settings_tree.cpp b/vkconfig_gui/settings_tree.cpp index 72e43c4c68..f708a8608f 100644 --- a/vkconfig_gui/settings_tree.cpp +++ b/vkconfig_gui/settings_tree.cpp @@ -139,9 +139,14 @@ void SettingsTreeManager::CreateGUI(QComboBox *preset_combobox, QTreeWidget *bui layer_item->setExpanded(parameter.control == LAYER_CONTROL_ON); */ if (layer == nullptr) { + preset_combobox->setVisible(false); continue; } + if (layer->api_version != this->parameter->api_version) { + configuration->SwitchLayerVersion(configurator.layers, layer->key, layer->api_version); + } + preset_combobox->blockSignals(true); preset_combobox->clear(); preset_labels.clear(); @@ -163,9 +168,6 @@ void SettingsTreeManager::CreateGUI(QComboBox *preset_combobox, QTreeWidget *bui preset_labels.push_back(layer_preset.label); } - // QTreeWidgetItem *presets_item = new QTreeWidgetItem(); - // this->tree->addTopLevelItem(presets_item); - // WidgetPreset *presets_combobox = new WidgetPreset(this->tree, presets_item, *layer, parameter); this->connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPresetChanged(int))); preset_combobox->setVisible(true); } else { diff --git a/vkconfig_gui/settings_tree.h b/vkconfig_gui/settings_tree.h index 602d3beb61..0a23bd8a9c 100644 --- a/vkconfig_gui/settings_tree.h +++ b/vkconfig_gui/settings_tree.h @@ -23,11 +23,11 @@ #include "widget_setting_flags.h" #include "widget_setting_filesystem.h" -#include "widget_preset.h" #include "../vkconfig_core/configuration.h" #include +#include #include #include diff --git a/vkconfig_gui/tab_layers.cpp b/vkconfig_gui/tab_layers.cpp index 18e4552b14..da37364063 100644 --- a/vkconfig_gui/tab_layers.cpp +++ b/vkconfig_gui/tab_layers.cpp @@ -109,6 +109,7 @@ void TabLayers::on_layers_add_pushButton_pressed() { LayersPathInfo info; info.path = ui->layers_lineEdit->text().toStdString(); configurator.layers.AddPath(info); + configurator.layers.LoadLayersFromPath(info.path); this->UpdateUI_LayersPaths(UPDATE_REBUILD_UI); } @@ -118,13 +119,14 @@ void TabLayers::on_layers_browse_pushButton_pressed() { this->ui->layers_lineEdit->text()); if (!selected_path.isEmpty()) { - this->ui->layers_lineEdit->setText(selected_path); + this->ui->layers_lineEdit->setText(Path(selected_path.toStdString()).AbsolutePath().c_str()); LayersPathInfo info; info.path = selected_path.toStdString(); Configurator &configurator = Configurator::Get(); configurator.layers.AddPath(info); + configurator.layers.LoadLayersFromPath(info.path); this->UpdateUI_LayersPaths(UPDATE_REBUILD_UI); } diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index 576febeaa6..687b0fae62 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -78,7 +78,6 @@ SOURCES += \ widget_tab_configurations_layer.cpp \ widget_tab_layers_path.cpp \ widget_tree_friendly_combobox.cpp \ - widget_preset.cpp \ widget_setting.cpp \ widget_setting_bool.cpp \ widget_setting_enum.cpp \ @@ -155,7 +154,6 @@ HEADERS += \ widget_tab_configurations_layer.h \ widget_tab_layers_path.h \ widget_tree_friendly_combobox.h \ - widget_preset.h \ widget_setting.h \ widget_setting_bool.h \ widget_setting_enum.h \ diff --git a/vkconfig_gui/widget_preset.cpp b/vkconfig_gui/widget_preset.cpp deleted file mode 100644 index 3bf4bfdc23..0000000000 --- a/vkconfig_gui/widget_preset.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "widget_preset.h" - -#include - -WidgetPreset::WidgetPreset(QTreeWidget* tree, QTreeWidgetItem* item, const Layer& layer, Parameter& parameter) - : WidgetSettingBase(tree, item), layer(layer), parameter(parameter), field(new ComboBox(this)) { - this->field->setFocusPolicy(Qt::StrongFocus); - this->field->addItem(Layer::NO_PRESET); - - preset_labels.push_back(Layer::NO_PRESET); - - for (std::size_t i = 0, n = layer.presets.size(); i < n; ++i) { - const LayerPreset& layer_preset = layer.presets[i]; - - if (!IsPlatformSupported(layer_preset.platform_flags)) continue; - if (layer_preset.view == SETTING_VIEW_HIDDEN) continue; - - this->field->addItem((layer_preset.label + " Preset").c_str()); - preset_labels.push_back(layer_preset.label); - } - - // 'Refresh' need to be called before 'connect' to avoid triggering 'currentIndexChanged' in an infinite loop - this->Refresh(REFRESH_ENABLE_AND_STATE); - this->connect(this->field, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPresetChanged(int))); - - this->item->setSizeHint(0, QSize(0, ITEM_HEIGHT)); - this->tree->setItemWidget(this->item, 0, this); -} - -void WidgetPreset::Refresh(RefreshAreas refresh_areas) { - (void)refresh_areas; - - const std::string& preset_label = layer.FindPresetLabel(parameter.settings); - - this->field->blockSignals(true); - this->field->setCurrentIndex(GetComboBoxIndex(preset_label.c_str())); - this->field->blockSignals(false); - - if (preset_label != Layer::NO_PRESET) { - const LayerPreset* preset = GetPreset(layer.presets, preset_label.c_str()); - assert(preset != nullptr); - this->setToolTip(preset->description.c_str()); - } -} - -void WidgetPreset::resizeEvent(QResizeEvent* event) { - const QRect button_rect = QRect(0, 0, event->size().width(), event->size().height()); - this->field->setGeometry(button_rect); -} - -int WidgetPreset::GetComboBoxIndex(const char* preset_label) const { - for (std::size_t i = 0, n = preset_labels.size(); i < n; ++i) { - if (preset_labels[i] == preset_label) return static_cast(i); - } - - assert(0); - return -1; -} - -void WidgetPreset::OnPresetChanged(int combox_preset_index) { - assert(combox_preset_index >= 0 && static_cast(combox_preset_index) < preset_labels.size()); - const std::string& preset_label = preset_labels[combox_preset_index]; - - if (preset_label == Layer::NO_PRESET) return; - - const LayerPreset* preset = GetPreset(layer.presets, preset_label.c_str()); - assert(preset != nullptr); - parameter.ApplyPresetSettings(*preset); - - emit itemChanged(); -} diff --git a/vkconfig_gui/widget_preset.h b/vkconfig_gui/widget_preset.h deleted file mode 100644 index b7dcc5c6b3..0000000000 --- a/vkconfig_gui/widget_preset.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "../vkconfig_core/layer.h" -#include "../vkconfig_core/parameter.h" - -#include "widget_setting.h" -#include "combo_box.h" - -#include - -#include - -class WidgetPreset : public WidgetSettingBase { - Q_OBJECT - - public: - explicit WidgetPreset(QTreeWidget* tree, QTreeWidgetItem* item, const Layer& layer, Parameter& parameter); - - void Refresh(RefreshAreas refresh_areas) override; - - public Q_SLOTS: - void OnPresetChanged(int combox_preset_index); - - Q_SIGNALS: - void itemChanged(); - - protected: - void resizeEvent(QResizeEvent* event) override; - - private: - int GetComboBoxIndex(const char* preset_label) const; - - std::vector preset_labels; // The preset in the combobox - const Layer& layer; - Parameter& parameter; - ComboBox* field; -}; diff --git a/vkconfig_gui/widget_tab_configurations_layer.cpp b/vkconfig_gui/widget_tab_configurations_layer.cpp index ce42789dbd..150f312a78 100644 --- a/vkconfig_gui/widget_tab_configurations_layer.cpp +++ b/vkconfig_gui/widget_tab_configurations_layer.cpp @@ -102,10 +102,11 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const const Layer *layer = configurator.layers.Find(parameter.key, parameter.api_version); if (parameter.control != LAYER_CONTROL_APPLICATIONS_API && parameter.control != LAYER_CONTROL_APPLICATIONS_ENV) { - assert(layer != nullptr); + this->setEnabled(layer != nullptr); this->layer_version = new QComboBox(this); this->layer_version->setVisible(advanced_view); + this->layer_version->setEnabled(layer != nullptr); this->layer_version->addItem("Latest"); int version_index = 0; @@ -113,7 +114,9 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const if (layer_versions[i] == parameter.api_version) { version_index = this->layer_version->count(); - this->layer_version->setToolTip(layer->manifest_path.AbsolutePath().c_str()); + if (layer != nullptr) { + this->layer_version->setToolTip(layer->manifest_path.AbsolutePath().c_str()); + } } this->layer_version->addItem(layer_versions[i].str().c_str()); @@ -130,6 +133,7 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const } this->layer_state->setEnabled(!layer_versions.empty()); this->layer_state->setCurrentIndex(parameter.control); + this->layer_state->setEnabled(layer != nullptr); this->connect(this->layer_state, SIGNAL(currentIndexChanged(int)), this, SLOT(on_layer_state_currentIndexChanged(int))); // this->layer_state->installEventFilter(this); } From 31434566c108695323e26cd787ff453dd282ed49 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Fri, 13 Sep 2024 12:59:47 -0500 Subject: [PATCH 24/33] Replace "implem" with "driver" loader log level Matches the Vulkan-Loader's own log levels. --- vkconfig_core/type_log.cpp | 2 +- vkconfig_core/type_log.h | 4 ++-- vkconfig_gui/tab_configurations.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vkconfig_core/type_log.cpp b/vkconfig_core/type_log.cpp index 99020c10e7..40dc2d9a41 100644 --- a/vkconfig_core/type_log.cpp +++ b/vkconfig_core/type_log.cpp @@ -33,7 +33,7 @@ const char* GetToken(LogType value) { "debug", // LOG_DEBUG "perf", // LOG_PERF "layer", // LOG_LAYER - "implem", // LOG_IMPLEM + "driver", // LOG_DRIVER }; static_assert(std::size(TOKENS) == LOG_COUNT); diff --git a/vkconfig_core/type_log.h b/vkconfig_core/type_log.h index ec413d0d6e..76da1d9868 100644 --- a/vkconfig_core/type_log.h +++ b/vkconfig_core/type_log.h @@ -31,10 +31,10 @@ enum LogType { LOG_DEBUG, LOG_PERF, LOG_LAYER, - LOG_IMPLEM, + LOG_DRIVER, LOG_FIRST = LOG_ERROR, - LOG_LAST = LOG_IMPLEM, + LOG_LAST = LOG_DRIVER, LOG_MESSAGE_INVALID = ~0, }; diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index 5ef56d0b73..6b6bd5a9e4 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -193,7 +193,7 @@ void TabConfigurations::UpdateUI_LoaderMessages() { ui->configuration_loader_layers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_LAYER)); ui->configuration_loader_layers_checkBox->blockSignals(false); ui->configuration_loader_drivers_checkBox->blockSignals(true); - ui->configuration_loader_drivers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_IMPLEM)); + ui->configuration_loader_drivers_checkBox->setChecked(configuration->loader_log_messages_flags & GetBit(LOG_DRIVER)); ui->configuration_loader_drivers_checkBox->blockSignals(false); } } @@ -572,7 +572,7 @@ void TabConfigurations::OnCheckedLoaderMessageTypes(bool checked) { loader_log_messages_bits |= ui->configuration_loader_infos_checkBox->isChecked() ? GetBit(LOG_INFO) : 0; loader_log_messages_bits |= ui->configuration_loader_debug_checkBox->isChecked() ? GetBit(LOG_DEBUG) : 0; loader_log_messages_bits |= ui->configuration_loader_layers_checkBox->isChecked() ? GetBit(LOG_LAYER) : 0; - loader_log_messages_bits |= ui->configuration_loader_drivers_checkBox->isChecked() ? GetBit(LOG_IMPLEM) : 0; + loader_log_messages_bits |= ui->configuration_loader_drivers_checkBox->isChecked() ? GetBit(LOG_DRIVER) : 0; active_configuration->loader_log_messages_flags = loader_log_messages_bits; } From fc6273cdec200baff48f0ad2626d907d43ba89ea Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 11 Sep 2024 18:16:53 +0200 Subject: [PATCH 25/33] vkconfig3: Add applications tab Change-Id: I9d4ac74f169edcea2df10bb932ff078aab4760b7 --- vkconfig_gui/mainwindow.ui | 252 ++++++++++++++++++++++++++----------- 1 file changed, 182 insertions(+), 70 deletions(-) diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index e6e9aa9ed7..c0f9aa71a6 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -72,7 +72,7 @@ QTabWidget::Rounded - 1 + 3 @@ -794,21 +794,123 @@ 0 - - - - QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked - - - + + 0 + 0 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 32 + 16777215 + + + + + + + + + + + + + 32 + 16777215 + + + + - + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Executable Path: + + + + + + + + + + + 32 + 16777215 + + + + ... + + + + + + + @@ -909,14 +1011,31 @@ 0 - + + + + Label: + + + + + + + Env Variables: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + Layers Mode: - + Arguments: @@ -926,7 +1045,56 @@ - + + + + + + + Output Log: + + + + + + + + + + Working Dir: + + + + + + + 0 + + + + + + Layers Controlled by Vulkan Applications + + + + + Layers Controlled by Vulkan Configurator + + + + + Layers Disabled by Vulkan Configurator + + + + + + + + + + 0 @@ -949,7 +1117,7 @@ - + 0 @@ -972,64 +1140,8 @@ - - - - - - - - - - Output Log: - - - - - - - Env Variables: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - Working Dir: - - - - - - - 0 - - - - - - Layers Controlled by Vulkan Applications - - - - - Layers Controlled by Vulkan Configurator - - - - - Layers Disabled by Vulkan Configurator - - - - - - - - + + From a27fd578809651de0d3776e58c88cebb77c656ad Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 12 Sep 2024 18:41:15 +0200 Subject: [PATCH 26/33] vkconfig3: Add applications tab --- vkconfig_core/application.cpp | 36 -- vkconfig_core/application.h | 45 -- vkconfig_core/application_manager.cpp | 21 - vkconfig_core/application_manager.h | 26 -- vkconfig_core/configuration_manager.cpp | 39 +- vkconfig_core/configuration_manager.h | 12 +- vkconfig_core/configurator.cpp | 19 +- vkconfig_core/configurator.h | 5 +- vkconfig_core/environment.cpp | 369 +-------------- vkconfig_core/environment.h | 45 +- vkconfig_core/executable_manager.cpp | 425 ++++++++++++++++++ vkconfig_core/executable_manager.h | 97 ++++ vkconfig_core/layer_manager.cpp | 4 - vkconfig_core/layer_manager.h | 3 - vkconfig_core/registry.cpp | 2 - vkconfig_core/test/CMakeLists.txt | 2 +- vkconfig_core/test/test_environment.cpp | 89 ---- .../test/test_executable_manager.cpp | 87 ++++ vkconfig_gui/dialog_vulkan_analysis.cpp | 1 - vkconfig_gui/dialog_vulkan_info.cpp | 1 - vkconfig_gui/mainwindow.cpp | 49 +- vkconfig_gui/mainwindow.ui | 316 +++++++------ vkconfig_gui/tab_applications.cpp | 365 ++++++--------- vkconfig_gui/tab_applications.h | 12 + vkconfig_gui/tab_configurations.cpp | 31 +- vkconfig_gui/vkconfig.pro | 6 +- 26 files changed, 1007 insertions(+), 1100 deletions(-) delete mode 100644 vkconfig_core/application.cpp delete mode 100644 vkconfig_core/application.h delete mode 100644 vkconfig_core/application_manager.cpp delete mode 100644 vkconfig_core/application_manager.h create mode 100644 vkconfig_core/executable_manager.cpp create mode 100644 vkconfig_core/executable_manager.h delete mode 100644 vkconfig_core/test/test_environment.cpp create mode 100644 vkconfig_core/test/test_executable_manager.cpp diff --git a/vkconfig_core/application.cpp b/vkconfig_core/application.cpp deleted file mode 100644 index 3122339e57..0000000000 --- a/vkconfig_core/application.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "application.h" - -#include -#include -/* -Application::Application(const std::string& name, const std::string& executable_full_path, const std::string& arguments) - : app_name(name), - executable_path(executable_full_path), - working_folder(QFileInfo(executable_full_path.c_str()).path().toStdString()), - arguments(arguments), - log_file((QString(GetPath(BUILTIN_PATH_LOCAL).c_str()) + GetNativeSeparator() + - QFileInfo(executable_full_path.c_str()).baseName() + ".txt") - .toStdString() - .c_str()), - layers_mode(LAYERS_MODE_BY_CONFIGURATOR_RUNNING) {} -*/ diff --git a/vkconfig_core/application.h b/vkconfig_core/application.h deleted file mode 100644 index e230db59ff..0000000000 --- a/vkconfig_core/application.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -#include "type_layers_mode.h" -#include "path.h" - -#include -#include - -struct ApplicationOptions { - std::string label; - Path working_folder; - std::vector arguments; - std::vector environment_variables; - Path log_file; -}; - -struct Application { - Path executable_path; - int active_option_index = 0; - std::vector options; - - ApplicationOptions& GetActiveOptions() { return this->options[active_option_index]; } - - const ApplicationOptions& GetActiveOptions() const { return this->options[active_option_index]; } -}; diff --git a/vkconfig_core/application_manager.cpp b/vkconfig_core/application_manager.cpp deleted file mode 100644 index 974198f104..0000000000 --- a/vkconfig_core/application_manager.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#include "application_manager.h" diff --git a/vkconfig_core/application_manager.h b/vkconfig_core/application_manager.h deleted file mode 100644 index 8264ae2b2a..0000000000 --- a/vkconfig_core/application_manager.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Christophe Riccio - */ - -#pragma once - -class ApplicationManager { - public: - private: -}; diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index 5125f5d335..d7365e096b 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -36,9 +36,9 @@ bool ConfigurationManager::Load(const QJsonObject &json_root_object) { // configurations json object if (json_root_object.value("configurations") != QJsonValue::Undefined) { const QJsonObject &json_configurations_object = json_root_object.value("configurations").toObject(); - this->use_per_application_configuration = json_configurations_object.value("use_per_application").toBool(); + this->use_per_executable_configuration = json_configurations_object.value("use_per_executable").toBool(); this->use_system_tray = json_configurations_object.value("use_system_tray").toBool(); - this->active_application = json_configurations_object.value("active_application").toString().toStdString(); + this->active_executable = json_configurations_object.value("active_application").toString().toStdString(); if (json_configurations_object.value("infos") != QJsonValue::Undefined) { this->configuration_infos.clear(); @@ -90,9 +90,9 @@ bool ConfigurationManager::Save(QJsonObject &json_root_object) const { } QJsonObject json_configurations_object; - json_configurations_object.insert("use_per_application", this->use_per_application_configuration); + json_configurations_object.insert("use_per_executable", this->use_per_executable_configuration); json_configurations_object.insert("use_system_tray", this->use_system_tray); - json_configurations_object.insert("active_application", this->active_application.c_str()); + json_configurations_object.insert("active_executable", this->active_executable.c_str()); json_configurations_object.insert("infos", json_infos_object); json_configurations_object.insert("removed_builtin", json_removed_builtin_configurations_object); @@ -103,9 +103,9 @@ bool ConfigurationManager::Save(QJsonObject &json_root_object) const { void ConfigurationManager::Reset() { this->removed_built_in_configuration.clear(); - this->use_per_application_configuration = false; + this->use_per_executable_configuration = false; this->use_system_tray = false; - this->active_application.clear(); + this->active_executable.clear(); this->configuration_infos.clear(); this->available_configurations.clear(); @@ -212,16 +212,16 @@ void ConfigurationManager::SaveAllConfigurations() const { } const ConfigurationInfo *ConfigurationManager::GetActiveConfigurationInfo() const { - if (this->use_per_application_configuration) { - return &this->configuration_infos.find(this->active_application.c_str())->second; + if (this->use_per_executable_configuration) { + return &this->configuration_infos.find(this->active_executable.c_str())->second; } else { return &this->configuration_infos.find(GLOBAL_CONFIGURATION_TOKEN)->second; } } ConfigurationInfo *ConfigurationManager::GetActiveConfigurationInfo() { - if (this->use_per_application_configuration) { - return &this->configuration_infos.find(this->active_application.c_str())->second; + if (this->use_per_executable_configuration) { + return &this->configuration_infos.find(this->active_executable.c_str())->second; } else { return &this->configuration_infos.find(GLOBAL_CONFIGURATION_TOKEN)->second; } @@ -339,6 +339,17 @@ void ConfigurationManager::RemoveConfiguration(const std::string &configuration_ } } +int ConfigurationManager::GetConfigurationIndex(const std::string &configuration_name) const { + for (std::size_t i = 0, n = this->available_configurations.size(); i < n; ++i) { + if (this->available_configurations[i].key == configuration_name) { + return static_cast(i); + } + } + + assert(0); + return -1; +} + Configuration *ConfigurationManager::FindConfiguration(const std::string &configuration_name) { if (configuration_name.empty()) { return nullptr; @@ -382,6 +393,8 @@ const Configuration *ConfigurationManager::FindConfiguration(const std::string & void ConfigurationManager::ImportConfiguration(const LayerManager &layers, const Path &full_import_path) { assert(!full_import_path.Empty()); + this->last_path_import = full_import_path; + Configuration configuration; if (!configuration.Load(full_import_path, layers)) { QMessageBox msg; @@ -405,6 +418,8 @@ void ConfigurationManager::ExportConfiguration(const LayerManager &layers, const assert(!configuration_name.empty()); assert(!full_export_path.Empty()); + this->last_path_export = full_export_path; + Configuration *configuration = this->FindConfiguration(configuration_name); assert(configuration); @@ -466,9 +481,9 @@ bool ConfigurationManager::CompareLayersVersions(const std::vector &avail return result; } -bool ConfigurationManager::GetPerApplicationConfig() const { return this->use_per_application_configuration; } +bool ConfigurationManager::GetPerExecutableConfig() const { return this->use_per_executable_configuration; } -void ConfigurationManager::SetPerApplicationConfig(bool enabled) { this->use_per_application_configuration = enabled; } +void ConfigurationManager::SetPerExecutableConfig(bool enabled) { this->use_per_executable_configuration = enabled; } bool ConfigurationManager::GetUseSystemTray() const { return this->use_system_tray; } diff --git a/vkconfig_core/configuration_manager.h b/vkconfig_core/configuration_manager.h index fdf54bbc49..b154315aa6 100644 --- a/vkconfig_core/configuration_manager.h +++ b/vkconfig_core/configuration_manager.h @@ -49,8 +49,8 @@ class ConfigurationManager : public Serialize { bool HasActiveConfiguration() const; Configuration& CreateConfiguration(const LayerManager& layers, const std::string& configuration_name, bool duplicate = false); - void RemoveConfiguration(const std::string& configuration_name); + int GetConfigurationIndex(const std::string& configuration_name) const; void ImportConfiguration(const LayerManager& layers, const Path& full_import_path); void ExportConfiguration(const LayerManager& layers, const Path& full_export_path, const std::string& configuration_name); @@ -70,13 +70,15 @@ class ConfigurationManager : public Serialize { bool HasFile(const Configuration& configuration) const; void RemoveConfigurationFile(const std::string& key); - bool GetPerApplicationConfig() const; - void SetPerApplicationConfig(bool enabled); + bool GetPerExecutableConfig() const; + void SetPerExecutableConfig(bool enabled); bool GetUseSystemTray() const; void SetUseSystemTray(bool enabled); std::vector available_configurations; + Path last_path_import; + Path last_path_export; private: bool CompareLayersVersions(const std::vector& available_layers, Configuration* selected_configuration, @@ -89,7 +91,7 @@ class ConfigurationManager : public Serialize { std::map removed_built_in_configuration; bool use_system_tray = false; - bool use_per_application_configuration = false; - std::string active_application; + bool use_per_executable_configuration = false; + std::string active_executable; std::map configuration_infos; }; diff --git a/vkconfig_core/configurator.cpp b/vkconfig_core/configurator.cpp index 844b9f255f..bef4751aaa 100644 --- a/vkconfig_core/configurator.cpp +++ b/vkconfig_core/configurator.cpp @@ -50,6 +50,7 @@ Configurator::~Configurator() { this->environment.Save(json_root_object); this->configurations.Save(json_root_object); this->layers.Save(json_root_object); + this->executables.Save(json_root_object); QJsonDocument json_doc(json_root_object); @@ -98,9 +99,11 @@ bool Configurator::Init(Mode mode) { this->Surrender(OVERRIDE_AREA_LOADER_SETTINGS_BIT); this->environment.Reset(); + this->executables.Reset(); this->layers.Reset(); this->configurations.Reset(); } else { + this->executables.Load(json_root_object); this->layers.Load(json_root_object); this->configurations.Load(json_root_object); } @@ -108,6 +111,7 @@ bool Configurator::Init(Mode mode) { this->Override(OVERRIDE_AREA_ALL); } else { this->environment.Reset(); + this->executables.Reset(); this->layers.Reset(); this->configurations.Reset(); } @@ -215,7 +219,7 @@ bool Configurator::WriteLoaderSettings(OverrideArea override_area, const Path& l const std::map& infos = this->configurations.GetConfigurationInfos(); for (auto it = infos.begin(), end = infos.end(); it != end; ++it) { - if (this->configurations.GetPerApplicationConfig()) { + if (this->configurations.GetPerExecutableConfig()) { if (it->first == GLOBAL_CONFIGURATION_TOKEN) { continue; } @@ -264,15 +268,14 @@ bool Configurator::WriteLayersSettings(OverrideArea override_area, const Path& l if (override_area & OVERRIDE_AREA_LAYERS_SETTINGS_BIT) { std::vector layers_settings_array; - if (this->configurations.GetPerApplicationConfig()) { - const std::vector& applications = this->environment.GetApplications(); + if (this->configurations.GetPerExecutableConfig()) { + const std::vector& executables = this->executables.GetExecutables(); - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { + for (std::size_t i = 0, n = executables.size(); i < n; ++i) { LayersSettings settings; - settings.configuration_name = - this->configurations.FindConfigurationInfo(applications[i].executable_path.AbsolutePath())->name; - settings.executable_path = applications[i].executable_path; - settings.settings_path = applications[i].GetActiveOptions().working_folder; + settings.configuration_name = this->configurations.FindConfigurationInfo(executables[i].path.AbsolutePath())->name; + settings.executable_path = executables[i].path; + settings.settings_path = executables[i].GetActiveOptions()->working_folder; layers_settings_array.push_back(settings); } } else { diff --git a/vkconfig_core/configurator.h b/vkconfig_core/configurator.h index 65dfef3e73..8ce2369c67 100644 --- a/vkconfig_core/configurator.h +++ b/vkconfig_core/configurator.h @@ -22,10 +22,10 @@ #pragma once #include "../vkconfig_core/version.h" -#include "../vkconfig_core/layer.h" +#include "../vkconfig_core/configuration_manager.h" #include "../vkconfig_core/layer_manager.h" +#include "../vkconfig_core/executable_manager.h" #include "../vkconfig_core/environment.h" -#include "../vkconfig_core/configuration_manager.h" #include "../vkconfig_core/type_platform.h" #include "../vkconfig_core/type_override_area.h" #include "../vkconfig_core/vulkan_info.h" @@ -85,5 +85,6 @@ class Configurator { Environment environment; LayerManager layers; ConfigurationManager configurations; + ExecutableManager executables; VulkanSystemInfo vulkan_system_info; }; diff --git a/vkconfig_core/environment.cpp b/vkconfig_core/environment.cpp index f0c4b9d9dd..1fd49d390c 100644 --- a/vkconfig_core/environment.cpp +++ b/vkconfig_core/environment.cpp @@ -34,34 +34,15 @@ #include #include #include -#include #include #include -static const char* GetApplicationSuffix() { - static const char* TABLE[] = { - ".exe", // PLATFORM_WINDOWS_X86 - ".exe", // PLATFORM_WINDOWS_ARM - "", // PLATFORM_LINUX - ".app", // PLATFORM_MACOS - "N/A", // PLATFORM_ANDROID - "N/A" // PLATFORM_IOS - }; - static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); - - return TABLE[VKC_PLATFORM]; -} - Environment::Environment() {} Environment::~Environment() {} -void Environment::Reset() { - this->loader_message_types_flags = ::GetLogFlags(qgetenv("VK_LOADER_DEBUG").toStdString()); - this->active_executable_index = 0; - this->applications = CreateDefaultApplications(); -} +void Environment::Reset() { this->loader_message_types_flags = ::GetLogFlags(qgetenv("VK_LOADER_DEBUG").toStdString()); } std::string GetPath() { static const char* TABLE[] = { @@ -94,50 +75,6 @@ bool Environment::Load(const QJsonObject& json_root_object) { this->loader_message_types_flags |= GetLogBit(token.c_str()); } - // applications json object - const QJsonObject& json_applications_object = json_root_object.value("applications").toObject(); - - this->active_executable_index = json_applications_object.value("active_executable_index").toInt(); - - const QJsonObject& json_list_object = json_applications_object.value("list").toObject(); - - const QStringList& json_list_keys = json_list_object.keys(); - - this->applications.clear(); - for (int i = 0, n = json_list_keys.length(); i < n; ++i) { - Application application; - - const QJsonObject& json_application_object = json_list_object.value(json_list_keys[i]).toObject(); - application.executable_path = json_list_keys[i].toStdString(); - application.active_option_index = json_application_object.value("active_option_index").toInt(); - - const QJsonArray& json_options_array = json_application_object.value("options").toArray(); - for (int j = 0, o = json_options_array.size(); j < o; ++j) { - const QJsonObject& json_options_object = json_options_array[j].toObject(); - - ApplicationOptions application_options; - - application_options.label = json_options_object.value("label").toString().toStdString(); - application_options.working_folder = json_options_object.value("working_folder").toString().toStdString(); - - const QJsonArray& json_command_lines_array = json_options_object.value("arguments").toArray(); - for (int k = 0, p = json_command_lines_array.size(); k < p; ++k) { - application_options.arguments.push_back(json_command_lines_array[k].toString().toStdString()); - } - - const QJsonArray& json_environment_variables_array = json_options_object.value("environment_variables").toArray(); - for (int k = 0, p = json_environment_variables_array.size(); k < p; ++k) { - application_options.environment_variables.push_back(json_environment_variables_array[k].toString().toStdString()); - } - - application_options.log_file = json_options_array[j].toObject().value("log_file").toString().toStdString(); - - application.options.push_back(application_options); - } - - this->applications.push_back(application); - } - // preferences json object const QJsonObject& json_preferences_object = json_root_object.value("preferences").toObject(); this->home_sdk_path = json_preferences_object.value("VK_HOME").toString().toStdString(); @@ -152,10 +89,6 @@ bool Environment::Load(const QJsonObject& json_root_object) { this->hide_message_boxes_flags |= GetLogBit(token.c_str()); } - if (this->applications.empty()) { - this->applications = CreateDefaultApplications(); - } - return true; } @@ -180,48 +113,6 @@ bool Environment::Save(QJsonObject& json_root_object) const { json_root_object.insert("diagnostic", json_diagnostic_object); - QJsonObject json_applications_object; - json_applications_object.insert("active_executable", this->active_executable_index); - QJsonObject json_applications_list_object; - - for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { - const Application& application = this->applications[i]; - - QJsonObject json_application_object; - json_application_object.insert("active_option", application.active_option_index); - - QJsonArray json_options_array; - for (std::size_t j = 0, o = application.options.size(); j < o; ++j) { - const ApplicationOptions& options = application.options[j]; - - QJsonArray json_arg_array; - for (std::size_t k = 0, p = options.arguments.size(); k < p; ++k) { - json_arg_array.append(options.arguments[k].c_str()); - } - - QJsonArray json_env_array; - for (std::size_t k = 0, p = options.environment_variables.size(); k < p; ++k) { - json_env_array.append(options.environment_variables[k].c_str()); - } - - QJsonObject json_option_object; - json_option_object.insert("label", options.label.c_str()); - json_option_object.insert("working_folder", options.working_folder.RelativePath().c_str()); - json_option_object.insert("arguments", json_arg_array); - json_option_object.insert("environment_variables", json_env_array); - json_option_object.insert("log_file", options.log_file.RelativePath().c_str()); - - json_options_array.append(json_option_object); - } - json_application_object.insert("options", json_options_array); - - json_applications_list_object.insert(application.executable_path.RelativePath().c_str(), json_application_object); - } - - json_applications_object.insert("list", json_applications_list_object); - - json_root_object.insert("applications", json_applications_object); - QJsonObject json_preferences_object; json_preferences_object.insert("VK_HOME", this->home_sdk_path.RelativePath().c_str()); @@ -238,261 +129,3 @@ bool Environment::Save(QJsonObject& json_root_object) const { return true; } - -void Environment::SelectActiveApplication(std::size_t application_index) { - assert(application_index < this->applications.size()); - this->active_executable_index = application_index; -} - -int Environment::GetActiveApplicationIndex() const { - return this->active_executable_index; // Not found, but the list is present, so return the first item. -} - -bool Environment::AppendApplication(const Application& application) { - this->applications.push_back(application); - return true; -} - -bool Environment::RemoveApplication(std::size_t application_index) { - assert(!this->applications.empty()); - assert(application_index < this->applications.size()); - - if (this->applications.size() == 1u) { - this->applications.clear(); - return true; - } - - std::vector new_applications; - new_applications.reserve(this->applications.size() - 1); - - for (std::size_t i = 0, n = this->applications.size(); i < n; ++i) { - if (i == application_index) { - continue; - } - new_applications.push_back(this->applications[i]); - } - - std::swap(this->applications, new_applications); - return true; -} - -const Application& Environment::GetActiveApplication() const { - assert(!this->applications.empty()); - - return this->applications[this->active_executable_index]; // Not found, but the list is present, so return the first item. -} - -Application& Environment::GetActiveApplication() { - assert(!this->applications.empty()); - - return this->applications[this->active_executable_index]; // Not found, but the list is present, so return the first item. -} - -const Application& Environment::GetApplication(std::size_t application_index) const { - assert(application_index < this->applications.size()); - - return this->applications[application_index]; -} - -Application& Environment::GetApplication(std::size_t application_index) { - assert(application_index < this->applications.size()); - - return this->applications[application_index]; -} - -/////////////////////////////////////////////////////////////////////////// -/// This is only used on macOS to extract the executable from the bundle. -/// You have to look at the plist.info file, you can't just assume whatever -/// you find in the /MacOS folder is the executable. -/// The initial path is the folder where info.plist resides, and the -/// path is completed to the executable upon completion. -/// Note, not ALL macOS executables are in a bundle, so if a non-bundled -/// executable is fed in here, it will silently just return without -/// modifying the path (which will be the correct behavior) -bool ExactExecutableFromAppBundle(Path& app_path) { - std::string path = app_path.AbsolutePath(); - path += "/Contents/"; - std::string list_file = path + "Info.plist"; - QFile file(list_file.c_str()); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return false; - } - - QTextStream stream(&file); - - // Read a line at a time looking for the executable tag - QString line_buffer; - while (!stream.atEnd()) { - line_buffer = stream.readLine(); - if (line_buffer.contains("CFBundleExecutable")) { // Exe follows this - line_buffer = stream.readLine(); // Qt Creator - char* cExeName = new char[line_buffer.length()]; // Prevent buffer overrun - - QByteArray line_array = line_buffer.toUtf8(); - const char* pStart = strstr(line_array.constData(), ""); - if (pStart == nullptr) return false; - - // We found it, now extract it out - pStart += 8; - int iIndex = 0; - while (*pStart != '<') { - cExeName[iIndex++] = *pStart++; - } - cExeName[iIndex] = '\0'; - - // Complete the partial path - path += "MacOS/"; - path += cExeName; - - // Return original if not found, but root if found - app_path = Path(path); - - delete[] cExeName; - break; - } - } - - file.close(); - - return true; -} - -DefaultPath Environment::GetDefaultExecutablePath(const std::string& executable_name) const { - static const char* DEFAULT_PATH = VKC_PLATFORM == PLATFORM_MACOS ? "/../.." : ""; - - DefaultPath default_path{"." + executable_name, "."}; - - // Using VULKAN_SDK environement variable - const Path env = ::Get(Path::SDK_BIN); - if (!env.Empty()) { - const Path search_path(env + DEFAULT_PATH + executable_name.c_str()); - if (search_path.Exists()) { - default_path.executable_path = Path(search_path.AbsolutePath(), true); - default_path.working_folder = Path(search_path.AbsoluteDir(), true); - return default_path; - } - } - - // Search the default applications from package installation (Linux) - if (VKC_PLATFORM == PLATFORM_LINUX) { - const Path search_path(std::string("/usr/bin") + DEFAULT_PATH + executable_name); - if (search_path.Exists()) { - default_path.executable_path = Path(search_path.AbsolutePath(), true); - default_path.working_folder = Path(search_path.AbsoluteDir(), true); - return default_path; - } - } else if (VKC_PLATFORM == PLATFORM_MACOS) { - Path search_path(std::string("/Applications") + executable_name); - if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { - default_path.executable_path = Path(search_path.AbsolutePath(), true); - default_path.working_folder = Path(search_path.AbsoluteDir(), true); - return default_path; - } - } - - // Using relative path to vkconfig in case SDK is not "installed" - if (VKC_PLATFORM == PLATFORM_MACOS) { - Path search_path(std::string("..") + DEFAULT_PATH + executable_name); - if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { - default_path.executable_path = Path(search_path.AbsolutePath(), true); - default_path.working_folder = Path(search_path.AbsoluteDir(), true); - return default_path; - } - } else { - Path search_path(std::string(".") + DEFAULT_PATH + executable_name); - if (search_path.Exists()) { - default_path.executable_path = Path(search_path.AbsolutePath(), true); - default_path.working_folder = Path(search_path.AbsoluteDir(), true); - return default_path; - } - } - - return default_path; -} - -static const DefaultApplication defaults_applications[] = {{"vkcube", "/vkcube", "--suppress_popups"}, - {"vkcubepp", "/vkcubepp", "--suppress_popups"}}; - -Application Environment::CreateDefaultApplication(const DefaultApplication& default_application) const { - const DefaultPath& default_paths = GetDefaultExecutablePath((default_application.key + GetApplicationSuffix()).c_str()); - if (default_paths.executable_path.Empty()) { - Application(); // application could not be found.. - } - - ApplicationOptions options; - options.label = "Default"; - options.working_folder = default_paths.working_folder; - // On all operating systems, but Windows we keep running into problems with this ending up - // somewhere the user isn't allowed to create and write files. For consistncy sake, the log - // initially will be set to the users home folder across all OS's. This is highly visible - // in the application launcher and should not present a usability issue. The developer can - // easily change this later to anywhere they like. - options.log_file = std::string("${VK_LOCAL}") + default_application.key + ".txt"; - - Application application; - application.executable_path = Path(default_paths.executable_path.AbsolutePath(), true); - application.options.push_back(options); - application.active_option_index = 0; - - return application; -} - -std::vector Environment::CreateDefaultApplications() const { - std::vector new_applications; - - for (std::size_t name_index = 0, name_count = std::size(defaults_applications); name_index < name_count; ++name_index) { - const Application& application = CreateDefaultApplication(defaults_applications[name_index]); - - if (application.executable_path.Empty()) { - continue; - } - - new_applications.push_back(application); - } - - return new_applications; -} - -std::vector Environment::RemoveMissingApplications(const std::vector& applications) const { - std::vector valid_applications; - - // Remove applications that can't be found - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - const Application& application = applications[i]; - - const QFileInfo file_info(application.executable_path.AbsolutePath().c_str()); - if (!file_info.exists()) { - continue; - } - - valid_applications.push_back(application); - } - - return valid_applications; -} - -std::vector Environment::UpdateDefaultApplications(const std::vector& applications) const { - std::vector search_applications; - std::vector updated_applications = applications; - - for (std::size_t default_index = 0, default_count = std::size(defaults_applications); default_index < default_count; - ++default_index) { - const std::string defaults_name = defaults_applications[default_index].key + GetApplicationSuffix(); - - std::swap(updated_applications, search_applications); - updated_applications.clear(); - - for (std::size_t application_index = 0, application_count = search_applications.size(); - application_index < application_count; ++application_index) { - const Application& application = search_applications[application_index]; - - if (QString(application.executable_path.AbsolutePath().c_str()).endsWith(defaults_name.c_str())) { - updated_applications.push_back(CreateDefaultApplication(defaults_applications[default_index])); - } else { - updated_applications.push_back(application); - } - } - } - - return updated_applications; -} diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index 730e49f0e1..2bdbb6d39c 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -21,9 +21,9 @@ #pragma once #include "version.h" -#include "application.h" #include "type_tab.h" #include "type_log.h" +#include "path.h" #include "serialization.h" #include @@ -32,17 +32,6 @@ #include #include -struct DefaultApplication { - std::string name; - std::string key; - std::string arguments; -}; - -struct DefaultPath { - Path executable_path; - Path working_folder; -}; - class Environment : public Serialize { public: Environment(); @@ -52,31 +41,12 @@ class Environment : public Serialize { bool Save(QJsonObject& json_root_object) const override; void Reset() override; - void SelectActiveApplication(std::size_t application_index); - int GetActiveApplicationIndex() const; - bool AppendApplication(const Application& application); - bool RemoveApplication(std::size_t application_index); - - const std::vector& GetApplications() const { return applications; } - const Application& GetActiveApplication() const; - Application& GetActiveApplication(); - const Application& GetApplication(std::size_t application_index) const; - Application& GetApplication(std::size_t application_index); - LogFlags GetLoaderMessageFlags() const { return this->loader_message_types_flags; } void SetLoaderMessageFlags(LogFlags flags) { this->loader_message_types_flags = flags; } - // Search for all the applications in the list, an remove the application which executable can't be found - std::vector RemoveMissingApplications(const std::vector& applications) const; - bool has_crashed = false; int hide_message_boxes_flags = 0; - Path path_export; - Path path_import; - - bool launcher_clear_on_launch = true; - private: Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; @@ -84,17 +54,4 @@ class Environment : public Serialize { TabType active_tab = TAB_DIAGNOSTIC; LogFlags loader_message_types_flags; Path home_sdk_path; - - int active_executable_index; - std::vector applications; - - // Update default applications path to use relative path (really useful only on Windows) - std::vector UpdateDefaultApplications(const std::vector& applications) const; - - // Create a list of default applications, eg vkcube - std::vector CreateDefaultApplications() const; - Application CreateDefaultApplication(const DefaultApplication& default_application) const; - DefaultPath GetDefaultExecutablePath(const std::string& executable_name) const; }; - -bool ExactExecutableFromAppBundle(Path& path); diff --git a/vkconfig_core/executable_manager.cpp b/vkconfig_core/executable_manager.cpp new file mode 100644 index 0000000000..03858838a9 --- /dev/null +++ b/vkconfig_core/executable_manager.cpp @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "executable_manager.h" +#include "version.h" +#include "type_platform.h" + +#include +#include + +static const char* GetExecutableSuffix() { + static const char* TABLE[] = { + ".exe", // PLATFORM_WINDOWS_X86 + ".exe", // PLATFORM_WINDOWS_ARM + "", // PLATFORM_LINUX + ".app", // PLATFORM_MACOS + "N/A", // PLATFORM_ANDROID + "N/A" // PLATFORM_IOS + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + return TABLE[VKC_PLATFORM]; +} + +static const DefaultExecutable defaults_executables[] = {{"vkcube", "/vkcube", "--suppress_popups"}, + {"vkcubepp", "/vkcubepp", "--suppress_popups"}}; + +void ExecutableManager::Reset() { + this->active_executable.Clear(); + this->data = this->CreateDefaultExecutables(); + this->active_executable = "vkcube"; +} + +void ExecutableManager::Clear() { + this->data.clear(); + this->active_executable.Clear(); +} + +bool ExecutableManager::Empty() const { return this->data.empty(); } + +std::size_t ExecutableManager::Size() const { return this->data.size(); } + +bool ExecutableManager::Load(const QJsonObject& json_root_object) { + // applications json object + const QJsonObject& json_executables_object = json_root_object.value("executables").toObject(); + + if (json_executables_object.value("active_executable") != QJsonValue::Undefined) { + this->active_executable = Path(json_executables_object.value("active_executable").toString().toStdString()); + } + + if (json_executables_object.value("last_path_executable") != QJsonValue::Undefined) { + this->last_path_executable = json_executables_object.value("last_path_executable").toString().toStdString(); + } + + const QJsonObject& json_list_object = json_executables_object.value("list").toObject(); + + const QStringList& json_list_keys = json_list_object.keys(); + + this->data.clear(); + for (int i = 0, n = json_list_keys.length(); i < n; ++i) { + Executable executable; + + const QJsonObject& json_application_object = json_list_object.value(json_list_keys[i]).toObject(); + executable.path = json_list_keys[i].toStdString(); + executable.active_option_index = json_application_object.value("active_option_index").toInt(); + + const QJsonArray& json_options_array = json_application_object.value("options").toArray(); + for (int j = 0, o = json_options_array.size(); j < o; ++j) { + const QJsonObject& json_options_object = json_options_array[j].toObject(); + + ExecutableOptions executable_options; + + executable_options.label = json_options_object.value("label").toString().toStdString(); + executable_options.working_folder = json_options_object.value("working_folder").toString().toStdString(); + + const QJsonArray& json_command_lines_array = json_options_object.value("arguments").toArray(); + for (int k = 0, p = json_command_lines_array.size(); k < p; ++k) { + executable_options.args.push_back(json_command_lines_array[k].toString().toStdString()); + } + + const QJsonArray& json_environment_variables_array = json_options_object.value("environment_variables").toArray(); + for (int k = 0, p = json_environment_variables_array.size(); k < p; ++k) { + executable_options.envs.push_back(json_environment_variables_array[k].toString().toStdString()); + } + + executable_options.log_file = json_options_array[j].toObject().value("log_file").toString().toStdString(); + + executable.options.push_back(executable_options); + } + + this->data.push_back(executable); + } + + if (this->data.empty()) { + this->data = this->CreateDefaultExecutables(); + this->active_executable = this->data[0].path; + } + + return true; +} + +bool ExecutableManager::Save(QJsonObject& json_root_object) const { + QJsonObject json_executables_object; + json_executables_object.insert("active_executable", this->active_executable.RelativePath().c_str()); + json_executables_object.insert("last_path_executable", this->last_path_executable.RelativePath().c_str()); + + QJsonObject json_executables_list_object; + for (std::size_t i = 0, n = this->data.size(); i < n; ++i) { + const Executable& executable = this->data[i]; + + QJsonObject json_executable_object; + json_executable_object.insert("active_option", executable.active_option_index); + + QJsonArray json_options_array; + for (std::size_t j = 0, o = executable.options.size(); j < o; ++j) { + const ExecutableOptions& options = executable.options[j]; + + QJsonArray json_arg_array; + for (std::size_t k = 0, p = options.args.size(); k < p; ++k) { + json_arg_array.append(options.args[k].c_str()); + } + + QJsonArray json_env_array; + for (std::size_t k = 0, p = options.envs.size(); k < p; ++k) { + json_env_array.append(options.envs[k].c_str()); + } + + QJsonObject json_option_object; + json_option_object.insert("label", options.label.c_str()); + json_option_object.insert("layers_mode", GetToken(options.layers_mode)); + json_option_object.insert("configuration", options.configuration.c_str()); + json_option_object.insert("working_folder", options.working_folder.RelativePath().c_str()); + json_option_object.insert("arguments", json_arg_array); + json_option_object.insert("environment_variables", json_env_array); + json_option_object.insert("log_file", options.log_file.RelativePath().c_str()); + + json_options_array.append(json_option_object); + } + json_executable_object.insert("options", json_options_array); + + json_executables_list_object.insert(executable.path.RelativePath().c_str(), json_executable_object); + } + + json_executables_object.insert("list", json_executables_list_object); + + json_root_object.insert("executables", json_executables_object); + + return true; +} + +void ExecutableManager::SelectActiveExecutable(std::size_t executable_index) { + assert(executable_index < this->data.size()); + this->active_executable = this->data[executable_index].path; +} + +int ExecutableManager::GetActiveExecutableIndex() const { + for (std::size_t i = 0, n = this->data.size(); i < n; ++i) { + if (this->data[i].path == this->active_executable) { + return static_cast(i); + } + } + + assert(0); + return -1; // Not found, but the list is present, so return the first item. +} + +bool ExecutableManager::AppendExecutable(const Executable& executable) { + this->data.push_back(executable); + return true; +} + +bool ExecutableManager::AppendExecutable(const Path& executable_path) { + this->last_path_executable = executable_path; + this->active_executable = executable_path; + + ExecutableOptions options; + options.working_folder = executable_path.AbsoluteDir(); + + Executable executable; + executable.path = executable_path; + executable.options.push_back(options); + executable.active_option_index = 0; + + this->data.push_back(executable); + return true; +} + +bool ExecutableManager::RemoveExecutable(std::size_t executable_index) { + assert(!this->data.empty()); + assert(executable_index < this->data.size()); + + if (this->data.size() == 1u) { + this->data.clear(); + return true; + } + + std::vector new_executables; + new_executables.reserve(this->data.size() - 1); + + for (std::size_t i = 0, n = this->data.size(); i < n; ++i) { + if (i == executable_index) { + continue; + } + new_executables.push_back(this->data[i]); + } + + std::swap(this->data, new_executables); + return true; +} + +const Executable* ExecutableManager::GetActiveExecutable() const { + for (std::size_t i = 0, n = this->data.size(); i < n; ++i) { + if (this->data[i].path == this->active_executable) { + return &this->data[i]; + } + } + + return nullptr; // Not found, but the list is present, so return the first item. +} + +Executable* ExecutableManager::GetActiveExecutable() { + for (std::size_t i = 0, n = this->data.size(); i < n; ++i) { + if (this->data[i].path == this->active_executable) { + return &this->data[i]; + } + } + + return nullptr; // Not found, but the list is present, so return the first item. +} + +const Executable* ExecutableManager::GetExecutable(std::size_t executable_index) const { + assert(executable_index < this->data.size()); + + return &this->data[executable_index]; +} + +Executable* ExecutableManager::GetExecutable(std::size_t executable_index) { + assert(executable_index < this->data.size()); + + return &this->data[executable_index]; +} + +/////////////////////////////////////////////////////////////////////////// +/// This is only used on macOS to extract the executable from the bundle. +/// You have to look at the plist.info file, you can't just assume whatever +/// you find in the /MacOS folder is the executable. +/// The initial path is the folder where info.plist resides, and the +/// path is completed to the executable upon completion. +/// Note, not ALL macOS executables are in a bundle, so if a non-bundled +/// executable is fed in here, it will silently just return without +/// modifying the path (which will be the correct behavior) +bool ExactExecutableFromAppBundle(Path& app_path) { + std::string path = app_path.AbsolutePath(); + path += "/Contents/"; + std::string list_file = path + "Info.plist"; + QFile file(list_file.c_str()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return false; + } + + QTextStream stream(&file); + + // Read a line at a time looking for the executable tag + QString line_buffer; + while (!stream.atEnd()) { + line_buffer = stream.readLine(); + if (line_buffer.contains("CFBundleExecutable")) { // Exe follows this + line_buffer = stream.readLine(); // Qt Creator + char* cExeName = new char[line_buffer.length()]; // Prevent buffer overrun + + QByteArray line_array = line_buffer.toUtf8(); + const char* pStart = strstr(line_array.constData(), ""); + if (pStart == nullptr) return false; + + // We found it, now extract it out + pStart += 8; + int iIndex = 0; + while (*pStart != '<') { + cExeName[iIndex++] = *pStart++; + } + cExeName[iIndex] = '\0'; + + // Complete the partial path + path += "MacOS/"; + path += cExeName; + + // Return original if not found, but root if found + app_path = Path(path); + + delete[] cExeName; + break; + } + } + + file.close(); + + return true; +} + +DefaultPath ExecutableManager::GetDefaultExecutablePath(const std::string& executable_name) const { + static const char* DEFAULT_PATH = VKC_PLATFORM == PLATFORM_MACOS ? "/../.." : ""; + + DefaultPath default_path{"." + executable_name, "."}; + + // Using VULKAN_SDK environement variable + const Path env = ::Get(Path::SDK_BIN); + if (!env.Empty()) { + const Path search_path(env + DEFAULT_PATH + executable_name.c_str()); + if (search_path.Exists()) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; + } + } + + // Search the default applications from package installation (Linux) + if (VKC_PLATFORM == PLATFORM_LINUX) { + const Path search_path(std::string("/usr/bin") + DEFAULT_PATH + executable_name); + if (search_path.Exists()) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; + } + } else if (VKC_PLATFORM == PLATFORM_MACOS) { + Path search_path(std::string("/Applications") + executable_name); + if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; + } + } + + // Using relative path to vkconfig in case SDK is not "installed" + if (VKC_PLATFORM == PLATFORM_MACOS) { + Path search_path(std::string("..") + DEFAULT_PATH + executable_name); + if (search_path.Exists() && ExactExecutableFromAppBundle(search_path)) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; + } + } else { + Path search_path(std::string(".") + DEFAULT_PATH + executable_name); + if (search_path.Exists()) { + default_path.executable_path = Path(search_path.AbsolutePath(), true); + default_path.working_folder = Path(search_path.AbsoluteDir(), true); + return default_path; + } + } + + return default_path; +} + +Executable ExecutableManager::CreateDefaultExecutable(const DefaultExecutable& default_executable) const { + const DefaultPath& default_paths = GetDefaultExecutablePath((default_executable.key + GetExecutableSuffix()).c_str()); + if (default_paths.executable_path.Empty()) { + Executable(); // application could not be found.. + } + + ExecutableOptions options; + options.label = "Default"; + options.working_folder = default_paths.working_folder; + // On all operating systems, but Windows we keep running into problems with this ending up + // somewhere the user isn't allowed to create and write files. For consistncy sake, the log + // initially will be set to the users home folder across all OS's. This is highly visible + // in the application launcher and should not present a usability issue. The developer can + // easily change this later to anywhere they like. + options.log_file = std::string("${VK_LOCAL}") + default_executable.key + ".txt"; + + Executable executable; + executable.path = Path(default_paths.executable_path.AbsolutePath(), true); + executable.options.push_back(options); + executable.active_option_index = 0; + return executable; +} + +std::vector ExecutableManager::CreateDefaultExecutables() const { + std::vector new_executables; + + for (std::size_t name_index = 0, name_count = std::size(defaults_executables); name_index < name_count; ++name_index) { + const Executable& executable = CreateDefaultExecutable(defaults_executables[name_index]); + + if (executable.path.Empty()) { + continue; + } + + new_executables.push_back(executable); + } + + return new_executables; +} + +std::vector ExecutableManager::RemoveMissingExecutables(const std::vector& executables) const { + std::vector valid_applications; + + // Remove applications that can't be found + for (std::size_t i = 0, n = executables.size(); i < n; ++i) { + const Executable& application = executables[i]; + + const QFileInfo file_info(application.path.AbsolutePath().c_str()); + if (!file_info.exists()) { + continue; + } + + valid_applications.push_back(application); + } + + return valid_applications; +} diff --git a/vkconfig_core/executable_manager.h b/vkconfig_core/executable_manager.h new file mode 100644 index 0000000000..89ef872a28 --- /dev/null +++ b/vkconfig_core/executable_manager.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "serialization.h" +#include "path.h" +#include "type_layers_mode.h" + +#include +#include + +struct DefaultExecutable { + std::string name; + std::string key; + std::string arguments; +}; + +struct DefaultPath { + Path executable_path; + Path working_folder; +}; + +struct ExecutableOptions { + std::string label = "Default"; + LayersMode layers_mode = LAYERS_CONTROLLED_BY_APPLICATIONS; + std::string configuration = "Validation"; + Path working_folder; + std::vector args; + std::vector envs; + Path log_file; +}; + +struct Executable { + Path path; + int active_option_index = 0; + std::vector options; + + ExecutableOptions* GetActiveOptions() { return &this->options[active_option_index]; } + + const ExecutableOptions* GetActiveOptions() const { return &this->options[active_option_index]; } +}; + +class ExecutableManager : public Serialize { + public: + bool Load(const QJsonObject& json_root_object) override; + bool Save(QJsonObject& json_root_object) const override; + void Reset() override; + + void Clear(); + bool Empty() const; + std::size_t Size() const; + + void SelectActiveExecutable(std::size_t executable_index); + int GetActiveExecutableIndex() const; + bool AppendExecutable(const Executable& executable); + bool AppendExecutable(const Path& executable_path); + bool RemoveExecutable(std::size_t executable_index); + + const std::vector& GetExecutables() const { return this->data; } + const Executable* GetActiveExecutable() const; + Executable* GetActiveExecutable(); + const Executable* GetExecutable(std::size_t executable_index) const; + Executable* GetExecutable(std::size_t executable_index); + + // Search for all the applications in the list, an remove the application which executable can't be found + std::vector RemoveMissingExecutables(const std::vector& executables) const; + + bool launcher_clear_on_launch = true; + Path last_path_executable = ::Get(Path::HOME); + + private: + Path active_executable; + std::vector data; + + // Create a list of default executables, eg vkcube + std::vector CreateDefaultExecutables() const; + Executable CreateDefaultExecutable(const DefaultExecutable& default_executable) const; + DefaultPath GetDefaultExecutablePath(const std::string& executable_name) const; +}; diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 53ec7a1dc7..4e898a5476 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -121,10 +121,6 @@ static LayersPathInfo *FindPathInfo(std::array, LAYE return nullptr; } -LayerManager::LayerManager() {} - -LayerManager::~LayerManager() {} - bool LayerManager::Load(const QJsonObject &json_root_object) { this->paths[LAYERS_PATHS_IMPLICIT] = GetImplicitLayerPaths(); diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index 864b9126cc..c35e3c6918 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -46,9 +46,6 @@ LayerType GetLayerType(LayersPaths Layers_paths_type); class LayerManager : public Serialize { public: - LayerManager(); - ~LayerManager(); - bool Load(const QJsonObject& json_root_object) override; bool Save(QJsonObject& json_root_object) const override; void Reset() override; diff --git a/vkconfig_core/registry.cpp b/vkconfig_core/registry.cpp index 5b4f368ec1..28f4d229dc 100644 --- a/vkconfig_core/registry.cpp +++ b/vkconfig_core/registry.cpp @@ -20,8 +20,6 @@ #include "registry.h" -#include - #if VKC_ENV == VKC_ENV_WIN32 #include #include diff --git a/vkconfig_core/test/CMakeLists.txt b/vkconfig_core/test/CMakeLists.txt index 07133ae207..1b6369742f 100644 --- a/vkconfig_core/test/CMakeLists.txt +++ b/vkconfig_core/test/CMakeLists.txt @@ -37,7 +37,6 @@ endfunction() vkConfigTest(test_date) vkConfigTest(test_util) vkConfigTest(test_version) -vkConfigTest(test_environment) vkConfigTest(test_command_line) vkConfigTest(test_json) vkConfigTest(test_layer) @@ -64,6 +63,7 @@ vkConfigTest(test_path) vkConfigTest(test_configuration) vkConfigTest(test_configuration_built_in) vkConfigTest(test_configuration_manager) +vkConfigTest(test_executable_manager) vkConfigTest(test_override) vkConfigTest(test_application_singleton) vkConfigTest(test_type_hide_message) diff --git a/vkconfig_core/test/test_environment.cpp b/vkconfig_core/test/test_environment.cpp deleted file mode 100644 index 2776b33b35..0000000000 --- a/vkconfig_core/test/test_environment.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2020-2024 Valve Corporation - * Copyright (c) 2020-2024 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. - * - * Authors: - * - Richard S. Wright Jr. - * - Christophe Riccio - */ - -#include "../environment.h" -#include "../type_platform.h" - -#include - -#include - -TEST(test_environment, reset_default_applications_sdk_found) { - Environment environment; - environment.Reset(); - - const std::vector& applications = environment.GetApplications(); - - std::string result = qgetenv("VULKAN_SDK").toStdString(); - - if (!result.empty()) { - EXPECT_EQ(2, applications.size()); - - // Make sure the variable are not replaced - EXPECT_TRUE(applications[0].executable_path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); - EXPECT_TRUE(applications[0].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); - EXPECT_TRUE(applications[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); - EXPECT_TRUE(applications[1].executable_path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); - EXPECT_TRUE(applications[1].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); - EXPECT_TRUE(applications[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); - } -} - -TEST(test_environment, reset_default_applications_no_sdk) { - qunsetenv("VULKAN_SDK"); - - Environment environment; - environment.Reset(); - - const std::vector& applications = environment.GetApplications(); - - EXPECT_EQ(2, applications.size()); - - // Make sure the variable are not replaced - EXPECT_TRUE(applications[0].executable_path.RelativePath().find("vkcube") != std::string::npos); - EXPECT_TRUE(applications[0].options[0].working_folder.RelativePath().find(".") != std::string::npos); - EXPECT_TRUE(applications[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); - EXPECT_TRUE(applications[1].executable_path.RelativePath().find("vkcubepp") != std::string::npos); - EXPECT_TRUE(applications[1].options[0].working_folder.RelativePath().find(".") != std::string::npos); - EXPECT_TRUE(applications[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); -} - -TEST(test_environment, remove_missing_applications) { - Environment environment; - - const Path& path_missing = ::Get(Path::HOME) + "my_missing_executable"; - const Path& path_exciting = ::Get(Path::HOME) + "my_exciting_executable"; - - QFile file(path_exciting.AbsolutePath().c_str()); - const bool result = file.open(QIODevice::WriteOnly); - ASSERT_TRUE(result); - - std::vector applications; - Application application; - - application.executable_path = path_missing.AbsolutePath(); - applications.push_back(application); - - application.executable_path = path_exciting.AbsolutePath(); - applications.push_back(application); - - EXPECT_EQ(1, environment.RemoveMissingApplications(applications).size()); -} diff --git a/vkconfig_core/test/test_executable_manager.cpp b/vkconfig_core/test/test_executable_manager.cpp new file mode 100644 index 0000000000..8e0a5e9e74 --- /dev/null +++ b/vkconfig_core/test/test_executable_manager.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../executable_manager.h" + +#include + +#include + +TEST(test_executable_manager, reset_default_applications_sdk_found) { + ExecutableManager executable_manager; + executable_manager.Reset(); + + const std::vector& executables = executable_manager.GetExecutables(); + + std::string result = qgetenv("VULKAN_SDK").toStdString(); + + if (!result.empty()) { + EXPECT_EQ(2, executables.size()); + + // Make sure the variable are not replaced + EXPECT_TRUE(executables[0].path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(executables[0].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(executables[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(executables[1].path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(executables[1].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); + EXPECT_TRUE(executables[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + } +} + +TEST(test_executable_manager, reset_default_applications_no_sdk) { + qunsetenv("VULKAN_SDK"); + + ExecutableManager executable_manager; + executable_manager.Reset(); + + const std::vector& executables = executable_manager.GetExecutables(); + + EXPECT_EQ(2, executables.size()); + + // Make sure the variable are not replaced + EXPECT_TRUE(executables[0].path.RelativePath().find("vkcube") != std::string::npos); + EXPECT_TRUE(executables[0].options[0].working_folder.RelativePath().find(".") != std::string::npos); + EXPECT_TRUE(executables[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(executables[1].path.RelativePath().find("vkcubepp") != std::string::npos); + EXPECT_TRUE(executables[1].options[0].working_folder.RelativePath().find(".") != std::string::npos); + EXPECT_TRUE(executables[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); +} + +TEST(test_executable_manager, remove_missing_applications) { + ExecutableManager executable_manager; + + const Path& path_missing = ::Get(Path::HOME) + "my_missing_executable"; + const Path& path_exciting = ::Get(Path::HOME) + "my_exciting_executable"; + + QFile file(path_exciting.AbsolutePath().c_str()); + const bool result = file.open(QIODevice::WriteOnly); + ASSERT_TRUE(result); + + std::vector executables; + Executable executable; + + executable.path = path_missing.AbsolutePath(); + executables.push_back(executable); + + executable.path = path_exciting.AbsolutePath(); + executables.push_back(executable); + + EXPECT_EQ(1, executable_manager.RemoveMissingExecutables(executables).size()); +} diff --git a/vkconfig_gui/dialog_vulkan_analysis.cpp b/vkconfig_gui/dialog_vulkan_analysis.cpp index b16cfc5634..a61488af36 100644 --- a/vkconfig_gui/dialog_vulkan_analysis.cpp +++ b/vkconfig_gui/dialog_vulkan_analysis.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/vkconfig_gui/dialog_vulkan_info.cpp b/vkconfig_gui/dialog_vulkan_info.cpp index 88335e5b98..aa8ba7e681 100644 --- a/vkconfig_gui/dialog_vulkan_info.cpp +++ b/vkconfig_gui/dialog_vulkan_info.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index c7402c4405..0f96e6535e 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -61,7 +61,6 @@ MainWindow::MainWindow(QWidget *parent) _tray_quit_action(nullptr), ui(new Ui::MainWindow) { ui->setupUi(this); - ui->application_list->installEventFilter(this); this->InitTray(); @@ -273,14 +272,13 @@ void MainWindow::UpdateUI() { assert(check_recurse <= 1); Configurator &configurator = Configurator::Get(); - const Environment &environment = Configurator::Get().environment; this->blockSignals(true); ui->configurations_list->blockSignals(true); - const bool has_application_list = !environment.GetApplications().empty(); + const bool has_application_list = !configurator.executables.GetExecutables().empty(); ui->push_button_launcher->setText(_launch_application ? "Terminate" : "Launch"); - ui->check_box_clear_on_launch->setChecked(environment.launcher_clear_on_launch); + ui->check_box_clear_on_launch->setChecked(configurator.executables.launcher_clear_on_launch); // Mode states // this->UpdateUI_Status(); @@ -292,7 +290,7 @@ void MainWindow::UpdateUI() { } void MainWindow::on_check_box_clear_on_launch_clicked() { - Configurator::Get().environment.launcher_clear_on_launch = ui->check_box_clear_on_launch->isChecked(); + Configurator::Get().executables.launcher_clear_on_launch = ui->check_box_clear_on_launch->isChecked(); } void MainWindow::toolsResetToDefault(bool checked) { @@ -312,7 +310,7 @@ void MainWindow::toolsResetToDefault(bool checked) { void MainWindow::StartTool(Tool tool) { Configurator &configurator = Configurator::Get(); - if (!configurator.configurations.GetPerApplicationConfig()) { + if (!configurator.configurations.GetPerExecutableConfig()) { configurator.Surrender(OVERRIDE_AREA_LOADER_SETTINGS_BIT); } @@ -325,7 +323,7 @@ void MainWindow::StartTool(Tool tool) { break; } - if (!configurator.configurations.GetPerApplicationConfig()) { + if (!configurator.configurations.GetPerExecutableConfig()) { configurator.Override(OVERRIDE_AREA_LOADER_SETTINGS_BIT); } } @@ -497,39 +495,39 @@ void MainWindow::on_push_button_launcher_clicked() { std::string launch_log = "Launching Vulkan Application:\n"; Configurator &configurator = Configurator::Get(); - const Application &active_application = configurator.environment.GetActiveApplication(); + const Executable *active_executable = configurator.executables.GetActiveExecutable(); - assert(!active_application.executable_path.Empty()); - launch_log += format("- Executable: %s\n", active_application.executable_path.AbsolutePath().c_str()); - if (!active_application.executable_path.Exists()) { + assert(!active_executable->path.Empty()); + launch_log += format("- Executable: %s\n", active_executable->path.AbsolutePath().c_str()); + if (!active_executable->path.Exists()) { Alert::PathInvalid( - active_application.executable_path, - format("The '%s' application will fail to launch.", active_application.executable_path.AbsolutePath().c_str()).c_str()); + active_executable->path, + format("The '%s' application will fail to launch.", active_executable->path.AbsolutePath().c_str()).c_str()); } - const ApplicationOptions &options = active_application.GetActiveOptions(); + const ExecutableOptions *options = active_executable->GetActiveOptions(); - launch_log += format("- Working Directory: %s\n", options.working_folder.AbsolutePath().c_str()); - if (!options.working_folder.Exists()) { + launch_log += format("- Working Directory: %s\n", options->working_folder.AbsolutePath().c_str()); + if (!options->working_folder.Exists()) { Alert::PathInvalid( - options.working_folder, - format("The '%s' application will fail to launch.", active_application.executable_path.AbsolutePath().c_str()).c_str()); + options->working_folder, + format("The '%s' application will fail to launch.", active_executable->path.AbsolutePath().c_str()).c_str()); } /* if (!_launcher_arguments->text().isEmpty()) { launch_log += format("- Command-line Arguments: %s\n", _launcher_arguments->text().toStdString().c_str()); } */ - if (!options.log_file.Empty()) { - launch_log += format("- Log file: %s\n", options.log_file.AbsolutePath().c_str()); + if (!options->log_file.Empty()) { + launch_log += format("- Log file: %s\n", options->log_file.AbsolutePath().c_str()); } - if (!options.log_file.Empty()) { + if (!options->log_file.Empty()) { // Start logging // Make sure the log file is not already opened. This can occur if the // launched application is closed from the applicaiton. if (!_log_file.isOpen()) { - _log_file.setFileName(options.log_file.AbsolutePath().c_str()); + _log_file.setFileName(options->log_file.AbsolutePath().c_str()); // Open and append, or open and truncate? QIODevice::OpenMode mode = QIODevice::WriteOnly | QIODevice::Text; @@ -555,8 +553,8 @@ void MainWindow::on_push_button_launcher_clicked() { //_launch_application->setWorkingDirectory(ui->edit_dir->text()); //_launch_application->setEnvironment(BuildEnvVariables() + ui->edit_env->text().split(",")); - if (!options.arguments.empty()) { - const QStringList args = ConvertString(options.arguments); + if (!options->args.empty()) { + const QStringList args = ConvertString(options->args); _launch_application->setArguments(args); } @@ -569,8 +567,7 @@ void MainWindow::on_push_button_launcher_clicked() { _launch_application->deleteLater(); _launch_application = nullptr; - const std::string failed_log = - std::string("Failed to launch ") + active_application.executable_path.AbsolutePath().c_str() + "!\n"; + const std::string failed_log = std::string("Failed to launch ") + active_executable->path.AbsolutePath().c_str() + "!\n"; Log(failed_log); } diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index c0f9aa71a6..8cf299ae5c 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -121,7 +121,7 @@ 0 - + 0 @@ -222,7 +222,7 @@ - Per-Application: + Per-executable: @@ -679,6 +679,9 @@ Layers + + 0 + 5 @@ -775,16 +778,19 @@ - 6 + 0 + + + 5 - 6 + 5 - 6 + 5 - 6 + 0 @@ -802,11 +808,17 @@ 0 + + 0 + 0 + + 0 + - + 0 @@ -820,94 +832,46 @@ 0 - 0 + 3 - - - 0 - - - 0 - - - 0 - - - 0 + + + + 16777215 + 32 + - - 0 + + true - - - - - - - - 32 - 16777215 - - - - + - - - - - - - - 32 - 16777215 - - - - - - - - - + - - - 0 + + + + 32 + 32 + - - 0 + + - - - 0 + + + + + + + 32 + 32 + - - 0 + + ... - - - - Executable Path: - - - - - - - - - - - 32 - 16777215 - - - - ... - - - - + @@ -916,24 +880,39 @@ 0 + + 0 + 0 - + 0 + + 3 + - + 0 0 + + + 16777215 + 32 + + + + true + - + 0 @@ -942,23 +921,30 @@ - 0 + 32 0 32 - 16777215 + 32 - + + - + + + + .. + + + false - + 0 @@ -967,25 +953,18 @@ - 32 + 0 0 32 - 16777215 + 32 - - - - - - .. - - - false + + @@ -1011,12 +990,8 @@ 0 - - - - Label: - - + + @@ -1028,50 +1003,19 @@ - - - - Layers Mode: - - - - - - - Arguments: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - Output Log: - - - - - - - - - - Working Dir: - - - 0 - + + + + 16777215 + 32 + + Layers Controlled by Vulkan Applications @@ -1090,24 +1034,72 @@ - + + + + 16777215 + 32 + + + - - + + + + + + + Layers Mode: + + + + + + + Output Log: + + + + + + + Working Dir: + + + + + + + Arguments: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 - + + + + 16777215 + 32 + + + - + 32 - 16777215 + 32 @@ -1117,20 +1109,27 @@ - - + + 0 - + + + + 16777215 + 32 + + + - + 32 - 16777215 + 32 @@ -1140,9 +1139,6 @@ - - - diff --git a/vkconfig_gui/tab_applications.cpp b/vkconfig_gui/tab_applications.cpp index cb9225de60..d62b4a1a6e 100644 --- a/vkconfig_gui/tab_applications.cpp +++ b/vkconfig_gui/tab_applications.cpp @@ -23,6 +23,8 @@ #include "../vkconfig_core/configurator.h" +#include + /* case PATH_EXECUTABLE: { static const char* TABLE[] = { @@ -56,283 +58,194 @@ } */ -TabApplications::TabApplications(MainWindow &window, std::shared_ptr ui) : Tab(TAB_APPLICATIONS, window, ui) {} +TabApplications::TabApplications(MainWindow &window, std::shared_ptr ui) : Tab(TAB_APPLICATIONS, window, ui) { + this->connect(this->ui->applications_remove_application_pushButton, SIGNAL(pressed()), this, + SLOT(on_applications_remove_application_pushButton_pressed())); + this->connect(this->ui->applications_append_application_pushButton, SIGNAL(pressed()), this, + SLOT(on_applications_append_application_pushButton_pressed())); + this->connect(this->ui->applications_list_comboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_applications_list_comboBox_activated(int))); + this->connect(this->ui->applications_list_comboBox, SIGNAL(editTextChanged(QString)), this, + SLOT(on_applications_list_comboBox_textEdited(QString))); + + this->connect(this->ui->applications_options_remove_pushButton, SIGNAL(pressed()), this, + SLOT(on_applications_options_remove_pushButton_pressed())); + this->connect(this->ui->applications_options_duplicate_pushButton, SIGNAL(pressed()), this, + SLOT(on_applications_options_duplicate_pushButton_pressed())); + this->connect(this->ui->applications_options_comboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_applications_options_comboBox_activated(int))); + this->connect(this->ui->applications_options_comboBox, SIGNAL(editTextChanged(QString)), this, + SLOT(on_applications_options_comboBox_textEdited(QString))); + + this->connect(this->ui->applications_layers_mode_comboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_applications_layers_mode_comboBox_activated(int))); + this->connect(this->ui->applications_configuration_comboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(on_applications_configuration_comboBox_activated(int))); +} TabApplications::~TabApplications() {} void TabApplications::UpdateUI(UpdateUIMode mode) { const Configurator &configurator = Configurator::Get(); - const Environment &environment = Configurator::Get().environment; - - const std::vector &applications = configurator.environment.GetApplications(); - ui->application_list->clear(); - for (std::size_t i = 0, n = applications.size(); i < n; ++i) { - QListWidgetItem *application_item = new QListWidgetItem(); - application_item->setText(applications[i].executable_path.RelativePath().c_str()); - application_item->setToolTip(applications[i].executable_path.AbsolutePath().c_str()); - ui->application_list->addItem(application_item); - } - const std::vector &configurations = configurator.configurations.available_configurations; - ui->application_configuration_comboBox->clear(); - for (std::size_t i = 0, n = configurations.size(); i < n; ++i) { - ui->application_configuration_comboBox->addItem(configurations[i].key.c_str()); + const std::vector &executables = configurator.executables.GetExecutables(); + + if (mode == UPDATE_REBUILD_UI) { + // Rebuild list of layers configurations + const std::vector &configurations = configurator.configurations.available_configurations; + ui->applications_configuration_comboBox->blockSignals(true); + ui->applications_configuration_comboBox->clear(); + for (std::size_t i = 0, n = configurations.size(); i < n; ++i) { + ui->applications_configuration_comboBox->addItem(configurations[i].key.c_str()); + } + ui->applications_configuration_comboBox->blockSignals(false); + + // Rebuild list of applications + ui->applications_list_comboBox->blockSignals(true); + ui->applications_list_comboBox->clear(); + for (std::size_t i = 0, n = executables.size(); i < n; ++i) { + ui->applications_list_comboBox->addItem(executables[i].path.RelativePath().c_str()); + } + ui->applications_list_comboBox->blockSignals(false); + ui->applications_list_comboBox->setCurrentIndex(configurator.executables.GetActiveExecutableIndex()); } - /* - // App Name - QTreeWidgetItem *launcher_parent = new QTreeWidgetItem(); - launcher_parent->setText(0, "Application"); - ui->application_list->addTopLevelItem(launcher_parent); - - _launcher_apps_combo = new QComboBox(); - _launcher_apps_combo->setFocusPolicy(Qt::StrongFocus); - _launcher_apps_combo->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_apps_combo->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->application_list->setItemWidget(launcher_parent, 1, _launcher_apps_combo); - - _launcher_apps_browse_button = new QPushButton(); - _launcher_apps_browse_button->setText("..."); - _launcher_apps_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_apps_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_apps_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_apps_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_parent, 2, _launcher_apps_browse_button); - connect(_launcher_apps_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(launchItemChanged(int))); - connect(_launcher_apps_browse_button, SIGNAL(clicked()), this, SLOT(on_push_button_applications_clicked())); - - // Executable - QTreeWidgetItem *launcher_executable_item = new QTreeWidgetItem(); - launcher_executable_item->setText(0, "Executable"); - launcher_parent->addChild(launcher_executable_item); - - _launcher_executable = new QLineEdit(); - _launcher_executable->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_executable->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->application_list->setItemWidget(launcher_executable_item, 1, _launcher_executable); - _launcher_executable->setReadOnly(false); - - _launcher_executable_browse_button = new QPushButton(); - _launcher_executable_browse_button->setText("..."); - _launcher_executable_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_executable_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_executable_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_executable_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_executable_item, 2, _launcher_executable_browse_button); - connect(_launcher_executable, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeExecutable(const QString &))); - connect(_launcher_executable_browse_button, SIGNAL(clicked()), this, SLOT(launchSetExecutable())); - - // Working folder - QTreeWidgetItem *launcher_folder_item = new QTreeWidgetItem(); - launcher_folder_item->setText(0, "Working Directory"); - launcher_parent->addChild(launcher_folder_item); - - _launcher_working = new QLineEdit(); - _launcher_working->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_working->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_folder_item, 1, _launcher_working); - _launcher_working->setReadOnly(false); - - _launcher_working_browse_button = new QPushButton(); - _launcher_working_browse_button->setText("..."); - _launcher_working_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_working_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - _launcher_working_browse_button->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_working_browse_button->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_folder_item, 2, _launcher_working_browse_button); - connect(_launcher_working, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeWorkingFolder(const QString &))); - connect(_launcher_working_browse_button, SIGNAL(clicked()), this, SLOT(launchSetWorkingFolder())); - - // Command line arguments - QTreeWidgetItem *launcher_arguments_item = new QTreeWidgetItem(); - launcher_arguments_item->setText(0, "Command-line Arguments"); - launcher_parent->addChild(launcher_arguments_item); - - _launcher_arguments = new QLineEdit(); - _launcher_arguments->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_arguments->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_arguments_item, 1, _launcher_arguments); - connect(_launcher_arguments, SIGNAL(textEdited(const QString &)), this, SLOT(launchArgsEdited(const QString &))); - - // Log file - QTreeWidgetItem *launcher_log_file_item = new QTreeWidgetItem(); - launcher_log_file_item->setText(0, "Output Log"); - launcher_parent->addChild(launcher_log_file_item); - - _launcher_log_file_edit = new QLineEdit(); - _launcher_log_file_edit->setMinimumHeight(LAUNCH_ROW_HEIGHT); - _launcher_log_file_edit->setMaximumHeight(LAUNCH_ROW_HEIGHT); - ui->launcher_tree->setItemWidget(launcher_log_file_item, 1, _launcher_log_file_edit); - connect(_launcher_log_file_edit, SIGNAL(textEdited(const QString &)), this, SLOT(launchChangeLogFile(const QString &))); - - _launcher_log_file_browse_button = new QPushButton(); - _launcher_log_file_browse_button->setText("..."); - _launcher_log_file_browse_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - _launcher_log_file_browse_button->setMaximumWidth(LAUNCH_COLUMN2_SIZE); - ui->launcher_tree->setItemWidget(launcher_log_file_item, 2, _launcher_log_file_browse_button); - connect(_launcher_log_file_browse_button, SIGNAL(clicked()), this, SLOT(launchSetLogFile())); - - // Launcher tree - ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - - ui->launcher_tree->setColumnWidth(0, LAUNCH_COLUMN0_SIZE); - ui->launcher_tree->setColumnWidth( - 1, ui->launcher_tree->rect().width() - LAUNCH_COLUMN0_SIZE - LAUNCH_COLUMN2_SIZE - LAUNCH_SPACING_SIZE); - ui->launcher_tree->setColumnWidth(2, LAUNCH_COLUMN2_SIZE); - - ui->launcher_tree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->launcher_tree->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - */ + this->on_applications_list_comboBox_activated(configurator.executables.GetActiveExecutableIndex()); } void TabApplications::CleanUI() {} bool TabApplications::EventFilter(QObject *target, QEvent *event) { return false; } -/* -// Expanding the tree also grows the tree to match -void MainWindow::launchItemExpanded(QTreeWidgetItem *item) { - (void)item; - ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); - ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT * 5 + 6); -} +void TabApplications::on_applications_remove_application_pushButton_pressed() { + Configurator &configurator = Configurator::Get(); + + configurator.executables.RemoveExecutable(ui->applications_list_comboBox->currentIndex()); + ui->applications_list_comboBox->setEnabled(!configurator.executables.Empty()); -// Collapsing the tree also shrinks the tree to match and show only the first line -void MainWindow::launchItemCollapsed(QTreeWidgetItem *item) { - (void)item; - ui->launcher_tree->setMinimumHeight(LAUNCH_ROW_HEIGHT + 6); - ui->launcher_tree->setMaximumHeight(LAUNCH_ROW_HEIGHT + 6); + this->UpdateUI(UPDATE_REBUILD_UI); } -*/ -/* -void MainWindow::OnLauncherLoaderMessageChanged(int level) { +void TabApplications::on_applications_append_application_pushButton_pressed() { + static const char *TABLE[] = { + "Applications (*.exe)", // PLATFORM_WINDOWS_X86 + "Applications (*.exe)", // PLATFORM_WINDOWS_ARM + "Applications (*)", // PLATFORM_LINUX + "Applications (*.app, *)", // PLATFORM_MACOS + "N/A", // PLATFORM_ANDROID + "N/A" // PLATFORM_IOS + }; + static_assert(std::size(TABLE) == PLATFORM_COUNT, "The tranlation table size doesn't match the enum number of elements"); + + const std::string filter = TABLE[VKC_PLATFORM]; + Configurator &configurator = Configurator::Get(); - // configurator.environment.SetLoaderMessage(static_cast(level)); - // configurator.environment.SetLoaderMessageFlags(GetBit(static_cast(level))); + const Path &path = configurator.executables.last_path_executable; + const Path &selected_path = + QFileDialog::getOpenFileName(&this->window, "Executable Path", path.AbsolutePath().c_str(), filter.c_str()).toStdString(); - if (ui->check_box_clear_on_launch->isChecked()) { - this->UpdateUI(); + if (selected_path.Empty()) { + return; } -} -void MainWindow::launchSetExecutable() { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); + configurator.executables.AppendExecutable(selected_path); + + this->UpdateUI(UPDATE_REBUILD_UI); +} +void TabApplications::on_applications_list_comboBox_activated(int index) { Configurator &configurator = Configurator::Get(); - Application &application = configurator.environment.GetApplication(current_application_index); + configurator.executables.SelectActiveExecutable(index); - //const Path exe = configurator.path.SelectPath(this, PATH_EXECUTABLE, application.executable_path); + const Executable *executable = configurator.executables.GetActiveExecutable(); + ui->applications_list_comboBox->setToolTip(executable->path.AbsolutePath().c_str()); - //// The user has cancel the operation - //if (exe.Empty()) { - // return; - //} + ui->applications_options_remove_pushButton->setEnabled(executable->options.size() > 1); - //application.executable_path = exe; + ui->applications_options_comboBox->blockSignals(true); + ui->applications_options_comboBox->clear(); + for (std::size_t i = 0, n = executable->options.size(); i < n; ++i) { + ui->applications_options_comboBox->addItem(executable->options[i].label.c_str()); + } + ui->applications_options_comboBox->blockSignals(false); + ui->applications_options_comboBox->setCurrentIndex(executable->active_option_index); - _launcher_executable->setText(application.executable_path.RelativePath().c_str()); + this->on_applications_options_comboBox_activated(executable->active_option_index); } -*/ -/* -void MainWindow::launchSetLogFile() { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); +void TabApplications::on_applications_list_comboBox_textEdited(const QString &text) { Configurator &configurator = Configurator::Get(); - Application &application = configurator.environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); - // TODO - //const Path &path = configurator.path.SelectPath(this, PATH_LAUNCHER_LOG_FILE, options.log_file); - - //// The user has cancel the operation - //if (path.Empty()) { - // return; - //} - //options.log_file = path; - - _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); + Executable *executable = configurator.executables.GetActiveExecutable(); + executable->path = text.toStdString(); } -*/ -/* -void MainWindow::launchSetWorkingFolder() { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); +void TabApplications::on_applications_options_remove_pushButton_pressed() { Configurator &configurator = Configurator::Get(); - Application &application = configurator.environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); + Executable *executable = configurator.executables.GetActiveExecutable(); - // TODO - //const Path path = configurator.path.SelectPath(this, PATH_WORKING_DIR, options.working_folder); + this->ui->applications_options_remove_pushButton->setEnabled(executable->options.size() > 1); +} - //// The user has cancel the operation - //if (path.Empty()) { - // return; - //} +void TabApplications::on_applications_options_duplicate_pushButton_pressed() {} - //options.working_folder = path; +void TabApplications::on_applications_options_comboBox_activated(int index) { + Configurator &configurator = Configurator::Get(); + Executable *executable = configurator.executables.GetActiveExecutable(); - _launcher_working->setText(options.working_folder.RelativePath().c_str()); -} -*/ + executable->active_option_index = index; + const ExecutableOptions *options = executable->GetActiveOptions(); -/* -// Log file path edited manually. -void MainWindow::launchChangeLogFile(const QString &log_file) { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); - - Application &application = Configurator::Get().environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); - options.log_file = log_file.toStdString(); -} + ui->applications_layers_mode_comboBox->setCurrentIndex(options->layers_mode); + ui->applications_configuration_comboBox->setEnabled(options->layers_mode == LAYERS_CONTROLLED_BY_CONFIGURATOR); + ui->applications_configuration_comboBox->setCurrentIndex( + configurator.configurations.GetConfigurationIndex(options->configuration)); -void MainWindow::launchChangeExecutable(const QString &exe) { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); + ui->applications_directory_edit->setText(options->working_folder.RelativePath().c_str()); + ui->applications_directory_edit->setToolTip(options->working_folder.AbsolutePath().c_str()); - Application &application = Configurator::Get().environment.GetApplication(current_application_index); - application.executable_path = exe.toStdString(); -} + ui->application_args_list->blockSignals(true); + ui->application_args_list->clear(); + for (std::size_t i = 0, n = options->args.size(); i < n; ++i) { + ui->application_args_list->addItem(options->args[i].c_str()); + } + ui->application_args_list->blockSignals(false); -void MainWindow::launchChangeWorkingFolder(const QString &working_folder) { - int current_application_index = _launcher_apps_combo->currentIndex(); - assert(current_application_index >= 0); + ui->application_envs_list->blockSignals(true); + ui->application_envs_list->clear(); + for (std::size_t i = 0, n = options->envs.size(); i < n; ++i) { + ui->application_envs_list->addItem(options->envs[i].c_str()); + } + ui->application_envs_list->blockSignals(false); - Application &application = Configurator::Get().environment.GetApplication(current_application_index); - ApplicationOptions &options = application.GetActiveOptions(); - options.working_folder = working_folder.toStdString(); + ui->application_output_log_edit->setText(options->log_file.RelativePath().c_str()); + ui->application_output_log_edit->setToolTip(options->log_file.AbsolutePath().c_str()); } -// Launch app change -void MainWindow::launchItemChanged(int application_index) { - if (application_index < 0) return; +void TabApplications::on_applications_options_comboBox_textEdited(const QString &text) { + Configurator &configurator = Configurator::Get(); + Executable *executable = configurator.executables.GetActiveExecutable(); - Environment &environment = Configurator::Get().environment; + ExecutableOptions *options = executable->GetActiveOptions(); + options->label = text.toStdString(); +} - environment.SelectActiveApplication(application_index); +void TabApplications::on_applications_layers_mode_comboBox_activated(int index) { + Configurator &configurator = Configurator::Get(); - Application &application = environment.GetApplication(application_index); - ApplicationOptions &options = application.GetActiveOptions(); + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); - _launcher_executable->setText(application.executable_path.RelativePath().c_str()); - _launcher_working->setText(options.working_folder.RelativePath().c_str()); - _launcher_arguments->setText(Merge(options.arguments, " ").c_str()); - _launcher_log_file_edit->setText(options.log_file.RelativePath().c_str()); + ui->applications_configuration_comboBox->setEnabled(index == LAYERS_CONTROLLED_BY_CONFIGURATOR); + options->layers_mode = static_cast(index); } -/// New command line arguments. Update them. -void MainWindow::launchArgsEdited(const QString &arguments) { - int application_index = _launcher_apps_combo->currentIndex(); - if (application_index < 0) return; +void TabApplications::on_applications_configuration_comboBox_activated(int index) { + Configurator &configurator = Configurator::Get(); + + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); - Application &application = Configurator::Get().environment.GetApplication(application_index); - ApplicationOptions &options = application.GetActiveOptions(); - options.arguments = SplitSpace(arguments.toStdString()); + options->configuration = ui->applications_configuration_comboBox->itemText(index).toStdString(); } -*/ diff --git a/vkconfig_gui/tab_applications.h b/vkconfig_gui/tab_applications.h index e5cb295be4..a3f422d853 100644 --- a/vkconfig_gui/tab_applications.h +++ b/vkconfig_gui/tab_applications.h @@ -34,6 +34,18 @@ struct TabApplications : public Tab { virtual bool EventFilter(QObject* target, QEvent* event) override; public Q_SLOTS: + void on_applications_remove_application_pushButton_pressed(); + void on_applications_append_application_pushButton_pressed(); + void on_applications_list_comboBox_activated(int index); + void on_applications_list_comboBox_textEdited(const QString& text); + + void on_applications_options_remove_pushButton_pressed(); + void on_applications_options_duplicate_pushButton_pressed(); + void on_applications_options_comboBox_activated(int index); + void on_applications_options_comboBox_textEdited(const QString& text); + + void on_applications_layers_mode_comboBox_activated(int index); + void on_applications_configuration_comboBox_activated(int index); private: }; diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index 6b6bd5a9e4..5c73794c4e 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -82,7 +82,6 @@ TabConfigurations::~TabConfigurations() { void TabConfigurations::UpdateUI_Configurations(UpdateUIMode ui_update_mode) { Configurator &configurator = Configurator::Get(); - Environment &environment = configurator.environment; const ConfigurationInfo *configuration_info = configurator.configurations.GetActiveConfigurationInfo(); assert(configuration_info != nullptr); @@ -142,32 +141,33 @@ void TabConfigurations::UpdateUI_Configurations(UpdateUIMode ui_update_mode) { void TabConfigurations::UpdateUI_Applications(UpdateUIMode ui_update_mode) { Configurator &configurator = Configurator::Get(); - Environment &environment = configurator.environment; - if (environment.GetApplications().empty()) { + const std::vector &executables = configurator.executables.GetExecutables(); + + if (executables.empty()) { ui->check_box_per_application->setEnabled(false); ui->check_box_per_application->setVisible(false); ui->combo_box_applications->setVisible(false); } else { ui->check_box_per_application->setEnabled(true); - ui->check_box_per_application->setChecked(configurator.configurations.GetPerApplicationConfig()); + ui->check_box_per_application->setChecked(configurator.configurations.GetPerExecutableConfig()); - ui->combo_box_applications->setEnabled(configurator.configurations.GetPerApplicationConfig()); + ui->combo_box_applications->setEnabled(configurator.configurations.GetPerExecutableConfig()); ui->combo_box_applications->blockSignals(true); if (ui_update_mode == UPDATE_REBUILD_UI) { ui->combo_box_applications->clear(); - for (std::size_t i = 0, n = environment.GetApplications().size(); i < n; ++i) { - const Application &application = environment.GetApplications()[i]; + for (std::size_t i = 0, n = executables.size(); i < n; ++i) { + const Executable &executable = executables[i]; - ui->combo_box_applications->addItem(application.executable_path.RelativePath().c_str()); + ui->combo_box_applications->addItem(executable.path.RelativePath().c_str()); } } - Application &application = configurator.environment.GetActiveApplication(); - ui->combo_box_applications->setCurrentIndex(environment.GetActiveApplicationIndex()); - ui->combo_box_applications->setToolTip(application.executable_path.AbsolutePath().c_str()); + const Executable *executable = configurator.executables.GetActiveExecutable(); + ui->combo_box_applications->setCurrentIndex(configurator.executables.GetActiveExecutableIndex()); + ui->combo_box_applications->setToolTip(executable->path.AbsolutePath().c_str()); ui->combo_box_applications->blockSignals(false); } } @@ -594,7 +594,7 @@ void TabConfigurations::OnContextMenuImportClicked(ConfigurationListItem *item) Configurator &configurator = Configurator::Get(); - const Path &path_import = configurator.environment.path_import; + const Path &path_import = configurator.configurations.last_path_import; const std::string selected_path = QFileDialog::getOpenFileName(&this->window, "Import Layers Configuration File", path_import.AbsolutePath().c_str(), "JSON configuration(*.json)") .toStdString(); @@ -603,7 +603,6 @@ void TabConfigurations::OnContextMenuImportClicked(ConfigurationListItem *item) return; } - configurator.environment.path_import = selected_path; configurator.configurations.ImportConfiguration(configurator.layers, selected_path); configurator.Override(OVERRIDE_AREA_ALL); @@ -711,7 +710,7 @@ void TabConfigurations::OnContextMenuExportConfigsClicked(ConfigurationListItem Configurator &configurator = Configurator::Get(); - const Path &path_export = configurator.environment.path_export; + const Path &path_export = configurator.configurations.last_path_export; const std::string &selected_path = QFileDialog::getSaveFileName(&this->window, "Export Layers Configuration File", path_export.AbsolutePath().c_str(), "JSON configuration(*.json)") @@ -743,7 +742,7 @@ void TabConfigurations::on_combo_box_mode_currentIndexChanged(int index) { void TabConfigurations::on_combo_box_applications_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); - configurator.environment.SelectActiveApplication(index); + configurator.executables.SelectActiveExecutable(index); this->UpdateUI(UPDATE_REFRESH_UI); this->window.UpdateUI_Status(); @@ -752,7 +751,7 @@ void TabConfigurations::on_combo_box_applications_currentIndexChanged(int index) void TabConfigurations::on_check_box_per_application_toggled(bool checked) { Configurator &configurator = Configurator::Get(); - configurator.configurations.SetPerApplicationConfig(checked); + configurator.configurations.SetPerExecutableConfig(checked); configurator.Override(OVERRIDE_AREA_ALL); this->UpdateUI(UPDATE_REFRESH_UI); diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index 687b0fae62..e899ab1cf9 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -28,8 +28,6 @@ linux: QMAKE_CXXFLAGS += -Wunused-variable SOURCES += \ ../vkconfig_core/alert.cpp \ - ../vkconfig_core/application.cpp \ - ../vkconfig_core/application_manager.cpp \ ../vkconfig_core/application_singleton.cpp \ ../vkconfig_core/bitfield.cpp \ ../vkconfig_core/command_line.cpp \ @@ -41,6 +39,7 @@ SOURCES += \ ../vkconfig_core/date.cpp \ ../vkconfig_core/doc.cpp \ ../vkconfig_core/environment.cpp \ + ../vkconfig_core/executable_manager.cpp \ ../vkconfig_core/header.cpp \ ../vkconfig_core/help.cpp \ ../vkconfig_core/json.cpp \ @@ -104,8 +103,6 @@ SOURCES += \ HEADERS += \ ../vkconfig_core/alert.h \ - ../vkconfig_core/application.h \ - ../vkconfig_core/application_manager.h \ ../vkconfig_core/application_singleton.h \ ../vkconfig_core/bitfield.h \ ../vkconfig_core/command_line.h \ @@ -117,6 +114,7 @@ HEADERS += \ ../vkconfig_core/date.h \ ../vkconfig_core/doc.h \ ../vkconfig_core/environment.h \ + ../vkconfig_core/executable_manager.h \ ../vkconfig_core/header.h \ ../vkconfig_core/help.h \ ../vkconfig_core/json.h \ From 2a3e79f0144ac795df54bbd28ca0a6de95d5e290 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 18 Sep 2024 17:03:28 +0200 Subject: [PATCH 27/33] vkconfig3: Implement application launcher --- vkconfig_core/configuration.cpp | 26 -- .../configurations/3.0.0/Frame Capture.json | 2 +- vkconfig_core/executable_manager.cpp | 50 ++- vkconfig_core/executable_manager.h | 6 +- .../test/test_executable_manager.cpp | 8 +- vkconfig_core/util.cpp | 28 ++ vkconfig_core/util.h | 4 + vkconfig_gui/mainwindow.cpp | 180 +--------- vkconfig_gui/mainwindow.h | 34 -- vkconfig_gui/mainwindow.ui | 48 ++- vkconfig_gui/tab_applications.cpp | 316 ++++++++++++++---- vkconfig_gui/tab_applications.h | 22 +- vkconfig_gui/tab_configurations.cpp | 2 +- 13 files changed, 395 insertions(+), 331 deletions(-) diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index 8947aa7d39..7fb0acfb20 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -494,32 +494,6 @@ bool Configuration::IsBuiltIn() const { static const size_t NOT_FOUND = static_cast(-1); -static std::size_t ExtractDuplicateNumber(const std::string& configuration_name) { - const std::size_t name_open = configuration_name.find_last_of("("); - if (name_open == NOT_FOUND) { - return NOT_FOUND; - } - - const std::size_t name_close = configuration_name.find_last_of(")"); - if (name_close == NOT_FOUND) { - return NOT_FOUND; - } - - const std::string number = configuration_name.substr(name_open + 1, name_close - (name_open + 1)); - if (!IsNumber(number)) { - return NOT_FOUND; - } - - return std::stoi(number); -} - -static std::string ExtractDuplicateBaseName(const std::string& configuration_name) { - assert(ExtractDuplicateNumber(configuration_name) != NOT_FOUND); - const std::size_t found = configuration_name.find_last_of("("); - assert(found != NOT_FOUND); - return configuration_name.substr(0, found - 1); -} - std::string MakeConfigurationName(const std::vector& configurations, const std::string& configuration_name) { const std::string key = configuration_name; const std::string base_name = ExtractDuplicateNumber(key) != NOT_FOUND ? ExtractDuplicateBaseName(key) : key; diff --git a/vkconfig_core/configurations/3.0.0/Frame Capture.json b/vkconfig_core/configurations/3.0.0/Frame Capture.json index f0503f0b5b..848c779df4 100644 --- a/vkconfig_core/configurations/3.0.0/Frame Capture.json +++ b/vkconfig_core/configurations/3.0.0/Frame Capture.json @@ -16,7 +16,7 @@ { "key": "capture_file", "type": "SAVE_FILE", - "value": "${VK_LOCAL}/gfxrecon_capture.gfxr" + "value": "${VK_HOME}/gfxrecon_capture.gfxr" } ], "control": "on", diff --git a/vkconfig_core/executable_manager.cpp b/vkconfig_core/executable_manager.cpp index 03858838a9..36c59c0304 100644 --- a/vkconfig_core/executable_manager.cpp +++ b/vkconfig_core/executable_manager.cpp @@ -21,6 +21,7 @@ #include "executable_manager.h" #include "version.h" #include "type_platform.h" +#include "util.h" #include #include @@ -57,6 +58,29 @@ bool ExecutableManager::Empty() const { return this->data.empty(); } std::size_t ExecutableManager::Size() const { return this->data.size(); } +static const size_t NOT_FOUND = static_cast(-1); + +std::string ExecutableManager::MakeOptionsName(const std::string& name) const { + const std::string key = name; + const std::string base_name = ExtractDuplicateNumber(key) != NOT_FOUND ? ExtractDuplicateBaseName(key) : key; + + const Executable* executable = GetActiveExecutable(); + + std::size_t max_duplicate = 0; + for (std::size_t i = 0, n = executable->options.size(); i < n; ++i) { + const std::string& search_name = executable->options[i].label; + + if (search_name.compare(0, base_name.length(), base_name) != 0) { + continue; + } + + const std::size_t found_number = ExtractDuplicateNumber(search_name); + max_duplicate = std::max(max_duplicate, found_number != NOT_FOUND ? found_number : 1); + } + + return base_name + (max_duplicate > 0 ? format(" (%d)", max_duplicate + 1).c_str() : ""); +} + bool ExecutableManager::Load(const QJsonObject& json_root_object) { // applications json object const QJsonObject& json_executables_object = json_root_object.value("executables").toObject(); @@ -88,6 +112,9 @@ bool ExecutableManager::Load(const QJsonObject& json_root_object) { ExecutableOptions executable_options; executable_options.label = json_options_object.value("label").toString().toStdString(); + executable_options.layers_mode = + GetLayersMode(json_options_object.value("layers_mode").toString().toStdString().c_str()); + executable_options.configuration = json_options_object.value("configuration").toString().toStdString(); executable_options.working_folder = json_options_object.value("working_folder").toString().toStdString(); const QJsonArray& json_command_lines_array = json_options_object.value("arguments").toArray(); @@ -165,9 +192,14 @@ bool ExecutableManager::Save(QJsonObject& json_root_object) const { return true; } -void ExecutableManager::SelectActiveExecutable(std::size_t executable_index) { - assert(executable_index < this->data.size()); - this->active_executable = this->data[executable_index].path; +void ExecutableManager::SetActiveExecutable(int executable_index) { + assert(executable_index < static_cast(this->data.size())); + + if (executable_index < 0) { + this->active_executable.Clear(); + } else { + this->active_executable = this->data[executable_index].path; + } } int ExecutableManager::GetActiveExecutableIndex() const { @@ -177,7 +209,6 @@ int ExecutableManager::GetActiveExecutableIndex() const { } } - assert(0); return -1; // Not found, but the list is present, so return the first item. } @@ -222,6 +253,13 @@ bool ExecutableManager::RemoveExecutable(std::size_t executable_index) { } std::swap(this->data, new_executables); + + if (this->data.empty()) { + this->active_executable.Clear(); + } else { + this->active_executable = this->data[0].path; + } + return true; } @@ -376,12 +414,14 @@ Executable ExecutableManager::CreateDefaultExecutable(const DefaultExecutable& d ExecutableOptions options; options.label = "Default"; options.working_folder = default_paths.working_folder; + options.args.push_back(default_executable.arguments); + // On all operating systems, but Windows we keep running into problems with this ending up // somewhere the user isn't allowed to create and write files. For consistncy sake, the log // initially will be set to the users home folder across all OS's. This is highly visible // in the application launcher and should not present a usability issue. The developer can // easily change this later to anywhere they like. - options.log_file = std::string("${VK_LOCAL}") + default_executable.key + ".txt"; + options.log_file = std::string("${VK_HOME}") + default_executable.key + ".txt"; Executable executable; executable.path = Path(default_paths.executable_path.AbsolutePath(), true); diff --git a/vkconfig_core/executable_manager.h b/vkconfig_core/executable_manager.h index 89ef872a28..2c1d36247e 100644 --- a/vkconfig_core/executable_manager.h +++ b/vkconfig_core/executable_manager.h @@ -39,7 +39,7 @@ struct DefaultPath { }; struct ExecutableOptions { - std::string label = "Default"; + std::string label = "Default Options"; LayersMode layers_mode = LAYERS_CONTROLLED_BY_APPLICATIONS; std::string configuration = "Validation"; Path working_folder; @@ -68,7 +68,9 @@ class ExecutableManager : public Serialize { bool Empty() const; std::size_t Size() const; - void SelectActiveExecutable(std::size_t executable_index); + std::string MakeOptionsName(const std::string& name) const; + + void SetActiveExecutable(int executable_index); int GetActiveExecutableIndex() const; bool AppendExecutable(const Executable& executable); bool AppendExecutable(const Path& executable_path); diff --git a/vkconfig_core/test/test_executable_manager.cpp b/vkconfig_core/test/test_executable_manager.cpp index 8e0a5e9e74..e23be1a6b9 100644 --- a/vkconfig_core/test/test_executable_manager.cpp +++ b/vkconfig_core/test/test_executable_manager.cpp @@ -38,10 +38,10 @@ TEST(test_executable_manager, reset_default_applications_sdk_found) { // Make sure the variable are not replaced EXPECT_TRUE(executables[0].path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); EXPECT_TRUE(executables[0].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); - EXPECT_TRUE(executables[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(executables[0].options[0].log_file.RelativePath().find("${VK_HOME}") != std::string::npos); EXPECT_TRUE(executables[1].path.RelativePath().find("${VULKAN_SDK}") != std::string::npos); EXPECT_TRUE(executables[1].options[0].working_folder.RelativePath().find("${VULKAN_SDK}") != std::string::npos); - EXPECT_TRUE(executables[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(executables[1].options[0].log_file.RelativePath().find("${VK_HOME}") != std::string::npos); } } @@ -58,10 +58,10 @@ TEST(test_executable_manager, reset_default_applications_no_sdk) { // Make sure the variable are not replaced EXPECT_TRUE(executables[0].path.RelativePath().find("vkcube") != std::string::npos); EXPECT_TRUE(executables[0].options[0].working_folder.RelativePath().find(".") != std::string::npos); - EXPECT_TRUE(executables[0].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(executables[0].options[0].log_file.RelativePath().find("${VK_HOME}") != std::string::npos); EXPECT_TRUE(executables[1].path.RelativePath().find("vkcubepp") != std::string::npos); EXPECT_TRUE(executables[1].options[0].working_folder.RelativePath().find(".") != std::string::npos); - EXPECT_TRUE(executables[1].options[0].log_file.RelativePath().find("${VK_LOCAL}") != std::string::npos); + EXPECT_TRUE(executables[1].options[0].log_file.RelativePath().find("${VK_HOME}") != std::string::npos); } TEST(test_executable_manager, remove_missing_applications) { diff --git a/vkconfig_core/util.cpp b/vkconfig_core/util.cpp index 545c7e51df..d8216921a7 100644 --- a/vkconfig_core/util.cpp +++ b/vkconfig_core/util.cpp @@ -343,3 +343,31 @@ std::string GetLayerSettingPrefix(const std::string& key) { result.remove("VK_LAYER_"); return ToLowerCase(result.toStdString()) + "."; } + +static const size_t NOT_FOUND = static_cast(-1); + +std::size_t ExtractDuplicateNumber(const std::string& name) { + const std::size_t name_open = name.find_last_of("("); + if (name_open == NOT_FOUND) { + return NOT_FOUND; + } + + const std::size_t name_close = name.find_last_of(")"); + if (name_close == NOT_FOUND) { + return NOT_FOUND; + } + + const std::string number = name.substr(name_open + 1, name_close - (name_open + 1)); + if (!IsNumber(number)) { + return NOT_FOUND; + } + + return std::stoi(number); +} + +std::string ExtractDuplicateBaseName(const std::string& name) { + assert(ExtractDuplicateNumber(name) != NOT_FOUND); + const std::size_t found = name.find_last_of("("); + assert(found != NOT_FOUND); + return name.substr(0, found - 1); +} diff --git a/vkconfig_core/util.h b/vkconfig_core/util.h index ea89c4dc46..15326c331e 100644 --- a/vkconfig_core/util.h +++ b/vkconfig_core/util.h @@ -165,3 +165,7 @@ std::vector GetVector(const T& value) { result.push_back(value); return result; } + +std::size_t ExtractDuplicateNumber(const std::string& name); + +std::string ExtractDuplicateBaseName(const std::string& name); diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 0f96e6535e..1a74b9334a 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -51,7 +51,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - _launch_application(nullptr), _tray_icon(nullptr), _tray_icon_menu(nullptr), _tray_restore_action(nullptr), @@ -103,7 +102,7 @@ MainWindow::MainWindow(QWidget *parent) this->UpdateUI(); } -MainWindow::~MainWindow() { this->ResetLaunchApplication(); } +MainWindow::~MainWindow() {} void MainWindow::InitTray() { if (QSystemTrayIcon::isSystemTrayAvailable()) { @@ -277,8 +276,6 @@ void MainWindow::UpdateUI() { ui->configurations_list->blockSignals(true); const bool has_application_list = !configurator.executables.GetExecutables().empty(); - ui->push_button_launcher->setText(_launch_application ? "Terminate" : "Launch"); - ui->check_box_clear_on_launch->setChecked(configurator.executables.launcher_clear_on_launch); // Mode states // this->UpdateUI_Status(); @@ -289,10 +286,6 @@ void MainWindow::UpdateUI() { --check_recurse; } -void MainWindow::on_check_box_clear_on_launch_clicked() { - Configurator::Get().executables.launcher_clear_on_launch = ui->check_box_clear_on_launch->isChecked(); -} - void MainWindow::toolsResetToDefault(bool checked) { (void)checked; @@ -410,11 +403,6 @@ void MainWindow::closeEvent(QCloseEvent *event) { } } - // If a child process is still running, destroy it - if (_launch_application) { - ResetLaunchApplication(); - } - this->tabs[this->ui->tab_widget->currentIndex()]->CleanUI(); QSettings settings("LunarG", VKCONFIG_SHORT_NAME); @@ -446,13 +434,6 @@ void MainWindow::showEvent(QShowEvent *event) { event->accept(); } -// Clear the browser window -void MainWindow::on_push_button_clear_log_clicked() { - ui->log_browser->clear(); - ui->log_browser->update(); - ui->push_button_clear_log->setEnabled(false); -} - bool MainWindow::eventFilter(QObject *target, QEvent *event) { if (this->tabs[this->ui->tab_widget->currentIndex()] == nullptr) { return false; @@ -461,166 +442,7 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { return this->tabs[this->ui->tab_widget->currentIndex()]->EventFilter(target, event); } -void MainWindow::ResetLaunchApplication() { - if (_launch_application) { - _launch_application->kill(); - _launch_application->waitForFinished(); - _launch_application.reset(); - - UpdateUI(); - } -} - -QStringList MainWindow::BuildEnvVariables() const { - Configurator &configurator = Configurator::Get(); - - QStringList env = QProcess::systemEnvironment(); - env << (QString("VK_LOADER_DEBUG=") + ::GetLogString(configurator.environment.GetLoaderMessageFlags()).c_str()); - return env; -} - void MainWindow::on_tab_widget_currentChanged(int index) { assert(index >= 0); this->tabs[index]->UpdateUI(UPDATE_REBUILD_UI); } - -void MainWindow::on_push_button_launcher_clicked() { - // Are we already monitoring a running app? If so, terminate it - if (_launch_application != nullptr) { - ResetLaunchApplication(); - return; - } - - // We are logging, let's add that we've launched a new application - std::string launch_log = "Launching Vulkan Application:\n"; - - Configurator &configurator = Configurator::Get(); - const Executable *active_executable = configurator.executables.GetActiveExecutable(); - - assert(!active_executable->path.Empty()); - launch_log += format("- Executable: %s\n", active_executable->path.AbsolutePath().c_str()); - if (!active_executable->path.Exists()) { - Alert::PathInvalid( - active_executable->path, - format("The '%s' application will fail to launch.", active_executable->path.AbsolutePath().c_str()).c_str()); - } - - const ExecutableOptions *options = active_executable->GetActiveOptions(); - - launch_log += format("- Working Directory: %s\n", options->working_folder.AbsolutePath().c_str()); - if (!options->working_folder.Exists()) { - Alert::PathInvalid( - options->working_folder, - format("The '%s' application will fail to launch.", active_executable->path.AbsolutePath().c_str()).c_str()); - } - /* - if (!_launcher_arguments->text().isEmpty()) { - launch_log += format("- Command-line Arguments: %s\n", _launcher_arguments->text().toStdString().c_str()); - } - */ - if (!options->log_file.Empty()) { - launch_log += format("- Log file: %s\n", options->log_file.AbsolutePath().c_str()); - } - - if (!options->log_file.Empty()) { - // Start logging - // Make sure the log file is not already opened. This can occur if the - // launched application is closed from the applicaiton. - if (!_log_file.isOpen()) { - _log_file.setFileName(options->log_file.AbsolutePath().c_str()); - - // Open and append, or open and truncate? - QIODevice::OpenMode mode = QIODevice::WriteOnly | QIODevice::Text; - if (!ui->check_box_clear_on_launch->isChecked()) mode |= QIODevice::Append; - - if (!_log_file.open(mode)) { - Alert::LogFileFailed(); - } - } - } - - if (ui->check_box_clear_on_launch->isChecked()) ui->log_browser->clear(); - Log(launch_log.c_str()); - - // Launch the test application - _launch_application.reset(new QProcess(this)); - connect(_launch_application.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(standardOutputAvailable())); - connect(_launch_application.get(), SIGNAL(readyReadStandardError()), this, SLOT(errorOutputAvailable())); - connect(_launch_application.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(processClosed(int, QProcess::ExitStatus))); - - //_launch_application->setProgram(ui->edit_executable->text()); - //_launch_application->setWorkingDirectory(ui->edit_dir->text()); - //_launch_application->setEnvironment(BuildEnvVariables() + ui->edit_env->text().split(",")); - - if (!options->args.empty()) { - const QStringList args = ConvertString(options->args); - _launch_application->setArguments(args); - } - - _launch_application->start(QIODevice::ReadOnly | QIODevice::Unbuffered); - _launch_application->setProcessChannelMode(QProcess::MergedChannels); - _launch_application->closeWriteChannel(); - - // Wait... did we start? Give it 4 seconds, more than enough time - if (!_launch_application->waitForStarted(4000)) { - _launch_application->deleteLater(); - _launch_application = nullptr; - - const std::string failed_log = std::string("Failed to launch ") + active_executable->path.AbsolutePath().c_str() + "!\n"; - Log(failed_log); - } - - UpdateUI(); -} - -/// The process we are following is closed. We don't actually care about the -/// exit status/code, we just need to know to destroy the QProcess object -/// and set it back to nullptr so that we know we can launch a new app. -/// Also, if we are logging, it's time to close the log file. -void MainWindow::processClosed(int exit_code, QProcess::ExitStatus status) { - (void)exit_code; - (void)status; - - assert(_launch_application); - - disconnect(_launch_application.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(processClosed(int, QProcess::ExitStatus))); - disconnect(_launch_application.get(), SIGNAL(readyReadStandardError()), this, SLOT(errorOutputAvailable())); - disconnect(_launch_application.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(standardOutputAvailable())); - - Log("Process terminated"); - - if (_log_file.isOpen()) { - _log_file.close(); - } - - ResetLaunchApplication(); -} - -/// This signal get's raised whenever the spawned Vulkan appliction writes -/// to stdout and there is data to be read. The layers flush after all stdout -/// writes, so we should see layer output here in realtime, as we just read -/// the string and append it to the text browser. -/// If a log file is open, we also write the output to the log. -void MainWindow::standardOutputAvailable() { - if (_launch_application) { - Log(_launch_application->readAllStandardOutput().toStdString()); - } -} - -void MainWindow::errorOutputAvailable() { - if (_launch_application) { - Log(_launch_application->readAllStandardError().toStdString()); - } -} - -void MainWindow::Log(const std::string &log) { - ui->log_browser->setPlainText(ui->log_browser->toPlainText() + "\n" + log.c_str()); - ui->push_button_clear_log->setEnabled(true); - - if (_log_file.isOpen()) { - _log_file.write(log.c_str(), log.size()); - _log_file.flush(); - } -} diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index 7e266e2e75..b03b588a74 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -31,16 +31,11 @@ #include "ui_mainwindow.h" -#include #include -#include -#include #include #include -#include #include -#include #include enum Tool { TOOL_VULKAN_INFO, TOOL_VULKAN_INSTALL }; @@ -55,9 +50,6 @@ class MainWindow : public QMainWindow { void UpdateUI(); private: - std::unique_ptr _launch_application; // Keeps track of the monitored app - QFile _log_file; // Log file for layer output - void closeEvent(QCloseEvent *event) override; void showEvent(QShowEvent *event) override; bool eventFilter(QObject *target, QEvent *event) override; @@ -65,8 +57,6 @@ class MainWindow : public QMainWindow { std::unique_ptr vk_info_dialog; std::unique_ptr vk_installation_dialog; - void Log(const std::string &log); - QSystemTrayIcon *_tray_icon; QMenu *_tray_icon_menu; QAction *_tray_restore_action; @@ -98,28 +88,6 @@ class MainWindow : public QMainWindow { void on_tab_widget_currentChanged(int index); - // Applications tabs - void on_push_button_launcher_clicked(); - void on_push_button_clear_log_clicked(); - void on_check_box_clear_on_launch_clicked(); - - void standardOutputAvailable(); // stdout output is available - void errorOutputAvailable(); // Layeroutput is available - void processClosed(int exitCode, QProcess::ExitStatus status); // app died - - /* - void launchItemExpanded(QTreeWidgetItem *item); - void launchItemCollapsed(QTreeWidgetItem *item); - void launchItemChanged(int index); - void launchSetLogFile(); - void launchSetExecutable(); - void launchSetWorkingFolder(); - void launchChangeLogFile(const QString &new_text); - void launchChangeExecutable(const QString &new_text); - void launchChangeWorkingFolder(const QString &new_text); - void launchArgsEdited(const QString &new_text); - */ - void UpdateUI_Status(); private: @@ -127,9 +95,7 @@ class MainWindow : public QMainWindow { MainWindow &operator=(const MainWindow &) = delete; void InitTray(); - void ResetLaunchApplication(); void StartTool(Tool tool); - QStringList BuildEnvVariables() const; std::shared_ptr ui; std::array, TAB_COUNT> tabs; diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index 8cf299ae5c..f59315e320 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -876,7 +876,7 @@ - + 0 @@ -944,7 +944,7 @@ - + 0 @@ -971,7 +971,7 @@ - + 0 @@ -991,7 +991,14 @@ 0 - + + + + 0 + 0 + + + @@ -1046,7 +1053,14 @@ - + + + + 0 + 0 + + + @@ -1085,7 +1099,7 @@ 0 - + 16777215 @@ -1095,7 +1109,7 @@ - + 32 @@ -1125,7 +1139,7 @@ - + 32 @@ -1189,7 +1203,7 @@ - + Arial @@ -1202,7 +1216,7 @@ - + Arial @@ -1218,7 +1232,7 @@ - + Arial @@ -1285,7 +1299,7 @@ - VK_LOCAL + VK_HOME @@ -1363,7 +1377,7 @@ - :/resourcefiles/lunarg_logo.png + :/resourcefiles/lunarg_logo.png Qt::TextBrowserInteraction @@ -1382,7 +1396,7 @@ - :/resourcefiles/qt_logo.png + :/resourcefiles/qt_logo.png @@ -1649,7 +1663,7 @@ - :/resourcefiles/vulkan_configurator.png + :/resourcefiles/vulkan_configurator.png true @@ -1759,8 +1773,6 @@ - - - + diff --git a/vkconfig_gui/tab_applications.cpp b/vkconfig_gui/tab_applications.cpp index d62b4a1a6e..f2f0e65138 100644 --- a/vkconfig_gui/tab_applications.cpp +++ b/vkconfig_gui/tab_applications.cpp @@ -22,43 +22,12 @@ #include "mainwindow.h" #include "../vkconfig_core/configurator.h" +#include "../vkconfig_core/alert.h" #include -/* - case PATH_EXECUTABLE: { - static const char* TABLE[] = { - "Applications (*.exe)", // PLATFORM_WINDOWS - "Applications (*)", // PLATFORM_LINUX - "Applications (*.app, *)", // PLATFORM_MACOS - "N/A" // PLATFORM_ANDROID - }; - static_assert(std::size(TABLE) == PLATFORM_COUNT, - "The tranlation table size doesn't match the enum number of elements"); - - const std::string filter = TABLE[VKC_PLATFORM]; - const std::string selected_path = QFileDialog::getOpenFileName(parent, "Select a Vulkan Executable...", - suggested_path.AbsolutePath().c_str(), filter.c_str()) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, QFileInfo(selected_path.c_str()).absolutePath().toStdString()); - return GetFullPath(path, QFileInfo(selected_path.c_str()).fileName().toStdString()); - } - case PATH_WORKING_DIR: { - const std::string selected_path = - QFileDialog::getExistingDirectory(parent, "Set Working Folder To...", suggested_path.AbsolutePath().c_str()) - .toStdString(); - if (selected_path.empty()) // The user cancelled - return Path(""); - - SetPath(path, selected_path); - return Path(GetPath(path)); - } -*/ - -TabApplications::TabApplications(MainWindow &window, std::shared_ptr ui) : Tab(TAB_APPLICATIONS, window, ui) { +TabApplications::TabApplications(MainWindow &window, std::shared_ptr ui) + : Tab(TAB_APPLICATIONS, window, ui), _launch_application(nullptr) { this->connect(this->ui->applications_remove_application_pushButton, SIGNAL(pressed()), this, SLOT(on_applications_remove_application_pushButton_pressed())); this->connect(this->ui->applications_append_application_pushButton, SIGNAL(pressed()), this, @@ -70,8 +39,8 @@ TabApplications::TabApplications(MainWindow &window, std::shared_ptrconnect(this->ui->applications_options_remove_pushButton, SIGNAL(pressed()), this, SLOT(on_applications_options_remove_pushButton_pressed())); - this->connect(this->ui->applications_options_duplicate_pushButton, SIGNAL(pressed()), this, - SLOT(on_applications_options_duplicate_pushButton_pressed())); + this->connect(this->ui->applications_options_append_pushButton, SIGNAL(pressed()), this, + SLOT(on_applications_options_append_pushButton_pressed())); this->connect(this->ui->applications_options_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_applications_options_comboBox_activated(int))); this->connect(this->ui->applications_options_comboBox, SIGNAL(editTextChanged(QString)), this, @@ -81,9 +50,16 @@ TabApplications::TabApplications(MainWindow &window, std::shared_ptrconnect(this->ui->applications_configuration_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_applications_configuration_comboBox_activated(int))); + + this->connect(this->ui->applications_push_button_launcher, SIGNAL(pressed()), this, + SLOT(on_applications_launcher_pushButton_pressed())); + this->connect(this->ui->applications_push_button_clear_log, SIGNAL(pressed()), this, + SLOT(on_applications_clear_log_pushButton_pressed())); + this->connect(this->ui->applications_check_box_clear_on_launch, SIGNAL(pressed()), this, + SLOT(on_applications_check_box_clear_on_launch_pressed())); } -TabApplications::~TabApplications() {} +TabApplications::~TabApplications() { this->ResetLaunchApplication(); } void TabApplications::UpdateUI(UpdateUIMode mode) { const Configurator &configurator = Configurator::Get(); @@ -110,10 +86,12 @@ void TabApplications::UpdateUI(UpdateUIMode mode) { ui->applications_list_comboBox->setCurrentIndex(configurator.executables.GetActiveExecutableIndex()); } + ui->applications_check_box_clear_on_launch->setChecked(configurator.executables.launcher_clear_on_launch); + this->on_applications_list_comboBox_activated(configurator.executables.GetActiveExecutableIndex()); } -void TabApplications::CleanUI() {} +void TabApplications::CleanUI() { this->ResetLaunchApplication(); } bool TabApplications::EventFilter(QObject *target, QEvent *event) { return false; } @@ -121,7 +99,7 @@ void TabApplications::on_applications_remove_application_pushButton_pressed() { Configurator &configurator = Configurator::Get(); configurator.executables.RemoveExecutable(ui->applications_list_comboBox->currentIndex()); - ui->applications_list_comboBox->setEnabled(!configurator.executables.Empty()); + this->EnableOptions(); this->UpdateUI(UPDATE_REBUILD_UI); } @@ -156,39 +134,57 @@ void TabApplications::on_applications_append_application_pushButton_pressed() { void TabApplications::on_applications_list_comboBox_activated(int index) { Configurator &configurator = Configurator::Get(); - configurator.executables.SelectActiveExecutable(index); + configurator.executables.SetActiveExecutable(index); const Executable *executable = configurator.executables.GetActiveExecutable(); - ui->applications_list_comboBox->setToolTip(executable->path.AbsolutePath().c_str()); - ui->applications_options_remove_pushButton->setEnabled(executable->options.size() > 1); + if (executable != nullptr) { + ui->applications_list_comboBox->setToolTip(executable->path.AbsolutePath().c_str()); + ui->applications_options_remove_pushButton->setEnabled(executable->options.size() > 1); + this->on_applications_options_comboBox_activated(executable->active_option_index); + } + ui->applications_options_list_layout->setEnabled(executable != nullptr); + ui->applications_options_layout->setEnabled(executable != nullptr); ui->applications_options_comboBox->blockSignals(true); ui->applications_options_comboBox->clear(); - for (std::size_t i = 0, n = executable->options.size(); i < n; ++i) { - ui->applications_options_comboBox->addItem(executable->options[i].label.c_str()); + if (executable != nullptr) { + for (std::size_t i = 0, n = executable->options.size(); i < n; ++i) { + ui->applications_options_comboBox->addItem(executable->options[i].label.c_str()); + } } ui->applications_options_comboBox->blockSignals(false); - ui->applications_options_comboBox->setCurrentIndex(executable->active_option_index); - - this->on_applications_options_comboBox_activated(executable->active_option_index); + ui->applications_options_comboBox->setCurrentIndex(index); } void TabApplications::on_applications_list_comboBox_textEdited(const QString &text) { Configurator &configurator = Configurator::Get(); Executable *executable = configurator.executables.GetActiveExecutable(); - executable->path = text.toStdString(); + if (executable != nullptr) { + executable->path = text.toStdString(); + } } void TabApplications::on_applications_options_remove_pushButton_pressed() { Configurator &configurator = Configurator::Get(); Executable *executable = configurator.executables.GetActiveExecutable(); - this->ui->applications_options_remove_pushButton->setEnabled(executable->options.size() > 1); + this->EnableOptions(); } -void TabApplications::on_applications_options_duplicate_pushButton_pressed() {} +void TabApplications::on_applications_options_append_pushButton_pressed() { + Configurator &configurator = Configurator::Get(); + Executable *executable = configurator.executables.GetActiveExecutable(); + + ExecutableOptions options = *executable->GetActiveOptions(); + options.label = configurator.executables.MakeOptionsName(options.label); + + executable->active_option_index = static_cast(executable->options.size()); + executable->options.push_back(options); + + this->UpdateUI(UPDATE_REBUILD_UI); +} void TabApplications::on_applications_options_comboBox_activated(int index) { Configurator &configurator = Configurator::Get(); @@ -205,22 +201,22 @@ void TabApplications::on_applications_options_comboBox_activated(int index) { ui->applications_directory_edit->setText(options->working_folder.RelativePath().c_str()); ui->applications_directory_edit->setToolTip(options->working_folder.AbsolutePath().c_str()); - ui->application_args_list->blockSignals(true); - ui->application_args_list->clear(); + ui->applications_args_list->blockSignals(true); + ui->applications_args_list->clear(); for (std::size_t i = 0, n = options->args.size(); i < n; ++i) { - ui->application_args_list->addItem(options->args[i].c_str()); + ui->applications_args_list->addItem(options->args[i].c_str()); } - ui->application_args_list->blockSignals(false); + ui->applications_args_list->blockSignals(false); - ui->application_envs_list->blockSignals(true); - ui->application_envs_list->clear(); + ui->applications_envs_list->blockSignals(true); + ui->applications_envs_list->clear(); for (std::size_t i = 0, n = options->envs.size(); i < n; ++i) { - ui->application_envs_list->addItem(options->envs[i].c_str()); + ui->applications_envs_list->addItem(options->envs[i].c_str()); } - ui->application_envs_list->blockSignals(false); + ui->applications_envs_list->blockSignals(false); - ui->application_output_log_edit->setText(options->log_file.RelativePath().c_str()); - ui->application_output_log_edit->setToolTip(options->log_file.AbsolutePath().c_str()); + ui->applications_output_log_edit->setText(options->log_file.RelativePath().c_str()); + ui->applications_output_log_edit->setToolTip(options->log_file.AbsolutePath().c_str()); } void TabApplications::on_applications_options_comboBox_textEdited(const QString &text) { @@ -249,3 +245,203 @@ void TabApplications::on_applications_configuration_comboBox_activated(int index options->configuration = ui->applications_configuration_comboBox->itemText(index).toStdString(); } + +void TabApplications::on_check_box_clear_on_launch_clicked() { + Configurator::Get().executables.launcher_clear_on_launch = ui->applications_check_box_clear_on_launch->isChecked(); +} + +void TabApplications::on_applications_clear_log_pushButton_pressed() { + ui->log_browser->clear(); + ui->log_browser->update(); + ui->applications_push_button_clear_log->setEnabled(false); +} + +void TabApplications::on_applications_launcher_pushButton_pressed() { + // Are we already monitoring a running app? If so, terminate it + if (_launch_application != nullptr) { + if (_launch_application->processId() > 0) { + this->ResetLaunchApplication(); + return; + } + } + + // We are logging, let's add that we've launched a new application + std::string launch_log = "Launching Vulkan Application:\n"; + + Configurator &configurator = Configurator::Get(); + const Executable *active_executable = configurator.executables.GetActiveExecutable(); + + assert(!active_executable->path.Empty()); + launch_log += format("- Executable: %s\n", active_executable->path.AbsolutePath().c_str()); + if (!active_executable->path.Exists()) { + Alert::PathInvalid( + active_executable->path, + format("The '%s' application will fail to launch.", active_executable->path.AbsolutePath().c_str()).c_str()); + } + + const ExecutableOptions *options = active_executable->GetActiveOptions(); + + launch_log += format("- Working Directory: %s\n", options->working_folder.AbsolutePath().c_str()); + if (!options->working_folder.Exists()) { + Alert::PathInvalid( + options->working_folder, + format("The '%s' application will fail to launch.", active_executable->path.AbsolutePath().c_str()).c_str()); + } + /* + if (!_launcher_arguments->text().isEmpty()) { + launch_log += format("- Command-line Arguments: %s\n", _launcher_arguments->text().toStdString().c_str()); + } + */ + if (!options->log_file.Empty()) { + launch_log += format("- Log file: %s\n", options->log_file.AbsolutePath().c_str()); + } + + if (!options->log_file.Empty()) { + // Start logging + // Make sure the log file is not already opened. This can occur if the + // launched application is closed from the applicaiton. + if (!this->_log_file.isOpen()) { + this->_log_file.setFileName(options->log_file.AbsolutePath().c_str()); + + // Open and append, or open and truncate? + QIODevice::OpenMode mode = QIODevice::WriteOnly | QIODevice::Text; + if (!ui->applications_check_box_clear_on_launch->isChecked()) { + mode |= QIODevice::Append; + } + + if (!this->_log_file.open(mode)) { + Alert::LogFileFailed(); + } + } + } + + if (ui->applications_check_box_clear_on_launch->isChecked()) { + ui->log_browser->clear(); + } + this->Log(launch_log.c_str()); + + // Launch the test application + if (_launch_application == nullptr) { + _launch_application.reset(new QProcess(this)); + this->connect(_launch_application.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(standardOutputAvailable())); + this->connect(_launch_application.get(), SIGNAL(readyReadStandardError()), this, SLOT(errorOutputAvailable())); + this->connect(_launch_application.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, + SLOT(processClosed(int, QProcess::ExitStatus))); + } + + this->_launch_application->setProgram(active_executable->path.AbsolutePath().c_str()); + this->_launch_application->setWorkingDirectory(options->working_folder.AbsolutePath().c_str()); + + Configuration *configuration = configurator.configurations.FindConfiguration(options->configuration); + + QStringList env = QProcess::systemEnvironment(); + env << (QString("VK_LOADER_DEBUG=") + ::GetLogString(configuration->loader_log_messages_flags).c_str()); + if (!options->envs.empty()) { + const QStringList envs = ConvertString(options->envs); + env << envs; + } + this->_launch_application->setEnvironment(env); + + if (!options->args.empty()) { + const QStringList args = ConvertString(options->args); + this->_launch_application->setArguments(args); + } + + this->ui->applications_push_button_launcher->setText("Terminate"); + this->_launch_application->start(QIODevice::ReadOnly | QIODevice::Unbuffered); + this->_launch_application->setProcessChannelMode(QProcess::MergedChannels); + this->_launch_application->closeWriteChannel(); + + // Wait... did we start? Give it 4 seconds, more than enough time + if (!this->_launch_application->waitForStarted(4000)) { + this->ui->applications_push_button_launcher->setText("Launch"); + + const std::string failed_log = std::string("Failed to launch ") + active_executable->path.AbsolutePath().c_str() + "!\n"; + this->Log(failed_log); + } +} + +void TabApplications::EnableOptions() { + Configurator &configurator = Configurator::Get(); + const bool executable_enabled = !configurator.executables.Empty(); + + const Executable *executable = configurator.executables.GetActiveExecutable(); + const bool options_enabled = executable_enabled && (executable == nullptr ? false : !executable->options.empty()); + + this->ui->applications_list_comboBox->setEnabled(executable_enabled); + this->ui->applications_remove_application_pushButton->setEnabled(executable_enabled); + + this->ui->applications_options_comboBox->setEnabled(executable_enabled); + this->ui->applications_options_remove_pushButton->setEnabled(executable_enabled ? (executable->options.size() > 1) : false); + this->ui->applications_options_append_pushButton->setEnabled(executable_enabled); + + this->ui->applications_layers_mode_comboBox->setEnabled(options_enabled); + this->ui->applications_directory_edit->setEnabled(options_enabled); + this->ui->applications_directory_edit_pushButton->setEnabled(options_enabled); + this->ui->applications_args_list->setEnabled(options_enabled); + this->ui->applications_envs_list->setEnabled(options_enabled); + this->ui->applications_output_log_edit->setEnabled(options_enabled); + this->ui->applications_output_log_pushButton->setEnabled(options_enabled); + + if (!options_enabled) { + this->ui->applications_directory_edit->clear(); + this->ui->applications_args_list->clear(); + this->ui->applications_envs_list->clear(); + this->ui->applications_output_log_edit->clear(); + } +} + +void TabApplications::ResetLaunchApplication() { + if (_launch_application->processId() > 0) { + this->_launch_application->kill(); + this->_launch_application->waitForFinished(); + } + + ui->applications_push_button_launcher->setText("Launch"); +} + +/// The process we are following is closed. We don't actually care about the +/// exit status/code, we just need to know to destroy the QProcess object +/// and set it back to nullptr so that we know we can launch a new app. +/// Also, if we are logging, it's time to close the log file. +void TabApplications::processClosed(int exit_code, QProcess::ExitStatus status) { + (void)exit_code; + (void)status; + + assert(_launch_application); + + Log("Process terminated"); + + if (_log_file.isOpen()) { + _log_file.close(); + } + + ResetLaunchApplication(); +} + +/// This signal get's raised whenever the spawned Vulkan appliction writes +/// to stdout and there is data to be read. The layers flush after all stdout +/// writes, so we should see layer output here in realtime, as we just read +/// the string and append it to the text browser. +/// If a log file is open, we also write the output to the log. +void TabApplications::standardOutputAvailable() { + if (_launch_application) { + this->Log(_launch_application->readAllStandardOutput().toStdString()); + } +} + +void TabApplications::errorOutputAvailable() { + if (_launch_application) { + this->Log(_launch_application->readAllStandardError().toStdString()); + } +} + +void TabApplications::Log(const std::string &log) { + ui->log_browser->setPlainText(ui->log_browser->toPlainText() + "\n" + log.c_str()); + ui->applications_push_button_clear_log->setEnabled(true); + + if (this->_log_file.isOpen()) { + this->_log_file.write(log.c_str(), log.size()); + this->_log_file.flush(); + } +} diff --git a/vkconfig_gui/tab_applications.h b/vkconfig_gui/tab_applications.h index a3f422d853..fcdf3f0890 100644 --- a/vkconfig_gui/tab_applications.h +++ b/vkconfig_gui/tab_applications.h @@ -22,6 +22,10 @@ #include "tab.h" +#include + +#include + struct TabApplications : public Tab { Q_OBJECT @@ -33,6 +37,8 @@ struct TabApplications : public Tab { virtual void CleanUI() override; virtual bool EventFilter(QObject* target, QEvent* event) override; + void ResetLaunchApplication(); + public Q_SLOTS: void on_applications_remove_application_pushButton_pressed(); void on_applications_append_application_pushButton_pressed(); @@ -40,12 +46,26 @@ struct TabApplications : public Tab { void on_applications_list_comboBox_textEdited(const QString& text); void on_applications_options_remove_pushButton_pressed(); - void on_applications_options_duplicate_pushButton_pressed(); + void on_applications_options_append_pushButton_pressed(); void on_applications_options_comboBox_activated(int index); void on_applications_options_comboBox_textEdited(const QString& text); void on_applications_layers_mode_comboBox_activated(int index); void on_applications_configuration_comboBox_activated(int index); + void on_applications_launcher_pushButton_pressed(); + void on_applications_clear_log_pushButton_pressed(); + void on_check_box_clear_on_launch_clicked(); + + void standardOutputAvailable(); // stdout output is available + void errorOutputAvailable(); // Layeroutput is available + void processClosed(int exitCode, QProcess::ExitStatus status); // app died + private: + void EnableOptions(); + + void Log(const std::string& log); + + std::unique_ptr _launch_application; // Keeps track of the monitored app + QFile _log_file; // Log file for layer output }; diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index 5c73794c4e..d3d2e1be74 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -742,7 +742,7 @@ void TabConfigurations::on_combo_box_mode_currentIndexChanged(int index) { void TabConfigurations::on_combo_box_applications_currentIndexChanged(int index) { Configurator &configurator = Configurator::Get(); - configurator.executables.SelectActiveExecutable(index); + configurator.executables.SetActiveExecutable(index); this->UpdateUI(UPDATE_REFRESH_UI); this->window.UpdateUI_Status(); From fd1dd65568ce83da09ec4231f7d37b1ac2c236ea Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 19 Sep 2024 17:49:23 +0200 Subject: [PATCH 28/33] vkconfig3: Implement applications options --- vkconfig_gui/mainwindow.ui | 26 ++----- vkconfig_gui/tab_applications.cpp | 113 +++++++++++++++++++++++++----- vkconfig_gui/tab_applications.h | 7 ++ 3 files changed, 107 insertions(+), 39 deletions(-) diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index f59315e320..23a4832d35 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -990,16 +990,6 @@ 0 - - - - - 0 - 0 - - - - @@ -1052,16 +1042,6 @@ - - - - - 0 - 0 - - - - @@ -1153,6 +1133,12 @@ + + + + + + diff --git a/vkconfig_gui/tab_applications.cpp b/vkconfig_gui/tab_applications.cpp index f2f0e65138..2d946299ad 100644 --- a/vkconfig_gui/tab_applications.cpp +++ b/vkconfig_gui/tab_applications.cpp @@ -51,12 +51,29 @@ TabApplications::TabApplications(MainWindow &window, std::shared_ptrconnect(this->ui->applications_configuration_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_applications_configuration_comboBox_activated(int))); + this->connect(this->ui->applications_directory_edit, SIGNAL(textEdited(QString)), this, + SLOT(on_applications_directory_edit_textEdited(QString))); + this->connect(this->ui->applications_directory_edit_pushButton, SIGNAL(pressed()), this, + SLOT(on_applications_directory_edit_pushButton_pressed())); + this->connect(this->ui->applications_args_list, SIGNAL(textEdited(QString)), this, + SLOT(on_applications_args_list_textEdited(QString))); + this->connect(this->ui->applications_envs_list, SIGNAL(textEdited(QString)), this, + SLOT(on_applications_envs_list_textEdited(QString))); + this->connect(this->ui->applications_output_log_edit, SIGNAL(textEdited(QString)), this, + SLOT(on_applications_output_log_edit_textEdited(QString))); + this->connect(this->ui->applications_output_log_pushButton, SIGNAL(pressed()), this, + SLOT(on_applications_output_log_pushButton_pressed())); + this->connect(this->ui->applications_push_button_launcher, SIGNAL(pressed()), this, SLOT(on_applications_launcher_pushButton_pressed())); this->connect(this->ui->applications_push_button_clear_log, SIGNAL(pressed()), this, SLOT(on_applications_clear_log_pushButton_pressed())); this->connect(this->ui->applications_check_box_clear_on_launch, SIGNAL(pressed()), this, SLOT(on_applications_check_box_clear_on_launch_pressed())); + + this->ui->applications_args_list->setToolTip("Eg: '--argA --argB'"); + this->ui->applications_envs_list->setToolTip(VKC_ENV == VKC_ENV_WIN32 ? "Eg: 'ENV_A=ValueA;ENV_B=ValueB'" + : "Eg: 'ENV_A=ValueA:ENV_B=ValueB'"); } TabApplications::~TabApplications() { this->ResetLaunchApplication(); } @@ -154,7 +171,7 @@ void TabApplications::on_applications_list_comboBox_activated(int index) { } } ui->applications_options_comboBox->blockSignals(false); - ui->applications_options_comboBox->setCurrentIndex(index); + ui->applications_options_comboBox->setCurrentIndex(executable->active_option_index); } void TabApplications::on_applications_list_comboBox_textEdited(const QString &text) { @@ -183,6 +200,8 @@ void TabApplications::on_applications_options_append_pushButton_pressed() { executable->active_option_index = static_cast(executable->options.size()); executable->options.push_back(options); + // this->ui->applications_options_comboBox->setCurrentIndex(executable->active_option_index); + this->UpdateUI(UPDATE_REBUILD_UI); } @@ -200,21 +219,8 @@ void TabApplications::on_applications_options_comboBox_activated(int index) { ui->applications_directory_edit->setText(options->working_folder.RelativePath().c_str()); ui->applications_directory_edit->setToolTip(options->working_folder.AbsolutePath().c_str()); - - ui->applications_args_list->blockSignals(true); - ui->applications_args_list->clear(); - for (std::size_t i = 0, n = options->args.size(); i < n; ++i) { - ui->applications_args_list->addItem(options->args[i].c_str()); - } - ui->applications_args_list->blockSignals(false); - - ui->applications_envs_list->blockSignals(true); - ui->applications_envs_list->clear(); - for (std::size_t i = 0, n = options->envs.size(); i < n; ++i) { - ui->applications_envs_list->addItem(options->envs[i].c_str()); - } - ui->applications_envs_list->blockSignals(false); - + ui->applications_args_list->setText(Merge(options->args, " ").c_str()); + ui->applications_envs_list->setText(Merge(options->envs, ",").c_str()); ui->applications_output_log_edit->setText(options->log_file.RelativePath().c_str()); ui->applications_output_log_edit->setToolTip(options->log_file.AbsolutePath().c_str()); } @@ -246,6 +252,73 @@ void TabApplications::on_applications_configuration_comboBox_activated(int index options->configuration = ui->applications_configuration_comboBox->itemText(index).toStdString(); } +void TabApplications::on_applications_directory_edit_textEdited(const QString &text) { + Configurator &configurator = Configurator::Get(); + + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); + + options->working_folder = text.toStdString(); +} + +void TabApplications::on_applications_directory_edit_pushButton_pressed() { + Configurator &configurator = Configurator::Get(); + + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); + + const QString selected_path = + QFileDialog::getExistingDirectory(this->ui->applications_directory_edit_pushButton, "Select Working Directory...", + this->ui->applications_directory_edit->text()); + + if (!selected_path.isEmpty()) { + options->working_folder = selected_path.toStdString(); + this->ui->applications_directory_edit->setText(options->working_folder.RelativePath().c_str()); + } +} + +void TabApplications::on_applications_args_list_textEdited(const QString &text) { + Configurator &configurator = Configurator::Get(); + + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); + + options->args = Split(text.toStdString(), " "); +} + +void TabApplications::on_applications_envs_list_textEdited(const QString &text) { + Configurator &configurator = Configurator::Get(); + + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); + + options->envs = Split(text.toStdString(), VKC_ENV == VKC_ENV_WIN32 ? ";" : ":"); +} + +void TabApplications::on_applications_output_log_edit_textEdited(const QString &text) { + Configurator &configurator = Configurator::Get(); + + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); + + options->log_file = text.toStdString(); +} + +void TabApplications::on_applications_output_log_pushButton_pressed() { + Configurator &configurator = Configurator::Get(); + + Executable *executable = configurator.executables.GetActiveExecutable(); + ExecutableOptions *options = executable->GetActiveOptions(); + + const QString selected_path = QFileDialog::getSaveFileName(this->ui->applications_output_log_pushButton, "Select Log file...", + this->ui->applications_output_log_edit->text(), "Log (*.txt)"); + + if (!selected_path.isEmpty()) { + options->log_file = selected_path.toStdString(); + this->ui->applications_output_log_edit->setText(options->log_file.RelativePath().c_str()); + } +} + void TabApplications::on_check_box_clear_on_launch_clicked() { Configurator::Get().executables.launcher_clear_on_launch = ui->applications_check_box_clear_on_launch->isChecked(); } @@ -392,9 +465,11 @@ void TabApplications::EnableOptions() { } void TabApplications::ResetLaunchApplication() { - if (_launch_application->processId() > 0) { - this->_launch_application->kill(); - this->_launch_application->waitForFinished(); + if (_launch_application != nullptr) { + if (_launch_application->processId() > 0) { + this->_launch_application->kill(); + this->_launch_application->waitForFinished(); + } } ui->applications_push_button_launcher->setText("Launch"); diff --git a/vkconfig_gui/tab_applications.h b/vkconfig_gui/tab_applications.h index fcdf3f0890..0d44dc0849 100644 --- a/vkconfig_gui/tab_applications.h +++ b/vkconfig_gui/tab_applications.h @@ -53,6 +53,13 @@ struct TabApplications : public Tab { void on_applications_layers_mode_comboBox_activated(int index); void on_applications_configuration_comboBox_activated(int index); + void on_applications_directory_edit_textEdited(const QString& text); + void on_applications_directory_edit_pushButton_pressed(); + void on_applications_args_list_textEdited(const QString& text); + void on_applications_envs_list_textEdited(const QString& text); + void on_applications_output_log_edit_textEdited(const QString& text); + void on_applications_output_log_pushButton_pressed(); + void on_applications_launcher_pushButton_pressed(); void on_applications_clear_log_pushButton_pressed(); void on_check_box_clear_on_launch_clicked(); From 5a556514524cb382759fa3deac987b1d7c5fb8db Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 19 Sep 2024 18:48:35 +0200 Subject: [PATCH 29/33] vkconfig3: Don't allow implicit layer forced on --- vkconfig_core/alert.h | 1 + vkconfig_core/type_layer_control.cpp | 2 +- vkconfig_core/type_layer_control.h | 9 ++++++--- vkconfig_gui/widget_tab_configurations_layer.cpp | 12 ++++++++++-- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/vkconfig_core/alert.h b/vkconfig_core/alert.h index 38e030dfae..fa5a4b1029 100644 --- a/vkconfig_core/alert.h +++ b/vkconfig_core/alert.h @@ -33,6 +33,7 @@ struct Alert { static void LayerInvalid(const Path& path, const char* message); static QMessageBox::Button LayerImplicit(const char* layer_name); + static QMessageBox::Button LayerProfiles(); static void PathInvalid(const Path& path, const char* message); diff --git a/vkconfig_core/type_layer_control.cpp b/vkconfig_core/type_layer_control.cpp index 42c4675d72..607127c1ea 100644 --- a/vkconfig_core/type_layer_control.cpp +++ b/vkconfig_core/type_layer_control.cpp @@ -28,8 +28,8 @@ const char* GetToken(LayerControl control) { static const char* TOKENS[] = { "Auto", // LAYER_CONTROL_AUTO - "On", // LAYER_CONTROL_ON "Off", // LAYER_CONTROL_OFF + "On", // LAYER_CONTROL_ON "application_enabled_layers", // LAYER_CONTROL_APPLICATIONS "unordered_layer_location" // LAYER_CONTROL_UNORDERED }; diff --git a/vkconfig_core/type_layer_control.h b/vkconfig_core/type_layer_control.h index 2ca084da6c..0150b7f26f 100644 --- a/vkconfig_core/type_layer_control.h +++ b/vkconfig_core/type_layer_control.h @@ -22,16 +22,19 @@ enum LayerControl { LAYER_CONTROL_AUTO = 0, - LAYER_CONTROL_ON, LAYER_CONTROL_OFF, + LAYER_CONTROL_ON, LAYER_CONTROL_APPLICATIONS_API, LAYER_CONTROL_APPLICATIONS_ENV, LAYER_CONTROL_FIRST = LAYER_CONTROL_AUTO, LAYER_CONTROL_LAST = LAYER_CONTROL_APPLICATIONS_ENV, - LAYER_CONTROL_UI_FIRST = LAYER_CONTROL_AUTO, - LAYER_CONTROL_UI_LAST = LAYER_CONTROL_OFF + LAYER_CONTROL_EXPLICIT_FIRST = LAYER_CONTROL_AUTO, + LAYER_CONTROL_EXPLICIT_LAST = LAYER_CONTROL_ON, + + LAYER_CONTROL_IMPLICIT_FIRST = LAYER_CONTROL_AUTO, + LAYER_CONTROL_IMPLICIT_LAST = LAYER_CONTROL_OFF }; enum { LAYER_CONTROL_COUNT = LAYER_CONTROL_LAST - LAYER_CONTROL_FIRST + 1 }; diff --git a/vkconfig_gui/widget_tab_configurations_layer.cpp b/vkconfig_gui/widget_tab_configurations_layer.cpp index 150f312a78..3958c58acf 100644 --- a/vkconfig_gui/widget_tab_configurations_layer.cpp +++ b/vkconfig_gui/widget_tab_configurations_layer.cpp @@ -128,8 +128,16 @@ ConfigurationLayerWidget::ConfigurationLayerWidget(TabConfigurations *tab, const // this->layer_version->installEventFilter(this); this->layer_state = new QComboBox(this); - for (int i = LAYER_CONTROL_UI_FIRST; i <= LAYER_CONTROL_UI_LAST; ++i) { - this->layer_state->addItem(GetToken(static_cast(i))); + if (layer != nullptr) { + if (layer->type == LAYER_TYPE_EXPLICIT) { + for (int i = LAYER_CONTROL_EXPLICIT_FIRST; i <= LAYER_CONTROL_EXPLICIT_LAST; ++i) { + this->layer_state->addItem(GetToken(static_cast(i))); + } + } else { + for (int i = LAYER_CONTROL_IMPLICIT_FIRST; i <= LAYER_CONTROL_IMPLICIT_LAST; ++i) { + this->layer_state->addItem(GetToken(static_cast(i))); + } + } } this->layer_state->setEnabled(!layer_versions.empty()); this->layer_state->setCurrentIndex(parameter.control); From 2e62c870e06315a55d740e41a29c3fb406461363 Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 26 Sep 2024 16:48:04 +0200 Subject: [PATCH 30/33] vkconfig3: Add unit tests for layer paths --- vkconfig_core/layer_manager.cpp | 15 ++++- vkconfig_core/layer_manager.h | 6 +- vkconfig_core/test/test_layer_manager.cpp | 69 +++++++++++++++++++++++ vkconfig_gui/tab_layers.cpp | 4 +- vkconfig_gui/widget_tab_layers_path.cpp | 2 +- 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index 4e898a5476..d6c166b935 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -180,7 +180,7 @@ bool LayerManager::Load(const QJsonObject &json_root_object) { LayersPathInfo info; info.path = json_paths_keys[i].toStdString(); info.enabled = json_paths_object.value(json_paths_keys[i].toStdString().c_str()).toBool(); - this->AddPath(info); + this->AppendPath(info); } } } @@ -351,7 +351,7 @@ void LayerManager::LoadLayersFromPath(const Path &layers_path, LayerType type) { } } -void LayerManager::AddPath(const LayersPathInfo &info) { +void LayerManager::AppendPath(const LayersPathInfo &info) { LayersPathInfo *existing_info = FindPathInfo(this->paths, info.path.RelativePath()); if (existing_info != nullptr) { existing_info->enabled = info.enabled; @@ -389,7 +389,16 @@ void LayerManager::RemovePath(const LayersPathInfo &path_info) { } } -void LayerManager::UpdatePath(const LayersPathInfo &path_info) { +void LayerManager::UpdatePathEnabled(const LayersPathInfo &path_info) { + for (int paths_type_index = LAYERS_PATHS_FIRST; paths_type_index <= LAYERS_PATHS_LAST; ++paths_type_index) { + for (std::size_t i = 0, n = this->paths[paths_type_index].size(); i < n; ++i) { + if (path_info.path == this->paths[paths_type_index][i].path) { + this->paths[paths_type_index][i].enabled = path_info.enabled; + break; + } + } + } + const std::vector &layers_paths = CollectFilePaths(path_info.path); for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index c35e3c6918..063b18a6e9 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -62,15 +62,15 @@ class LayerManager : public Serialize { void LoadAllInstalledLayers(); void LoadLayersFromPath(const Path& layers_path, LayerType type = LAYER_TYPE_EXPLICIT); - void AddPath(const LayersPathInfo& path_info); + void AppendPath(const LayersPathInfo& path_info); void RemovePath(const LayersPathInfo& path_info); - void UpdatePath(const LayersPathInfo& path_info); + void UpdatePathEnabled(const LayersPathInfo& path_info); std::vector BuildLayerNameList() const; std::vector selected_layers; std::array, LAYERS_PATHS_COUNT> paths; - std::vector removed_paths; + std::vector removed_paths; // TODO: Remove? private: std::map layers_validated; diff --git a/vkconfig_core/test/test_layer_manager.cpp b/vkconfig_core/test/test_layer_manager.cpp index e987c32ee1..8abc82489d 100644 --- a/vkconfig_core/test/test_layer_manager.cpp +++ b/vkconfig_core/test/test_layer_manager.cpp @@ -186,3 +186,72 @@ TEST(test_layer_manager, avoid_duplicate) { EXPECT_EQ(first_load_count, second_load_count); } + +TEST(test_layer_manager, custom_path_append_remove) { + LayerManager layer_manager; + + LayersPathInfo infoA; + infoA.path = ":/layers"; + LayersPathInfo infoB; + infoB.path = ":/layersB"; + LayersPathInfo infoC; + infoC.path = ":/layersC"; + + layer_manager.AppendPath(infoA); + layer_manager.AppendPath(infoB); + layer_manager.AppendPath(infoC); + + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 3); + + layer_manager.AppendPath(infoA); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 3); + + layer_manager.RemovePath(infoA); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 2); + + layer_manager.AppendPath(infoA); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 3); + + layer_manager.RemovePath(infoA); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 2); + + layer_manager.RemovePath(infoA); // Check that removing an already removed path doesn't cause any issue + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 2); + + layer_manager.RemovePath(infoB); + layer_manager.RemovePath(infoC); + + EXPECT_TRUE(layer_manager.paths[LAYERS_PATHS_GUI].empty()); +} + +TEST(test_layer_manager, custom_path_update_layers) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + LayersPathInfo info; + info.path = ":/layers"; + // info.enabled = true; default value + + layer_manager.AppendPath(info); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 1); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI][0].enabled, true); + for (std::size_t i = 0, n = layer_manager.selected_layers.size(); i < n; ++i) { + EXPECT_TRUE(layer_manager.selected_layers[i].visible); + } + + info.enabled = false; + layer_manager.UpdatePathEnabled(info); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI][0].enabled, false); + for (std::size_t i = 0, n = layer_manager.selected_layers.size(); i < n; ++i) { + EXPECT_FALSE(layer_manager.selected_layers[i].visible); + } + + info.enabled = true; + layer_manager.UpdatePathEnabled(info); + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI][0].enabled, true); + for (std::size_t i = 0, n = layer_manager.selected_layers.size(); i < n; ++i) { + EXPECT_TRUE(layer_manager.selected_layers[i].visible); + } + + EXPECT_EQ(layer_manager.paths[LAYERS_PATHS_GUI].size(), 1); +} diff --git a/vkconfig_gui/tab_layers.cpp b/vkconfig_gui/tab_layers.cpp index da37364063..d6e2bbc798 100644 --- a/vkconfig_gui/tab_layers.cpp +++ b/vkconfig_gui/tab_layers.cpp @@ -108,7 +108,7 @@ void TabLayers::on_layers_add_pushButton_pressed() { Configurator &configurator = Configurator::Get(); LayersPathInfo info; info.path = ui->layers_lineEdit->text().toStdString(); - configurator.layers.AddPath(info); + configurator.layers.AppendPath(info); configurator.layers.LoadLayersFromPath(info.path); this->UpdateUI_LayersPaths(UPDATE_REBUILD_UI); @@ -125,7 +125,7 @@ void TabLayers::on_layers_browse_pushButton_pressed() { info.path = selected_path.toStdString(); Configurator &configurator = Configurator::Get(); - configurator.layers.AddPath(info); + configurator.layers.AppendPath(info); configurator.layers.LoadLayersFromPath(info.path); this->UpdateUI_LayersPaths(UPDATE_REBUILD_UI); diff --git a/vkconfig_gui/widget_tab_layers_path.cpp b/vkconfig_gui/widget_tab_layers_path.cpp index 48986020f5..1a71c8c5f8 100644 --- a/vkconfig_gui/widget_tab_layers_path.cpp +++ b/vkconfig_gui/widget_tab_layers_path.cpp @@ -59,5 +59,5 @@ void LayersPathWidget::on_toggled(bool checked) { this->path_info->enabled = checked; Configurator& configurator = Configurator::Get(); - configurator.layers.UpdatePath(*this->path_info); + configurator.layers.UpdatePathEnabled(*this->path_info); } From 26d65032072ec4af7a6a22601efa6d053b5098c7 Mon Sep 17 00:00:00 2001 From: Christophe Date: Thu, 26 Sep 2024 17:59:09 +0200 Subject: [PATCH 31/33] vkconfig3: Fix new configuration and add unit tests --- vkconfig_core/configuration.cpp | 10 +- vkconfig_core/configuration.h | 2 +- vkconfig_core/configuration_manager.cpp | 39 +++-- vkconfig_core/configuration_manager.h | 3 +- vkconfig_core/test/test_configuration.cpp | 191 +++++++++++++++++++++- vkconfig_gui/tab_configurations.cpp | 5 +- 6 files changed, 228 insertions(+), 22 deletions(-) diff --git a/vkconfig_core/configuration.cpp b/vkconfig_core/configuration.cpp index 7fb0acfb20..acd2998afa 100644 --- a/vkconfig_core/configuration.cpp +++ b/vkconfig_core/configuration.cpp @@ -79,10 +79,10 @@ static void AddApplicationEnabledParameters(std::vector& parameters) } } -Configuration Configuration::Create(const LayerManager& layers, const std::string& key) { +Configuration Configuration::Create(const LayerManager& layers, const std::string& configuration_key) { Configuration result; - result.key = key; + result.key = configuration_key; result.GatherParameters(layers); AddApplicationEnabledParameters(result.parameters); @@ -409,7 +409,7 @@ void Configuration::SwitchLayerVersion(const LayerManager& layers, const std::st const Layer* new_layer = layers.Find(layer_key, version); - parameter->api_version = version; + parameter->api_version = new_layer->api_version == version ? version : Version::LATEST; CollectDefaultSettingData(new_layer->settings, parameter->settings); } @@ -455,7 +455,9 @@ void Configuration::Reorder(const std::vector& layer_names) { for (std::size_t i = 0, n = layer_names.size(); i < n; ++i) { Parameter* parameter = this->Find(layer_names[i]); - assert(parameter != nullptr); + if (parameter == nullptr) { + continue; + } ordered_parameters.push_back(*parameter); } diff --git a/vkconfig_core/configuration.h b/vkconfig_core/configuration.h index b0c0dc97ec..ff876a18c0 100644 --- a/vkconfig_core/configuration.h +++ b/vkconfig_core/configuration.h @@ -34,7 +34,7 @@ class LayerManager; class Configuration { public: static Configuration CreateDisabled(const LayerManager& layers); - static Configuration Create(const LayerManager& layers, const std::string& layer_key); + static Configuration Create(const LayerManager& layers, const std::string& configuration_key); bool Load(const Path& full_path, const LayerManager& layers); bool Save(const Path& full_path, bool exporter = false) const; diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index d7365e096b..74507f29be 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -255,27 +255,40 @@ bool ConfigurationManager::HasActiveConfiguration() const { return false; } -Configuration &ConfigurationManager::CreateConfiguration(const LayerManager &layers, const std::string &configuration_name, - bool duplicate) { - Configuration *duplicate_configuration = this->FindConfiguration(configuration_name); +Configuration &ConfigurationManager::CreateConfiguration(const LayerManager &layers, const std::string &configuration_name) { + std::string configuration_key = MakeConfigurationName(available_configurations, configuration_name); - Configuration new_configuration = duplicate_configuration != nullptr && duplicate ? *duplicate_configuration : Configuration(); - new_configuration.key = MakeConfigurationName(available_configurations, configuration_name); + Configuration new_configuration = Configuration::Create(layers, configuration_key); - const Path &path(MakeConfigurationPath(new_configuration.key)); - new_configuration.Save(path); + this->available_configurations.push_back(new_configuration); + this->SortConfigurations(); + + this->GetActiveConfigurationInfo()->name = new_configuration.key; + + return *this->FindConfiguration(new_configuration.key); +} + +Configuration &ConfigurationManager::DuplicateConfiguration(const LayerManager &layers, const std::string &configuration_name) { + Configuration *source_configuration = this->FindConfiguration(configuration_name); + assert(source_configuration != nullptr); + + Configuration duplicated_configuration = *source_configuration; + duplicated_configuration.key = MakeConfigurationName(available_configurations, configuration_name); + + const Path &path = MakeConfigurationPath(duplicated_configuration.key); + duplicated_configuration.Save(path); // Reload from file to workaround the lack of SettingSet copy support - Configuration configuration; - const bool result = configuration.Load(path, layers); + Configuration reloaded_configuration; + const bool result = reloaded_configuration.Load(path, layers); assert(result); - this->available_configurations.push_back(configuration); - this->SortConfigurations(); + this->available_configurations.push_back(reloaded_configuration); + this->SortConfigurations(); // invalidated all pointers to configuration object - this->GetActiveConfigurationInfo()->name = configuration.key; + this->GetActiveConfigurationInfo()->name = reloaded_configuration.key; - return *this->FindConfiguration(configuration.key); + return *this->FindConfiguration(reloaded_configuration.key); } bool ConfigurationManager::HasFile(const Configuration &configuration) const { diff --git a/vkconfig_core/configuration_manager.h b/vkconfig_core/configuration_manager.h index b154315aa6..4cf63ab51c 100644 --- a/vkconfig_core/configuration_manager.h +++ b/vkconfig_core/configuration_manager.h @@ -48,7 +48,8 @@ class ConfigurationManager : public Serialize { const std::map& GetConfigurationInfos() const; bool HasActiveConfiguration() const; - Configuration& CreateConfiguration(const LayerManager& layers, const std::string& configuration_name, bool duplicate = false); + Configuration& CreateConfiguration(const LayerManager& layers, const std::string& configuration_name); + Configuration& DuplicateConfiguration(const LayerManager& layers, const std::string& configuration_name); void RemoveConfiguration(const std::string& configuration_name); int GetConfigurationIndex(const std::string& configuration_name) const; diff --git a/vkconfig_core/test/test_configuration.cpp b/vkconfig_core/test/test_configuration.cpp index 8c457dd198..4a36cc9c06 100644 --- a/vkconfig_core/test/test_configuration.cpp +++ b/vkconfig_core/test/test_configuration.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020-2021 Valve Corporation - * Copyright (c) 2020-2021 LunarG, Inc. + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ */ #include "../configuration.h" +#include "../layer_manager.h" #include "../util.h" #include @@ -195,3 +196,189 @@ TEST(test_configuration, make_duplicate_tagged_name_mix) { EXPECT_STREQ("Tag Configuration (tag) Bla", new_name.c_str()); EXPECT_TRUE(!new_name.empty()); } + +TEST(test_configuration, create) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration = Configuration::Create(layer_manager, "New Configuration"); + + bool has_app_api = false; + bool has_app_env = false; + + for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { + if (configuration.parameters[i].control == LAYER_CONTROL_APPLICATIONS_API) { + has_app_api = true; + continue; + } + + if (configuration.parameters[i].control == LAYER_CONTROL_APPLICATIONS_ENV) { + has_app_env = true; + continue; + } + + EXPECT_EQ(configuration.parameters[i].control, LAYER_CONTROL_AUTO); + } + + EXPECT_EQ(has_app_api, true); + EXPECT_EQ(has_app_env, true); +} + +TEST(test_configuration, create_disabled) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration = Configuration::CreateDisabled(layer_manager); + + bool has_app_api = false; + bool has_app_env = false; + + for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { + if (configuration.parameters[i].control == LAYER_CONTROL_APPLICATIONS_API) { + has_app_api = true; + continue; + } + + if (configuration.parameters[i].control == LAYER_CONTROL_APPLICATIONS_ENV) { + has_app_env = true; + continue; + } + + EXPECT_EQ(configuration.parameters[i].control, LAYER_CONTROL_OFF); + } + + EXPECT_EQ(has_app_api, true); + EXPECT_EQ(has_app_env, true); +} + +TEST(test_configuration, SwitchLayerVersion) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration = Configuration::Create(layer_manager, "New Configuration"); + for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { + EXPECT_EQ(configuration.parameters[i].api_version, Version::LATEST); + } + Parameter* parameter_latest = configuration.Find("VK_LAYER_LUNARG_version"); + EXPECT_EQ(parameter_latest->api_version, Version::LATEST); + + configuration.SwitchLayerVersion(layer_manager, "VK_LAYER_LUNARG_version", Version(1, 3, 204)); + Parameter* parameter_204 = configuration.Find("VK_LAYER_LUNARG_version"); + EXPECT_EQ(parameter_204->api_version, Version(1, 3, 204)); + + configuration.SwitchLayerVersion(layer_manager, "VK_LAYER_LUNARG_version", Version::LATEST); + Parameter* parameter_restore = configuration.Find("VK_LAYER_LUNARG_version"); + EXPECT_EQ(parameter_restore->api_version, Version::LATEST); + + configuration.SwitchLayerVersion(layer_manager, "VK_LAYER_LUNARG_version", Version(1, 3, 205)); + Parameter* parameter_version_not_found = configuration.Find("VK_LAYER_LUNARG_version"); + EXPECT_EQ(parameter_version_not_found->api_version, Version::LATEST); +} + +TEST(test_configuration, Reorder_full) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration = Configuration::Create(layer_manager, "New Configuration"); + + std::vector layer_names; + layer_names.push_back("VK_LAYER_LUNARG_test_04"); + layer_names.push_back("VK_LAYER_LUNARG_test_01"); + layer_names.push_back("VK_LAYER_LUNARG_test_02"); + layer_names.push_back("Vulkan Layers from the Application Vulkan API"); + layer_names.push_back("Vulkan Layers from Application Environment Variables"); + layer_names.push_back("VK_LAYER_LUNARG_version"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_2_1"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_2_0"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_1_0"); + layer_names.push_back("VK_LAYER_LUNARG_test_00"); + layer_names.push_back("VK_LAYER_LUNARG_test_05"); + layer_names.push_back("VK_LAYER_LUNARG_test_06"); + layer_names.push_back("VK_LAYER_LUNARG_test_03"); + + configuration.Reorder(layer_names); + + EXPECT_STREQ(configuration.parameters[0].key.c_str(), "VK_LAYER_LUNARG_test_04"); + EXPECT_STREQ(configuration.parameters[1].key.c_str(), "VK_LAYER_LUNARG_test_01"); + EXPECT_STREQ(configuration.parameters[2].key.c_str(), "VK_LAYER_LUNARG_test_02"); + EXPECT_STREQ(configuration.parameters[3].key.c_str(), "Vulkan Layers from the Application Vulkan API"); + EXPECT_STREQ(configuration.parameters[4].key.c_str(), "Vulkan Layers from Application Environment Variables"); + EXPECT_STREQ(configuration.parameters[5].key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_STREQ(configuration.parameters[6].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_1"); + EXPECT_STREQ(configuration.parameters[7].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_0"); + EXPECT_STREQ(configuration.parameters[8].key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); + EXPECT_STREQ(configuration.parameters[9].key.c_str(), "VK_LAYER_LUNARG_test_00"); + EXPECT_STREQ(configuration.parameters[10].key.c_str(), "VK_LAYER_LUNARG_test_05"); + EXPECT_STREQ(configuration.parameters[11].key.c_str(), "VK_LAYER_LUNARG_test_06"); + EXPECT_STREQ(configuration.parameters[12].key.c_str(), "VK_LAYER_LUNARG_test_03"); +} + +TEST(test_configuration, Reorder_partial) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration = Configuration::Create(layer_manager, "New Configuration"); + + std::vector layer_names; + layer_names.push_back("VK_LAYER_LUNARG_test_04"); + layer_names.push_back("Vulkan Layers from the Application Vulkan API"); + layer_names.push_back("VK_LAYER_LUNARG_version"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_2_1"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_2_0"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_1_0"); + layer_names.push_back("VK_LAYER_LUNARG_test_06"); + layer_names.push_back("VK_LAYER_LUNARG_test_03"); + + configuration.Reorder(layer_names); + + EXPECT_STREQ(configuration.parameters[0].key.c_str(), "VK_LAYER_LUNARG_test_04"); + EXPECT_STREQ(configuration.parameters[1].key.c_str(), "Vulkan Layers from the Application Vulkan API"); + EXPECT_STREQ(configuration.parameters[2].key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_STREQ(configuration.parameters[3].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_1"); + EXPECT_STREQ(configuration.parameters[4].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_0"); + EXPECT_STREQ(configuration.parameters[5].key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); + EXPECT_STREQ(configuration.parameters[6].key.c_str(), "VK_LAYER_LUNARG_test_06"); + EXPECT_STREQ(configuration.parameters[7].key.c_str(), "VK_LAYER_LUNARG_test_03"); +} + +TEST(test_configuration, Reorder_missing) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration = Configuration::Create(layer_manager, "New Configuration"); + + std::vector layer_names; + layer_names.push_back("VK_LAYER_LUNARG_test_04"); + layer_names.push_back("Vulkan Layers from the Application Vulkan API"); + layer_names.push_back("VK_LAYER_LUNARG_missing_0"); + layer_names.push_back("VK_LAYER_LUNARG_version"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_2_1"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_2_0"); + layer_names.push_back("VK_LAYER_LUNARG_reference_1_1_0"); + layer_names.push_back("VK_LAYER_LUNARG_test_06"); + layer_names.push_back("VK_LAYER_LUNARG_test_03"); + layer_names.push_back("VK_LAYER_LUNARG_missing_1"); + + configuration.Reorder(layer_names); + + EXPECT_STREQ(configuration.parameters[0].key.c_str(), "VK_LAYER_LUNARG_test_04"); + EXPECT_STREQ(configuration.parameters[1].key.c_str(), "Vulkan Layers from the Application Vulkan API"); + EXPECT_STREQ(configuration.parameters[2].key.c_str(), "VK_LAYER_LUNARG_version"); + EXPECT_STREQ(configuration.parameters[3].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_1"); + EXPECT_STREQ(configuration.parameters[4].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_0"); + EXPECT_STREQ(configuration.parameters[5].key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); + EXPECT_STREQ(configuration.parameters[6].key.c_str(), "VK_LAYER_LUNARG_test_06"); + EXPECT_STREQ(configuration.parameters[7].key.c_str(), "VK_LAYER_LUNARG_test_03"); +} + +TEST(test_configuration, Reorder_empty) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration = Configuration::Create(layer_manager, "New Configuration"); + + std::vector layer_names; + configuration.Reorder(layer_names); + + EXPECT_TRUE(configuration.parameters.empty()); +} diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index d3d2e1be74..e3253a39a8 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -587,6 +587,9 @@ void TabConfigurations::OnContextMenuNewClicked(ConfigurationListItem *item) { configurator.Override(OVERRIDE_AREA_ALL); this->UpdateUI_Configurations(UPDATE_REBUILD_UI); + this->UpdateUI_LoaderMessages(); + this->UpdateUI_Layers(UPDATE_REBUILD_UI); + this->UpdateUI_Settings(UPDATE_REBUILD_UI); } void TabConfigurations::OnContextMenuImportClicked(ConfigurationListItem *item) { @@ -629,7 +632,7 @@ void TabConfigurations::OnContextMenuDuplicateClicked(ConfigurationListItem *ite Configurator &configurator = Configurator::Get(); const Configuration &duplicated_configuration = - configurator.configurations.CreateConfiguration(configurator.layers, item->configuration_name, true); + configurator.configurations.DuplicateConfiguration(configurator.layers, item->configuration_name); item->configuration_name = duplicated_configuration.key; From 612381dddbafcb5e1821b174c4adde0fb0ad2455 Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 27 Sep 2024 15:28:31 +0200 Subject: [PATCH 32/33] vkconfig3: Add more unit tests --- vkconfig_core/configuration_manager.cpp | 62 +--- vkconfig_core/configuration_manager.h | 8 - vkconfig_core/layer_manager.cpp | 11 +- vkconfig_core/layer_manager.h | 1 - vkconfig_core/test/CMakeLists.txt | 1 + vkconfig_core/test/test_configuration.cpp | 144 +++++++++ .../test/test_configuration_manager.cpp | 125 ++++++++ vkconfig_core/test/test_configurator.cpp | 25 ++ vkconfig_core/test/test_layer_manager.cpp | 25 ++ vkconfig_core/test/test_parameter.cpp | 282 +++--------------- 10 files changed, 376 insertions(+), 308 deletions(-) create mode 100644 vkconfig_core/test/test_configurator.cpp diff --git a/vkconfig_core/configuration_manager.cpp b/vkconfig_core/configuration_manager.cpp index 74507f29be..afc71a3e3f 100644 --- a/vkconfig_core/configuration_manager.cpp +++ b/vkconfig_core/configuration_manager.cpp @@ -213,7 +213,10 @@ void ConfigurationManager::SaveAllConfigurations() const { const ConfigurationInfo *ConfigurationManager::GetActiveConfigurationInfo() const { if (this->use_per_executable_configuration) { - return &this->configuration_infos.find(this->active_executable.c_str())->second; + if (this->active_executable.empty()) + return nullptr; + else + return &this->configuration_infos.find(this->active_executable.c_str())->second; } else { return &this->configuration_infos.find(GLOBAL_CONFIGURATION_TOKEN)->second; } @@ -237,10 +240,6 @@ const ConfigurationInfo *ConfigurationManager::FindConfigurationInfo(const std:: return nullptr; } -const std::map &ConfigurationManager::GetConfigurationInfos() const { - return this->configuration_infos; -} - bool ConfigurationManager::HasActiveConfiguration() const { if (this->GetActiveConfigurationInfo() == nullptr) { return false; @@ -255,6 +254,10 @@ bool ConfigurationManager::HasActiveConfiguration() const { return false; } +const std::map &ConfigurationManager::GetConfigurationInfos() const { + return this->configuration_infos; +} + Configuration &ConfigurationManager::CreateConfiguration(const LayerManager &layers, const std::string &configuration_name) { std::string configuration_key = MakeConfigurationName(available_configurations, configuration_name); @@ -359,7 +362,6 @@ int ConfigurationManager::GetConfigurationIndex(const std::string &configuration } } - assert(0); return -1; } @@ -446,54 +448,6 @@ void ConfigurationManager::ExportConfiguration(const LayerManager &layers, const } } -bool ConfigurationManager::CheckApiVersions(const std::vector &available_layers, Configuration *selected_configuration, - std::string &log_versions) const { - return this->CompareLayersVersions(available_layers, selected_configuration, Version::VKCONFIG, log_versions, true); -} - -bool ConfigurationManager::CheckLayersVersions(const std::vector &available_layers, Configuration *selected_configuration, - std::string &log_versions) const { - return this->CompareLayersVersions(available_layers, selected_configuration, Version::NONE, log_versions, false); -} - -bool ConfigurationManager::CompareLayersVersions(const std::vector &available_layers, Configuration *selected_configuration, - const Version &version, std::string &log_versions, bool is_less) const { - assert(selected_configuration != nullptr); - - Version current_version = version; - - bool result = true; - - for (std::size_t param_index = 0, param_count = selected_configuration->parameters.size(); param_index < param_count; - ++param_index) { - const Parameter ¶meter = selected_configuration->parameters[param_index]; - - if (parameter.control != LAYER_CONTROL_ON) { - continue; - } - - for (std::size_t layer_index = 0, layer_count = available_layers.size(); layer_index < layer_count; ++layer_index) { - const Layer &layer = available_layers[layer_index]; - - if (layer.key == parameter.key) { - if (current_version == Version::NONE) { - current_version = layer.api_version; - } - - if (is_less) { - if (layer.api_version.GetMinor() > version.GetMinor()) result = false; - } else { - if (layer.api_version.GetMinor() != current_version.GetMinor()) result = false; - } - - log_versions += format("%s - %s\n", layer.key.c_str(), layer.api_version.str().c_str()); - } - } - } - - return result; -} - bool ConfigurationManager::GetPerExecutableConfig() const { return this->use_per_executable_configuration; } void ConfigurationManager::SetPerExecutableConfig(bool enabled) { this->use_per_executable_configuration = enabled; } diff --git a/vkconfig_core/configuration_manager.h b/vkconfig_core/configuration_manager.h index 4cf63ab51c..258cc246bc 100644 --- a/vkconfig_core/configuration_manager.h +++ b/vkconfig_core/configuration_manager.h @@ -61,11 +61,6 @@ class ConfigurationManager : public Serialize { void SortConfigurations(); - bool CheckLayersVersions(const std::vector& available_layers, Configuration* selected_configuration, - std::string& log_versions) const; - bool CheckApiVersions(const std::vector& available_layers, Configuration* selected_configuration, - std::string& log_versions) const; - bool Empty() const { return available_configurations.empty(); } bool HasFile(const Configuration& configuration) const; @@ -82,9 +77,6 @@ class ConfigurationManager : public Serialize { Path last_path_export; private: - bool CompareLayersVersions(const std::vector& available_layers, Configuration* selected_configuration, - const Version& version, std::string& log_versions, bool is_less) const; - void RemoveConfigurationFiles(); void LoadConfigurationsPath(const LayerManager& layers); diff --git a/vkconfig_core/layer_manager.cpp b/vkconfig_core/layer_manager.cpp index d6c166b935..902001b114 100644 --- a/vkconfig_core/layer_manager.cpp +++ b/vkconfig_core/layer_manager.cpp @@ -140,7 +140,8 @@ bool LayerManager::Load(const QJsonObject &json_root_object) { // LAYERS_PATHS_ENV_ADD: VK_ADD_LAYER_PATH env variables { - const std::vector &VK_ADD_LAYER_PATH = UniqueStrings(Split(qgetenv("VK_ADD_LAYER_PATH").toStdString(), SEPARATOR)); + const std::vector &VK_ADD_LAYER_PATH = + UniqueStrings(Split(qgetenv("VK_ADD_LAYER_PATH").toStdString(), SEPARATOR)); this->paths[LAYERS_PATHS_ENV_ADD].resize(VK_ADD_LAYER_PATH.size()); for (std::size_t i = 0, n = VK_ADD_LAYER_PATH.size(); i < n; ++i) { this->paths[LAYERS_PATHS_ENV_ADD][i].path = VK_ADD_LAYER_PATH[i]; @@ -206,15 +207,9 @@ bool LayerManager::Save(QJsonObject &json_root_object) const { } } - QJsonArray json_removed_paths_array; - for (std::size_t i = 0, n = this->removed_paths.size(); i < n; ++i) { - json_removed_paths_array.append(this->removed_paths[i].RelativePath().c_str()); - } - QJsonObject json_layers_object; json_layers_object.insert("validated", json_layers_paths_object); json_layers_object.insert("paths", json_paths_object); - json_layers_object.insert("removed_paths", json_removed_paths_array); json_root_object.insert("layers", json_layers_object); @@ -363,8 +358,6 @@ void LayerManager::AppendPath(const LayersPathInfo &info) { } void LayerManager::RemovePath(const LayersPathInfo &path_info) { - this->removed_paths.push_back(path_info.path); - const std::vector &layers_paths = CollectFilePaths(path_info.path); for (std::size_t i = 0, n = layers_paths.size(); i < n; ++i) { diff --git a/vkconfig_core/layer_manager.h b/vkconfig_core/layer_manager.h index 063b18a6e9..f68b95bc74 100644 --- a/vkconfig_core/layer_manager.h +++ b/vkconfig_core/layer_manager.h @@ -70,7 +70,6 @@ class LayerManager : public Serialize { std::vector selected_layers; std::array, LAYERS_PATHS_COUNT> paths; - std::vector removed_paths; // TODO: Remove? private: std::map layers_validated; diff --git a/vkconfig_core/test/CMakeLists.txt b/vkconfig_core/test/CMakeLists.txt index 1b6369742f..457a5f25bf 100644 --- a/vkconfig_core/test/CMakeLists.txt +++ b/vkconfig_core/test/CMakeLists.txt @@ -63,6 +63,7 @@ vkConfigTest(test_path) vkConfigTest(test_configuration) vkConfigTest(test_configuration_built_in) vkConfigTest(test_configuration_manager) +vkConfigTest(test_configurator) vkConfigTest(test_executable_manager) vkConfigTest(test_override) vkConfigTest(test_application_singleton) diff --git a/vkconfig_core/test/test_configuration.cpp b/vkconfig_core/test/test_configuration.cpp index 4a36cc9c06..8ba4f74138 100644 --- a/vkconfig_core/test/test_configuration.cpp +++ b/vkconfig_core/test/test_configuration.cpp @@ -275,6 +275,150 @@ TEST(test_configuration, SwitchLayerVersion) { EXPECT_EQ(parameter_version_not_found->api_version, Version::LATEST); } +TEST(test_configuration, gather_parameters_exist) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration; + configuration.key = "New Configuration"; + + configuration.GatherParameters(layer_manager); + + EXPECT_STREQ(configuration.parameters[0].key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); + EXPECT_STREQ(configuration.parameters[1].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_0"); + EXPECT_STREQ(configuration.parameters[2].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_1"); + + EXPECT_STREQ(configuration.parameters[3].key.c_str(), "VK_LAYER_LUNARG_test_00"); + EXPECT_STREQ(configuration.parameters[4].key.c_str(), "VK_LAYER_LUNARG_test_01"); + EXPECT_STREQ(configuration.parameters[5].key.c_str(), "VK_LAYER_LUNARG_test_02"); + EXPECT_STREQ(configuration.parameters[6].key.c_str(), "VK_LAYER_LUNARG_test_03"); + EXPECT_STREQ(configuration.parameters[7].key.c_str(), "VK_LAYER_LUNARG_test_04"); + EXPECT_STREQ(configuration.parameters[8].key.c_str(), "VK_LAYER_LUNARG_test_05"); + EXPECT_STREQ(configuration.parameters[9].key.c_str(), "VK_LAYER_LUNARG_test_06"); + + EXPECT_STREQ(configuration.parameters[10].key.c_str(), "VK_LAYER_LUNARG_version"); + + std::string missing_layer; + EXPECT_FALSE(HasMissingLayer(configuration.parameters, layer_manager, missing_layer)); + EXPECT_TRUE(missing_layer.empty()); +} + +TEST(test_configuration, gather_parameters_repeat) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + Configuration configuration; + configuration.key = "New Configuration"; + + configuration.GatherParameters(layer_manager); + configuration.GatherParameters(layer_manager); // Again, check for no duplication! + + EXPECT_STREQ(configuration.parameters[0].key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); + EXPECT_STREQ(configuration.parameters[1].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_0"); + EXPECT_STREQ(configuration.parameters[2].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_1"); + + EXPECT_STREQ(configuration.parameters[3].key.c_str(), "VK_LAYER_LUNARG_test_00"); + EXPECT_STREQ(configuration.parameters[4].key.c_str(), "VK_LAYER_LUNARG_test_01"); + EXPECT_STREQ(configuration.parameters[5].key.c_str(), "VK_LAYER_LUNARG_test_02"); + EXPECT_STREQ(configuration.parameters[6].key.c_str(), "VK_LAYER_LUNARG_test_03"); + EXPECT_STREQ(configuration.parameters[7].key.c_str(), "VK_LAYER_LUNARG_test_04"); + EXPECT_STREQ(configuration.parameters[8].key.c_str(), "VK_LAYER_LUNARG_test_05"); + EXPECT_STREQ(configuration.parameters[9].key.c_str(), "VK_LAYER_LUNARG_test_06"); + + EXPECT_STREQ(configuration.parameters[10].key.c_str(), "VK_LAYER_LUNARG_version"); +} + +TEST(test_configuration, gather_parameters_missing) { + LayerManager layer_manager; + + Configuration configuration; + configuration.key = "New Configuration"; + + layer_manager.LoadLayersFromPath(":/layers"); + configuration.GatherParameters(layer_manager); + + layer_manager.Clear(); + configuration.GatherParameters(layer_manager); + + EXPECT_STREQ(configuration.parameters[0].key.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); + EXPECT_STREQ(configuration.parameters[1].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_0"); + EXPECT_STREQ(configuration.parameters[2].key.c_str(), "VK_LAYER_LUNARG_reference_1_2_1"); + + EXPECT_STREQ(configuration.parameters[3].key.c_str(), "VK_LAYER_LUNARG_test_00"); + EXPECT_STREQ(configuration.parameters[4].key.c_str(), "VK_LAYER_LUNARG_test_01"); + EXPECT_STREQ(configuration.parameters[5].key.c_str(), "VK_LAYER_LUNARG_test_02"); + EXPECT_STREQ(configuration.parameters[6].key.c_str(), "VK_LAYER_LUNARG_test_03"); + EXPECT_STREQ(configuration.parameters[7].key.c_str(), "VK_LAYER_LUNARG_test_04"); + EXPECT_STREQ(configuration.parameters[8].key.c_str(), "VK_LAYER_LUNARG_test_05"); + EXPECT_STREQ(configuration.parameters[9].key.c_str(), "VK_LAYER_LUNARG_test_06"); + + EXPECT_STREQ(configuration.parameters[10].key.c_str(), "VK_LAYER_LUNARG_version"); + + std::string missing_layer; + EXPECT_TRUE(HasMissingLayer(configuration.parameters, layer_manager, missing_layer)); + EXPECT_STREQ(missing_layer.c_str(), "VK_LAYER_LUNARG_reference_1_1_0"); +} + +TEST(test_configuration, HasMissingLayer_UnsupportPlatform) { + LayerManager layer_manager; + + Configuration configuration; + configuration.key = "New Configuration"; + + layer_manager.LoadLayersFromPath(":/layers"); + configuration.GatherParameters(layer_manager); + + layer_manager.Clear(); + + for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { + configuration.parameters[i].platform_flags = 0; + } + + std::string missing_layer; + EXPECT_FALSE(HasMissingLayer(configuration.parameters, layer_manager, missing_layer)); + EXPECT_TRUE(missing_layer.empty()); +} + +TEST(test_configuration, HasMissingLayer_Off) { + LayerManager layer_manager; + + Configuration configuration; + configuration.key = "New Configuration"; + + layer_manager.LoadLayersFromPath(":/layers"); + configuration.GatherParameters(layer_manager); + + layer_manager.Clear(); + + for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { + configuration.parameters[i].control = LAYER_CONTROL_OFF; + } + + std::string missing_layer; + EXPECT_FALSE(HasMissingLayer(configuration.parameters, layer_manager, missing_layer)); + EXPECT_TRUE(missing_layer.empty()); +} + +TEST(test_configuration, gather_parameters_missing_but_unsupported_platform) { + LayerManager layer_manager; + + Configuration configuration; + configuration.key = "New Configuration"; + + layer_manager.LoadLayersFromPath(":/layers"); + configuration.GatherParameters(layer_manager); + + layer_manager.Clear(); + + for (std::size_t i = 0, n = configuration.parameters.size(); i < n; ++i) { + configuration.parameters[i].platform_flags = 0; + } + + std::string missing_layer; + EXPECT_FALSE(HasMissingLayer(configuration.parameters, layer_manager, missing_layer)); + EXPECT_TRUE(missing_layer.empty()); +} + TEST(test_configuration, Reorder_full) { LayerManager layer_manager; layer_manager.LoadLayersFromPath(":/layers"); diff --git a/vkconfig_core/test/test_configuration_manager.cpp b/vkconfig_core/test/test_configuration_manager.cpp index 067210f934..5d14ba035d 100644 --- a/vkconfig_core/test/test_configuration_manager.cpp +++ b/vkconfig_core/test/test_configuration_manager.cpp @@ -22,6 +22,24 @@ #include +TEST(test_configuration_manager, init_default) { + ConfigurationManager configuration_manager; + + const ConfigurationInfo* info_global = configuration_manager.FindConfigurationInfo(GLOBAL_CONFIGURATION_TOKEN); + EXPECT_TRUE(info_global != nullptr); + const ConfigurationInfo* info_unknown = configuration_manager.FindConfigurationInfo("unknown"); + EXPECT_TRUE(info_unknown == nullptr); + const ConfigurationInfo* info_active = configuration_manager.GetActiveConfigurationInfo(); + EXPECT_EQ(info_active, info_global); + + EXPECT_FALSE(configuration_manager.GetUseSystemTray()); + EXPECT_FALSE(configuration_manager.GetPerExecutableConfig()); + EXPECT_TRUE(configuration_manager.HasActiveConfiguration()); + EXPECT_TRUE(configuration_manager.Empty()); + EXPECT_TRUE(configuration_manager.last_path_import.Empty()); + EXPECT_TRUE(configuration_manager.last_path_export.Empty()); +} + TEST(test_configuration_manager, create_remove) { LayerManager layer_manager; layer_manager.LoadLayersFromPath(":/layers"); @@ -53,3 +71,110 @@ TEST(test_configuration_manager, create_remove) { configuration_manager.RemoveConfiguration(configuration_duplicate_key.c_str()); EXPECT_EQ(true, configuration_manager.Empty()); } + +TEST(test_configuration_manager, duplicate_names) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + ConfigurationManager configuration_manager; + + // Create configuration + configuration_manager.CreateConfiguration(layer_manager, "Configuration A"); + EXPECT_EQ(1, configuration_manager.available_configurations.size()); + + std::string dup2 = configuration_manager.DuplicateConfiguration(layer_manager, "Configuration A").key; + EXPECT_EQ(2, configuration_manager.available_configurations.size()); + Configuration* configuration2 = configuration_manager.FindConfiguration("Configuration A (2)"); + EXPECT_STREQ(configuration2->key.c_str(), dup2.c_str()); + + std::string dup3 = configuration_manager.DuplicateConfiguration(layer_manager, "Configuration A (2)").key; + EXPECT_EQ(3, configuration_manager.available_configurations.size()); + Configuration* configuration3 = configuration_manager.FindConfiguration("Configuration A (3)"); + EXPECT_STREQ(configuration3->key.c_str(), dup3.c_str()); + + std::string dup4 = configuration_manager.DuplicateConfiguration(layer_manager, "Configuration A").key; + EXPECT_EQ(4, configuration_manager.available_configurations.size()); + Configuration* configuration4 = configuration_manager.FindConfiguration("Configuration A (4)"); + EXPECT_STREQ(configuration4->key.c_str(), dup4.c_str()); +} + +TEST(test_configuration_manager, duplicate_object) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + ConfigurationManager configuration_manager; + + // Create configuration + configuration_manager.CreateConfiguration(layer_manager, "Configuration A"); + EXPECT_EQ(1, configuration_manager.available_configurations.size()); + + std::string dup2 = configuration_manager.DuplicateConfiguration(layer_manager, "Configuration A").key; + EXPECT_EQ(2, configuration_manager.available_configurations.size()); + + Configuration* configuration_ori = configuration_manager.FindConfiguration("Configuration A"); + Configuration* configuration_dup = configuration_manager.FindConfiguration("Configuration A (2)"); + + EXPECT_EQ(configuration_ori->version, configuration_dup->version); + EXPECT_EQ(configuration_ori->platform_flags, configuration_dup->platform_flags); + EXPECT_EQ(configuration_ori->description, configuration_dup->description); + EXPECT_EQ(configuration_ori->view_advanced_settings, configuration_dup->view_advanced_settings); + EXPECT_EQ(configuration_ori->view_advanced_layers, configuration_dup->view_advanced_layers); + EXPECT_EQ(configuration_ori->loader_log_messages_flags, configuration_dup->loader_log_messages_flags); + EXPECT_EQ(configuration_ori->selected_layer_name, configuration_dup->selected_layer_name); + EXPECT_EQ(configuration_ori->parameters.size(), configuration_dup->parameters.size()); + EXPECT_EQ(configuration_ori->user_defined_paths, configuration_dup->user_defined_paths); + EXPECT_EQ(configuration_ori->IsBuiltIn(), configuration_dup->IsBuiltIn()); + EXPECT_EQ(configuration_ori->Size(), configuration_dup->Size()); +} + +TEST(test_configuration_manager, sort) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + ConfigurationManager configuration_manager; + + configuration_manager.CreateConfiguration(layer_manager, "Configuration A"); + configuration_manager.CreateConfiguration(layer_manager, "Configuration 2"); + configuration_manager.CreateConfiguration(layer_manager, "Configuration 1"); + configuration_manager.CreateConfiguration(layer_manager, "Configuration B"); + configuration_manager.CreateConfiguration(layer_manager, "Configuration 3"); + + configuration_manager.SortConfigurations(); + + EXPECT_STREQ("Configuration 1", configuration_manager.available_configurations[0].key.c_str()); + EXPECT_STREQ("Configuration 2", configuration_manager.available_configurations[1].key.c_str()); + EXPECT_STREQ("Configuration 3", configuration_manager.available_configurations[2].key.c_str()); + EXPECT_STREQ("Configuration A", configuration_manager.available_configurations[3].key.c_str()); + EXPECT_STREQ("Configuration B", configuration_manager.available_configurations[4].key.c_str()); +} + +TEST(test_configuration_manager, get_index) { + LayerManager layer_manager; + layer_manager.LoadLayersFromPath(":/layers"); + + ConfigurationManager configuration_manager; + + configuration_manager.CreateConfiguration(layer_manager, "Configuration B"); + EXPECT_EQ(1, configuration_manager.available_configurations.size()); + EXPECT_EQ(0, configuration_manager.GetConfigurationIndex("Configuration B")); + + configuration_manager.CreateConfiguration(layer_manager, "Configuration A"); + EXPECT_EQ(2, configuration_manager.available_configurations.size()); + EXPECT_EQ(0, configuration_manager.GetConfigurationIndex("Configuration A")); + EXPECT_EQ(1, configuration_manager.GetConfigurationIndex("Configuration B")); + + configuration_manager.CreateConfiguration(layer_manager, "Configuration C"); + EXPECT_EQ(3, configuration_manager.available_configurations.size()); + EXPECT_EQ(0, configuration_manager.GetConfigurationIndex("Configuration A")); + EXPECT_EQ(1, configuration_manager.GetConfigurationIndex("Configuration B")); + EXPECT_EQ(2, configuration_manager.GetConfigurationIndex("Configuration C")); + + std::string configuration_a2_key = configuration_manager.CreateConfiguration(layer_manager, "Configuration A").key; + EXPECT_EQ(4, configuration_manager.available_configurations.size()); + EXPECT_EQ(0, configuration_manager.GetConfigurationIndex("Configuration A")); + EXPECT_EQ(1, configuration_manager.GetConfigurationIndex("Configuration A (2)")); + EXPECT_EQ(2, configuration_manager.GetConfigurationIndex("Configuration B")); + EXPECT_EQ(3, configuration_manager.GetConfigurationIndex("Configuration C")); + + EXPECT_EQ(-1, configuration_manager.GetConfigurationIndex("Configuration D")); +} diff --git a/vkconfig_core/test/test_configurator.cpp b/vkconfig_core/test/test_configurator.cpp new file mode 100644 index 0000000000..2b58a03152 --- /dev/null +++ b/vkconfig_core/test/test_configurator.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "../configurator.h" + +#include + +TEST(test_configurator, init) { EXPECT_TRUE(true); } diff --git a/vkconfig_core/test/test_layer_manager.cpp b/vkconfig_core/test/test_layer_manager.cpp index 8abc82489d..06d9a65198 100644 --- a/vkconfig_core/test/test_layer_manager.cpp +++ b/vkconfig_core/test/test_layer_manager.cpp @@ -30,6 +30,31 @@ TEST(test_layer_manager, clear) { EXPECT_TRUE(layer_manager.Size() == 0); } +TEST(test_layer_manager, load_json) { + QJsonObject json_object; + + LayerManager layer_manager; + bool result = layer_manager.Load(json_object); + EXPECT_TRUE(result); +} + +TEST(test_layer_manager, save_json) { + QJsonObject json_root_object; + + LayerManager layer_manager; + bool result = layer_manager.Save(json_root_object); + EXPECT_TRUE(result); + + EXPECT_TRUE(json_root_object.value("layers") != QJsonValue::Undefined); + + if (json_root_object.value("layers") != QJsonValue::Undefined) { + const QJsonObject& json_layers_object = json_root_object.value("layers").toObject(); + + EXPECT_TRUE(json_layers_object.value("validated") != QJsonValue::Undefined); + EXPECT_TRUE(json_layers_object.value("paths") != QJsonValue::Undefined); + } +} + TEST(test_layer_manager, load_all) { LayerManager layer_manager; layer_manager.LoadLayersFromPath(":/layers"); diff --git a/vkconfig_core/test/test_parameter.cpp b/vkconfig_core/test/test_parameter.cpp index 0db2cca793..16d4ff5ec4 100644 --- a/vkconfig_core/test/test_parameter.cpp +++ b/vkconfig_core/test/test_parameter.cpp @@ -24,11 +24,11 @@ #include "../setting_string.h" #include -/* + inline SettingMetaString* InstantiateString(Layer& layer, const std::string& key) { return static_cast(layer.Instantiate(layer.settings, key, SETTING_STRING)); } - +/* static std::vector GenerateTestLayers() { std::vector layers; layers.push_back(Layer("Layer E0", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 148), "1", "layer.json")); @@ -42,7 +42,7 @@ static std::vector GenerateTestLayers() { layers.push_back(Layer("Layer C2", LAYER_TYPE_USER_DEFINED, Version(1, 0, 0), Version(1, 2, 148), "1", "layer.json")); return layers; } - +*/ static std::vector GenerateTestParametersExist() { std::vector parameters; parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_ON)); @@ -53,10 +53,10 @@ static std::vector GenerateTestParametersExist() { static std::vector GenerateTestParametersImplicitOrdering() { std::vector parameters; - parameters.push_back(Parameter("Layer I0", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer I1", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E0", LAYER_STATE_OVERRIDDEN)); - parameters.push_back(Parameter("Layer E1", LAYER_STATE_OVERRIDDEN)); + parameters.push_back(Parameter("Layer I0", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer I1", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_ON)); + parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); return parameters; } @@ -93,14 +93,48 @@ static std::vector GenerateTestParametersAll() { return parameters; } -TEST(test_parameter, ordering_no_layers) { - std::vector layers; +TEST(test_parameter, apply_settings) { + Layer layer; + + SettingMetaString* metaA = InstantiateString(layer, "A"); + SettingMetaString* metaB = InstantiateString(layer, "B"); + + SettingDataString* preset_setting = Instantiate(metaA); + preset_setting->value = "preset value"; + + LayerPreset preset; + preset.settings.push_back(preset_setting); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_CONTROL_AUTO))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_CONTROL_ON))); - EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer", LAYER_CONTROL_OFF))); + SettingDataString* layer_setting_a = Instantiate(metaA); + layer_setting_a->value = "setting value"; + + SettingDataString* layer_setting_b = Instantiate(metaB); + layer_setting_b->value = "setting value"; + + Parameter parameter; + parameter.settings.push_back(layer_setting_a); + parameter.settings.push_back(layer_setting_b); + + EXPECT_EQ(1, preset.settings.size()); + EXPECT_EQ(2, parameter.settings.size()); + + parameter.ApplyPresetSettings(preset); + + EXPECT_EQ(1, preset.settings.size()); + EXPECT_EQ(2, parameter.settings.size()); + + EXPECT_STREQ("preset value", static_cast(FindSetting(parameter.settings, "A"))->value.c_str()); + EXPECT_STREQ("setting value", static_cast(FindSetting(parameter.settings, "B"))->value.c_str()); } +TEST(test_parameter, ordering_no_layers) { + LayerManager layer_manager; + + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layer_manager, Parameter("Layer", LAYER_CONTROL_AUTO))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layer_manager, Parameter("Layer", LAYER_CONTROL_ON))); + EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layer_manager, Parameter("Layer", LAYER_CONTROL_OFF))); +} +/* TEST(test_parameter, ordering_found_custom_layers) { const std::vector& layers = GenerateTestLayers(); @@ -131,35 +165,6 @@ TEST(test_parameter, ordering_found_implicit_layers) { EXPECT_EQ(PARAMETER_RANK_MISSING, GetParameterOrdering(layers, Parameter("Layer I4", LAYER_CONTROL_OFF))); } -TEST(test_parameter, missing_layers) { - std::vector layers_empty; - std::vector layers = GenerateTestLayers(); - - std::string missing_layer; - - std::vector parameters_exist = GenerateTestParametersExist(); - EXPECT_EQ(true, HasMissingLayer(parameters_exist, layers_empty, missing_layer)); - EXPECT_EQ(false, HasMissingLayer(parameters_exist, layers, missing_layer)); - - std::vector parameters_missing = GenerateTestParametersMissing(); - EXPECT_EQ(true, HasMissingLayer(parameters_missing, layers_empty, missing_layer)); - EXPECT_EQ(true, HasMissingLayer(parameters_missing, layers, missing_layer)); -} - -TEST(test_parameter, filter) { - std::vector parameters_app_controlled = GenerateTestParametersExist(); - FilterParameters(parameters_app_controlled, LAYER_CONTROL_AUTO); - EXPECT_EQ(2, parameters_app_controlled.size()); - - std::vector parameters_overridden = GenerateTestParametersExist(); - FilterParameters(parameters_overridden, LAYER_CONTROL_ON); - EXPECT_EQ(2, parameters_overridden.size()); - - std::vector parameters_excluded = GenerateTestParametersExist(); - FilterParameters(parameters_excluded, LAYER_CONTROL_OFF); - EXPECT_EQ(2, parameters_excluded.size()); -} - TEST(test_parameter, order_automatic) { std::vector layers = GenerateTestLayers(); std::vector parameters = GenerateTestParametersAll(); @@ -240,201 +245,6 @@ TEST(test_parameter, order_manual) { EXPECT_STREQ("Layer E2", parameters[17].key.c_str()); } -TEST(test_parameter, apply_settings) { - Layer layer; - - SettingMetaString* metaA = InstantiateString(layer, "A"); - SettingMetaString* metaB = InstantiateString(layer, "B"); - - SettingDataString* preset_setting = Instantiate(metaA); - preset_setting->value = "preset value"; - - LayerPreset preset; - preset.settings.push_back(preset_setting); - - SettingDataString* layer_setting_a = Instantiate(metaA); - layer_setting_a->value = "setting value"; - - SettingDataString* layer_setting_b = Instantiate(metaB); - layer_setting_b->value = "setting value"; - - Parameter parameter; - parameter.settings.push_back(layer_setting_a); - parameter.settings.push_back(layer_setting_b); - - EXPECT_EQ(1, preset.settings.size()); - EXPECT_EQ(2, parameter.settings.size()); - - parameter.ApplyPresetSettings(preset); - - EXPECT_EQ(1, preset.settings.size()); - EXPECT_EQ(2, parameter.settings.size()); - - EXPECT_STREQ("preset value", static_cast(FindSetting(parameter.settings, "A"))->value.c_str()); - EXPECT_STREQ("setting value", static_cast(FindSetting(parameter.settings, "B"))->value.c_str()); -} - -TEST(test_parameter, gather_parameters_exist) { - std::vector parameters = GatherParameters(GenerateTestParametersExist(), GenerateTestLayers()); - - EXPECT_EQ(9, parameters.size()); - - EXPECT_STREQ("Layer E1", parameters[0].key.c_str()); - EXPECT_STREQ("Layer I0", parameters[1].key.c_str()); - EXPECT_STREQ("Layer I1", parameters[2].key.c_str()); - EXPECT_STREQ("Layer I2", parameters[3].key.c_str()); - EXPECT_STREQ("Layer E0", parameters[4].key.c_str()); - EXPECT_STREQ("Layer C0", parameters[5].key.c_str()); - EXPECT_STREQ("Layer C1", parameters[6].key.c_str()); - EXPECT_STREQ("Layer C2", parameters[7].key.c_str()); - EXPECT_STREQ("Layer E2", parameters[8].key.c_str()); -} - -TEST(test_parameter, gather_parameters_missing) { - std::vector parameters = GatherParameters(GenerateTestParametersMissing(), GenerateTestLayers()); - - EXPECT_EQ(10, parameters.size()); - - EXPECT_STREQ("Layer E3", parameters[0].key.c_str()); - EXPECT_STREQ("Layer E1", parameters[1].key.c_str()); - EXPECT_STREQ("Layer I0", parameters[2].key.c_str()); - EXPECT_STREQ("Layer I1", parameters[3].key.c_str()); - EXPECT_STREQ("Layer I2", parameters[4].key.c_str()); - EXPECT_STREQ("Layer C0", parameters[5].key.c_str()); - EXPECT_STREQ("Layer C1", parameters[6].key.c_str()); - EXPECT_STREQ("Layer C2", parameters[7].key.c_str()); - EXPECT_STREQ("Layer E0", parameters[8].key.c_str()); - EXPECT_STREQ("Layer E2", parameters[9].key.c_str()); -} - -TEST(test_parameter, gather_parameters_all) { - std::vector parameters = GatherParameters(GenerateTestParametersAll(), GenerateTestLayers()); - - EXPECT_EQ(18, parameters.size()); - - EXPECT_STREQ("Layer C3", parameters[0].key.c_str()); - EXPECT_STREQ("Layer C4", parameters[1].key.c_str()); - EXPECT_STREQ("Layer C5", parameters[2].key.c_str()); - EXPECT_STREQ("Layer E3", parameters[3].key.c_str()); - EXPECT_STREQ("Layer E4", parameters[4].key.c_str()); - EXPECT_STREQ("Layer E5", parameters[5].key.c_str()); - EXPECT_STREQ("Layer I3", parameters[6].key.c_str()); - EXPECT_STREQ("Layer I4", parameters[7].key.c_str()); - EXPECT_STREQ("Layer I5", parameters[8].key.c_str()); - EXPECT_STREQ("Layer C1", parameters[9].key.c_str()); - EXPECT_STREQ("Layer E1", parameters[10].key.c_str()); - EXPECT_STREQ("Layer I1", parameters[11].key.c_str()); - EXPECT_STREQ("Layer I2", parameters[12].key.c_str()); - EXPECT_STREQ("Layer I0", parameters[13].key.c_str()); - EXPECT_STREQ("Layer C0", parameters[14].key.c_str()); - EXPECT_STREQ("Layer E0", parameters[15].key.c_str()); - EXPECT_STREQ("Layer C2", parameters[16].key.c_str()); - EXPECT_STREQ("Layer E2", parameters[17].key.c_str()); -} - -TEST(test_parameter, compute_min_api_version) { - std::vector parameters = GenerateTestParametersExist(); - std::vector layers = GenerateTestLayers(); - - Version min_version = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); - EXPECT_EQ(Version(1, 2, 148), min_version); -} - -TEST(test_parameter, compute_min_api_version_exclude_middle) { - std::vector layers; - layers.push_back(Layer("Layer E0", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 148), "1", "layer.json")); - layers.push_back(Layer("Layer E1", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 162), "1", "layer.json")); - layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); - - std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_ON)); - parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_OFF)); - parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_AUTO)); - - Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); - EXPECT_EQ(Version(1, 2, 148), min_version_A); - - Version min_version_B = ComputeMinApiVersion(Version(1, 2, 140), parameters, layers); - EXPECT_EQ(Version(1, 2, 140), min_version_B); -} - -TEST(test_parameter, compute_min_api_version_exclude_older) { - std::vector layers; - layers.push_back(Layer("Layer E0", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 148), "1", "layer.json")); - layers.push_back(Layer("Layer E1", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 162), "1", "layer.json")); - layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); - - std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_OFF)); - parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); - parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_AUTO)); - - Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); - EXPECT_EQ(Version(1, 2, 162), min_version_A); - - Version min_version_B = ComputeMinApiVersion(Version(1, 2, 160), parameters, layers); - EXPECT_EQ(Version(1, 2, 160), min_version_B); -} - -TEST(test_parameter, compute_min_api_version_exclude_newer) { - std::vector layers; - layers.push_back(Layer("Layer E0", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 148), "1", "layer.json")); - layers.push_back(Layer("Layer E1", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 162), "1", "layer.json")); - layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); - - std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_AUTO)); - parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); - parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_OFF)); - - Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); - EXPECT_EQ(Version(1, 2, 148), min_version_A); - - Version min_version_B = ComputeMinApiVersion(Version(1, 2, 140), parameters, layers); - EXPECT_EQ(Version(1, 2, 140), min_version_B); -} - -TEST(test_parameter, compute_min_api_version_exclude_all) { - std::vector layers; - layers.push_back(Layer("Layer E0", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 148), "1", "layer.json")); - layers.push_back(Layer("Layer E1", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 162), "1", "layer.json")); - layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); - - std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_OFF)); - parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_OFF)); - parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_OFF)); - - Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); - EXPECT_EQ(Version(1, 2, 170), min_version_A); -} - -TEST(test_parameter, compute_min_api_version_missing_one) { - std::vector layers; - layers.push_back(Layer("Layer E0", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 148), "1", "layer.json")); - layers.push_back(Layer("Layer E2", LAYER_TYPE_EXPLICIT, Version(1, 0, 0), Version(1, 2, 176), "1", "layer.json")); - - std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_AUTO)); - parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); - parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_ON)); - - Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); - EXPECT_EQ(Version(1, 2, 148), min_version_A); -} - -TEST(test_parameter, compute_min_api_version_missing_all) { - std::vector layers; - - std::vector parameters; - parameters.push_back(Parameter("Layer E0", LAYER_CONTROL_AUTO)); - parameters.push_back(Parameter("Layer E1", LAYER_CONTROL_ON)); - parameters.push_back(Parameter("Layer E2", LAYER_CONTROL_ON)); - - Version min_version_A = ComputeMinApiVersion(Version(1, 2, 170), parameters, layers); - EXPECT_EQ(Version(1, 2, 170), min_version_A); -} - TEST(test_parameter, OrderParameter_ImplicitLayer) { std::vector layers = GenerateTestLayers(); std::vector sources = GenerateTestParametersImplicitOrdering(); From 927600c688cce550773cfdf05e17948de35c824a Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 2 Oct 2024 15:58:50 +0200 Subject: [PATCH 33/33] vkconfig3: Prepare Alpha build for internal testing --- vkconfig_core/environment.h | 2 +- vkconfig_core/test/test_ui.cpp | 4 +- vkconfig_core/type_tab.cpp | 3 +- vkconfig_core/type_tab.h | 5 +- vkconfig_core/ui.cpp | 2 +- vkconfig_gui/CHANGELOG.md | 15 +- vkconfig_gui/main.cpp | 1 - vkconfig_gui/mainwindow.cpp | 12 +- vkconfig_gui/mainwindow.h | 4 +- vkconfig_gui/mainwindow.ui | 723 +++++++++--------- vkconfig_gui/tab_about.cpp | 43 ++ vkconfig_gui/tab_about.h | 41 + vkconfig_gui/tab_applications.h | 1 + vkconfig_gui/tab_configurations.cpp | 4 + .../{tab_help.cpp => tab_documentation.cpp} | 12 +- .../{tab_help.h => tab_documentation.h} | 6 +- vkconfig_gui/vkconfig.pro | 6 +- 17 files changed, 514 insertions(+), 370 deletions(-) create mode 100644 vkconfig_gui/tab_about.cpp create mode 100644 vkconfig_gui/tab_about.h rename vkconfig_gui/{tab_help.cpp => tab_documentation.cpp} (66%) rename vkconfig_gui/{tab_help.h => tab_documentation.h} (86%) diff --git a/vkconfig_core/environment.h b/vkconfig_core/environment.h index 2bdbb6d39c..f2ea71bbb7 100644 --- a/vkconfig_core/environment.h +++ b/vkconfig_core/environment.h @@ -46,12 +46,12 @@ class Environment : public Serialize { bool has_crashed = false; int hide_message_boxes_flags = 0; + TabType active_tab = TAB_CONFIGURATIONS; private: Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; - TabType active_tab = TAB_DIAGNOSTIC; LogFlags loader_message_types_flags; Path home_sdk_path; }; diff --git a/vkconfig_core/test/test_ui.cpp b/vkconfig_core/test/test_ui.cpp index 92ca01d870..540998255c 100644 --- a/vkconfig_core/test/test_ui.cpp +++ b/vkconfig_core/test/test_ui.cpp @@ -48,11 +48,11 @@ TEST(test_ui, ExtractLayerName_found) { TEST(test_ui, GetMainWindowTitle) { std::string title = GetMainWindowTitle(false, false); - EXPECT_STREQ(("Vulkan Configurator " + Version::VKCONFIG.str()).c_str(), title.c_str()); + EXPECT_STREQ(("Vulkan Configurator " + Version::VKCONFIG.str() + "-Alpha").c_str(), title.c_str()); } TEST(test_ui, GetMainWindowTitle_active) { std::string title = GetMainWindowTitle(true, false); - EXPECT_STREQ(("Vulkan Configurator " + Version::VKCONFIG.str() + " ").c_str(), title.c_str()); + EXPECT_STREQ(("Vulkan Configurator " + Version::VKCONFIG.str() + "-Alpha ").c_str(), title.c_str()); } diff --git a/vkconfig_core/type_tab.cpp b/vkconfig_core/type_tab.cpp index 00689e1aa3..31ac87a30a 100644 --- a/vkconfig_core/type_tab.cpp +++ b/vkconfig_core/type_tab.cpp @@ -30,7 +30,8 @@ const char* GetToken(TabType type) { "LAYERS", // TAB_LAYERS "APPLICATIONS", // TAB_APPLICATIONS "PREFERENCES", // TAB_PREFERENCES - "HELP" // TAB_HELP + "DOCUMENTATION", // TAB_DOCUMENTATION + "ABOUT" // TAB_ABOUT }; static_assert(std::size(TOKENS) == TAB_COUNT, "The tranlation table size doesn't match the enum number of elements"); diff --git a/vkconfig_core/type_tab.h b/vkconfig_core/type_tab.h index 18c9e40b59..45acc8c46c 100644 --- a/vkconfig_core/type_tab.h +++ b/vkconfig_core/type_tab.h @@ -26,10 +26,11 @@ enum TabType { TAB_LAYERS, TAB_APPLICATIONS, TAB_PREFERENCES, - TAB_HELP, + TAB_DOCUMENTATION, + TAB_ABOUT, TAB_FIRST = TAB_DIAGNOSTIC, - TAB_LAST = TAB_HELP + TAB_LAST = TAB_ABOUT }; enum { TAB_COUNT = TAB_LAST - TAB_FIRST + 1 }; diff --git a/vkconfig_core/ui.cpp b/vkconfig_core/ui.cpp index 43bae44dd1..7a51c633cb 100644 --- a/vkconfig_core/ui.cpp +++ b/vkconfig_core/ui.cpp @@ -33,7 +33,7 @@ std::string ExtractLayerName(const LayerManager& layer_manager, const std::strin } std::string GetMainWindowTitle(bool active, bool display_date) { - std::string title = format("%s %s", VKCONFIG_NAME, Version::VKCONFIG.str().c_str()); + std::string title = format("%s %s-Alpha", VKCONFIG_NAME, Version::VKCONFIG.str().c_str()); #if VKCONFIG_DATE if (display_date) { diff --git a/vkconfig_gui/CHANGELOG.md b/vkconfig_gui/CHANGELOG.md index 3bdc25925a..1450e8b727 100644 --- a/vkconfig_gui/CHANGELOG.md +++ b/vkconfig_gui/CHANGELOG.md @@ -11,8 +11,16 @@ # Release notes -<<<<<<< HEAD:vkconfig/CHANGELOG.md -## [Vulkan Configurator 2.6.2](https://github.com/LunarG/VulkanTools/tree/main) - October 2024 +## [Vulkan Configurator 3.0.0](https://github.com/LunarG/VulkanTools/tree/main) - January 2025 + +### Features: +- UI redesign: per use case tabs +- Enable loading multiple versions of the same layer +- Enable ordering all layers executed by Vulkan application +- Enable ordering layers independently from enabling them +- Enable storing multiple set applications options for the application launcher + +## [Vulkan Configurator 2.6.2](https://github.com/LunarG/VulkanTools/tree/vulkan-sdk-1.3.296.0) - October 2024 ### Improvements: - Show message warnings when overriding implicit layer, either disabling or enabling @@ -25,9 +33,6 @@ - Fix renaming configuration with the same name but different cases ## [Vulkan Configurator 2.6.1](https://github.com/LunarG/VulkanTools/tree/vulkan-sdk-1.3.290.0) - July 2024 -======= -## [Vulkan Configurator 3.0.0](https://github.com/LunarG/VulkanTools/tree/main) - ??? 2024 ->>>>>>> a680297a5... vkconfig3: UI for new Vulkan Loader settings:vkconfig_gui/CHANGELOG.md ### Features: - Redesign main window UI around tabs diff --git a/vkconfig_gui/main.cpp b/vkconfig_gui/main.cpp index c04daae456..b1837e937f 100644 --- a/vkconfig_gui/main.cpp +++ b/vkconfig_gui/main.cpp @@ -20,7 +20,6 @@ #include "mainwindow.h" -#include "../vkconfig_core/vulkan_util.h" #include "../vkconfig_core/vulkan_util.h" #include "../vkconfig_core/alert.h" #include "../vkconfig_core/application_singleton.h" diff --git a/vkconfig_gui/mainwindow.cpp b/vkconfig_gui/mainwindow.cpp index 1a74b9334a..c2046a4def 100644 --- a/vkconfig_gui/mainwindow.cpp +++ b/vkconfig_gui/mainwindow.cpp @@ -68,7 +68,8 @@ MainWindow::MainWindow(QWidget *parent) this->tabs[TAB_LAYERS].reset(new TabLayers(*this, ui)); this->tabs[TAB_CONFIGURATIONS].reset(new TabConfigurations(*this, ui)); this->tabs[TAB_PREFERENCES].reset(new TabPreferences(*this, ui)); - this->tabs[TAB_HELP].reset(new TabHelp(*this, ui)); + this->tabs[TAB_DOCUMENTATION].reset(new TabDocumentation(*this, ui)); + this->tabs[TAB_ABOUT].reset(new TabAbout(*this, ui)); connect(ui->action_find_more_layers, SIGNAL(triggered(bool)), this, SLOT(OnHelpFindLayers(bool))); connect(ui->actionAbout, SIGNAL(triggered(bool)), this, SLOT(OnHelpAbout(bool))); @@ -96,7 +97,10 @@ MainWindow::MainWindow(QWidget *parent) this->restoreGeometry(settings.value("mainwindow/geometry").toByteArray()); this->restoreState(settings.value("mainwindow/state").toByteArray()); - this->tabs[this->ui->tab_widget->currentIndex()]->UpdateUI(UPDATE_REBUILD_UI); + const Configurator &configurator = Configurator::Get(); + + this->ui->tab_widget->setCurrentIndex(configurator.environment.active_tab); + this->tabs[configurator.environment.active_tab]->UpdateUI(UPDATE_REBUILD_UI); this->UpdateUI_Status(); this->UpdateUI(); @@ -444,5 +448,9 @@ bool MainWindow::eventFilter(QObject *target, QEvent *event) { void MainWindow::on_tab_widget_currentChanged(int index) { assert(index >= 0); + + Configurator &configurator = Configurator::Get(); + configurator.environment.active_tab = static_cast(index); + this->tabs[index]->UpdateUI(UPDATE_REBUILD_UI); } diff --git a/vkconfig_gui/mainwindow.h b/vkconfig_gui/mainwindow.h index b03b588a74..4aef75f24c 100644 --- a/vkconfig_gui/mainwindow.h +++ b/vkconfig_gui/mainwindow.h @@ -25,10 +25,10 @@ #include "tab_applications.h" #include "tab_configurations.h" #include "tab_diagnostics.h" -#include "tab_help.h" +#include "tab_documentation.h" #include "tab_layers.h" #include "tab_preferences.h" - +#include "tab_about.h" #include "ui_mainwindow.h" #include diff --git a/vkconfig_gui/mainwindow.ui b/vkconfig_gui/mainwindow.ui index 23a4832d35..3696a06f16 100644 --- a/vkconfig_gui/mainwindow.ui +++ b/vkconfig_gui/mainwindow.ui @@ -59,6 +59,9 @@ + + true + 0 @@ -72,7 +75,7 @@ QTabWidget::Rounded - 3 + 1 @@ -80,27 +83,14 @@ - - - 32 + + + TODO - - 32 + + Qt::AlignCenter - - 32 - - - 32 - - - - - PushButton - - - - + @@ -1273,6 +1263,16 @@ 32 + + + + TODO + + + Qt::AlignCenter + + + @@ -1318,351 +1318,388 @@ - + - Help + Documentation - - - - 640 - 520 - 151 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::NoButton + + + 0 - - - - - 10 - 250 - 551 - 171 - + + 5 - - About + + 5 - - - - 10 - 20 - 161 - 71 - - - - - - - :/resourcefiles/lunarg_logo.png - - - Qt::TextBrowserInteraction - - - - - - 10 - 90 - 91 - 81 - - - - - - - :/resourcefiles/qt_logo.png - - - - - - 180 - 50 - 241 - 31 - - - - - Arial - 10 - 50 - false - - - - Licensed under Apache 2.0 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - 180 - 20 - 241 - 41 - - - - - Arial - 10 - 50 - false - - - - Qt::LeftToRight - - - Copyright (c) 2020-2024 LunarG, Inc. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - 120 - 130 - 81 - 32 - - - - About Qt - - - - - - 120 - 90 - 231 - 41 - - - - - Arial - 10 - 50 - false - - - - Qt licensed under LGPL 3.0 - - - true - - - - - - 410 - 130 - 131 - 31 - - - - Reset to Default - - - - - - - 10 - 430 - 551 - 111 - + + 5 - - Tools + + 0 - - - - - - - Vulkan Info - - - + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - Vulkan Installation Analysis - - + + + + + Vulkan Info + + + + + + + Vulkan Installation Analysis + + + + - - - - - - - 10 - 10 - 551 - 231 - - - - Documentation - - - - - - - - <a href="https://">Find More Layers!</a> - - - Qt::TextBrowserInteraction - - - - - - - Qt::Horizontal - - - - - - - <a href="https://">Vulkan Specification</a> - - - Qt::LinksAccessibleByMouse|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - <a href="https://">Vulkan Layer Specification</a> - - - Qt::LinksAccessibleByMouse|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - <a href="https://">Vulkan GPU Info Reports</a> - - + + + + + <a href="https://">Find More Layers!</a> + + + Qt::TextBrowserInteraction + + + + + + + Qt::Horizontal + + + + + + + <a href="https://">Vulkan Specification</a> + + + Qt::LinksAccessibleByMouse|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + <a href="https://">Vulkan Layer Specification</a> + + + Qt::LinksAccessibleByMouse|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + <a href="https://">Vulkan GPU Info Reports</a> + + + + + + + TODO more? + + + + + + + Qt::Horizontal + + + + + + + <a href="https://">Vulkan Configurator Readme</a> + + + + + + + <a href="https://">Vulkan Configurator Changelog</a> + + + + + + + Qt::Horizontal + + + + - + - Qt::Horizontal - - - - - - - <a href="https://">Vulkan Configurator Readme</a> - - - - - - - <a href="https://">Vulkan Configurator Changelog</a> + Qt::Vertical - - - - - - Qt::Horizontal + + + 20 + 40 + - + - - - + + + + + + + + 16777215 + 16777215 + + + + About + + + + + + + + + false + + + + + 210 + 300 + 141 + 61 + + + + + + + :/resourcefiles/lunarg_logo.png + + + Qt::TextBrowserInteraction + + + + + + 10 + 470 + 91 + 81 + + + + + + + :/resourcefiles/qt_logo.png + + + + + + 360 + 250 + 201 + 31 + + - Consolas - 9 + Arial + 10 + 50 + false - - false + + Licensed under Apache 2.0 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true - - - - - - - 570 - 30 - 421 - 171 - - - - - 0 - 0 - - - - - - - :/resourcefiles/vulkan_configurator.png - - - true - - - Qt::TextBrowserInteraction - - - label_18 - buttonBox - groupBox - groupBox_2 - groupBox_3 + + + + 380 + 310 + 191 + 41 + + + + + Arial + 10 + 50 + false + + + + Qt::LeftToRight + + + Copyright (c) 2020-2024 LunarG, Inc. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + 140 + 510 + 81 + 32 + + + + About Qt + + + + + + 140 + 470 + 231 + 41 + + + + + Arial + 10 + 50 + false + + + + Qt licensed under LGPL 3.0 + + + true + + + + + + 10 + 10 + 600 + 245 + + + + + 0 + 0 + + + + + 600 + 245 + + + + + + + :/resourcefiles/vulkan_configurator.png + + + true + + + Qt::TextBrowserInteraction + + + + + + 440 + 360 + 121 + 31 + + + + About LunarG + + + + + @@ -1759,6 +1796,8 @@ - + + + diff --git a/vkconfig_gui/tab_about.cpp b/vkconfig_gui/tab_about.cpp new file mode 100644 index 0000000000..5db25745d6 --- /dev/null +++ b/vkconfig_gui/tab_about.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#include "tab_about.h" +#include "mainwindow.h" + +#include + +TabAbout::TabAbout(MainWindow &window, std::shared_ptr ui) : Tab(TAB_ABOUT, window, ui) { + this->connect(this->ui->about_lunarg_pushButton, SIGNAL(pressed()), this, SLOT(on_about_lunarg_pushButton_pressed())); + this->connect(this->ui->about_qt_pushButton, SIGNAL(pressed()), this, SLOT(on_about_qt_pushButton_pressed())); +} + +TabAbout::~TabAbout() {} + +void TabAbout::UpdateUI(UpdateUIMode mode) {} + +void TabAbout::CleanUI() {} + +bool TabAbout::EventFilter(QObject *target, QEvent *event) { return false; } + +void TabAbout::on_about_lunarg_pushButton_pressed() { + QDesktopServices::openUrl(QUrl("https://www.lunarg.com/", QUrl::TolerantMode)); +} + +void TabAbout::on_about_qt_pushButton_pressed() { QDesktopServices::openUrl(QUrl("https://www.qt.io/", QUrl::TolerantMode)); } diff --git a/vkconfig_gui/tab_about.h b/vkconfig_gui/tab_about.h new file mode 100644 index 0000000000..a9c442e195 --- /dev/null +++ b/vkconfig_gui/tab_about.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020-2024 Valve Corporation + * Copyright (c) 2020-2024 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. + * + * Authors: + * - Christophe Riccio + */ + +#pragma once + +#include "tab.h" + +struct TabAbout : public Tab { + Q_OBJECT + + public: + TabAbout(MainWindow& window, std::shared_ptr ui); + virtual ~TabAbout(); + + virtual void UpdateUI(UpdateUIMode mode) override; + virtual void CleanUI() override; + virtual bool EventFilter(QObject* target, QEvent* event) override; + + public Q_SLOTS: + void on_about_lunarg_pushButton_pressed(); + void on_about_qt_pushButton_pressed(); + + private: +}; diff --git a/vkconfig_gui/tab_applications.h b/vkconfig_gui/tab_applications.h index 0d44dc0849..2d93e98434 100644 --- a/vkconfig_gui/tab_applications.h +++ b/vkconfig_gui/tab_applications.h @@ -25,6 +25,7 @@ #include #include +#include struct TabApplications : public Tab { Q_OBJECT diff --git a/vkconfig_gui/tab_configurations.cpp b/vkconfig_gui/tab_configurations.cpp index e3253a39a8..655d0d1862 100644 --- a/vkconfig_gui/tab_configurations.cpp +++ b/vkconfig_gui/tab_configurations.cpp @@ -550,6 +550,10 @@ void TabConfigurations::OnSelectLayer(int currentRow) { } QWidget *widget = ui->configurations_layers_list->itemWidget(ui->configurations_layers_list->item(currentRow)); + if (widget == nullptr) { + return; + } + const std::string &layer_string = static_cast(widget)->text().toStdString(); Configurator &configurator = Configurator::Get(); diff --git a/vkconfig_gui/tab_help.cpp b/vkconfig_gui/tab_documentation.cpp similarity index 66% rename from vkconfig_gui/tab_help.cpp rename to vkconfig_gui/tab_documentation.cpp index 11a10f8af0..f4f571f3c7 100644 --- a/vkconfig_gui/tab_help.cpp +++ b/vkconfig_gui/tab_documentation.cpp @@ -18,15 +18,15 @@ * - Christophe Riccio */ -#include "tab_help.h" +#include "tab_documentation.h" #include "mainwindow.h" -TabHelp::TabHelp(MainWindow &window, std::shared_ptr ui) : Tab(TAB_HELP, window, ui) {} +TabDocumentation::TabDocumentation(MainWindow &window, std::shared_ptr ui) : Tab(TAB_DOCUMENTATION, window, ui) {} -TabHelp::~TabHelp() {} +TabDocumentation::~TabDocumentation() {} -void TabHelp::UpdateUI(UpdateUIMode mode) {} +void TabDocumentation::UpdateUI(UpdateUIMode mode) {} -void TabHelp::CleanUI() {} +void TabDocumentation::CleanUI() {} -bool TabHelp::EventFilter(QObject *target, QEvent *event) { return false; } +bool TabDocumentation::EventFilter(QObject *target, QEvent *event) { return false; } diff --git a/vkconfig_gui/tab_help.h b/vkconfig_gui/tab_documentation.h similarity index 86% rename from vkconfig_gui/tab_help.h rename to vkconfig_gui/tab_documentation.h index 6b786c26a9..deb8fcd994 100644 --- a/vkconfig_gui/tab_help.h +++ b/vkconfig_gui/tab_documentation.h @@ -22,12 +22,12 @@ #include "tab.h" -struct TabHelp : public Tab { +struct TabDocumentation : public Tab { Q_OBJECT public: - TabHelp(MainWindow& window, std::shared_ptr ui); - virtual ~TabHelp(); + TabDocumentation(MainWindow& window, std::shared_ptr ui); + virtual ~TabDocumentation(); virtual void UpdateUI(UpdateUIMode mode) override; virtual void CleanUI() override; diff --git a/vkconfig_gui/vkconfig.pro b/vkconfig_gui/vkconfig.pro index e899ab1cf9..08e9634938 100644 --- a/vkconfig_gui/vkconfig.pro +++ b/vkconfig_gui/vkconfig.pro @@ -93,10 +93,11 @@ SOURCES += \ main.cpp \ mainwindow.cpp \ tab.cpp \ + tab_about.cpp \ tab_applications.cpp \ tab_configurations.cpp \ tab_diagnostics.cpp \ - tab_help.cpp \ + tab_documentation.cpp \ tab_layers.cpp \ tab_preferences.cpp \ settings_tree.cpp @@ -167,10 +168,11 @@ HEADERS += \ dialog_vulkan_info.h \ mainwindow.h \ tab.h \ + tab_about.h \ tab_applications.h \ tab_configurations.h \ tab_diagnostics.h \ - tab_help.h \ + tab_documentation.h \ tab_layers.h \ tab_preferences.h \ settings_tree.h

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�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