1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
#!/usr/bin/env python3
# Copyright (c) 2020-2025 Valve Corporation
# Copyright (c) 2020-2025 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.
import subprocess
import sys
import os
import argparse
import common_ci
# Where all artifacts will ultimately be placed under
CI_BUILD_DIR = common_ci.RepoRelative('build-ci')
# Where all dependencies will be installed under
CI_EXTERNAL_DIR = f'{CI_BUILD_DIR}/external'
# Where all repos will install to
CI_INSTALL_DIR = f'{CI_BUILD_DIR}/install'
#
# Prepare the Validation Layers for testing
def BuildVVL(config, cmake_args, build_tests, mock_android):
print("Log CMake version")
cmake_ver_cmd = 'cmake --version'
common_ci.RunShellCmd(cmake_ver_cmd)
SRC_DIR = common_ci.PROJECT_SRC_DIR
BUILD_DIR = f'{CI_BUILD_DIR}/vvl'
print("Configure VVL")
cmake_cmd = f'cmake -S {SRC_DIR} -B {BUILD_DIR}'
cmake_cmd += f' -D CMAKE_BUILD_TYPE={config}'
cmake_cmd += f' -D BUILD_TESTS={build_tests}'
cmake_cmd += f' -D UPDATE_DEPS=ON -D UPDATE_DEPS_DIR={CI_EXTERNAL_DIR}'
cmake_cmd += ' -D BUILD_WERROR=ON'
cmake_cmd += ' -D INSTALL_VVL_TEST_ICD=ON'
if cmake_args:
cmake_cmd += f' {cmake_args}'
if mock_android:
cmake_cmd += ' -DVVL_MOCK_ANDROID=ON'
common_ci.RunShellCmd(cmake_cmd)
print("Build VVL")
build_cmd = f'cmake --build {BUILD_DIR}'
common_ci.RunShellCmd(build_cmd)
print("Install VVL")
install_cmd = f'cmake --install {BUILD_DIR} --prefix {CI_INSTALL_DIR}'
common_ci.RunShellCmd(install_cmd)
#
# Prepare Loader for executing Layer Validation Tests
def BuildLoader():
SRC_DIR = f'{CI_EXTERNAL_DIR}/Vulkan-Loader'
BUILD_DIR = f'{SRC_DIR}/build'
if not os.path.exists(SRC_DIR):
print("Unable to find Vulkan-Loader")
sys.exit(1)
print("Run CMake for Loader")
cmake_cmd = f'cmake -S {SRC_DIR} -B {BUILD_DIR}'
cmake_cmd += ' -D UPDATE_DEPS=ON -D CMAKE_BUILD_TYPE=Release'
# GitHub actions runs our test as admin on Windows
if common_ci.IsGHA() and common_ci.IsWindows():
cmake_cmd += ' -D LOADER_USE_UNSAFE_FILE_SEARCH=ON'
common_ci.RunShellCmd(cmake_cmd)
print("Build Loader")
build_cmd = f'cmake --build {BUILD_DIR}'
common_ci.RunShellCmd(build_cmd)
print("Install Loader")
install_cmd = f'cmake --install {BUILD_DIR} --prefix {CI_INSTALL_DIR}'
common_ci.RunShellCmd(install_cmd)
#
# Prepare Profile Layer for use with Layer Validation Tests
def BuildProfileLayer(mockAndroid):
SRC_DIR = f'{CI_EXTERNAL_DIR}/Vulkan-Profiles'
BUILD_DIR = f'{SRC_DIR}/build'
if not os.path.exists(SRC_DIR):
print("Unable to find Vulkan-Profiles")
sys.exit(1)
print("Run CMake for Profile Layer")
cmake_cmd = f'cmake -S {SRC_DIR} -B {BUILD_DIR}'
cmake_cmd += ' -D CMAKE_BUILD_TYPE=Release'
cmake_cmd += ' -D UPDATE_DEPS=ON'
if mockAndroid:
cmake_cmd += ' -DBUILD_MOCK_ANDROID_SUPPORT=ON'
common_ci.RunShellCmd(cmake_cmd)
print("Build Profile Layer")
build_cmd = f'cmake --build {BUILD_DIR}'
common_ci.RunShellCmd(build_cmd)
print("Install Profile Layer")
install_cmd = f'cmake --install {BUILD_DIR} --prefix {CI_INSTALL_DIR}'
common_ci.RunShellCmd(install_cmd)
#
# Module Entrypoint
def Build(args):
config = args.configuration
# Since this script uses Ninja to build Windows users need to be in a developer command prompt.
if common_ci.IsWindows():
# This environment variable is arbitrary. I just picked one set by the developer command prompt.
if "VSCMD_ARG_TGT_ARCH" not in os.environ:
print("This script must be invoked in a developer command prompt!")
sys.exit(1)
try:
BuildVVL(config = config, cmake_args = args.cmake, build_tests = "ON", mock_android = args.mockAndroid)
BuildLoader()
BuildProfileLayer(args.mockAndroid)
except subprocess.CalledProcessError as proc_error:
print('Command "%s" failed with return code %s' % (' '.join(proc_error.cmd), proc_error.returncode))
sys.exit(proc_error.returncode)
except Exception as unknown_error:
print('An unknown error occured: %s', unknown_error)
sys.exit(1)
sys.exit(0)
#
# Run the Layer Validation Tests
def RunVVLTests(args):
print("Run VVL Tests using Mock ICD")
lvt_env = dict(os.environ)
# Needed for undefined behavior sanitizor to actually cause program to fail.
lvt_env['UBSAN_OPTIONS'] = 'abort_on_error=1:halt_on_error=1'
# Because we installed everything to CI_INSTALL_DIR all the libraries/json files are in pre-determined locations
# defined by GNUInstallDirs. This makes setting VK_LAYER_PATH and other environment variables trivial/robust.
if common_ci.IsWindows():
lvt_env['VK_LAYER_PATH'] = os.path.join(CI_INSTALL_DIR, 'bin')
lvt_env['VK_DRIVER_FILES'] = os.path.join(CI_INSTALL_DIR, 'bin\\VVL_Test_ICD.json')
else:
lvt_env['LD_LIBRARY_PATH'] = os.path.join(CI_INSTALL_DIR, 'lib')
lvt_env['DYLD_LIBRARY_PATH'] = os.path.join(CI_INSTALL_DIR, 'lib')
lvt_env['VK_LAYER_PATH'] = os.path.join(CI_INSTALL_DIR, 'share/vulkan/explicit_layer.d')
lvt_env['VK_DRIVER_FILES'] = os.path.join(CI_INSTALL_DIR, 'share/vulkan/icd.d/VVL_Test_ICD.json')
# This enables better stack traces from tools like leak sanitizer by using the loader feature which prevents unloading of libraries at shutdown.
lvt_env['VK_LOADER_DISABLE_DYNAMIC_LIBRARY_UNLOADING'] = '1'
# Useful for debugging
# lvt_env['VK_LOADER_DEBUG'] = 'error,warn,info'
# lvt_env['VK_LAYER_TESTS_PRINT_DRIVER'] = '1'
lvt_env['VK_INSTANCE_LAYERS'] = 'VK_LAYER_KHRONOS_validation' + os.pathsep + 'VK_LAYER_KHRONOS_profiles'
lvt_env['VK_KHRONOS_PROFILES_SIMULATE_CAPABILITIES'] = 'SIMULATE_API_VERSION_BIT,SIMULATE_FEATURES_BIT,SIMULATE_PROPERTIES_BIT,SIMULATE_EXTENSIONS_BIT,SIMULATE_FORMATS_BIT,SIMULATE_QUEUE_FAMILY_PROPERTIES_BIT,SIMULATE_VIDEO_CAPABILITIES_BIT,SIMULATE_VIDEO_FORMATS_BIT'
# By default use the max_profile.json
if "VK_KHRONOS_PROFILES_PROFILE_FILE" not in os.environ:
lvt_env['VK_KHRONOS_PROFILES_PROFILE_FILE'] = common_ci.RepoRelative('tests/device_profiles/max_profile.json')
# By default set portability to false
if "VK_KHRONOS_PROFILES_EMULATE_PORTABILITY" not in os.environ:
lvt_env['VK_KHRONOS_PROFILES_EMULATE_PORTABILITY'] = 'false'
lvt_env['VK_KHRONOS_PROFILES_DEBUG_REPORTS'] = 'DEBUG_REPORT_ERROR_BIT'
lvt_env['VK_KHRONOS_PROFILES_UNKNOWN_FEATURE_VALUES'] = 'UNKNOWN_FEATURE_VALUES_DEVICE'
lvt_cmd = os.path.join(CI_INSTALL_DIR, 'bin', 'vk_layer_validation_tests')
if args.mockAndroid:
# TODO - only reason running this subset, is mockAndoid fails any test that does
# a manual vkCreateDevice call and need to investigate more why
common_ci.RunShellCmd(lvt_cmd + " --gtest_filter=*AndroidHardwareBuffer.*:*AndroidExternalResolve.*", env=lvt_env)
return
if args.tsan and args.wsi:
# Combo of both below
common_ci.RunShellCmd(f'xvfb-run --auto-servernum {lvt_cmd} --gtest_filter=*Wsi.*', env=lvt_env)
return
if args.tsan:
# These are tests we have decided are worth using Thread Sanitize as it will take about 9x longer to run a test
# We have also seen TSAN turn bug out and make each test incrementally take longer
# (https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8931)
common_ci.RunShellCmd(lvt_cmd + " --gtest_filter=*SyncVal.*:*Threading.*:*SyncObject.*:-*Video*", env=lvt_env)
return
if args.wsi:
# We need to use xvfb to get github action runners to be able to create a surface context
# Adding to other tests is a slow, unnecessary, overheader
common_ci.RunShellCmd(f'xvfb-run --auto-servernum {lvt_cmd} --gtest_filter=*Wsi.*', env=lvt_env)
return
# these will 100% be skipped by default on CI machine, save time filtering them out first
skip_list = [
# AHB as it is ran separately
'*AndroidHardwareBuffer.*',
'*AndroidExternalResolve.*',
# WSI as it is ran separately
'*Wsi.*'
]
# The "default" run
common_ci.RunShellCmd(f'{lvt_cmd} --gtest_filter=-{":".join(skip_list)}', env=lvt_env)
print("Re-Running syncval tests with core validation disabled (--syncval-disable-core)")
common_ci.RunShellCmd(lvt_cmd + ' --gtest_filter=*SyncVal* --syncval-disable-core', env=lvt_env)
print("Re-Running multithreaded tests with VK_LAYER_FINE_GRAINED_LOCKING disabled")
lvt_env['VK_LAYER_FINE_GRAINED_LOCKING'] = '0'
common_ci.RunShellCmd(lvt_cmd + ' --gtest_filter=*Thread*', env=lvt_env)
def Test(args):
try:
RunVVLTests(args)
except subprocess.CalledProcessError as proc_error:
print('Command "%s" failed with return code %s' % (' '.join(proc_error.cmd), proc_error.returncode))
sys.exit(proc_error.returncode)
except Exception as unknown_error:
print('An unknown error occured: %s', unknown_error)
sys.exit(1)
sys.exit(0)
if __name__ == '__main__':
configs = ['release', 'debug']
default_config = configs[0]
parser = argparse.ArgumentParser()
parser.add_argument(
'-c', '--config', dest='configuration',
metavar='CONFIG', action='store',
choices=configs, default=default_config,
help='Build target configuration. Can be one of: {0}'.format(
', '.join(configs)))
parser.add_argument(
'--cmake', dest='cmake',
metavar='CMAKE', type=str,
default='', help='Additional args to pass to cmake')
parser.add_argument(
'--build', dest='build',
action='store_true', help='Build the layers')
parser.add_argument(
'--test', dest='test',
action='store_true', help='Tests the layers')
parser.add_argument(
'--mockAndroid', dest='mockAndroid',
action='store_true', help='Use Mock Android')
parser.add_argument(
'--tsan', dest='tsan',
action='store_true', help='Filter out tests for TSAN')
parser.add_argument(
'--wsi', dest='wsi',
action='store_true', help='Filter out tests for WSI (which uses xvfb and will slow down other tests)')
args = parser.parse_args()
if (args.build):
Build(args)
if (args.test):
Test(args)
|