blob: 7232de1aaccb7fbaf13e763ad1983208219d6f03 [file] [log] [blame]
#!/usr/bin/python3 -i
#
# Copyright (c) 2015-2017, 2019-2023 The Khronos Group Inc.
# Copyright (c) 2015-2017, 2019-2023 Valve Corporation
# Copyright (c) 2015-2017, 2019-2023 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 os
import sys
import subprocess
import platform
import shutil
import argparse
if sys.version_info[0] != 3:
print("This script requires Python 3. Run script with [-h] option for more details.")
sys_exit(0)
# Use Ninja for all platforms for performance/simplicity
os.environ['CMAKE_GENERATOR'] = "Ninja"
# Utility for creating a directory if it does not exist. Behaves similarly to 'mkdir -p'
def make_dirs(path, clean=False):
if clean and os.path.isdir(path):
shutil.rmtree(path)
os.makedirs(path, exist_ok=True)
# helper to define paths relative to the repo root
def RepoRelative(path):
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', path))
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.split(os.path.abspath(__file__))[0], '..'))
# TODO: Pass this in as arg, may be useful for running locally
EXTERNAL_DIR_NAME = "external"
BUILD_DIR_NAME = "build"
VVL_BUILD_DIR = RepoRelative(BUILD_DIR_NAME)
TEST_INSTALL_DIR = RepoRelative("build/install")
def externalDir(config): return os.path.join(RepoRelative(EXTERNAL_DIR_NAME), config)
# Runs a command in a directory and returns its return code.
# Directory is project root by default, or a relative path from project root
def RunShellCmd(command, start_dir = PROJECT_ROOT, env=None, verbose=False):
if start_dir != PROJECT_ROOT:
start_dir = RepoRelative(start_dir)
cmd_list = command.split(" ")
if verbose or ('VVL_CI_VERBOSE' in os.environ and os.environ['VVL_CI_VERBOSE'] != '0'):
print(f'CICMD({cmd_list}, env={env})')
subprocess.check_call(cmd_list, cwd=start_dir, env=env)
#
# Check if the system is Windows
def IsWindows(): return 'windows' == platform.system().lower()
#
# Run VVL scripts
def CheckVVL(config):
ext_dir = externalDir(config)
vulkan_registry = ext_dir + "/Vulkan-Headers/registry"
spirv_unified = ext_dir + "/SPIRV-Headers/include/spirv/unified1/"
# Scripts depend on modules within the Vulkan registry.
if "PYTHONPATH" in os.environ:
print(f"Using provided PYTHONPATH {os.environ['PYTHONPATH']}")
else:
os.environ['PYTHONPATH'] = vulkan_registry
# Verify consistency of generated source code
print("Check Generated Source Code Consistency")
gen_check_cmd = f'python3 scripts/generate_source.py --verify {vulkan_registry} {spirv_unified}'
RunShellCmd(gen_check_cmd)
print('Run vk_validation_stats.py')
valid_usage_json = vulkan_registry + "/validusage.json"
text_file = RepoRelative(f'{VVL_BUILD_DIR}/layers/vuid_coverage_database.txt')
gen_check_cmd = f'python3 scripts/vk_validation_stats.py {valid_usage_json} -text {text_file}'
RunShellCmd(gen_check_cmd)
#
# Prepare the Validation Layers for testing
def BuildVVL(config, cmake_args, build_tests):
print("Log CMake version")
cmake_ver_cmd = 'cmake --version'
RunShellCmd(cmake_ver_cmd)
print("Run CMake for Validation Layers")
cmake_cmd = f'cmake -S . -B {VVL_BUILD_DIR} -DUPDATE_DEPS=ON -DCMAKE_BUILD_TYPE={config}'
# By default BUILD_WERROR is OFF, CI should always enable it.
cmake_cmd += ' -DBUILD_WERROR=ON'
cmake_cmd += f' -DBUILD_TESTS={build_tests}'
if cmake_args:
cmake_cmd += f' {cmake_args}'
RunShellCmd(cmake_cmd)
print("Build Validation Layers and Tests")
build_cmd = f'cmake --build {VVL_BUILD_DIR}'
RunShellCmd(build_cmd)
print("Install Validation Layers")
install_cmd = f'cmake --install {VVL_BUILD_DIR} --prefix {TEST_INSTALL_DIR}'
RunShellCmd(install_cmd)
#
# Prepare Loader for executing Layer Validation Tests
def BuildLoader():
LOADER_DIR = RepoRelative(os.path.join("%s/Vulkan-Loader" % EXTERNAL_DIR_NAME))
# Clone Loader repo
if not os.path.exists(LOADER_DIR):
print("Clone Loader Source Code")
clone_loader_cmd = 'git clone https://github.com/KhronosGroup/Vulkan-Loader.git'
RunShellCmd(clone_loader_cmd, EXTERNAL_DIR_NAME)
print("Run CMake for Loader")
LOADER_BUILD_DIR = RepoRelative("%s/Vulkan-Loader/%s" % (EXTERNAL_DIR_NAME, BUILD_DIR_NAME))
print("Run CMake for Loader")
cmake_cmd = f'cmake -S {LOADER_DIR} -B {LOADER_BUILD_DIR} '
cmake_cmd += '-D UPDATE_DEPS=ON -D BUILD_TESTS=OFF -D CMAKE_BUILD_TYPE=Release'
# This enables better stack traces from leak sanitizer by using the loader feature which prevents unloading of libraries at shutdown.
if not IsWindows():
cmake_cmd += ' -D LOADER_ENABLE_ADDRESS_SANITIZER=ON -D LOADER_DISABLE_DYNAMIC_LIBRARY_UNLOADING=ON'
RunShellCmd(cmake_cmd)
print("Build Loader")
build_cmd = f'cmake --build {LOADER_BUILD_DIR}'
RunShellCmd(build_cmd)
print("Install Loader")
install_cmd = f'cmake --install {LOADER_BUILD_DIR} --prefix {TEST_INSTALL_DIR}'
RunShellCmd(install_cmd)
#
# Prepare Mock ICD for use with Layer Validation Tests
def BuildMockICD():
VT_DIR = RepoRelative("%s/Vulkan-Tools" % EXTERNAL_DIR_NAME)
if not os.path.exists(VT_DIR):
print("Clone Vulkan-Tools Repository")
clone_tools_cmd = 'git clone https://github.com/KhronosGroup/Vulkan-Tools.git'
RunShellCmd(clone_tools_cmd, EXTERNAL_DIR_NAME)
ICD_BUILD_DIR = RepoRelative("%s/Vulkan-Tools/%s" % (EXTERNAL_DIR_NAME,BUILD_DIR_NAME))
print("Running update_deps.py for ICD")
RunShellCmd(f'python3 scripts/update_deps.py --dir {EXTERNAL_DIR_NAME} --config release', VT_DIR)
print("Run CMake for ICD")
cmake_cmd = f'cmake -S {VT_DIR} -B {ICD_BUILD_DIR} -D CMAKE_BUILD_TYPE=Release '
cmake_cmd += '-DBUILD_CUBE=NO -DBUILD_VULKANINFO=NO -D INSTALL_ICD=ON '
cmake_cmd += f'-C {VT_DIR}/{EXTERNAL_DIR_NAME}/helper.cmake'
RunShellCmd(cmake_cmd)
print("Build Mock ICD")
build_cmd = f'cmake --build {ICD_BUILD_DIR}'
RunShellCmd(build_cmd)
print("Install Mock ICD")
install_cmd = f'cmake --install {ICD_BUILD_DIR} --prefix {TEST_INSTALL_DIR}'
RunShellCmd(install_cmd)
#
# Prepare Profile Layer for use with Layer Validation Tests
def BuildProfileLayer():
RunShellCmd('pip3 install jsonschema', EXTERNAL_DIR_NAME)
VP_DIR = RepoRelative("%s/Vulkan-Profiles" % EXTERNAL_DIR_NAME)
if not os.path.exists(VP_DIR):
print("Clone Vulkan-Profiles Repository")
clone_cmd = 'git clone https://github.com/KhronosGroup/Vulkan-Profiles.git'
RunShellCmd(clone_cmd, EXTERNAL_DIR_NAME)
BUILD_DIR = RepoRelative("%s/Vulkan-Profiles/%s" % (EXTERNAL_DIR_NAME, BUILD_DIR_NAME))
print("Run CMake for Profile Layer")
cmake_cmd = f'cmake -S {VP_DIR} -B {BUILD_DIR}'
cmake_cmd += ' -D CMAKE_BUILD_TYPE=Release'
cmake_cmd += ' -D UPDATE_DEPS=ON'
cmake_cmd += ' -D PROFILES_BUILD_TESTS=OFF'
RunShellCmd(cmake_cmd)
print("Build Profile Layer")
build_cmd = f'cmake --build {BUILD_DIR}'
RunShellCmd(build_cmd)
print("Install Profile Layer")
install_cmd = f'cmake --install {BUILD_DIR} --prefix {TEST_INSTALL_DIR}'
RunShellCmd(install_cmd)
#
# Run the Layer Validation Tests
def RunVVLTests():
print("Run Vulkan-ValidationLayer Tests using Mock ICD")
if IsWindows():
print("Not implemented yet")
exit(-1)
lvt_cmd = os.path.join(PROJECT_ROOT, BUILD_DIR_NAME, 'tests', 'vk_layer_validation_tests')
lvt_env = dict(os.environ)
# Because we installed everything to TEST_INSTALL_DIR all the libraries/json files are in pre-determined locations
# defined by GNUInstallDirs. This makes adding the LD_LIBRARY_PATH and VK_LAYER_PATH trivial/robust.
lvt_env['LD_LIBRARY_PATH'] = os.path.join(TEST_INSTALL_DIR, 'lib')
lvt_env['VK_LAYER_PATH'] = os.path.join(TEST_INSTALL_DIR, 'share/vulkan/explicit_layer.d')
lvt_env['VK_DRIVER_FILES'] = os.path.join(TEST_INSTALL_DIR, 'share/vulkan/icd.d/VkICD_mock_icd.json')
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'
# By default use the max_profile.json
if "VK_KHRONOS_PROFILES_PROFILE_FILE" not in os.environ:
lvt_env['VK_KHRONOS_PROFILES_PROFILE_FILE'] = 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'
RunShellCmd(lvt_cmd, env=lvt_env)
print("Re-Running multithreaded tests with VK_LAYER_FINE_GRAINED_LOCKING disabled")
lvt_env['VK_LAYER_FINE_GRAINED_LOCKING'] = '0'
RunShellCmd(lvt_cmd + ' --gtest_filter=*Thread*', env=lvt_env)
def GetArgParser():
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')
return parser