Merge remote-tracking branch 'upstream/master' into main
These changes allow for cross-compiling asm_offset, which will allow us
to fix handling of unknown entrypoints.
Bug: 59688
Change-Id: I40b5be830ddfe732a3a892a1a14ce684052bad1b
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 41ce80f..85e0e25 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -44,7 +44,9 @@
- uses: actions/setup-python@v2
with:
python-version: '3.7'
- - run: sudo apt install libwayland-dev libxrandr-dev
+ - run: sudo apt update
+ - name: Install Dependencies
+ run: sudo apt install --yes --no-install-recommends libwayland-dev libxrandr-dev
- name: Generate build files
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{matrix.config}} -DBUILD_TESTS=On -DUPDATE_DEPS=ON -DTEST_USE_ADDRESS_SANITIZER=ON
@@ -68,6 +70,48 @@
- name: Verify commit message formatting
run: ./scripts/check_commit_message_format.sh
+ linux-32:
+ runs-on: ${{matrix.os}}
+
+ strategy:
+ matrix:
+ cc: [ gcc, clang ]
+ cxx: [ g++, clang++ ]
+ config: [ Debug, Release ]
+ os: [ ubuntu-18.04, ubuntu-20.04 ]
+ exclude:
+ - cc: gcc
+ cxx: clang++
+ - cc: clang
+ cxx: g++
+
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-python@v2
+ with:
+ python-version: '3.7'
+ - name: Install Dependencies
+ run: |-
+ sudo dpkg --add-architecture i386
+ sudo apt-get update
+ sudo apt install --yes --no-install-recommends gcc-multilib g++-multilib libc6-dev-i386 pkg-config-i686-linux-gnu libwayland-dev:i386 libxrandr-dev:i386
+ - name: Generate build files
+ run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{matrix.config}} -DBUILD_TESTS=On -DUPDATE_DEPS=ON
+ env:
+ CFLAGS: -m32
+ CXXFLAGS: -m32
+ LDFLAGS: -m32
+ ASFLAGS: --32
+ PKG_CONFIG: i686-pc-linux-gnu-pkg-config
+
+
+ - name: Build the loader
+ run: make -C build
+
+ - name: Run regression tests
+ working-directory: ./build
+ run: ctest --output-on-failure
+
windows:
runs-on: ${{matrix.os}}
@@ -97,11 +141,19 @@
run: python scripts/generate_source.py --verify external/Vulkan-Headers/registry
mac:
- runs-on: macos-latest
+ runs-on: ${{matrix.os}}
strategy:
matrix:
config: [ Debug, Release ]
+ os: [ macos-11, macos-latest ]
+ static_build: [ BUILD_STATIC_LOADER=ON, BUILD_STATIC_LOADER=OFF ]
+ exclude:
+ - os: macos-latest
+ static_build: BUILD_STATIC_LOADER=ON
+ - config: Debug
+ os: macos-11
+ static_build: BUILD_STATIC_LOADER=ON
steps:
- uses: actions/checkout@v2
@@ -110,7 +162,11 @@
python-version: '3.7'
- name: Generate build files
- run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{matrix.config}} -DBUILD_TESTS=On -DUPDATE_DEPS=ON -DTEST_USE_ADDRESS_SANITIZER=ON
+ run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{matrix.config}} -D${{matrix.static_build}} -DBUILD_TESTS=On -DUPDATE_DEPS=ON -DTEST_USE_ADDRESS_SANITIZER=ON
+ env:
+ # Specify the minimum version of macOS on which the target binaries are to be deployed.
+ # https://cmake.org/cmake/help/latest/envvar/MACOSX_DEPLOYMENT_TARGET.html
+ MACOSX_DEPLOYMENT_TARGET: 10.12
- name: Build the loader
run: make -C build
diff --git a/BUILD.gn b/BUILD.gn
index af10287..8b60426 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -43,7 +43,6 @@
cflags = [
"-Wno-conversion",
"-Wno-extra-semi",
- "-Wno-implicit-fallthrough",
"-Wno-sign-compare",
"-Wno-strict-prototypes",
"-Wno-unreachable-code",
@@ -122,10 +121,11 @@
"loader/generated/vk_layer_dispatch_table.h",
"loader/generated/vk_loader_extensions.h",
"loader/generated/vk_object_types.h",
- "loader/get_environment.c",
- "loader/get_environment.h",
"loader/gpa_helper.c",
"loader/gpa_helper.h",
+ "loader/loader_common.h",
+ "loader/loader_environment.c",
+ "loader/loader_environment.h",
"loader/loader.c",
"loader/loader.h",
"loader/loader_common.h",
diff --git a/BUILD.md b/BUILD.md
index c60c7c6..9b5a8f6 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -4,33 +4,64 @@
## Table Of Contents
-- [Contributing to the Repository](#contributing-to-the-repository)
-- [Repository Content](#repository-content)
- - [Installed Files](#installed-files)
-- [Repository Set-Up](#repository-set-up)
- - [Display Drivers](#display-drivers)
- - [Download the Repository](#download-the-repository)
- - [Repository Dependencies](#repository-dependencies)
- - [Build and Install Directories](#build-and-install-directories)
- - [Building Dependent Repositories with Known-Good Revisions](#building-dependent-repositories-with-known-good-revisions)
- - [Generated source code](#generated-source-code)
- - [Build Options](#build-options)
-- [Building On Windows](#building-on-windows)
- - [Windows Development Environment Requirements](#windows-development-environment-requirements)
- - [Windows Build - Microsoft Visual Studio](#windows-build---microsoft-visual-studio)
- - [Windows Notes](#windows-notes)
- - [CMake Visual Studio Generators](#cmake-visual-studio-generators)
- - [Using The Vulkan Loader Library in this Repository on Windows](#using-the-vulkan-loader-library-in-this-repository-on-windows)
-- [Building On Linux](#building-on-linux)
- - [Linux Development Environment Requirements](#linux-development-environment-requirements)
- - [Linux Build](#linux-build)
-- [Building on MacOS](#building-on-macos)
- - [MacOS Development Environment Requirements](#macos-development-environment-requirements)
- - [Clone the Repository](#clone-the-repository)
- - [MacOS build](#macos-build)
-- [Building on Fuchsia](#building-on-fuchsia)
-- [Building on QNX](#building-on-qnx)
- - [SDK Symbols](#sdk-symbols)
+- [Build Instructions](#build-instructions)
+ - [Table Of Contents](#table-of-contents)
+ - [Contributing to the Repository](#contributing-to-the-repository)
+ - [Repository Content](#repository-content)
+ - [Installed Files](#installed-files)
+ - [Repository Set-Up](#repository-set-up)
+ - [Display Drivers](#display-drivers)
+ - [Download the Repository](#download-the-repository)
+ - [Repository Dependencies](#repository-dependencies)
+ - [Vulkan-Headers](#vulkan-headers)
+ - [Test Dependencies](#test-dependencies)
+ - [Build and Install Directories](#build-and-install-directories)
+ - [Building Dependent Repositories with Known-Good Revisions](#building-dependent-repositories-with-known-good-revisions)
+ - [Manually](#manually)
+ - [Notes About the Manual Option](#notes-about-the-manual-option)
+ - [Automatically](#automatically)
+ - [Notes About the Automatic Option](#notes-about-the-automatic-option)
+ - [Generated source code](#generated-source-code)
+ - [Build Options](#build-options)
+ - [Building On Windows](#building-on-windows)
+ - [Windows Development Environment Requirements](#windows-development-environment-requirements)
+ - [Windows Build - Microsoft Visual Studio](#windows-build---microsoft-visual-studio)
+ - [Windows Quick Start](#windows-quick-start)
+ - [Use `CMake` to Create the Visual Studio Project Files](#use-cmake-to-create-the-visual-studio-project-files)
+ - [Build the Solution From the Command Line](#build-the-solution-from-the-command-line)
+ - [Build the Solution With Visual Studio](#build-the-solution-with-visual-studio)
+ - [Windows Install Target](#windows-install-target)
+ - [Windows Notes](#windows-notes)
+ - [Using The Vulkan Loader Library in this Repository on Windows](#using-the-vulkan-loader-library-in-this-repository-on-windows)
+ - [Building On Linux](#building-on-linux)
+ - [Linux Development Environment Requirements](#linux-development-environment-requirements)
+ - [Required Package List](#required-package-list)
+ - [Linux Build](#linux-build)
+ - [Linux Quick Start](#linux-quick-start)
+ - [Use CMake to Create the Make Files](#use-cmake-to-create-the-make-files)
+ - [Build the Project](#build-the-project)
+ - [Linux Notes](#linux-notes)
+ - [Using The Vulkan Loader Library in this Repository on Linux](#using-the-vulkan-loader-library-in-this-repository-on-linux)
+ - [WSI Support Build Options](#wsi-support-build-options)
+ - [Linux Install to System Directories](#linux-install-to-system-directories)
+ - [Linux Uninstall](#linux-uninstall)
+ - [Linux 32-bit support](#linux-32-bit-support)
+ - [Building on MacOS](#building-on-macos)
+ - [MacOS Development Environment Requirements](#macos-development-environment-requirements)
+ - [Clone the Repository](#clone-the-repository)
+ - [MacOS build](#macos-build)
+ - [CMake Generators](#cmake-generators)
+ - [Building with the Unix Makefiles Generator](#building-with-the-unix-makefiles-generator)
+ - [Building with the Xcode Generator](#building-with-the-xcode-generator)
+ - [Using the new macOS loader](#using-the-new-macos-loader)
+ - [Building on Fuchsia](#building-on-fuchsia)
+ - [Building on QNX](#building-on-qnx)
+ - [SDK Symbols](#sdk-symbols)
+ - [Cross Compilation](#cross-compilation)
+ - [Unknown function handling which requires explicit assembly implementations](#unknown-function-handling-which-requires-explicit-assembly-implementations)
+ - [Platforms which fully support unknown function handling](#platforms-which-fully-support-unknown-function-handling)
+ - [Link Time Optimization](#link-time-optimization)
+ - [Tests](#tests)
## Contributing to the Repository
@@ -220,21 +251,39 @@
| BUILD_WSI_DIRECTFB_SUPPORT | Linux | `OFF` | Build the loader with the DirectFB entry points enabled. Without this, the DirectFB headers should not be needed, but the extension `VK_EXT_directfb_surface` won't be available. |
| BUILD_WSI_SCREEN_QNX_SUPPORT | QNX | `OFF` | Build the loader with the QNX Screen entry points enabled. Without this the extension `VK_QNX_screen_surface` won't be available. |
| ENABLE_WIN10_ONECORE | Windows | `OFF` | Link the loader to the [OneCore](https://msdn.microsoft.com/en-us/library/windows/desktop/mt654039.aspx) umbrella library, instead of the standard Win32 ones. |
-| USE_CCACHE | Linux | `OFF` | Enable caching with the CCache program. |
| USE_GAS | Linux | `ON` | Controls whether to build assembly files with the GNU assembler, else fallback to C code. |
| USE_MASM | Windows | `ON` | Controls whether to build assembly files with MS assembler, else fallback to C code |
| BUILD_STATIC_LOADER | macOS | `OFF` | This allows the loader to be built as a static library on macOS. Not tested, use at your own risk. |
The following is a table of all string options currently supported by this repository:
-| Option | Platform | Default | Description |
-| --------------------------- | ----------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
-| CMAKE_OSX_DEPLOYMENT_TARGET | MacOS | `10.12` | The minimum version of MacOS for loader deployment. |
-| FALLBACK_CONFIG_DIRS | Linux/MacOS | `/etc/xdg` | Configuration path(s) to use instead of `XDG_CONFIG_DIRS` if that environment variable is unavailable. The default setting is freedesktop compliant. |
-| FALLBACK_DATA_DIRS | Linux/MacOS | `/usr/local/share:/usr/share` | Configuration path(s) to use instead of `XDG_DATA_DIRS` if that environment variable is unavailable. The default setting is freedesktop compliant. |
-| BUILD_DLL_VERSIONINFO | Windows | `""` (empty string) | Allows setting the Windows specific version information for the Loader DLL. Format is "major.minor.patch.build". |
+| Option | Platform | Default | Description |
+| --------------------- | ----------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
+| FALLBACK_CONFIG_DIRS | Linux/MacOS | `/etc/xdg` | Configuration path(s) to use instead of `XDG_CONFIG_DIRS` if that environment variable is unavailable. The default setting is freedesktop compliant. |
+| FALLBACK_DATA_DIRS | Linux/MacOS | `/usr/local/share:/usr/share` | Configuration path(s) to use instead of `XDG_DATA_DIRS` if that environment variable is unavailable. The default setting is freedesktop compliant. |
+| BUILD_DLL_VERSIONINFO | Windows | `""` (empty string) | Allows setting the Windows specific version information for the Loader DLL. Format is "major.minor.patch.build". |
These variables should be set using the `-D` option when invoking CMake to generate the native platform files.
+### CCACHE
+
+There are 2 methods to enable CCACHE:
+
+1.) Set environment variables
+
+```bash
+# Requires CMake 3.17 (https://cmake.org/cmake/help/latest/envvar/CMAKE_LANG_COMPILER_LAUNCHER.html)
+export CMAKE_CXX_COMPILER_LAUNCHER=/usr/bin/ccache
+export CMAKE_C_COMPILER_LAUNCHER=/usr/bin/ccache
+```
+
+2.) Pass in cache variables
+
+```
+cmake ... -D CMAKE_CXX_COMPILER_LAUNCHER=/usr/bin/ccache -D CMAKE_C_COMPILER_LAUNCHER=/usr/bin/ccache
+```
+
+
+
## Building On Windows
### Windows Development Environment Requirements
@@ -243,9 +292,8 @@
- Any Personal Computer version supported by Microsoft
- Microsoft [Visual Studio](https://www.visualstudio.com/)
- Versions
- - [2015](https://www.visualstudio.com/vs/older-downloads/)
- - [2017](https://www.visualstudio.com/vs/older-downloads/)
- - [2019](https://www.visualstudio.com/vs/downloads/)
+ - [2022](https://www.visualstudio.com/vs/downloads/)
+ - [2017 & 2019](https://www.visualstudio.com/vs/older-downloads/)
- The Community Edition of each of the above versions is sufficient, as
well as any more capable edition.
- [CMake 3.10.2](https://cmake.org/files/v3.10/cmake-3.10.2-win64-x64.zip) is recommended.
@@ -271,7 +319,7 @@
cd Vulkan-Loader
mkdir build
cd build
- cmake -A x64 -DVULKAN_HEADERS_INSTALL_DIR=absolute_path_to_install_dir ..
+ cmake -A x64 -DUPDATE_DEPS=ON ..
cmake --build .
The above commands instruct CMake to find and use the default Visual Studio
@@ -279,10 +327,6 @@
architecture. The second CMake command builds the Debug (default)
configuration of the solution.
-Note that if you do not wish to use a developer command prompt, you may either
-run either `vcvars64.bat` or `vcvars32.bat` to set the required environment
-variables.
-
#### Use `CMake` to Create the Visual Studio Project Files
Change your current directory to the top of the cloned repository directory,
@@ -291,26 +335,25 @@
cd Vulkan-Loader
mkdir build
cd build
- cmake -A x64 -DVULKAN_HEADERS_INSTALL_DIR=absolute_path_to_install_dir ..
+ cmake -DUPDATE_DEPS=ON -G "Visual Studio 16 2019" -A x64 ..
> Note: The `..` parameter tells `cmake` the location of the top of the
> repository. If you place your build directory someplace else, you'll need to
-> specify the location of the repository top differently.
+> specify the location of the repository differently.
-The `-A` option is used to select either the "Win32" or "x64" architecture.
+The `-G` option is used to select the generator
-If a generator for a specific version of Visual Studio is required, you can
-specify it for Visual Studio 2015, for example, with:
+Supported Visual Studio generators:
+* `Visual Studio 17 2022`
+* `Visual Studio 16 2019`
+* `Visual Studio 15 2017`
- 64-bit: -G "Visual Studio 14 2015 Win64"
- 32-bit: -G "Visual Studio 14 2015"
-
-See this [list](#cmake-visual-studio-generators) of other possible generators
-for Visual Studio.
+The `-A` option is used to select either the "Win32", "x64", or "ARM64 architecture.
When generating the project files, the absolute path to a Vulkan-Headers
-install directory must be provided. This can be done by setting the
-`VULKAN_HEADERS_INSTALL_DIR` environment variable or by setting the
+install directory must be provided. This can be done automatically by the
+`-DUPDATE_DEPS=ON` option, by directly setting the
+`VULKAN_HEADERS_INSTALL_DIR` environment variable, or by setting the
`VULKAN_HEADERS_INSTALL_DIR` CMake variable with the `-D` CMake option. In
either case, the variable should point to the installation directory of a
Vulkan-Headers repository built with the install target.
@@ -347,8 +390,8 @@
style directory structure. This may be useful for collecting the artifacts and
providing them to another project that is dependent on them.
-The default location is `$CMAKE_BINARY_DIR\install`, but can be changed with
-the `CMAKE_INSTALL_PREFIX` variable when first generating the project build
+The default location is `$CMAKE_CURRENT_BINARY_DIR\install`, but can be changed
+with the `CMAKE_INSTALL_PREFIX` variable when first generating the project build
files with CMake.
You can build the install target from the command line with:
@@ -357,48 +400,9 @@
or build the `INSTALL` target from the Visual Studio solution explorer.
-### Windows Tests
-
-The Vulkan-Loader repository contains some simple unit tests for the loader
-but no other test clients.
-
-To run the loader test script, open a Powershell Console, change to the
-`build\tests` directory, and run:
-
-For Release builds:
-
- .\run_all_tests.ps1
-
-For Debug builds:
-
- .\run_all_tests.ps1 -Debug
-
-This script will run the following tests:
-
-- `vk_loader_validation_tests`:
- Vulkan loader handle wrapping, allocation callback, and loader/layer interface tests
-
-You can also change to either `build\tests\Debug` or `build\tests\Release`
-(depending on which one you built) and run the executable tests (`*.exe`)
-files from there.
### Windows Notes
-#### CMake Visual Studio Generators
-
-The chosen generator should match one of the Visual Studio versions that you
-have installed. Generator strings that correspond to versions of Visual Studio
-include:
-
-| Build Platform | 64-bit Generator | 32-bit Generator |
-| ---------------------------- | ----------------------------- | ----------------------- |
-| Microsoft Visual Studio 2015 | "Visual Studio 14 2015 Win64" | "Visual Studio 14 2015" |
-| Microsoft Visual Studio 2017 | "Visual Studio 15 2017 Win64" | "Visual Studio 15 2017" |
-| Microsoft Visual Studio 2019 | "Visual Studio 16 2019" | "Visual Studio 16 2019" |
-
-Note that with Visual Studio 2019, the architecture will need to be specified with the `-A`
-flag for 64-bit builds.
-
#### Using The Vulkan Loader Library in this Repository on Windows
Vulkan programs must be able to find and use the Vulkan loader
@@ -408,14 +412,13 @@
library and the "googletest" libraries to the `build\tests\Debug` or the
`build\tests\Release` directory, which is where the
`vk_loader_validation_test.exe` executable is found, depending on what
-configuration you built. (The loader validation tests use the "googletest"
-testing framework.)
+configuration you built.
Other techniques include placing the library in a system folder
(C:\Windows\System32) or in a directory that appears in the `PATH` environment
variable.
-See the `LoaderAndLayerInterface` document in the `loader` folder in this
+See the documentation in the `docs` folder in this
repository for more information on how the loader finds driver libraries and
layer libraries. The document also describes both how ICDs and layers should
be packaged, and how developers can point to ICDs and layers within their
@@ -426,7 +429,7 @@
### Linux Development Environment Requirements
This repository has been built and tested on the two most recent Ubuntu LTS
-versions. Currently, the oldest supported version is Ubuntu 16.04, meaning
+versions. Currently, the oldest supported version is Ubuntu 18.04, meaning
that the minimum officially supported C++11 compiler version is GCC 5.4.0,
although earlier versions may work. It should be straightforward to adapt this
repository to other Linux distributions.
@@ -448,7 +451,7 @@
cd Vulkan-Loader
mkdir build
cd build
- cmake -DVULKAN_HEADERS_INSTALL_DIR=absolute_path_to_install_dir ..
+ cmake -DUPDATE_DEPS=ON ..
make
See below for the details.
@@ -472,8 +475,9 @@
Use `-DCMAKE_BUILD_TYPE` to specify a Debug or Release build.
When generating the project files, the absolute path to a Vulkan-Headers
-install directory must be provided. This can be done by setting the
-`VULKAN_HEADERS_INSTALL_DIR` environment variable or by setting the
+install directory must be provided. This can be done automatically by the
+`-DUPDATE_DEPS=ON` option, by directly setting the
+`VULKAN_HEADERS_INSTALL_DIR` environment variable, or by setting the
`VULKAN_HEADERS_INSTALL_DIR` CMake variable with the `-D` CMake option. In
either case, the variable should point to the installation directory of a
Vulkan-Headers repository built with the install target.
@@ -496,20 +500,11 @@
cmake --build .
-If your build system supports ccache, you can enable that via CMake option
-`-DUSE_CCACHE=On`
-
### Linux Notes
#### Using The Vulkan Loader Library in this Repository on Linux
-The `vk_loader_validation_tests` executable is linked with an RPATH setting to
-allow it to find the Vulkan loader library in the repository's build
-directory. This allows the test executable to run and find this Vulkan loader
-library without installing the loader library to a directory searched by the
-system loader or in the `LD_LIBRARY_PATH`.
-
-If you want to test a Vulkan application that is not built within this
+If you want to run a Vulkan application that is not built within this
repository with the loader you just built from this repository, you can direct
the application to load it from your build directory:
@@ -588,19 +583,6 @@
sudo make uninstall
-#### Linux Tests
-
-The Vulkan-Loader repository contains some simple unit tests for the loader
-but no other test clients.
-
-To run the loader test script, change to the `build/tests` directory, and run:
-
- ./run_all_tests.sh
-
-This script will run the following tests:
-
-- `vk_loader_validation_tests`: Vulkan loader handle wrapping, allocation
- callback, and loader/layer interface tests
#### Linux 32-bit support
@@ -634,7 +616,9 @@
### MacOS Development Environment Requirements
-Tested on OSX version 10.12.6
+Tested on OSX version 10.12
+
+NOTE: To force the OSX version set the environment variable [MACOSX_DEPLOYMENT_TARGET](https://cmake.org/cmake/help/latest/envvar/MACOSX_DEPLOYMENT_TARGET.html) when building VVL and it's dependencies.
Setup Homebrew and components
@@ -675,15 +659,16 @@
This generator is the default generator.
When generating the project files, the absolute path to a Vulkan-Headers
-install directory must be provided. This can be done by setting the
-`VULKAN_HEADERS_INSTALL_DIR` environment variable or by setting the
+install directory must be provided. This can be done automatically by the
+`-DUPDATE_DEPS=ON` option, by directly setting the
+`VULKAN_HEADERS_INSTALL_DIR` environment variable, or by setting the
`VULKAN_HEADERS_INSTALL_DIR` CMake variable with the `-D` CMake option. In
either case, the variable should point to the installation directory of a
Vulkan-Headers repository built with the install target.
mkdir build
cd build
- cmake -DVULKAN_HEADERS_INSTALL_DIR=absolute_path_to_install_dir -DCMAKE_BUILD_TYPE=Debug ..
+ cmake -DUPDATE_DEPS=ON -DVULKAN_HEADERS_INSTALL_DIR=absolute_path_to_install_dir -DCMAKE_BUILD_TYPE=Debug ..
make
To speed up the build on a multi-core machine, use the `-j` option for `make`
@@ -710,23 +695,6 @@
export DYLD_LIBRARY_PATH=<path to your repository>/build/loader
-### MacOS Tests
-
-The Vulkan-Loader repository contains some simple unit tests for the loader
-but no other test clients.
-
-Before you run these tests, you will need to clone and build the
-[MoltenVK](https://github.com/KhronosGroup/MoltenVK) repository.
-
-You will also need to direct your new loader to the MoltenVK ICD:
-
- export VK_DRIVER_FILES=<path to MoltenVK repository>/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json
-
-To run the loader test script, change to the `build/tests` directory in your
-Vulkan-Loader repository, and run:
-
- ./vk_loader_validation_tests
-
## Building on Fuchsia
Fuchsia uses the project's GN build system to integrate with the Fuchsia platform build.
@@ -744,3 +712,40 @@
The Vulkan Loader is a component of the Fuchsia SDK, so it must explicitly declare its exported symbols in
the file vulkan.symbols.api; see [SDK](https://fuchsia.dev/fuchsia-src/development/sdk).
+
+## Cross Compilation
+
+While this repo is capable of cross compilation, there are a handful of caveats.
+
+### Unknown function handling which requires explicit assembly implementations
+
+Unknown function handling is only fully supported on select platforms due to the
+need for assembly in the implementation. Other platforms will need to disable
+assembly by setting `USE_GAS` or `USE_MASM` to `OFF`.
+#### Platforms which fully support unknown function handling
+
+* 64 bit Windows (x64)
+* 32 bit Windows (x86)
+* 64 bit Linux (x64)
+* 32 bit Linux (x86)
+* 64 bit Arm (aarch64)
+
+Platforms not listed will use a fallback C Code path that relies on tail-call optimization to work.
+No guarantees are made about the use of the fallback code paths.
+
+### Link Time Optimization
+
+When cross compiling, the use of Link Time Optimization (LTO) and unknown function handling
+is not supported. Either LTO needs to be turned off, or the assembly should be disabled.
+
+## Tests
+
+To build tests, make sure that the `BUILD_TESTS` option is set to true. Using
+the command line, this looks like `-DBUILD_TESTS=ON`.
+
+This project is configured to run with `ctest`, which makes it easy to run the
+tests. To run the tests, change the directory to that of the build direction, and
+execute `ctest`.
+
+More details can be found in the [README.md](./tests/README.md) for the tests
+directory of this project.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 645afe7..e71de78 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,11 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ~~~
-
cmake_minimum_required(VERSION 3.10.2)
-
-# Apple: Must be set before enable_language() or project() as it may influence configuration of the toolchain and flags.
-set(CMAKE_OSX_DEPLOYMENT_TARGET "10.12" CACHE STRING "Minimum OS X deployment version")
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# If we are building in Visual Studio 2015 and with a CMake version 3.19 or greater, we need to set this variable
# so that CMake will choose a Windows SDK version higher than 10.0.14393.0, as dxgi1_6.h is only found in Windows SDK
@@ -33,7 +30,9 @@
if (CMAKE_GENERATOR_PLATFORM)
set(_target_arch ${CMAKE_GENERATOR_PLATFORM})
else()
- message(WARNING "CMAKE_GENERATOR_PLATFORM not set. Using x64 as target architecture.")
+ if (MSVC_IDE)
+ message(WARNING "CMAKE_GENERATOR_PLATFORM not set. Using x64 as target architecture.")
+ endif()
set(_target_arch x64)
endif()
@@ -50,7 +49,7 @@
endif()
message("********************************************************************************")
- message("* NOTE: Adding target vl_update_deps to run as needed for updating *")
+ message("* NOTE: Adding target vl_update_deps to run as needed for updating *")
message("* dependencies. *")
message("********************************************************************************")
@@ -80,8 +79,10 @@
message("********************************************************************************")
find_package(PythonInterp 3 QUIET)
endif()
+if (VULKAN_HEADERS_INSTALL_DIR)
+ list(APPEND CMAKE_PREFIX_PATH ${VULKAN_HEADERS_INSTALL_DIR})
+endif()
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(PythonInterp 3 QUIET)
set(THREADS_PREFER_PTHREAD_FLAG ON)
@@ -108,44 +109,12 @@
"or tested as part of the loader. Use it at your own risk.")
endif()
-if (TARGET Vulkan::Headers)
- message(STATUS "Using Vulkan headers from Vulkan::Headers target")
- get_target_property(VulkanHeaders_INCLUDE_DIRS Vulkan::Headers INTERFACE_INCLUDE_DIRECTORIES)
- get_target_property(VulkanRegistry_DIR Vulkan::Registry INTERFACE_INCLUDE_DIRECTORIES)
-else()
- find_package(VulkanHeaders)
- if(NOT ${VulkanHeaders_FOUND})
- message(FATAL_ERROR "Could not find Vulkan headers path. This can be fixed by setting VULKAN_HEADERS_INSTALL_DIR to an "
- "installation of the Vulkan-Headers repository.")
- endif()
- if(NOT ${VulkanRegistry_FOUND})
- message(FATAL_ERROR "Could not find Vulkan registry path. This can be fixed by setting VULKAN_HEADERS_INSTALL_DIR to an "
- "installation of the Vulkan-Headers repository.")
- endif()
-
- # set up the Vulkan::Headers target for consistency
- add_library(vulkan-headers INTERFACE)
- target_include_directories(vulkan-headers SYSTEM INTERFACE "${VulkanHeaders_INCLUDE_DIRS}")
- add_library(Vulkan::Headers ALIAS vulkan-headers)
-endif()
-
-option(USE_CCACHE "Use ccache" OFF)
-if(USE_CCACHE)
- find_program(CCACHE_FOUND ccache)
- if(CCACHE_FOUND)
- set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
- endif()
-endif()
+find_package(VulkanHeaders REQUIRED CONFIG QUIET)
include(GNUInstallDirs)
if(UNIX AND NOT APPLE) # i.e.: Linux
- include(FindPkgConfig)
-endif()
-
-if(APPLE)
- # CMake versions 3 or later need CMAKE_MACOSX_RPATH defined. This avoids the CMP0042 policy message.
- set(CMAKE_MACOSX_RPATH 1)
+ find_package(PkgConfig)
endif()
set(GIT_BRANCH_NAME "--unknown--")
@@ -172,7 +141,7 @@
if(WIN32 AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
# Windows: if install locations not set by user, set install prefix to "<build_dir>\install".
- set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "default install path" FORCE)
+ set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/install" CACHE PATH "default install path" FORCE)
endif()
# Enable IDE GUI folders. "Helper targets" that don't have interesting source code should set their FOLDER property to this
@@ -215,11 +184,6 @@
find_package(X11 REQUIRED)
endif()
- if(BUILD_WSI_WAYLAND_SUPPORT)
- find_package(Wayland REQUIRED)
- include_directories(SYSTEM ${WAYLAND_CLIENT_INCLUDE_DIR})
- endif()
-
if(BUILD_WSI_DIRECTFB_SUPPORT)
find_package(DirectFB REQUIRED)
include_directories(SYSTEM ${DIRECTFB_INCLUDE_DIR})
@@ -301,13 +265,8 @@
target_compile_options(loader_common_options INTERFACE -fno-strict-aliasing -fno-builtin-memcmp)
endif()
- # For GCC version 7.1 or greater, we need to disable the implicit fallthrough warning since there's no consistent way to satisfy
- # all compilers until they all accept the C++17 standard
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(loader_common_options INTERFACE -Wno-stringop-truncation -Wno-stringop-overflow)
- if(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 7.1)
- target_compile_options(loader_common_options INTERFACE -Wimplicit-fallthrough=0)
- endif()
endif()
if(UNIX)
@@ -360,6 +319,7 @@
# Optional codegen target
if(PYTHONINTERP_FOUND)
+ get_target_property(VulkanRegistry_DIR Vulkan::Registry INTERFACE_INCLUDE_DIRECTORIES)
add_custom_target(VulkanLoader_generated_source
COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/generate_source.py
${VulkanRegistry_DIR} --incremental
@@ -498,7 +458,7 @@
endif()
if (BUILD_TESTS)
- add_subdirectory(tests ${CMAKE_BINARY_DIR}/tests)
+ add_subdirectory(tests)
endif()
endif()
diff --git a/build-qnx/common.mk b/build-qnx/common.mk
index d851f7f..a0d2a73 100644
--- a/build-qnx/common.mk
+++ b/build-qnx/common.mk
@@ -31,7 +31,7 @@
CCFLAGS += -DVK_USE_PLATFORM_SCREEN_QNX=1 -Dvulkan_EXPORTS
CCFLAGS += -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
CCFLAGS += -fno-strict-aliasing -fno-builtin-memcmp -Wno-stringop-truncation
-CCFLAGS += -Wno-stringop-overflow -Wimplicit-fallthrough=0 -fvisibility=hidden
+CCFLAGS += -Wno-stringop-overflow -fvisibility=hidden
CCFLAGS += -Wpointer-arith -fPIC
# Enable this if required
diff --git a/cmake/FindVulkanHeaders.cmake b/cmake/FindVulkanHeaders.cmake
deleted file mode 100644
index 0b4585d..0000000
--- a/cmake/FindVulkanHeaders.cmake
+++ /dev/null
@@ -1,154 +0,0 @@
-#.rst:
-# FindVulkanHeaders
-# -----------------
-#
-# Try to find Vulkan Headers and Registry.
-#
-# This module is intended to be used by projects that build Vulkan
-# "system" components such as the loader and layers.
-# Vulkan applications should instead use the FindVulkan (or similar)
-# find module that locates the headers and the loader library.
-#
-# When using this find module to locate the headers and registry
-# in a Vulkan-Headers repository, the Vulkan-Headers repository
-# should be built with 'install' target and the following environment
-# or CMake variable set to the location of the install directory.
-#
-# VULKAN_HEADERS_INSTALL_DIR
-#
-# IMPORTED Targets
-# ^^^^^^^^^^^^^^^^
-#
-# This module defines no IMPORTED targets
-#
-# Result Variables
-# ^^^^^^^^^^^^^^^^
-#
-# This module defines the following variables::
-#
-# VulkanHeaders_FOUND - True if VulkanHeaders was found
-# VulkanHeaders_INCLUDE_DIRS - include directories for VulkanHeaders
-#
-# VulkanRegistry_FOUND - True if VulkanRegistry was found
-# VulkanRegistry_DIRS - directories for VulkanRegistry
-#
-# VulkanHeaders_VERSION_MAJOR - The Major API version of the latest version
-# contained in the Vulkan header
-# VulkanHeaders_VERSION_MINOR - The Minor API version of the latest version
-# contained in the Vulkan header
-# VulkanHeaders_VERSION_PATCH - The Patch API version of the latest version
-# contained in the Vulkan header
-#
-# The module will also define two cache variables::
-#
-# VulkanHeaders_INCLUDE_DIR - the VulkanHeaders include directory
-# VulkanRegistry_DIR - the VulkanRegistry directory
-#
-
-# Probe command-line arguments and the environment to see if they specify the
-# Vulkan headers installation path.
-if(NOT DEFINED VULKAN_HEADERS_INSTALL_DIR)
- if (DEFINED ENV{VULKAN_HEADERS_INSTALL_DIR})
- set(VULKAN_HEADERS_INSTALL_DIR "$ENV{VULKAN_HEADERS_INSTALL_DIR}")
- elseif(DEFINED ENV{VULKAN_SDK})
- set(VULKAN_HEADERS_INSTALL_DIR "$ENV{VULKAN_SDK}/include")
- endif()
-endif()
-
-if(DEFINED VULKAN_HEADERS_INSTALL_DIR)
- # When CMAKE_FIND_ROOT_PATH_INCLUDE is set to ONLY, the HINTS in find_path()
- # are re-rooted, which prevents VULKAN_HEADERS_INSTALL_DIR to work as
- # expected. So use NO_CMAKE_FIND_ROOT_PATH to avoid it.
-
- # Use HINTS instead of PATH to search these locations before
- # searching system environment variables like $PATH that may
- # contain SDK directories.
- find_path(VulkanHeaders_INCLUDE_DIR
- NAMES vulkan/vulkan.h
- HINTS ${VULKAN_HEADERS_INSTALL_DIR}/include
- NO_CMAKE_FIND_ROOT_PATH)
- find_path(VulkanRegistry_DIR
- NAMES vk.xml
- HINTS ${VULKAN_HEADERS_INSTALL_DIR}/share/vulkan/registry
- NO_CMAKE_FIND_ROOT_PATH)
-else()
- # If VULKAN_HEADERS_INSTALL_DIR, or one of its variants was not specified,
- # do a normal search without hints.
- find_path(VulkanHeaders_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS "${CMAKE_CURRENT_SOURCE_DIR}/external/Vulkan-Headers/include" NO_CMAKE_FIND_ROOT_PATH)
- get_filename_component(VULKAN_REGISTRY_PATH_HINT ${VulkanHeaders_INCLUDE_DIR} DIRECTORY)
- find_path(VulkanRegistry_DIR NAMES vk.xml HINTS ${VULKAN_REGISTRY_PATH_HINT}/share/vulkan/registry
- "${VULKAN_REGISTRY_PATH_HINT}/registry" NO_CMAKE_FIND_ROOT_PATH)
-endif()
-
-set(VulkanHeaders_INCLUDE_DIRS ${VulkanHeaders_INCLUDE_DIR})
-set(VulkanRegistry_DIRS ${VulkanRegistry_DIR})
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(VulkanHeaders
- DEFAULT_MSG
- VulkanHeaders_INCLUDE_DIR)
-set(FPHSA_NAME_MISMATCHED TRUE)
-find_package_handle_standard_args(VulkanRegistry
- DEFAULT_MSG
- VulkanRegistry_DIR)
-unset(FPHSA_NAME_MISMATCHED)
-
-mark_as_advanced(VulkanHeaders_INCLUDE_DIR VulkanRegistry_DIR)
-
-# Determine the major/minor/patch version from the vulkan header
-set(VulkanHeaders_VERSION_MAJOR "0")
-set(VulkanHeaders_VERSION_MINOR "0")
-set(VulkanHeaders_VERSION_PATCH "0")
-
-# First, determine which header we need to grab the version information from.
-# Starting with Vulkan 1.1, we should use vulkan_core.h, but prior to that,
-# the information was in vulkan.h.
-if (EXISTS "${VulkanHeaders_INCLUDE_DIR}/vulkan/vulkan_core.h")
- set(VulkanHeaders_main_header ${VulkanHeaders_INCLUDE_DIR}/vulkan/vulkan_core.h)
-else()
- set(VulkanHeaders_main_header ${VulkanHeaders_INCLUDE_DIR}/vulkan/vulkan.h)
-endif()
-
-# Find all lines in the header file that contain any version we may be interested in
-# NOTE: They start with #define and then have other keywords
-file(STRINGS
- ${VulkanHeaders_main_header}
- VulkanHeaders_lines
- REGEX "^#define VK_HEADER_VERSION(_COMPLETE)? ")
-
-foreach(VulkanHeaders_line ${VulkanHeaders_lines})
-
- # First, handle the case where we have a major/minor version
- # Format is:
- # #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, X, Y, VK_HEADER_VERSION)
- # We grab the major version (X) and minor version (Y) out of the parentheses
- string(REGEX MATCH "VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION\\(.*\\)" VulkanHeaders_out ${VulkanHeaders_line})
- string(REGEX MATCHALL "[0-9]+" VulkanHeaders_MAJOR_MINOR "${VulkanHeaders_out}")
- if (VulkanHeaders_MAJOR_MINOR)
- list (GET VulkanHeaders_MAJOR_MINOR 1 VulkanHeaders_cur_major)
- list (GET VulkanHeaders_MAJOR_MINOR 2 VulkanHeaders_cur_minor)
- if (${VulkanHeaders_cur_major} GREATER ${VulkanHeaders_VERSION_MAJOR})
- set(VulkanHeaders_VERSION_MAJOR ${VulkanHeaders_cur_major})
- set(VulkanHeaders_VERSION_MINOR ${VulkanHeaders_cur_minor})
- endif()
- if (${VulkanHeaders_cur_major} EQUAL ${VulkanHeaders_VERSION_MAJOR} AND
- ${VulkanHeaders_cur_minor} GREATER ${VulkanHeaders_VERSION_MINOR})
- set(VulkanHeaders_VERSION_MINOR ${VulkanHeaders_cur_minor})
- endif()
- endif()
-
- # Second, handle the case where we have the patch version
- # Format is:
- # #define VK_HEADER_VERSION Z
- # Where Z is the patch version which we just grab off the end
- string(REGEX MATCH "define.*VK_HEADER_VERSION[^_].*[0-9]+" VulkanHeaders_out ${VulkanHeaders_line})
- list(LENGTH VulkanHeaders_out VulkanHeaders_len)
- if (VulkanHeaders_len)
- string(REGEX MATCH "[0-9]+" VulkanHeaders_VERSION_PATCH "${VulkanHeaders_out}")
- endif()
-
-endforeach()
-MESSAGE(STATUS
- "Detected Vulkan Version ${VulkanHeaders_VERSION_MAJOR}."
- "${VulkanHeaders_VERSION_MINOR}."
- "${VulkanHeaders_VERSION_PATCH}")
diff --git a/cmake/FindWayland.cmake b/cmake/FindWayland.cmake
deleted file mode 100644
index a94c151..0000000
--- a/cmake/FindWayland.cmake
+++ /dev/null
@@ -1,68 +0,0 @@
-# Try to find Wayland on a Unix system
-#
-# This will define:
-#
-# WAYLAND_FOUND - True if Wayland is found
-# WAYLAND_LIBRARIES - Link these to use Wayland
-# WAYLAND_INCLUDE_DIR - Include directory for Wayland
-# WAYLAND_DEFINITIONS - Compiler flags for using Wayland
-#
-# In addition the following more fine grained variables will be defined:
-#
-# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
-# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
-# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
-#
-# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-IF (NOT WIN32)
- IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
- # In the cache already
- SET(WAYLAND_FIND_QUIETLY TRUE)
- ENDIF ()
-
- # Use pkg-config to get the directories and then use these values
- # in the FIND_PATH() and FIND_LIBRARY() calls
- FIND_PACKAGE(PkgConfig)
- PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor)
-
- SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})
-
- FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
- FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
- FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
- FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
-
- FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
- FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
- FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
- FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
-
- set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR})
-
- set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES})
-
- list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR)
-
- include(FindPackageHandleStandardArgs)
-
- set(FPHSA_NAME_MISMATCHED TRUE)
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR)
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR)
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR)
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CURSOR DEFAULT_MSG WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR)
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR)
- unset(FPHSA_NAME_MISMATCHED)
-
- MARK_AS_ADVANCED(
- WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES
- WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
- WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
- WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
- WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES
- )
-
-ENDIF ()
diff --git a/docs/LoaderApplicationInterface.md b/docs/LoaderApplicationInterface.md
index c9af034..9b9eef2 100644
--- a/docs/LoaderApplicationInterface.md
+++ b/docs/LoaderApplicationInterface.md
@@ -7,7 +7,7 @@
# Application Interface to Loader
[![Creative Commons][3]][4]
-<!-- Copyright © 2015-2021 LunarG, Inc. -->
+<!-- Copyright © 2015-2022 LunarG, Inc. -->
[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
[4]: https://creativecommons.org/licenses/by-nd/4.0/
@@ -36,9 +36,6 @@
- [Forcing Layers to be Enabled on Windows, Linux and macOS](#forcing-layers-to-be-enabled-on-windows-linux-and-macos)
- [Overall Layer Ordering](#overall-layer-ordering)
- [Debugging Possible Layer Issues](#debugging-possible-layer-issues)
- - [Enable Loader Debug Layer Output](#enable-loader-debug-layer-output)
- - [Disable All Layers](#disable-all-layers)
- - [Enable More Loader Debug Output](#enable-more-loader-debug-output)
- [Application Usage of Extensions](#application-usage-of-extensions)
- [Instance and Device Extensions](#instance-and-device-extensions)
- [WSI Extensions](#wsi-extensions)
@@ -474,7 +471,7 @@
1. Selecting specific layer paths using the
[VkConfig](https://github.com/LunarG/VulkanTools/blob/master/vkconfig/README.md)
tool shipped with the Vulkan SDK.
- 2. Directing the loader to look for layers in specific folders by using the
+ 2. Directing the loader to look for layers in specific files and/or folders by using the
`VK_LAYER_PATH` environment variable.
The `VK_LAYER_PATH` environment variable can contain multiple paths separated by
@@ -482,7 +479,7 @@
On Windows, this is a semicolon (`;`), while on Linux and macOS it is a colon
(`:`).
-If `VK_LAYER_PATH` exists, the folders listed in it will be scanned for explicit
+If `VK_LAYER_PATH` exists, the files and/or folders listed will be scanned for explicit
layer manifest files.
Implicit layer discovery is unaffected by this environment variable.
Each directory listed should be the full pathname of a folder containing layer
@@ -572,140 +569,10 @@
### Debugging Possible Layer Issues
If it is possible that a layer is causing issues, there are several things that
-can be tried.
-
-
-#### Enable Loader Debug Layer Output
-
-First, enable the "layer" debug output option (`VK_LOADER_DEBUG`) in the loader,
-See the
-[Table of Debug Environment Variables](LoaderInterfaceArchitecture.md##table-of-debug-environment-variables)
-for more info.
-
-When enabled, the loader will output information on:
- * Where it looks for implicit layers
- * Where it looks for explicit layers
- * What manifest files it finds
- * Which layer manifest files are loaded
- * What libraries are associated with a layer
- * What the layer callstack looks like for both the instance and device chain
-
-For example, the layer output for searching for implicit layers on Linux may
-look like:
-
-```
-LAYER: Searching for layer manifest files
-LAYER: In following folders:
-LAYER: /home/linust/.config/vulkan/implicit_layer.d
-LAYER: /etc/xdg/vulkan/implicit_layer.d
-LAYER: /usr/local/etc/vulkan/implicit_layer.d
-LAYER: /etc/vulkan/implicit_layer.d
-LAYER: /home/linust/.local/share/vulkan/implicit_layer.d
-LAYER: /home/linust/.local/share/flatpak/exports/share/vulkan/implicit_layer.d
-LAYER: /var/lib/flatpak/exports/share/vulkan/implicit_layer.d
-LAYER: /usr/local/share/vulkan/implicit_layer.d
-LAYER: /usr/share/vulkan/implicit_layer.d
-LAYER: Found the following files:
-LAYER: /home/linust/.local/share/vulkan/implicit_layer.d/renderdoc_capture.json
-LAYER: /home/linust/.local/share/vulkan/implicit_layer.d/steamfossilize_i386.json
-LAYER: /home/linust/.local/share/vulkan/implicit_layer.d/steamfossilize_x86_64.json
-LAYER: /home/linust/.local/share/vulkan/implicit_layer.d/steamoverlay_i386.json
-LAYER: /home/linust/.local/share/vulkan/implicit_layer.d/steamoverlay_x86_64.json
-LAYER: /usr/share/vulkan/implicit_layer.d/nvidia_layers.json
-LAYER: /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
-```
-
-In the above scenario, seven implicit layers were discovered in two different
-folders.
-Just because they were found does not mean that they will be loaded, but this
-information can be used to make sure a layer JSON file was properly discovered.
-
-When the loader actually loads a layer, the messages may look like the
-following:
-
-```
-LAYER | DEBUG: Loading layer library libVkLayer_khronos_validation.so
-LAYER | INFO: Insert instance layer VK_LAYER_KHRONOS_validation (libVkLayer_khronos_validation.so)
-LAYER | DEBUG: Loading layer library libVkLayer_MESA_device_select.so
-LAYER | INFO: Insert instance layer VK_LAYER_MESA_device_select (libVkLayer_MESA_device_select.so)
-```
-
-This information does not indicate the order the layers are used in.
-That information is displayed later showing all the callstack during both
-`vkCreateInstance` and `vkCreateDevice`.
-In the same sample above, the callstack for `vkCreateInstance` looks like the
-following:
-
-```
-LAYER: vkCreateInstance layer callstack setup to:
-LAYER: <Application>
-LAYER: ||
-LAYER: <Loader>
-LAYER: ||
-LAYER: VK_LAYER_MESA_device_select
-LAYER: Type: Implicit
-LAYER: Disable Env Var: NODEVICE_SELECT
-LAYER: Manifest: /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
-LAYER: Library: libVkLayer_MESA_device_select.so
-LAYER: ||
-LAYER: VK_LAYER_KHRONOS_validation
-LAYER: Type: Explicit
-LAYER: Manifest: /usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
-LAYER: Library: libVkLayer_khronos_validation.so
-LAYER: ||
-LAYER: <Drivers>
-```
-
-In this scenario, two layers were used (the same two that were loaded earlier):
-* `VK_LAYER_MESA_device_select`
-* `VK_LAYER_KHRONOS_validation`
-
-This information now shows us that the `VK_LAYER_MESA_device_select` is loaded
-first, followed by `VK_LAYER_KHRONOS_validation` which will then continue into
-any available drivers.
-It also shows that `VK_LAYER_MESA_device_select` is an implicit layer which
-implies that it wasn't directly enabled by the application.
-On the other hand, `VK_LAYER_KHRONOS_validation` is shown as an explicit layer
-which indicates that it was likely enabled by the application.
-
-Sometimes, implicit layers can cause issues with an application.
-Because of this, the next step is to try to disable one or more of the listed
-implicit layers.
-This can be done by defining the disable environment variable for that layer.
-Each layer has it's own disable environment variable as mentioned in the
-[Layer Manifest File Format](LoaderLayerInterface.md#layer-manifest-file-format).
-However, it can be difficult to find this variable in the manifest files, so
-the loader now outputs it as part of the callstack information.
-Looking at the above `vkCreateInstance` callstack output, under the
-section for `VK_LAYER_MESA_device_select` exists a section listed as
-"Disable Env Var:".
-This is the disable environment variable that can be used to disable the
-`VK_LAYER_MESA_device_select` layer from being loaded by the loader.
-In the above output, the disable environment variable is listed as
-"NODEVICE_SELECT" which can be defined to a non-zero value to cause the loader
-to ignore this layer.
-
-
-#### Disable All Layers
-
-Because implicit layers are virtually unknown to the application, it is best to
-next try to disable each one of them.
-Using the above debug output, define each environment variable to disable the
-corresponding implicit layer that was used.
-
-Once all are disabled, re-run the application again.
-
-If the failure still occurs, try disabling all explicit layers loaded by the
-application by modifying the application or using a tool such as
-[VkConfig](https://github.com/LunarG/VulkanTools/blob/master/vkconfig/README.md).
-
-
-#### Enable More Loader Debug Output
-
-If the failure continues after disabling all layers, then enable all loader
-debug warnings and errors by setting `VK_LOADER_DEBUG` to "error,warn" or
-even "all".
-This will output any other issues that the loader has encountered.
+can be tried which are documented in the
+[Debugging Possible Layer Issues](LoaderDebugging.md#debugging-possible-layer-issues)
+section of the [LoaderDebugging.mg](LoaderDebugging.md) document in the docs
+folder.
## Application Usage of Extensions
diff --git a/docs/LoaderDebugging.md b/docs/LoaderDebugging.md
new file mode 100644
index 0000000..1704c8f
--- /dev/null
+++ b/docs/LoaderDebugging.md
@@ -0,0 +1,331 @@
+<!-- markdownlint-disable MD041 -->
+[![Khronos Vulkan][1]][2]
+
+[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
+[2]: https://www.khronos.org/vulkan/
+
+# Debugging The Vulkan Desktop Loader
+[![Creative Commons][3]][4]
+
+<!-- Copyright © 2015-2022 LunarG, Inc. -->
+
+[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
+[4]: https://creativecommons.org/licenses/by-nd/4.0/
+## Table of Contents
+
+- [Debugging Issues](#debugging-issues)
+- [Loader Logging](#loader-logging)
+- [Debugging Possible Layer Issues](#debugging-possible-layer-issues)
+ - [Enable Layer Logging](#enable-layer-logging)
+ - [Disable Layers](#disable-layers)
+ - [Selectively Re-enable Layers](#selectively-re-enable-layers)
+- [Debugging Possible Driver Issues](#debugging-possible-driver-issues)
+ - [Enable Driver Logging](#enable-driver-logging)
+ - [Selectively Enable Specific Drivers](#selectively-enable-specific-drivers)
+
+## Debugging Issues
+
+If your application is crashing or behaving weirdly, the loader provides
+several mechanisms for you to debug the issues.
+
+**NOTE**: This functionality is all specific to the desktop Vulkan loader and
+does not work for the Android loader.
+
+## Loader Logging
+
+The Vulkan desktop loader has added logging functionality that can be enabled by
+using the `VK_LOADER_DEBUG` environment variable.
+The results will be output to the standard output, but will also be passed to
+any `VK_EXT_debug_utils` messengers present as well.
+The variable can be set to a comma-delimited list of debug level options which
+include:
+
+ * error Report any errors encountered by
+ the loader
+ * warn Report any warnings encountered by
+ the loader
+ * info Report info-level
+ messages generated by the loader
+ * debug Report debug-level messages generated by the
+ loader
+ * layer Report all layer-specific messages
+ generated by the loader
+ * driver Report all driver-specific messages
+ generated by the loader
+ * all Report all
+ messages generated by the loader (includes all of the above)
+
+If you're not sure where the issue comes from, at least set it to output all
+messages through the "info" level:
+
+```
+set VK_LOADER_DEBUG=error,warn,info
+```
+
+Then, you can search the list for any errors or warnings that might provide a
+hint at why you're seeing issues.
+
+For more info on enabling loader logging, refer to the
+[Enable Loader Debug Layer Output](LoaderApplicationInterface.md#enable-loader-debug-layer-output)
+and the
+[Table of Debug Environment Variables](LoaderInterfaceArchitecture.md#table-of-debug-environment-variables)
+below.
+
+## Debugging Possible Layer Issues
+
+### Enable Layer Logging
+
+If you suspect a layer issue, set the loader logging to specifically output
+layer messages in addition to warnings and errors:
+
+```
+set VK_LOADER_DEBUG=error,warn,layer
+```
+
+Most important layer messages should go out with error or warning levels set,
+but this will provide more layer-specific info as well such as:
+ * What layers are found
+ * Where they were found
+ * If they are implicit, what environment variables can be used to disable them
+ * If there is any incompatibility with a given layer, this could include:
+ * The layer library file (.so/.dll) wasn't found
+ * The layer library is the wrong bit-depth for the executing application
+ (i.e. 32-bit vs 64-bit)
+ * The layer itself doesn't support the application desired version of Vulkan
+ * If any environment variables are disabling any layers
+
+For example, the output of the loader looking for implicit layers may look like
+the following:
+
+```
+LAYER: Searching for layer manifest files
+LAYER: In following locations:
+LAYER: /home/${USER}/.config/vulkan/implicit_layer.d
+LAYER: /etc/xdg/vulkan/implicit_layer.d
+LAYER: /usr/local/etc/vulkan/implicit_layer.d
+LAYER: /etc/vulkan/implicit_layer.d
+LAYER: /home/${USER}/.local/share/vulkan/implicit_layer.d
+LAYER: /home/${USER}/.local/share/flatpak/exports/share/vulkan/implicit_layer.d
+LAYER: /var/lib/flatpak/exports/share/vulkan/implicit_layer.d
+LAYER: /usr/local/share/vulkan/implicit_layer.d
+LAYER: /usr/share/vulkan/implicit_layer.d
+LAYER: Found the following files:
+LAYER: /home/${USER}/.local/share/vulkan/implicit_layer.d/renderdoc_capture.json
+LAYER: /home/${USER}/.local/share/vulkan/implicit_layer.d/steamfossilize_i386.json
+LAYER: /home/${USER}/.local/share/vulkan/implicit_layer.d/steamfossilize_x86_64.json
+LAYER: /home/${USER}/.local/share/vulkan/implicit_layer.d/steamoverlay_i386.json
+LAYER: /home/${USER}/.local/share/vulkan/implicit_layer.d/steamoverlay_x86_64.json
+LAYER: /usr/share/vulkan/implicit_layer.d/nvidia_layers.json
+LAYER: /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
+```
+
+Then, the loading of layer libraries is reported similar to this:
+
+```
+LAYER | DEBUG: Loading layer library libVkLayer_khronos_validation.so
+LAYER | INFO: Insert instance layer VK_LAYER_KHRONOS_validation (libVkLayer_khronos_validation.so)
+LAYER | DEBUG: Loading layer library libVkLayer_MESA_device_select.so
+LAYER | INFO: Insert instance layer VK_LAYER_MESA_device_select (libVkLayer_MESA_device_select.so)
+```
+
+Finally, when the Vulkan instance is created, you can see the full instance
+call-chain from a functional standpoint with output like this:
+
+```
+LAYER: vkCreateInstance layer callstack setup to:
+LAYER: <Application>
+LAYER: ||
+LAYER: <Loader>
+LAYER: ||
+LAYER: VK_LAYER_MESA_device_select
+LAYER: Type: Implicit
+LAYER: Disable Env Var: NODEVICE_SELECT
+LAYER: Manifest: /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
+LAYER: Library: libVkLayer_MESA_device_select.so
+LAYER: ||
+LAYER: VK_LAYER_KHRONOS_validation
+LAYER: Type: Explicit
+LAYER: Manifest: /usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
+LAYER: Library: libVkLayer_khronos_validation.so
+LAYER: ||
+LAYER: <Drivers>
+```
+
+In this scenario, two layers were used (the same two that were loaded earlier):
+* `VK_LAYER_MESA_device_select`
+* `VK_LAYER_KHRONOS_validation`
+
+This information now shows us that the `VK_LAYER_MESA_device_select` is loaded
+first, followed by `VK_LAYER_KHRONOS_validation` which will then continue into
+any available drivers.
+It also shows that `VK_LAYER_MESA_device_select` is an implicit layer which
+implies that it wasn't directly enabled by the application.
+On the other hand, `VK_LAYER_KHRONOS_validation` is shown as an explicit layer
+which indicates that it was likely enabled by the application.
+
+### Disable Layers
+
+**NOTE:** This functionality is only available with Loaders built with version
+1.3.234 of the Vulkan headers and later.
+
+Sometimes, implicit layers can cause issues with an application.
+Because of this, the next step is to try to disable one or more of the listed
+implicit layers.
+You can use the filtering environment variables
+(`VK_LOADER_LAYERS_ENABLE` and `VK_LOADER_LAYERS_DISABLE`) to selectively enable
+or disable various layers.
+If you're not sure what to do, try disabling all implicit layers manually by
+setting `VK_LOADER_LAYERS_DISABLE` to '~implicit~'.
+
+```
+ set VK_LOADER_LAYERS_DISABLE=~implicit~
+```
+
+This will disable all implicit layers and the loader will report any disabled
+layers to the logging output when layer logging is enabled in the following way:
+
+```
+WARNING | LAYER: Implicit layer "VK_LAYER_MESA_device_select" forced disabled because name matches filter of env var 'VK_LOADER_LAYERS_DISABLE'.
+WARNING | LAYER: Implicit layer "VK_LAYER_AMD_switchable_graphics_64" forced disabled because name matches filter of env var 'VK_LOADER_LAYERS_DISABLE'.
+WARNING | LAYER: Implicit layer "VK_LAYER_Twitch_Overlay" forced disabled because name matches filter of env var 'VK_LOADER_LAYERS_DISABLE'.
+```
+
+### Selectively Re-enable Layers
+
+**NOTE:** This functionality is only available with Loaders built with version
+1.3.234 of the Vulkan headers and later.
+
+When trying to diagnose problems caused by layers, it is useful to first disable
+all layers and re-enable each layer individually.
+If the problem reappears, then it is immediately clear which layer is the source
+of the issue.
+
+For example, from the above given list of disabled layers, let’s selectively
+re-enable one:
+
+```
+set VK_LOADER_LAYERS_DISABLE=~implicit~
+set VK_LOADER_LAYERS_ENABLE=*AMD*
+```
+
+This would keep both the "VK_LAYER_MESA_device_select" and
+"VK_LAYER_Twitch_Overlay" layers disabled, while enabling the
+"VK_LAYER_AMD_switchable_graphics_64" layer.
+If everything continues to work, then the evidence seems to suggest the issue is
+likely not related to the AMD layer.
+This would lead to enabling one other layer and trying again:
+
+```
+set VK_LOADER_LAYERS_DISABLE=~implicit~
+set VK_LOADER_LAYERS_ENABLE=*AMD*,*twitch*
+```
+
+And so forth.
+
+For more info on how to use the filtering environment variables, refer to the
+[Layer Filtering](LoaderLayerInterface.md#layer-filtering) section of the
+[LoaderLayerInterface](LoaderLayerInterface.md) document.
+
+
+## Debugging Possible Driver Issues
+
+### Enable Driver Logging
+
+**NOTE:** This functionality is only available with Loaders built with version
+1.3.234 of the Vulkan headers and later.
+
+If you suspect a driver issue, set the loader logging to specifically output
+driver messages:
+
+```
+set VK_LOADER_DEBUG=error,warn,driver
+```
+
+Most important driver messages should go out with error or warning levels set,
+but this will provide more driver-specific info as well such as:
+ * What drivers are found
+ * Where they were found
+ * If there is any incompatibility with a given driver
+ * If any environment variables are disabling any of the drivers
+
+For example, the output of the loader looking for drivers on a Linux system may
+look like the following (NOTE: additional spaces have been removed from the
+output for easier reading):
+
+```
+DRIVER: Searching for driver manifest files
+DRIVER: In following folders:
+DRIVER: /home/$(USER)/.config/vulkan/icd.d
+DRIVER: /etc/xdg/vulkan/icd.d
+DRIVER: /etc/vulkan/icd.d
+DRIVER: /home/$(USER)/.local/share/vulkan/icd.d
+DRIVER: /home/$(USER)/.local/share/flatpak/exports/share/vulkan/icd.d
+DRIVER: /var/lib/flatpak/exports/share/vulkan/icd.d
+DRIVER: /usr/local/share/vulkan/icd.d
+DRIVER: /usr/share/vulkan/icd.d
+DRIVER: Found the following files:
+DRIVER: /usr/share/vulkan/icd.d/intel_icd.x86_64.json
+DRIVER: /usr/share/vulkan/icd.d/lvp_icd.x86_64.json
+DRIVER: /usr/share/vulkan/icd.d/radeon_icd.x86_64.json
+DRIVER: /usr/share/vulkan/icd.d/lvp_icd.i686.json
+DRIVER: /usr/share/vulkan/icd.d/radeon_icd.i686.json
+DRIVER: /usr/share/vulkan/icd.d/intel_icd.i686.json
+DRIVER: /usr/share/vulkan/icd.d/nvidia_icd.json
+DRIVER: Found ICD manifest file /usr/share/vulkan/icd.d/intel_icd.x86_64.json, version "1.0.0"
+DRIVER: Found ICD manifest file /usr/share/vulkan/icd.d/lvp_icd.x86_64.json, version "1.0.0"
+DRIVER: Found ICD manifest file /usr/share/vulkan/icd.d/radeon_icd.x86_64.json, version "1.0.0"
+DRIVER: Found ICD manifest file /usr/share/vulkan/icd.d/lvp_icd.i686.json, version "1.0.0"
+DRIVER: Requested driver /usr/lib/libvulkan_lvp.so was wrong bit-type. Ignoring this JSON
+DRIVER: Found ICD manifest file /usr/share/vulkan/icd.d/radeon_icd.i686.json, version "1.0.0"
+DRIVER: Requested driver /usr/lib/libvulkan_radeon.so was wrong bit-type. Ignoring this JSON
+DRIVER: Found ICD manifest file /usr/share/vulkan/icd.d/intel_icd.i686.json, version "1.0.0"
+DRIVER: Requested driver /usr/lib/libvulkan_intel.so was wrong bit-type. Ignoring this JSON
+DRIVER: Found ICD manifest file /usr/share/vulkan/icd.d/nvidia_icd.json, version "1.0.0"
+```
+
+Then when the application selects the device to use, you will see the Vulkan
+device call chain reported in the following way (NOTE: additional spaces have
+been removed from the output for easier reading):
+
+```
+DRIVER: vkCreateDevice layer callstack setup to:
+DRIVER: <Application>
+DRIVER: ||
+DRIVER: <Loader>
+DRIVER: ||
+DRIVER: <Device>
+DRIVER: Using "Intel(R) UHD Graphics 630 (CFL GT2)" with driver: "/usr/lib64/libvulkan_intel.so"
+```
+
+
+### Selectively Enable Specific Drivers
+
+**NOTE:** This functionality is only available with Loaders built with version
+1.3.234 of the Vulkan headers and later.
+
+You can now use the filtering environment variables
+(`VK_LOADER_DRIVERS_SELECT` and `VK_LOADER_DRIVERS_DISABLE`) to control what
+drivers the loader will attempt to load.
+For drivers, the string globs passed into the above environment variables will
+be compared against the driver JSON file name since there is no driver name
+known to the loader until much later in the Vulkan initialization process.
+
+For example, to disable all drivers except Nvidia you could do the following:
+
+```
+set VK_LOADER_DRIVERS_DISABLE=*
+set VK_LOADER_DRIVERS_SELECT=*nvidia*
+```
+
+The loader outputs messages like the following when the environment variables
+are used:
+
+```
+WARNING | DRIVER: Driver "intel_icd.x86_64.json" ignored because not selected by env var 'VK_LOADER_DRIVERS_SELECT'
+WARNING | DRIVER: Driver "radeon_icd.x86_64.json" ignored because it was disabled by env var 'VK_LOADER_DRIVERS_DISABLE'
+```
+
+For more info on how to use the filtering environment variables, refer to the
+[Driver Filtering](LoaderDriverInterface.md#driver-filtering) section of the
+[LoaderDriverInterface](LoaderDriverInterface.md) document.
+
diff --git a/docs/LoaderDriverInterface.md b/docs/LoaderDriverInterface.md
index 40430fb..821f1d5 100644
--- a/docs/LoaderDriverInterface.md
+++ b/docs/LoaderDriverInterface.md
@@ -7,7 +7,7 @@
# Driver interface to the Vulkan Loader
[![Creative Commons][3]][4]
-<!-- Copyright © 2015-2021 LunarG, Inc. -->
+<!-- Copyright © 2015-2022 LunarG, Inc. -->
[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
[4]: https://creativecommons.org/licenses/by-nd/4.0/
@@ -19,7 +19,10 @@
- [Driver Discovery](#driver-discovery)
- [Overriding the Default Driver Discovery](#overriding-the-default-driver-discovery)
- [Additional Driver Discovery](#additional-driver-discovery)
- - [Exception for Elevated Privileges](#exception-for-elevated-privileges)
+ - [Driver Filtering](#driver-filtering)
+ - [Driver Select Filtering](#driver-select-filtering)
+ - [Driver Disable Filtering](#driver-disable-filtering)
+ - [Exception for Elevated Privileges](#exception-for-elevated-privileges)
- [Examples](#examples)
- [On Windows](#on-windows)
- [On Linux](#on-linux)
@@ -126,7 +129,8 @@
Driver in addition to the standard drivers (without replacing the standard
search paths.
The `VK_ADD_DRIVER_FILES` environment variable can be used to add a list of
-Driver Manifest files, containing the full path to the driver JSON Manifest file.
+Driver Manifest files, containing the full path to the driver JSON Manifest
+file.
This list is colon-separated on Linux and macOS, and semicolon-separated on
Windows.
It will be added prior to the standard driver search files.
@@ -134,11 +138,65 @@
`VK_ADD_DRIVER_FILES` will not be used by the loader and any values will be
ignored.
-#### Exception for Elevated Privileges
+### Driver Filtering
-For security reasons, `VK_ICD_FILENAMES`, `VK_DRIVER_FILES` and
-`VK_ADD_DRIVER_FILES` are all ignored if running the Vulkan application with
-elevated privileges.
+**NOTE:** This functionality is only available with Loaders built with version
+1.3.234 of the Vulkan headers and later.
+
+The loader supports filter environment variables which can forcibly select and
+disable known drivers.
+Known driver manifests are those files that are already found by the loader
+taking into account default search paths and other environment variables (like
+`VK_ICD_FILENAMES` or `VK_ADD_DRIVER_FILES`).
+
+The filter variables will be compared against the driver's manifest filename.
+
+The filters must also follow the behaviors define in the
+[Filter Environment Variable Behaviors](LoaderInterfaceArchitecture.md#filter-environment-variable-behaviors)
+section of the [LoaderLayerInterface](LoaderLayerInterface.md) document.
+
+#### Driver Select Filtering
+
+The driver select environment variable `VK_LOADER_DRIVERS_SELECT` is a
+comma-delimited list of globs to search for in known drivers.
+
+If a driver is not selected when using the `VK_LOADER_DRIVERS_SELECT` filter,
+and loader logging is set to emit either warnings or driver messages, then a
+message will show for each driver that has been ignored.
+This message will look like the following:
+
+```
+WARNING | DRIVER: Driver "intel_icd.x86_64.json" ignored because not selected by env var 'VK_LOADER_DRIVERS_SELECT'
+```
+
+If no drivers are found with a manifest filename that matches any of the
+provided globs, then no driver is enabled and may result in failures for
+any Vulkan application that is run.
+
+#### Driver Disable Filtering
+
+The driver disable environment variable `VK_LOADER_DRIVERS_DISABLE` is a
+comma-delimited list of globs to search for in known drivers.
+
+When a driver is disabled using the `VK_LOADER_DRIVERS_DISABLE` filter, and
+loader logging is set to emit either warnings or driver messages, then a message
+will show for each driver that has been forcibly disabled.
+This message will look like the following:
+
+```
+WARNING | DRIVER: Driver "radeon_icd.x86_64.json" ignored because it was disabled by env var 'VK_LOADER_DRIVERS_DISABLE'
+```
+
+If no drivers are found with a manifest filename that matches any of the
+provided globs, then no driver is disabled.
+
+### Exception for Elevated Privileges
+
+For security reasons, `VK_ICD_FILENAMES`, `VK_DRIVER_FILES`, and
+`VK_ADD_DRIVER_FILES` are all ignored if running the Vulkan application
+with elevated privileges.
+This is because they may insert new libraries into the executable process that
+are not normally found by the loader.
Because of this, these environment variables can only be used for applications
that do not use elevated privileges.
@@ -292,9 +350,10 @@
This is because the value of 1 for vendor_b_vk.json disables the driver.
Additionally, the Vulkan loader will scan the system for well-known Windows
-AppX/MSIX packages. If a package is found, the loader will scan the root directory
-of this installed package for JSON manifest files. At this time, the only package
-that is known is Microsoft's
+AppX/MSIX packages.
+If a package is found, the loader will scan the root directory of this installed
+package for JSON manifest files. At this time, the only package that is known is
+Microsoft's
[OpenCL™ and OpenGL® Compatibility Pack](https://apps.microsoft.com/store/detail/9NQPSL29BFFF?hl=en-us&gl=US).
The Vulkan loader will open each enabled manifest file found to obtain the name
@@ -510,7 +569,8 @@
## Driver Manifest File Format
-The following section discusses the details of the Driver Manifest JSON file format.
+The following section discusses the details of the Driver Manifest JSON file
+format.
The JSON file itself does not have any requirements for naming.
The only requirement is that the extension suffix of the file is ".json".
@@ -569,18 +629,18 @@
<td>"api_version" </td>
<td>The major.minor.patch version number of the maximum Vulkan API supported
by the driver.
- However, just because the driver supports the specific Vulkan API version,
- it does not guarantee that the hardware on a user's system can support
- that version.
+ However, just because the driver supports the specific Vulkan API
+ version, it does not guarantee that the hardware on a user's system can
+ support that version.
Information on what the underlying physical device can support must be
- queried by the user using the <i>vkGetPhysicalDeviceProperties</i> API call.
- <br/>
+ queried by the user using the <i>vkGetPhysicalDeviceProperties</i> API
+ call.<br/>
For example: 1.0.33.</td>
</tr>
<tr>
<td>"is_portability_driver" </td>
- <td>Defines whether the driver contains any VkPhysicalDevices which implement
- the VK_KHR_portability_subset extension.<br/>
+ <td>Defines whether the driver contains any VkPhysicalDevices which
+ implement the VK_KHR_portability_subset extension.<br/>
</td>
</tr>
</table>
@@ -762,13 +822,13 @@
the driver.
Implementations of the function should have the following behavior:
-* If `pName` is the name of a Vulkan API entrypoint that takes a `VkPhysicalDevice`
- as its primary dispatch handle, and the driver supports the entrypoint, then
- the driver **must** return the valid function pointer to the driver's
- implementation of that entrypoint.
-* If `pName` is the name of a Vulkan API entrypoint that takes something other than
- a `VkPhysicalDevice` as its primary dispatch handle, then the driver **must**
- return `NULL`.
+* If `pName` is the name of a Vulkan API entrypoint that takes a
+ `VkPhysicalDevice` as its primary dispatch handle, and the driver supports the
+ entrypoint, then the driver **must** return the valid function pointer to the
+ driver's implementation of that entrypoint.
+* If `pName` is the name of a Vulkan API entrypoint that takes something other
+ than a `VkPhysicalDevice` as its primary dispatch handle, then the driver
+ **must** return `NULL`.
* If the driver is unaware of any entrypoint with the name `pName`, it **must**
return `NULL`.
@@ -886,6 +946,14 @@
Other platforms may be included in the future, but they will require separate
platform-specific interfaces.
+A requirement of `vk_icdEnumerateAdapterPhysicalDevices` is that it *must*
+return the same `VkPhysicalDevice` handle values for the same physical
+devices that are returned by `vkEnumeratePhysicalDevices`.
+This is because the loader calls both functions on the driver then
+de-duplicates the physical devices using the `VkPhysicalDevice` handles.
+Since not all physical devices in a driver will have a LUID, such as for
+software implementations, this step is necessary to allow drivers to
+enumerate all available physical devices.
## Driver Dispatchable Object Creation
@@ -1257,12 +1325,13 @@
The loader implements the `VK_KHR_portability_enumeration` instance extension,
which filters out any drivers that report support for the portability subset
device extension. Unless the application explicitly requests enumeration of
-portability devices by setting the VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR
-bit in the VkInstanceCreateInfo::flags, the loader does not load any drivers
-that declare themselves to be portability drivers.
+portability devices by setting the
+`VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` bit in the
+VkInstanceCreateInfo::flags, the loader does not load any drivers that declare
+themselves to be portability drivers.
-Drivers declare whether they are portability drivers or not in the Driver Manifest
-Json file, with the `is_portability_driver` boolean field.
+Drivers declare whether they are portability drivers or not in the Driver
+Manifest Json file, with the `is_portability_driver` boolean field.
[More information here](#driver-manifest-file-version-101)
The initial support for this extension only reported errors when an application
@@ -1404,7 +1473,8 @@
</tr>
<tr>
<td><small><b>LDP_DRIVER_6</b></small></td>
- <td>Removed - See <a href="#removed-driver-policies">Removed Driver Policies</a>
+ <td>Removed - See
+ <a href="#removed-driver-policies">Removed Driver Policies</a>
</td>
<td>-</td>
<td>-</td>
@@ -1515,7 +1585,8 @@
#### Removed Driver Policies
-These policies were in the loader source at some point but later removed. They are documented here for reference.
+These policies were in the loader source at some point but later removed.
+They are documented here for reference.
<table>
<tr>
diff --git a/docs/LoaderInterfaceArchitecture.md b/docs/LoaderInterfaceArchitecture.md
index 66d38e6..8c203b8 100644
--- a/docs/LoaderInterfaceArchitecture.md
+++ b/docs/LoaderInterfaceArchitecture.md
@@ -7,7 +7,7 @@
# Architecture of the Vulkan Loader Interfaces
[![Creative Commons][3]][4]
-<!-- Copyright © 2015-2021 LunarG, Inc. -->
+<!-- Copyright © 2015-2022 LunarG, Inc. -->
[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
[4]: https://creativecommons.org/licenses/by-nd/4.0/
@@ -38,7 +38,14 @@
- [Application Interface to the Loader](#application-interface-to-the-loader)
- [Layer Interface with the Loader](#layer-interface-with-the-loader)
- [Driver Interface With the Loader](#driver-interface-with-the-loader)
+- [Debugging Issues](#debugging-issues)
- [Loader Policies](#loader-policies)
+- [Filter Environment Variable Behaviors](#filter-environment-variable-behaviors)
+ - [Comparison Strings](#comparison-strings)
+ - [Comma-Delimited Lists](#comma-delimited-lists)
+ - [Globs](#globs)
+ - [Case-Insensitive](#case-insensitive)
+ - [Environment Variable Priority](#environment-variable-priority)
- [Table of Debug Environment Variables](#table-of-debug-environment-variables)
- [Glossary of Terms](#glossary-of-terms)
@@ -458,6 +465,17 @@
<br/>
+## Debugging Issues
+
+
+If your application is crashing or behaving weirdly, the loader provides
+several mechanisms for you to debug the issues.
+These are detailed in the [LoaderDebugging.md](LoaderDebugging.md) document
+found in the same directory as this file.
+<br/>
+<br/>
+
+
## Loader Policies
Loader policies with regards to the loader interaction with drivers and layers
@@ -478,6 +496,62 @@
<br/>
<br/>
+## Filter Environment Variable Behaviors
+
+The filter environment variables provided in certain areas have some common
+restrictions and behaviors that should be listed.
+
+### Comparison Strings
+
+The filter variables will be compared against the appropriate strings for either
+drivers or layers.
+The appropriate string for layers is the layer name provided in the layer's
+manifest file.
+Since drivers don’t have a name like layers, this substring is used to compare
+against the driver manifest's filename.
+
+### Comma-Delimited Lists
+
+All of the filter environment variables accept comma-delimited input.
+Therefore, you can chain multiple strings together and it will use the strings
+to individually enable or disable the appropriate item in the current list of
+available items.
+
+### Globs
+
+To provide enough flexibility to limit name searches to only those wanted by the
+developer, the loader uses a limited glob format for strings.
+Acceptable globs are:
+ - Prefixes: `"string*"`
+ - Suffixes: `"*string"`
+ - Substrings: `"*string*"`
+ - Whole strings: `"string"`
+ - In the case of whole strings, the string will be compared against each
+ layer or driver file name in its entirety.
+ - Because of this, it will only match the specific target such as:
+ `VK_LAYER_KHRONOS_validation` will match the layer name
+ `VK_LAYER_KHRONOS_validation`, but **not** a layer named
+ `VK_LAYER_KHRONOS_validation2` (not that there is such a layer).
+
+This is especially useful because it is difficult sometimes to determine the
+full name of a driver manifest file or even some commonly used layers
+such as `VK_LAYER_KHRONOS_validation`.
+
+### Case-Insensitive
+
+All of the filter environment variables assume the strings inside of the glob
+are not case-sensitive.
+Therefore, “Bob”, “bob”, and “BOB” all amount to the same thing.
+
+### Environment Variable Priority
+
+The values from the *disable* environment variable will be considered
+**before** the *enable* or *select* environment variable.
+Because of this, it is possible to disable a layer/driver using the *disable*
+environment variable, only to have it be re-enabled by the *enable*/*select*
+environment variable.
+This is useful if you disable all layers/drivers with the intent of only
+enabling a smaller subset of specific layers/drivers for issue triaging.
## Table of Debug Environment Variables
@@ -582,33 +656,10 @@
</tr>
<tr>
<td><small>
- <i>VK_INSTANCE_LAYERS</i>
- </small></td>
- <td><small>
- Force the loader to add the given layers to the list of Enabled layers
- normally passed into <b>vkCreateInstance</b>.
- These layers are added first, and the loader will remove any duplicate
- layers that appear in both this list as well as that passed into
- <i>ppEnabledLayerNames</i>.
- </small></td>
- <td><small>
- None
- </small></td>
- <td><small>
- export<br/>
- VK_INSTANCE_LAYERS=<br/>
- <layer_a>:<layer_b><br/><br/>
- set<br/>
- VK_INSTANCE_LAYERS=<br/>
- <layer_a>;<layer_b>
- </small></td>
- </tr>
- <tr>
- <td><small>
<i>VK_LAYER_PATH</i></small></td>
<td><small>
Override the loader's standard Layer library search folders and use the
- provided delimited folders to search for explicit layer manifest files.
+ provided delimited file and/or folders to locate explicit layer manifest files.
</small></td>
<td><small>
<a href="#elevated-privilege-caveats">
@@ -626,6 +677,34 @@
</tr>
<tr>
<td><small>
+ <i>VK_LOADER_DEBUG</i>
+ </small></td>
+ <td><small>
+ Enable loader debug messages using a comma-delimited list of level
+ options. These options are:<br/>
+ * error (only errors)<br/>
+ * warn (only warnings)<br/>
+ * info (only info)<br/>
+ * debug (only debug)<br/>
+ * layer (layer-specific output)<br/>
+ * driver (driver-specific output)<br/>
+ * all (report out all messages)<br/><br/>
+ To enable multiple options (outside of "all") like info, warning and
+ error messages, set the value to "error,warn,info".
+ </small></td>
+ <td><small>
+ None
+ </small></td>
+ <td><small>
+ export<br/>
+ VK_LOADER_DEBUG=all<br/>
+ <br/>
+ set<br/>
+ VK_LOADER_DEBUG=warn
+ </small></td>
+ </tr>
+ <tr>
+ <td><small>
<i>VK_LOADER_DEVICE_SELECT</i>
</small></td>
<td><small>
@@ -679,30 +758,131 @@
</tr>
<tr>
<td><small>
- <i>VK_LOADER_DEBUG</i>
+ <i>VK_LOADER_DRIVERS_SELECT</i>
</small></td>
<td><small>
- Enable loader debug messages using a comma-delimited list of level
- options. These options are:<br/>
- * error (only errors)<br/>
- * warn (only warnings)<br/>
- * info (only info)<br/>
- * debug (only debug)<br/>
- * layer (layer-specific output)<br/>
- * driver (driver-specific output)<br/>
- * all (report out all messages)<br/><br/>
- To enable multiple options (outside of "all") like info, warning and
- error messages, set the value to "error,warn,info".
+ A comma-delimited list of globs to search for in known drivers and
+ used to select only the drivers whose manifest file names match one or
+ more of the provided globs.<br/>
+ Since drivers don’t have a name like layers, this glob is used to
+ compare against the manifest filename.
+ Known driver manifests being those files that are already found by the
+ loader taking into account default search paths and other environment
+ variables (like <i>VK_ICD_FILENAMES</i> or <i>VK_ADD_DRIVER_FILES</i>).
</small></td>
<td><small>
- None
+ This functionality is only available with Loaders built with version
+ 1.3.234 of the Vulkan headers and later.<br/>
+ If no drivers are found with a manifest filename that matches any of the
+ provided globs, then no driver is enabled and it <b>may</b> result
+ in Vulkan applications failing to run properly.
</small></td>
<td><small>
export<br/>
- VK_LOADER_DEBUG=all<br/>
+ VK_LOADER_DRIVERS_SELECT=nvidia<br/>
<br/>
set<br/>
- VK_LOADER_DEBUG=warn
+ VK_LOADER_DRIVERS_SELECT=nvidia<br/><br/>
+ The above would select only the Nvidia driver if it was present on the
+ system and already visible to the loader.
+ </small></td>
+ </tr>
+ <tr>
+ <td><small>
+ <i>VK_LOADER_DRIVERS_DISABLE</i>
+ </small></td>
+ <td><small>
+ A comma-delimited list of globs to search for in known drivers and
+ used to disable only the drivers whose manifest file names match one or
+ more of the provided globs.<br/>
+ Since drivers don’t have a name like layers, this glob is used to
+ compare against the manifest filename.
+ Known driver manifests being those files that are already found by the
+ loader taking into account default search paths and other environment
+ variables (like <i>VK_ICD_FILENAMES</i> or <i>VK_ADD_DRIVER_FILES</i>).
+ </small></td>
+ <td><small>
+ This functionality is only available with Loaders built with version
+ 1.3.234 of the Vulkan headers and later.<br/>
+ If all available drivers are disabled using this environment variable,
+ then no drivers will be found by the loader and <b>will</b> result
+ in Vulkan applications failing to run properly.<br/>
+ This is also checked before other driver environment variables (such as
+ <i>VK_LOADER_DRIVERS_SELECT</i>) so that a user may easily disable all
+ drivers and then selectively re-enable individual drivers using the
+ enable environment variable.
+ </small></td>
+ <td><small>
+ export<br/>
+ VK_LOADER_DRIVERS_DISABLE=*amd*,*intel*<br/>
+ <br/>
+ set<br/>
+ VK_LOADER_DRIVERS_DISABLE=*amd*,*intel*<br/><br/>
+ The above would disable both Intel and AMD drivers if both were present
+ on the system and already visible to the loader.
+ </small></td>
+ </tr>
+ <tr>
+ <td><small>
+ <i>VK_LOADER_LAYERS_ENABLE</i>
+ </small></td>
+ <td><small>
+ A comma-delimited list of globs to search for in known layers and
+ used to select only the layers whose layer name matches one or more of
+ the provided globs.<br/>
+ Known layers are those which are found by the loader taking into account
+ default search paths and other environment variables
+ (like <i>VK_LAYER_PATH</i>).
+ <br/>
+ This has replaced the older deprecated environment variable
+ <i>VK_INSTANCE_LAYERS</i>
+ </small></td>
+ <td><small>
+ This functionality is only available with Loaders built with version
+ 1.3.234 of the Vulkan headers and later.
+ </small></td>
+ <td><small>
+ export<br/>
+ VK_LOADER_LAYERS_ENABLE=*validation,*recon*<br/>
+ <br/>
+ set<br/>
+ VK_LOADER_LAYERS_ENABLE=*validation,*recon*<br/><br/>
+ The above would enable the Khronos validation layer and the
+ GfxReconstruct layer, if both were present on the system and already
+ visible to the loader.
+ </small></td>
+ </tr>
+ <tr>
+ <td><small>
+ <i>VK_LOADER_LAYERS_DISABLE</i>
+ </small></td>
+ <td><small>
+ A comma-delimited list of globs to search for in known layers and
+ used to disable only the layers whose layer name matches one or more of
+ the provided globs.<br/>
+ Known layers are those which are found by the loader taking into account
+ default search paths and other environment variables
+ (like <i>VK_LAYER_PATH</i>).
+ </small></td>
+ <td><small>
+ This functionality is only available with Loaders built with version
+ 1.3.234 of the Vulkan headers and later.<br/>
+ Disabling a layer that an application intentionally enables as an
+ explicit layer <b>may</b> cause the application to not function
+ properly.<br/>
+ This is also checked before other layer environment variables (such as
+ <i>VK_LOADER_LAYERS_ENABLE</i>) so that a user may easily disable all
+ layers and then selectively re-enable individual layers using the
+ enable environment variable.
+ </small></td>
+ <td><small>
+ export<br/>
+ VK_LOADER_LAYERS_DISABLE=*MESA*,~implicit~<br/>
+ <br/>
+ set<br/>
+ VK_LOADER_LAYERS_DISABLE=*MESA*,~implicit~<br/><br/>
+ The above would disable any Mesa layer and all other implicit layers
+ that would normally be enabled on the system.
</small></td>
</tr>
</table>
@@ -750,6 +930,34 @@
<folder_a>\nvidia.json;<folder_b>\mesa.json
</small></td>
</tr>
+ <tr>
+ <td><small>
+ <i>VK_INSTANCE_LAYERS</i>
+ </small></td>
+ <td><small>
+ Force the loader to add the given layers to the list of Enabled layers
+ normally passed into <b>vkCreateInstance</b>.
+ These layers are added first, and the loader will remove any duplicate
+ layers that appear in both this list as well as that passed into
+ <i>ppEnabledLayerNames</i>.
+ </small></td>
+ <td><small>
+ This has been deprecated by <i>VK_LOADER_LAYERS_ENABLE</i>.
+ It also overrides any layers disabled with
+ <i>VK_LOADER_LAYERS_DISABLE</i>.
+ </small></td>
+ <td><small>
+ None
+ </small></td>
+ <td><small>
+ export<br/>
+ VK_INSTANCE_LAYERS=<br/>
+ <layer_a>;<layer_b><br/><br/>
+ set<br/>
+ VK_INSTANCE_LAYERS=<br/>
+ <layer_a>;<layer_b>
+ </small></td>
+ </tr>
</table>
<br/>
<br/>
@@ -814,8 +1022,8 @@
<td>Discovery</td>
<td>The process of the loader searching for driver and layer files to set up
the internal list of Vulkan objects available.<br/>
- On <i>Windows/Linux/macOS</i>, the discovery process typically focuses on
- searching for Manifest files.<br/>
+ On <i>Windows/Linux/macOS</i>, the discovery process typically focuses
+ on searching for Manifest files.<br/>
On <i>Android</i>, the process focuses on searching for library files.
</td>
</tr>
diff --git a/docs/LoaderLayerInterface.md b/docs/LoaderLayerInterface.md
index bd6266a..1d0a3be 100644
--- a/docs/LoaderLayerInterface.md
+++ b/docs/LoaderLayerInterface.md
@@ -7,7 +7,7 @@
# Layer Interface to the Loader
[![Creative Commons][3]][4]
-<!-- Copyright © 2015-2021 LunarG, Inc. -->
+<!-- Copyright © 2015-2022 LunarG, Inc. -->
[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
[4]: https://creativecommons.org/licenses/by-nd/4.0/
@@ -25,6 +25,11 @@
- [Fuchsia Layer Discovery](#fuchsia-layer-discovery)
- [macOS Layer Discovery](#macos-layer-discovery)
- [Example macOS Implicit Layer Search Path](#example-macos-implicit-layer-search-path)
+ - [Layer Filtering](#layer-filtering)
+ - [Layer Enable Filtering](#layer-enable-filtering)
+ - [Layer Disable Filtering](#layer-disable-filtering)
+ - [Layer Special Case Disable](#layer-special-case-disable)
+ - [Layer Disable Warning](#layer-disable-warning)
- [Exception for Elevated Privileges](#exception-for-elevated-privileges)
- [Layer Version Negotiation](#layer-version-negotiation)
- [Layer Call Chains and Distributed Dispatch](#layer-call-chains-and-distributed-dispatch)
@@ -335,6 +340,9 @@
The paths provided by `VK_ADD_LAYER_PATH` are added before the standard list
of search folders and will therefore be searched first.
+If `VK_LAYER_PATH` is present, then `VK_ADD_LAYER_PATH` will not be used by the
+loader and any values will be ignored.
+
For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
if running with elevated privileges.
See [Exception for Elevated Privileges](#exception-for-elevated-privileges)
@@ -412,14 +420,106 @@
/usr/share/vulkan/implicit_layer.d
```
+### Layer Filtering
+
+**NOTE:** This functionality is only available with Loaders built with version
+1.3.234 of the Vulkan headers and later.
+
+The loader supports filter environment variables which can forcibly enable and
+disable known layers.
+Known layers are those that are already found by the loader taking into account
+default search paths and other environment variables
+(like `VK_LAYER_PATH` or `VK_ADD_LAYER_PATH`).
+
+The filter variables will be compared against the layer name provided in the
+layer's manifest file.
+
+The filters must also follow the behaviors define in the
+[Filter Environment Variable Behaviors](LoaderInterfaceArchitecture.md#filter-environment-variable-behaviors)
+section of the [LoaderLayerInterface](LoaderLayerInterface.md) document.
+
+#### Layer Enable Filtering
+
+The layer enable environment variable `VK_LOADER_LAYERS_ENABLE` is a
+comma-delimited list of globs to search for in known layers.
+The layer names are compared against the globs listed in the environment
+variable, and if they match, they will automatically be added to the enabled
+layer list in the loader for each application.
+These layers are enabled after implicit layers but before other explicit layers.
+
+When a layer is enabled using the `VK_LOADER_LAYERS_ENABLE` filter, and
+loader logging is set to emit either warnings or layer messages, then a message
+will show for each layer that has been forced on.
+This message will look like the following:
+
+```
+WARNING | LAYER: Layer "VK_LAYER_LUNARG_wrap_objects" force enabled due to env var 'VK_LOADER_LAYERS_ENABLE'
+```
+
+#### Layer Disable Filtering
+
+The layer disable environment variable `VK_LOADER_LAYERS_DISABLE` is a
+comma-delimited list of globs to search for in known layers.
+The layer names are compared against the globs listed in the environment
+variable, and if they match, they will automatically be disabled (whether or not
+the layer is Implicit or Explicit).
+This means that they will not be added to the enabled layer list in the loader
+for each application.
+This could mean that layers requested by an application are also not enabled
+such as `VK_KHRONOS_LAYER_synchronization2` which could cause some applications
+to misbehave.
+
+When a layer is disabled using the `VK_LOADER_LAYERS_DISABLE` filter, and
+loader logging is set to emit either warnings or layer messages, then a message
+will show for each layer that has been forcibly disabled.
+This message will look like the following:
+
+```
+WARNING | LAYER: Layer "VK_LAYER_LUNARG_wrap_objects" disabled because name matches filter of env var 'VK_LOADER_LAYERS_DISABLE'
+```
+
+#### Layer Special Case Disable
+
+Because there are different types of layers, there are 3 additional special
+disable options available when using the `VK_LOADER_LAYERS_DISABLE` environment
+variable.
+
+These are:
+
+ * `~all~`
+ * `~implicit~`
+ * `~explicit~`
+
+`~all~` will effectively disable every layer.
+This enables a developer to disable all layers on the system.
+`~implicit~` will effectively disable every implicit layer (leaving explicit
+layers still present in the application call chain).
+`~explicit~` will effectively disable every explicit layer (leaving implicit
+layers still present in the application call chain).
+
+#### Layer Disable Warning
+
+Disabling layers, whether just through normal usage of
+`VK_LOADER_LAYERS_DISABLE` or by evoking one of the special disable options like
+`~all~` or `~explicit~` could cause application breakage if the application is
+relying on features provided by one or more explicit layers.
+
+##### VK_INSTANCE_LAYERS
+
+The original `VK_INSTANCE_LAYERS` can be viewed as a special case of the new
+`VK_LOADER_LAYERS_ENABLE`.
+Because of this, any layers enabled via `VK_INSTANCE_LAYERS` will be treated the
+same as layers enabled with `VK_LOADER_LAYERS_ENABLE` and will therefore
+override any disables supplied in `VK_LOADER_LAYERS_DISABLE`.
+
### Exception for Elevated Privileges
-There is an exception to when either `VK_LAYER_PATH` or `VK_ADD_LAYER_PATH` are
-available for use.
-For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
-if running the Vulkan application with elevated privileges.
-Because of this, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` can only be used
-for applications that do not use elevated privileges.
+For security reasons, `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored if
+running the Vulkan application with elevated privileges.
+This is because they may insert new libraries into the executable process that
+are not normally found by the loader.
+Because of this, these environment variables can only be used for applications
+that do not use elevated privileges.
For more information see
[Elevated Privilege Caveats](LoaderInterfaceArchitecture.md#elevated-privilege-caveats)
@@ -630,7 +730,8 @@
`vk_layerGetPhysicalDeviceProcAddr`.
If a layer intends to support functions that take VkPhysicalDevice as the
-dispatchable parameter, then layer should support `vk_layerGetPhysicalDeviceProcAddr`.
+dispatchable parameter, then layer should support
+`vk_layerGetPhysicalDeviceProcAddr`.
This is because if these functions aren't known to the loader, such as those
from unreleased extensions or because the loader is an older build thus doesn't
know about them _yet_, the loader won't be able to distinguish whether this is
@@ -658,8 +759,8 @@
driver.
4. Call down using `GetInstanceProcAddr`
- If it returns non-NULL, treat it as an unknown logical device command.
-This means setting up a generic trampoline function that takes in a `VkDevice` as
-the first parameter and adjusting the dispatch table to call the
+This means setting up a generic trampoline function that takes in a `VkDevice`
+as the first parameter and adjusting the dispatch table to call the
driver/layer's function after getting the dispatch table from the `VkDevice`.
Then, return the pointer to corresponding trampoline function.
5. Return NULL
@@ -714,7 +815,8 @@
corresponding Vulkan function in the next entity.
* The common behavior for a layer is to intercept a call, perform some
behavior, then pass it down to the next entity.
- * If a layer doesn't pass the information down, undefined behavior may occur.
+ * If a layer doesn't pass the information down, undefined behavior may
+ occur.
* This is because the function will not be received by layers further
down the chain, or any drivers.
* One function that **must never call down the chain** is:
@@ -1083,8 +1185,8 @@
Vulkan includes a small number of functions which are called without any
dispatchable object.
-<b>Most layers do not intercept these functions</b>, as layers are enabled when an
-instance is created.
+<b>Most layers do not intercept these functions</b>, as layers are enabled when
+an instance is created.
However, under certain conditions it is possible for a layer to intercept
these functions.
@@ -1411,7 +1513,8 @@
* The `app_keys` member of the override meta layer will make a meta layer apply
to only applications found in this list.
-If there are any items in the app keys list, the meta layer isn't enabled for any application except those found in the list.
+If there are any items in the app keys list, the meta layer isn't enabled for
+any application except those found in the list.
* The `override_paths` member of the override meta layer, if present, will
replace the search paths the loader uses to find component layers.
@@ -1539,7 +1642,7 @@
supports.
It does not require the application to make use of that API version.
It simply is an indication that the layer can support Vulkan API
- instance and device functions up to and including that API version. </br>
+ instance and device functions up to and including that API version.</br>
For example: 1.0.33.
</td>
<td>None</td>
@@ -1837,8 +1940,8 @@
- NOTE: This is an optional field and, as the two previous fields, only
needed if the layer requires changing the name of the function for some reason.
-The layer manifest file does not need to to be updated if the names of any listed
-functions has not changed.
+The layer manifest file does not need to to be updated if the names of any
+listed functions has not changed.
#### Layer Manifest File Version 1.0.1
@@ -1878,7 +1981,7 @@
### Layer Interface Version 2
Introduced the concept of
-[loader and layer interface](#layer-version-negotiation) using the new
+[loader and layer interface](#layer-version-negotiation) using the
`vkNegotiateLoaderLayerInterfaceVersion` function.
Additionally, it introduced the concept of
[Layer Unknown Physical Device Extensions](#layer-unknown-physical-device-extensions)
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index bf43087..eb6032c 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -17,9 +17,6 @@
# limitations under the License.
# ~~~
-# Get version of the API the generated code used and put it into a cmake variable LOADER_GENERATED_HEADER_VERSION
-include(generated/loader_generated_header_version.cmake)
-
add_library(loader_specific_options INTERFACE)
target_link_libraries(loader_specific_options INTERFACE loader_common_options Vulkan::Headers)
target_include_directories(loader_specific_options INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/generated ${CMAKE_CURRENT_BINARY_DIR})
@@ -106,7 +103,7 @@
cJSON.c
debug_utils.c
extension_manual.c
- get_environment.c
+ loader_environment.c
gpa_helper.c
loader.c
log.c
@@ -157,13 +154,30 @@
endif()
add_executable(asm_offset asm_offset.c)
- target_link_libraries(asm_offset loader_specific_options)
- add_custom_command(OUTPUT gen_defines.asm DEPENDS asm_offset COMMAND asm_offset MASM)
+ target_link_libraries(asm_offset PRIVATE loader_specific_options)
+ # If not cross compiling, run asm_offset to generage gen_defines.asm
+ if (NOT CMAKE_CROSSCOMPILING)
+ add_custom_command(OUTPUT gen_defines.asm DEPENDS asm_offset COMMAND asm_offset MASM)
+ else()
+ # Forces compiler to write the intermediate asm file, needed so that we can get sizeof/offset of info out of it.
+ target_compile_options(asm_offset PRIVATE "/Fa$<TARGET_FILE_DIR:asm_offset>/asm_offset.asm" /FA)
+ # Force off optimization so that the output assembly includes all the necessary info - optimizer would get rid of it otherwise.
+ target_compile_options(asm_offset PRIVATE /Od)
+
+ find_package(PythonInterp REQUIRED)
+ # Run parse_asm_values.py on asm_offset's assembly file to generate the gen_defines.asm, which the asm code depends on
+ add_custom_command(TARGET asm_offset POST_BUILD
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/parse_asm_values.py "${CMAKE_CURRENT_BINARY_DIR}/gen_defines.asm"
+ "$<TARGET_FILE_DIR:asm_offset>/asm_offset.asm" "MASM" "${CMAKE_CXX_COMPILER_ID}" "${CMAKE_SYSTEM_PROCESSOR}"
+ BYPRODUCTS gen_defines.asm
+ )
+ endif()
add_custom_target(loader_asm_gen_files DEPENDS gen_defines.asm)
set_target_properties(loader_asm_gen_files PROPERTIES FOLDER ${LOADER_HELPER_FOLDER})
+
add_library(loader-unknown-chain OBJECT unknown_ext_chain_masm.asm)
target_link_libraries(loader-unknown-chain Vulkan::Headers)
- target_include_directories(loader-unknown-chain PUBLIC $<TARGET_PROPERTY:loader_asm_gen_files,BINARY_DIR>)
+ target_include_directories(loader-unknown-chain PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(loader-unknown-chain loader_asm_gen_files)
else()
message(WARNING "Could not find working MASM assembler\n${ASM_FAILURE_MSG}")
@@ -203,14 +217,42 @@
endif()
endif()
+ # When compiling for x86 on x64, we can't use CMAKE_SYSTEM_PROCESSOR to determine which architecture to use,
+ # Instead, check the size of void* and if its 4, set ASM_OFFSET_SYSTEM_PROCESSOR to x86
+ # Note - there is no 32 bit arm assembly code, so this only applies to x86 currently.
+ if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ set(ASM_OFFSET_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}) # x86_64 or aarch64
+ else()
+ set(ASM_OFFSET_SYSTEM_PROCESSOR "x86")
+ endif()
+
if(ASSEMBLER_WORKS)
add_executable(asm_offset asm_offset.c)
target_link_libraries(asm_offset loader_specific_options)
- add_custom_command(OUTPUT gen_defines.asm DEPENDS asm_offset COMMAND asm_offset GAS)
+ # If not cross compiling, run asm_offset to generage gen_defines.asm
+ if (NOT CMAKE_CROSSCOMPILING)
+ add_custom_command(OUTPUT gen_defines.asm DEPENDS asm_offset COMMAND asm_offset GAS)
+ else()
+ # Forces compiler to write the intermediate asm file, needed so that we can get sizeof/offset of info out of it.
+ target_compile_options(asm_offset PRIVATE -save-temps=obj)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(ASM_OFFSET_INTERMEDIATE_LOCATION "$<TARGET_FILE_DIR:asm_offset>/CMakeFiles/asm_offset.dir/asm_offset.c.s")
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(ASM_OFFSET_INTERMEDIATE_LOCATION "$<TARGET_FILE_DIR:asm_offset>/CMakeFiles/asm_offset.dir/asm_offset.s")
+ endif()
+
+ find_package(PythonInterp REQUIRED)
+ # Run parse_asm_values.py on asm_offset's assembly file to generate the gen_defines.asm, which the asm code depends on
+ add_custom_command(TARGET asm_offset POST_BUILD
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/parse_asm_values.py "$<TARGET_FILE_DIR:asm_offset>/gen_defines.asm"
+ "${ASM_OFFSET_INTERMEDIATE_LOCATION}" "GAS" "${CMAKE_CXX_COMPILER_ID}" "${ASM_OFFSET_SYSTEM_PROCESSOR}"
+ BYPRODUCTS gen_defines.asm
+ )
+ endif()
add_custom_target(loader_asm_gen_files DEPENDS gen_defines.asm)
else()
if(USE_GAS)
- message(WARNING "Could not find working ${CMAKE_SYSTEM_PROCESSOR} GAS assembler\n${ASM_FAILURE_MSG}")
+ message(WARNING "Could not find working ${ASM_OFFSET_SYSTEM_PROCESSOR} GAS assembler\n${ASM_FAILURE_MSG}")
else()
message(WARNING "Assembly sources have been disabled\n${ASM_FAILURE_MSG}")
endif()
@@ -268,10 +310,9 @@
add_library(vulkan SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS})
endif()
add_dependencies(vulkan loader_asm_gen_files)
- # set version based on LOADER_GENERATED_HEADER_VERSION used to generate the code
set_target_properties(vulkan
PROPERTIES SOVERSION "1"
- VERSION ${LOADER_GENERATED_HEADER_VERSION})
+ VERSION ${VulkanHeaders_VERSION})
target_link_libraries(vulkan PRIVATE ${CMAKE_DL_LIBS} m)
if (NOT ANDROID)
target_link_libraries(vulkan PRIVATE Threads::Threads)
@@ -285,6 +326,7 @@
# Use GLOB_RECURSE to find all the header files and populate the vulkan.framework headers with them
# Use CONFIGURE_DEPENDS to ensure that if the header files are updated, this list is also updated
# Note: CONFIGURE_DEPENDS is a 3.12 feature - gate it for now and remove when CMake minimum version is higher
+ get_target_property(VulkanHeaders_INCLUDE_DIRS Vulkan::Headers INTERFACE_INCLUDE_DIRECTORIES)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0")
file(GLOB_RECURSE CONFIGURE_DEPENDS FRAMEWORK_HEADERS ${VulkanHeaders_INCLUDE_DIRS})
else()
@@ -309,8 +351,8 @@
OUTPUT_NAME vulkan
FRAMEWORK TRUE
FRAMEWORK_VERSION A
- VERSION "${LOADER_GENERATED_HEADER_VERSION}" # "current version"
- SOVERSION "1.0.0" # "compatibility version"
+ VERSION "${VulkanHeaders_VERSION}" # "current version"
+ SOVERSION "1.0.0" # "compatibility version"
MACOSX_FRAMEWORK_IDENTIFIER com.lunarg.vulkanFramework
PUBLIC_HEADER "${FRAMEWORK_HEADERS}"
)
@@ -331,12 +373,18 @@
endif()
# Generate pkg-config file.
-include(FindPkgConfig QUIET)
+find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
- set(VK_API_VERSION "${LOADER_GENERATED_HEADER_VERSION}")
- foreach(LIB ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES} ${PLATFORM_LIBS})
- set(PRIVATE_LIBS "${PRIVATE_LIBS} -l${LIB}")
- endforeach()
+ set(VK_API_VERSION "${VulkanHeaders_VERSION}")
+ set(PRIVATE_LIBS "")
+ if (APPLE AND BUILD_STATIC_LOADER)
+ # Libs.private should only be present when building a static loader
+ foreach(LIB ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES})
+ list(APPEND PRIVATE_LIBS "-l${LIB}")
+ endforeach()
+ list(REMOVE_DUPLICATES PRIVATE_LIBS)
+ set(PRIVATE_LIBS "Libs.private: ${PRIVATE_LIBS}")
+ endif()
if(WIN32)
if(MINGW)
set(VULKAN_LIB_SUFFIX "-1.dll")
@@ -353,6 +401,13 @@
else()
set(CMAKE_INSTALL_FULL_LIBDIR_PC ${CMAKE_INSTALL_FULL_LIBDIR})
endif ()
+ if ("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
+ set(CMAKE_INSTALL_REL_LIBDIR_PC ${CMAKE_INSTALL_FULL_LIBDIR_PC})
+ set(CMAKE_INSTALL_REL_INCLUDEDIR_PC ${CMAKE_INSTALL_FULL_INCLUDEDIR})
+ else()
+ file(RELATIVE_PATH CMAKE_INSTALL_REL_LIBDIR_PC ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_LIBDIR_PC})
+ file(RELATIVE_PATH CMAKE_INSTALL_REL_INCLUDEDIR_PC ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_INCLUDEDIR})
+ endif()
configure_file("vulkan.pc.in" "vulkan.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/vulkan.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()
diff --git a/loader/asm_offset.c b/loader/asm_offset.c
index 80b7106..248d8fb 100644
--- a/loader/asm_offset.c
+++ b/loader/asm_offset.c
@@ -26,6 +26,36 @@
#include "loader_common.h"
#include "log.h"
+#if defined(__GNUC__) || defined(__clang__)
+void produce_asm_define() {
+ // GCC and clang make it easy to print easy to regex for values
+ __asm__("# VULKAN_LOADER_ERROR_BIT = %c0" : : "i"(VULKAN_LOADER_ERROR_BIT));
+ __asm__("# PTR_SIZE = %c0" : : "i"(sizeof(void *)));
+ __asm__("# CHAR_PTR_SIZE = %c0" : : "i"(sizeof(char *)));
+ __asm__("# FUNCTION_OFFSET_INSTANCE = %c0" : : "i"(offsetof(struct loader_instance, phys_dev_ext_disp_functions)));
+ __asm__("# PHYS_DEV_OFFSET_INST_DISPATCH = %c0" : : "i"(offsetof(struct loader_instance_dispatch_table, phys_dev_ext)));
+ __asm__("# PHYS_DEV_OFFSET_PHYS_DEV_TRAMP = %c0" : : "i"(offsetof(struct loader_physical_device_tramp, phys_dev)));
+ __asm__("# ICD_TERM_OFFSET_PHYS_DEV_TERM = %c0" : : "i"(offsetof(struct loader_physical_device_term, this_icd_term)));
+ __asm__("# PHYS_DEV_OFFSET_PHYS_DEV_TERM = %c0" : : "i"(offsetof(struct loader_physical_device_term, phys_dev)));
+ __asm__("# INSTANCE_OFFSET_ICD_TERM = %c0" : : "i"(offsetof(struct loader_icd_term, this_instance)));
+ __asm__("# DISPATCH_OFFSET_ICD_TERM = %c0" : : "i"(offsetof(struct loader_icd_term, phys_dev_ext)));
+ __asm__("# EXT_OFFSET_DEVICE_DISPATCH = %c0" : : "i"(offsetof(struct loader_dev_dispatch_table, ext_dispatch)));
+}
+#elif defined(_WIN32)
+// MSVC will print the name of the value and the value in hex
+// Must disable optimization for this translation unit, otherwise the compiler strips out the variables
+static const uint32_t PTR_SIZE = sizeof(void *);
+static const uint32_t CHAR_PTR_SIZE = sizeof(char *);
+static const uint32_t FUNCTION_OFFSET_INSTANCE = offsetof(struct loader_instance, phys_dev_ext_disp_functions);
+static const uint32_t PHYS_DEV_OFFSET_INST_DISPATCH = offsetof(struct loader_instance_dispatch_table, phys_dev_ext);
+static const uint32_t PHYS_DEV_OFFSET_PHYS_DEV_TRAMP = offsetof(struct loader_physical_device_tramp, phys_dev);
+static const uint32_t ICD_TERM_OFFSET_PHYS_DEV_TERM = offsetof(struct loader_physical_device_term, this_icd_term);
+static const uint32_t PHYS_DEV_OFFSET_PHYS_DEV_TERM = offsetof(struct loader_physical_device_term, phys_dev);
+static const uint32_t INSTANCE_OFFSET_ICD_TERM = offsetof(struct loader_icd_term, this_instance);
+static const uint32_t DISPATCH_OFFSET_ICD_TERM = offsetof(struct loader_icd_term, phys_dev_ext);
+static const uint32_t EXT_OFFSET_DEVICE_DISPATCH = offsetof(struct loader_dev_dispatch_table, ext_dispatch);
+#endif
+
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
#define SIZE_T_FMT "%-8zu"
#else
@@ -38,6 +68,8 @@
const char *comment;
};
+// This file can both be executed to produce gen_defines.asm and contains all the relevant data which
+// the parse_asm_values.py script needs to write gen_defines.asm, necessary for cross compilation
int main(int argc, char **argv) {
const char *assembler = NULL;
for (int i = 0; i < argc; ++i) {
diff --git a/loader/cJSON.c b/loader/cJSON.c
index 40adcb4..6368f21 100644
--- a/loader/cJSON.c
+++ b/loader/cJSON.c
@@ -165,31 +165,35 @@
/* Render the number nicely from the given item into a string. */
char *print_number(cJSON *item, printbuffer *p) {
char *str = 0;
+ size_t str_buf_size;
double d = item->valuedouble;
if (d == 0) {
+ str_buf_size = 2; /* special case for 0. */
if (p)
- str = ensure(item->pAllocator, p, 2);
+ str = ensure(item->pAllocator, p, str_buf_size);
else
- str = (char *)cJSON_malloc(item->pAllocator, 2); /* special case for 0. */
+ str = (char *)cJSON_malloc(item->pAllocator, str_buf_size);
if (str) strcpy(str, "0");
} else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
+ str_buf_size = 21; /* 2^64+1 can be represented in 21 chars. */
if (p)
- str = ensure(item->pAllocator, p, 21);
+ str = ensure(item->pAllocator, p, str_buf_size);
else
- str = (char *)cJSON_malloc(item->pAllocator, 21); /* 2^64+1 can be represented in 21 chars. */
- if (str) sprintf(str, "%d", item->valueint);
+ str = (char *)cJSON_malloc(item->pAllocator, str_buf_size);
+ if (str) snprintf(str, str_buf_size, "%d", item->valueint);
} else {
+ str_buf_size = 64; /* This is a nice tradeoff. */
if (p)
- str = ensure(item->pAllocator, p, 64);
+ str = ensure(item->pAllocator, p, str_buf_size);
else
- str = (char *)cJSON_malloc(item->pAllocator, 64); /* This is a nice tradeoff. */
+ str = (char *)cJSON_malloc(item->pAllocator, str_buf_size);
if (str) {
if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60)
- sprintf(str, "%.0f", d);
+ snprintf(str, str_buf_size, "%.0f", d);
else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9)
- sprintf(str, "%e", d);
+ snprintf(str, str_buf_size, "%e", d);
else
- sprintf(str, "%f", d);
+ snprintf(str, str_buf_size, "%f", d);
}
}
return str;
@@ -304,21 +308,13 @@
len = 3;
ptr2 += len;
- switch (len) {
- case 4:
- *--ptr2 = ((uc | 0x80) & 0xBF);
- uc >>= 6;
- // fall through
- case 3:
- *--ptr2 = ((uc | 0x80) & 0xBF);
- uc >>= 6;
- // fall through
- case 2:
- *--ptr2 = ((uc | 0x80) & 0xBF);
- uc >>= 6;
- // fall through
- case 1:
+ for (size_t i = len; i > 0; i--) {
+ if (i == 1) {
*--ptr2 = ((unsigned char)uc | firstByteMark[len]);
+ } else if (i >= 2) {
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ }
}
ptr2 += len;
break;
@@ -341,16 +337,17 @@
const char *ptr;
char *ptr2;
char *out;
- size_t len = 0, flag = 0;
+ size_t out_buf_size, len = 0, flag = 0;
unsigned char token;
for (ptr = str; *ptr; ptr++) flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;
if (!flag) {
len = ptr - str;
+ out_buf_size = len + 3;
if (p)
- out = ensure(pAllocator, p, len + 3);
+ out = ensure(pAllocator, p, out_buf_size);
else
- out = (char *)cJSON_malloc(pAllocator, len + 3);
+ out = (char *)cJSON_malloc(pAllocator, out_buf_size);
if (!out) return 0;
ptr2 = out;
*ptr2++ = '\"';
@@ -361,10 +358,11 @@
}
if (!str) {
+ out_buf_size = 3;
if (p)
- out = ensure(pAllocator, p, 3);
+ out = ensure(pAllocator, p, out_buf_size);
else
- out = (char *)cJSON_malloc(pAllocator, 3);
+ out = (char *)cJSON_malloc(pAllocator, out_buf_size);
if (!out) return 0;
strcpy(out, "\"\"");
return out;
@@ -380,10 +378,11 @@
token = *ptr;
}
+ out_buf_size = len + 3;
if (p)
- out = ensure(pAllocator, p, len + 3);
+ out = ensure(pAllocator, p, out_buf_size);
else
- out = (char *)cJSON_malloc(pAllocator, len + 3);
+ out = (char *)cJSON_malloc(pAllocator, out_buf_size);
if (!out) return 0;
ptr2 = out;
@@ -416,7 +415,7 @@
*ptr2++ = '\t';
break;
default:
- sprintf(ptr2, "u%04x", token);
+ snprintf(ptr2, out_buf_size - (ptr2 - out), "u%04x", token);
ptr2 += 5;
break; /* escape and print */
}
diff --git a/loader/extension_manual.c b/loader/extension_manual.c
index 196df20..50cc720 100644
--- a/loader/extension_manual.c
+++ b/loader/extension_manual.c
@@ -307,18 +307,30 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.GetDeviceGroupSurfacePresentModes2EXT) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pSurfaceInfo->surface;
- if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)NULL != icd_surface->real_icd_surfaces[icd_index]) {
- VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
- surface_info_copy.sType = pSurfaceInfo->sType;
- surface_info_copy.pNext = pSurfaceInfo->pNext;
- surface_info_copy.surface = icd_surface->real_icd_surfaces[icd_index];
- return icd_term->dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, &surface_info_copy, pModes);
- }
- return icd_term->dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, pSurfaceInfo, pModes);
+ if (NULL == icd_term || NULL == dev ||
+ NULL == dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkGetDeviceGroupSurfacePresentModes2EXT Terminator: Invalid device handle. This is likely the result of a "
+ "layer wrapping device handles and failing to unwrap them in all functions. "
+ "[VUID-vkGetDeviceGroupSurfacePresentModes2EXT-device-parameter]");
+ abort(); /* Intentionally fail so user can correct issue. */
}
- return VK_SUCCESS;
+ if (NULL == pSurfaceInfo) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkGetDeviceGroupSurfacePresentModes2EXT: Invalid pSurfaceInfo pointer "
+ "[VUID-vkGetDeviceGroupSurfacePresentModes2EXT-pSurfaceInfo-parameter]");
+ abort(); /* Intentionally fail so user can correct issue. */
+ }
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pSurfaceInfo->surface;
+ if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)NULL != icd_surface->real_icd_surfaces[icd_index]) {
+ VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
+ surface_info_copy.sType = pSurfaceInfo->sType;
+ surface_info_copy.pNext = pSurfaceInfo->pNext;
+ surface_info_copy.surface = icd_surface->real_icd_surfaces[icd_index];
+ return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, &surface_info_copy,
+ pModes);
+ }
+ return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, pSurfaceInfo, pModes);
}
#endif // VK_USE_PLATFORM_WIN32_KHR
diff --git a/loader/generated/loader_generated_header_version.cmake b/loader/generated/loader_generated_header_version.cmake
deleted file mode 100644
index 897103b..0000000
--- a/loader/generated/loader_generated_header_version.cmake
+++ /dev/null
@@ -1,28 +0,0 @@
-# *** THIS FILE IS GENERATED - DO NOT EDIT ***
-# See loader_versioning_generator.py for modifications
-
-############################################################################
-#
-# Copyright (c) 2021 The Khronos Group Inc.
-# Copyright (c) 2021 Valve Corporation
-# Copyright (c) 2021 LunarG, Inc.
-# Copyright (c) 2021 Google 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: Charles Giessen <charles@lunarg.com>
-#
-############################################################################
-
-set(LOADER_GENERATED_HEADER_VERSION "1.3.231")
-
diff --git a/loader/generated/vk_loader_extensions.c b/loader/generated/vk_loader_extensions.c
index 4960ab8..34b52f8 100644
--- a/loader/generated/vk_loader_extensions.c
+++ b/loader/generated/vk_loader_extensions.c
@@ -98,8 +98,6 @@
LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModesKHR, false);
// ---- VK_KHR_swapchain extension commands
- LOOKUP_GIPA(CreateSwapchainKHR, false);
- LOOKUP_GIPA(GetDeviceGroupSurfacePresentModesKHR, false);
LOOKUP_GIPA(GetPhysicalDevicePresentRectanglesKHR, false);
// ---- VK_KHR_display extension commands
@@ -111,9 +109,6 @@
LOOKUP_GIPA(GetDisplayPlaneCapabilitiesKHR, false);
LOOKUP_GIPA(CreateDisplayPlaneSurfaceKHR, false);
- // ---- VK_KHR_display_swapchain extension commands
- LOOKUP_GIPA(CreateSharedSwapchainsKHR, false);
-
// ---- VK_KHR_xlib_surface extension commands
#ifdef VK_USE_PLATFORM_XLIB_KHR
LOOKUP_GIPA(CreateXlibSurfaceKHR, false);
@@ -202,10 +197,6 @@
LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
LOOKUP_GIPA(DebugReportMessageEXT, false);
- // ---- VK_EXT_debug_marker extension commands
- LOOKUP_GIPA(DebugMarkerSetObjectTagEXT, false);
- LOOKUP_GIPA(DebugMarkerSetObjectNameEXT, false);
-
// ---- VK_GGP_stream_descriptor_surface extension commands
#ifdef VK_USE_PLATFORM_GGP
LOOKUP_GIPA(CreateStreamDescriptorSurfaceGGP, false);
@@ -244,14 +235,6 @@
#endif // VK_USE_PLATFORM_MACOS_MVK
// ---- VK_EXT_debug_utils extension commands
- LOOKUP_GIPA(SetDebugUtilsObjectNameEXT, false);
- LOOKUP_GIPA(SetDebugUtilsObjectTagEXT, false);
- LOOKUP_GIPA(QueueBeginDebugUtilsLabelEXT, false);
- LOOKUP_GIPA(QueueEndDebugUtilsLabelEXT, false);
- LOOKUP_GIPA(QueueInsertDebugUtilsLabelEXT, false);
- LOOKUP_GIPA(CmdBeginDebugUtilsLabelEXT, false);
- LOOKUP_GIPA(CmdEndDebugUtilsLabelEXT, false);
- LOOKUP_GIPA(CmdInsertDebugUtilsLabelEXT, false);
LOOKUP_GIPA(CreateDebugUtilsMessengerEXT, false);
LOOKUP_GIPA(DestroyDebugUtilsMessengerEXT, false);
LOOKUP_GIPA(SubmitDebugUtilsMessageEXT, false);
@@ -285,9 +268,6 @@
#ifdef VK_USE_PLATFORM_WIN32_KHR
LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModes2EXT, false);
#endif // VK_USE_PLATFORM_WIN32_KHR
-#ifdef VK_USE_PLATFORM_WIN32_KHR
- LOOKUP_GIPA(GetDeviceGroupSurfacePresentModes2EXT, false);
-#endif // VK_USE_PLATFORM_WIN32_KHR
// ---- VK_EXT_headless_surface extension commands
LOOKUP_GIPA(CreateHeadlessSurfaceEXT, false);
@@ -1364,6 +1344,48 @@
table->GetPhysicalDeviceOpticalFlowImageFormatsNV = (PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)gpa(inst, "vkGetPhysicalDeviceOpticalFlowImageFormatsNV");
}
+// Functions that required a terminator need to have a separate dispatch table which contains their corresponding
+// device function. This is used in the terminators themselves.
+void init_extension_device_proc_terminator_dispatch(struct loader_device *dev) {
+ struct loader_device_terminator_dispatch* dispatch = &dev->loader_dispatch.extension_terminator_dispatch;
+ PFN_vkGetDeviceProcAddr gpda = (PFN_vkGetDeviceProcAddr)dev->phys_dev_term->this_icd_term->dispatch.GetDeviceProcAddr;
+ // ---- VK_KHR_swapchain extension commands
+ if (dev->extensions.khr_swapchain_enabled)
+ dispatch->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpda(dev->icd_device, "vkCreateSwapchainKHR");
+ if (dev->extensions.khr_swapchain_enabled)
+ dispatch->GetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR)gpda(dev->icd_device, "vkGetDeviceGroupSurfacePresentModesKHR");
+ // ---- VK_KHR_display_swapchain extension commands
+ if (dev->extensions.khr_display_swapchain_enabled)
+ dispatch->CreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)gpda(dev->icd_device, "vkCreateSharedSwapchainsKHR");
+ // ---- VK_EXT_debug_marker extension commands
+ if (dev->extensions.ext_debug_marker_enabled)
+ dispatch->DebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)gpda(dev->icd_device, "vkDebugMarkerSetObjectTagEXT");
+ if (dev->extensions.ext_debug_marker_enabled)
+ dispatch->DebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)gpda(dev->icd_device, "vkDebugMarkerSetObjectNameEXT");
+ // ---- VK_EXT_debug_utils extension commands
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->SetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)gpda(dev->icd_device, "vkSetDebugUtilsObjectNameEXT");
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->SetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT)gpda(dev->icd_device, "vkSetDebugUtilsObjectTagEXT");
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->QueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)gpda(dev->icd_device, "vkQueueBeginDebugUtilsLabelEXT");
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->QueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)gpda(dev->icd_device, "vkQueueEndDebugUtilsLabelEXT");
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->QueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)gpda(dev->icd_device, "vkQueueInsertDebugUtilsLabelEXT");
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->CmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)gpda(dev->icd_device, "vkCmdBeginDebugUtilsLabelEXT");
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->CmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)gpda(dev->icd_device, "vkCmdEndDebugUtilsLabelEXT");
+ if (dev->extensions.ext_debug_utils_enabled)
+ dispatch->CmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)gpda(dev->icd_device, "vkCmdInsertDebugUtilsLabelEXT");
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+ // ---- VK_EXT_full_screen_exclusive extension commands
+ if (dev->extensions.ext_full_screen_exclusive_enabled && dev->extensions.khr_device_group_enabled)
+ dispatch->GetDeviceGroupSurfacePresentModes2EXT = (PFN_vkGetDeviceGroupSurfacePresentModes2EXT)gpda(dev->icd_device, "vkGetDeviceGroupSurfacePresentModes2EXT");
+#endif // None
+}
+
// Device command lookup function
VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name) {
if (!name || name[0] != 'v' || name[1] != 'k') return NULL;
@@ -3928,26 +3950,30 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.DebugMarkerSetObjectTagEXT) {
- VkDebugMarkerObjectTagInfoEXT local_tag_info;
- memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));
- // If this is a physical device, we have to replace it with the proper one for the next call.
- if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {
- struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->object;
- local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
- // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
- } else if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {
- if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->object;
- if (NULL != icd_surface->real_icd_surfaces) {
- local_tag_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
- }
+ if (NULL == icd_term || NULL == dev) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "DebugMarkerSetObjectTagEXT: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
+ }
+ VkDebugMarkerObjectTagInfoEXT local_tag_info;
+ memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));
+ // If this is a physical device, we have to replace it with the proper one for the next call.
+ if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {
+ struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->object;
+ local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
+ // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
+ } else if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {
+ if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->object;
+ if (NULL != icd_surface->real_icd_surfaces) {
+ local_tag_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
}
}
- return icd_term->dispatch.DebugMarkerSetObjectTagEXT(device, &local_tag_info);
- } else {
- return VK_SUCCESS;
}
+ // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports
+ // debug utils but the driver does not.
+ if (NULL == dev->loader_dispatch.extension_terminator_dispatch.DebugMarkerSetObjectTagEXT)
+ return VK_SUCCESS;
+ return dev->loader_dispatch.extension_terminator_dispatch.DebugMarkerSetObjectTagEXT(device, &local_tag_info);
}
VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectNameEXT(
@@ -3976,26 +4002,30 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.DebugMarkerSetObjectNameEXT) {
- VkDebugMarkerObjectNameInfoEXT local_name_info;
- memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));
- // If this is a physical device, we have to replace it with the proper one for the next call.
- if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {
- struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->object;
- local_name_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
- // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
- } else if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {
- if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->object;
- if (NULL != icd_surface->real_icd_surfaces) {
- local_name_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
- }
+ if (NULL == icd_term || NULL == dev) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "DebugMarkerSetObjectNameEXT: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
+ }
+ VkDebugMarkerObjectNameInfoEXT local_name_info;
+ memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));
+ // If this is a physical device, we have to replace it with the proper one for the next call.
+ if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {
+ struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->object;
+ local_name_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
+ // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
+ } else if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {
+ if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->object;
+ if (NULL != icd_surface->real_icd_surfaces) {
+ local_name_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
}
}
- return icd_term->dispatch.DebugMarkerSetObjectNameEXT(device, &local_name_info);
- } else {
- return VK_SUCCESS;
}
+ // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports
+ // debug utils but the driver does not.
+ if (NULL == dev->loader_dispatch.extension_terminator_dispatch.DebugMarkerSetObjectNameEXT)
+ return VK_SUCCESS;
+ return dev->loader_dispatch.extension_terminator_dispatch.DebugMarkerSetObjectNameEXT(device, &local_name_info);
}
VKAPI_ATTR void VKAPI_CALL CmdDebugMarkerBeginEXT(
@@ -4530,26 +4560,30 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.SetDebugUtilsObjectNameEXT) {
- VkDebugUtilsObjectNameInfoEXT local_name_info;
- memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));
- // If this is a physical device, we have to replace it with the proper one for the next call.
- if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {
- struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->objectHandle;
- local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
- // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
- } else if (pNameInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {
- if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->objectHandle;
- if (NULL != icd_surface->real_icd_surfaces) {
- local_name_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
- }
+ if (NULL == icd_term || NULL == dev) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "SetDebugUtilsObjectNameEXT: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
+ }
+ VkDebugUtilsObjectNameInfoEXT local_name_info;
+ memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));
+ // If this is a physical device, we have to replace it with the proper one for the next call.
+ if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {
+ struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->objectHandle;
+ local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
+ // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
+ } else if (pNameInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {
+ if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->objectHandle;
+ if (NULL != icd_surface->real_icd_surfaces) {
+ local_name_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
}
}
- return icd_term->dispatch.SetDebugUtilsObjectNameEXT(device, &local_name_info);
- } else {
- return VK_SUCCESS;
}
+ // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports
+ // debug utils but the driver does not.
+ if (NULL == dev->loader_dispatch.extension_terminator_dispatch.SetDebugUtilsObjectNameEXT)
+ return VK_SUCCESS;
+ return dev->loader_dispatch.extension_terminator_dispatch.SetDebugUtilsObjectNameEXT(device, &local_name_info);
}
VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectTagEXT(
@@ -4582,26 +4616,30 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.SetDebugUtilsObjectTagEXT) {
- VkDebugUtilsObjectTagInfoEXT local_tag_info;
- memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));
- // If this is a physical device, we have to replace it with the proper one for the next call.
- if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {
- struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->objectHandle;
- local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
- // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
- } else if (pTagInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {
- if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->objectHandle;
- if (NULL != icd_surface->real_icd_surfaces) {
- local_tag_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
- }
+ if (NULL == icd_term || NULL == dev) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "SetDebugUtilsObjectTagEXT: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
+ }
+ VkDebugUtilsObjectTagInfoEXT local_tag_info;
+ memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));
+ // If this is a physical device, we have to replace it with the proper one for the next call.
+ if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {
+ struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->objectHandle;
+ local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;
+ // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.
+ } else if (pTagInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {
+ if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->objectHandle;
+ if (NULL != icd_surface->real_icd_surfaces) {
+ local_tag_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];
}
}
- return icd_term->dispatch.SetDebugUtilsObjectTagEXT(device, &local_tag_info);
- } else {
- return VK_SUCCESS;
}
+ // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports
+ // debug utils but the driver does not.
+ if (NULL == dev->loader_dispatch.extension_terminator_dispatch.SetDebugUtilsObjectTagEXT)
+ return VK_SUCCESS;
+ return dev->loader_dispatch.extension_terminator_dispatch.SetDebugUtilsObjectTagEXT(device, &local_tag_info);
}
VKAPI_ATTR void VKAPI_CALL QueueBeginDebugUtilsLabelEXT(
@@ -4622,12 +4660,14 @@
VKAPI_ATTR void VKAPI_CALL terminator_QueueBeginDebugUtilsLabelEXT(
VkQueue queue,
const VkDebugUtilsLabelEXT* pLabelInfo) {
- uint32_t icd_index = 0;
- struct loader_device *dev;
- struct loader_icd_term *icd_term = loader_get_icd_and_device(queue, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.QueueBeginDebugUtilsLabelEXT) {
- icd_term->dispatch.QueueBeginDebugUtilsLabelEXT(queue, pLabelInfo);
+ struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch(queue);
+ if (NULL == dispatch_table) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "VK_EXT_debug_utils: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
}
+ // Only call down if the device supports the function
+ if (NULL != dispatch_table->extension_terminator_dispatch.QueueBeginDebugUtilsLabelEXT)
+ dispatch_table->extension_terminator_dispatch.QueueBeginDebugUtilsLabelEXT(queue, pLabelInfo);
}
VKAPI_ATTR void VKAPI_CALL QueueEndDebugUtilsLabelEXT(
@@ -4646,12 +4686,14 @@
VKAPI_ATTR void VKAPI_CALL terminator_QueueEndDebugUtilsLabelEXT(
VkQueue queue) {
- uint32_t icd_index = 0;
- struct loader_device *dev;
- struct loader_icd_term *icd_term = loader_get_icd_and_device(queue, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.QueueEndDebugUtilsLabelEXT) {
- icd_term->dispatch.QueueEndDebugUtilsLabelEXT(queue);
+ struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch(queue);
+ if (NULL == dispatch_table) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "VK_EXT_debug_utils: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
}
+ // Only call down if the device supports the function
+ if (NULL != dispatch_table->extension_terminator_dispatch.QueueEndDebugUtilsLabelEXT)
+ dispatch_table->extension_terminator_dispatch.QueueEndDebugUtilsLabelEXT(queue);
}
VKAPI_ATTR void VKAPI_CALL QueueInsertDebugUtilsLabelEXT(
@@ -4672,12 +4714,14 @@
VKAPI_ATTR void VKAPI_CALL terminator_QueueInsertDebugUtilsLabelEXT(
VkQueue queue,
const VkDebugUtilsLabelEXT* pLabelInfo) {
- uint32_t icd_index = 0;
- struct loader_device *dev;
- struct loader_icd_term *icd_term = loader_get_icd_and_device(queue, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.QueueInsertDebugUtilsLabelEXT) {
- icd_term->dispatch.QueueInsertDebugUtilsLabelEXT(queue, pLabelInfo);
+ struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch(queue);
+ if (NULL == dispatch_table) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "VK_EXT_debug_utils: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
}
+ // Only call down if the device supports the function
+ if (NULL != dispatch_table->extension_terminator_dispatch.QueueInsertDebugUtilsLabelEXT)
+ dispatch_table->extension_terminator_dispatch.QueueInsertDebugUtilsLabelEXT(queue, pLabelInfo);
}
VKAPI_ATTR void VKAPI_CALL CmdBeginDebugUtilsLabelEXT(
@@ -4698,12 +4742,14 @@
VKAPI_ATTR void VKAPI_CALL terminator_CmdBeginDebugUtilsLabelEXT(
VkCommandBuffer commandBuffer,
const VkDebugUtilsLabelEXT* pLabelInfo) {
- uint32_t icd_index = 0;
- struct loader_device *dev;
- struct loader_icd_term *icd_term = loader_get_icd_and_device(commandBuffer, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.CmdBeginDebugUtilsLabelEXT) {
- icd_term->dispatch.CmdBeginDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
+ struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch(commandBuffer);
+ if (NULL == dispatch_table) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "VK_EXT_debug_utils: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
}
+ // Only call down if the device supports the function
+ if (NULL != dispatch_table->extension_terminator_dispatch.CmdBeginDebugUtilsLabelEXT)
+ dispatch_table->extension_terminator_dispatch.CmdBeginDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
}
VKAPI_ATTR void VKAPI_CALL CmdEndDebugUtilsLabelEXT(
@@ -4722,12 +4768,14 @@
VKAPI_ATTR void VKAPI_CALL terminator_CmdEndDebugUtilsLabelEXT(
VkCommandBuffer commandBuffer) {
- uint32_t icd_index = 0;
- struct loader_device *dev;
- struct loader_icd_term *icd_term = loader_get_icd_and_device(commandBuffer, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.CmdEndDebugUtilsLabelEXT) {
- icd_term->dispatch.CmdEndDebugUtilsLabelEXT(commandBuffer);
+ struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch(commandBuffer);
+ if (NULL == dispatch_table) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "VK_EXT_debug_utils: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
}
+ // Only call down if the device supports the function
+ if (NULL != dispatch_table->extension_terminator_dispatch.CmdEndDebugUtilsLabelEXT)
+ dispatch_table->extension_terminator_dispatch.CmdEndDebugUtilsLabelEXT(commandBuffer);
}
VKAPI_ATTR void VKAPI_CALL CmdInsertDebugUtilsLabelEXT(
@@ -4748,12 +4796,14 @@
VKAPI_ATTR void VKAPI_CALL terminator_CmdInsertDebugUtilsLabelEXT(
VkCommandBuffer commandBuffer,
const VkDebugUtilsLabelEXT* pLabelInfo) {
- uint32_t icd_index = 0;
- struct loader_device *dev;
- struct loader_icd_term *icd_term = loader_get_icd_and_device(commandBuffer, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.CmdInsertDebugUtilsLabelEXT) {
- icd_term->dispatch.CmdInsertDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
+ struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch(commandBuffer);
+ if (NULL == dispatch_table) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "VK_EXT_debug_utils: Invalid device handle");
+ abort(); /* Intentionally fail so user can correct issue. */
}
+ // Only call down if the device supports the function
+ if (NULL != dispatch_table->extension_terminator_dispatch.CmdInsertDebugUtilsLabelEXT)
+ dispatch_table->extension_terminator_dispatch.CmdInsertDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
}
@@ -9535,64 +9585,90 @@
// Some device commands still need a terminator because the loader needs to unwrap something about them.
// In many cases, the item needing unwrapping is a VkPhysicalDevice or VkSurfaceKHR object. But there may be other items
// in the future.
-PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *pName) {
- PFN_vkVoidFunction addr = NULL;
-
+PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name) {
+ *found_name = false;
+ if (!name || name[0] != 'v' || name[1] != 'k') {
+ return NULL;
+ }
+ name += 2;
// ---- VK_KHR_swapchain extension commands
- if (dev->extensions.khr_swapchain_enabled) {
- if(!strcmp(pName, "vkCreateSwapchainKHR")) {
- addr = (PFN_vkVoidFunction)terminator_CreateSwapchainKHR;
- } else if(!strcmp(pName, "vkGetDeviceGroupSurfacePresentModesKHR")) {
- addr = (PFN_vkVoidFunction)terminator_GetDeviceGroupSurfacePresentModesKHR;
- }
+ if (!strcmp(name, "CreateSwapchainKHR")) {
+ *found_name = true;
+ return dev->extensions.khr_swapchain_enabled ?
+ (PFN_vkVoidFunction)terminator_CreateSwapchainKHR : NULL;
}
-
+ if (!strcmp(name, "GetDeviceGroupSurfacePresentModesKHR")) {
+ *found_name = true;
+ return dev->extensions.khr_swapchain_enabled ?
+ (PFN_vkVoidFunction)terminator_GetDeviceGroupSurfacePresentModesKHR : NULL;
+ }
// ---- VK_KHR_display_swapchain extension commands
- if (dev->extensions.khr_display_swapchain_enabled) {
- if(!strcmp(pName, "vkCreateSharedSwapchainsKHR")) {
- addr = (PFN_vkVoidFunction)terminator_CreateSharedSwapchainsKHR;
- }
+ if (!strcmp(name, "CreateSharedSwapchainsKHR")) {
+ *found_name = true;
+ return dev->extensions.khr_display_swapchain_enabled ?
+ (PFN_vkVoidFunction)terminator_CreateSharedSwapchainsKHR : NULL;
}
-
// ---- VK_EXT_debug_marker extension commands
- if (dev->extensions.ext_debug_marker_enabled) {
- if(!strcmp(pName, "vkDebugMarkerSetObjectTagEXT")) {
- addr = (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectTagEXT;
- } else if(!strcmp(pName, "vkDebugMarkerSetObjectNameEXT")) {
- addr = (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectNameEXT;
- }
+ if (!strcmp(name, "DebugMarkerSetObjectTagEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_marker_enabled ?
+ (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectTagEXT : NULL;
}
-
+ if (!strcmp(name, "DebugMarkerSetObjectNameEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_marker_enabled ?
+ (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectNameEXT : NULL;
+ }
// ---- VK_EXT_debug_utils extension commands
- if (dev->extensions.ext_debug_utils_enabled) {
- if(!strcmp(pName, "vkSetDebugUtilsObjectNameEXT")) {
- addr = (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectNameEXT;
- } else if(!strcmp(pName, "vkSetDebugUtilsObjectTagEXT")) {
- addr = (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectTagEXT;
- } else if(!strcmp(pName, "vkQueueBeginDebugUtilsLabelEXT")) {
- addr = (PFN_vkVoidFunction)terminator_QueueBeginDebugUtilsLabelEXT;
- } else if(!strcmp(pName, "vkQueueEndDebugUtilsLabelEXT")) {
- addr = (PFN_vkVoidFunction)terminator_QueueEndDebugUtilsLabelEXT;
- } else if(!strcmp(pName, "vkQueueInsertDebugUtilsLabelEXT")) {
- addr = (PFN_vkVoidFunction)terminator_QueueInsertDebugUtilsLabelEXT;
- } else if(!strcmp(pName, "vkCmdBeginDebugUtilsLabelEXT")) {
- addr = (PFN_vkVoidFunction)terminator_CmdBeginDebugUtilsLabelEXT;
- } else if(!strcmp(pName, "vkCmdEndDebugUtilsLabelEXT")) {
- addr = (PFN_vkVoidFunction)terminator_CmdEndDebugUtilsLabelEXT;
- } else if(!strcmp(pName, "vkCmdInsertDebugUtilsLabelEXT")) {
- addr = (PFN_vkVoidFunction)terminator_CmdInsertDebugUtilsLabelEXT;
- }
+ if (!strcmp(name, "SetDebugUtilsObjectNameEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectNameEXT : NULL;
+ }
+ if (!strcmp(name, "SetDebugUtilsObjectTagEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectTagEXT : NULL;
+ }
+ if (!strcmp(name, "QueueBeginDebugUtilsLabelEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_QueueBeginDebugUtilsLabelEXT : NULL;
+ }
+ if (!strcmp(name, "QueueEndDebugUtilsLabelEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_QueueEndDebugUtilsLabelEXT : NULL;
+ }
+ if (!strcmp(name, "QueueInsertDebugUtilsLabelEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_QueueInsertDebugUtilsLabelEXT : NULL;
+ }
+ if (!strcmp(name, "CmdBeginDebugUtilsLabelEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_CmdBeginDebugUtilsLabelEXT : NULL;
+ }
+ if (!strcmp(name, "CmdEndDebugUtilsLabelEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_CmdEndDebugUtilsLabelEXT : NULL;
+ }
+ if (!strcmp(name, "CmdInsertDebugUtilsLabelEXT")) {
+ *found_name = true;
+ return dev->extensions.ext_debug_utils_enabled ?
+ (PFN_vkVoidFunction)terminator_CmdInsertDebugUtilsLabelEXT : NULL;
}
#ifdef VK_USE_PLATFORM_WIN32_KHR
-
// ---- VK_EXT_full_screen_exclusive extension commands
- if (dev->extensions.ext_full_screen_exclusive_enabled && dev->extensions.khr_device_group_enabled) {
- if(!strcmp(pName, "vkGetDeviceGroupSurfacePresentModes2EXT")) {
- addr = (PFN_vkVoidFunction)terminator_GetDeviceGroupSurfacePresentModes2EXT;
- }
+ if (!strcmp(name, "GetDeviceGroupSurfacePresentModes2EXT")) {
+ *found_name = true;
+ return dev->extensions.ext_full_screen_exclusive_enabled && dev->extensions.khr_device_group_enabled ?
+ (PFN_vkVoidFunction)terminator_GetDeviceGroupSurfacePresentModes2EXT : NULL;
}
#endif // None
- return addr;
+ return NULL;
}
// This table contains the loader's instance dispatch table, which contains
diff --git a/loader/generated/vk_loader_extensions.h b/loader/generated/vk_loader_extensions.h
index c0bcfa8..dfdb42b 100644
--- a/loader/generated/vk_loader_extensions.h
+++ b/loader/generated/vk_loader_extensions.h
@@ -45,7 +45,7 @@
// Extension interception for vkGetDeviceProcAddr function, so we can return
// an appropriate terminator if this is one of those few device commands requiring
// a terminator.
-PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *pName);
+PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name);
// Dispatch table properly filled in with appropriate terminators for the
// supported extensions.
@@ -250,8 +250,6 @@
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;
// ---- VK_KHR_swapchain extension commands
- PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
- PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR;
PFN_vkGetPhysicalDevicePresentRectanglesKHR GetPhysicalDevicePresentRectanglesKHR;
// ---- VK_KHR_display extension commands
@@ -263,9 +261,6 @@
PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR;
PFN_vkCreateDisplayPlaneSurfaceKHR CreateDisplayPlaneSurfaceKHR;
- // ---- VK_KHR_display_swapchain extension commands
- PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR;
-
// ---- VK_KHR_xlib_surface extension commands
#ifdef VK_USE_PLATFORM_XLIB_KHR
PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR;
@@ -354,10 +349,6 @@
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
- // ---- VK_EXT_debug_marker extension commands
- PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
- PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
-
// ---- VK_GGP_stream_descriptor_surface extension commands
#ifdef VK_USE_PLATFORM_GGP
PFN_vkCreateStreamDescriptorSurfaceGGP CreateStreamDescriptorSurfaceGGP;
@@ -396,14 +387,6 @@
#endif // VK_USE_PLATFORM_MACOS_MVK
// ---- VK_EXT_debug_utils extension commands
- PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
- PFN_vkSetDebugUtilsObjectTagEXT SetDebugUtilsObjectTagEXT;
- PFN_vkQueueBeginDebugUtilsLabelEXT QueueBeginDebugUtilsLabelEXT;
- PFN_vkQueueEndDebugUtilsLabelEXT QueueEndDebugUtilsLabelEXT;
- PFN_vkQueueInsertDebugUtilsLabelEXT QueueInsertDebugUtilsLabelEXT;
- PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT;
- PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
- PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;
PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT;
@@ -437,9 +420,6 @@
#ifdef VK_USE_PLATFORM_WIN32_KHR
PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT GetPhysicalDeviceSurfacePresentModes2EXT;
#endif // VK_USE_PLATFORM_WIN32_KHR
-#ifdef VK_USE_PLATFORM_WIN32_KHR
- PFN_vkGetDeviceGroupSurfacePresentModes2EXT GetDeviceGroupSurfacePresentModes2EXT;
-#endif // VK_USE_PLATFORM_WIN32_KHR
// ---- VK_EXT_headless_surface extension commands
PFN_vkCreateHeadlessSurfaceEXT CreateHeadlessSurfaceEXT;
@@ -491,4 +471,30 @@
uint8_t ext_acquire_drm_display;
};
+// Functions that required a terminator need to have a separate dispatch table which contains their corresponding
+// device function. This is used in the terminators themselves.
+struct loader_device_terminator_dispatch {
+ // ---- VK_KHR_swapchain extension commands
+ PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
+ PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR;
+ // ---- VK_KHR_display_swapchain extension commands
+ PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR;
+ // ---- VK_EXT_debug_marker extension commands
+ PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
+ PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
+ // ---- VK_EXT_debug_utils extension commands
+ PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
+ PFN_vkSetDebugUtilsObjectTagEXT SetDebugUtilsObjectTagEXT;
+ PFN_vkQueueBeginDebugUtilsLabelEXT QueueBeginDebugUtilsLabelEXT;
+ PFN_vkQueueEndDebugUtilsLabelEXT QueueEndDebugUtilsLabelEXT;
+ PFN_vkQueueInsertDebugUtilsLabelEXT QueueInsertDebugUtilsLabelEXT;
+ PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT;
+ PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
+ PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+ // ---- VK_EXT_full_screen_exclusive extension commands
+ PFN_vkGetDeviceGroupSurfacePresentModes2EXT GetDeviceGroupSurfacePresentModes2EXT;
+#endif // None
+};
+
diff --git a/loader/get_environment.c b/loader/get_environment.c
deleted file mode 100644
index 41ed61f..0000000
--- a/loader/get_environment.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- *
- * Copyright (c) 2014-2021 The Khronos Group Inc.
- * Copyright (c) 2014-2021 Valve Corporation
- * Copyright (c) 2014-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.
- *
- * Author: Jon Ashburn <jon@lunarg.com>
- * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
- * Author: Chia-I Wu <olvaffe@gmail.com>
- * Author: Chia-I Wu <olv@lunarg.com>
- * Author: Mark Lobodzinski <mark@LunarG.com>
- * Author: Lenny Komow <lenny@lunarg.com>
- * Author: Charles Giessen <charles@lunarg.com>
- *
- */
-
-#include "get_environment.h"
-
-#include "allocation.h"
-#include "log.h"
-
-// Environment variables
-#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-
-bool is_high_integrity() { return geteuid() != getuid() || getegid() != getgid(); }
-
-char *loader_getenv(const char *name, const struct loader_instance *inst) {
- // No allocation of memory necessary for Linux, but we should at least touch
- // the inst pointer to get rid of compiler warnings.
- (void)inst;
- return getenv(name);
-}
-
-char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
- // Apple does not appear to have a secure getenv implementation.
- // The main difference between secure getenv and getenv is that secure getenv
- // returns NULL if the process is being run with elevated privileges by a normal user.
- // The idea is to prevent the reading of malicious environment variables by a process
- // that can do damage.
- // This algorithm is derived from glibc code that sets an internal
- // variable (__libc_enable_secure) if the process is running under setuid or setgid.
- return is_high_integrity() ? NULL : loader_getenv(name, inst);
-#elif defined(__Fuchsia__)
- return loader_getenv(name, inst);
-#else
- // Linux
- char *out;
-#if defined(HAVE_SECURE_GETENV) && !defined(USE_UNSAFE_FILE_SEARCH)
- (void)inst;
- out = secure_getenv(name);
-#elif defined(HAVE___SECURE_GETENV) && !defined(USE_UNSAFE_FILE_SEARCH)
- (void)inst;
- out = __secure_getenv(name);
-#else
- out = loader_getenv(name, inst);
-#if !defined(USE_UNSAFE_FILE_SEARCH)
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Loader is using non-secure environment variable lookup for %s", name);
-#endif
-#endif
- return out;
-#endif
-}
-
-void loader_free_getenv(char *val, const struct loader_instance *inst) {
- // No freeing of memory necessary for Linux, but we should at least touch
- // the val and inst pointers to get rid of compiler warnings.
- (void)val;
- (void)inst;
-}
-
-#elif defined(WIN32)
-
-bool is_high_integrity() {
- HANDLE process_token;
- if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
- // Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD.
- uint8_t mandatory_label_buffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)];
- DWORD buffer_size;
- if (GetTokenInformation(process_token, TokenIntegrityLevel, mandatory_label_buffer, sizeof(mandatory_label_buffer),
- &buffer_size) != 0) {
- const TOKEN_MANDATORY_LABEL *mandatory_label = (const TOKEN_MANDATORY_LABEL *)mandatory_label_buffer;
- const DWORD sub_authority_count = *GetSidSubAuthorityCount(mandatory_label->Label.Sid);
- const DWORD integrity_level = *GetSidSubAuthority(mandatory_label->Label.Sid, sub_authority_count - 1);
-
- CloseHandle(process_token);
- return integrity_level > SECURITY_MANDATORY_MEDIUM_RID;
- }
-
- CloseHandle(process_token);
- }
-
- return false;
-}
-
-char *loader_getenv(const char *name, const struct loader_instance *inst) {
- int name_utf16_size = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
- if (name_utf16_size <= 0) {
- return NULL;
- }
- wchar_t *name_utf16 = (wchar_t *)loader_stack_alloc(name_utf16_size * sizeof(wchar_t));
- if (MultiByteToWideChar(CP_UTF8, 0, name, -1, name_utf16, name_utf16_size) != name_utf16_size) {
- return NULL;
- }
-
- DWORD val_size = GetEnvironmentVariableW(name_utf16, NULL, 0);
- // val_size DOES include the null terminator, so for any set variable
- // will always be at least 1. If it's 0, the variable wasn't set.
- if (val_size == 0) {
- return NULL;
- }
-
- wchar_t *val = (wchar_t *)loader_stack_alloc(val_size * sizeof(wchar_t));
- if (GetEnvironmentVariableW(name_utf16, val, val_size) != val_size - 1) {
- return NULL;
- }
-
- int val_utf8_size = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
- if (val_utf8_size <= 0) {
- return NULL;
- }
- char *val_utf8 = (char *)loader_instance_heap_alloc(inst, val_utf8_size * sizeof(char), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
- if (val_utf8 == NULL) {
- return NULL;
- }
- if (WideCharToMultiByte(CP_UTF8, 0, val, -1, val_utf8, val_utf8_size, NULL, NULL) != val_utf8_size) {
- loader_instance_heap_free(inst, val_utf8);
- return NULL;
- }
- return val_utf8;
-}
-
-char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
-#if !defined(USE_UNSAFE_FILE_SEARCH)
- if (is_high_integrity()) {
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
- "Loader is running with elevated permissions. Environment variable %s will be ignored", name);
- return NULL;
- }
-#endif
-
- return loader_getenv(name, inst);
-}
-
-void loader_free_getenv(char *val, const struct loader_instance *inst) { loader_instance_heap_free(inst, (void *)val); }
-
-#else
-
-char *loader_getenv(const char *name, const struct loader_instance *inst) {
- // stub func
- (void)inst;
- (void)name;
- return NULL;
-}
-void loader_free_getenv(char *val, const struct loader_instance *inst) {
- // stub func
- (void)val;
- (void)inst;
-}
-
-#endif
diff --git a/loader/get_environment.h b/loader/get_environment.h
deleted file mode 100644
index 2b1663b..0000000
--- a/loader/get_environment.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *
- * Copyright (c) 2014-2021 The Khronos Group Inc.
- * Copyright (c) 2014-2021 Valve Corporation
- * Copyright (c) 2014-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.
- *
- * Author: Jon Ashburn <jon@lunarg.com>
- * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
- * Author: Chia-I Wu <olvaffe@gmail.com>
- * Author: Chia-I Wu <olv@lunarg.com>
- * Author: Mark Lobodzinski <mark@LunarG.com>
- * Author: Lenny Komow <lenny@lunarg.com>
- * Author: Charles Giessen <charles@lunarg.com>
- *
- */
-
-#pragma once
-
-#include "loader_common.h"
-
-// Common functionality for accessing environemnt variables and whether the process is running in priviledged mode
-
-char *loader_getenv(const char *name, const struct loader_instance *inst);
-void loader_free_getenv(char *val, const struct loader_instance *inst);
-
-#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-
-bool is_high_integrity();
-
-char *loader_secure_getenv(const char *name, const struct loader_instance *inst);
-
-#endif
diff --git a/loader/loader.c b/loader/loader.c
index b05fb56..b7d03ba 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -29,6 +29,7 @@
#include "loader.h"
#include <fcntl.h>
+#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@@ -42,9 +43,6 @@
#include <sys/param.h>
#endif
-// Time related functions
-#include <time.h>
-
#include <sys/types.h>
#if defined(_WIN32)
#include "dirent_on_windows.h"
@@ -55,7 +53,7 @@
#include "allocation.h"
#include "cJSON.h"
#include "debug_utils.h"
-#include "get_environment.h"
+#include "loader_environment.h"
#include "gpa_helper.h"
#include "log.h"
#include "unknown_function_handling.h"
@@ -93,6 +91,7 @@
loader_platform_thread_mutex loader_lock;
loader_platform_thread_mutex loader_json_lock;
loader_platform_thread_mutex loader_preload_icd_lock;
+loader_platform_thread_mutex loader_global_instance_list_lock;
// A list of ICDs that gets initialized when the loader does its global initialization. This list should never be used by anything
// other than EnumerateInstanceExtensionProperties(), vkDestroyInstance, and loader_release(). This list does not change
@@ -196,7 +195,7 @@
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
- if (NULL == icd_term) {
+ if (NULL == icd_term || NULL == dev) {
return VK_ERROR_INITIALIZATION_FAILED;
}
loader_set_dispatch(object, &dev->loader_dispatch);
@@ -543,6 +542,15 @@
goto out;
}
+ // Make sure we never call ourself by accident, this should never happen outside of error paths
+ if (fp_get_props == vkEnumerateInstanceExtensionProperties) {
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ "loader_add_instance_extensions: %s's vkEnumerateInstanceExtensionProperties points to the loader, this would "
+ "lead to infinite recursion.",
+ lib_name);
+ goto out;
+ }
+
res = fp_get_props(NULL, &count, NULL);
if (res != VK_SUCCESS) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
@@ -582,27 +590,6 @@
return res;
}
-// Initialize ext_list with the physical device extensions.
-// The extension properties are passed as inputs in count and ext_props.
-static VkResult loader_init_device_extensions(const struct loader_instance *inst, struct loader_physical_device_term *phys_dev_term,
- uint32_t count, VkExtensionProperties *ext_props,
- struct loader_extension_list *ext_list) {
- VkResult res;
- uint32_t i;
-
- res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
- if (VK_SUCCESS != res) {
- return res;
- }
-
- for (i = 0; i < count; i++) {
- res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
- if (res != VK_SUCCESS) return res;
- }
-
- return VK_SUCCESS;
-}
-
VkResult loader_add_device_extensions(const struct loader_instance *inst,
PFN_vkEnumerateDeviceExtensionProperties fpEnumerateDeviceExtensionProperties,
VkPhysicalDevice physical_device, const char *lib_name,
@@ -774,11 +761,6 @@
return VK_SUCCESS;
}
-// Prototypes needed.
-bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
- struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
- const struct loader_layer_list *source_list);
-
// Manage lists of VkLayerProperties
static bool loader_init_layer_list(const struct loader_instance *inst, struct loader_layer_list *list) {
list->capacity = 32 * sizeof(struct loader_layer_properties);
@@ -851,9 +833,35 @@
return VK_SUCCESS;
}
+// Determine if the provided explicit layer should be available by querying the appropriate environmental variables.
+bool loader_layer_is_available(const struct loader_instance *inst, const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ const struct loader_layer_properties *prop) {
+ bool available = true;
+ if (NULL != disable_filter) {
+ bool is_implicit = (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER));
+ bool disabled_by_type = (is_implicit) ? (disable_filter->disable_all_implicit) : (disable_filter->disable_all_explicit);
+ if (disable_filter->disable_all || disabled_by_type ||
+ check_name_matches_filter_environment_var(inst, prop->info.layerName, &disable_filter->additional_filters)) {
+ available = false;
+ }
+ }
+ if (NULL != enable_filter && check_name_matches_filter_environment_var(inst, prop->info.layerName, enable_filter)) {
+ available = true;
+ } else if (!available) {
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+ "Layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", prop->info.layerName,
+ VK_LAYERS_DISABLE_ENV_VAR);
+ }
+
+ return available;
+}
+
// Search the given search_list for any layers in the props list. Add these to the
// output layer_list.
-static VkResult loader_add_layer_names_to_list(const struct loader_instance *inst, struct loader_layer_list *output_list,
+static VkResult loader_add_layer_names_to_list(const struct loader_instance *inst, const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ struct loader_layer_list *output_list,
struct loader_layer_list *expanded_output_list, uint32_t name_count,
const char *const *names, const struct loader_layer_list *source_list) {
struct loader_layer_properties *layer_prop;
@@ -861,10 +869,11 @@
for (uint32_t i = 0; i < name_count; i++) {
const char *source_name = names[i];
+
layer_prop = loader_find_layer_property(source_name, source_list);
if (NULL == layer_prop) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_add_layer_names_to_list: Unable to find layer %s", source_name);
+ "loader_add_layer_names_to_list: Unable to find layer \"%s\"", source_name);
err = VK_ERROR_LAYER_NOT_PRESENT;
continue;
}
@@ -874,54 +883,76 @@
continue;
}
+ if (!loader_layer_is_available(inst, enable_filter, disable_filter, layer_prop)) {
+ continue;
+ }
+
// If not a meta-layer, simply add it.
if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
- loader_add_layer_properties_to_list(inst, output_list, 1, layer_prop);
- loader_add_layer_properties_to_list(inst, expanded_output_list, 1, layer_prop);
+ err = loader_add_layer_properties_to_list(inst, output_list, 1, layer_prop);
+ if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err;
+ err = loader_add_layer_properties_to_list(inst, expanded_output_list, 1, layer_prop);
+ if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err;
} else {
- loader_add_meta_layer(inst, layer_prop, output_list, expanded_output_list, source_list);
+ err = loader_add_meta_layer(inst, enable_filter, disable_filter, layer_prop, output_list, expanded_output_list,
+ source_list, NULL);
+ if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err;
}
}
return err;
}
-static bool check_expiration(const struct loader_instance *inst, const struct loader_layer_properties *prop) {
- time_t current = time(NULL);
- struct tm tm_current = *localtime(¤t);
-
- struct tm tm_expiration;
- tm_expiration.tm_sec = 0;
- tm_expiration.tm_min = prop->expiration.minute;
- tm_expiration.tm_hour = prop->expiration.hour;
- tm_expiration.tm_mday = prop->expiration.day;
- tm_expiration.tm_mon = prop->expiration.month - 1;
- tm_expiration.tm_year = prop->expiration.year - 1900;
- tm_expiration.tm_isdst = tm_current.tm_isdst;
- // wday and yday are ignored by mktime
- time_t expiration = mktime(&tm_expiration);
-
- return current < expiration;
-}
-
// Determine if the provided implicit layer should be enabled by querying the appropriate environmental variables.
// For an implicit layer, at least a disable environment variable is required.
-bool loader_implicit_layer_is_enabled(const struct loader_instance *inst, const struct loader_layer_properties *prop) {
+bool loader_implicit_layer_is_enabled(const struct loader_instance *inst, const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ const struct loader_layer_properties *prop) {
bool enable = false;
+ bool forced_disabled = false;
+ bool forced_enabled = false;
char *env_value = NULL;
+ if ((NULL != disable_filter &&
+ (disable_filter->disable_all || disable_filter->disable_all_implicit ||
+ check_name_matches_filter_environment_var(inst, prop->info.layerName, &disable_filter->additional_filters)))) {
+ forced_disabled = true;
+ }
+ if (NULL != enable_filter && check_name_matches_filter_environment_var(inst, prop->info.layerName, enable_filter)) {
+ forced_enabled = true;
+ }
+
// If no enable_environment variable is specified, this implicit layer is always be enabled by default.
if (prop->enable_env_var.name[0] == 0) {
enable = true;
} else {
- // Otherwise, only enable this layer if the enable environment variable is defined
env_value = loader_getenv(prop->enable_env_var.name, inst);
if (env_value && !strcmp(prop->enable_env_var.value, env_value)) {
enable = true;
}
+
+ // Otherwise, only enable this layer if the enable environment variable is defined
loader_free_getenv(env_value, inst);
}
+ if (forced_enabled) {
+ // Only report a message that we've forced on a layer if it wouldn't have been enabled
+ // normally.
+ if (!enable) {
+ enable = true;
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+ "Implicit layer \"%s\" forced enabled due to env var \'%s\'.", prop->info.layerName,
+ VK_LAYERS_ENABLE_ENV_VAR);
+ }
+ } else if (enable && forced_disabled) {
+ enable = false;
+ // Report a message that we've forced off a layer if it would have been enabled normally.
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+ "Implicit layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", prop->info.layerName,
+ VK_LAYERS_DISABLE_ENV_VAR);
+ return false;
+ }
+
// The disable_environment has priority over everything else. If it is defined, the layer is always
// disabled.
env_value = loader_getenv(prop->disable_env_var.name, inst);
@@ -930,11 +961,6 @@
}
loader_free_getenv(env_value, inst);
- // If this layer has an expiration, check it to determine if this layer has expired.
- if (prop->has_expiration) {
- enable = check_expiration(inst, prop);
- }
-
// Enable this layer if it is included in the override layer
if (inst != NULL && inst->override_layer_present) {
struct loader_layer_properties *override = NULL;
@@ -959,26 +985,35 @@
// Check the individual implicit layer for the enable/disable environment variable settings. Only add it after
// every check has passed indicating it should be used.
-static void loader_add_implicit_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
- struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
- const struct loader_layer_list *source_list) {
- if (loader_implicit_layer_is_enabled(inst, prop)) {
+static VkResult loader_add_implicit_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
+ const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
+ const struct loader_layer_list *source_list) {
+ VkResult result = VK_SUCCESS;
+ if (loader_implicit_layer_is_enabled(inst, enable_filter, disable_filter, prop)) {
if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
- loader_add_layer_properties_to_list(inst, target_list, 1, prop);
+ result = loader_add_layer_properties_to_list(inst, target_list, 1, prop);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
if (NULL != expanded_target_list) {
- loader_add_layer_properties_to_list(inst, expanded_target_list, 1, prop);
+ result = loader_add_layer_properties_to_list(inst, expanded_target_list, 1, prop);
}
} else {
- loader_add_meta_layer(inst, prop, target_list, expanded_target_list, source_list);
+ result = loader_add_meta_layer(inst, enable_filter, disable_filter, prop, target_list, expanded_target_list,
+ source_list, NULL);
}
}
+ return result;
}
// Add the component layers of a meta-layer to the active list of layers
-bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
- struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
- const struct loader_layer_list *source_list) {
- bool found = true;
+VkResult loader_add_meta_layer(const struct loader_instance *inst, const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ const struct loader_layer_properties *prop, struct loader_layer_list *target_list,
+ struct loader_layer_list *expanded_target_list, const struct loader_layer_list *source_list,
+ bool *out_found_all_component_layers) {
+ VkResult result = VK_SUCCESS;
+ bool found_all_component_layers = true;
// We need to add all the individual component layers
loader_api_version meta_layer_api_version = loader_make_version(prop->info.specVersion);
@@ -989,77 +1024,57 @@
loader_api_version search_prop_version = loader_make_version(prop->info.specVersion);
if (!loader_check_version_meets_required(meta_layer_api_version, search_prop_version)) {
loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_add_meta_layer: Meta-layer API version %u.%u, component layer %s version %u.%u, may have "
+ "Meta-layer \"%s\" API version %u.%u, component layer \"%s\" version %u.%u, may have "
"incompatibilities (Policy #LLP_LAYER_8)!",
- meta_layer_api_version.major, meta_layer_api_version.minor, search_prop->info.layerName,
- search_prop_version.major, search_prop_version.minor);
+ prop->info.layerName, meta_layer_api_version.major, meta_layer_api_version.minor,
+ search_prop->info.layerName, search_prop_version.major, search_prop_version.minor);
+ }
+
+ if (!loader_layer_is_available(inst, enable_filter, disable_filter, search_prop)) {
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+ "Meta Layer \"%s\" component layer \"%s\" disabled.", prop->info.layerName, search_prop->info.layerName);
+ continue;
}
// If the component layer is itself an implicit layer, we need to do the implicit layer enable
// checks
if (0 == (search_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
- loader_add_implicit_layer(inst, search_prop, target_list, expanded_target_list, source_list);
+ result = loader_add_implicit_layer(inst, search_prop, enable_filter, disable_filter, target_list,
+ expanded_target_list, source_list);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
} else {
if (0 != (search_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
- found = loader_add_meta_layer(inst, search_prop, target_list, expanded_target_list, source_list);
+ bool found_layers_in_component_meta_layer = true;
+ result = loader_add_meta_layer(inst, enable_filter, disable_filter, search_prop, target_list,
+ expanded_target_list, source_list, &found_layers_in_component_meta_layer);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
+ if (!found_layers_in_component_meta_layer) found_all_component_layers = false;
} else {
- loader_add_layer_properties_to_list(inst, target_list, 1, search_prop);
+ result = loader_add_layer_properties_to_list(inst, target_list, 1, search_prop);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
if (NULL != expanded_target_list) {
- loader_add_layer_properties_to_list(inst, expanded_target_list, 1, search_prop);
+ result = loader_add_layer_properties_to_list(inst, expanded_target_list, 1, search_prop);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
}
}
}
} else {
loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_add_meta_layer: Failed to find layer name %s component layer %s to activate (Policy #LLP_LAYER_7)",
+ "Failed to find layer name \"%s\" component layer \"%s\" to activate (Policy #LLP_LAYER_7)",
prop->component_layer_names[comp_layer], prop->component_layer_names[comp_layer]);
- found = false;
+ found_all_component_layers = false;
}
}
// Add this layer to the overall target list (not the expanded one)
- if (found) {
- loader_add_layer_properties_to_list(inst, target_list, 1, prop);
+ if (found_all_component_layers) {
+ result = loader_add_layer_properties_to_list(inst, target_list, 1, prop);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
+ // Write the result to out_found_all_component_layers in case this function is being recursed
+ if (out_found_all_component_layers) *out_found_all_component_layers = found_all_component_layers;
}
- return found;
-}
-
-// Search the source_list for any layer with a name that matches the given name and a type
-// that matches the given type. Add all matching layers to the target_list.
-VkResult loader_add_layer_name_to_list(const struct loader_instance *inst, const char *name, const enum layer_type_flags type_flags,
- const struct loader_layer_list *source_list, struct loader_layer_list *target_list,
- struct loader_layer_list *expanded_target_list) {
- VkResult res = VK_SUCCESS;
- bool found = false;
- for (uint32_t i = 0; i < source_list->count; i++) {
- struct loader_layer_properties *source_prop = &source_list->list[i];
- if (0 == strcmp(source_prop->info.layerName, name) && (source_prop->type_flags & type_flags) == type_flags) {
- // If not a meta-layer, simply add it.
- if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
- if (VK_SUCCESS == loader_add_layer_properties_to_list(inst, target_list, 1, source_prop)) {
- found = true;
- }
- if (VK_SUCCESS == loader_add_layer_properties_to_list(inst, expanded_target_list, 1, source_prop)) {
- found = true;
- }
- } else {
- found = loader_add_meta_layer(inst, source_prop, target_list, expanded_target_list, source_list);
- }
- }
- }
- if (!found) {
- if (strcmp(name, "VK_LAYER_LUNARG_standard_validation")) {
- loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_add_layer_name_to_list: Failed to find layer name %s to activate", name);
- } else {
- res = VK_ERROR_LAYER_NOT_PRESENT;
- loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "Layer VK_LAYER_LUNARG_standard_validation has been changed to VK_LAYER_KHRONOS_validation. Please use the "
- "new version of the layer.");
- }
- }
- return res;
+ return result;
}
static VkExtensionProperties *get_extension_property(const char *name, const struct loader_extension_list *list) {
@@ -1102,8 +1117,6 @@
char *env_value;
bool filter_extensions = true;
- loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Build ICD instance extension list");
-
// Check if a user wants to disable the instance extension filtering behavior
env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
if (NULL != env_value && atoi(env_value) != 0) {
@@ -1166,6 +1179,7 @@
}
struct loader_icd_term *loader_get_icd_and_device(const void *device, struct loader_device **found_dev, uint32_t *icd_index) {
+ loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
*found_dev = NULL;
for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
uint32_t index = 0;
@@ -1179,11 +1193,13 @@
if (NULL != icd_index) {
*icd_index = index;
}
+ loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
return icd_term;
}
index++;
}
}
+ loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
return NULL;
}
@@ -1192,12 +1208,8 @@
if (pAllocator) {
dev->alloc_callbacks = *pAllocator;
}
- if (NULL != dev->expanded_activated_layer_list.list) {
- loader_deactivate_layers(inst, dev, &dev->expanded_activated_layer_list);
- }
- if (NULL != dev->app_activated_layer_list.list) {
- loader_destroy_layer_list(inst, dev, &dev->app_activated_layer_list);
- }
+ loader_destroy_layer_list(inst, dev, &dev->expanded_activated_layer_list);
+ loader_destroy_layer_list(inst, dev, &dev->app_activated_layer_list);
loader_device_heap_free(dev, dev);
}
@@ -1335,7 +1347,7 @@
static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
const char *filename, uint32_t api_version, enum loader_layer_library_status *lib_status) {
- loader_platform_dl_handle handle;
+ loader_platform_dl_handle handle = NULL;
PFN_vkCreateInstance fp_create_inst;
PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
PFN_vkGetInstanceProcAddr fp_get_proc_addr;
@@ -1348,6 +1360,15 @@
uint32_t interface_vers;
VkResult res = VK_SUCCESS;
+ // This shouldn't happen, but the check is necessary because dlopen returns a handle to the main program when
+ // filename is NULL
+ if (filename == NULL) {
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_scanned_icd_add: A NULL filename was used, skipping this ICD",
+ filename);
+ res = VK_ERROR_INCOMPATIBLE_DRIVER;
+ goto out;
+ }
+
// TODO implement smarter opening/closing of libraries. For now this
// function leaves libraries open and the scanned_icd_clear closes them
#if defined(__Fuchsia__)
@@ -1407,10 +1428,10 @@
}
fp_get_inst_ext_props = loader_platform_get_proc_address(handle, "vkEnumerateInstanceExtensionProperties");
if (NULL == fp_get_inst_ext_props) {
- loader_log(
- inst, VULKAN_LOADER_ERROR_BIT, 0,
- "loader_scanned_icd_add: Could not get \'vkEnumerateInstanceExtensionProperties\' via dlsym/loadlibrary for ICD %s",
- filename);
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ "loader_scanned_icd_add: Could not get \'vkEnumerateInstanceExtensionProperties\' via dlsym/loadlibrary "
+ "for ICD %s",
+ filename);
goto out;
}
} else {
@@ -1498,6 +1519,8 @@
loader_platform_thread_create_mutex(&loader_lock);
loader_platform_thread_create_mutex(&loader_json_lock);
loader_platform_thread_create_mutex(&loader_preload_icd_lock);
+ loader_platform_thread_create_mutex(&loader_global_instance_list_lock);
+
// initialize logging
loader_debug_init();
#if defined(_WIN32)
@@ -1527,6 +1550,7 @@
loader_platform_thread_delete_mutex(&loader_lock);
loader_platform_thread_delete_mutex(&loader_json_lock);
loader_platform_thread_delete_mutex(&loader_preload_icd_lock);
+ loader_platform_thread_delete_mutex(&loader_global_instance_list_lock);
}
// Preload the ICD libraries that are likely to be needed so we don't repeatedly load/unload them later
@@ -1798,7 +1822,8 @@
}
if (success) {
loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "Meta-layer %s all %d component layers appear to be valid.", prop->info.layerName, prop->num_component_layers);
+ "Meta-layer \"%s\" all %d component layers appear to be valid.", prop->info.layerName,
+ prop->num_component_layers);
// If layer logging is on, list the internals included in the meta-layer
if ((loader_get_debug_level() & VULKAN_LOADER_LAYER_BIT) != 0) {
@@ -1811,8 +1836,9 @@
}
// Verify that all meta-layers in a layer list are valid.
-static void verify_all_meta_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers,
- bool *override_layer_present) {
+static void verify_all_meta_layers(struct loader_instance *inst, const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ struct loader_layer_list *instance_layers, bool *override_layer_present) {
*override_layer_present = false;
for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
struct loader_layer_properties *prop = &instance_layers->list[i];
@@ -1826,7 +1852,7 @@
loader_remove_layer_in_list(inst, instance_layers, i);
i--;
- } else if (prop->is_override && loader_implicit_layer_is_enabled(inst, prop)) {
+ } else if (prop->is_override && loader_implicit_layer_is_enabled(inst, enable_filter, disable_filter, prop)) {
*override_layer_present = true;
}
}
@@ -1863,10 +1889,10 @@
if (!found_active_override_layer) {
found_active_override_layer = true;
} else {
- loader_log(
- inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "remove_all_non_valid_override_layers: Multiple override layers where the same path in app_keys "
- "was found. Using the first layer found");
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+ "remove_all_non_valid_override_layers: Multiple override layers where the same path in "
+ "app_keys "
+ "was found. Using the first layer found");
// Remove duplicate active override layers that have the same app_key_path
loader_remove_layer_in_list(inst, instance_layers, i);
@@ -2003,71 +2029,9 @@
goto out;
}
- // Expiration date for override layer. Field starte with JSON file 1.1.2 and
- // is completely optional. So, no check put in place.
+ // Check if this layer's name matches the override layer name, set is_override to true if so.
if (!strcmp(name, VK_OVERRIDE_LAYER_NAME)) {
- cJSON *expiration;
- if (!loader_check_version_meets_required(loader_combine_version(1, 1, 2), version)) {
- loader_log(
- inst, VULKAN_LOADER_WARN_BIT, 0,
- "Override layer expiration date not added until version 1.1.2. Please update JSON file version appropriately.");
- }
-
props->is_override = true;
- expiration = cJSON_GetObjectItem(layer_node, "expiration_date");
- if (NULL != expiration) {
- char date_copy[32];
- uint8_t cur_item = 0;
-
- // Get the string for the current item
- temp = cJSON_Print(expiration);
- if (temp == NULL) {
- loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
- "Problem accessing layer value 'expiration_date' in manifest JSON file, skipping this layer");
- result = VK_ERROR_OUT_OF_HOST_MEMORY;
- goto out;
- }
- temp[strlen(temp) - 1] = '\0';
- strcpy(date_copy, &temp[1]);
- loader_instance_heap_free(inst, temp);
-
- if (strlen(date_copy) == 16) {
- char *cur_start = &date_copy[0];
- char *next_dash = strchr(date_copy, '-');
- if (NULL != next_dash) {
- while (cur_item < 5 && strlen(cur_start)) {
- if (next_dash != NULL) {
- *next_dash = '\0';
- }
- switch (cur_item) {
- case 0: // Year
- props->expiration.year = (uint16_t)atoi(cur_start);
- break;
- case 1: // Month
- props->expiration.month = (uint8_t)atoi(cur_start);
- break;
- case 2: // Day
- props->expiration.day = (uint8_t)atoi(cur_start);
- break;
- case 3: // Hour
- props->expiration.hour = (uint8_t)atoi(cur_start);
- break;
- case 4: // Minute
- props->expiration.minute = (uint8_t)atoi(cur_start);
- props->has_expiration = true;
- break;
- default: // Ignore
- break;
- }
- if (next_dash != NULL) {
- cur_start = next_dash + 1;
- next_dash = strchr(cur_start, '-');
- }
- cur_item++;
- }
- }
- }
- }
}
// Library path no longer required unless component_layers is also not defined
@@ -2144,14 +2108,14 @@
// This is now, officially, a meta-layer
props->type_flags |= VK_LAYER_TYPE_FLAG_META_LAYER;
- loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Encountered meta-layer %s", name);
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Encountered meta-layer \"%s\"", name);
// Make sure we set up other things so we head down the correct branches below
library_path_str = NULL;
} else {
- loader_log(
- inst, VULKAN_LOADER_WARN_BIT, 0,
- "Layer missing both library_path and component_layers fields. One or the other MUST be defined. Skipping this layer");
+ loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
+ "Layer missing both library_path and component_layers fields. One or the other MUST be defined. Skipping "
+ "this layer");
goto out;
}
@@ -2161,7 +2125,7 @@
if (blacklisted_layers != NULL) {
if (strcmp(name, VK_OVERRIDE_LAYER_NAME)) {
loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
- "Layer %s contains a blacklist, but a blacklist can only be provided by the override metalayer. This "
+ "Layer \"%s\" contains a blacklist, but a blacklist can only be provided by the override metalayer. This "
"blacklist will be ignored.",
name);
} else {
@@ -2262,7 +2226,7 @@
// Make sure the layer's manifest doesn't contain a non zero variant value
if (VK_API_VERSION_VARIANT(props->info.specVersion) != 0) {
loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "Layer %s has an \'api_version\' field which contains a non-zero variant value of %d. "
+ "Layer \"%s\" has an \'api_version\' field which contains a non-zero variant value of %d. "
" Skipping Layer.",
props->info.layerName, VK_API_VERSION_VARIANT(props->info.specVersion));
goto out;
@@ -2593,6 +2557,7 @@
}
file_vers = cJSON_PrintUnformatted(item);
if (NULL == file_vers) {
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
}
loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Found manifest file %s (file version %s)", filename, file_vers);
@@ -3204,7 +3169,7 @@
log_flags = VULKAN_LOADER_LAYER_BIT;
loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "Searching for layer manifest files");
}
- loader_log(inst, log_flags, 0, " In following folders:");
+ loader_log(inst, log_flags, 0, " In following locations:");
char *cur_file;
char *next_file = tmp_search_path;
while (NULL != next_file && *next_file != '\0') {
@@ -3354,6 +3319,8 @@
uint32_t version;
};
+// Takes a json file, opens, reads, and parses an ICD Manifest out of it.
+// Should only return VK_SUCCESS, VK_ERROR_INCOMPATIBLE_DRIVER, or VK_ERROR_OUT_OF_HOST_MEMORY
VkResult loader_parse_icd_manifest(const struct loader_instance *inst, int dir_fd, char *file_str, struct ICDManifestInfo *icd,
bool *skipped_portability_drivers) {
VkResult res = VK_SUCCESS;
@@ -3370,7 +3337,11 @@
}
res = loader_get_json(inst, dir_fd, file_str, &json);
+ if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
+ goto out;
+ }
if (res != VK_SUCCESS || NULL == json) {
+ res = VK_ERROR_INCOMPATIBLE_DRIVER;
goto out;
}
@@ -3442,7 +3413,7 @@
}
// Print out the paths being searched if debugging is enabled
- loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Searching for ICD drivers named %s", library_path);
+ loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "Searching for ICD drivers named %s", library_path);
if (loader_platform_is_path(library_path)) {
// a relative or absolute path
char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
@@ -3510,6 +3481,9 @@
res = VK_ERROR_INCOMPATIBLE_DRIVER;
goto out;
}
+ } else {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
}
}
out:
@@ -3540,9 +3514,23 @@
struct loader_data_files manifest_files;
VkResult res = VK_SUCCESS;
bool lockedMutex = false;
+ struct loader_envvar_filter select_filter;
+ struct loader_envvar_filter disable_filter;
+ // Before we begin anything, init manifest_files to avoid a delete of garbage memory if
+ // a failure occurs before allocating the manifest filename_list.
memset(&manifest_files, 0, sizeof(struct loader_data_files));
+ // Parse the filter environment variables to determine if we have any special behavior
+ res = parse_generic_filter_environment_var(inst, VK_DRIVERS_SELECT_ENV_VAR, &select_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+ res = parse_generic_filter_environment_var(inst, VK_DRIVERS_DISABLE_ENV_VAR, &disable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+
res = loader_scanned_icd_init(inst, icd_tramp_list);
if (VK_SUCCESS != res) {
goto out;
@@ -3572,6 +3560,36 @@
continue;
}
+ if (select_filter.count > 0 || disable_filter.count > 0) {
+ // Get only the filename for comparing to the filters
+ char *just_filename_str = strrchr(manifest_files.filename_list[i], DIRECTORY_SYMBOL);
+
+ // No directory symbol, just the filename
+ if (NULL == just_filename_str) {
+ just_filename_str = manifest_files.filename_list[i];
+ } else {
+ just_filename_str++;
+ }
+
+ bool name_matches_select =
+ (select_filter.count > 0 && check_name_matches_filter_environment_var(inst, just_filename_str, &select_filter));
+ bool name_matches_disable =
+ (disable_filter.count > 0 && check_name_matches_filter_environment_var(inst, just_filename_str, &disable_filter));
+
+ if (name_matches_disable && !name_matches_select) {
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ "Driver \"%s\" ignored because it was disabled by env var \'%s\'", just_filename_str,
+ VK_DRIVERS_DISABLE_ENV_VAR);
+ continue;
+ }
+ if (select_filter.count != 0 && !name_matches_select) {
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ "Driver \"%s\" ignored because not selected by env var \'%s\'", just_filename_str,
+ VK_DRIVERS_SELECT_ENV_VAR);
+ continue;
+ }
+ }
+
enum loader_layer_library_status lib_status;
icd_res = loader_scanned_icd_add(inst, icd_tramp_list, icd.full_library_path, icd.version, &lib_status);
if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_res) {
@@ -3615,23 +3633,39 @@
return res;
}
-void loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers) {
+VkResult loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers) {
+ VkResult res = VK_SUCCESS;
char *file_str;
struct loader_data_files manifest_files;
- cJSON *json;
+ cJSON *json = NULL;
bool override_layer_valid = false;
char *override_paths = NULL;
uint32_t total_count = 0;
+ struct loader_envvar_filter enable_filter;
+ struct loader_envvar_disable_layers_filter disable_filter;
+ // Before we begin anything, init manifest_files to avoid a delete of garbage memory if
+ // a failure occurs before allocating the manifest filename_list.
memset(&manifest_files, 0, sizeof(struct loader_data_files));
+ // Parse the filter environment variables to determine if we have any special behavior
+ res = parse_generic_filter_environment_var(NULL, VK_LAYERS_ENABLE_ENV_VAR, &enable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+ res = parse_layers_disable_filter_environment_var(NULL, &disable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+
// Cleanup any previously scanned libraries
loader_delete_layer_list_and_properties(inst, instance_layers);
loader_platform_thread_lock_mutex(&loader_json_lock);
// Get a list of manifest files for any implicit layers
- if (VK_SUCCESS != loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, &manifest_files)) {
+ res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, &manifest_files);
+ if (VK_SUCCESS != res) {
goto out;
}
@@ -3644,18 +3678,20 @@
}
// Parse file into JSON struct
- VkResult res = loader_get_json(inst, -1, file_str, &json);
- if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
+ VkResult local_res = loader_get_json(inst, -1, file_str, &json);
+ if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
- } else if (VK_SUCCESS != res || NULL == json) {
+ } else if (VK_SUCCESS != local_res || NULL == json) {
continue;
}
- VkResult local_res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
+ local_res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
cJSON_Delete(json);
// If the error is anything other than out of memory we still want to try to load the other layers
if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
}
}
@@ -3667,7 +3703,8 @@
// Check to see if the override layer is present, and use it's override paths.
for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
struct loader_layer_properties *prop = &instance_layers->list[i];
- if (prop->is_override && loader_implicit_layer_is_enabled(inst, prop) && prop->num_override_paths > 0) {
+ if (prop->is_override && loader_implicit_layer_is_enabled(inst, &enable_filter, &disable_filter, prop) &&
+ prop->num_override_paths > 0) {
char *cur_write_ptr = NULL;
size_t override_path_size = 0;
for (uint32_t j = 0; j < prop->num_override_paths; j++) {
@@ -3675,6 +3712,7 @@
}
override_paths = loader_instance_heap_alloc(inst, override_path_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
if (override_paths == NULL) {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
}
cur_write_ptr = &override_paths[0];
@@ -3685,13 +3723,14 @@
--cur_write_ptr;
assert(cur_write_ptr - override_paths < (ptrdiff_t)override_path_size);
*cur_write_ptr = '\0';
- loader_log(NULL, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_scan_for_layers: Override layer has override paths set to %s", override_paths);
+ loader_log(NULL, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Override layer has override paths set to %s",
+ override_paths);
}
}
// Get a list of manifest files for explicit layers
- if (VK_SUCCESS != loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER, override_paths, &manifest_files)) {
+ res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER, override_paths, &manifest_files);
+ if (VK_SUCCESS != res) {
goto out;
}
@@ -3706,18 +3745,20 @@
}
// Parse file into JSON struct
- VkResult res = loader_get_json(inst, -1, file_str, &json);
- if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
+ VkResult local_res = loader_get_json(inst, -1, file_str, &json);
+ if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
- } else if (VK_SUCCESS != res || NULL == json) {
+ } else if (VK_SUCCESS != local_res || NULL == json) {
continue;
}
- VkResult local_res = loader_add_layer_properties(inst, instance_layers, json, false, file_str);
+ local_res = loader_add_layer_properties(inst, instance_layers, json, false, file_str);
cJSON_Delete(json);
// If the error is anything other than out of memory we still want to try to load the other layers
if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
+ res = local_res;
goto out;
}
}
@@ -3725,7 +3766,7 @@
// Verify any meta-layers in the list are valid and all the component layers are
// actually present in the available layer list
- verify_all_meta_layers(inst, instance_layers, &override_layer_valid);
+ verify_all_meta_layers(inst, &enable_filter, &disable_filter, instance_layers, &override_layer_valid);
if (override_layer_valid) {
loader_remove_layers_in_blacklist(inst, instance_layers);
@@ -3734,6 +3775,14 @@
}
}
+ // Remove disabled layers
+ for (uint32_t i = 0; i < instance_layers->count; ++i) {
+ if (!loader_layer_is_available(inst, &enable_filter, &disable_filter, &instance_layers->list[i])) {
+ loader_remove_layer_in_list(inst, instance_layers, i);
+ i--;
+ }
+ }
+
out:
loader_instance_heap_free(inst, override_paths);
@@ -3744,22 +3793,37 @@
loader_instance_heap_free(inst, manifest_files.filename_list);
}
loader_platform_thread_unlock_mutex(&loader_json_lock);
+ return res;
}
-void loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers) {
+VkResult loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers,
+ loader_platform_dl_handle **libs) {
+ struct loader_envvar_filter enable_filter;
+ struct loader_envvar_disable_layers_filter disable_filter;
char *file_str;
struct loader_data_files manifest_files;
- cJSON *json;
+ cJSON *json = NULL;
bool override_layer_valid = false;
char *override_paths = NULL;
bool implicit_metalayer_present = false;
bool have_json_lock = false;
+ VkResult res = VK_SUCCESS;
// Before we begin anything, init manifest_files to avoid a delete of garbage memory if
// a failure occurs before allocating the manifest filename_list.
memset(&manifest_files, 0, sizeof(struct loader_data_files));
- VkResult res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, &manifest_files);
+ // Parse the filter environment variables to determine if we have any special behavior
+ res = parse_generic_filter_environment_var(inst, VK_LAYERS_ENABLE_ENV_VAR, &enable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+ res = parse_layers_disable_filter_environment_var(inst, &disable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+
+ res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, &manifest_files);
if (VK_SUCCESS != res || manifest_files.count == 0) {
goto out;
}
@@ -3777,20 +3841,22 @@
}
// parse file into JSON struct
- res = loader_get_json(inst, -1, file_str, &json);
- if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
+ VkResult temp_res = loader_get_json(inst, -1, file_str, &json);
+ if (VK_ERROR_OUT_OF_HOST_MEMORY == temp_res) {
+ res = temp_res;
goto out;
- } else if (VK_SUCCESS != res || NULL == json) {
+ } else if (VK_SUCCESS != temp_res || NULL == json) {
continue;
}
- res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
+ temp_res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
loader_instance_heap_free(inst, file_str);
manifest_files.filename_list[i] = NULL;
cJSON_Delete(json);
- if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
+ if (VK_ERROR_OUT_OF_HOST_MEMORY == temp_res) {
+ res = temp_res;
goto out;
}
}
@@ -3802,7 +3868,7 @@
// Each of these may require explicit layers to be enabled at this time.
for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
struct loader_layer_properties *prop = &instance_layers->list[i];
- if (prop->is_override && loader_implicit_layer_is_enabled(inst, prop)) {
+ if (prop->is_override && loader_implicit_layer_is_enabled(inst, &enable_filter, &disable_filter, prop)) {
override_layer_valid = true;
if (prop->num_override_paths > 0) {
char *cur_write_ptr = NULL;
@@ -3822,8 +3888,8 @@
--cur_write_ptr;
assert(cur_write_ptr - override_paths < (ptrdiff_t)override_path_size);
*cur_write_ptr = '\0';
- loader_log(NULL, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_scan_for_implicit_layers: Override layer has override paths set to %s", override_paths);
+ loader_log(NULL, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Override layer has override paths set to %s",
+ override_paths);
}
} else if (!prop->is_override && prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
implicit_metalayer_present = true;
@@ -3852,13 +3918,13 @@
continue;
}
- res = loader_add_layer_properties(inst, instance_layers, json, false, file_str);
-
+ VkResult temp_res = loader_add_layer_properties(inst, instance_layers, json, false, file_str);
loader_instance_heap_free(inst, file_str);
manifest_files.filename_list[i] = NULL;
cJSON_Delete(json);
- if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
+ if (VK_ERROR_OUT_OF_HOST_MEMORY == temp_res) {
+ res = temp_res;
goto out;
}
}
@@ -3866,7 +3932,7 @@
// Verify any meta-layers in the list are valid and all the component layers are
// actually present in the available layer list
- verify_all_meta_layers(inst, instance_layers, &override_layer_valid);
+ verify_all_meta_layers(inst, &enable_filter, &disable_filter, instance_layers, &override_layer_valid);
if (override_layer_valid || implicit_metalayer_present) {
loader_remove_layers_not_in_implicit_meta_layers(inst, instance_layers);
@@ -3875,6 +3941,23 @@
}
}
+ // Remove disabled layers
+ for (uint32_t i = 0; i < instance_layers->count; ++i) {
+ if (!loader_implicit_layer_is_enabled(inst, &enable_filter, &disable_filter, &instance_layers->list[i])) {
+ loader_remove_layer_in_list(inst, instance_layers, i);
+ i--;
+ }
+ }
+
+ // We'll need to save the dl handles so we can close them later
+ if (instance_layers->count > 0 && NULL != libs) {
+ *libs = loader_calloc(NULL, sizeof(loader_platform_dl_handle) * instance_layers->count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (*libs == NULL) {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ }
+
out:
loader_instance_heap_free(inst, override_paths);
@@ -3886,6 +3969,8 @@
if (have_json_lock) {
loader_platform_thread_unlock_mutex(&loader_json_lock);
}
+
+ return res;
}
static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) {
@@ -3928,6 +4013,8 @@
}
// The VK_EXT_debug_utils functions need a special case here so the terminators can still be found from vkGetInstanceProcAddr
+ // This is because VK_EXT_debug_utils is an instance level extension with device level functions, and is 'supported' by the
+ // loader. There needs to be a terminator in case a driver doesn't support VK_EXT_debug_utils.
if (!strcmp(pName, "vkSetDebugUtilsObjectNameEXT")) {
return (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectNameEXT;
}
@@ -4003,9 +4090,15 @@
// object before passing the appropriate info along to the ICD.
// This is why we also have to override the direct ICD call to
// vkGetDeviceProcAddr to intercept those calls.
- PFN_vkVoidFunction addr = get_extension_device_proc_terminator(dev, pName);
- if (NULL != addr) {
- return addr;
+ // If the pName is for a 'known' function but isn't available, due to
+ // the corresponding extension/feature not being enabled, we need to
+ // return NULL and not call down to the driver's GetDeviceProcAddr.
+ if (NULL != dev) {
+ bool found_name = false;
+ PFN_vkVoidFunction addr = get_extension_device_proc_terminator(dev, pName, &found_name);
+ if (found_name) {
+ return addr;
+ }
}
return icd_term->dispatch.GetDeviceProcAddr(device, pName);
@@ -4021,18 +4114,19 @@
return NULL;
} else {
disp = loader_get_instance_layer_dispatch(instance);
+ loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
if (&inst->disp->layer_inst_disp == disp) {
ptr_instance = inst;
break;
}
}
+ loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
}
return ptr_instance;
}
-static loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, const char *chain_type,
- struct loader_layer_properties *prop) {
+static loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop) {
if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) == NULL) {
loader_handle_load_library_error(inst, prop->lib_name, &prop->lib_status);
} else {
@@ -4064,86 +4158,72 @@
// Go through the search_list and find any layers which match type. If layer
// type match is found in then add it to ext_list.
-static void loader_add_implicit_layers(const struct loader_instance *inst, struct loader_layer_list *target_list,
- struct loader_layer_list *expanded_target_list,
- const struct loader_layer_list *source_list) {
+static VkResult loader_add_implicit_layers(const struct loader_instance *inst, const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
+ const struct loader_layer_list *source_list) {
for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) {
const struct loader_layer_properties *prop = &source_list->list[src_layer];
if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
- loader_add_implicit_layer(inst, prop, target_list, expanded_target_list, source_list);
+ VkResult result = loader_add_implicit_layer(inst, prop, enable_filter, disable_filter, target_list,
+ expanded_target_list, source_list);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
}
}
-}
-
-// Get the layer name(s) from the env_name environment variable. If layer is found in
-// search_list then add it to layer_list. But only add it to layer_list if type_flags matches.
-static VkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags,
- const char *env_name, struct loader_layer_list *target_list,
- struct loader_layer_list *expanded_target_list,
- const struct loader_layer_list *source_list) {
- VkResult res = VK_SUCCESS;
- char *next, *name;
- char *layer_env = loader_getenv(env_name, inst);
- if (layer_env == NULL) {
- goto out;
- }
- name = loader_stack_alloc(strlen(layer_env) + 1);
- if (name == NULL) {
- goto out;
- }
- strcpy(name, layer_env);
-
- loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_add_environment_layers: Env Var %s defined and adding layers %s", env_name, name);
-
- while (name && *name) {
- next = loader_get_next_path(name);
- res = loader_add_layer_name_to_list(inst, name, type_flags, source_list, target_list, expanded_target_list);
- if (res != VK_SUCCESS) {
- goto out;
- }
- name = next;
- }
-
-out:
-
- if (layer_env != NULL) {
- loader_free_getenv(layer_env, inst);
- }
-
- return res;
+ return VK_SUCCESS;
}
VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo,
const struct loader_layer_list *instance_layers) {
+ VkResult res = VK_SUCCESS;
+ struct loader_envvar_filter layers_enable_filter;
+ struct loader_envvar_disable_layers_filter layers_disable_filter;
+
assert(inst && "Cannot have null instance");
if (!loader_init_layer_list(inst, &inst->app_activated_layer_list)) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
"loader_enable_instance_layers: Failed to initialize application version of the layer list");
- return VK_ERROR_OUT_OF_HOST_MEMORY;
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
}
if (!loader_init_layer_list(inst, &inst->expanded_activated_layer_list)) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
"loader_enable_instance_layers: Failed to initialize expanded version of the layer list");
- return VK_ERROR_OUT_OF_HOST_MEMORY;
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+
+ // Parse the filter environment variables to determine if we have any special behavior
+ res = parse_generic_filter_environment_var(inst, VK_LAYERS_ENABLE_ENV_VAR, &layers_enable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+ res = parse_layers_disable_filter_environment_var(inst, &layers_disable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
}
// Add any implicit layers first
- loader_add_implicit_layers(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, instance_layers);
+ res = loader_add_implicit_layers(inst, &layers_enable_filter, &layers_disable_filter, &inst->app_activated_layer_list,
+ &inst->expanded_activated_layer_list, instance_layers);
+ if (res != VK_SUCCESS) {
+ goto out;
+ }
// Add any layers specified via environment variable next
- VkResult err =
- loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, "VK_INSTANCE_LAYERS",
- &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, instance_layers);
- if (err != VK_SUCCESS) {
- return err;
+ res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, "VK_INSTANCE_LAYERS", &layers_enable_filter,
+ &layers_disable_filter, &inst->app_activated_layer_list,
+ &inst->expanded_activated_layer_list, instance_layers);
+ if (res != VK_SUCCESS) {
+ goto out;
}
// Add layers specified by the application
- err = loader_add_layer_names_to_list(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list,
- pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers);
+ res = loader_add_layer_names_to_list(inst, &layers_enable_filter, &layers_disable_filter, &inst->app_activated_layer_list,
+ &inst->expanded_activated_layer_list, pCreateInfo->enabledLayerCount,
+ pCreateInfo->ppEnabledLayerNames, instance_layers);
for (uint32_t i = 0; i < inst->expanded_activated_layer_list.count; i++) {
// Verify that the layer api version is at least that of the application's request, if not, throw a warning since
@@ -4158,8 +4238,8 @@
inst->app_api_version.minor);
}
}
-
- return err;
+out:
+ return res;
}
// Determine the layer interface version to use.
@@ -4356,9 +4436,11 @@
const struct loader_instance *inst = icd_term->this_instance;
destroyFunction(device, pAllocator);
- dev->chain_device = NULL;
- dev->icd_device = NULL;
- loader_remove_logical_device(inst, icd_term, dev, pAllocator);
+ if (NULL != dev) {
+ dev->chain_device = NULL;
+ dev->icd_device = NULL;
+ loader_remove_logical_device(inst, icd_term, dev, pAllocator);
+ }
}
// Given the list of layers to activate in the loader_instance
@@ -4425,7 +4507,7 @@
continue;
}
- lib_handle = loader_open_layer_file(inst, "instance", layer_prop);
+ lib_handle = loader_open_layer_file(inst, layer_prop);
if (!lib_handle) {
continue;
}
@@ -4481,7 +4563,7 @@
if (NULL == cur_gipa) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_create_instance_chain: Failed to find \'vkGetInstanceProcAddr\' in layer %s",
+ "loader_create_instance_chain: Failed to find \'vkGetInstanceProcAddr\' in layer \"%s\"",
layer_prop->lib_name);
continue;
}
@@ -4491,7 +4573,7 @@
if (NULL == cur_gipa) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_create_instance_chain: Failed to find \'%s\' in layer %s",
+ "loader_create_instance_chain: Failed to find \'%s\' in layer \"%s\"",
layer_prop->functions.str_gipa, layer_prop->lib_name);
continue;
}
@@ -4525,7 +4607,7 @@
activated_layers[num_activated_layers].disable_env = layer_prop->disable_env_var.name;
}
- loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Insert instance layer %s (%s)",
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Insert instance layer \"%s\" (%s)",
layer_prop->info.layerName, layer_prop->lib_name);
num_activated_layers++;
@@ -4562,15 +4644,17 @@
}
switch (exp_layer_prop->lib_status) {
case LOADER_LAYER_LIB_NOT_LOADED:
- loader_log(inst, log_flag, 0, "Requested layer %s was not loaded%c", exp_layer_prop->info.layerName, ending);
+ loader_log(inst, log_flag, 0, "Requested layer \"%s\" was not loaded%c", exp_layer_prop->info.layerName,
+ ending);
break;
case LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE: {
- loader_log(inst, log_flag, 0, "Requested layer %s was wrong bit-type%c", exp_layer_prop->info.layerName,
+ loader_log(inst, log_flag, 0, "Requested layer \"%s\" was wrong bit-type%c", exp_layer_prop->info.layerName,
ending);
break;
}
case LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD:
- loader_log(inst, log_flag, 0, "Requested layer %s failed to load%c", exp_layer_prop->info.layerName, ending);
+ loader_log(inst, log_flag, 0, "Requested layer \"%s\" failed to load%c", exp_layer_prop->info.layerName,
+ ending);
break;
case LOADER_LAYER_LIB_SUCCESS_LOADED:
// Shouldn't be able to reach this but if it is, best to report a debug
@@ -4658,10 +4742,17 @@
created_inst);
}
+#ifdef __APPLE__
VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
struct loader_device *dev, PFN_vkGetInstanceProcAddr callingLayer,
- PFN_vkGetDeviceProcAddr *layerNextGDPA) {
+ PFN_vkGetDeviceProcAddr *layerNextGDPA) __attribute__ ((optnone)) {
+#else
+ VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
+ struct loader_device *dev, PFN_vkGetInstanceProcAddr callingLayer,
+ PFN_vkGetDeviceProcAddr *layerNextGDPA) {
+#endif
uint32_t num_activated_layers = 0;
struct activated_layer_info *activated_layers = NULL;
VkLayerDeviceLink *layer_device_link_info;
@@ -4739,20 +4830,19 @@
chain_info.pNext = loader_create_info.pNext;
loader_create_info.pNext = &chain_info;
- bool done = false;
-
// Create instance chain of enabled layers
for (int32_t i = dev->expanded_activated_layer_list.count - 1; i >= 0; i--) {
struct loader_layer_properties *layer_prop = &dev->expanded_activated_layer_list.list[i];
- loader_platform_dl_handle lib_handle;
+ loader_platform_dl_handle lib_handle = layer_prop->lib_handle;
// Skip it if a Layer with the same name has been already successfully activated
if (loader_names_array_has_layer_property(&layer_prop->info, num_activated_layers, activated_layers)) {
continue;
}
- lib_handle = loader_open_layer_file(inst, "device", layer_prop);
- if (!lib_handle || done) {
+ // Skip the layer if the handle is NULL - this is likely because the library failed to load but wasn't removed from
+ // the list.
+ if (!lib_handle) {
continue;
}
@@ -4767,7 +4857,8 @@
(PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa);
if (!fpGIPA) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "loader_create_device_chain: Failed to find \'vkGetInstanceProcAddr\' in layer %s. Skipping layer.",
+ "loader_create_device_chain: Failed to find \'vkGetInstanceProcAddr\' in layer \"%s\". "
+ "Skipping layer.",
layer_prop->lib_name);
continue;
}
@@ -4777,8 +4868,9 @@
if (layerNextGDPA != NULL) {
*layerNextGDPA = nextGDPA;
}
- done = true;
- continue;
+ // Break here because if fpGIPA is the same as callingLayer, that means a layer is trying to create a device,
+ // and once we don't want to continue any further as the next layer will be the calling layer
+ break;
}
if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
@@ -4789,7 +4881,7 @@
fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa);
if (!fpGDPA) {
loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
- "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->lib_name);
+ "Failed to find vkGetDeviceProcAddr in layer \"%s\"", layer_prop->lib_name);
continue;
}
}
@@ -4809,7 +4901,7 @@
activated_layers[num_activated_layers].disable_env = layer_prop->disable_env_var.name;
}
- loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Inserted device layer %s (%s)",
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Inserted device layer \"%s\" (%s)",
layer_prop->info.layerName, layer_prop->lib_name);
num_activated_layers++;
@@ -4860,8 +4952,8 @@
}
dev->chain_device = created_device;
- // Because we changed the pNext chain to use our own VkDeviceGroupDeviceCreateInfoKHR, we need to fixup the chain to point
- // back at the original VkDeviceGroupDeviceCreateInfoKHR.
+ // Because we changed the pNext chain to use our own VkDeviceGroupDeviceCreateInfoKHR, we need to fixup the chain to
+ // point back at the original VkDeviceGroupDeviceCreateInfoKHR.
VkBaseOutStructure *pNext = (VkBaseOutStructure *)loader_create_info.pNext;
VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&loader_create_info;
while (NULL != pNext) {
@@ -4886,6 +4978,9 @@
// Initialize device dispatch table
loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device);
+ // Initialize the dispatch table to functions which need terminators
+ // These functions point directly to the driver, not the terminator functions
+ init_extension_device_proc_terminator_dispatch(dev);
return res;
}
@@ -4926,6 +5021,8 @@
char *env_value;
bool check_if_known = true;
VkResult res = VK_SUCCESS;
+ struct loader_envvar_filter layers_enable_filter;
+ struct loader_envvar_disable_layers_filter layers_disable_filter;
struct loader_layer_list active_layers;
struct loader_layer_list expanded_layers;
@@ -4947,16 +5044,30 @@
goto out;
}
+ // Parse the filter environment variables to determine if we have any special behavior
+ res = parse_generic_filter_environment_var(inst, VK_LAYERS_ENABLE_ENV_VAR, &layers_enable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+ res = parse_layers_disable_filter_environment_var(inst, &layers_disable_filter);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
+
// Build the lists of active layers (including metalayers) and expanded layers (with metalayers resolved to their
// components)
- loader_add_implicit_layers(inst, &active_layers, &expanded_layers, instance_layers);
- res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &active_layers,
- &expanded_layers, instance_layers);
+ res = loader_add_implicit_layers(inst, &layers_enable_filter, &layers_disable_filter, &active_layers, &expanded_layers,
+ instance_layers);
if (res != VK_SUCCESS) {
goto out;
}
- res = loader_add_layer_names_to_list(inst, &active_layers, &expanded_layers, pCreateInfo->enabledLayerCount,
- pCreateInfo->ppEnabledLayerNames, instance_layers);
+ res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &layers_enable_filter,
+ &layers_disable_filter, &active_layers, &expanded_layers, instance_layers);
+ if (res != VK_SUCCESS) {
+ goto out;
+ }
+ res = loader_add_layer_names_to_list(inst, &layers_enable_filter, &layers_disable_filter, &active_layers, &expanded_layers,
+ pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers);
if (VK_SUCCESS != res) {
goto out;
}
@@ -5108,6 +5219,16 @@
ptr_instance->magic);
}
+ // Save the application version if it has been modified - layers sometimes needs features in newer API versions than
+ // what the application requested, and thus will increase the instance version to a level that suites their needs.
+ if (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->apiVersion) {
+ loader_api_version altered_version = loader_make_version(pCreateInfo->pApplicationInfo->apiVersion);
+ if (altered_version.major != ptr_instance->app_api_version.major ||
+ altered_version.minor != ptr_instance->app_api_version.minor) {
+ ptr_instance->app_api_version = altered_version;
+ }
+ }
+
memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
icd_create_info.enabledLayerCount = 0;
@@ -5159,7 +5280,6 @@
icd_create_info.enabledExtensionCount = 0;
struct loader_extension_list icd_exts;
- loader_log(ptr_instance, VULKAN_LOADER_DEBUG_BIT, 0, "Build ICD instance extension list");
// traverse scanned icd list adding non-duplicate extensions to the list
res = loader_init_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
@@ -5401,6 +5521,7 @@
// Remove this instance from the list of instances:
struct loader_instance *prev = NULL;
+ loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
struct loader_instance *next = loader.instances;
while (next != NULL) {
if (next == ptr_instance) {
@@ -5414,6 +5535,7 @@
prev = next;
next = next->next;
}
+ loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
while (NULL != icd_terms) {
if (icd_terms->instance) {
@@ -5889,36 +6011,59 @@
}
#endif // LOADER_ENABLE_LINUX_SORT
-// Check if this physical device is already in the old buffer
-void check_if_phys_dev_already_present(struct loader_instance *inst, VkPhysicalDevice physical_device, uint32_t idx,
- struct loader_physical_device_term **new_phys_devs) {
- if (NULL != inst->phys_devs_term) {
- for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
- if (physical_device == inst->phys_devs_term[old_idx]->phys_dev) {
- new_phys_devs[idx] = inst->phys_devs_term[old_idx];
- break;
- }
+// Look for physical_device in the provided phys_devs list, return true if found and put the index into out_idx, otherwise return
+// false
+bool find_phys_dev(VkPhysicalDevice physical_device, uint32_t phys_devs_count, struct loader_physical_device_term **phys_devs,
+ uint32_t *out_idx) {
+ if (NULL == phys_devs) return false;
+ for (uint32_t idx = 0; idx < phys_devs_count; idx++) {
+ if (NULL != phys_devs[idx] && physical_device == phys_devs[idx]->phys_dev) {
+ *out_idx = idx;
+ return true;
}
}
+ return false;
}
-VkResult allocate_new_phys_dev_at_idx(struct loader_instance *inst, VkPhysicalDevice physical_device,
- struct loader_phys_dev_per_icd *dev_array, uint32_t idx,
- struct loader_physical_device_term **new_phys_devs) {
- if (NULL == new_phys_devs[idx]) {
- new_phys_devs[idx] =
- loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
- if (NULL == new_phys_devs[idx]) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
- "allocate_new_phys_dev_at_idx: Failed to allocate physical device terminator object %d", idx);
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
-
- loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
- new_phys_devs[idx]->this_icd_term = dev_array->icd_term;
- new_phys_devs[idx]->icd_index = (uint8_t)(dev_array->icd_index);
- new_phys_devs[idx]->phys_dev = physical_device;
+// Add physical_device to new_phys_devs
+VkResult check_and_add_to_new_phys_devs(struct loader_instance *inst, VkPhysicalDevice physical_device,
+ struct loader_phys_dev_per_icd *dev_array, uint32_t *cur_new_phys_dev_count,
+ struct loader_physical_device_term **new_phys_devs) {
+ uint32_t out_idx = 0;
+ uint32_t idx = *cur_new_phys_dev_count;
+ // Check if the physical_device already exists in the new_phys_devs buffer, that means it was found from both
+ // EnumerateAdapterPhysicalDevices and EnumeratePhysicalDevices and we need to skip it.
+ if (find_phys_dev(physical_device, idx, new_phys_devs, &out_idx)) {
+ return VK_SUCCESS;
}
+ // Check if it was found in a previous call to vkEnumeratePhysicalDevices, we can just copy over the old data.
+ if (find_phys_dev(physical_device, inst->phys_dev_count_term, inst->phys_devs_term, &out_idx)) {
+ new_phys_devs[idx] = inst->phys_devs_term[out_idx];
+ (*cur_new_phys_dev_count)++;
+ return VK_SUCCESS;
+ }
+
+ // Exit in case something is already present - this shouldn't happen but better to be safe than overwrite existing data since
+ // this code has been refactored a half dozen times.
+ if (NULL != new_phys_devs[idx]) {
+ return VK_SUCCESS;
+ }
+ // If this physical device is new, we need to allocate space for it.
+ new_phys_devs[idx] =
+ loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL == new_phys_devs[idx]) {
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ "check_and_add_to_new_phys_devs: Failed to allocate physical device terminator object %d", idx);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
+ new_phys_devs[idx]->this_icd_term = dev_array->icd_term;
+ new_phys_devs[idx]->icd_index = (uint8_t)(dev_array->icd_index);
+ new_phys_devs[idx]->phys_dev = physical_device;
+
+ // Increment the count of new physical devices
+ (*cur_new_phys_dev_count)++;
return VK_SUCCESS;
}
@@ -5941,6 +6086,7 @@
struct loader_phys_dev_per_icd *windows_sorted_devices_array = NULL;
uint32_t icd_count = 0;
struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
+ uint32_t new_phys_devs_capacity = 0;
uint32_t new_phys_devs_count = 0;
struct loader_physical_device_term **new_phys_devs = NULL;
@@ -5969,16 +6115,6 @@
// internal value for those physical devices.
icd_term = inst->icd_terms;
while (NULL != icd_term) {
- // This is the legacy behavior which should be skipped if EnumerateAdapterPhysicalDevices is available
- // and we successfully enumerated sorted adapters using windows_read_sorted_physical_devices.
-#if defined(VK_USE_PLATFORM_WIN32_KHR)
- if (icd_term->scanned_icd->EnumerateAdapterPhysicalDevices != NULL) {
- icd_term = icd_term->next;
- ++icd_idx;
- continue;
- }
-#endif
-
res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].device_count, NULL);
if (VK_SUCCESS != res) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
@@ -6010,52 +6146,47 @@
// Add up both the windows sorted and non windows found physical device counts
for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) {
- new_phys_devs_count += windows_sorted_devices_array[i].device_count;
+ new_phys_devs_capacity += windows_sorted_devices_array[i].device_count;
}
for (uint32_t i = 0; i < icd_count; ++i) {
- new_phys_devs_count += icd_phys_dev_array[i].device_count;
+ new_phys_devs_capacity += icd_phys_dev_array[i].device_count;
}
// Bail out if there are no physical devices reported
- if (0 == new_phys_devs_count) {
+ if (0 == new_phys_devs_capacity) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
"setup_loader_term_phys_devs: Failed to detect any valid GPUs in the current config");
res = VK_ERROR_INITIALIZATION_FAILED;
goto out;
}
- // Create an allocation large enough to hold both the windows sorting enumeration and non-windows physical device enumeration
- new_phys_devs = loader_instance_heap_calloc(inst, sizeof(struct loader_physical_device_term *) * new_phys_devs_count,
+ // Create an allocation large enough to hold both the windows sorting enumeration and non-windows physical device
+ // enumeration
+ new_phys_devs = loader_instance_heap_calloc(inst, sizeof(struct loader_physical_device_term *) * new_phys_devs_capacity,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == new_phys_devs) {
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
- "setup_loader_term_phys_devs: Failed to allocate new physical device array of size %d", new_phys_devs_count);
+ "setup_loader_term_phys_devs: Failed to allocate new physical device array of size %d", new_phys_devs_capacity);
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
}
- // Current index into the new_phys_devs array - increment whenever we've written in.
- uint32_t idx = 0;
-
// Copy over everything found through sorted enumeration
for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) {
for (uint32_t j = 0; j < windows_sorted_devices_array[i].device_count; ++j) {
- check_if_phys_dev_already_present(inst, windows_sorted_devices_array[i].physical_devices[j], idx, new_phys_devs);
-
- res = allocate_new_phys_dev_at_idx(inst, windows_sorted_devices_array[i].physical_devices[j],
- &windows_sorted_devices_array[i], idx, new_phys_devs);
+ res = check_and_add_to_new_phys_devs(inst, windows_sorted_devices_array[i].physical_devices[j],
+ &windows_sorted_devices_array[i], &new_phys_devs_count, new_phys_devs);
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
goto out;
}
- // Increment the count of new physical devices
- idx++;
}
}
// Now go through the rest of the physical devices and add them to new_phys_devs
#ifdef LOADER_ENABLE_LINUX_SORT
+
if (is_linux_sort_enabled(inst)) {
- for (uint32_t dev = idx; dev < new_phys_devs_count; ++dev) {
+ for (uint32_t dev = new_phys_devs_count; dev < new_phys_devs_capacity; ++dev) {
new_phys_devs[dev] =
loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == new_phys_devs[dev]) {
@@ -6069,13 +6200,13 @@
// Get the physical devices supported by platform sorting mechanism into a separate list
// Pass in a sublist to the function so it only operates on the correct elements. This means passing in a pointer to the
// current next element in new_phys_devs and passing in a `count` of currently unwritten elements
- res =
- linux_read_sorted_physical_devices(inst, icd_count, icd_phys_dev_array, new_phys_devs_count - idx, &new_phys_devs[idx]);
+ res = linux_read_sorted_physical_devices(inst, icd_count, icd_phys_dev_array, new_phys_devs_capacity - new_phys_devs_count,
+ &new_phys_devs[new_phys_devs_count]);
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
goto out;
}
// Keep previously allocated physical device info since apps may already be using that!
- for (uint32_t new_idx = idx; new_idx < new_phys_devs_count; new_idx++) {
+ for (uint32_t new_idx = new_phys_devs_count; new_idx < new_phys_devs_capacity; new_idx++) {
for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
if (new_phys_devs[new_idx]->phys_dev == inst->phys_devs_term[old_idx]->phys_dev) {
loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
@@ -6087,6 +6218,8 @@
}
}
}
+ // now set the count to the capacity, as now the list is filled in
+ new_phys_devs_count = new_phys_devs_capacity;
// We want the following code to run if either linux sorting is disabled at compile time or runtime
} else {
#endif // LOADER_ENABLE_LINUX_SORT
@@ -6094,16 +6227,11 @@
// Copy over everything found through the non-sorted means.
for (uint32_t i = 0; i < icd_count; ++i) {
for (uint32_t j = 0; j < icd_phys_dev_array[i].device_count; ++j) {
- check_if_phys_dev_already_present(inst, icd_phys_dev_array[i].physical_devices[j], idx, new_phys_devs);
-
- // If this physical device isn't in the old buffer, then we need to create it.
- res = allocate_new_phys_dev_at_idx(inst, icd_phys_dev_array[i].physical_devices[j], &icd_phys_dev_array[i], idx,
- new_phys_devs);
+ res = check_and_add_to_new_phys_devs(inst, icd_phys_dev_array[i].physical_devices[j], &icd_phys_dev_array[i],
+ &new_phys_devs_count, new_phys_devs);
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
goto out;
}
- // Increment the count of new physical devices
- idx++;
}
}
#ifdef LOADER_ENABLE_LINUX_SORT
@@ -6114,7 +6242,10 @@
if (VK_SUCCESS != res) {
if (NULL != new_phys_devs) {
// We've encountered an error, so we should free the new buffers.
- for (uint32_t i = 0; i < new_phys_devs_count; i++) {
+ for (uint32_t i = 0; i < new_phys_devs_capacity; i++) {
+ // May not have allocated this far, skip it if we hadn't.
+ if (new_phys_devs[i] == NULL) continue;
+
// If an OOM occurred inside the copying of the new physical devices into the existing array
// will leave some of the old physical devices in the array which may have been copied into
// the new array, leading to them being freed twice. To avoid this we just make sure to not
@@ -6257,10 +6388,6 @@
VkExtensionProperties *pProperties) {
struct loader_physical_device_term *phys_dev_term;
- struct loader_layer_list implicit_layer_list = {0};
- struct loader_extension_list all_exts = {0};
- struct loader_extension_list icd_exts = {0};
-
// Any layer or trampoline wrapping should be removed at this point in time can just cast to the expected
// type for VkPhysicalDevice.
phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
@@ -6312,6 +6439,8 @@
struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
uint32_t icd_ext_count = *pPropertyCount;
VkExtensionProperties *icd_props_list = pProperties;
+ const struct loader_instance *inst = icd_term->this_instance;
+ struct loader_extension_list all_exts = {0};
VkResult res;
if (NULL == icd_props_list) {
@@ -6337,34 +6466,29 @@
goto out;
}
- if (!loader_init_layer_list(icd_term->this_instance, &implicit_layer_list)) {
- res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ // Init a list with enough capacity for the device extensions and the implicit layer device extensions
+ res = loader_init_generic_list(inst, (struct loader_generic_list *)&all_exts,
+ sizeof(VkExtensionProperties) * (icd_ext_count + 20));
+ if (VK_SUCCESS != res) {
goto out;
}
- loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL, &icd_term->this_instance->instance_layer_list);
-
- // Initialize dev_extension list within the physicalDevice object
- res = loader_init_device_extensions(icd_term->this_instance, phys_dev_term, icd_ext_count, icd_props_list, &icd_exts);
+ // Copy over the device extensions into all_exts & deduplicate
+ res = loader_add_to_ext_list(inst, &all_exts, icd_ext_count, icd_props_list);
if (res != VK_SUCCESS) {
goto out;
}
- // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
- // it depends on results of environment variables (which can change).
- res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, icd_exts.count, icd_exts.list);
- if (res != VK_SUCCESS) {
- goto out;
- }
-
- loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL, &icd_term->this_instance->instance_layer_list);
-
- for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
- for (uint32_t j = 0; j < implicit_layer_list.list[i].device_extension_list.count; j++) {
- res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1,
- &implicit_layer_list.list[i].device_extension_list.list[j].props);
- if (res != VK_SUCCESS) {
- goto out;
+ // Iterate over active layers, if they are an implicit layer, add their device extensions
+ for (uint32_t i = 0; i < icd_term->this_instance->expanded_activated_layer_list.count; i++) {
+ struct loader_layer_properties *layer_props = &icd_term->this_instance->expanded_activated_layer_list.list[i];
+ if (0 == (layer_props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
+ for (uint32_t j = 0; j < layer_props->device_extension_list.count; j++) {
+ res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1,
+ &layer_props->device_extension_list.list[j].props);
+ if (res != VK_SUCCESS) {
+ goto out;
+ }
}
}
}
@@ -6389,15 +6513,7 @@
out:
- if (NULL != implicit_layer_list.list) {
- loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&implicit_layer_list);
- }
- if (NULL != all_exts.list) {
- loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts);
- }
- if (NULL != icd_exts.list) {
- loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
- }
+ loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts);
if (NULL == pProperties && NULL != icd_props_list) {
loader_instance_heap_free(icd_term->this_instance, icd_props_list);
}
@@ -6475,7 +6591,10 @@
goto out;
}
- loader_scan_for_layers(NULL, &instance_layers);
+ res = loader_scan_for_layers(NULL, &instance_layers);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
for (uint32_t i = 0; i < instance_layers.count; i++) {
struct loader_layer_properties *props = &instance_layers.list[i];
if (strcmp(props->info.layerName, pLayerName) == 0) {
@@ -6501,11 +6620,11 @@
loader_scanned_icd_clear(NULL, &icd_tramp_list);
// Append enabled implicit layers.
- loader_scan_for_implicit_layers(NULL, &instance_layers);
+ res = loader_scan_for_implicit_layers(NULL, &instance_layers, NULL);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
for (uint32_t i = 0; i < instance_layers.count; i++) {
- if (!loader_implicit_layer_is_enabled(NULL, &instance_layers.list[i])) {
- continue;
- }
struct loader_extension_list *ext_list = &instance_layers.list[i].instance_extension_list;
loader_add_to_ext_list(NULL, &local_ext_list, ext_list->count, ext_list->list);
}
@@ -6553,7 +6672,10 @@
// Get layer libraries
memset(&instance_layer_list, 0, sizeof(instance_layer_list));
- loader_scan_for_layers(NULL, &instance_layer_list);
+ result = loader_scan_for_layers(NULL, &instance_layer_list);
+ if (VK_SUCCESS != result) {
+ goto out;
+ }
if (pProperties == NULL) {
*pPropertyCount = instance_layer_list.count;
@@ -6868,10 +6990,10 @@
new_phys_dev_groups[idx] = (VkPhysicalDeviceGroupPropertiesKHR *)loader_instance_heap_alloc(
inst, sizeof(VkPhysicalDeviceGroupPropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == new_phys_dev_groups[idx]) {
- loader_log(
- inst, VULKAN_LOADER_ERROR_BIT, 0,
- "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate physical device group Terminator object %d",
- idx);
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate physical device group Terminator "
+ "object %d",
+ idx);
total_count = idx;
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
@@ -6890,10 +7012,10 @@
if (NULL != new_phys_dev_groups) {
// We've encountered an error, so we should free the new buffers.
for (uint32_t i = 0; i < total_count; i++) {
- // If an OOM occurred inside the copying of the new physical device groups into the existing array will leave
- // some of the old physical device groups in the array which may have been copied into the new array, leading to
- // them being freed twice. To avoid this we just make sure to not delete physical device groups which were
- // copied.
+ // If an OOM occurred inside the copying of the new physical device groups into the existing array will
+ // leave some of the old physical device groups in the array which may have been copied into the new array,
+ // leading to them being freed twice. To avoid this we just make sure to not delete physical device groups
+ // which were copied.
bool found = false;
if (NULL != inst->phys_devs_term) {
for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
diff --git a/loader/loader.h b/loader/loader.h
index 0de007e..6296491 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -86,6 +86,7 @@
extern loader_platform_thread_mutex loader_lock;
extern loader_platform_thread_mutex loader_json_lock;
extern loader_platform_thread_mutex loader_preload_icd_lock;
+extern loader_platform_thread_mutex loader_global_instance_list_lock;
bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2);
@@ -104,7 +105,14 @@
const VkExtensionProperties *ext_array);
bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list);
+VkResult loader_add_layer_properties_to_list(const struct loader_instance *inst, struct loader_layer_list *list,
+ uint32_t prop_list_count, const struct loader_layer_properties *props);
void loader_free_layer_properties(const struct loader_instance *inst, struct loader_layer_properties *layer_properties);
+VkResult loader_add_meta_layer(const struct loader_instance *inst, const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ const struct loader_layer_properties *prop, struct loader_layer_list *target_list,
+ struct loader_layer_list *expanded_target_list, const struct loader_layer_list *source_list,
+ bool *out_found_all_component_layers);
VkResult loader_add_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list,
uint32_t prop_list_count, const VkExtensionProperties *props);
VkResult loader_add_to_dev_ext_list(const struct loader_instance *inst, struct loader_device_extension_list *ext_list,
@@ -118,17 +126,14 @@
void loader_destroy_layer_list(const struct loader_instance *inst, struct loader_device *device,
struct loader_layer_list *layer_list);
void loader_delete_layer_list_and_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list);
-VkResult loader_add_layer_name_to_list(const struct loader_instance *inst, const char *name, const enum layer_type_flags type_flags,
- const struct loader_layer_list *source_list, struct loader_layer_list *target_list,
- struct loader_layer_list *expanded_target_list);
-void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
- const VkAllocationCallbacks *pAllocator);
void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list);
VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
bool *skipped_portability_drivers);
-void loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers);
-void loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers);
-bool loader_implicit_layer_is_enabled(const struct loader_instance *inst, const struct loader_layer_properties *prop);
+void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
+ const VkAllocationCallbacks *pAllocator);
+VkResult loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers);
+VkResult loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers,
+ loader_platform_dl_handle **libs);
VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
struct loader_extension_list *inst_exts);
struct loader_icd_term *loader_get_icd_and_device(const void *device, struct loader_device **found_dev, uint32_t *icd_index);
diff --git a/loader/loader_common.h b/loader/loader_common.h
index 55584cf..d79cca7 100644
--- a/loader/loader_common.h
+++ b/loader/loader_common.h
@@ -30,7 +30,6 @@
#pragma once
#include "vulkan/vk_platform.h"
-#include "vulkan/vk_sdk_platform.h"
#include <vulkan/vulkan.h>
#include <vulkan/vk_layer.h>
#include <vulkan/vk_icd.h>
@@ -99,14 +98,6 @@
PFN_GetPhysicalDeviceProcAddr get_physical_device_proc_addr;
};
-struct loader_override_expiration {
- uint16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
-};
-
// This structure is used to store the json file version in a more manageable way.
typedef struct {
uint16_t major;
@@ -153,8 +144,6 @@
uint32_t num_override_paths;
char (*override_paths)[MAX_STRING_SIZE];
bool is_override;
- bool has_expiration;
- struct loader_override_expiration expiration;
bool keep;
uint32_t num_blacklist_layers;
char (*blacklist_layer_names)[MAX_STRING_SIZE];
@@ -173,6 +162,7 @@
struct loader_dev_dispatch_table {
VkLayerDispatchTable core_dispatch;
PFN_vkDevExt ext_dispatch[MAX_NUM_UNKNOWN_EXTS];
+ struct loader_device_terminator_dispatch extension_terminator_dispatch;
};
// per CreateDevice structure
@@ -462,3 +452,29 @@
VkDebugReportCallbackEXT icd_obj;
VkDebugReportCallbackEXT loader_obj;
};
+
+typedef enum loader_filter_string_type {
+ FILTER_STRING_FULLNAME = 0,
+ FILTER_STRING_SUBSTRING,
+ FILTER_STRING_PREFIX,
+ FILTER_STRING_SUFFIX,
+ FILTER_STRING_SPECIAL,
+} loader_filter_string_type;
+
+struct loader_envvar_filter_value {
+ char value[VK_MAX_EXTENSION_NAME_SIZE];
+ size_t length;
+ loader_filter_string_type type;
+};
+
+#define MAX_ADDITIONAL_FILTERS 16
+struct loader_envvar_filter {
+ uint32_t count;
+ struct loader_envvar_filter_value filters[MAX_ADDITIONAL_FILTERS];
+};
+struct loader_envvar_disable_layers_filter {
+ struct loader_envvar_filter additional_filters;
+ bool disable_all;
+ bool disable_all_implicit;
+ bool disable_all_explicit;
+};
diff --git a/loader/loader_environment.c b/loader/loader_environment.c
new file mode 100644
index 0000000..f4205f4
--- /dev/null
+++ b/loader/loader_environment.c
@@ -0,0 +1,550 @@
+/*
+ *
+ * Copyright (c) 2014-2022 The Khronos Group Inc.
+ * Copyright (c) 2014-2022 Valve Corporation
+ * Copyright (c) 2014-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.
+ *
+ * Author: Jon Ashburn <jon@lunarg.com>
+ * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+ * Author: Chia-I Wu <olvaffe@gmail.com>
+ * Author: Chia-I Wu <olv@lunarg.com>
+ * Author: Mark Lobodzinski <mark@LunarG.com>
+ * Author: Lenny Komow <lenny@lunarg.com>
+ * Author: Charles Giessen <charles@lunarg.com>
+ *
+ */
+
+#include "loader_environment.h"
+
+#include "allocation.h"
+#include "loader.h"
+#include "log.h"
+
+#include <ctype.h>
+
+// Environment variables
+#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || \
+ defined(__OpenBSD__)
+
+bool is_high_integrity() { return geteuid() != getuid() || getegid() != getgid(); }
+
+char *loader_getenv(const char *name, const struct loader_instance *inst) {
+ // No allocation of memory necessary for Linux, but we should at least touch
+ // the inst pointer to get rid of compiler warnings.
+ (void)inst;
+ return getenv(name);
+}
+
+char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ // Apple does not appear to have a secure getenv implementation.
+ // The main difference between secure getenv and getenv is that secure getenv
+ // returns NULL if the process is being run with elevated privileges by a normal user.
+ // The idea is to prevent the reading of malicious environment variables by a process
+ // that can do damage.
+ // This algorithm is derived from glibc code that sets an internal
+ // variable (__libc_enable_secure) if the process is running under setuid or setgid.
+ return is_high_integrity() ? NULL : loader_getenv(name, inst);
+#elif defined(__Fuchsia__)
+ return loader_getenv(name, inst);
+#else
+ // Linux
+ char *out;
+#if defined(HAVE_SECURE_GETENV) && !defined(USE_UNSAFE_FILE_SEARCH)
+ (void)inst;
+ out = secure_getenv(name);
+#elif defined(HAVE___SECURE_GETENV) && !defined(USE_UNSAFE_FILE_SEARCH)
+ (void)inst;
+ out = __secure_getenv(name);
+#else
+ out = loader_getenv(name, inst);
+#if !defined(USE_UNSAFE_FILE_SEARCH)
+ loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Loader is using non-secure environment variable lookup for %s", name);
+#endif
+#endif
+ return out;
+#endif
+}
+
+void loader_free_getenv(char *val, const struct loader_instance *inst) {
+ // No freeing of memory necessary for Linux, but we should at least touch
+ // the val and inst pointers to get rid of compiler warnings.
+ (void)val;
+ (void)inst;
+}
+
+#elif defined(WIN32)
+
+bool is_high_integrity() {
+ HANDLE process_token;
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
+ // Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD.
+ uint8_t mandatory_label_buffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)];
+ DWORD buffer_size;
+ if (GetTokenInformation(process_token, TokenIntegrityLevel, mandatory_label_buffer, sizeof(mandatory_label_buffer),
+ &buffer_size) != 0) {
+ const TOKEN_MANDATORY_LABEL *mandatory_label = (const TOKEN_MANDATORY_LABEL *)mandatory_label_buffer;
+ const DWORD sub_authority_count = *GetSidSubAuthorityCount(mandatory_label->Label.Sid);
+ const DWORD integrity_level = *GetSidSubAuthority(mandatory_label->Label.Sid, sub_authority_count - 1);
+
+ CloseHandle(process_token);
+ return integrity_level >= SECURITY_MANDATORY_HIGH_RID;
+ }
+
+ CloseHandle(process_token);
+ }
+
+ return false;
+}
+
+char *loader_getenv(const char *name, const struct loader_instance *inst) {
+ int name_utf16_size = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
+ if (name_utf16_size <= 0) {
+ return NULL;
+ }
+ wchar_t *name_utf16 = (wchar_t *)loader_stack_alloc(name_utf16_size * sizeof(wchar_t));
+ if (MultiByteToWideChar(CP_UTF8, 0, name, -1, name_utf16, name_utf16_size) != name_utf16_size) {
+ return NULL;
+ }
+
+ DWORD val_size = GetEnvironmentVariableW(name_utf16, NULL, 0);
+ // val_size DOES include the null terminator, so for any set variable
+ // will always be at least 1. If it's 0, the variable wasn't set.
+ if (val_size == 0) {
+ return NULL;
+ }
+
+ wchar_t *val = (wchar_t *)loader_stack_alloc(val_size * sizeof(wchar_t));
+ if (GetEnvironmentVariableW(name_utf16, val, val_size) != val_size - 1) {
+ return NULL;
+ }
+
+ int val_utf8_size = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
+ if (val_utf8_size <= 0) {
+ return NULL;
+ }
+ char *val_utf8 = (char *)loader_instance_heap_alloc(inst, val_utf8_size * sizeof(char), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (val_utf8 == NULL) {
+ return NULL;
+ }
+ if (WideCharToMultiByte(CP_UTF8, 0, val, -1, val_utf8, val_utf8_size, NULL, NULL) != val_utf8_size) {
+ loader_instance_heap_free(inst, val_utf8);
+ return NULL;
+ }
+ return val_utf8;
+}
+
+char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
+#if !defined(USE_UNSAFE_FILE_SEARCH)
+ if (is_high_integrity()) {
+ loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ "Loader is running with elevated permissions. Environment variable %s will be ignored", name);
+ return NULL;
+ }
+#endif
+
+ return loader_getenv(name, inst);
+}
+
+void loader_free_getenv(char *val, const struct loader_instance *inst) { loader_instance_heap_free(inst, (void *)val); }
+
+#else
+
+char *loader_getenv(const char *name, const struct loader_instance *inst) {
+ // stub func
+ (void)inst;
+ (void)name;
+ return NULL;
+}
+void loader_free_getenv(char *val, const struct loader_instance *inst) {
+ // stub func
+ (void)val;
+ (void)inst;
+}
+
+#endif
+
+// Determine the type of filter string based on the contents of it.
+// This will properly check against:
+// - substrings "*string*"
+// - prefixes "string*"
+// - suffixes "*string"
+// - full string names "string"
+// It will also return the correct start and finish to remove any star '*' characters for the actual string compare
+void determine_filter_type(const char *filter_string, enum loader_filter_string_type *filter_type, const char **new_start,
+ size_t *new_length) {
+ size_t filter_length = strlen(filter_string);
+ bool star_begin = false;
+ bool star_end = false;
+ if ('~' == filter_string[0]) {
+ // One of the special identifiers like: ~all~, ~implicit~, or ~explicit~
+ *filter_type = FILTER_STRING_SPECIAL;
+ *new_start = filter_string;
+ *new_length = filter_length;
+ } else {
+ if ('*' == filter_string[0]) {
+ // Only the * means everything
+ if (filter_length == 1) {
+ *filter_type = FILTER_STRING_SPECIAL;
+ *new_start = filter_string;
+ *new_length = filter_length;
+ } else {
+ star_begin = true;
+ }
+ }
+ if ('*' == filter_string[filter_length - 1]) {
+ // Not really valid, but just catch this case so if someone accidentally types "**" it will also mean everything
+ if (filter_length == 2) {
+ *filter_type = FILTER_STRING_SPECIAL;
+ *new_start = filter_string;
+ *new_length = filter_length;
+ } else {
+ star_end = true;
+ }
+ }
+ if (star_begin && star_end) {
+ *filter_type = FILTER_STRING_SUBSTRING;
+ *new_start = &filter_string[1];
+ *new_length = filter_length - 2;
+ } else if (star_begin) {
+ *new_start = &filter_string[1];
+ *new_length = filter_length - 1;
+ *filter_type = FILTER_STRING_SUFFIX;
+ } else if (star_end) {
+ *filter_type = FILTER_STRING_PREFIX;
+ *new_start = filter_string;
+ *new_length = filter_length - 1;
+ } else {
+ *filter_type = FILTER_STRING_FULLNAME;
+ *new_start = filter_string;
+ *new_length = filter_length;
+ }
+ }
+}
+
+// Parse the provided filter string provided by the envrionment variable into the appropriate filter
+// struct variable.
+VkResult parse_generic_filter_environment_var(const struct loader_instance *inst, const char *env_var_name,
+ struct loader_envvar_filter *filter_struct) {
+ VkResult result = VK_SUCCESS;
+ memset(filter_struct, 0, sizeof(struct loader_envvar_filter));
+ char *env_var_value = loader_secure_getenv(env_var_name, inst);
+ if (NULL == env_var_value) {
+ return result;
+ }
+ if (strlen(env_var_value) > 0) {
+ const size_t env_var_len = strlen(env_var_value);
+ // Allocate a separate string since strtok modifies the original string
+ char *parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL != parsing_string) {
+ const char tokenizer[3] = ",";
+
+ for (uint32_t iii = 0; iii < env_var_len; ++iii) {
+ parsing_string[iii] = (char)tolower(env_var_value[iii]);
+ }
+ parsing_string[env_var_len] = '\0';
+
+ char *token = strtok(parsing_string, tokenizer);
+ while (NULL != token) {
+ enum loader_filter_string_type cur_filter_type;
+ const char *actual_start;
+ size_t actual_len;
+ determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
+ if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
+ strncpy(filter_struct->filters[filter_struct->count].value, actual_start, VK_MAX_EXTENSION_NAME_SIZE);
+ } else {
+ strncpy(filter_struct->filters[filter_struct->count].value, actual_start, actual_len);
+ }
+ filter_struct->filters[filter_struct->count].length = actual_len;
+ filter_struct->filters[filter_struct->count++].type = cur_filter_type;
+ if (filter_struct->count >= MAX_ADDITIONAL_FILTERS) {
+ break;
+ }
+ token = strtok(NULL, tokenizer);
+ }
+ loader_instance_heap_free(inst, parsing_string);
+ } else {
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ "parse_generic_filter_environment_var: Failed to allocate space for parsing env var \'%s\'", env_var_name);
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ }
+ loader_free_getenv(env_var_value, inst);
+ return result;
+}
+
+// Parse the disable layer string. The layer disable has some special behavior because we allow it to disable
+// all layers (either with "~all~", "*", or "**"), all implicit layers (with "~implicit~"), and all explicit layers
+// (with "~explicit~"), in addition to the other layer filtering behavior.
+VkResult parse_layers_disable_filter_environment_var(const struct loader_instance *inst,
+ struct loader_envvar_disable_layers_filter *disable_struct) {
+ VkResult result = VK_SUCCESS;
+ memset(disable_struct, 0, sizeof(struct loader_envvar_disable_layers_filter));
+ char *env_var_value = loader_secure_getenv(VK_LAYERS_DISABLE_ENV_VAR, inst);
+ if (NULL == env_var_value) {
+ goto out;
+ }
+ if (strlen(env_var_value) > 0) {
+ const size_t env_var_len = strlen(env_var_value);
+ // Allocate a separate string since strtok modifies the original string
+ char *parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL != parsing_string) {
+ const char tokenizer[3] = ",";
+
+ for (uint32_t iii = 0; iii < env_var_len; ++iii) {
+ parsing_string[iii] = (char)tolower(env_var_value[iii]);
+ }
+ parsing_string[env_var_len] = '\0';
+
+ char *token = strtok(parsing_string, tokenizer);
+ while (NULL != token) {
+ uint32_t cur_count = disable_struct->additional_filters.count;
+ enum loader_filter_string_type cur_filter_type;
+ const char *actual_start;
+ size_t actual_len;
+ determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
+ if (cur_filter_type == FILTER_STRING_SPECIAL) {
+ if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, token) || !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, token) ||
+ !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, token)) {
+ disable_struct->disable_all = true;
+ } else if (!strcmp(VK_LOADER_DISABLE_IMPLICIT_LAYERS_VAR, token)) {
+ disable_struct->disable_all_implicit = true;
+ } else if (!strcmp(VK_LOADER_DISABLE_EXPLICIT_LAYERS_VAR, token)) {
+ disable_struct->disable_all_explicit = true;
+ }
+ } else {
+ if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
+ strncpy(disable_struct->additional_filters.filters[cur_count].value, actual_start,
+ VK_MAX_EXTENSION_NAME_SIZE);
+ } else {
+ strncpy(disable_struct->additional_filters.filters[cur_count].value, actual_start, actual_len);
+ }
+ disable_struct->additional_filters.filters[cur_count].length = actual_len;
+ disable_struct->additional_filters.filters[cur_count].type = cur_filter_type;
+ disable_struct->additional_filters.count++;
+ if (disable_struct->additional_filters.count >= MAX_ADDITIONAL_FILTERS) {
+ break;
+ }
+ }
+ token = strtok(NULL, tokenizer);
+ }
+ loader_instance_heap_free(inst, parsing_string);
+ } else {
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ "parse_layers_disable_filter_environment_var: Failed to allocate space for parsing env var "
+ "\'VK_LAYERS_DISABLE_ENV_VAR\'");
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ }
+ loader_free_getenv(env_var_value, inst);
+out:
+ return result;
+}
+
+// Check to see if the provided layer name matches any of the filter strings.
+// This will properly check against:
+// - substrings "*string*"
+// - prefixes "string*"
+// - suffixes "*string"
+// - full string names "string"
+bool check_name_matches_filter_environment_var(const struct loader_instance *inst, const char *name,
+ const struct loader_envvar_filter *filter_struct) {
+ bool ret_value = false;
+ const size_t name_len = strlen(name);
+ char lower_name[VK_MAX_EXTENSION_NAME_SIZE];
+ for (uint32_t iii = 0; iii < name_len; ++iii) {
+ lower_name[iii] = (char)tolower(name[iii]);
+ }
+ lower_name[name_len] = '\0';
+ for (uint32_t filt = 0; filt < filter_struct->count; ++filt) {
+ // Check if the filter name is longer (this is with all special characters removed), and if it is
+ // continue since it can't match.
+ if (filter_struct->filters[filt].length > name_len) {
+ continue;
+ }
+ switch (filter_struct->filters[filt].type) {
+ case FILTER_STRING_SPECIAL:
+ if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, filter_struct->filters[filt].value) ||
+ !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, filter_struct->filters[filt].value) ||
+ !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, filter_struct->filters[filt].value)) {
+ ret_value = true;
+ }
+ break;
+
+ case FILTER_STRING_SUBSTRING:
+ if (NULL != strstr(lower_name, filter_struct->filters[filt].value)) {
+ ret_value = true;
+ }
+ break;
+
+ case FILTER_STRING_SUFFIX:
+ if (0 == strncmp(lower_name + name_len - filter_struct->filters[filt].length, filter_struct->filters[filt].value,
+ filter_struct->filters[filt].length)) {
+ ret_value = true;
+ }
+ break;
+
+ case FILTER_STRING_PREFIX:
+ if (0 == strncmp(lower_name, filter_struct->filters[filt].value, filter_struct->filters[filt].length)) {
+ ret_value = true;
+ }
+ break;
+
+ case FILTER_STRING_FULLNAME:
+ if (0 == strncmp(lower_name, filter_struct->filters[filt].value, name_len)) {
+ ret_value = true;
+ }
+ break;
+ }
+ if (ret_value) {
+ break;
+ }
+ }
+ return ret_value;
+}
+
+// Get the layer name(s) from the env_name environment variable. If layer is found in
+// search_list then add it to layer_list. But only add it to layer_list if type_flags matches.
+VkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags, const char *env_name,
+ const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
+ const struct loader_layer_list *source_list) {
+ VkResult res = VK_SUCCESS;
+ char *next, *name;
+ char *layer_env = loader_getenv(env_name, inst);
+ char **vk_inst_layers = NULL;
+ uint32_t vk_inst_layer_count = 0;
+ uint32_t separator_count = 0;
+
+ // If the layer environment variable is present (i.e. VK_INSTANCE_LAYERS), we will always add it to the layer list.
+ if (layer_env != NULL) {
+ name = loader_stack_alloc(strlen(layer_env) + 1);
+ if (name != NULL) {
+ separator_count = 1;
+ for (uint32_t c = 0; c < strlen(layer_env); ++c) {
+ if (layer_env[c] == PATH_SEPARATOR) {
+ separator_count++;
+ }
+ }
+
+ vk_inst_layers =
+ loader_instance_heap_calloc(inst, (separator_count * sizeof(char *)), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (vk_inst_layers == NULL) {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ for (uint32_t cur_layer = 0; cur_layer < separator_count; ++cur_layer) {
+ vk_inst_layers[cur_layer] =
+ loader_instance_heap_calloc(inst, VK_MAX_EXTENSION_NAME_SIZE, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (vk_inst_layers[cur_layer] == NULL) {
+ res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ }
+
+ strcpy(name, layer_env);
+
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers \"%s\"",
+ env_name, name);
+
+ // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS
+ while (name && *name) {
+ next = loader_get_next_path(name);
+
+ if (strlen(name) > 0) {
+ strncpy(vk_inst_layers[vk_inst_layer_count++], name, VK_MAX_EXTENSION_NAME_SIZE);
+ }
+ name = next;
+ }
+ }
+ }
+
+ // Loop through all the layers and check the enable/disable filters as well as the VK_INSTANCE_LAYERS value.
+ for (uint32_t i = 0; i < source_list->count; i++) {
+ struct loader_layer_properties *source_prop = &source_list->list[i];
+
+ // If it doesn't match the type, or the name isn't what we're looking for, just continue
+ if ((source_prop->type_flags & type_flags) != type_flags) {
+ continue;
+ }
+
+ // We found a layer we're interested in, but has it been disabled...
+ bool adding = true;
+ bool is_implicit = (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER));
+ bool disabled_by_type = (is_implicit) ? (NULL != disable_filter && disable_filter->disable_all_implicit)
+ : (NULL != disable_filter && disable_filter->disable_all_explicit);
+ if (NULL != disable_filter &&
+ (disable_filter->disable_all || disabled_by_type ||
+ check_name_matches_filter_environment_var(inst, source_prop->info.layerName, &disable_filter->additional_filters))) {
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+ "Layer \"%s\" ignored because it has been disabled by env var \'%s\'", source_prop->info.layerName,
+ VK_LAYERS_DISABLE_ENV_VAR);
+ adding = false;
+ }
+
+ // If we are supposed to filter through all layers, we need to compare the layer name against the filter.
+ // This can override the disable above, so we want to do it second.
+ if (check_name_matches_filter_environment_var(inst, source_prop->info.layerName, enable_filter)) {
+ adding = true;
+ // Only way is_substring is true is if there are enable variables. If that's the case, and we're past the
+ // above, we should indicate that it was forced on in this way.
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+ "Layer \"%s\" forced enabled due to env var \'%s\'", source_prop->info.layerName, VK_LAYERS_ENABLE_ENV_VAR);
+ } else {
+ adding = false;
+ // If it's not in the enable filter, check the environment variable if it exists
+ if (vk_inst_layer_count > 0) {
+ for (uint32_t cur_layer = 0; cur_layer < vk_inst_layer_count; ++cur_layer) {
+ if (!strcmp(vk_inst_layers[cur_layer], source_prop->info.layerName)) {
+ adding = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!adding) {
+ continue;
+ }
+
+ // If not a meta-layer, simply add it.
+ if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
+ res = loader_add_layer_properties_to_list(inst, target_list, 1, source_prop);
+ if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
+ res = loader_add_layer_properties_to_list(inst, expanded_target_list, 1, source_prop);
+ if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
+ } else {
+ res = loader_add_meta_layer(inst, enable_filter, disable_filter, source_prop, target_list, expanded_target_list,
+ source_list, NULL);
+ if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
+ }
+ }
+
+out:
+
+ if (NULL != vk_inst_layers) {
+ for (uint32_t cur_layer = 0; cur_layer < separator_count; ++cur_layer) {
+ loader_instance_heap_free(inst, vk_inst_layers[cur_layer]);
+ }
+ loader_instance_heap_free(inst, vk_inst_layers);
+ }
+
+ if (layer_env != NULL) {
+ loader_free_getenv(layer_env, inst);
+ }
+
+ return res;
+}
diff --git a/loader/loader_environment.h b/loader/loader_environment.h
new file mode 100644
index 0000000..2eb61d5
--- /dev/null
+++ b/loader/loader_environment.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright (c) 2014-2021 The Khronos Group Inc.
+ * Copyright (c) 2014-2021 Valve Corporation
+ * Copyright (c) 2014-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.
+ *
+ * Author: Jon Ashburn <jon@lunarg.com>
+ * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+ * Author: Chia-I Wu <olvaffe@gmail.com>
+ * Author: Chia-I Wu <olv@lunarg.com>
+ * Author: Mark Lobodzinski <mark@LunarG.com>
+ * Author: Lenny Komow <lenny@lunarg.com>
+ * Author: Charles Giessen <charles@lunarg.com>
+ *
+ */
+
+#pragma once
+
+#include "loader_common.h"
+
+// Common functionality for accessing environemnt variables and whether the process is running in priviledged mode
+
+char *loader_getenv(const char *name, const struct loader_instance *inst);
+void loader_free_getenv(char *val, const struct loader_instance *inst);
+
+#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || \
+ defined(__FreeBSD__) || defined(__OpenBSD__)
+
+bool is_high_integrity();
+
+char *loader_secure_getenv(const char *name, const struct loader_instance *inst);
+
+#endif
+
+VkResult parse_generic_filter_environment_var(const struct loader_instance *inst, const char *env_var_name,
+ struct loader_envvar_filter *filter_struct);
+VkResult parse_layers_disable_filter_environment_var(const struct loader_instance *inst,
+ struct loader_envvar_disable_layers_filter *disable_struct);
+bool check_name_matches_filter_environment_var(const struct loader_instance *inst, const char *name,
+ const struct loader_envvar_filter *filter_struct);
+VkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags, const char *env_name,
+ const struct loader_envvar_filter *enable_filter,
+ const struct loader_envvar_disable_layers_filter *disable_filter,
+ struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
+ const struct loader_layer_list *source_list);
\ No newline at end of file
diff --git a/loader/loader_linux.c b/loader/loader_linux.c
index 4a31da6..9f1a168 100644
--- a/loader/loader_linux.c
+++ b/loader/loader_linux.c
@@ -30,7 +30,7 @@
#include "loader_linux.h"
#include "allocation.h"
-#include "get_environment.h"
+#include "loader_environment.h"
#include "loader.h"
#include "log.h"
@@ -209,7 +209,7 @@
char *selection = loader_getenv("VK_LOADER_DEVICE_SELECT", inst);
if (NULL != selection) {
loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
- "linux_env_var_default_device: Found VK_LOADER_DEVICE_SELECT set to %s", selection);
+ "linux_env_var_default_device: Found \'VK_LOADER_DEVICE_SELECT\' set to %s", selection);
// The environment variable exists, so grab the vendor ID and device ID of the
// selected default device
diff --git a/loader/loader_windows.c b/loader/loader_windows.c
index 4015acb..db8b691 100644
--- a/loader/loader_windows.c
+++ b/loader/loader_windows.c
@@ -36,7 +36,7 @@
#include "loader_windows.h"
#include "allocation.h"
-#include "get_environment.h"
+#include "loader_environment.h"
#include "loader.h"
#include "log.h"
@@ -525,8 +525,8 @@
foundDuplicate = true;
}
}
-
- if (foundDuplicate == false) {
+ // Only skip if we are adding a driver and a duplicate was found
+ if (!is_driver || (is_driver && foundDuplicate == false)) {
// Add the new entry to the list.
(void)snprintf(*reg_data + strlen(*reg_data), name_size + 2, "%c%s", PATH_SEPARATOR, name);
found = true;
diff --git a/loader/log.c b/loader/log.c
index 6b68bd0..33ed3ce 100644
--- a/loader/log.c
+++ b/loader/log.c
@@ -32,7 +32,7 @@
#include <stdarg.h>
#include "debug_utils.h"
-#include "get_environment.h"
+#include "loader_environment.h"
uint32_t g_loader_debug = 0;
@@ -229,3 +229,8 @@
assert(false);
}
}
+
+void loader_log_asm_function_not_supported(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code,
+ const char *func_name) {
+ loader_log(inst, msg_type, msg_code, "Function %s not supported for this physical device", func_name);
+}
diff --git a/loader/log.h b/loader/log.h
index 06d3f0d..3e074c3 100644
--- a/loader/log.h
+++ b/loader/log.h
@@ -54,6 +54,11 @@
// May output to DebugUtils if the instance isn't null and the extension is enabled.
void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...);
+// Used for the assembly code to emit an specific error message
+// This is a work around for linux 32 bit error handling not passing relocatable strings correctly
+void loader_log_asm_function_not_supported(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code,
+ const char *func_name);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/loader/trampoline.c b/loader/trampoline.c
index d65e7b1..9066a08 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -160,21 +160,19 @@
// Get the implicit layers
struct loader_layer_list layers;
- memset(&layers, 0, sizeof(layers));
- loader_scan_for_implicit_layers(NULL, &layers);
-
- // We'll need to save the dl handles so we can close them later
- loader_platform_dl_handle *libs =
- loader_calloc(NULL, sizeof(loader_platform_dl_handle) * layers.count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
- if (libs == NULL && layers.count > 0) {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
+ loader_platform_dl_handle *libs = NULL;
size_t lib_count = 0;
+ memset(&layers, 0, sizeof(layers));
+
+ res = loader_scan_for_implicit_layers(NULL, &layers, &libs);
+ if (VK_SUCCESS != res) {
+ return res;
+ }
// Prepend layers onto the chain if they implement this entry point
for (uint32_t i = 0; i < layers.count; ++i) {
- if (!loader_implicit_layer_is_enabled(NULL, layers.list + i) ||
- layers.list[i].pre_instance_functions.enumerate_instance_extension_properties[0] == '\0') {
+ // Skip this layer if it doesn't expose the entry-point
+ if (layers.list[i].pre_instance_functions.enumerate_instance_extension_properties[0] == '\0') {
continue;
}
@@ -255,24 +253,17 @@
// Get the implicit layers
struct loader_layer_list layers;
- memset(&layers, 0, sizeof(layers));
- loader_scan_for_implicit_layers(NULL, &layers);
-
- // We'll need to save the dl handles so we can close them later
- loader_platform_dl_handle *libs =
- loader_calloc(NULL, sizeof(loader_platform_dl_handle) * layers.count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
- if (libs == NULL && layers.count > 0) {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
+ loader_platform_dl_handle *libs = NULL;
size_t lib_count = 0;
+ memset(&layers, 0, sizeof(layers));
+
+ res = loader_scan_for_implicit_layers(NULL, &layers, &libs);
+ if (VK_SUCCESS != res) {
+ return res;
+ }
// Prepend layers onto the chain if they implement this entry point
for (uint32_t i = 0; i < layers.count; ++i) {
- if (!loader_implicit_layer_is_enabled(NULL, layers.list + i) ||
- layers.list[i].pre_instance_functions.enumerate_instance_layer_properties[0] == '\0') {
- continue;
- }
-
loader_platform_dl_handle layer_lib = loader_platform_open_library(layers.list[i].lib_name);
if (layer_lib == NULL) {
loader_log(NULL, VULKAN_LOADER_WARN_BIT, 0, "%s: Unable to load implicit layer library \"%s\"", __FUNCTION__,
@@ -357,21 +348,19 @@
// Get the implicit layers
struct loader_layer_list layers;
- memset(&layers, 0, sizeof(layers));
- loader_scan_for_implicit_layers(NULL, &layers);
-
- // We'll need to save the dl handles so we can close them later
- loader_platform_dl_handle *libs =
- loader_calloc(NULL, sizeof(loader_platform_dl_handle) * layers.count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
- if (libs == NULL && layers.count > 0) {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
+ loader_platform_dl_handle *libs = NULL;
size_t lib_count = 0;
+ memset(&layers, 0, sizeof(layers));
+
+ res = loader_scan_for_implicit_layers(NULL, &layers, &libs);
+ if (VK_SUCCESS != res) {
+ return res;
+ }
// Prepend layers onto the chain if they implement this entry point
for (uint32_t i = 0; i < layers.count; ++i) {
- if (!loader_implicit_layer_is_enabled(NULL, layers.list + i) ||
- layers.list[i].pre_instance_functions.enumerate_instance_version[0] == '\0') {
+ // Skip this layer if it doesn't expose the entry-point
+ if (layers.list[i].pre_instance_functions.enumerate_instance_version[0] == '\0') {
continue;
}
@@ -470,8 +459,6 @@
ptr_instance->app_api_version = LOADER_VERSION_1_0_0;
} else {
ptr_instance->app_api_version = loader_make_version(pCreateInfo->pApplicationInfo->apiVersion);
- // zero out the patch version since we don't actually want to compare with it
- ptr_instance->app_api_version.patch = 0;
}
// Look for one or more VK_EXT_debug_report or VK_EXT_debug_utils create info structures
@@ -520,7 +507,10 @@
// enabledLayerCount == 0 and VK_INSTANCE_LAYERS is unset. For now always
// get layer list via loader_scan_for_layers().
memset(&ptr_instance->instance_layer_list, 0, sizeof(ptr_instance->instance_layer_list));
- loader_scan_for_layers(ptr_instance, &ptr_instance->instance_layer_list);
+ res = loader_scan_for_layers(ptr_instance, &ptr_instance->instance_layer_list);
+ if (VK_SUCCESS != res) {
+ goto out;
+ }
// Validate the app requested layers to be enabled
if (pCreateInfo->enabledLayerCount > 0) {
@@ -543,8 +533,8 @@
loader_log(
ptr_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
"vkCreateInstance: Found drivers that contain devices which support the portability subset, but the "
- "portability enumeration bit was not set!. Applications that wish to enumerate portability drivers must set the "
- "VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit in the VkInstanceCreateInfo flags and"
+ "portability enumeration bit was not set! Applications that wish to enumerate portability drivers must set the "
+ "VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit in the VkInstanceCreateInfo flags and "
"enable the VK_KHR_portability_enumeration instance extension.");
}
loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "vkCreateInstance: Found no drivers!");
@@ -572,8 +562,10 @@
}
memcpy(&ptr_instance->disp->layer_inst_disp, &instance_disp, sizeof(instance_disp));
+ loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
ptr_instance->next = loader.instances;
loader.instances = ptr_instance;
+ loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
// Activate any layers on instance chain
res = loader_enable_instance_layers(ptr_instance, &ici, &ptr_instance->instance_layer_list);
@@ -611,10 +603,13 @@
if (NULL != ptr_instance) {
if (res != VK_SUCCESS) {
+ loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
// error path, should clean everything up
if (loader.instances == ptr_instance) {
loader.instances = ptr_instance->next;
}
+ loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
+
loader_instance_heap_free(ptr_instance, ptr_instance->disp);
// Remove any created VK_EXT_debug_report or VK_EXT_debug_utils items
destroy_debug_callbacks_chain(ptr_instance, pAllocator);
@@ -646,6 +641,7 @@
ptr_instance->InstanceCreationDeletionDebugFunctionHead = ptr_instance->DbgFunctionHead;
ptr_instance->DbgFunctionHead = NULL;
}
+ // Only unlock when ptr_instance isn't NULL, as if it is, the above code didn't make it to when loader_lock was locked.
loader_platform_thread_unlock_mutex(&loader_lock);
}
diff --git a/loader/unknown_ext_chain.c b/loader/unknown_ext_chain.c
index 3ce7f3b..93d71bf 100644
--- a/loader/unknown_ext_chain.c
+++ b/loader/unknown_ext_chain.c
@@ -48,7 +48,7 @@
struct loader_icd_term *icd_term = phys_dev_term->this_icd_term; \
struct loader_instance *inst = (struct loader_instance *)icd_term->this_instance; \
if (NULL == icd_term->phys_dev_ext[num]) { \
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "Extension %s not supported for this physical device", \
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "Function %s not supported for this physical device", \
inst->phys_dev_ext_disp_functions[num]); \
} \
icd_term->phys_dev_ext[num](phys_dev_term->phys_dev); \
diff --git a/loader/unknown_ext_chain_gas_aarch64.S b/loader/unknown_ext_chain_gas_aarch64.S
index 5a7d98a..1be8af9 100644
--- a/loader/unknown_ext_chain_gas_aarch64.S
+++ b/loader/unknown_ext_chain_gas_aarch64.S
@@ -27,6 +27,7 @@
.macro PhysDevExtTramp num
.global vkPhysDevExtTramp\num
+.hidden vkPhysDevExtTramp\num
vkPhysDevExtTramp\num:
ldr x9, [x0] // Load the loader_instance_dispatch_table* into x9
ldr x0, [x0, PHYS_DEV_OFFSET_PHYS_DEV_TRAMP] // Load the unwrapped VkPhysicalDevice into x0
@@ -37,6 +38,7 @@
.macro PhysDevExtTermin num
.global vkPhysDevExtTermin\num
+.hidden vkPhysDevExtTermin\num
vkPhysDevExtTermin\num:
ldr x9, [x0, ICD_TERM_OFFSET_PHYS_DEV_TERM] // Load the loader_icd_term* in x9
mov x11, (DISPATCH_OFFSET_ICD_TERM + (PTR_SIZE * \num)) // Put the offset into the dispatch table in x11
@@ -60,6 +62,7 @@
.macro DevExtTramp num
.global vkdev_ext\num
+.hidden vkdev_ext\num
vkdev_ext\num:
ldr x9, [x0] // Load the loader_instance_dispatch_table* into x9
mov x10, (EXT_OFFSET_DEVICE_DISPATCH + (PTR_SIZE * \num)) // Offset of the desired function in the dispatch table
@@ -76,7 +79,7 @@
.data
termin_error_string:
-.string "Extension %s not supported for this physical device"
+.string "Function %s not supported for this physical device"
.text
diff --git a/loader/unknown_ext_chain_gas_x86.S b/loader/unknown_ext_chain_gas_x86.S
index 496208d..a380427 100644
--- a/loader/unknown_ext_chain_gas_x86.S
+++ b/loader/unknown_ext_chain_gas_x86.S
@@ -37,6 +37,7 @@
.macro PhysDevExtTramp num
.global vkPhysDevExtTramp\num
+.hidden vkPhysDevExtTramp\num
vkPhysDevExtTramp\num:
_CET_ENDBR
mov rax, [rdi]
@@ -46,6 +47,7 @@
.macro PhysDevExtTermin num
.global vkPhysDevExtTermin\num
+.hidden vkPhysDevExtTermin\num
vkPhysDevExtTermin\num:
_CET_ENDBR
mov rax, [rdi + ICD_TERM_OFFSET_PHYS_DEV_TERM] # Store the loader_icd_term* in rax
@@ -68,6 +70,7 @@
.macro DevExtTramp num
.global vkdev_ext\num
+.hidden vkdev_ext\num
vkdev_ext\num:
_CET_ENDBR
mov rax, [rdi] # Dereference the handle to get the dispatch table
@@ -78,6 +81,7 @@
.macro PhysDevExtTramp num
.global vkPhysDevExtTramp\num
+.hidden vkPhysDevExtTramp\num
vkPhysDevExtTramp\num:
_CET_ENDBR
mov eax, [esp + 4] # Load the wrapped VkPhysicalDevice into eax
@@ -89,6 +93,7 @@
.macro PhysDevExtTermin num
.global vkPhysDevExtTermin\num
+.hidden vkPhysDevExtTermin\num
vkPhysDevExtTermin\num:
_CET_ENDBR
mov ecx, [esp + 4] # Move the wrapped VkPhysicalDevice into ecx
@@ -100,12 +105,11 @@
jmp [eax + (DISPATCH_OFFSET_ICD_TERM + (PTR_SIZE * \num))] # Jump to the next function in the chain
terminError\num:
mov eax, dword ptr [eax + INSTANCE_OFFSET_ICD_TERM] # Load the loader_instance into eax
- push dword ptr [eax + (FUNCTION_OFFSET_INSTANCE + (CHAR_PTR_SIZE * \num))] # Push the func name (fifth arg)
- push offset termin_error_string@GOT # Push the error string (fourth arg)
+ push dword ptr [eax + (FUNCTION_OFFSET_INSTANCE + (CHAR_PTR_SIZE * \num))] # Push the func name (fourth arg)
push 0 # Push zero (third arg)
push VULKAN_LOADER_ERROR_BIT # Push the error logging bit (second arg)
push eax # Push the loader_instance (first arg)
- call loader_log # Log the error message before we crash
+ call loader_log_asm_function_not_supported # Log the error message before we crash
add esp, 20 # Clean up the args
mov eax, 0
jmp eax # Crash intentionally by jumping to address zero
@@ -113,6 +117,7 @@
.macro DevExtTramp num
.global vkdev_ext\num
+.hidden vkdev_ext\num
vkdev_ext\num:
_CET_ENDBR
mov eax, dword ptr [esp + 4] # Dereference the handle to get the dispatch table
@@ -129,7 +134,7 @@
.data
termin_error_string:
-.string "Extension %s not supported for this physical device"
+.string "Function %s not supported for this physical device"
.text
diff --git a/loader/unknown_ext_chain_masm.asm b/loader/unknown_ext_chain_masm.asm
index e33858a..46d13de 100644
--- a/loader/unknown_ext_chain_masm.asm
+++ b/loader/unknown_ext_chain_masm.asm
@@ -119,7 +119,7 @@
ENDIF
.const
- termin_error_string db 'Extension %s not supported for this physical device', 0
+ termin_error_string db 'Function %s not supported for this physical device', 0
.code
diff --git a/loader/unknown_function_handling.c b/loader/unknown_function_handling.c
index 6eb6918..2fbb2e7 100644
--- a/loader/unknown_function_handling.c
+++ b/loader/unknown_function_handling.c
@@ -188,6 +188,7 @@
icd_term = inst->icd_terms;
while (NULL != icd_term) {
if (icd_term->scanned_icd->interface_version >= MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION &&
+ icd_term->scanned_icd->GetPhysicalDeviceProcAddr &&
icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName))
// this icd supports funcName
return true;
diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h
index 55d8ae9..b3145cb 100644
--- a/loader/vk_loader_platform.h
+++ b/loader/vk_loader_platform.h
@@ -43,7 +43,8 @@
#include "dlopen_fuchsia.h"
#endif // defined(__Fuchsia__)
-#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || \
+ defined(__OpenBSD__)
#include <unistd.h>
// Note: The following file is for dynamic loading:
#include <dlfcn.h>
@@ -88,11 +89,22 @@
#endif
// Environment Variable information
-#define VK_ICD_FILENAMES_ENV_VAR "VK_ICD_FILENAMES" // Deprecated
+#define VK_ICD_FILENAMES_ENV_VAR "VK_ICD_FILENAMES" // Deprecated in v1.3.207 loader
#define VK_DRIVER_FILES_ENV_VAR "VK_DRIVER_FILES"
-#define VK_ADDITIONAL_DRIVER_FILES_ENV_VAR "VK_ADD_DRIVER_FILES"
#define VK_LAYER_PATH_ENV_VAR "VK_LAYER_PATH"
+// Support added in v1.3.207 loader
+#define VK_ADDITIONAL_DRIVER_FILES_ENV_VAR "VK_ADD_DRIVER_FILES"
#define VK_ADDITIONAL_LAYER_PATH_ENV_VAR "VK_ADD_LAYER_PATH"
+// Support added in v1.3.234 loader
+#define VK_LAYERS_ENABLE_ENV_VAR "VK_LOADER_LAYERS_ENABLE"
+#define VK_LAYERS_DISABLE_ENV_VAR "VK_LOADER_LAYERS_DISABLE"
+#define VK_DRIVERS_SELECT_ENV_VAR "VK_LOADER_DRIVERS_SELECT"
+#define VK_DRIVERS_DISABLE_ENV_VAR "VK_LOADER_DRIVERS_DISABLE"
+#define VK_LOADER_DISABLE_ALL_LAYERS_VAR_1 "~all~"
+#define VK_LOADER_DISABLE_ALL_LAYERS_VAR_2 "*"
+#define VK_LOADER_DISABLE_ALL_LAYERS_VAR_3 "**"
+#define VK_LOADER_DISABLE_IMPLICIT_LAYERS_VAR "~implicit~"
+#define VK_LOADER_DISABLE_EXPLICIT_LAYERS_VAR "~explicit~"
// Override layer information
#define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override"
@@ -100,7 +112,8 @@
#define LAYERS_PATH_ENV "VK_LAYER_PATH"
#define ENABLED_LAYERS_ENV "VK_INSTANCE_LAYERS"
-#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || \
+ defined(__OpenBSD__)
/* Linux-specific common code: */
// VK Library Filenames, Paths, etc.:
@@ -221,7 +234,8 @@
#endif
-#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) || \
+ defined(__OpenBSD__)
// File IO
static inline bool loader_platform_file_exists(const char *path) {
diff --git a/loader/vulkan.pc.in b/loader/vulkan.pc.in
index 1538155..1d38a22 100644
--- a/loader/vulkan.pc.in
+++ b/loader/vulkan.pc.in
@@ -1,12 +1,12 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
-libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
-includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
+libdir=${exec_prefix}/@CMAKE_INSTALL_REL_LIBDIR_PC@
+includedir=${prefix}/@CMAKE_INSTALL_REL_INCLUDEDIR_PC@
Name: @CMAKE_PROJECT_NAME@
Description: Vulkan Loader
Version: @VK_API_VERSION@
Libs: -L${libdir} -lvulkan@VULKAN_LIB_SUFFIX@
-Libs.private: @PRIVATE_LIBS@
+@PRIVATE_LIBS@
Cflags: -I${includedir}
diff --git a/loader/wsi.c b/loader/wsi.c
index 23c589b..8a97ca5 100644
--- a/loader/wsi.c
+++ b/loader/wsi.c
@@ -251,9 +251,11 @@
*pSupported = false;
if (NULL == icd_term->dispatch.GetPhysicalDeviceSurfaceSupportKHR) {
+ // set pSupported to false as this driver doesn't support WSI functionality
+ *pSupported = false;
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceSurfaceSupportKHR!\n");
- abort();
+ return VK_SUCCESS;
}
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
@@ -303,9 +305,11 @@
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR) {
+ // Zero out the capabilities as this driver doesn't support WSI functionality
+ memset(pSurfaceCapabilities, 0, sizeof(VkSurfaceCapabilitiesKHR));
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceSurfaceCapabilitiesKHR!\n");
- abort();
+ return VK_SUCCESS;
}
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
@@ -357,9 +361,11 @@
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR) {
+ // Zero out the format count as this driver doesn't support WSI functionality
+ *pSurfaceFormatCount = 0;
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceSurfaceCapabilitiesKHR!\n");
- abort();
+ return VK_SUCCESS;
}
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
@@ -413,9 +419,11 @@
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceSurfacePresentModesKHR) {
+ // Zero out the present mode count as this driver doesn't support WSI functionality
+ *pPresentModeCount = 0;
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceSurfacePresentModesKHR!\n");
- abort();
+ return VK_SUCCESS;
}
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
@@ -441,6 +449,14 @@
"vkCreateSwapchainKHR: Invalid device [VUID-vkCreateSwapchainKHR-device-parameter]");
abort(); /* Intentionally fail so user can correct issue. */
}
+ if (NULL == disp->CreateSwapchainKHR) {
+ struct loader_device *dev = *((struct loader_device **)device);
+ loader_log(NULL != dev ? dev->phys_dev_term->this_icd_term->this_instance : NULL,
+ VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+ "extension enabled?");
+ abort();
+ }
return disp->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
}
@@ -449,25 +465,42 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pCreateInfo->surface;
- if (NULL != icd_surface->real_icd_surfaces) {
- if ((VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
- // We found the ICD, and there is an ICD KHR surface
- // associated with it, so copy the CreateInfo struct
- // and point it at the ICD's surface.
- VkSwapchainCreateInfoKHR *pCreateCopy = loader_stack_alloc(sizeof(VkSwapchainCreateInfoKHR));
- if (NULL == pCreateCopy) {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- memcpy(pCreateCopy, pCreateInfo, sizeof(VkSwapchainCreateInfoKHR));
- pCreateCopy->surface = icd_surface->real_icd_surfaces[icd_index];
- return icd_term->dispatch.CreateSwapchainKHR(device, pCreateCopy, pAllocator, pSwapchain);
- }
- }
- return icd_term->dispatch.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
+ if (NULL == icd_term || NULL == dev) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkCreateSwapchainKHR Terminator: device handle. This is likely the result of a "
+ "layer wrapping device handles and failing to unwrap them in all functions. "
+ "[VUID-vkCreateSwapchainKHR-device-parameter]");
+ abort(); /* Intentionally fail so user can correct issue. */
}
- return VK_SUCCESS;
+ if (NULL == pCreateInfo) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkCreateSwapchainKHR: Invalid pCreateInfo pointer [VUID-vkCreateSwapchainKHR-pCreateInfo-parameter]");
+ abort(); /* Intentionally fail so user can correct issue. */
+ }
+ // Need to gracefully handle the function pointer not being found.
+ if (NULL == dev->loader_dispatch.extension_terminator_dispatch.CreateSwapchainKHR) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+ "extension enabled?");
+ return VK_SUCCESS;
+ }
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pCreateInfo->surface;
+ if (NULL != icd_surface->real_icd_surfaces) {
+ if ((VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
+ // We found the ICD, and there is an ICD KHR surface
+ // associated with it, so copy the CreateInfo struct
+ // and point it at the ICD's surface.
+ VkSwapchainCreateInfoKHR *pCreateCopy = loader_stack_alloc(sizeof(VkSwapchainCreateInfoKHR));
+ if (NULL == pCreateCopy) {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ memcpy(pCreateCopy, pCreateInfo, sizeof(VkSwapchainCreateInfoKHR));
+ pCreateCopy->surface = icd_surface->real_icd_surfaces[icd_index];
+ return dev->loader_dispatch.extension_terminator_dispatch.CreateSwapchainKHR(device, pCreateCopy, pAllocator,
+ pSwapchain);
+ }
+ }
+ return dev->loader_dispatch.extension_terminator_dispatch.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
}
// This is the trampoline entrypoint for DestroySwapchainKHR
@@ -646,13 +679,14 @@
if (!loader_inst->wsi_win32_surface_enabled) {
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"VK_KHR_win32_surface extension not enabled. vkGetPhysicalDeviceWin32PresentationSupportKHR not executed!\n");
- return VK_SUCCESS;
+ return VK_FALSE;
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceWin32PresentationSupportKHR) {
+ // return VK_FALSE as this driver doesn't support WSI functionality
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceWin32PresentationSupportKHR!\n");
- abort();
+ return VK_FALSE;
}
return icd_term->dispatch.GetPhysicalDeviceWin32PresentationSupportKHR(phys_dev_term->phys_dev, queueFamilyIndex);
@@ -767,13 +801,14 @@
loader_log(
loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"VK_KHR_wayland_surface extension not enabled. vkGetPhysicalDeviceWaylandPresentationSupportKHR not executed!\n");
- return VK_SUCCESS;
+ return VK_FALSE;
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceWaylandPresentationSupportKHR) {
+ // return VK_FALSE as this driver doesn't support WSI functionality
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceWaylandPresentationSupportKHR!\n");
- abort();
+ return VK_FALSE;
}
return icd_term->dispatch.GetPhysicalDeviceWaylandPresentationSupportKHR(phys_dev_term->phys_dev, queueFamilyIndex, display);
@@ -890,13 +925,14 @@
if (!loader_inst->wsi_xcb_surface_enabled) {
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"VK_KHR_xcb_surface extension not enabled. vkGetPhysicalDeviceXcbPresentationSupportKHR not executed!\n");
- return VK_SUCCESS;
+ return VK_FALSE;
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceXcbPresentationSupportKHR) {
+ // return VK_FALSE as this driver doesn't support WSI functionality
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceXcbPresentationSupportKHR!\n");
- abort();
+ return VK_FALSE;
}
return icd_term->dispatch.GetPhysicalDeviceXcbPresentationSupportKHR(phys_dev_term->phys_dev, queueFamilyIndex, connection,
@@ -1012,13 +1048,14 @@
if (!loader_inst->wsi_xlib_surface_enabled) {
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"VK_KHR_xlib_surface extension not enabled. vkGetPhysicalDeviceXlibPresentationSupportKHR not executed!\n");
- return VK_SUCCESS;
+ return VK_FALSE;
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceXlibPresentationSupportKHR) {
+ // return VK_FALSE as this driver doesn't support WSI functionality
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceXlibPresentationSupportKHR!\n");
- abort();
+ return VK_FALSE;
}
return icd_term->dispatch.GetPhysicalDeviceXlibPresentationSupportKHR(phys_dev_term->phys_dev, queueFamilyIndex, dpy, visualID);
@@ -1137,13 +1174,14 @@
loader_log(
loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"VK_EXT_directfb_surface extension not enabled. vkGetPhysicalDeviceDirectFBPresentationSupportKHR not executed!\n");
- return VK_SUCCESS;
+ return VK_FALSE;
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceDirectFBPresentationSupportEXT) {
+ // return VK_FALSE as this driver doesn't support WSI functionality
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceDirectFBPresentationSupportEXT!\n");
- abort();
+ return VK_FALSE;
}
return icd_term->dispatch.GetPhysicalDeviceDirectFBPresentationSupportEXT(phys_dev_term->phys_dev, queueFamilyIndex, dfb);
@@ -1656,13 +1694,14 @@
if (!loader_inst->wsi_screen_surface_enabled) {
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"VK_QNX_screen_surface extension not enabled. vkGetPhysicalDeviceScreenPresentationSupportQNX not executed!\n");
- return VK_SUCCESS;
+ return VK_FALSE;
}
if (NULL == icd_term->dispatch.GetPhysicalDeviceScreenPresentationSupportQNX) {
+ // return VK_FALSE as this driver doesn't support WSI functionality
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceScreenPresentationSupportQNX!\n");
- abort();
+ return VK_FALSE;
}
return icd_term->dispatch.GetPhysicalDeviceScreenPresentationSupportQNX(phys_dev_term->phys_dev, queueFamilyIndex, window);
@@ -1780,7 +1819,10 @@
if (NULL == icd_term->dispatch.GetPhysicalDeviceDisplayPropertiesKHR) {
loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceDisplayPropertiesKHR!\n");
- *pPropertyCount = 0;
+ // return 0 for property count as this driver doesn't support WSI functionality
+ if (pPropertyCount) {
+ *pPropertyCount = 0;
+ }
return VK_SUCCESS;
}
@@ -1818,7 +1860,10 @@
if (NULL == icd_term->dispatch.GetPhysicalDeviceDisplayPlanePropertiesKHR) {
loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
"ICD for selected physical device does not export vkGetPhysicalDeviceDisplayPlanePropertiesKHR!\n");
- *pPropertyCount = 0;
+ // return 0 for property count as this driver doesn't support WSI functionality
+ if (pPropertyCount) {
+ *pPropertyCount = 0;
+ }
return VK_SUCCESS;
}
@@ -1856,7 +1901,10 @@
if (NULL == icd_term->dispatch.GetDisplayPlaneSupportedDisplaysKHR) {
loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
"ICD for selected physical device does not export vkGetDisplayPlaneSupportedDisplaysKHR!\n");
- *pDisplayCount = 0;
+ // return 0 for property count as this driver doesn't support WSI functionality
+ if (pDisplayCount) {
+ *pDisplayCount = 0;
+ }
return VK_SUCCESS;
}
@@ -1895,7 +1943,10 @@
if (NULL == icd_term->dispatch.GetDisplayModePropertiesKHR) {
loader_log(loader_inst, VULKAN_LOADER_WARN_BIT, 0,
"ICD for selected physical device does not export vkGetDisplayModePropertiesKHR!\n");
- *pPropertyCount = 0;
+ // return 0 for property count as this driver doesn't support WSI functionality
+ if (pPropertyCount) {
+ *pPropertyCount = 0;
+ }
return VK_SUCCESS;
}
@@ -2086,27 +2137,37 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.CreateSharedSwapchainsKHR) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pCreateInfos->surface;
- if (NULL != icd_surface->real_icd_surfaces) {
- if ((VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
- // We found the ICD, and there is an ICD KHR surface
- // associated with it, so copy the CreateInfo struct
- // and point it at the ICD's surface.
- VkSwapchainCreateInfoKHR *pCreateCopy = loader_stack_alloc(sizeof(VkSwapchainCreateInfoKHR) * swapchainCount);
- if (NULL == pCreateCopy) {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- memcpy(pCreateCopy, pCreateInfos, sizeof(VkSwapchainCreateInfoKHR) * swapchainCount);
- for (uint32_t sc = 0; sc < swapchainCount; sc++) {
- pCreateCopy[sc].surface = icd_surface->real_icd_surfaces[icd_index];
- }
- return icd_term->dispatch.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateCopy, pAllocator, pSwapchains);
- }
- }
- return icd_term->dispatch.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
+ if (NULL == icd_term || NULL == dev) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkCreateSharedSwapchainsKHR Terminator: Invalid device handle. This is likely the result of a "
+ "layer wrapping device handles and failing to unwrap them in all functions. "
+ "[VUID-vkCreateSharedSwapchainsKHR-device-parameter]");
+ abort(); /* Intentionally fail so user can correct issue. */
}
- return VK_SUCCESS;
+ if (NULL == dev->loader_dispatch.extension_terminator_dispatch.CreateSharedSwapchainsKHR) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT, 0,
+ "vkCreateSharedSwapchainsKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the "
+ "VK_KHR_display_swapchain extension enabled?");
+ return VK_SUCCESS;
+ }
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pCreateInfos->surface;
+ if ((VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
+ // We found the ICD, and there is an ICD KHR surface
+ // associated with it, so copy the CreateInfo struct
+ // and point it at the ICD's surface.
+ VkSwapchainCreateInfoKHR *pCreateCopy = loader_stack_alloc(sizeof(VkSwapchainCreateInfoKHR) * swapchainCount);
+ if (NULL == pCreateCopy) {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ memcpy(pCreateCopy, pCreateInfos, sizeof(VkSwapchainCreateInfoKHR) * swapchainCount);
+ for (uint32_t sc = 0; sc < swapchainCount; sc++) {
+ pCreateCopy[sc].surface = icd_surface->real_icd_surfaces[icd_index];
+ }
+ return dev->loader_dispatch.extension_terminator_dispatch.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateCopy,
+ pAllocator, pSwapchains);
+ }
+ return dev->loader_dispatch.extension_terminator_dispatch.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos,
+ pAllocator, pSwapchains);
}
LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
@@ -2138,15 +2199,25 @@
uint32_t icd_index = 0;
struct loader_device *dev;
struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
- if (NULL != icd_term && NULL != icd_term->dispatch.GetDeviceGroupSurfacePresentModesKHR) {
- VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
- if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
- return icd_term->dispatch.GetDeviceGroupSurfacePresentModesKHR(device, icd_surface->real_icd_surfaces[icd_index],
- pModes);
- }
- return icd_term->dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+ if (NULL == icd_term || NULL == dev) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
+ "vkGetDeviceGroupSurfacePresentModesKHR: Invalid device "
+ "[VUID-vkGetDeviceGroupSurfacePresentModesKHR-device-parameter]");
+ abort(); /* Intentionally fail so user can correct issue. */
}
- return VK_SUCCESS;
+ if (NULL == dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModesKHR) {
+ loader_log(NULL, VULKAN_LOADER_ERROR_BIT, 0,
+ "vkGetDeviceGroupSurfacePresentModesKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was either "
+ "Vulkan 1.1 and VK_KHR_swapchain enabled or both the VK_KHR_device_group and VK_KHR_surface "
+ "extensions enabled when using Vulkan 1.0?");
+ return VK_SUCCESS;
+ }
+ VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
+ if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)(uintptr_t)NULL != icd_surface->real_icd_surfaces[icd_index]) {
+ return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModesKHR(
+ device, icd_surface->real_icd_surfaces[icd_index], pModes);
+ }
+ return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
}
LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice,
@@ -2172,7 +2243,11 @@
if (NULL == icd_term->dispatch.GetPhysicalDevicePresentRectanglesKHR) {
loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
"ICD associated with VkPhysicalDevice does not support GetPhysicalDevicePresentRectanglesKHX");
- abort();
+ // return as this driver doesn't support WSI functionality
+ if (pRectCount) {
+ *pRectCount = 0;
+ }
+ return VK_SUCCESS;
}
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(surface);
uint8_t icd_index = phys_dev_term->icd_index;
@@ -2394,8 +2469,15 @@
loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
"vkGetDisplayPlaneCapabilities2KHR: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
+ // If the icd doesn't support VK_KHR_display, then there are no capabilities
+ if (NULL == icd_term->dispatch.GetDisplayPlaneCapabilitiesKHR) {
+ if (pCapabilities) {
+ memset(&pCapabilities->capabilities, 0, sizeof(VkDisplayPlaneCapabilitiesKHR));
+ }
+ return VK_SUCCESS;
+ }
+
// Just call into the old version of the function.
- // If the icd doesn't support VK_KHR_display, there are zero planes and this call is invalid (and will crash)
return icd_term->dispatch.GetDisplayPlaneCapabilitiesKHR(phys_dev_term->phys_dev, pDisplayPlaneInfo->mode,
pDisplayPlaneInfo->planeIndex, &pCapabilities->capabilities);
}
@@ -2554,6 +2636,14 @@
if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)(uintptr_t)(icd_surface->real_icd_surfaces[icd_index])) {
surface = icd_surface->real_icd_surfaces[icd_index];
}
+
+ // If the icd doesn't support VK_KHR_surface, then there are no capabilities
+ if (NULL == icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR) {
+ if (pSurfaceCapabilities) {
+ memset(&pSurfaceCapabilities->surfaceCapabilities, 0, sizeof(VkSurfaceCapabilitiesKHR));
+ }
+ return VK_SUCCESS;
+ }
VkResult res = icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev_term->phys_dev, surface,
&pSurfaceCapabilities->surfaceCapabilities);
@@ -2626,6 +2716,14 @@
surface = icd_surface->real_icd_surfaces[icd_index];
}
+ // If the icd doesn't support VK_KHR_surface, then there are no formats
+ if (NULL == icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR) {
+ if (pSurfaceFormatCount) {
+ *pSurfaceFormatCount = 0;
+ }
+ return VK_SUCCESS;
+ }
+
if (*pSurfaceFormatCount == 0 || pSurfaceFormats == NULL) {
// Write to pSurfaceFormatCount
return icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(phys_dev_term->phys_dev, surface, pSurfaceFormatCount,
diff --git a/scripts/generate_source.py b/scripts/generate_source.py
index 233e92b..712747b 100755
--- a/scripts/generate_source.py
+++ b/scripts/generate_source.py
@@ -45,8 +45,7 @@
'vk_layer_dispatch_table.h',
'vk_loader_extensions.h',
'vk_loader_extensions.c',
- 'vk_object_types.h',
- 'loader_generated_header_version.cmake']]
+ 'vk_object_types.h']]
repo_dir = common_codegen.repo_relative('loader/generated')
diff --git a/scripts/known_good.json b/scripts/known_good.json
index 6354dbd..5b71481 100644
--- a/scripts/known_good.json
+++ b/scripts/known_good.json
@@ -6,7 +6,7 @@
"sub_dir": "Vulkan-Headers",
"build_dir": "Vulkan-Headers/build",
"install_dir": "Vulkan-Headers/build/install",
- "commit": "v1.3.231"
+ "commit": "v1.3.238"
},
{
"name": "googletest",
@@ -41,4 +41,4 @@
"googletest": "GOOGLETEST_INSTALL_DIR",
"detours": "DETOURS_INSTALL_DIR"
}
-}
\ No newline at end of file
+}
diff --git a/scripts/loader_extension_generator.py b/scripts/loader_extension_generator.py
index e597088..86322f7 100644
--- a/scripts/loader_extension_generator.py
+++ b/scripts/loader_extension_generator.py
@@ -242,11 +242,13 @@
file_data += self.OutputLoaderTerminators()
file_data += self.OutputIcdDispatchTable()
file_data += self.OutputIcdExtensionEnableUnion()
+ file_data += self.OutputDeviceFunctionTerminatorDispatchTable()
elif self.genOpts.filename == 'vk_loader_extensions.c':
file_data += self.OutputUtilitiesInSource()
file_data += self.OutputIcdDispatchTableInit()
file_data += self.OutputLoaderDispatchTables()
+ file_data += self.InitDeviceFunctionTerminatorDispatchTable()
file_data += self.OutputLoaderLookupFunc()
file_data += self.CreateTrampTermFuncs()
file_data += self.InstExtensionGPA()
@@ -445,7 +447,7 @@
protos += '// Extension interception for vkGetDeviceProcAddr function, so we can return\n'
protos += '// an appropriate terminator if this is one of those few device commands requiring\n'
protos += '// a terminator.\n'
- protos += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *pName);\n'
+ protos += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name);\n'
protos += '\n'
protos += '// Dispatch table properly filled in with appropriate terminators for the\n'
protos += '// supported extensions.\n'
@@ -591,12 +593,22 @@
return table
#
+ # Common code between the dispatch table struct and the function filling out said struct
+ def ShouldPrintInIcdDispatchTable(self, cur_cmd, skip_list):
+ return cur_cmd.name == 'vkGetDeviceProcAddr' or \
+ (cur_cmd.handle_type not in ['VkDevice', 'VkCommandBuffer', 'VkQueue'] and cur_cmd.name not in skip_list)
+
+ #
# Create a dispatch table from the appropriate list and return it as a string
def OutputIcdDispatchTable(self):
commands = []
table = ''
cur_extension_name = ''
+ skip_commands = ['vkGetInstanceProcAddr',
+ 'vkEnumerateDeviceLayerProperties',
+ ]
+
table += '// ICD function pointer dispatch table\n'
table += 'struct loader_icd_term_dispatch {\n'
@@ -607,10 +619,7 @@
commands = self.ext_commands
for cur_cmd in commands:
- is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
- if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and
- (cur_cmd.name != 'vkGetInstanceProcAddr' and cur_cmd.name != 'vkEnumerateDeviceLayerProperties')):
-
+ if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_commands)):
if cur_cmd.ext_name != cur_extension_name:
if 'VK_VERSION_' in cur_cmd.ext_name:
table += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
@@ -669,8 +678,7 @@
required = False
for cur_cmd in commands:
- is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
- if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and (cur_cmd.name not in skip_gipa_commands)):
+ if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_gipa_commands)):
if cur_cmd.ext_name != cur_extension_name:
if 'VK_VERSION_' in cur_cmd.ext_name:
@@ -919,7 +927,7 @@
return tables
#
- # Create the appropriate trampoline (and possibly terminator) functinos
+ # Create the appropriate trampoline (and possibly terminator) functions
def CreateTrampTermFuncs(self):
entries = []
funcs = ''
@@ -1195,40 +1203,6 @@
count += 1
funcs += ');\n'
- elif has_surface == 1 and not (ext_cmd.handle_type == 'VkPhysicalDevice' or ext_cmd.handle_type == 'VkInstance'):
- funcs += ' uint32_t icd_index = 0;\n'
- funcs += ' struct loader_device *dev;\n'
- funcs += ' struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);\n'
- funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.%s) {\n' % base_name
- funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)%s;\n' % (surface_var_name)
- funcs += ' if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)NULL != icd_surface->real_icd_surfaces[icd_index]) {\n'
- funcs += ' %sicd_term->dispatch.%s(' % (return_prefix, base_name)
- count = 0
- for param in ext_cmd.params:
- if count != 0:
- funcs += ', '
-
- if param.type == 'VkSurfaceKHR':
- funcs += 'icd_surface->real_icd_surfaces[icd_index]'
- else:
- funcs += param.name
-
- count += 1
- funcs += ');\n'
- if not has_return_type:
- funcs += ' return;\n'
- funcs += ' }\n'
- funcs += ' %sicd_term->dispatch.%s(' % (return_prefix, base_name)
- count = 0
- for param in ext_cmd.params:
- if count != 0:
- funcs += ', '
- funcs += param.name
- count += 1
- funcs += ');\n'
- funcs += ' }\n'
- if has_return_type:
- funcs += ' return VK_SUCCESS;\n'
elif ext_cmd.handle_type == 'VkInstance':
funcs += ' struct loader_instance *inst = loader_get_instance(%s);\n' % (instance_var_name)
@@ -1239,83 +1213,54 @@
funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n'
funcs += ' }\n'
funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
- elif 'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name or 'DebugUtilsLabel' in ext_cmd.name:
- funcs += ' uint32_t icd_index = 0;\n'
- funcs += ' struct loader_device *dev;\n'
- funcs += ' struct loader_icd_term *icd_term = loader_get_icd_and_device(%s, &dev, &icd_index);\n' % (ext_cmd.params[0].name)
- funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.'
- funcs += base_name
- funcs += ') {\n'
- if 'DebugMarkerSetObjectName' in ext_cmd.name:
- funcs += ' VkDebugMarkerObjectNameInfoEXT local_name_info;\n'
- funcs += ' memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n'
- funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n'
- funcs += ' if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
- funcs += ' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->object;\n'
- funcs += ' local_name_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
- funcs += ' // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
- funcs += ' } else if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
- funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
- funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->object;\n'
- funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
- funcs += ' local_name_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
- funcs += ' }\n'
+ elif ext_cmd.ext_name in ['VK_EXT_debug_utils', 'VK_EXT_debug_marker']:
+ if ext_cmd.name in ['vkDebugMarkerSetObjectNameEXT', 'vkDebugMarkerSetObjectTagEXT', 'vkSetDebugUtilsObjectNameEXT' , 'vkSetDebugUtilsObjectTagEXT']:
+
+ is_debug_utils = ext_cmd.ext_name == "VK_EXT_debug_utils"
+ debug_struct_name = ext_cmd.params[1].name
+ local_struct = 'local_name_info' if 'ObjectName' in ext_cmd.name else 'local_tag_info'
+ member_name = 'objectHandle' if is_debug_utils else 'object'
+ phys_dev_check = 'VK_OBJECT_TYPE_PHYSICAL_DEVICE' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT'
+ surf_check = 'VK_OBJECT_TYPE_SURFACE_KHR' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT'
+ funcs += ' uint32_t icd_index = 0;\n'
+ funcs += ' struct loader_device *dev;\n'
+ funcs += f' struct loader_icd_term *icd_term = loader_get_icd_and_device({ ext_cmd.params[0].name}, &dev, &icd_index);\n'
+ funcs += f' if (NULL == icd_term || NULL == dev) {{\n'
+ funcs += f' loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "{ext_cmd.name[2:]}: Invalid device handle");\n'
+ funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n'
+ funcs += ' }\n'
+ funcs += f' { ext_cmd.params[1].type} {local_struct};\n'
+ funcs += f' memcpy(&{local_struct}, {debug_struct_name}, sizeof({ ext_cmd.params[1].type}));\n'
+ funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n'
+ funcs += f' if ({debug_struct_name}->objectType == {phys_dev_check}) {{\n'
+ funcs += f' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t){debug_struct_name}->{member_name};\n'
+ funcs += f' {local_struct}.{member_name} = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
+ funcs += ' // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
+ funcs += f' }} else if ({debug_struct_name}->objectType == {surf_check}) {{\n'
+ funcs += ' if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {\n'
+ funcs += f' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t){debug_struct_name}->{member_name};\n'
+ funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
+ funcs += f' {local_struct}.{member_name} = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
funcs += ' }\n'
funcs += ' }\n'
- elif 'DebugMarkerSetObjectTag' in ext_cmd.name:
- funcs += ' VkDebugMarkerObjectTagInfoEXT local_tag_info;\n'
- funcs += ' memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n'
- funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n'
- funcs += ' if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
- funcs += ' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->object;\n'
- funcs += ' local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
- funcs += ' // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
- funcs += ' } else if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
- funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
- funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->object;\n'
- funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
- funcs += ' local_tag_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
- funcs += ' }\n'
- funcs += ' }\n'
- funcs += ' }\n'
- elif 'SetDebugUtilsObjectName' in ext_cmd.name:
- funcs += ' VkDebugUtilsObjectNameInfoEXT local_name_info;\n'
- funcs += ' memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n'
- funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n'
- funcs += ' if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
- funcs += ' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->objectHandle;\n'
- funcs += ' local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
- funcs += ' // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
- funcs += ' } else if (pNameInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
- funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
- funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->objectHandle;\n'
- funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
- funcs += ' local_name_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
- funcs += ' }\n'
- funcs += ' }\n'
- funcs += ' }\n'
- elif 'SetDebugUtilsObjectTag' in ext_cmd.name:
- funcs += ' VkDebugUtilsObjectTagInfoEXT local_tag_info;\n'
- funcs += ' memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n'
- funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n'
- funcs += ' if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
- funcs += ' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->objectHandle;\n'
- funcs += ' local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
- funcs += ' // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
- funcs += ' } else if (pTagInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
- funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
- funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->objectHandle;\n'
- funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
- funcs += ' local_tag_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
- funcs += ' }\n'
- funcs += ' }\n'
- funcs += ' }\n'
- funcs += ' '
+ funcs += ' }\n'
+ funcs += ' // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports\n'
+ funcs += ' // debug utils but the driver does not.\n'
+ funcs += f' if (NULL == dev->loader_dispatch.extension_terminator_dispatch.{ext_cmd.name[2:]})\n return VK_SUCCESS;\n'
+ dispatch = 'dev->loader_dispatch.'
+ else:
+ funcs += f' struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch({ext_cmd.params[0].name});\n'
+ funcs += f' if (NULL == dispatch_table) {{\n'
+ funcs += f' loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "{ext_cmd.ext_name}: Invalid device handle");\n'
+ funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n'
+ funcs += ' }\n'
+ funcs += ' // Only call down if the device supports the function\n'
+ funcs += f' if (NULL != dispatch_table->extension_terminator_dispatch.{base_name})\n '
+ dispatch = 'dispatch_table->'
+ funcs += ' '
if has_return_type:
funcs += 'return '
- funcs += 'icd_term->dispatch.'
- funcs += base_name
- funcs += '('
+ funcs += f'{dispatch}extension_terminator_dispatch.{base_name}('
count = 0
for param in ext_cmd.params:
if count != 0:
@@ -1334,10 +1279,6 @@
count += 1
funcs += ');\n'
- if has_return_type:
- funcs += ' } else {\n'
- funcs += ' return VK_SUCCESS;\n'
- funcs += ' }\n'
else:
funcs += '#error("Unknown error path!");\n'
@@ -1358,6 +1299,7 @@
if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES:
funcs += ' if (disp->' + base_name + ' != NULL) {\n'
+ funcs += ' '
funcs += return_prefix
funcs += 'disp->'
funcs += base_name
@@ -1481,60 +1423,115 @@
# extension entrypoints and return it as a string
def DeviceExtensionGetTerminator(self):
term_func = ''
- cur_extension_name = ''
term_func += '// Some device commands still need a terminator because the loader needs to unwrap something about them.\n'
term_func += '// In many cases, the item needing unwrapping is a VkPhysicalDevice or VkSurfaceKHR object. But there may be other items\n'
term_func += '// in the future.\n'
- term_func += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *pName) {\n'
- term_func += ' PFN_vkVoidFunction addr = NULL;\n'
-
- count = 0
- is_extension = False
+ term_func += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name) {\n'
+ term_func += ''' *found_name = false;
+ if (!name || name[0] != 'v' || name[1] != 'k') {
+ return NULL;
+ }
+ name += 2;
+'''
last_protect = None
+ last_ext = None
for ext_cmd in self.ext_commands:
if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
- if ext_cmd.ext_name != cur_extension_name:
- if count > 0:
- count = 0;
- term_func += ' }\n'
- if is_extension:
- term_func += ' }\n'
- is_extension = False
-
- if 'VK_VERSION_' in ext_cmd.ext_name:
- term_func += '\n // ---- Core %s commands\n' % ext_cmd.ext_name[11:]
- else:
- last_protect = ext_cmd.protect
- if ext_cmd.protect is not None:
- term_func += '#ifdef %s\n' % ext_cmd.protect
- term_func += '\n // ---- %s extension commands\n' % ext_cmd.ext_name
- if ext_cmd.require:
- term_func += ' if (dev->extensions.%s_enabled && dev->extensions.%s_enabled) {\n' % (ext_cmd.ext_name[3:].lower(), ext_cmd.require[3:].lower())
- else:
- term_func += ' if (dev->extensions.%s_enabled) {\n' % ext_cmd.ext_name[3:].lower()
- is_extension = True
- cur_extension_name = ext_cmd.ext_name
-
- if count == 0:
- term_func += ' if'
+ if 'VK_VERSION_' in ext_cmd.ext_name:
+ term_func += f' // ---- Core {ext_cmd.ext_name[11:]} commands\n'
else:
- term_func += ' } else if'
+ last_protect = ext_cmd.protect
+ if ext_cmd.protect is not None:
+ term_func += f'#ifdef {ext_cmd.protect}\n'
+ if (last_ext != ext_cmd.ext_name):
+ term_func += f' // ---- {ext_cmd.ext_name} extension commands\n'
+ last_ext = ext_cmd.ext_name
- term_func += '(!strcmp(pName, "%s")) {\n' % (ext_cmd.name)
- term_func += ' addr = (PFN_vkVoidFunction)terminator_%s;\n' % (ext_cmd.name[2:])
+ term_func += f' if (!strcmp(name, "{ext_cmd.name[2:]}")) {{\n'
+ term_func += f' *found_name = true;\n'
+ if ext_cmd.require:
+ term_func += f' return dev->extensions.{ext_cmd.ext_name[3:].lower()}_enabled && dev->extensions.{ext_cmd.require[3:].lower()}_enabled ?\n'
+ else:
+ term_func += f' return dev->extensions.{ext_cmd.ext_name[3:].lower()}_enabled ?\n'
+ term_func += f' (PFN_vkVoidFunction)terminator_{(ext_cmd.name[2:])} : NULL;\n'
+ term_func += f' }}\n'
+
+ if last_protect is not None:
+ term_func += '#endif // %s\n' % ext_cmd.protect
+
+ term_func += ' return NULL;\n'
+ term_func += '}\n\n'
+
+ return term_func
+
+ #
+ # Create a dispatch table solely for device functions which have custom terminators
+ def OutputDeviceFunctionTerminatorDispatchTable(self):
+ term_func = ''
+ term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n'
+ term_func += '// device function. This is used in the terminators themselves.\n'
+ term_func += 'struct loader_device_terminator_dispatch {\n'
+
+ last_protect = None
+ last_ext = None
+ for ext_cmd in self.ext_commands:
+ if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
+ if 'VK_VERSION_' in ext_cmd.ext_name:
+ term_func += f' // ---- Core {ext_cmd.ext_name[11:]} commands\n'
+ else:
+ last_protect = ext_cmd.protect
+ if ext_cmd.protect is not None:
+ term_func += f'#ifdef {ext_cmd.protect}\n'
+ if (last_ext != ext_cmd.ext_name):
+ term_func += f' // ---- {ext_cmd.ext_name} extension commands\n'
+ last_ext = ext_cmd.ext_name
+
+ term_func += f' PFN_{ext_cmd.name} {ext_cmd.name[2:]};\n'
+
+ if last_protect is not None:
+ term_func += '#endif // %s\n' % ext_cmd.protect
+
+ term_func += '}; \n\n'
+
+ return term_func
+
+ #
+ # Create code to initialize a dispatch table from the appropriate list of
+ # extension entrypoints and return it as a string
+ def InitDeviceFunctionTerminatorDispatchTable(self):
+ term_func = ''
+
+ term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n'
+ term_func += '// device function. This is used in the terminators themselves.\n'
+ term_func += 'void init_extension_device_proc_terminator_dispatch(struct loader_device *dev) {\n'
+ term_func += ' struct loader_device_terminator_dispatch* dispatch = &dev->loader_dispatch.extension_terminator_dispatch;\n'
+ term_func += ' PFN_vkGetDeviceProcAddr gpda = (PFN_vkGetDeviceProcAddr)dev->phys_dev_term->this_icd_term->dispatch.GetDeviceProcAddr;\n'
+ last_protect = None
+ last_ext = None
+ for ext_cmd in self.ext_commands:
+ if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
+ if 'VK_VERSION_' in ext_cmd.ext_name:
+ term_func += f' // ---- Core {ext_cmd.ext_name[11:]} commands\n'
+ else:
+ last_protect = ext_cmd.protect
+ if ext_cmd.protect is not None:
+ term_func += f'#ifdef {ext_cmd.protect}\n'
+ if (last_ext != ext_cmd.ext_name):
+ term_func += f' // ---- {ext_cmd.ext_name} extension commands\n'
+ last_ext = ext_cmd.ext_name
- count += 1
+ if ext_cmd.require:
+ term_func += f' if (dev->extensions.{ext_cmd.ext_name[3:].lower()}_enabled && dev->extensions.{ext_cmd.require[3:].lower()}_enabled)\n'
+ term_func += f' dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n'
+ else:
+ term_func += f' if (dev->extensions.{ext_cmd.ext_name[3:].lower()}_enabled)\n'
+ term_func += f' dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n'
- if count > 0:
- term_func += ' }\n'
- if is_extension:
- term_func += ' }\n'
- if last_protect is not None:
- term_func += '#endif // %s\n' % ext_cmd.protect
+ if last_protect is not None:
+ term_func += '#endif // %s\n' % ext_cmd.protect
- term_func += ' return addr;\n'
term_func += '}\n\n'
return term_func
diff --git a/scripts/loader_genvk.py b/scripts/loader_genvk.py
index 5d79f44..3489599 100644
--- a/scripts/loader_genvk.py
+++ b/scripts/loader_genvk.py
@@ -239,30 +239,6 @@
helper_file_type = 'object_types_header')
]
- # Loader Generated Header Version Options for loader_generated_header_version.cmake
- genOpts['loader_generated_header_version.cmake'] = [
- LoaderVersioningGenerator,
- LoaderVersioningGeneratorOptions(
- conventions = conventions,
- filename = 'loader_generated_header_version.cmake',
- directory = directory,
- genpath = None,
- apiname = 'vulkan',
- profile = None,
- versions = featuresPat,
- emitversions = featuresPat,
- defaultExtensions = 'vulkan',
- addExtensions = addExtensionsPat,
- removeExtensions = removeExtensionsPat,
- emitExtensions = emitExtensionsPat,
- prefixText = prefixStrings + vkPrefixStrings,
- apicall = 'VKAPI_ATTR ',
- apientry = 'VKAPI_CALL ',
- apientryp = 'VKAPI_PTR *',
- alignFuncParam = 48,
- expandEnumerants = False)
- ]
-
# Create an API generator and corresponding generator options based on
# the requested target and command line options.
# This is encapsulated in a function so it can be profiled and/or timed.
@@ -381,7 +357,6 @@
from dispatch_table_helper_generator import DispatchTableHelperOutputGenerator, DispatchTableHelperOutputGeneratorOptions
from helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions
from loader_extension_generator import LoaderExtensionOutputGenerator, LoaderExtensionGeneratorOptions
- from loader_versioning_generator import LoaderVersioningGenerator, LoaderVersioningGeneratorOptions
# Temporary workaround for vkconventions python2 compatibility
import abc; abc.ABC = abc.ABCMeta('ABC', (object,), {})
diff --git a/scripts/loader_versioning_generator.py b/scripts/loader_versioning_generator.py
deleted file mode 100644
index 821cfbc..0000000
--- a/scripts/loader_versioning_generator.py
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2021 The Khronos Group Inc.
-# Copyright (c) 2021 Valve Corporation
-# Copyright (c) 2021 LunarG, Inc.
-# Copyright (c) 2021 Google 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: Charles Giessen <charles@lunarg.com>
-
-import os,re,sys
-import xml.etree.ElementTree as etree
-from generator import *
-from collections import namedtuple
-from common_codegen import *
-
-#
-# LoaderVersioningGeneratorOptions - subclass of GeneratorOptions.
-class LoaderVersioningGeneratorOptions(GeneratorOptions):
- def __init__(self,
- conventions = None,
- filename = None,
- directory = '.',
- genpath = None,
- apiname = None,
- profile = None,
- versions = '.*',
- emitversions = '.*',
- defaultExtensions = None,
- addExtensions = None,
- removeExtensions = None,
- emitExtensions = None,
- sortProcedure = regSortFeatures,
- prefixText = "",
- genFuncPointers = True,
- protectFile = True,
- protectFeature = True,
- apicall = '',
- apientry = '',
- apientryp = '',
- alignFuncParam = 0,
- library_name = '',
- expandEnumerants = True):
- GeneratorOptions.__init__(self,
- conventions = conventions,
- filename = filename,
- directory = directory,
- genpath = genpath,
- apiname = apiname,
- profile = profile,
- versions = versions,
- emitversions = emitversions,
- defaultExtensions = defaultExtensions,
- addExtensions = addExtensions,
- removeExtensions = removeExtensions,
- emitExtensions = emitExtensions,
- sortProcedure = sortProcedure)
- self.prefixText = prefixText
- self.genFuncPointers = genFuncPointers
- self.protectFile = protectFile
- self.protectFeature = protectFeature
- self.apicall = apicall
- self.apientry = apientry
- self.apientryp = apientryp
- self.alignFuncParam = alignFuncParam
- self.library_name = library_name
-#
-# LoaderVersioningGenerator - subclass of OutputGenerator. Outputs cmake file containing vulkan version used when generating files
-class LoaderVersioningGenerator(OutputGenerator):
- """Generate helper file based on XML element attributes"""
- def __init__(self,
- errFile = sys.stderr,
- warnFile = sys.stderr,
- diagFile = sys.stdout):
- OutputGenerator.__init__(self, errFile, warnFile, diagFile)
-
- #
- # Called once at the beginning of each run
- def beginFile(self, genOpts):
- OutputGenerator.beginFile(self, genOpts)
- # User-supplied prefix text, if any (list of strings)
- self.library_name = genOpts.library_name
-
- version_major = ''
- version_minor = ''
- version_patch = ''
- for elem in self.registry.reg.find('types').findall('type'):
- if elem.get('category') == 'define':
- if elem.get('name') == 'VK_HEADER_VERSION_COMPLETE':
- # Parses the following string:
- #define <name>VK_HEADER_VERSION_COMPLETE</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 2, VK_HEADER_VERSION)</type>
- # The 0th index is the VARIANT version, 1st & 2nd are the Major & Minor
- version_major = re.findall("[0-9]+", ''.join(elem.itertext()))[1]
- version_minor = re.findall("[0-9]+", ''.join(elem.itertext()))[2]
- if elem.get('name') == 'VK_HEADER_VERSION':
- # Parses the following string:
- #define <name>VK_HEADER_VERSION</name> 189</type>
- version_patch = re.findall("[0-9]+", ''.join(elem.itertext()))[0]
-
- # File Comment
- file_comment = '# *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
- file_comment += '# See loader_versioning_generator.py for modifications\n'
- write(file_comment, file=self.outFile)
- # Copyright Notice
- cmake_version_copyright = '''############################################################################
-#
-# Copyright (c) 2021 The Khronos Group Inc.
-# Copyright (c) 2021 Valve Corporation
-# Copyright (c) 2021 LunarG, Inc.
-# Copyright (c) 2021 Google 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: Charles Giessen <charles@lunarg.com>
-#
-############################################################################
-'''
- write(cmake_version_copyright, file=self.outFile)
- write(f'set(LOADER_GENERATED_HEADER_VERSION \"{version_major}.{version_minor}.{version_patch}\")', file=self.outFile)
-
- #
- # Write generated file content to output file
- def endFile(self):
- dest_file = ''
- # Remove blank lines at EOF
- if dest_file.endswith('\n'):
- dest_file = dest_file[:-1]
- write(dest_file, file=self.outFile)
- # Finish processing in superclass
- OutputGenerator.endFile(self)
\ No newline at end of file
diff --git a/scripts/parse_asm_values.py b/scripts/parse_asm_values.py
new file mode 100644
index 0000000..df7a046
--- /dev/null
+++ b/scripts/parse_asm_values.py
@@ -0,0 +1,99 @@
+#!/usr/bin/python3 -i
+#
+# Copyright (c) 2022 The Khronos Group Inc.
+# 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.
+#
+# Author: Charles Giessen <charles@lunarg.com>
+
+# This script reads in the 'intermediate output' of a compiler to look for sizeof/offsetof information
+# necessary for the assembler portions of the loader. This is achieved by forcing the compiler to output
+# the intermediate assembly output and looking for specific patterns which contain the relevant information
+
+import sys
+import os.path
+from os.path import exists
+import re
+
+
+# Where to write the "gen_defines.asm" file
+destination_file = sys.argv[1]
+# The location the build system puts the intermediate asm file which depends on the compiler
+source_asm_file = sys.argv[2]
+# Whether we are using "MASM" or "GAS" for the assembler
+assembler_type = sys.argv[3]
+# Whether we are using gcc, clang, or msvc
+compiler = sys.argv[4]
+# taken from CMAKE_SYSTEM_PROCESSOR - x86_64, aarch64, or x86
+# Only used with GAS - MASM doesn't need this, as it has its own way to determine x86 vs x64
+arch = sys.argv[5]
+
+if destination_file is None or source_asm_file is None or assembler_type is None or compiler is None or arch is None:
+ print("Required command line arguments were not provided")
+ sys.exit(1)
+
+defines = ["VULKAN_LOADER_ERROR_BIT",
+ "PTR_SIZE",
+ "CHAR_PTR_SIZE",
+ "FUNCTION_OFFSET_INSTANCE",
+ "PHYS_DEV_OFFSET_INST_DISPATCH",
+ "PHYS_DEV_OFFSET_PHYS_DEV_TRAMP",
+ "ICD_TERM_OFFSET_PHYS_DEV_TERM",
+ "PHYS_DEV_OFFSET_PHYS_DEV_TERM",
+ "INSTANCE_OFFSET_ICD_TERM",
+ "DISPATCH_OFFSET_ICD_TERM",
+ "EXT_OFFSET_DEVICE_DISPATCH" ]
+
+try:
+ with open(source_asm_file, 'r') as f:
+ asm_intermediate_file = f.read()
+except IOError:
+ print("Could not open assembler file:", source_asm_file)
+ sys.exit(1)
+
+with open(destination_file, "w", encoding="utf-8") as dest:
+ if assembler_type == "MASM":
+ # special case vulkan error bit due to it not appearing in the asm - its defined in the header as 8 so it shouldn't change
+ dest.write("VULKAN_LOADER_ERROR_BIT equ 8;\n")
+ elif assembler_type == "GAS":
+ # let the assembler know which platform to use
+ if arch == "x86_64":
+ dest.write(".set X86_64, 1\n")
+ elif arch == "aarch64":
+ dest.write(".set AARCH_64, 1\n")
+ # Nothing to write in the x86 case
+
+ for d in defines:
+ match = None
+ if compiler == "MSVC":
+ if d == "VULKAN_LOADER_ERROR_BIT":
+ continue # skip due to special case
+ match = re.search(d + " DD [ ]*([0-9a-f]+)H", asm_intermediate_file)
+ elif compiler == "Clang" or compiler == "GNU":
+ match = re.search(d + " = ([0-9]+)", asm_intermediate_file)
+
+ if match:
+ if compiler == "MSVC":
+ value = str(int(match.group(1), 16))
+ elif compiler == "Clang" or compiler == "GNU":
+ value = match.group(1)
+ if assembler_type == "MASM":
+ # MASM uses hex values, decode them here
+ dest.write(d + " equ " + value +";\n")
+ elif assembler_type == "GAS":
+ dest.write(".set " + d + ", " + value + "\n")
+ else:
+ print("Couldn't find ", d)
+ sys.exit(1)
+
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 4e0c8a8..f9677bc 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -43,6 +43,8 @@
set_target_properties(test_regression ${LOADER_STANDARD_CXX_PROPERTIES})
target_compile_definitions(test_regression PUBLIC VK_NO_PROTOTYPES)
+# Threading tests live in separate executabe just for threading tests as it'll need support
+# in the test harness to enable in CI, as thread sanitizer doesn't work with address sanitizer enabled.
add_executable(
test_threading
loader_testing_main.cpp
@@ -74,4 +76,8 @@
endif()
# must happen after the dll's get copied over
-gtest_discover_tests(test_regression PROPERTIES DISCOVERY_TIMEOUT 100)
\ No newline at end of file
+if(NOT CMAKE_CROSSCOMPILING)
+ gtest_discover_tests(test_regression PROPERTIES DISCOVERY_TIMEOUT 100)
+else()
+ gtest_add_tests(TARGET test_regression)
+endif()
diff --git a/tests/framework/CMakeLists.txt b/tests/framework/CMakeLists.txt
index 75bbf49..c04ebae 100644
--- a/tests/framework/CMakeLists.txt
+++ b/tests/framework/CMakeLists.txt
@@ -41,6 +41,8 @@
target_link_options(testing_framework_util PUBLIC -fsanitize=thread)
target_compile_options(vulkan PUBLIC -fsanitize=thread)
target_link_options(vulkan PUBLIC -fsanitize=thread)
+ target_compile_options(gtest PUBLIC -fsanitize=thread)
+ target_link_options(gtest PUBLIC -fsanitize=thread)
endif()
endif()
@@ -49,7 +51,6 @@
target_compile_options(testing_framework_util PUBLIC /wd4458)
endif()
-include(CMakeParseArguments)
function(AddSharedLibrary LIBRARY_NAME)
set(singleValueArgs DEF_FILE)
set(multiValueArgs SOURCES DEFINITIONS)
@@ -83,17 +84,21 @@
PRE_BUILD
COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "${CMAKE_CURRENT_BINARY_DIR}/framework_config_$<CONFIG>.h" "${CMAKE_CURRENT_BINARY_DIR}/framework_config.h"
VERBATIM
- PRE_BUILD
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/framework_config_$<CONFIG>.h"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/framework_config.h"
COMMENT "creating framework_config.h file ({event: PRE_BUILD}, {filename: framework_config.h })"
)
add_custom_target (generate_framework_config DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/framework_config.h")
+add_dependencies (generate_framework_config vulkan)
add_dependencies (testing_framework_util generate_framework_config)
add_library(testing_dependencies STATIC test_environment.cpp test_environment.h)
target_link_libraries(testing_dependencies
PUBLIC gtest Vulkan::Headers testing_framework_util shim-library)
-target_include_directories(testing_dependencies PUBLIC ${CMAKE_BINARY_DIR}/tests/framework)
+target_include_directories(testing_dependencies PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_compile_definitions(testing_dependencies PUBLIC "GTEST_LINKED_AS_SHARED_LIBRARY=1")
set_target_properties(testing_dependencies ${LOADER_STANDARD_CXX_PROPERTIES})
+if (APPLE AND BUILD_STATIC_LOADER)
+ target_compile_definitions(testing_dependencies PUBLIC "BUILD_STATIC_LOADER=1")
+ target_link_libraries(testing_dependencies PUBLIC vulkan)
+endif()
\ No newline at end of file
diff --git a/tests/framework/data/VkLayer_complex_file.json b/tests/framework/data/VkLayer_complex_file.json
new file mode 100644
index 0000000..dde37e3
--- /dev/null
+++ b/tests/framework/data/VkLayer_complex_file.json
@@ -0,0 +1,741 @@
+{
+ "file_format_version": "1.2.0",
+ "layer": {
+ "test_code_description": "This file is literally a copy of an installed Validation layer manifest file for linux. It was chosen because it contains a lot of complex json structures that aren't present in the test framework's generated json, so exercises cJSON better",
+ "name": "VK_LAYER_KHRONOS_validation",
+ "type": "GLOBAL",
+ "library_path": "libVkLayer_khronos_validation.so",
+ "api_version": "1.3.231",
+ "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_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": "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.",
+ "platforms": [
+ "WINDOWS",
+ "LINUX",
+ "MACOS"
+ ],
+ "status": "STABLE",
+ "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"
+ ]
+ }
+ ]
+ },
+ {
+ "label": "Best Practices",
+ "description": "Provides warnings on valid API usage that is potential API misuse.",
+ "platforms": [
+ "WINDOWS",
+ "LINUX",
+ "MACOS",
+ "ANDROID"
+ ],
+ "status": "STABLE",
+ "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.",
+ "platforms": [
+ "WINDOWS",
+ "LINUX",
+ "MACOS",
+ "ANDROID"
+ ],
+ "status": "STABLE",
+ "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"
+ ],
+ "status": "STABLE",
+ "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": "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": "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": "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": "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": "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": "VALIDATION_CHECK_ENABLE_SYNCHRONIZATION_VALIDATION_QUEUE_SUBMIT",
+ "label": "QueueSubmit Synchronization Validation",
+ "description": "Enable synchronization validation between submitted command buffers when Synchronization Validation is enabled.",
+ "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",
+ "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": "ANY",
+ "settings": [
+ {
+ "key": "enables",
+ "value": [
+ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "key": "printf_verbose",
+ "label": "Printf verbose",
+ "description": "Set the verbosity of debug printf messages",
+ "type": "BOOL",
+ "default": false,
+ "platforms": [
+ "WINDOWS",
+ "LINUX"
+ ],
+ "dependence": {
+ "mode": "ANY",
+ "settings": [
+ {
+ "key": "enables",
+ "value": [
+ "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "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": "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_descriptor_indexing",
+ "label": "Check descriptor indexing accesses",
+ "description": "Enable descriptor indexing access checking",
+ "type": "BOOL",
+ "default": true,
+ "platforms": [
+ "WINDOWS",
+ "LINUX"
+ ],
+ "dependence": {
+ "mode": "ANY",
+ "settings": [
+ {
+ "key": "enables",
+ "value": [
+ "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "key": "gpuav_buffer_oob",
+ "label": "Check Out of Bounds ",
+ "description": "Enable buffer out of bounds checking",
+ "type": "BOOL",
+ "default": true,
+ "platforms": [
+ "WINDOWS",
+ "LINUX"
+ ],
+ "dependence": {
+ "mode": "ANY",
+ "settings": [
+ {
+ "key": "enables",
+ "value": [
+ "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "key": "validate_draw_indirect",
+ "label": "Check Draw Indirect Count Buffers and firstInstance values",
+ "description": "Enable draw indirect checking",
+ "type": "BOOL",
+ "default": true,
+ "platforms": [
+ "WINDOWS",
+ "LINUX"
+ ],
+ "dependence": {
+ "mode": "ANY",
+ "settings": [
+ {
+ "key": "enables",
+ "value": [
+ "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "key": "validate_dispatch_indirect",
+ "label": "Check Dispatch Indirect group count values",
+ "description": "Enable dispatch indirect checking",
+ "type": "BOOL",
+ "default": true,
+ "platforms": [
+ "WINDOWS",
+ "LINUX"
+ ],
+ "dependence": {
+ "mode": "ANY",
+ "settings": [
+ {
+ "key": "enables",
+ "value": [
+ "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "key": "vma_linear_output",
+ "label": "Use VMA linear memory allocations for GPU-AV output buffers",
+ "description": "Use linear allocation algorithm",
+ "type": "BOOL",
+ "default": true,
+ "platforms": [
+ "WINDOWS",
+ "LINUX"
+ ],
+ "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",
+ "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_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"
+ ]
+ }
+ ],
+ "default": []
+ },
+ {
+ "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.",
+ "status": "STABLE",
+ "type": "BOOL",
+ "default": true,
+ "platforms": [
+ "WINDOWS",
+ "LINUX",
+ "MACOS",
+ "ANDROID"
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/framework/framework_config.h.in b/tests/framework/framework_config.h.in
index ddbb0ab..e7abe0d 100644
--- a/tests/framework/framework_config.h.in
+++ b/tests/framework/framework_config.h.in
@@ -65,6 +65,8 @@
#define TEST_LAYER_WRAP_OBJECTS_2 "$<TARGET_FILE:test_layer_wrap_objects_2>"
#define TEST_LAYER_WRAP_OBJECTS_3 "$<TARGET_FILE:test_layer_wrap_objects_3>"
+#define COMPLEX_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/data/VkLayer_complex_file.json"
+
// Dummy Binaries
#if _WIN32 || _WIN64
#define DUMMY_BINARY_WINDOWS_64 "${CMAKE_CURRENT_SOURCE_DIR}/data/binaries/dummy_library_pe_64.dll"
diff --git a/tests/framework/icd/physical_device.h b/tests/framework/icd/physical_device.h
index fbe5cb1..e5129b0 100644
--- a/tests/framework/icd/physical_device.h
+++ b/tests/framework/icd/physical_device.h
@@ -64,9 +64,9 @@
BUILDER_VALUE(PhysicalDevice, VkDisplayModeKHR, display_mode, {})
BUILDER_VALUE(PhysicalDevice, VkDisplayPlaneCapabilitiesKHR, display_plane_capabilities, {})
- // VkDevice handles created from this physical device
+ // Objects created from this physical device
std::vector<VkDevice> device_handles;
-
+ std::vector<DeviceCreateInfo> device_create_infos;
std::vector<DispatchableHandle<VkQueue>> queue_handles;
// Unknown physical device functions. Add a `VulkanFunction` to this list which will be searched in
diff --git a/tests/framework/icd/test_icd.cpp b/tests/framework/icd/test_icd.cpp
index 41790db..079e806 100644
--- a/tests/framework/icd/test_icd.cpp
+++ b/tests/framework/icd/test_icd.cpp
@@ -327,6 +327,26 @@
}
}
+// Debug utils & debug marker ext stubs
+VKAPI_ATTR VkResult VKAPI_CALL test_vkDebugMarkerSetObjectTagEXT(VkDevice dev, const VkDebugMarkerObjectTagInfoEXT* pTagInfo) {
+ return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkDebugMarkerSetObjectNameEXT(VkDevice dev, const VkDebugMarkerObjectNameInfoEXT* pNameInfo) {
+ return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkSetDebugUtilsObjectNameEXT(VkDevice dev, const VkDebugUtilsObjectTagInfoEXT* pTagInfo) {
+ return VK_SUCCESS;
+}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkSetDebugUtilsObjectTagEXT(VkDevice dev, const VkDebugUtilsObjectTagInfoEXT* pTagInfo) {
+ return VK_SUCCESS;
+}
+VKAPI_ATTR void VKAPI_CALL test_vkQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+VKAPI_ATTR void VKAPI_CALL test_vkQueueEndDebugUtilsLabelEXT(VkQueue queue) {}
+VKAPI_ATTR void VKAPI_CALL test_vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+VKAPI_ATTR void VKAPI_CALL test_vkCmdBeginDebugUtilsLabelEXT(VkCommandBuffer cmd_buf, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+VKAPI_ATTR void VKAPI_CALL test_vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer cmd_buf) {}
+VKAPI_ATTR void VKAPI_CALL test_vkCmdInsertDebugUtilsLabelEXT(VkCommandBuffer cmd_buf, const VkDebugUtilsLabelEXT* pLabelInfo) {}
+
//// Physical Device functions ////
// VK_SUCCESS,VK_INCOMPLETE
@@ -366,11 +386,11 @@
auto device_handle = DispatchableHandle<VkDevice>();
*pDevice = device_handle.handle;
found->device_handles.push_back(device_handle.handle);
- icd.device_handles.emplace_back(std::move(device_handle));
-
+ found->device_create_infos.push_back(DeviceCreateInfo{pCreateInfo});
for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
found->queue_handles.emplace_back();
}
+ icd.device_handles.emplace_back(std::move(device_handle));
return VK_SUCCESS;
}
@@ -378,6 +398,11 @@
VKAPI_ATTR void VKAPI_CALL test_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
auto found = std::find(icd.device_handles.begin(), icd.device_handles.end(), device);
if (found != icd.device_handles.end()) icd.device_handles.erase(found);
+ auto fd = icd.lookup_device(device);
+ if (!fd.found) return;
+ auto& phys_dev = icd.physical_devices.at(fd.phys_dev_index);
+ phys_dev.device_handles.erase(phys_dev.device_handles.begin() + fd.dev_index);
+ phys_dev.device_create_infos.erase(phys_dev.device_create_infos.begin() + fd.dev_index);
}
VKAPI_ATTR VkResult VKAPI_CALL generic_tool_props_function(VkPhysicalDevice physicalDevice, uint32_t* pToolCount,
@@ -586,13 +611,27 @@
}
}
}
-
+// VK_KHR_swapchain
VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) {
common_nondispatch_handle_creation(icd.swapchain_handles, pSwapchain);
return VK_SUCCESS;
}
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain,
+ uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) {
+ std::vector<uint64_t> handles{123, 234, 345, 345, 456};
+ if (pSwapchainImages == nullptr) {
+ if (pSwapchainImageCount) *pSwapchainImageCount = static_cast<uint32_t>(handles.size());
+ } else if (pSwapchainImageCount) {
+ for (uint32_t i = 0; i < *pSwapchainImageCount && i < handles.size(); i++) {
+ pSwapchainImages[i] = to_nondispatch_handle<VkImage>(handles.back());
+ }
+ if (*pSwapchainImageCount < handles.size()) return VK_INCOMPLETE;
+ }
+ return VK_SUCCESS;
+}
+
VKAPI_ATTR void VKAPI_CALL test_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
const VkAllocationCallbacks* pAllocator) {
if (swapchain != VK_NULL_HANDLE) {
@@ -600,11 +639,18 @@
auto found_iter = icd.swapchain_handles.erase(
std::remove(icd.swapchain_handles.begin(), icd.swapchain_handles.end(), fake_swapchain_handle),
icd.swapchain_handles.end());
- if (found_iter == icd.swapchain_handles.end()) {
+ if (!icd.swapchain_handles.empty() && found_iter == icd.swapchain_handles.end()) {
assert(false && "Swapchain not found during destroy!");
}
}
}
+// VK_KHR_swapchain with 1.1
+VKAPI_ATTR VkResult VKAPI_CALL test_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface,
+ VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ if (!pModes) return VK_ERROR_INITIALIZATION_FAILED;
+ *pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR;
+ return VK_SUCCESS;
+}
// VK_KHR_surface
VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
@@ -750,6 +796,14 @@
}
return VK_SUCCESS;
}
+// VK_KHR_display_swapchain
+VkResult test_vkCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos,
+ const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains) {
+ for (uint32_t i = 0; i < swapchainCount; i++) {
+ common_nondispatch_handle_creation(icd.swapchain_handles, &pSwapchains[i]);
+ }
+ return VK_SUCCESS;
+}
//// misc
VKAPI_ATTR VkResult VKAPI_CALL test_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo,
@@ -1284,22 +1338,58 @@
return nullptr;
}
-PFN_vkVoidFunction get_device_func(VkDevice device, const char* pName) {
- if (device != nullptr) {
- if (!std::any_of(icd.physical_devices.begin(), icd.physical_devices.end(), [&](const PhysicalDevice& pd) {
- return std::any_of(pd.device_handles.begin(), pd.device_handles.end(),
- [&](const VkDevice& pd_device) { return pd_device == device; });
- })) {
- return nullptr;
+bool should_check(std::vector<const char*> const& exts, VkDevice device, const char* ext_name) {
+ if (device == NULL) return true; // always look if device is NULL
+ for (auto const& ext : exts) {
+ if (string_eq(ext, ext_name)) {
+ return true;
}
}
- if (string_eq(pName, "vkDestroyDevice")) return to_vkVoidFunction(test_vkDestroyDevice);
- if (string_eq(pName, "vkCreateSwapchainKHR")) return to_vkVoidFunction(test_vkCreateSwapchainKHR);
- if (string_eq(pName, "vkDestroySwapchainKHR")) return to_vkVoidFunction(test_vkDestroySwapchainKHR);
+ return false;
+}
+
+PFN_vkVoidFunction get_device_func(VkDevice device, const char* pName) {
+ TestICD::FindDevice fd{};
+ DeviceCreateInfo create_info{};
+ if (device != nullptr) {
+ fd = icd.lookup_device(device);
+ if (!fd.found) return NULL;
+ create_info = icd.physical_devices.at(fd.phys_dev_index).device_create_infos.at(fd.dev_index);
+ }
if (string_eq(pName, "vkCreateCommandPool")) return to_vkVoidFunction(test_vkCreateCommandPool);
if (string_eq(pName, "vkAllocateCommandBuffers")) return to_vkVoidFunction(test_vkAllocateCommandBuffers);
if (string_eq(pName, "vkDestroyCommandPool")) return to_vkVoidFunction(test_vkDestroyCommandPool);
if (string_eq(pName, "vkGetDeviceQueue")) return to_vkVoidFunction(test_vkGetDeviceQueue);
+ if (string_eq(pName, "vkDestroyDevice")) return to_vkVoidFunction(test_vkDestroyDevice);
+ if (should_check(create_info.enabled_extensions, device, "VK_KHR_swapchain")) {
+ if (string_eq(pName, "vkCreateSwapchainKHR")) return to_vkVoidFunction(test_vkCreateSwapchainKHR);
+ if (string_eq(pName, "vkGetSwapchainImagesKHR")) return to_vkVoidFunction(test_vkGetSwapchainImagesKHR);
+ if (string_eq(pName, "vkDestroySwapchainKHR")) return to_vkVoidFunction(test_vkDestroySwapchainKHR);
+
+ if (icd.icd_api_version >= VK_API_VERSION_1_1 && string_eq(pName, "vkGetDeviceGroupSurfacePresentModesKHR"))
+ return to_vkVoidFunction(test_vkGetDeviceGroupSurfacePresentModesKHR);
+ }
+ if (should_check(create_info.enabled_extensions, device, "VK_KHR_display_swapchain")) {
+ if (string_eq(pName, "vkCreateSharedSwapchainsKHR")) return to_vkVoidFunction(test_vkCreateSharedSwapchainsKHR);
+ }
+ if (should_check(create_info.enabled_extensions, device, "VK_KHR_device_group")) {
+ if (string_eq(pName, "vkGetDeviceGroupSurfacePresentModesKHR"))
+ return to_vkVoidFunction(test_vkGetDeviceGroupSurfacePresentModesKHR);
+ }
+ if (should_check(create_info.enabled_extensions, device, "VK_EXT_debug_marker")) {
+ if (string_eq(pName, "vkDebugMarkerSetObjectTagEXT")) return to_vkVoidFunction(test_vkDebugMarkerSetObjectTagEXT);
+ if (string_eq(pName, "vkDebugMarkerSetObjectNameEXT")) return to_vkVoidFunction(test_vkDebugMarkerSetObjectNameEXT);
+ }
+ if (IsInstanceExtensionEnabled("VK_EXT_debug_utils")) {
+ if (string_eq(pName, "vkSetDebugUtilsObjectNameEXT")) return to_vkVoidFunction(test_vkSetDebugUtilsObjectNameEXT);
+ if (string_eq(pName, "vkSetDebugUtilsObjectTagEXT")) return to_vkVoidFunction(test_vkSetDebugUtilsObjectTagEXT);
+ if (string_eq(pName, "vkQueueBeginDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkQueueBeginDebugUtilsLabelEXT);
+ if (string_eq(pName, "vkQueueEndDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkQueueEndDebugUtilsLabelEXT);
+ if (string_eq(pName, "vkQueueInsertDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkQueueInsertDebugUtilsLabelEXT);
+ if (string_eq(pName, "vkCmdBeginDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkCmdBeginDebugUtilsLabelEXT);
+ if (string_eq(pName, "vkCmdEndDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkCmdEndDebugUtilsLabelEXT);
+ if (string_eq(pName, "vkCmdInsertDebugUtilsLabelEXT")) return to_vkVoidFunction(test_vkCmdInsertDebugUtilsLabelEXT);
+ }
// look for device functions setup from a test
for (const auto& phys_dev : icd.physical_devices) {
for (const auto& function : phys_dev.known_device_functions) {
@@ -1378,7 +1468,6 @@
#if TEST_ICD_EXPORT_ICD_GPDPA
FRAMEWORK_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char* pName) {
- // std::cout << "icdGetPhysicalDeviceProcAddr: " << pName << "\n";
return get_physical_device_func(instance, pName);
}
#endif // TEST_ICD_EXPORT_ICD_GPDPA
diff --git a/tests/framework/icd/test_icd.h b/tests/framework/icd/test_icd.h
index 6acdab1..8134632 100644
--- a/tests/framework/icd/test_icd.h
+++ b/tests/framework/icd/test_icd.h
@@ -110,6 +110,28 @@
return info;
}
+ struct FindDevice {
+ bool found = false;
+ uint32_t phys_dev_index = 0;
+ uint32_t dev_index = 0;
+ };
+
+ FindDevice lookup_device(VkDevice device) {
+ FindDevice fd{};
+ for (uint32_t p = 0; p < physical_devices.size(); p++) {
+ auto const& phys_dev = physical_devices.at(p);
+ for (uint32_t d = 0; d < phys_dev.device_handles.size(); d++) {
+ if (phys_dev.device_handles.at(d) == device) {
+ fd.found = true;
+ fd.phys_dev_index = p;
+ fd.dev_index = d;
+ return fd;
+ }
+ }
+ }
+ return fd;
+ }
+
#if defined(WIN32)
BUILDER_VALUE(TestICD, LUID, adapterLUID, {})
#endif // defined(WIN32)
diff --git a/tests/framework/layer/test_layer.cpp b/tests/framework/layer/test_layer.cpp
index 0ccb1f6..d1cd26a 100644
--- a/tests/framework/layer/test_layer.cpp
+++ b/tests/framework/layer/test_layer.cpp
@@ -156,8 +156,26 @@
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
layer.next_vkGetInstanceProcAddr = fpGetInstanceProcAddr;
+ bool use_modified_create_info = false;
+ VkInstanceCreateInfo instance_create_info{};
+ VkApplicationInfo application_info{};
+ if (pCreateInfo) {
+ instance_create_info = *pCreateInfo;
+ if (pCreateInfo->pApplicationInfo) {
+ application_info = *pCreateInfo->pApplicationInfo;
+ }
+ }
+
+ // If the test needs to modify the api version, do it before we call down the chain
+ if (layer.alter_api_version != VK_API_VERSION_1_0 && pCreateInfo && pCreateInfo->pApplicationInfo) {
+ application_info.apiVersion = layer.alter_api_version;
+ instance_create_info.pApplicationInfo = &application_info;
+ use_modified_create_info = true;
+ }
+ const VkInstanceCreateInfo* create_info_pointer = use_modified_create_info ? &instance_create_info : pCreateInfo;
+
// Continue call down the chain
- VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
+ VkResult result = fpCreateInstance(create_info_pointer, pAllocator, pInstance);
if (result != VK_SUCCESS) {
return result;
}
diff --git a/tests/framework/layer/test_layer.h b/tests/framework/layer/test_layer.h
index 2d3571b..c0f0012 100644
--- a/tests/framework/layer/test_layer.h
+++ b/tests/framework/layer/test_layer.h
@@ -102,6 +102,9 @@
BUILDER_VALUE(TestLayer, uint32_t, min_implementation_version, 0)
BUILDER_VALUE(TestLayer, std::string, description, {})
+ // Some layers may try to change the API version during instance creation - we should allow testing of such behavior
+ BUILDER_VALUE(TestLayer, uint32_t, alter_api_version, VK_API_VERSION_1_0)
+
BUILDER_VECTOR(TestLayer, std::string, alternative_function_names, alternative_function_name)
BUILDER_VECTOR(TestLayer, Extension, instance_extensions, instance_extension)
diff --git a/tests/framework/layer/wrap_objects.cpp b/tests/framework/layer/wrap_objects.cpp
index f2ed84a..ae9ab43 100644
--- a/tests/framework/layer/wrap_objects.cpp
+++ b/tests/framework/layer/wrap_objects.cpp
@@ -670,7 +670,7 @@
VkLayerInstanceDispatchTable *pTable = &inst->layer_disp;
if (pTable->GetInstanceProcAddr == NULL) return NULL;
- return pTable->GetInstanceProcAddr(instance, funcName);
+ return pTable->GetInstanceProcAddr(inst->obj, funcName);
}
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
@@ -681,7 +681,7 @@
VkLayerInstanceDispatchTable *pTable = &inst->layer_disp;
if (pTable->GetPhysicalDeviceProcAddr == NULL) return NULL;
- return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
+ return pTable->GetPhysicalDeviceProcAddr(inst->obj, funcName);
}
} // namespace wrap_objects
diff --git a/tests/framework/shim/shim_common.cpp b/tests/framework/shim/shim_common.cpp
index dd4c4bf..2c16a8a 100644
--- a/tests/framework/shim/shim_common.cpp
+++ b/tests/framework/shim/shim_common.cpp
@@ -106,8 +106,9 @@
void PlatformShim::set_path(ManifestCategory category, fs::path const& path) {}
void PlatformShim::add_manifest(ManifestCategory category, fs::path const& path) {
- if (category == ManifestCategory::implicit_layer) hkey_local_machine_implicit_layers.emplace_back(path.str());
- if (category == ManifestCategory::explicit_layer)
+ if (category == ManifestCategory::implicit_layer)
+ hkey_local_machine_implicit_layers.emplace_back(path.str());
+ else if (category == ManifestCategory::explicit_layer)
hkey_local_machine_explicit_layers.emplace_back(path.str());
else
hkey_local_machine_drivers.emplace_back(path.str());
diff --git a/tests/framework/shim/unix_shim.cpp b/tests/framework/shim/unix_shim.cpp
index c52bec7..e930293 100644
--- a/tests/framework/shim/unix_shim.cpp
+++ b/tests/framework/shim/unix_shim.cpp
@@ -83,6 +83,21 @@
using PFN_SEC_GETENV = char* (*)(const char* name);
#endif
+#if defined(__APPLE__)
+#define real_opendir opendir
+#define real_readdir readdir
+#define real_closedir closedir
+#define real_access access
+#define real_fopen fopen
+#define real_geteuid geteuid
+#define real_getegid getegid
+#if defined(HAVE_SECURE_GETENV)
+#define real_secure_getenv _secure_getenv
+#endif
+#if defined(HAVE___SECURE_GETENV)
+#define real__secure_getenv __secure_getenv
+#endif
+#else
static PFN_OPENDIR real_opendir = nullptr;
static PFN_READDIR real_readdir = nullptr;
static PFN_CLOSEDIR real_closedir = nullptr;
@@ -96,10 +111,12 @@
#if defined(HAVE___SECURE_GETENV)
static PFN_SEC_GETENV real__secure_getenv = nullptr;
#endif
+#endif
FRAMEWORK_EXPORT DIR* OPENDIR_FUNC_NAME(const char* path_name) {
+#if !defined(__APPLE__)
if (!real_opendir) real_opendir = (PFN_OPENDIR)dlsym(RTLD_NEXT, "opendir");
-
+#endif
DIR* dir;
if (platform_shim.is_fake_path(path_name)) {
auto fake_path_name = platform_shim.get_fake_path(fs::path(path_name));
@@ -113,7 +130,9 @@
}
FRAMEWORK_EXPORT struct dirent* READDIR_FUNC_NAME(DIR* dir_stream) {
+#if !defined(__APPLE__)
if (!real_readdir) real_readdir = (PFN_READDIR)dlsym(RTLD_NEXT, "readdir");
+#endif
auto it = std::find_if(platform_shim.dir_entries.begin(), platform_shim.dir_entries.end(),
[dir_stream](DirEntry const& entry) { return entry.directory == dir_stream; });
@@ -151,8 +170,9 @@
}
FRAMEWORK_EXPORT int CLOSEDIR_FUNC_NAME(DIR* dir_stream) {
+#if !defined(__APPLE__)
if (!real_closedir) real_closedir = (PFN_CLOSEDIR)dlsym(RTLD_NEXT, "closedir");
-
+#endif
auto it = std::find_if(platform_shim.dir_entries.begin(), platform_shim.dir_entries.end(),
[dir_stream](DirEntry const& entry) { return entry.directory == dir_stream; });
@@ -164,8 +184,9 @@
}
FRAMEWORK_EXPORT int ACCESS_FUNC_NAME(const char* in_pathname, int mode) {
+#if !defined(__APPLE__)
if (!real_access) real_access = (PFN_ACCESS)dlsym(RTLD_NEXT, "access");
-
+#endif
fs::path path{in_pathname};
if (!path.has_parent_path()) {
return real_access(in_pathname, mode);
@@ -180,8 +201,9 @@
}
FRAMEWORK_EXPORT FILE* FOPEN_FUNC_NAME(const char* in_filename, const char* mode) {
+#if !defined(__APPLE__)
if (!real_fopen) real_fopen = (PFN_FOPEN)dlsym(RTLD_NEXT, "fopen");
-
+#endif
fs::path path{in_filename};
if (!path.has_parent_path()) {
return real_fopen(in_filename, mode);
@@ -199,8 +221,9 @@
}
FRAMEWORK_EXPORT uid_t GETEUID_FUNC_NAME(void) {
+#if !defined(__APPLE__)
if (!real_geteuid) real_geteuid = (PFN_GETEUID)dlsym(RTLD_NEXT, "geteuid");
-
+#endif
if (platform_shim.use_fake_elevation) {
// Root on linux is 0, so force pretending like we're root
return 0;
@@ -210,8 +233,9 @@
}
FRAMEWORK_EXPORT gid_t GETEGID_FUNC_NAME(void) {
+#if !defined(__APPLE__)
if (!real_getegid) real_getegid = (PFN_GETEGID)dlsym(RTLD_NEXT, "getegid");
-
+#endif
if (platform_shim.use_fake_elevation) {
// Root on linux is 0, so force pretending like we're root
return 0;
@@ -222,8 +246,9 @@
#if defined(HAVE_SECURE_GETENV)
FRAMEWORK_EXPORT char* SECURE_GETENV_FUNC_NAME(const char* name) {
+#if !defined(__APPLE__)
if (!real_secure_getenv) real_secure_getenv = (PFN_SEC_GETENV)dlsym(RTLD_NEXT, "secure_getenv");
-
+#endif
if (platform_shim.use_fake_elevation) {
return NULL;
} else {
@@ -233,7 +258,9 @@
#endif
#if defined(HAVE___SECURE_GETENV)
FRAMEWORK_EXPORT char* __SECURE_GETENV_FUNC_NAME(const char* name) {
+#if !defined(__APPLE__)
if (!real__secure_getenv) real__secure_getenv = (PFN_SEC_GETENV)dlsym(RTLD_NEXT, "__secure_getenv");
+#endif
if (platform_shim.use_fake_elevation) {
return NULL;
diff --git a/tests/framework/test_environment.cpp b/tests/framework/test_environment.cpp
index 5d058ab..308230e 100644
--- a/tests/framework/test_environment.cpp
+++ b/tests/framework/test_environment.cpp
@@ -27,6 +27,144 @@
#include "test_environment.h"
+fs::path get_loader_path() {
+ auto loader_path = fs::path(FRAMEWORK_VULKAN_LIBRARY_PATH);
+ auto env_var_res = get_env_var("VK_LOADER_TEST_LOADER_PATH", false);
+ if (!env_var_res.empty()) {
+ loader_path = fs::path(env_var_res);
+ }
+ return loader_path;
+}
+
+void init_vulkan_functions(VulkanFunctions& funcs) {
+#if defined(BUILD_STATIC_LOADER)
+#define GPA(name) name
+#else
+#define GPA(name) funcs.loader.get_symbol(#name)
+#endif
+
+ // clang-format off
+ funcs.vkGetInstanceProcAddr = GPA(vkGetInstanceProcAddr);
+ funcs.vkEnumerateInstanceExtensionProperties = GPA(vkEnumerateInstanceExtensionProperties);
+ funcs.vkEnumerateInstanceLayerProperties = GPA(vkEnumerateInstanceLayerProperties);
+ funcs.vkEnumerateInstanceVersion = GPA(vkEnumerateInstanceVersion);
+ funcs.vkCreateInstance = GPA(vkCreateInstance);
+ funcs.vkDestroyInstance = GPA(vkDestroyInstance);
+ funcs.vkEnumeratePhysicalDevices = GPA(vkEnumeratePhysicalDevices);
+ funcs.vkEnumeratePhysicalDeviceGroups = GPA(vkEnumeratePhysicalDeviceGroups);
+ funcs.vkGetPhysicalDeviceFeatures = GPA(vkGetPhysicalDeviceFeatures);
+ funcs.vkGetPhysicalDeviceFeatures2 = GPA(vkGetPhysicalDeviceFeatures2);
+ funcs.vkGetPhysicalDeviceFormatProperties = GPA(vkGetPhysicalDeviceFormatProperties);
+ funcs.vkGetPhysicalDeviceFormatProperties2 = GPA(vkGetPhysicalDeviceFormatProperties2);
+ funcs.vkGetPhysicalDeviceImageFormatProperties = GPA(vkGetPhysicalDeviceImageFormatProperties);
+ funcs.vkGetPhysicalDeviceImageFormatProperties2 = GPA(vkGetPhysicalDeviceImageFormatProperties2);
+ funcs.vkGetPhysicalDeviceSparseImageFormatProperties = GPA(vkGetPhysicalDeviceSparseImageFormatProperties);
+ funcs.vkGetPhysicalDeviceSparseImageFormatProperties2 = GPA(vkGetPhysicalDeviceSparseImageFormatProperties2);
+ funcs.vkGetPhysicalDeviceProperties = GPA(vkGetPhysicalDeviceProperties);
+ funcs.vkGetPhysicalDeviceProperties2 = GPA(vkGetPhysicalDeviceProperties2);
+ funcs.vkGetPhysicalDeviceQueueFamilyProperties = GPA(vkGetPhysicalDeviceQueueFamilyProperties);
+ funcs.vkGetPhysicalDeviceQueueFamilyProperties2 = GPA(vkGetPhysicalDeviceQueueFamilyProperties2);
+ funcs.vkGetPhysicalDeviceMemoryProperties = GPA(vkGetPhysicalDeviceMemoryProperties);
+ funcs.vkGetPhysicalDeviceMemoryProperties2 = GPA(vkGetPhysicalDeviceMemoryProperties2);
+ funcs.vkGetPhysicalDeviceSurfaceSupportKHR = GPA(vkGetPhysicalDeviceSurfaceSupportKHR);
+ funcs.vkGetPhysicalDeviceSurfaceFormatsKHR = GPA(vkGetPhysicalDeviceSurfaceFormatsKHR);
+ funcs.vkGetPhysicalDeviceSurfacePresentModesKHR = GPA(vkGetPhysicalDeviceSurfacePresentModesKHR);
+ funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR = GPA(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
+ funcs.vkEnumerateDeviceExtensionProperties = GPA(vkEnumerateDeviceExtensionProperties);
+ funcs.vkEnumerateDeviceLayerProperties = GPA(vkEnumerateDeviceLayerProperties);
+ funcs.vkGetPhysicalDeviceExternalBufferProperties = GPA(vkGetPhysicalDeviceExternalBufferProperties);
+ funcs.vkGetPhysicalDeviceExternalFenceProperties = GPA(vkGetPhysicalDeviceExternalFenceProperties);
+ funcs.vkGetPhysicalDeviceExternalSemaphoreProperties = GPA(vkGetPhysicalDeviceExternalSemaphoreProperties);
+
+ funcs.vkDestroySurfaceKHR = GPA(vkDestroySurfaceKHR);
+ funcs.vkGetDeviceProcAddr = GPA(vkGetDeviceProcAddr);
+ funcs.vkCreateDevice = GPA(vkCreateDevice);
+
+ funcs.vkCreateHeadlessSurfaceEXT = GPA(vkCreateHeadlessSurfaceEXT);
+ funcs.vkCreateDisplayPlaneSurfaceKHR = GPA(vkCreateDisplayPlaneSurfaceKHR);
+ funcs.vkGetPhysicalDeviceDisplayPropertiesKHR = GPA(vkGetPhysicalDeviceDisplayPropertiesKHR);
+ funcs.vkGetPhysicalDeviceDisplayPlanePropertiesKHR = GPA(vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
+ funcs.vkGetDisplayPlaneSupportedDisplaysKHR = GPA(vkGetDisplayPlaneSupportedDisplaysKHR);
+ funcs.vkGetDisplayModePropertiesKHR = GPA(vkGetDisplayModePropertiesKHR);
+ funcs.vkCreateDisplayModeKHR = GPA(vkCreateDisplayModeKHR);
+ funcs.vkGetDisplayPlaneCapabilitiesKHR = GPA(vkGetDisplayPlaneCapabilitiesKHR);
+ funcs.vkGetPhysicalDevicePresentRectanglesKHR = GPA(vkGetPhysicalDevicePresentRectanglesKHR);
+ funcs.vkGetPhysicalDeviceDisplayProperties2KHR = GPA(vkGetPhysicalDeviceDisplayProperties2KHR);
+ funcs.vkGetPhysicalDeviceDisplayPlaneProperties2KHR = GPA(vkGetPhysicalDeviceDisplayPlaneProperties2KHR);
+ funcs.vkGetDisplayModeProperties2KHR = GPA(vkGetDisplayModeProperties2KHR);
+ funcs.vkGetDisplayPlaneCapabilities2KHR = GPA(vkGetDisplayPlaneCapabilities2KHR);
+ funcs.vkGetPhysicalDeviceSurfaceCapabilities2KHR = GPA(vkGetPhysicalDeviceSurfaceCapabilities2KHR);
+ funcs.vkGetPhysicalDeviceSurfaceFormats2KHR = GPA(vkGetPhysicalDeviceSurfaceFormats2KHR);
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+ funcs.vkCreateAndroidSurfaceKHR = GPA(vkCreateAndroidSurfaceKHR);
+#endif // VK_USE_PLATFORM_ANDROID_KHR
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+ funcs.vkCreateDirectFBSurfaceEXT = GPA(vkCreateDirectFBSurfaceEXT);
+ funcs.vkGetPhysicalDeviceDirectFBPresentationSupportEXT = GPA(vkGetPhysicalDeviceDirectFBPresentationSupportEXT);
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_FUCHSIA
+ funcs.vkCreateImagePipeSurfaceFUCHSIA = GPA(vkCreateImagePipeSurfaceFUCHSIA);
+#endif // VK_USE_PLATFORM_FUCHSIA
+#ifdef VK_USE_PLATFORM_GGP
+ funcs.vkCreateStreamDescriptorSurfaceGGP = GPA(vkCreateStreamDescriptorSurfaceGGP);
+#endif // VK_USE_PLATFORM_GGP
+#ifdef VK_USE_PLATFORM_IOS_MVK
+ funcs.vkCreateIOSSurfaceMVK = GPA(vkCreateIOSSurfaceMVK);
+#endif // VK_USE_PLATFORM_IOS_MVK
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+ funcs.vkCreateMacOSSurfaceMVK = GPA(vkCreateMacOSSurfaceMVK);
+#endif // VK_USE_PLATFORM_MACOS_MVK
+#ifdef VK_USE_PLATFORM_METAL_EXT
+ funcs.vkCreateMetalSurfaceEXT = GPA(vkCreateMetalSurfaceEXT);
+#endif // VK_USE_PLATFORM_METAL_EXT
+#ifdef VK_USE_PLATFORM_SCREEN_QNX
+ funcs.vkCreateScreenSurfaceQNX = GPA(vkCreateScreenSurfaceQNX);
+ funcs.vkGetPhysicalDeviceScreenPresentationSupportQNX = GPA(vkGetPhysicalDeviceScreenPresentationSupportQNX);
+#endif // VK_USE_PLATFORM_SCREEN_QNX
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ funcs.vkCreateWaylandSurfaceKHR = GPA(vkCreateWaylandSurfaceKHR);
+ funcs.vkGetPhysicalDeviceWaylandPresentationSupportKHR = GPA(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
+#endif // VK_USE_PLATFORM_WAYLAND_KHR
+#ifdef VK_USE_PLATFORM_XCB_KHR
+ funcs.vkCreateXcbSurfaceKHR = GPA(vkCreateXcbSurfaceKHR);
+ funcs.vkGetPhysicalDeviceXcbPresentationSupportKHR = GPA(vkGetPhysicalDeviceXcbPresentationSupportKHR);
+#endif // VK_USE_PLATFORM_XCB_KHR
+#ifdef VK_USE_PLATFORM_XLIB_KHR
+ funcs.vkCreateXlibSurfaceKHR = GPA(vkCreateXlibSurfaceKHR);
+ funcs.vkGetPhysicalDeviceXlibPresentationSupportKHR = GPA(vkGetPhysicalDeviceXlibPresentationSupportKHR);
+#endif // VK_USE_PLATFORM_XLIB_KHR
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+ funcs.vkCreateWin32SurfaceKHR = GPA(vkCreateWin32SurfaceKHR);
+ funcs.vkGetPhysicalDeviceWin32PresentationSupportKHR = GPA(vkGetPhysicalDeviceWin32PresentationSupportKHR);
+#endif // VK_USE_PLATFORM_WIN32_KHR
+
+ funcs.vkDestroyDevice = GPA(vkDestroyDevice);
+ funcs.vkGetDeviceQueue = GPA(vkGetDeviceQueue);
+#undef GPA
+ // clang-format on
+}
+
+#if defined(BUILD_STATIC_LOADER)
+VulkanFunctions::VulkanFunctions() {
+#else
+VulkanFunctions::VulkanFunctions() : loader(get_loader_path()) {
+#endif
+ init_vulkan_functions(*this);
+}
+
+DeviceFunctions::DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device) {
+ vkGetDeviceProcAddr = vulkan_functions.vkGetDeviceProcAddr;
+ vkDestroyDevice = load(device, "vkDestroyDevice");
+ vkGetDeviceQueue = load(device, "vkGetDeviceQueue");
+ vkCreateCommandPool = load(device, "vkCreateCommandPool");
+ vkAllocateCommandBuffers = load(device, "vkAllocateCommandBuffers");
+ vkDestroyCommandPool = load(device, "vkDestroyCommandPool");
+ vkCreateSwapchainKHR = load(device, "vkCreateSwapchainKHR");
+ vkGetSwapchainImagesKHR = load(device, "vkGetSwapchainImagesKHR");
+ vkDestroySwapchainKHR = load(device, "vkDestroySwapchainKHR");
+}
+
InstWrapper::InstWrapper(VulkanFunctions& functions, VkAllocationCallbacks* callbacks) noexcept
: functions(&functions), callbacks(callbacks) {}
InstWrapper::InstWrapper(VulkanFunctions& functions, VkInstance inst, VkAllocationCallbacks* callbacks) noexcept
@@ -136,7 +274,29 @@
create_info.instance_info.pNext = wrapper.get();
}
-PlatformShimWrapper::PlatformShimWrapper(std::vector<fs::FolderManager>* folders) noexcept {
+// Look through the event log. If you find a line containing the prefix we're interested in, look for the end of
+// line character, and then see if the postfix occurs in it as well.
+bool DebugUtilsLogger::find_prefix_then_postfix(const char* prefix, const char* postfix) const {
+ size_t new_start = 0;
+ size_t postfix_index = 0;
+ size_t next_eol = 0;
+ while ((new_start = returned_output.find(prefix, new_start)) != std::string::npos) {
+ next_eol = returned_output.find("\n", new_start);
+ if ((postfix_index = returned_output.find(postfix, new_start)) != std::string::npos) {
+ if (postfix_index < next_eol) {
+ return true;
+ }
+ }
+ new_start = next_eol + 1;
+ }
+ return false;
+}
+
+bool FindPrefixPostfixStringOnLine(DebugUtilsLogger const& env_log, const char* prefix, const char* postfix) {
+ return env_log.find_prefix_then_postfix(prefix, postfix);
+}
+
+PlatformShimWrapper::PlatformShimWrapper(std::vector<fs::FolderManager>* folders, bool enable_log) noexcept {
#if defined(WIN32) || defined(__APPLE__)
shim_library = LibraryWrapper(SHIM_LIBRARY_NAME);
PFN_get_platform_shim get_platform_shim_func = shim_library.get_symbol(GET_PLATFORM_SHIM_STR);
@@ -147,9 +307,11 @@
#endif
platform_shim->reset();
- // leave it permanently on at full blast
- set_env_var("VK_LOADER_DEBUG", "all");
+ if (enable_log) {
+ set_env_var("VK_LOADER_DEBUG", "all");
+ }
}
+
PlatformShimWrapper::~PlatformShimWrapper() noexcept { platform_shim->reset(); }
TestICDHandle::TestICDHandle() noexcept {}
@@ -184,7 +346,10 @@
fs::path TestLayerHandle::get_layer_full_path() noexcept { return layer_library.lib_path; }
fs::path TestLayerHandle::get_layer_manifest_path() noexcept { return manifest_path; }
-FrameworkEnvironment::FrameworkEnvironment() noexcept : platform_shim(&folders), vulkan_functions() {
+FrameworkEnvironment::FrameworkEnvironment() noexcept : FrameworkEnvironment(true, true) {}
+FrameworkEnvironment::FrameworkEnvironment(bool enable_log) noexcept : FrameworkEnvironment(enable_log, true) {}
+FrameworkEnvironment::FrameworkEnvironment(bool enable_log, bool set_default_search_paths) noexcept
+ : platform_shim(&folders, enable_log), vulkan_functions() {
// This order is important, it matches the enum ManifestLocation, used to index the folders vector
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("null_dir"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("icd_manifests"));
@@ -197,9 +362,11 @@
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("app_package_manifests"));
platform_shim->redirect_all_paths(get_folder(ManifestLocation::null).location());
- platform_shim->set_path(ManifestCategory::icd, get_folder(ManifestLocation::driver).location());
- platform_shim->set_path(ManifestCategory::explicit_layer, get_folder(ManifestLocation::explicit_layer).location());
- platform_shim->set_path(ManifestCategory::implicit_layer, get_folder(ManifestLocation::implicit_layer).location());
+ if (set_default_search_paths) {
+ platform_shim->set_path(ManifestCategory::icd, get_folder(ManifestLocation::driver).location());
+ platform_shim->set_path(ManifestCategory::explicit_layer, get_folder(ManifestLocation::explicit_layer).location());
+ platform_shim->set_path(ManifestCategory::implicit_layer, get_folder(ManifestLocation::implicit_layer).location());
+ }
}
void FrameworkEnvironment::add_icd(TestICDDetails icd_details) noexcept {
@@ -222,7 +389,11 @@
icds.back().reset_icd();
icd_details.icd_manifest.lib_path = new_driver_location.str();
}
- std::string full_json_name = icd_details.json_name + "_" + std::to_string(cur_icd_index) + ".json";
+ std::string full_json_name = icd_details.json_name;
+ if (!icd_details.disable_icd_inc) {
+ full_json_name += "_" + std::to_string(cur_icd_index);
+ }
+ full_json_name += ".json";
icds.back().manifest_path = folder->write_manifest(full_json_name, icd_details.icd_manifest.get_manifest_str());
switch (icd_details.discovery_type) {
@@ -285,6 +456,11 @@
if (!env_var_vk_layer_paths.empty()) {
env_var_vk_layer_paths += OS_ENV_VAR_LIST_SEPARATOR;
}
+ if(layer_details.is_dir) {
+ env_var_vk_layer_paths += fs_ptr->location().str();
+ } else {
+ env_var_vk_layer_paths += fs_ptr->location().str() + OS_ENV_VAR_LIST_SEPARATOR + layer_details.json_name;
+ }
env_var_vk_layer_paths += fs_ptr->location().str();
set_env_var("VK_LAYER_PATH", env_var_vk_layer_paths);
break;
@@ -344,167 +520,124 @@
// index it directly using the enum location since they will always be in that order
return folders.at(static_cast<size_t>(location));
}
-void setup_WSI_in_ICD(TestICD& icd) {
+const char* get_platform_wsi_extension(const char* api_selection) {
+#if defined(VK_USE_PLATFORM_ANDROID_KHR)
+ return "VK_KHR_android_surface";
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ return "VK_EXT_directfb_surface";
+#elif defined(VK_USE_PLATFORM_FUCHSIA)
+ return "VK_FUCHSIA_imagepipe_surface";
+#elif defined(VK_USE_PLATFORM_GGP)
+ return "VK_GGP_stream_descriptor_surface";
+#elif defined(VK_USE_PLATFORM_IOS_MVK)
+ return "VK_MVK_ios_surface";
+#elif defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)
+#if defined(VK_USE_PLATFORM_MACOS_MVK)
+ if (string_eq(api_selection, "VK_USE_PLATFORM_MACOS_MVK")) return "VK_MVK_macos_surface";
+#endif
+#if defined(VK_USE_PLATFORM_METAL_EXT)
+ if (string_eq(api_selection, "VK_USE_PLATFORM_METAL_EXT")) return "VK_EXT_metal_surface";
+ return "VK_EXT_metal_surface";
+#endif
+#elif defined(VK_USE_PLATFORM_SCREEN_QNX)
+ return "VK_QNX_screen_surface";
+#elif defined(VK_USE_PLATFORM_VI_NN)
+ return "VK_NN_vi_surface";
+#elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
+#if defined(VK_USE_PLATFORM_XCB_KHR)
+ if (string_eq(api_selection, "VK_USE_PLATFORM_XCB_KHR")) return "VK_KHR_xcb_surface";
+#endif
+#if defined(VK_USE_PLATFORM_XLIB_KHR)
+ if (string_eq(api_selection, "VK_USE_PLATFORM_XLIB_KHR")) return "VK_KHR_xlib_surface";
+#endif
+#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ if (string_eq(api_selection, "VK_USE_PLATFORM_WAYLAND_KHR")) return "VK_KHR_wayland_surface";
+#endif
+#if defined(VK_USE_PLATFORM_XCB_KHR)
+ return "VK_KHR_xcb_surface";
+#endif
+#elif defined(VK_USE_PLATFORM_WIN32_KHR)
+ return "VK_KHR_win32_surface";
+#else
+ return "VK_KHR_display";
+#endif
+}
+
+void setup_WSI_in_ICD(TestICD& icd, const char* api_selection) {
icd.enable_icd_wsi = true;
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
- icd.add_instance_extensions({"VK_KHR_surface", "VK_KHR_android_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
- icd.add_instance_extensions({"VK_KHR_surface", "VK_EXT_directfb_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_FUCHSIA
- icd.add_instance_extensions({"VK_KHR_surface", "VK_FUCHSIA_imagepipe_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_GGP
- icd.add_instance_extensions({"VK_KHR_surface", "VK_GGP_stream_descriptor_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_IOS_MVK
- icd.add_instance_extensions({"VK_KHR_surface", "VK_MVK_ios_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_MACOS_MVK
- icd.add_instance_extensions({"VK_KHR_surface", "VK_MVK_macos_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_METAL_EXT
- icd.add_instance_extensions({"VK_KHR_surface", "VK_EXT_metal_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_SCREEN_QNX
- icd.add_instance_extensions({"VK_KHR_surface", "VK_QNX_screen_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_VI_NN
- icd.add_instance_extensions({"VK_KHR_surface", "VK_NN_vi_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_XCB_KHR
- icd.add_instance_extensions({"VK_KHR_surface", "VK_KHR_xcb_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_XLIB_KHR
- icd.add_instance_extensions({"VK_KHR_surface", "VK_KHR_xlib_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
- icd.add_instance_extensions({"VK_KHR_surface", "VK_KHR_wayland_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_WIN32_KHR
- icd.add_instance_extensions({"VK_KHR_surface", "VK_KHR_win32_surface"});
-#endif
+ icd.add_instance_extensions({"VK_KHR_surface", get_platform_wsi_extension(api_selection)});
}
-void setup_WSI_in_create_instance(InstWrapper& inst) {
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_KHR_android_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_EXT_directfb_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_FUCHSIA
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_FUCHSIA_imagepipe_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_GGP
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_GGP_stream_descriptor_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_IOS_MVK
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_MVK_ios_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_MACOS_MVK
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_MVK_macos_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_METAL_EXT
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_EXT_metal_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_SCREEN_QNX
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_QNX_screen_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_VI_NN
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_NN_vi_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_XCB_KHR
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_KHR_xcb_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_XLIB_KHR
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_KHR_xlib_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_KHR_wayland_surface"});
-#endif
-#ifdef VK_USE_PLATFORM_WIN32_KHR
- inst.create_info.add_extensions({"VK_KHR_surface", "VK_KHR_win32_surface"});
-#endif
+void setup_WSI_in_create_instance(InstWrapper& inst, const char* api_selection) {
+ inst.create_info.add_extensions({"VK_KHR_surface", get_platform_wsi_extension(api_selection)});
}
-VkSurfaceKHR create_surface(InstWrapper& inst, const char* api_selection) {
- VkSurfaceKHR surface{};
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
- PFN_vkCreateAndroidSurfaceKHR pfn_CreateSurface = inst.load("vkCreateAndroidSurfaceKHR");
- VkAndroidSurfaceCreateInfoKHR surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
- PFN_vkCreateDirectFBSurfaceEXT pfn_CreateSurface = inst.load("vkCreateDirectFBSurfaceEXT");
- VkDirectFBSurfaceCreateInfoEXT surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_FUCHSIA
- PFN_vkCreateImagePipeSurfaceFUCHSIA pfn_CreateSurface = inst.load("vkCreateImagePipeSurfaceFUCHSIA");
- VkImagePipeSurfaceCreateInfoFUCHSIA surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_GGP
- PFN__vkCreateStreamDescriptorSurfaceGGP pfn_CreateSurface = inst.load("vkCreateStreamDescriptorSurfaceGGP");
- VkStreamDescriptorSurfaceCreateInfoGGP surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_IOS_MVK
- PFN_vkCreateIOSSurfaceMVK pfn_CreateSurface = inst.load("vkCreateIOSSurfaceMVK");
- VkIOSSurfaceCreateInfoMVK surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_MACOS_MVK
- if (string_eq(api_selection, "VK_USE_PLATFORM_MACOS_MVK")) {
- PFN_vkCreateMacOSSurfaceMVK pfn_CreateSurface = inst.load("vkCreateMacOSSurfaceMVK");
- VkMacOSSurfaceCreateInfoMVK surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
- }
-#endif
-#ifdef VK_USE_PLATFORM_METAL_EXT
- if (string_eq(api_selection, "VK_USE_PLATFORM_METAL_EXT")) {
- PFN_vkCreateMetalSurfaceEXT pfn_CreateSurface = inst.load("vkCreateMetalSurfaceEXT");
- VkMetalSurfaceCreateInfoEXT surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
- }
-#endif
-#ifdef VK_USE_PLATFORM_SCREEN_QNX
- PFN_vkCreateScreenSurfaceQNX pfn_CreateSurface = inst.load("vkCreateScreenSurfaceQNX");
- VkScreenSurfaceCreateInfoQNX surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_VI_NN
- PFN_vkCreateViSurfaceNN pfn_CreateSurface = inst.load("vkCreateViSurfaceNN");
- VkViSurfaceCreateInfoNN surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_WIN32_KHR
- PFN_vkCreateWin32SurfaceKHR pfn_CreateSurface = inst.load("vkCreateWin32SurfaceKHR");
- VkWin32SurfaceCreateInfoKHR surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
-#endif
-#ifdef VK_USE_PLATFORM_XCB_KHR
- if (string_eq(api_selection, "VK_USE_PLATFORM_XCB_KHR")) {
- PFN_vkCreateXcbSurfaceKHR pfn_CreateSurface = inst.load("vkCreateXcbSurfaceKHR");
- VkXcbSurfaceCreateInfoKHR surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
- }
-#endif
-#ifdef VK_USE_PLATFORM_XLIB_KHR
- if (string_eq(api_selection, "VK_USE_PLATFORM_XLIB_KHR")) {
- PFN_vkCreateXlibSurfaceKHR pfn_CreateSurface = inst.load("vkCreateXlibSurfaceKHR");
- VkXlibSurfaceCreateInfoKHR surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
- }
-#endif
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
- if (string_eq(api_selection, "VK_USE_PLATFORM_WAYLAND_KHR")) {
- PFN_vkCreateWaylandSurfaceKHR pfn_CreateSurface = inst.load("vkCreateWaylandSurfaceKHR");
- VkWaylandSurfaceCreateInfoKHR surf_create_info{};
- EXPECT_EQ(VK_SUCCESS, pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface));
- }
-#endif
-
- return surface;
+template <typename CreationFunc, typename CreateInfo>
+testing::AssertionResult create_surface_helper(InstWrapper& inst, VkSurfaceKHR& surface, const char* load_func_name) {
+ CreationFunc pfn_CreateSurface = inst.load(load_func_name);
+ if (!pfn_CreateSurface) return testing::AssertionFailure();
+ CreateInfo surf_create_info{};
+ VkResult res = pfn_CreateSurface(inst, &surf_create_info, nullptr, &surface);
+ return res == VK_SUCCESS ? testing::AssertionSuccess() : testing::AssertionFailure();
}
+testing::AssertionResult create_surface(InstWrapper& inst, VkSurfaceKHR& surface, const char* api_selection) {
+#if defined(VK_USE_PLATFORM_ANDROID_KHR)
+ return create_surface_helper<PFN_vkCreateAndroidSurfaceKHR, VkAndroidSurfaceCreateInfoKHR>(inst, surface,
+ "vkCreateAndroidSurfaceKHR");
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ return create_surface_helper<PFN_vkCreateDirectFBSurfaceEXT, VkDirectFBSurfaceCreateInfoEXT>(inst, surface,
+ "vkCreateDirectFBSurfaceEXT")
+#elif defined(VK_USE_PLATFORM_FUCHSIA)
+ return create_surface_helper<PFN_vkCreateImagePipeSurfaceFUCHSIA, VkImagePipeSurfaceCreateInfoFUCHSIA>(
+ inst, surface, "vkCreateImagePipeSurfaceFUCHSIA");
+#elif defined(VK_USE_PLATFORM_GGP)
+ return create_surface_helper<PFN__vkCreateStreamDescriptorSurfaceGGP, VkStreamDescriptorSurfaceCreateInfoGGP>(
+ inst, surface, "vkCreateStreamDescriptorSurfaceGGP");
+#elif defined(VK_USE_PLATFORM_IOS_MVK)
+ return create_surface_helper<PFN_vkCreateIOSSurfaceMVK, VkIOSSurfaceCreateInfoMVK>(inst, surface, "vkCreateIOSSurfaceMVK");
+#elif defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)
+#if defined(VK_USE_PLATFORM_MACOS_MVK)
+ if (api_selection != nullptr && string_eq(api_selection, "VK_USE_PLATFORM_MACOS_MVK"))
+ return create_surface_helper<PFN_vkCreateMacOSSurfaceMVK, VkMacOSSurfaceCreateInfoMVK>(inst, surface,
+ "vkCreateMacOSSurfaceMVK");
+#endif
+#if defined(VK_USE_PLATFORM_METAL_EXT)
+ if (api_selection == nullptr || (api_selection != nullptr && string_eq(api_selection, "VK_USE_PLATFORM_METAL_EXT")))
+ return create_surface_helper<PFN_vkCreateMetalSurfaceEXT, VkMetalSurfaceCreateInfoEXT>(inst, surface,
+ "vkCreateMetalSurfaceEXT");
+#endif
+ return testing::AssertionFailure();
+#elif defined(VK_USE_PLATFORM_SCREEN_QNX)
+ return create_surface_helper<PFN_vkCreateScreenSurfaceQNX, VkScreenSurfaceCreateInfoQNX>(inst, surface,
+ "vkCreateScreenSurfaceQNX");
+#elif defined(VK_USE_PLATFORM_VI_NN)
+ return create_surface_helper<PFN_vkCreateViSurfaceNN, VkViSurfaceCreateInfoNN>(inst, surface, "vkCreateViSurfaceNN");
+#elif defined(VK_USE_PLATFORM_WIN32_KHR)
+ return create_surface_helper<PFN_vkCreateWin32SurfaceKHR, VkWin32SurfaceCreateInfoKHR>(inst, surface,
+ "vkCreateWin32SurfaceKHR");
+#elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
+#if defined(VK_USE_PLATFORM_XLIB_KHR)
+ if (string_eq(api_selection, "VK_USE_PLATFORM_XLIB_KHR"))
+ return create_surface_helper<PFN_vkCreateXlibSurfaceKHR, VkXlibSurfaceCreateInfoKHR>(inst, surface,
+ "vkCreateXlibSurfaceKHR");
+#endif
+#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ if (string_eq(api_selection, "VK_USE_PLATFORM_WAYLAND_KHR"))
+ return create_surface_helper<PFN_vkCreateWaylandSurfaceKHR, VkWaylandSurfaceCreateInfoKHR>(inst, surface,
+ "vkCreateWaylandSurfaceKHR");
+#endif
+#if defined(VK_USE_PLATFORM_XCB_KHR)
+ if (api_selection == nullptr || string_eq(api_selection, "VK_USE_PLATFORM_XCB_KHR"))
+ return create_surface_helper<PFN_vkCreateXcbSurfaceKHR, VkXcbSurfaceCreateInfoKHR>(inst, surface, "vkCreateXcbSurfaceKHR");
+#endif
+ return testing::AssertionFailure();
+#else
+ return create_surface_helper<PFN_vkCreateDisplayPlaneSurfaceKHR, VkDisplaySurfaceCreateInfoKHR>(
+ inst, surface, "vkCreateDisplayPlaneSurfaceKHR");
+#endif
+}
+
+extern "C" {
+void __ubsan_on_report() { FAIL() << "Encountered an undefined behavior sanitizer error"; }
+void __asan_on_error() { FAIL() << "Encountered an address sanitizer error"; }
+void __tsan_on_report() { FAIL() << "Encountered a thread sanitizer error"; }
+} // extern "C"
diff --git a/tests/framework/test_environment.h b/tests/framework/test_environment.h
index dbd9d71..bcc39bf 100644
--- a/tests/framework/test_environment.h
+++ b/tests/framework/test_environment.h
@@ -117,6 +117,147 @@
}
}
+// VulkanFunctions - loads vulkan functions for tests to use
+
+struct VulkanFunctions {
+#if !defined(BUILD_STATIC_LOADER)
+ LibraryWrapper loader;
+#endif
+ // Pre-Instance
+ PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
+ PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = nullptr;
+ PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = nullptr;
+ PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = nullptr;
+ PFN_vkCreateInstance vkCreateInstance = nullptr;
+
+ // Instance
+ PFN_vkDestroyInstance vkDestroyInstance = nullptr;
+ PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr;
+ PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups = nullptr;
+ PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures = nullptr;
+ PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2 = nullptr;
+ PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties = nullptr;
+ PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2 = nullptr;
+ PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties = nullptr;
+ PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2 = nullptr;
+ PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties = nullptr;
+ PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2 = nullptr;
+ PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = nullptr;
+ PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2 = nullptr;
+ PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
+ PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
+ PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = nullptr;
+ PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2 = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
+ PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties = nullptr;
+ PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties = nullptr;
+ PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties = nullptr;
+ PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties = nullptr;
+ PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties = nullptr;
+
+ PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
+ PFN_vkCreateDevice vkCreateDevice = nullptr;
+ PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
+ PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
+
+ // WSI
+ PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT = nullptr;
+ PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR = nullptr;
+ PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR = nullptr;
+ PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
+ PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR = nullptr;
+ PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR = nullptr;
+ PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR = nullptr;
+ PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR = nullptr;
+ PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR = nullptr;
+ PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR = nullptr;
+ PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR = nullptr;
+ PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR = nullptr;
+ PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR = nullptr;
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+ PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR = nullptr;
+#endif // VK_USE_PLATFORM_ANDROID_KHR
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+ PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT = nullptr;
+ PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT = nullptr;
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_FUCHSIA
+ PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
+#endif // VK_USE_PLATFORM_FUCHSIA
+#ifdef VK_USE_PLATFORM_GGP
+ PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP = nullptr;
+#endif // VK_USE_PLATFORM_GGP
+#ifdef VK_USE_PLATFORM_IOS_MVK
+ PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK = nullptr;
+#endif // VK_USE_PLATFORM_IOS_MVK
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+ PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = nullptr;
+#endif // VK_USE_PLATFORM_MACOS_MVK
+#ifdef VK_USE_PLATFORM_METAL_EXT
+ PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT = nullptr;
+#endif // VK_USE_PLATFORM_METAL_EXT
+#ifdef VK_USE_PLATFORM_SCREEN_QNX
+ PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX = nullptr;
+ PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX = nullptr;
+#endif // VK_USE_PLATFORM_SCREEN_QNX
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR = nullptr;
+ PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = nullptr;
+#endif // VK_USE_PLATFORM_WAYLAND_KHR
+#ifdef VK_USE_PLATFORM_XCB_KHR
+ PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR = nullptr;
+ PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = nullptr;
+#endif // VK_USE_PLATFORM_XCB_KHR
+#ifdef VK_USE_PLATFORM_XLIB_KHR
+ PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = nullptr;
+ PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = nullptr;
+#endif // VK_USE_PLATFORM_XLIB_KHR
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+ PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = nullptr;
+ PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = nullptr;
+#endif // VK_USE_PLATFORM_WIN32_KHR
+ PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = nullptr;
+
+ // device functions
+ PFN_vkDestroyDevice vkDestroyDevice = nullptr;
+ PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
+
+ VulkanFunctions();
+
+ FromVoidStarFunc load(VkInstance inst, const char* func_name) const {
+ return FromVoidStarFunc(vkGetInstanceProcAddr(inst, func_name));
+ }
+
+ FromVoidStarFunc load(VkDevice device, const char* func_name) const {
+ return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
+ }
+};
+
+struct DeviceFunctions {
+ PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
+ PFN_vkDestroyDevice vkDestroyDevice = nullptr;
+ PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
+ PFN_vkCreateCommandPool vkCreateCommandPool = nullptr;
+ PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = nullptr;
+ PFN_vkDestroyCommandPool vkDestroyCommandPool = nullptr;
+ PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
+ PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = nullptr;
+ PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = nullptr;
+
+ DeviceFunctions() = default;
+ DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device);
+
+ FromVoidStarFunc load(VkDevice device, const char* func_name) const {
+ return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
+ }
+};
+
// InstWrapper & DeviceWrapper - used to make creating instances & devices easier test writing
struct InstWrapper {
InstWrapper(VulkanFunctions& functions, VkAllocationCallbacks* callbacks = nullptr) noexcept;
@@ -211,6 +352,11 @@
DebugUtilsLogger& operator=(DebugUtilsLogger&&) = delete;
// Find a string in the log output
bool find(std::string const& search_text) const { return returned_output.find(search_text) != std::string::npos; }
+
+ // Look through the event log. If you find a line containing the prefix we're interested in, look for the end of
+ // line character, and then see if the postfix occurs in it as well.
+ bool find_prefix_then_postfix(const char* prefix, const char* postfix) const;
+
// Clear the log
void clear() { returned_output.clear(); }
VkDebugUtilsMessengerCreateInfoEXT* get() noexcept { return &create_info; }
@@ -262,7 +408,7 @@
struct FrameworkEnvironment; // forward declaration
struct PlatformShimWrapper {
- PlatformShimWrapper(std::vector<fs::FolderManager>* folders) noexcept;
+ PlatformShimWrapper(std::vector<fs::FolderManager>* folders, bool enable_log) noexcept;
~PlatformShimWrapper() noexcept;
PlatformShimWrapper(PlatformShimWrapper const&) = delete;
PlatformShimWrapper& operator=(PlatformShimWrapper const&) = delete;
@@ -319,6 +465,7 @@
}
BUILDER_VALUE(TestICDDetails, ManifestICD, icd_manifest, {});
BUILDER_VALUE(TestICDDetails, std::string, json_name, "test_icd");
+ BUILDER_VALUE(TestICDDetails, bool, disable_icd_inc, false);
BUILDER_VALUE(TestICDDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
BUILDER_VALUE(TestICDDetails, bool, is_fake, false);
};
@@ -330,6 +477,7 @@
BUILDER_VALUE(TestLayerDetails, std::string, json_name, "test_layer");
BUILDER_VALUE(TestLayerDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
BUILDER_VALUE(TestLayerDetails, bool, is_fake, false);
+ BUILDER_VALUE(TestLayerDetails, bool, is_dir, true);
};
enum class ManifestLocation {
@@ -345,7 +493,9 @@
};
struct FrameworkEnvironment {
- FrameworkEnvironment() noexcept;
+ FrameworkEnvironment() noexcept; // default is to enable VK_LOADER_DEBUG=all and enable the default search paths
+ FrameworkEnvironment(bool enable_log) noexcept;
+ FrameworkEnvironment(bool enable_log, bool enable_default_search_paths) noexcept;
void add_icd(TestICDDetails icd_details) noexcept;
void add_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
@@ -386,10 +536,27 @@
void add_layer_impl(TestLayerDetails layer_details, ManifestCategory category);
};
+// helper function which return a valid WSI platform extension
+// const char* api_selection: use this to select an extension on platforms that support multiple extensions
+const char* get_platform_wsi_extension(const char* api_selection = nullptr);
+
// The following helpers setup an icd with the required extensions and setting to use with WSI
// By default they use whatever the set VK_USE_PLATFORM_XXX macros define
-void setup_WSI_in_ICD(TestICD& icd);
-void setup_WSI_in_create_instance(InstWrapper& inst);
-// api_selection: optionally provide a VK_USE_PLATFORM_XXX string to select which API to create a surface with
-// Note: MUST provide api_selection on platforms with multiple viable API's, such as linux and MacOS
-VkSurfaceKHR create_surface(InstWrapper& inst, const char* api_selection = nullptr);
+void setup_WSI_in_ICD(TestICD& icd, const char* api_selection = nullptr);
+void setup_WSI_in_create_instance(InstWrapper& inst, const char* api_selection = nullptr);
+
+// Create a surface using a platform specific API
+// api_selection: optionally provide a VK_USE_PLATFORM_XXX string to select which API to create a surface with.
+// defaults to Metal on macOS and XCB on linux if not provided
+// Returns an assertion failure if the surface failed to be created
+testing::AssertionResult create_surface(InstWrapper& inst, VkSurfaceKHR& out_surface, const char* api_selection = nullptr);
+
+struct EnvVarCleaner {
+ std::string env_var;
+ EnvVarCleaner(std::string env_var) noexcept : env_var(env_var) {}
+ ~EnvVarCleaner() noexcept { remove_env_var(env_var); }
+
+ // delete copy operators
+ EnvVarCleaner(const EnvVarCleaner&) = delete;
+ EnvVarCleaner& operator=(const EnvVarCleaner&) = delete;
+};
diff --git a/tests/framework/test_util.cpp b/tests/framework/test_util.cpp
index f7acaee..c98ec1f 100644
--- a/tests/framework/test_util.cpp
+++ b/tests/framework/test_util.cpp
@@ -471,6 +471,8 @@
file << contents << std::endl;
return out_path;
}
+void FolderManager::add_existing_file(std::string const& file_name) { files.emplace_back(file_name); }
+
// close file handle, delete file, remove `name` from managed file list.
void FolderManager::remove(std::string const& name) {
path out_path = folder / name;
@@ -514,131 +516,8 @@
}
} // namespace fs
-bool string_eq(const char* a, const char* b) noexcept { return strcmp(a, b) == 0; }
-bool string_eq(const char* a, const char* b, size_t len) noexcept { return strncmp(a, b, len) == 0; }
-
-fs::path get_loader_path() {
- auto loader_path = fs::path(FRAMEWORK_VULKAN_LIBRARY_PATH);
- auto env_var_res = get_env_var("VK_LOADER_TEST_LOADER_PATH", false);
- if (!env_var_res.empty()) {
- loader_path = fs::path(env_var_res);
- }
- return loader_path;
-}
-
-VulkanFunctions::VulkanFunctions() : loader(get_loader_path()) {
- // clang-format off
- vkGetInstanceProcAddr = loader.get_symbol("vkGetInstanceProcAddr");
- vkEnumerateInstanceExtensionProperties = loader.get_symbol("vkEnumerateInstanceExtensionProperties");
- vkEnumerateInstanceLayerProperties = loader.get_symbol("vkEnumerateInstanceLayerProperties");
- vkEnumerateInstanceVersion = loader.get_symbol("vkEnumerateInstanceVersion");
- vkCreateInstance = loader.get_symbol("vkCreateInstance");
- vkDestroyInstance = loader.get_symbol("vkDestroyInstance");
- vkEnumeratePhysicalDevices = loader.get_symbol("vkEnumeratePhysicalDevices");
- vkEnumeratePhysicalDeviceGroups = loader.get_symbol("vkEnumeratePhysicalDeviceGroups");
- vkGetPhysicalDeviceFeatures = loader.get_symbol("vkGetPhysicalDeviceFeatures");
- vkGetPhysicalDeviceFeatures2 = loader.get_symbol("vkGetPhysicalDeviceFeatures2");
- vkGetPhysicalDeviceFormatProperties = loader.get_symbol("vkGetPhysicalDeviceFormatProperties");
- vkGetPhysicalDeviceFormatProperties2 = loader.get_symbol("vkGetPhysicalDeviceFormatProperties2");
- vkGetPhysicalDeviceImageFormatProperties = loader.get_symbol("vkGetPhysicalDeviceImageFormatProperties");
- vkGetPhysicalDeviceImageFormatProperties2 = loader.get_symbol("vkGetPhysicalDeviceImageFormatProperties2");
- vkGetPhysicalDeviceSparseImageFormatProperties = loader.get_symbol("vkGetPhysicalDeviceSparseImageFormatProperties");
- vkGetPhysicalDeviceSparseImageFormatProperties2 = loader.get_symbol("vkGetPhysicalDeviceSparseImageFormatProperties2");
- vkGetPhysicalDeviceProperties = loader.get_symbol("vkGetPhysicalDeviceProperties");
- vkGetPhysicalDeviceProperties2 = loader.get_symbol("vkGetPhysicalDeviceProperties2");
- vkGetPhysicalDeviceQueueFamilyProperties = loader.get_symbol("vkGetPhysicalDeviceQueueFamilyProperties");
- vkGetPhysicalDeviceQueueFamilyProperties2 = loader.get_symbol("vkGetPhysicalDeviceQueueFamilyProperties2");
- vkGetPhysicalDeviceMemoryProperties = loader.get_symbol("vkGetPhysicalDeviceMemoryProperties");
- vkGetPhysicalDeviceMemoryProperties2 = loader.get_symbol("vkGetPhysicalDeviceMemoryProperties2");
- vkGetPhysicalDeviceSurfaceSupportKHR = loader.get_symbol("vkGetPhysicalDeviceSurfaceSupportKHR");
- vkGetPhysicalDeviceSurfaceFormatsKHR = loader.get_symbol("vkGetPhysicalDeviceSurfaceFormatsKHR");
- vkGetPhysicalDeviceSurfacePresentModesKHR = loader.get_symbol("vkGetPhysicalDeviceSurfacePresentModesKHR");
- vkGetPhysicalDeviceSurfaceCapabilitiesKHR = loader.get_symbol("vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
- vkEnumerateDeviceExtensionProperties = loader.get_symbol("vkEnumerateDeviceExtensionProperties");
- vkEnumerateDeviceLayerProperties = loader.get_symbol("vkEnumerateDeviceLayerProperties");
- vkGetPhysicalDeviceExternalBufferProperties = loader.get_symbol("vkGetPhysicalDeviceExternalBufferProperties");
- vkGetPhysicalDeviceExternalFenceProperties = loader.get_symbol("vkGetPhysicalDeviceExternalFenceProperties");
- vkGetPhysicalDeviceExternalSemaphoreProperties = loader.get_symbol("vkGetPhysicalDeviceExternalSemaphoreProperties");
-
- vkDestroySurfaceKHR = loader.get_symbol("vkDestroySurfaceKHR");
- vkGetDeviceProcAddr = loader.get_symbol("vkGetDeviceProcAddr");
- vkCreateDevice = loader.get_symbol("vkCreateDevice");
-
- vkCreateHeadlessSurfaceEXT = loader.get_symbol("vkCreateHeadlessSurfaceEXT");
- vkCreateDisplayPlaneSurfaceKHR = loader.get_symbol("vkCreateDisplayPlaneSurfaceKHR");
- vkGetPhysicalDeviceDisplayPropertiesKHR = loader.get_symbol("vkGetPhysicalDeviceDisplayPropertiesKHR");
- vkGetPhysicalDeviceDisplayPlanePropertiesKHR = loader.get_symbol("vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
- vkGetDisplayPlaneSupportedDisplaysKHR = loader.get_symbol("vkGetDisplayPlaneSupportedDisplaysKHR");
- vkGetDisplayModePropertiesKHR = loader.get_symbol("vkGetDisplayModePropertiesKHR");
- vkCreateDisplayModeKHR = loader.get_symbol("vkCreateDisplayModeKHR");
- vkGetDisplayPlaneCapabilitiesKHR = loader.get_symbol("vkGetDisplayPlaneCapabilitiesKHR");
- vkGetPhysicalDevicePresentRectanglesKHR = loader.get_symbol("vkGetPhysicalDevicePresentRectanglesKHR");
- vkGetPhysicalDeviceDisplayProperties2KHR = loader.get_symbol("vkGetPhysicalDeviceDisplayProperties2KHR");
- vkGetPhysicalDeviceDisplayPlaneProperties2KHR = loader.get_symbol("vkGetPhysicalDeviceDisplayPlaneProperties2KHR");
- vkGetDisplayModeProperties2KHR = loader.get_symbol("vkGetDisplayModeProperties2KHR");
- vkGetDisplayPlaneCapabilities2KHR = loader.get_symbol("vkGetDisplayPlaneCapabilities2KHR");
- vkGetPhysicalDeviceSurfaceCapabilities2KHR = loader.get_symbol("vkGetPhysicalDeviceSurfaceCapabilities2KHR");
- vkGetPhysicalDeviceSurfaceFormats2KHR = loader.get_symbol("vkGetPhysicalDeviceSurfaceFormats2KHR");
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
- vkCreateAndroidSurfaceKHR = loader.get_symbol("vkCreateAndroidSurfaceKHR");
-#endif // VK_USE_PLATFORM_ANDROID_KHR
-#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
- vkCreateDirectFBSurfaceEXT = loader.get_symbol("vkCreateDirectFBSurfaceEXT");
- vkGetPhysicalDeviceDirectFBPresentationSupportEXT = loader.get_symbol("vkGetPhysicalDeviceDirectFBPresentationSupportEXT");
-#endif // VK_USE_PLATFORM_DIRECTFB_EXT
-#ifdef VK_USE_PLATFORM_FUCHSIA
- vkCreateImagePipeSurfaceFUCHSIA = loader.get_symbol("vkCreateImagePipeSurfaceFUCHSIA");
-#endif // VK_USE_PLATFORM_FUCHSIA
-#ifdef VK_USE_PLATFORM_GGP
- vkCreateStreamDescriptorSurfaceGGP = loader.get_symbol("vkCreateStreamDescriptorSurfaceGGP");
-#endif // VK_USE_PLATFORM_GGP
-#ifdef VK_USE_PLATFORM_IOS_MVK
- vkCreateIOSSurfaceMVK = loader.get_symbol("vkCreateIOSSurfaceMVK");
-#endif // VK_USE_PLATFORM_IOS_MVK
-#ifdef VK_USE_PLATFORM_MACOS_MVK
- vkCreateMacOSSurfaceMVK = loader.get_symbol("vkCreateMacOSSurfaceMVK");
-#endif // VK_USE_PLATFORM_MACOS_MVK
-#ifdef VK_USE_PLATFORM_METAL_EXT
- vkCreateMetalSurfaceEXT = loader.get_symbol("vkCreateMetalSurfaceEXT");
-#endif // VK_USE_PLATFORM_METAL_EXT
-#ifdef VK_USE_PLATFORM_SCREEN_QNX
- vkCreateScreenSurfaceQNX = loader.get_symbol("vkCreateScreenSurfaceQNX");
- vkGetPhysicalDeviceScreenPresentationSupportQNX = loader.get_symbol("vkGetPhysicalDeviceScreenPresentationSupportQNX");
-#endif // VK_USE_PLATFORM_SCREEN_QNX
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
- vkCreateWaylandSurfaceKHR = loader.get_symbol("vkCreateWaylandSurfaceKHR");
- vkGetPhysicalDeviceWaylandPresentationSupportKHR = loader.get_symbol("vkGetPhysicalDeviceWaylandPresentationSupportKHR");
-#endif // VK_USE_PLATFORM_WAYLAND_KHR
-#ifdef VK_USE_PLATFORM_XCB_KHR
- vkCreateXcbSurfaceKHR = loader.get_symbol("vkCreateXcbSurfaceKHR");
- vkGetPhysicalDeviceXcbPresentationSupportKHR = loader.get_symbol("vkGetPhysicalDeviceXcbPresentationSupportKHR");
-#endif // VK_USE_PLATFORM_XCB_KHR
-#ifdef VK_USE_PLATFORM_XLIB_KHR
- vkCreateXlibSurfaceKHR = loader.get_symbol("vkCreateXlibSurfaceKHR");
- vkGetPhysicalDeviceXlibPresentationSupportKHR = loader.get_symbol("vkGetPhysicalDeviceXlibPresentationSupportKHR");
-#endif // VK_USE_PLATFORM_XLIB_KHR
-#ifdef VK_USE_PLATFORM_WIN32_KHR
- vkCreateWin32SurfaceKHR = loader.get_symbol("vkCreateWin32SurfaceKHR");
- vkGetPhysicalDeviceWin32PresentationSupportKHR = loader.get_symbol("vkGetPhysicalDeviceWin32PresentationSupportKHR");
-#endif // VK_USE_PLATFORM_WIN32_KHR
-
- vkDestroyDevice = loader.get_symbol("vkDestroyDevice");
- vkGetDeviceQueue = loader.get_symbol("vkGetDeviceQueue");
-
- // clang-format on
-}
-
-DeviceFunctions::DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device) {
- vkGetDeviceProcAddr = vulkan_functions.vkGetDeviceProcAddr;
- vkDestroyDevice = load(device, "vkDestroyDevice");
- vkGetDeviceQueue = load(device, "vkGetDeviceQueue");
- vkCreateCommandPool = load(device, "vkCreateCommandPool");
- vkAllocateCommandBuffers = load(device, "vkAllocateCommandBuffers");
- vkDestroyCommandPool = load(device, "vkDestroyCommandPool");
- vkCreateSwapchainKHR = load(device, "vkCreateSwapchainKHR");
- vkDestroySwapchainKHR = load(device, "vkDestroySwapchainKHR");
-}
+bool string_eq(const char* a, const char* b) noexcept { return a && b && strcmp(a, b) == 0; }
+bool string_eq(const char* a, const char* b, size_t len) noexcept { return a && b && strncmp(a, b, len) == 0; }
InstanceCreateInfo::InstanceCreateInfo() {
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
@@ -667,13 +546,35 @@
}
DeviceQueueCreateInfo::DeviceQueueCreateInfo() { queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; }
+DeviceQueueCreateInfo::DeviceQueueCreateInfo(const VkDeviceQueueCreateInfo* create_info) {
+ queue_create_info = *create_info;
+ for (uint32_t i = 0; i < create_info->queueCount; i++) {
+ priorities.push_back(create_info->pQueuePriorities[i]);
+ }
+}
VkDeviceQueueCreateInfo DeviceQueueCreateInfo::get() noexcept {
queue_create_info.pQueuePriorities = priorities.data();
+ queue_create_info.queueCount = 1;
+ queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
return queue_create_info;
}
+DeviceCreateInfo::DeviceCreateInfo(const VkDeviceCreateInfo* create_info) {
+ dev = *create_info;
+ for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
+ enabled_extensions.push_back(create_info->ppEnabledExtensionNames[i]);
+ }
+ for (uint32_t i = 0; i < create_info->enabledLayerCount; i++) {
+ enabled_layers.push_back(create_info->ppEnabledLayerNames[i]);
+ }
+ for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
+ device_queue_infos.push_back(create_info->pQueueCreateInfos[i]);
+ }
+}
+
VkDeviceCreateInfo* DeviceCreateInfo::get() noexcept {
+ dev.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
dev.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
dev.ppEnabledLayerNames = enabled_layers.data();
dev.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
@@ -681,6 +582,7 @@
uint32_t index = 0;
for (auto& queue : queue_info_details) {
queue.queue_create_info.queueFamilyIndex = index++;
+ queue.queue_create_info.queueCount = 1;
device_queue_infos.push_back(queue.get());
}
diff --git a/tests/framework/test_util.h b/tests/framework/test_util.h
index 37791c2..4e20eb6 100644
--- a/tests/framework/test_util.h
+++ b/tests/framework/test_util.h
@@ -37,7 +37,6 @@
* LibraryWrapper - RAII wrapper for a library
* DispatchableHandle - RAII wrapper for vulkan dispatchable handle objects
* ostream overload for VkResult - prettifies googletest output
- * VulkanFunctions - loads vulkan functions for tests to use
* Instance & Device create info helpers
* operator == overloads for many vulkan structs - more concise tests
*/
@@ -210,8 +209,12 @@
FolderManager(FolderManager&& other) noexcept;
FolderManager& operator=(FolderManager&& other) noexcept;
+ // Add a manifest to the folder
path write_manifest(std::string const& name, std::string const& contents);
+ // Add an already existing file to the manager, so it will be cleaned up automatically
+ void add_existing_file(std::string const& file_name);
+
// close file handle, delete file, remove `name` from managed file list.
void remove(std::string const& name);
@@ -642,143 +645,6 @@
VkQueueFamilyProperties get() const noexcept { return properties; }
};
-struct VulkanFunctions {
- LibraryWrapper loader;
-
- // Pre-Instance
- PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
- PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = nullptr;
- PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = nullptr;
- PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = nullptr;
- PFN_vkCreateInstance vkCreateInstance = nullptr;
-
- // Instance
- PFN_vkDestroyInstance vkDestroyInstance = nullptr;
- PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr;
- PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups = nullptr;
- PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures = nullptr;
- PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2 = nullptr;
- PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties = nullptr;
- PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2 = nullptr;
- PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties = nullptr;
- PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2 = nullptr;
- PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties = nullptr;
- PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2 = nullptr;
- PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = nullptr;
- PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2 = nullptr;
- PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
- PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
- PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = nullptr;
- PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2 = nullptr;
- PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
- PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
- PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
- PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
- PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties = nullptr;
- PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties = nullptr;
- PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties = nullptr;
- PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties = nullptr;
- PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties = nullptr;
-
- PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
- PFN_vkCreateDevice vkCreateDevice = nullptr;
- PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
- PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
-
- // WSI
- PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT = nullptr;
- PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR = nullptr;
- PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR = nullptr;
- PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
- PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR = nullptr;
- PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR = nullptr;
- PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR = nullptr;
- PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR = nullptr;
- PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR = nullptr;
- PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR = nullptr;
- PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR = nullptr;
- PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR = nullptr;
- PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR = nullptr;
- PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR = nullptr;
- PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR = nullptr;
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
- PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR = nullptr;
-#endif // VK_USE_PLATFORM_ANDROID_KHR
-#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
- PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT = nullptr;
- PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT = nullptr;
-#endif // VK_USE_PLATFORM_DIRECTFB_EXT
-#ifdef VK_USE_PLATFORM_FUCHSIA
- PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
-#endif // VK_USE_PLATFORM_FUCHSIA
-#ifdef VK_USE_PLATFORM_GGP
- PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP = nullptr;
-#endif // VK_USE_PLATFORM_GGP
-#ifdef VK_USE_PLATFORM_IOS_MVK
- PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK = nullptr;
-#endif // VK_USE_PLATFORM_IOS_MVK
-#ifdef VK_USE_PLATFORM_MACOS_MVK
- PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = nullptr;
-#endif // VK_USE_PLATFORM_MACOS_MVK
-#ifdef VK_USE_PLATFORM_METAL_EXT
- PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT = nullptr;
-#endif // VK_USE_PLATFORM_METAL_EXT
-#ifdef VK_USE_PLATFORM_SCREEN_QNX
- PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX = nullptr;
- PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX = nullptr;
-#endif // VK_USE_PLATFORM_SCREEN_QNX
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
- PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR = nullptr;
- PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = nullptr;
-#endif // VK_USE_PLATFORM_WAYLAND_KHR
-#ifdef VK_USE_PLATFORM_XCB_KHR
- PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR = nullptr;
- PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = nullptr;
-#endif // VK_USE_PLATFORM_XCB_KHR
-#ifdef VK_USE_PLATFORM_XLIB_KHR
- PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = nullptr;
- PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = nullptr;
-#endif // VK_USE_PLATFORM_XLIB_KHR
-#ifdef VK_USE_PLATFORM_WIN32_KHR
- PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = nullptr;
- PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = nullptr;
-#endif // VK_USE_PLATFORM_WIN32_KHR
- PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = nullptr;
-
- // device functions
- PFN_vkDestroyDevice vkDestroyDevice = nullptr;
- PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
-
- VulkanFunctions();
-
- FromVoidStarFunc load(VkInstance inst, const char* func_name) const {
- return FromVoidStarFunc(vkGetInstanceProcAddr(inst, func_name));
- }
-
- FromVoidStarFunc load(VkDevice device, const char* func_name) const {
- return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
- }
-};
-
-struct DeviceFunctions {
- PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
- PFN_vkDestroyDevice vkDestroyDevice = nullptr;
- PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
- PFN_vkCreateCommandPool vkCreateCommandPool = nullptr;
- PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = nullptr;
- PFN_vkDestroyCommandPool vkDestroyCommandPool = nullptr;
- PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
- PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = nullptr;
-
- DeviceFunctions() = default;
- DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device);
-
- FromVoidStarFunc load(VkDevice device, const char* func_name) const {
- return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
- }
-};
-
struct InstanceCreateInfo {
BUILDER_VALUE(InstanceCreateInfo, VkInstanceCreateInfo, instance_info, {})
BUILDER_VALUE(InstanceCreateInfo, VkApplicationInfo, application_info, {})
@@ -801,14 +667,19 @@
};
struct DeviceQueueCreateInfo {
+ DeviceQueueCreateInfo();
+ DeviceQueueCreateInfo(const VkDeviceQueueCreateInfo* create_info);
+
BUILDER_VALUE(DeviceQueueCreateInfo, VkDeviceQueueCreateInfo, queue_create_info, {})
BUILDER_VECTOR(DeviceQueueCreateInfo, float, priorities, priority)
- DeviceQueueCreateInfo();
VkDeviceQueueCreateInfo get() noexcept;
};
struct DeviceCreateInfo {
+ DeviceCreateInfo() = default;
+ DeviceCreateInfo(const VkDeviceCreateInfo* create_info);
+
BUILDER_VALUE(DeviceCreateInfo, VkDeviceCreateInfo, dev, {})
BUILDER_VECTOR(DeviceCreateInfo, const char*, enabled_extensions, extension)
BUILDER_VECTOR(DeviceCreateInfo, const char*, enabled_layers, layer)
@@ -851,29 +722,19 @@
bool check_permutation(std::initializer_list<const char*> expected, std::array<T, U> const& returned) {
if (expected.size() != returned.size()) return false;
for (uint32_t i = 0; i < expected.size(); i++) {
- bool found = false;
- for (auto& elem : returned) {
- if (string_eq(*(expected.begin() + i), elem.layerName)) {
- found = true;
- break;
- }
- }
- if (!found) return false;
+ auto found = std::find_if(std::begin(returned), std::end(returned),
+ [&](T elem) { return string_eq(*(expected.begin() + i), elem.layerName); });
+ if (found == std::end(returned)) return false;
}
return true;
}
-template <typename T, size_t U>
+template <typename T>
bool check_permutation(std::initializer_list<const char*> expected, std::vector<T> const& returned) {
if (expected.size() != returned.size()) return false;
for (uint32_t i = 0; i < expected.size(); i++) {
- bool found = false;
- for (auto& elem : returned) {
- if (string_eq(*(expected.begin() + i), elem.layerName)) {
- found = true;
- break;
- }
- }
- if (!found) return false;
+ auto found = std::find_if(std::begin(returned), std::end(returned),
+ [&](T elem) { return string_eq(*(expected.begin() + i), elem.layerName); });
+ if (found == std::end(returned)) return false;
}
return true;
}
diff --git a/tests/live_verification/CMakeLists.txt b/tests/live_verification/CMakeLists.txt
index 87155e2..d9d5136 100644
--- a/tests/live_verification/CMakeLists.txt
+++ b/tests/live_verification/CMakeLists.txt
@@ -29,4 +29,4 @@
target_compile_options(macos_static_loader_build PUBLIC -fsanitize=thread)
target_link_options(macos_static_loader_build PUBLIC -fsanitize=thread)
endif()
-endif()
\ No newline at end of file
+endif()
diff --git a/tests/live_verification/dynamic_rendering_get_proc_addr.cpp b/tests/live_verification/dynamic_rendering_get_proc_addr.cpp
index f4a521f..95aea3e 100644
--- a/tests/live_verification/dynamic_rendering_get_proc_addr.cpp
+++ b/tests/live_verification/dynamic_rendering_get_proc_addr.cpp
@@ -69,7 +69,9 @@
VkCommandBufferBeginInfo begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VkResult res = vkBeginCommandBuffer(command_buffer, &begin_info);
- assert(res == VK_SUCCESS);
+ if (res != VK_SUCCESS) {
+ std::cout << "Failed to begin command buffer\n";
+ }
// call the dynamic rendering function -- should not go into the physical device function trampoline.
PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR =
@@ -79,4 +81,4 @@
vkCmdBeginRenderingKHR(command_buffer, &rendering_info);
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/loader_alloc_callback_tests.cpp b/tests/loader_alloc_callback_tests.cpp
index 56a20dd..0f2f2d0 100644
--- a/tests/loader_alloc_callback_tests.cpp
+++ b/tests/loader_alloc_callback_tests.cpp
@@ -49,61 +49,50 @@
VkAllocationCallbacks callbacks{};
// Implementation internals
struct AllocationDetails {
+ std::unique_ptr<char[]> allocation;
size_t requested_size_bytes;
size_t actual_size_bytes;
+ size_t alignment;
VkSystemAllocationScope alloc_scope;
};
const static size_t UNKNOWN_ALLOCATION = std::numeric_limits<size_t>::max();
size_t allocation_count = 0;
size_t call_count = 0;
- std::vector<std::unique_ptr<char[]>> allocations;
- std::vector<void*> allocations_aligned;
- std::vector<AllocationDetails> allocation_details;
- void add_element(std::unique_ptr<char[]>&& alloc, void* aligned_alloc, AllocationDetails detail) {
- allocations.push_back(std::move(alloc));
- allocations_aligned.push_back(aligned_alloc);
- allocation_details.push_back(detail);
- }
- void erase_index(size_t index) {
- allocations.erase(std::next(allocations.begin(), index));
- allocations_aligned.erase(std::next(allocations_aligned.begin(), index));
- allocation_details.erase(std::next(allocation_details.begin(), index));
- }
- size_t find_element(void* ptr) {
- auto it = std::find(allocations_aligned.begin(), allocations_aligned.end(), ptr);
- if (it == allocations_aligned.end()) return UNKNOWN_ALLOCATION;
- return it - allocations_aligned.begin();
- }
+ std::unordered_map<void*, AllocationDetails> allocations;
void* allocate(size_t size, size_t alignment, VkSystemAllocationScope alloc_scope) {
- if (settings.should_fail_on_allocation && allocation_count == settings.fail_after_allocations) return nullptr;
- if (settings.should_fail_after_set_number_of_calls && call_count == settings.fail_after_calls) return nullptr;
+ if ((settings.should_fail_on_allocation && allocation_count == settings.fail_after_allocations) ||
+ (settings.should_fail_after_set_number_of_calls && call_count == settings.fail_after_calls)) {
+ return nullptr;
+ }
call_count++;
- AllocationDetails detail{size, size + (alignment - 1), alloc_scope};
- auto alloc = std::unique_ptr<char[]>(new char[detail.actual_size_bytes]);
- if (!alloc) return nullptr;
- uint64_t addr = (uint64_t)alloc.get();
+ allocation_count++;
+ AllocationDetails detail{nullptr, size, size + (alignment - 1), alignment, alloc_scope};
+ detail.allocation = std::unique_ptr<char[]>(new char[detail.actual_size_bytes]);
+ if (!detail.allocation) {
+ abort();
+ };
+ uint64_t addr = (uint64_t)detail.allocation.get();
addr += (alignment - 1);
addr &= ~(alignment - 1);
void* aligned_alloc = (void*)addr;
- add_element(std::move(alloc), aligned_alloc, detail);
- allocation_count++;
- return allocations_aligned.back();
+ allocations.insert(std::make_pair(aligned_alloc, std::move(detail)));
+ return aligned_alloc;
}
void* reallocate(void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope alloc_scope) {
if (pOriginal == nullptr) {
return allocate(size, alignment, alloc_scope);
}
- size_t index = find_element(pOriginal);
- if (index == UNKNOWN_ALLOCATION) return nullptr;
- size_t original_size = allocation_details[index].requested_size_bytes;
+ auto elem = allocations.find(pOriginal);
+ if (elem == allocations.end()) return nullptr;
+ size_t original_size = elem->second.requested_size_bytes;
// We only care about the case where realloc is used to increase the size
if (size >= original_size && settings.should_fail_after_set_number_of_calls && call_count == settings.fail_after_calls)
return nullptr;
call_count++;
if (size == 0) {
- erase_index(index);
+ allocations.erase(elem);
allocation_count--;
return nullptr;
} else if (size < original_size) {
@@ -111,16 +100,18 @@
} else {
void* new_alloc = allocate(size, alignment, alloc_scope);
if (new_alloc == nullptr) return nullptr;
+ allocation_count--; // allocate() increments this, we we don't want that
+ call_count--; // allocate() also increments this, we don't want that
memcpy(new_alloc, pOriginal, original_size);
- erase_index(index);
+ allocations.erase(elem);
return new_alloc;
}
}
void free(void* pMemory) {
if (pMemory == nullptr) return;
- size_t index = find_element(pMemory);
- if (index == UNKNOWN_ALLOCATION) return;
- erase_index(index);
+ auto elem = allocations.find(pMemory);
+ if (elem == allocations.end()) return;
+ allocations.erase(elem);
assert(allocation_count != 0 && "Cant free when there are no valid allocations");
allocation_count--;
}
@@ -153,9 +144,7 @@
public:
MemoryTracker(MemoryTrackerSettings settings) noexcept : settings(settings) {
- allocations.reserve(512);
- allocations_aligned.reserve(512);
- allocation_details.reserve(512);
+ allocations.reserve(3000);
callbacks.pUserData = this;
callbacks.pfnAllocation = public_allocation;
@@ -170,9 +159,6 @@
bool empty() noexcept { return allocation_count == 0; }
- void update_settings(MemoryTrackerSettings new_settings) noexcept { settings = new_settings; }
- size_t current_allocation_count() const noexcept { return allocation_count; }
- size_t current_call_count() const noexcept { return call_count; }
// Static callbacks
static VKAPI_ATTR void* VKAPI_CALL public_allocation(void* pUserData, size_t size, size_t alignment,
VkSystemAllocationScope allocationScope) noexcept {
@@ -205,7 +191,7 @@
MemoryTracker tracker;
{
InstWrapper inst{env.vulkan_functions, tracker.get()};
- inst.CheckCreate();
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
}
ASSERT_TRUE(tracker.empty());
}
@@ -219,7 +205,7 @@
MemoryTracker tracker;
{
InstWrapper inst{env.vulkan_functions, tracker.get()};
- inst.CheckCreate();
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
auto* pfnCreateDevice = inst->vkGetInstanceProcAddr(inst, "vkCreateDevice");
auto* pfnDestroyDevice = inst->vkGetInstanceProcAddr(inst, "vkDestroyDevice");
@@ -239,7 +225,7 @@
driver.physical_devices.emplace_back("physical_device_0");
{
InstWrapper inst{env.vulkan_functions, tracker.get()};
- inst.CheckCreate();
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
uint32_t physical_count = 1;
uint32_t returned_physical_count = 0;
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
@@ -265,7 +251,7 @@
driver.physical_devices[0].add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
{
InstWrapper inst{env.vulkan_functions, tracker.get()};
- inst.CheckCreate();
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
uint32_t physical_count = 1;
uint32_t returned_physical_count = 0;
@@ -313,7 +299,7 @@
driver.physical_devices[0].add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
InstWrapper inst{env.vulkan_functions, tracker.get()};
- inst.CheckCreate();
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
uint32_t physical_count = 1;
uint32_t returned_physical_count = 0;
@@ -370,7 +356,7 @@
driver.physical_devices[0].add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
InstWrapper inst{env.vulkan_functions};
- inst.CheckCreate();
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
uint32_t physical_count = 1;
uint32_t returned_physical_count = 0;
@@ -453,7 +439,7 @@
driver_files += OS_ENV_VAR_LIST_SEPARATOR;
driver_files += (fs::path("totally_made_up") / "path_to_fake" / "jason_file.json").str();
set_env_var("VK_DRIVER_FILES", driver_files);
-
+ EnvVarCleaner cleaner("VK_DRIVER_FILES");
size_t fail_index = 66; // 0
VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
@@ -484,7 +470,7 @@
driver.physical_devices.emplace_back("physical_device_1");
driver.physical_devices[1].add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
- const char* layer_name = "VkLayerImplicit0";
+ const char* layer_name = "VK_LAYER_VkLayerImplicit0";
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name)
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
@@ -493,7 +479,7 @@
env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
InstWrapper inst{env.vulkan_functions};
- inst.CheckCreate();
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
uint32_t physical_count = 2;
uint32_t returned_physical_count = 0;
@@ -541,24 +527,49 @@
// leak memory if one of the out-of-memory conditions trigger.
TEST(Allocation, CreateInstanceDeviceIntentionalAllocFail) {
FrameworkEnvironment env{};
- env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+ uint32_t num_physical_devices = 4;
+ uint32_t num_implicit_layers = 3;
+ for (uint32_t i = 0; i < num_physical_devices; i++) {
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)
+ .icd_manifest.set_is_portability_driver(false)
+ .set_library_arch(sizeof(void*) == 8 ? "64" : "32"));
+ auto& driver = env.get_test_icd(i);
+ driver.set_icd_api_version(VK_API_VERSION_1_1);
+ driver.add_instance_extension("VK_KHR_get_physical_device_properties2");
+ driver.physical_devices.emplace_back("physical_device_0");
+ driver.physical_devices[0].add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
+ driver.physical_devices[0].add_extensions({"VK_EXT_one", "VK_EXT_two", "VK_EXT_three", "VK_EXT_four", "VK_EXT_five"});
+ }
- auto& driver = env.get_test_icd();
- driver.physical_devices.emplace_back("physical_device_0");
- driver.physical_devices[0].add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
+ env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE).set_is_fake(true));
- const char* layer_name = "VkLayerImplicit0";
+ const char* layer_name = "VK_LAYER_ImplicitAllocFail";
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(layer_name)
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
.set_disable_environment("DISABLE_ENV")),
"test_layer.json");
env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
+ for (uint32_t i = 1; i < num_implicit_layers + 1; i++) {
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("VK_LAYER_Implicit1" + std::to_string(i))
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DISABLE_ENV")),
+ "test_layer_" + std::to_string(i) + ".json");
+ }
+ std::fstream custom_json_file{COMPLEX_JSON_FILE, std::ios_base::in};
+ ASSERT_TRUE(custom_json_file.is_open());
+ std::stringstream custom_json_file_contents;
+ custom_json_file_contents << custom_json_file.rdbuf();
+
+ fs::path new_path = env.get_folder(ManifestLocation::explicit_layer)
+ .write_manifest("VkLayer_complex_file.json", custom_json_file_contents.str());
+ env.platform_shim->add_manifest(ManifestCategory::explicit_layer, new_path);
size_t fail_index = 0;
VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
- MemoryTracker tracker(MemoryTrackerSettings{false, 0, true, fail_index});
+ MemoryTracker tracker{MemoryTrackerSettings{false, 0, true, fail_index}};
fail_index++; // applies to the next loop
VkInstance instance;
@@ -568,8 +579,8 @@
ASSERT_TRUE(tracker.empty());
continue;
}
+ ASSERT_EQ(result, VK_SUCCESS);
- uint32_t physical_count = 1;
uint32_t returned_physical_count = 0;
result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, nullptr);
if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
@@ -577,37 +588,44 @@
ASSERT_TRUE(tracker.empty());
continue;
}
- ASSERT_EQ(physical_count, returned_physical_count);
+ ASSERT_EQ(result, VK_SUCCESS);
+ ASSERT_EQ(num_physical_devices, returned_physical_count);
- VkPhysicalDevice physical_device;
- result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, &physical_device);
+ std::vector<VkPhysicalDevice> physical_devices;
+ physical_devices.resize(returned_physical_count);
+ result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, physical_devices.data());
if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
ASSERT_TRUE(tracker.empty());
continue;
}
- ASSERT_EQ(physical_count, returned_physical_count);
+ ASSERT_EQ(result, VK_SUCCESS);
+ ASSERT_EQ(num_physical_devices, returned_physical_count);
+ for (uint32_t i = 0; i < returned_physical_count; i++) {
+ uint32_t family_count = 1;
+ uint32_t returned_family_count = 0;
+ env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices.at(i), &returned_family_count, nullptr);
+ ASSERT_EQ(returned_family_count, family_count);
- uint32_t family_count = 1;
- uint32_t returned_family_count = 0;
- env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, nullptr);
- ASSERT_EQ(returned_family_count, family_count);
+ VkQueueFamilyProperties family;
+ env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices.at(i), &returned_family_count, &family);
+ ASSERT_EQ(returned_family_count, family_count);
+ ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
+ ASSERT_EQ(family.queueCount, family_count);
+ ASSERT_EQ(family.timestampValidBits, 0U);
- VkQueueFamilyProperties family;
- env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, &family);
- ASSERT_EQ(returned_family_count, family_count);
- ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
- ASSERT_EQ(family.queueCount, family_count);
- ASSERT_EQ(family.timestampValidBits, 0U);
+ DeviceCreateInfo dev_create_info;
+ DeviceQueueCreateInfo queue_info;
+ queue_info.add_priority(0.0f);
+ dev_create_info.add_device_queue(queue_info);
- DeviceCreateInfo dev_create_info;
- DeviceQueueCreateInfo queue_info;
- queue_info.add_priority(0.0f);
- dev_create_info.add_device_queue(queue_info);
+ VkDevice device;
+ result = env.vulkan_functions.vkCreateDevice(physical_devices.at(i), dev_create_info.get(), tracker.get(), &device);
+ if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
+ break;
+ }
+ ASSERT_EQ(result, VK_SUCCESS);
- VkDevice device;
- result = env.vulkan_functions.vkCreateDevice(physical_device, dev_create_info.get(), tracker.get(), &device);
- if (result == VK_SUCCESS) {
env.vulkan_functions.vkDestroyDevice(device, tracker.get());
}
env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
@@ -724,7 +742,7 @@
}
ASSERT_EQ(physical_dev_count, returned_physical_count);
- std::array<VkDevice, 3> devices;
+ std::array<VkDevice, 5> devices;
for (uint32_t i = 0; i < returned_physical_count; i++) {
uint32_t family_count = 1;
uint32_t returned_family_count = 0;
diff --git a/tests/loader_debug_ext_tests.cpp b/tests/loader_debug_ext_tests.cpp
index 1cefbb8..59bb808 100644
--- a/tests/loader_debug_ext_tests.cpp
+++ b/tests/loader_debug_ext_tests.cpp
@@ -849,3 +849,163 @@
// Message should be found
ASSERT_EQ(true, message_found);
}
+
+void CheckDeviceFunctions(FrameworkEnvironment& env, bool use_GIPA, bool enable_debug_extensions) {
+ InstWrapper inst(env.vulkan_functions);
+ if (enable_debug_extensions) {
+ inst.create_info.add_extension("VK_EXT_debug_utils");
+ }
+ setup_WSI_in_create_instance(inst);
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+
+ auto phys_dev = inst.GetPhysDev();
+
+ DeviceWrapper dev{inst};
+ dev.create_info.add_extension("VK_KHR_swapchain");
+ dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+ if (enable_debug_extensions) {
+ dev.create_info.add_extension("VK_EXT_debug_marker");
+ }
+ // if the hardware doesn't support VK_EXT_debug_marker and we are trying to enable it, then we should exit since that will fail
+ // to create a device
+ if (enable_debug_extensions &&
+ env.get_test_icd().physical_devices.at(0).extensions.size() == 1 /*only swapchain should be available*/) {
+ dev.CheckCreate(phys_dev, VK_ERROR_EXTENSION_NOT_PRESENT);
+ return;
+ }
+ ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+ DeviceFunctions dev_funcs{env.vulkan_functions, dev};
+
+ VkSurfaceKHR surface{};
+ ASSERT_NO_FATAL_FAILURE(create_surface(inst, surface));
+
+ VkSwapchainCreateInfoKHR info{};
+ info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ info.surface = surface;
+
+ VkSwapchainKHR swapchain{};
+ ASSERT_EQ(VK_SUCCESS, dev_funcs.vkCreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain));
+
+ PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
+ DebugMarkerSetObjectTagEXT = use_GIPA ? inst.load("vkDebugMarkerSetObjectTagEXT") : dev.load("vkDebugMarkerSetObjectTagEXT");
+ PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
+ DebugMarkerSetObjectNameEXT = use_GIPA ? inst.load("vkDebugMarkerSetObjectNameEXT") : dev.load("vkDebugMarkerSetObjectNameEXT");
+ PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
+ SetDebugUtilsObjectNameEXT = use_GIPA ? inst.load("vkSetDebugUtilsObjectNameEXT") : dev.load("vkSetDebugUtilsObjectNameEXT");
+ PFN_vkSetDebugUtilsObjectTagEXT SetDebugUtilsObjectTagEXT;
+ SetDebugUtilsObjectTagEXT = use_GIPA ? inst.load("vkSetDebugUtilsObjectTagEXT") : dev.load("vkSetDebugUtilsObjectTagEXT");
+ PFN_vkQueueBeginDebugUtilsLabelEXT QueueBeginDebugUtilsLabelEXT;
+ QueueBeginDebugUtilsLabelEXT =
+ use_GIPA ? inst.load("vkQueueBeginDebugUtilsLabelEXT") : dev.load("vkQueueBeginDebugUtilsLabelEXT");
+ PFN_vkQueueEndDebugUtilsLabelEXT QueueEndDebugUtilsLabelEXT;
+ QueueEndDebugUtilsLabelEXT = use_GIPA ? inst.load("vkQueueEndDebugUtilsLabelEXT") : dev.load("vkQueueEndDebugUtilsLabelEXT");
+ PFN_vkQueueInsertDebugUtilsLabelEXT QueueInsertDebugUtilsLabelEXT;
+ QueueInsertDebugUtilsLabelEXT =
+ use_GIPA ? inst.load("vkQueueInsertDebugUtilsLabelEXT") : dev.load("vkQueueInsertDebugUtilsLabelEXT");
+ PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT;
+ CmdBeginDebugUtilsLabelEXT = use_GIPA ? inst.load("vkCmdBeginDebugUtilsLabelEXT") : dev.load("vkCmdBeginDebugUtilsLabelEXT");
+ PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
+ CmdEndDebugUtilsLabelEXT = use_GIPA ? inst.load("vkCmdEndDebugUtilsLabelEXT") : dev.load("vkCmdEndDebugUtilsLabelEXT");
+ PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
+ CmdInsertDebugUtilsLabelEXT = use_GIPA ? inst.load("vkCmdInsertDebugUtilsLabelEXT") : dev.load("vkCmdInsertDebugUtilsLabelEXT");
+
+ if (use_GIPA) {
+ // When querying from GIPA, these functions should always be found
+ ASSERT_TRUE(nullptr != DebugMarkerSetObjectTagEXT);
+ ASSERT_TRUE(nullptr != DebugMarkerSetObjectNameEXT);
+ // When querying from GIPA, these functions are found only if the extensions were enabled
+ ASSERT_EQ(enable_debug_extensions, nullptr != SetDebugUtilsObjectNameEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != SetDebugUtilsObjectTagEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != QueueBeginDebugUtilsLabelEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != QueueEndDebugUtilsLabelEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != QueueInsertDebugUtilsLabelEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != CmdBeginDebugUtilsLabelEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != CmdEndDebugUtilsLabelEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != CmdInsertDebugUtilsLabelEXT);
+ } else {
+ // When querying from GDPA, these functions are found only if the extensions were enabled
+ ASSERT_EQ(enable_debug_extensions, nullptr != DebugMarkerSetObjectTagEXT);
+ ASSERT_EQ(enable_debug_extensions, nullptr != DebugMarkerSetObjectNameEXT);
+ // When querying from GDPA, these functions should always be found
+ ASSERT_TRUE(nullptr != SetDebugUtilsObjectNameEXT);
+ ASSERT_TRUE(nullptr != SetDebugUtilsObjectTagEXT);
+ ASSERT_TRUE(nullptr != QueueBeginDebugUtilsLabelEXT);
+ ASSERT_TRUE(nullptr != QueueEndDebugUtilsLabelEXT);
+ ASSERT_TRUE(nullptr != QueueInsertDebugUtilsLabelEXT);
+ ASSERT_TRUE(nullptr != CmdBeginDebugUtilsLabelEXT);
+ ASSERT_TRUE(nullptr != CmdEndDebugUtilsLabelEXT);
+ ASSERT_TRUE(nullptr != CmdInsertDebugUtilsLabelEXT);
+ }
+ VkDebugUtilsObjectNameInfoEXT obj_name_info{};
+ obj_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+ obj_name_info.objectHandle = (uint64_t)swapchain;
+ obj_name_info.objectType = VK_OBJECT_TYPE_SWAPCHAIN_KHR;
+ obj_name_info.pObjectName = " Your mom!";
+ if (SetDebugUtilsObjectNameEXT) SetDebugUtilsObjectNameEXT(dev.dev, &obj_name_info);
+
+ VkDebugMarkerObjectTagInfoEXT marker_object_tag{};
+ VkDebugMarkerObjectNameInfoEXT marker_object_name{};
+ if (use_GIPA && !enable_debug_extensions) {
+ // These functions crash when the extension isn't enabled and the function was acquired with GIPA.
+ ASSERT_DEATH(DebugMarkerSetObjectTagEXT(dev.dev, &marker_object_tag), "");
+ ASSERT_DEATH(DebugMarkerSetObjectNameEXT(dev.dev, &marker_object_name), "");
+ } else {
+ if (DebugMarkerSetObjectTagEXT) DebugMarkerSetObjectTagEXT(dev.dev, &marker_object_tag);
+ if (DebugMarkerSetObjectNameEXT) DebugMarkerSetObjectNameEXT(dev.dev, &marker_object_name);
+ }
+ if (SetDebugUtilsObjectNameEXT) SetDebugUtilsObjectNameEXT(dev.dev, &obj_name_info);
+ VkDebugUtilsObjectTagInfoEXT utils_object_tag{};
+ if (SetDebugUtilsObjectTagEXT) SetDebugUtilsObjectTagEXT(dev.dev, &utils_object_tag);
+ VkQueue queue{};
+ dev.functions->vkGetDeviceQueue(dev.dev, 0, 0, &queue);
+ VkDebugUtilsLabelEXT utils_label{};
+ utils_label.pLabelName = "Testing testing 123";
+ if (QueueBeginDebugUtilsLabelEXT) QueueBeginDebugUtilsLabelEXT(queue, &utils_label);
+ if (QueueEndDebugUtilsLabelEXT) QueueEndDebugUtilsLabelEXT(queue);
+ if (QueueInsertDebugUtilsLabelEXT) QueueInsertDebugUtilsLabelEXT(queue, &utils_label);
+ VkCommandBuffer cmd_buf{};
+ VkCommandPool cmd_pool;
+ VkCommandPoolCreateInfo cmd_pool_info{};
+ cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ ASSERT_EQ(VK_SUCCESS, dev_funcs.vkCreateCommandPool(dev.dev, &cmd_pool_info, nullptr, &cmd_pool));
+ VkCommandBufferAllocateInfo cmd_buf_alloc_info{};
+ cmd_buf_alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ cmd_buf_alloc_info.commandBufferCount = 1;
+ cmd_buf_alloc_info.commandPool = cmd_pool;
+ ASSERT_EQ(VK_SUCCESS, dev_funcs.vkAllocateCommandBuffers(dev.dev, &cmd_buf_alloc_info, &cmd_buf));
+ if (CmdBeginDebugUtilsLabelEXT) CmdBeginDebugUtilsLabelEXT(cmd_buf, &utils_label);
+ if (CmdEndDebugUtilsLabelEXT) CmdEndDebugUtilsLabelEXT(cmd_buf);
+ if (CmdInsertDebugUtilsLabelEXT) CmdInsertDebugUtilsLabelEXT(cmd_buf, &utils_label);
+
+ dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+ env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr);
+}
+
+TEST(GetDeviceProcAddr, DebugFuncsWithTerminator) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+ setup_WSI_in_ICD(env.get_test_icd());
+ env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+ env.get_test_icd().physical_devices.at(0).add_extensions({"VK_KHR_swapchain"});
+ // Hardware doesn't support the debug extensions
+
+ // Use getDeviceProcAddr & vary enabling the debug extensions
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, false));
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, true));
+
+ // Use getInstanceProcAddr & vary enabling the debug extensions
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, false));
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, true));
+
+ // Now set the hardware to support the extensions and run the situations again
+ env.get_test_icd().physical_devices.at(0).add_extensions({"VK_EXT_debug_marker"});
+ env.get_test_icd().add_instance_extension("VK_EXT_debug_utils");
+
+ // Use getDeviceProcAddr & vary enabling the debug extensions
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, false));
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, false, true));
+
+ // Use getInstanceProcAddr & vary enabling the debug extensions
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, false));
+ ASSERT_NO_FATAL_FAILURE(CheckDeviceFunctions(env, true, true));
+}
diff --git a/tests/loader_envvar_tests.cpp b/tests/loader_envvar_tests.cpp
index 63e050c..d5682c0 100644
--- a/tests/loader_envvar_tests.cpp
+++ b/tests/loader_envvar_tests.cpp
@@ -147,8 +147,6 @@
EXPECT_TRUE(env.debug_log.find("vkCreateInstance: Found no drivers!"));
env.platform_shim->set_elevated_privilege(false);
-
- remove_env_var("VK_DRIVER_FILES");
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
@@ -200,6 +198,21 @@
check_paths(env.debug_log, ManifestCategory::implicit_layer, HOME);
check_paths(env.debug_log, ManifestCategory::explicit_layer, HOME);
}
+// Check that a json file in the paths don't cause the loader to crash
+TEST(EnvVarICDOverrideSetup, XDGContainsJsonFile) {
+ // Set up a layer path that includes default and user-specified locations,
+ // so that the test app can find them. Include some badly specified elements as well.
+ // Need to redirect the 'home' directory
+ set_env_var("XDG_CONFIG_DIRS", "bad_file.json");
+
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+ env.get_test_icd().physical_devices.push_back({});
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate(VK_SUCCESS);
+}
#endif
// Test VK_ADD_DRIVER_FILES environment variable
@@ -226,8 +239,6 @@
EXPECT_TRUE(env.debug_log.find("vkCreateInstance: Found no drivers!"));
env.platform_shim->set_elevated_privilege(false);
-
- remove_env_var("VK_ADD_DRIVER_FILES");
}
// Test Both VK_DRIVER_FILES and VK_ADD_DRIVER_FILES environment variable
@@ -250,9 +261,6 @@
uint32_t phys_dev_count = 3;
ASSERT_EQ(inst->vkEnumeratePhysicalDevices(inst.inst, &phys_dev_count, phys_devs_array.data()), VK_SUCCESS);
ASSERT_EQ(phys_dev_count, 3U);
-
- remove_env_var("VK_DRIVER_FILES");
- remove_env_var("VK_ADD_DRIVER_FILES");
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
@@ -278,7 +286,7 @@
std::string vk_layer_path = ":/tmp/carol::::/:";
vk_layer_path += (HOME / "/ with spaces/:::::/tandy:").str();
set_env_var("VK_LAYER_PATH", vk_layer_path);
-
+ EnvVarCleaner layer_path_cleaner("VK_LAYER_PATH");
InstWrapper inst1{env.vulkan_functions};
inst1.create_info.add_layer(layer_name);
FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
@@ -301,8 +309,6 @@
EXPECT_FALSE(env.debug_log.find("/tmp/carol"));
env.platform_shim->set_elevated_privilege(false);
-
- remove_env_var("VK_LAYER_PATH");
}
// Test VK_ADD_LAYER_PATH environment variable
@@ -327,6 +333,7 @@
std::string vk_layer_path = ":/tmp/carol::::/:";
vk_layer_path += (HOME / "/ with spaces/:::::/tandy:").str();
set_env_var("VK_ADD_LAYER_PATH", vk_layer_path);
+ EnvVarCleaner add_layer_path_cleaner("VK_ADD_LAYER_PATH");
InstWrapper inst1{env.vulkan_functions};
inst1.create_info.add_layer(layer_name);
@@ -350,8 +357,356 @@
EXPECT_FALSE(env.debug_log.find("/tmp/carol"));
env.platform_shim->set_elevated_privilege(false);
-
- remove_env_var("VK_ADD_LAYER_PATH");
}
#endif
+
+// Test that the driver filter select will only enable driver manifest files that match the filter
+TEST(EnvVarICDOverrideSetup, FilterSelectDriver) {
+ FrameworkEnvironment env{};
+ const char* filter_select_env_var = "VK_LOADER_DRIVERS_SELECT";
+
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6).set_disable_icd_inc(true).set_json_name("ABC_ICD"));
+ env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_6, VK_API_VERSION_1_2}.set_disable_icd_inc(true).set_json_name("BCD_ICD"));
+ env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_6, VK_API_VERSION_1_3}.set_disable_icd_inc(true).set_json_name("CDE_ICD"));
+
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match full-name
+ env.debug_log.clear();
+ set_env_var(filter_select_env_var, "ABC_ICD.json");
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match prefix
+ env.debug_log.clear();
+ set_env_var(filter_select_env_var, "ABC*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match suffix
+ env.debug_log.clear();
+ set_env_var(filter_select_env_var, "*C_ICD.json");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match sub-string
+ env.debug_log.clear();
+ set_env_var(filter_select_env_var, "*BC*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ inst5.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match all with star '*'
+ env.debug_log.clear();
+ set_env_var(filter_select_env_var, "*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ inst6.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match all with special name
+ env.debug_log.clear();
+ set_env_var(filter_select_env_var, "~all~");
+
+ InstWrapper inst7{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst7.create_info, env.debug_log);
+ inst7.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+}
+
+// Test that the driver filter disable disables driver manifest files that match the filter
+TEST(EnvVarICDOverrideSetup, FilterDisableDriver) {
+ FrameworkEnvironment env{};
+ const char* filter_disable_env_var = "VK_LOADER_DRIVERS_DISABLE";
+ EnvVarCleaner filter_disable_cleaner(filter_disable_env_var);
+
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6).set_disable_icd_inc(true).set_json_name("ABC_ICD"));
+ env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_6, VK_API_VERSION_1_2}.set_disable_icd_inc(true).set_json_name("BCD_ICD"));
+ env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_6, VK_API_VERSION_1_3}.set_disable_icd_inc(true).set_json_name("CDE_ICD"));
+
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match full-name
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "ABC_ICD.json");
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match prefix
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "ABC_*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match suffix
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "*C_ICD.json");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match substring
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "*BC*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ inst5.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match all with star '*'
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ inst6.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Match all with special name
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "~all~");
+
+ InstWrapper inst7{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst7.create_info, env.debug_log);
+ inst7.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+}
+
+// Test that the when both driver filter select and disable environment variables are present, that the
+// appropriate drivers are enabled and disabled
+TEST(EnvVarICDOverrideSetup, FilterSelectAndDisableDriver) {
+ FrameworkEnvironment env{};
+ const char* filter_select_env_var = "VK_LOADER_DRIVERS_SELECT";
+ const char* filter_disable_env_var = "VK_LOADER_DRIVERS_DISABLE";
+ EnvVarCleaner filter_select_cleaner(filter_select_env_var);
+ EnvVarCleaner filter_disable_cleaner(filter_disable_env_var);
+
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6).set_disable_icd_inc(true).set_json_name("ABC_ICD"));
+ env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_6, VK_API_VERSION_1_2}.set_disable_icd_inc(true).set_json_name("BCD_ICD"));
+ env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_6, VK_API_VERSION_1_3}.set_disable_icd_inc(true).set_json_name("CDE_ICD"));
+
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Disable two, but enable one
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "*BC*");
+ set_env_var(filter_select_env_var, "BCD*");
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Disable all, but enable two
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "*");
+ set_env_var(filter_select_env_var, "*BC*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+
+ // Disable all, but enable all
+ env.debug_log.clear();
+ set_env_var(filter_disable_env_var, "*");
+ set_env_var(filter_select_env_var, "*");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "ABC_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("ABC_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "BCD_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("BCD_ICD.json", "ignored because it was disabled by env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found ICD manifest file", "CDE_ICD.json"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because not selected by env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("CDE_ICD.json", "ignored because it was disabled by env var"));
+}
diff --git a/tests/loader_get_proc_addr_tests.cpp b/tests/loader_get_proc_addr_tests.cpp
index 64a3c74..20f7268 100644
--- a/tests/loader_get_proc_addr_tests.cpp
+++ b/tests/loader_get_proc_addr_tests.cpp
@@ -184,4 +184,111 @@
EnumeratePhysicalDevices = reinterpret_cast<PFN_vkGetInstanceProcAddr>(gipa(NULL, "vkEnumeratePhysicalDevices"));
handle_assert_null(EnumeratePhysicalDevices);
}
-}
\ No newline at end of file
+}
+
+// Swapchain functions which require a terminator in all cases have situations where the driver may have a
+// NULL function pointer but the loader shouldn't abort() if that is the case. Rather, it should log a message
+// and return VK_SUCCESS to maintain previous behavior.
+TEST(GetDeviceProcAddr, SwapchainFuncsWithTerminator) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+ setup_WSI_in_ICD(env.get_test_icd());
+ env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+ InstWrapper inst(env.vulkan_functions);
+ inst.create_info.add_extension("VK_EXT_debug_utils");
+ setup_WSI_in_create_instance(inst);
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+
+ VkSurfaceKHR surface{};
+ ASSERT_NO_FATAL_FAILURE(create_surface(inst, surface));
+
+ DebugUtilsWrapper log{inst};
+ ASSERT_EQ(VK_SUCCESS, CreateDebugUtilsMessenger(log));
+ auto phys_dev = inst.GetPhysDev();
+ {
+ DeviceWrapper dev{inst};
+ dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+ ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+ DeviceFunctions dev_funcs{env.vulkan_functions, dev};
+
+ PFN_vkCreateSwapchainKHR CreateSwapchainKHR = dev.load("vkCreateSwapchainKHR");
+ PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
+ PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR =
+ dev.load("vkGetDeviceGroupSurfacePresentModesKHR");
+ PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR = dev.load("vkCreateSharedSwapchainsKHR");
+ ASSERT_FALSE(CreateSwapchainKHR);
+ ASSERT_TRUE(inst_CreateSwapchainKHR);
+ ASSERT_FALSE(GetDeviceGroupSurfacePresentModesKHR);
+ ASSERT_FALSE(CreateSharedSwapchainsKHR);
+
+ VkSwapchainCreateInfoKHR info{};
+ info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ info.surface = surface;
+
+ VkSwapchainKHR swapchain{};
+ if (CreateSwapchainKHR) CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
+ ASSERT_FALSE(
+ log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+ "extension enabled?"));
+ log.logger.clear();
+ if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+ // try to call the vkCreateSwapchainKHR acquired from the instance - this *should* abort due to not enabling the extension
+ if (inst_CreateSwapchainKHR) {
+ ASSERT_DEATH(inst_CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain),
+ "vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+ "extension enabled?");
+ }
+ log.logger.clear();
+ if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+
+ VkDeviceGroupPresentModeFlagsKHR modes{};
+ if (GetDeviceGroupSurfacePresentModesKHR) GetDeviceGroupSurfacePresentModesKHR(dev.dev, surface, &modes);
+
+ if (CreateSharedSwapchainsKHR) CreateSharedSwapchainsKHR(dev.dev, 1, &info, nullptr, &swapchain);
+ }
+ {
+ env.get_test_icd().physical_devices.at(0).add_extensions(
+ {"VK_KHR_swapchain", "VK_KHR_display_swapchain", "VK_EXT_debug_marker"});
+
+ DeviceWrapper dev{inst};
+ dev.create_info.add_extensions({"VK_KHR_swapchain", "VK_KHR_display_swapchain", "VK_EXT_debug_marker"});
+ dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+ ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+ DeviceFunctions dev_funcs{env.vulkan_functions, dev};
+
+ PFN_vkCreateSwapchainKHR CreateSwapchainKHR = dev.load("vkCreateSwapchainKHR");
+ PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
+ PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR =
+ dev.load("vkGetDeviceGroupSurfacePresentModesKHR");
+ PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR = dev.load("vkCreateSharedSwapchainsKHR");
+ ASSERT_TRUE(CreateSwapchainKHR);
+ ASSERT_TRUE(inst_CreateSwapchainKHR);
+ ASSERT_TRUE(GetDeviceGroupSurfacePresentModesKHR);
+ ASSERT_TRUE(CreateSharedSwapchainsKHR);
+
+ VkSwapchainCreateInfoKHR info{};
+ info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ info.surface = surface;
+
+ VkSwapchainKHR swapchain{};
+ if (CreateSwapchainKHR) CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
+ ASSERT_FALSE(
+ log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+ "extension enabled?"));
+ log.logger.clear();
+ if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+ if (inst_CreateSwapchainKHR) inst_CreateSwapchainKHR(dev.dev, &info, nullptr, &swapchain);
+ ASSERT_FALSE(
+ log.find("vkCreateSwapchainKHR: Driver's function pointer was NULL, returning VK_SUCCESS. Was the VK_KHR_swapchain "
+ "extension enabled?"));
+ log.logger.clear();
+ if (dev_funcs.vkDestroySwapchainKHR) dev_funcs.vkDestroySwapchainKHR(dev.dev, swapchain, nullptr);
+
+ VkDeviceGroupPresentModeFlagsKHR modes{};
+ if (GetDeviceGroupSurfacePresentModesKHR) GetDeviceGroupSurfacePresentModesKHR(dev.dev, surface, &modes);
+
+ if (CreateSharedSwapchainsKHR) CreateSharedSwapchainsKHR(dev.dev, 1, &info, nullptr, &swapchain);
+ }
+ env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr);
+}
diff --git a/tests/loader_handle_validation_tests.cpp b/tests/loader_handle_validation_tests.cpp
index 614e433..e7751ce 100644
--- a/tests/loader_handle_validation_tests.cpp
+++ b/tests/loader_handle_validation_tests.cpp
@@ -1588,8 +1588,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkAndroidSurfaceCreateInfoKHR surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
@@ -1622,8 +1622,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkDirectFBSurfaceCreateInfoEXT surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT;
@@ -1656,8 +1656,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkImagePipeSurfaceCreateInfoFUCHSIA surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA;
@@ -1690,8 +1690,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkStreamDescriptorSurfaceCreateInfoGGP surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP;
@@ -1724,8 +1724,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkIOSSurfaceCreateInfoMVK surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
@@ -1745,7 +1745,7 @@
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
auto& driver = env.get_test_icd();
- setup_WSI_in_ICD(driver);
+ setup_WSI_in_ICD(driver, "VK_USE_PLATFORM_MACOS_MVK");
const char* wrap_objects_name = "WrapObjectsLayer";
env.add_explicit_layer(ManifestLayer{}.add_layer(
@@ -1757,9 +1757,9 @@
driver.physical_devices.back().queue_family_properties.push_back(family_props);
InstWrapper instance(env.vulkan_functions);
- setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
+ setup_WSI_in_create_instance(instance, "VK_USE_PLATFORM_MACOS_MVK");
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkMacOSSurfaceCreateInfoMVK surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
@@ -1779,7 +1779,7 @@
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
auto& driver = env.get_test_icd();
- setup_WSI_in_ICD(driver);
+ setup_WSI_in_ICD(driver, "VK_USE_PLATFORM_METAL_EXT");
const char* wrap_objects_name = "WrapObjectsLayer";
env.add_explicit_layer(ManifestLayer{}.add_layer(
@@ -1791,9 +1791,9 @@
driver.physical_devices.back().queue_family_properties.push_back(family_props);
InstWrapper instance(env.vulkan_functions);
- setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
+ setup_WSI_in_create_instance(instance, "VK_USE_PLATFORM_METAL_EXT");
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkMetalSurfaceCreateInfoEXT surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
@@ -1826,8 +1826,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkScreenSurfaceCreateInfoQNX surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX;
@@ -1860,8 +1860,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkViSurfaceCreateInfoNN surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN;
@@ -1881,7 +1881,7 @@
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
auto& driver = env.get_test_icd();
- setup_WSI_in_ICD(driver);
+ setup_WSI_in_ICD(driver, "VK_USE_PLATFORM_WAYLAND_KHR");
const char* wrap_objects_name = "WrapObjectsLayer";
env.add_explicit_layer(ManifestLayer{}.add_layer(
@@ -1893,9 +1893,9 @@
driver.physical_devices.back().queue_family_properties.push_back(family_props);
InstWrapper instance(env.vulkan_functions);
- setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
+ setup_WSI_in_create_instance(instance, "VK_USE_PLATFORM_WAYLAND_KHR");
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkWaylandSurfaceCreateInfoKHR surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
@@ -1928,8 +1928,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkWin32SurfaceCreateInfoKHR surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
@@ -1962,8 +1962,8 @@
InstWrapper instance(env.vulkan_functions);
setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkXcbSurfaceCreateInfoKHR surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
@@ -1983,8 +1983,10 @@
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
auto& driver = env.get_test_icd();
- setup_WSI_in_ICD(driver);
-
+ setup_WSI_in_ICD(driver, "VK_USE_PLATFORM_XLIB_KHR");
+ for (auto& ext : driver.instance_extensions) {
+ std::cout << ext.extensionName << "\n";
+ }
const char* wrap_objects_name = "WrapObjectsLayer";
env.add_explicit_layer(ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(wrap_objects_name).set_lib_path(TEST_LAYER_WRAP_OBJECTS)),
@@ -1995,9 +1997,13 @@
driver.physical_devices.back().queue_family_properties.push_back(family_props);
InstWrapper instance(env.vulkan_functions);
- setup_WSI_in_create_instance(instance);
- instance.CheckCreate();
+ setup_WSI_in_create_instance(instance, "VK_USE_PLATFORM_XLIB_KHR");
+ //
+ for (auto& ext : instance.create_info.enabled_extensions) {
+ std::cout << ext << "\n";
+ }
instance.create_info.add_layer(wrap_objects_name);
+ instance.CheckCreate();
VkXlibSurfaceCreateInfoKHR surf_create_info = {};
surf_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
diff --git a/tests/loader_layer_tests.cpp b/tests/loader_layer_tests.cpp
index ec07500..69f55be 100644
--- a/tests/loader_layer_tests.cpp
+++ b/tests/loader_layer_tests.cpp
@@ -33,9 +33,9 @@
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.CheckCreate(VK_SUCCESS);
if (check_for_enable) {
- ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + implicit_layer_name));
+ ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + implicit_layer_name));
} else {
- ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer ") + implicit_layer_name));
+ ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer \"") + implicit_layer_name));
}
}
env.debug_log.clear();
@@ -50,6 +50,9 @@
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
+ EnvVarCleaner disable_cleaner(disable_env_var);
+
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(implicit_layer_name)
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
@@ -68,10 +71,11 @@
set_env_var(enable_env_var, "0");
CheckLogForLayerString(env, implicit_layer_name, false);
- // // set enable env-var, layer should load
+ // set enable env-var, layer should load
set_env_var(enable_env_var, "1");
CheckLogForLayerString(env, implicit_layer_name, true);
+ // remove enable env var, so we can check what happens when only disable is present
remove_env_var(enable_env_var);
// set disable env-var to 0, layer should not load
@@ -86,9 +90,6 @@
set_env_var(enable_env_var, "1");
set_env_var(disable_env_var, "1");
CheckLogForLayerString(env, implicit_layer_name, false);
-
- remove_env_var(enable_env_var);
- remove_env_var(disable_env_var);
}
TEST(ImplicitLayers, OnlyDisableEnvVar) {
@@ -96,7 +97,7 @@
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
const char* implicit_layer_name = "ImplicitTestLayer";
const char* disable_env_var = "DISABLE_ME";
-
+ EnvVarCleaner disable_cleaner(disable_env_var);
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(implicit_layer_name)
.set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
@@ -123,9 +124,8 @@
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.create_info.add_layer(implicit_layer_name);
inst.CheckCreate(VK_SUCCESS);
- ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + implicit_layer_name));
+ ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + implicit_layer_name));
}
- remove_env_var(disable_env_var);
}
TEST(ImplicitLayers, PreInstanceEnumInstLayerProps) {
@@ -133,6 +133,7 @@
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
const char* implicit_layer_name = "ImplicitTestLayer";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner disable_cleaner(disable_env_var);
env.add_implicit_layer(
ManifestLayer{}
@@ -161,8 +162,6 @@
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr));
ASSERT_NE(count, 0U);
ASSERT_NE(count, layer_props);
-
- remove_env_var(disable_env_var);
}
TEST(ImplicitLayers, PreInstanceEnumInstExtProps) {
@@ -170,6 +169,7 @@
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
const char* implicit_layer_name = "ImplicitTestLayer";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner disable_cleaner(disable_env_var);
env.add_implicit_layer(ManifestLayer{}
.set_file_format_version(ManifestVersion(1, 1, 2))
@@ -198,8 +198,6 @@
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr));
ASSERT_NE(count, 0U);
ASSERT_NE(count, ext_props);
-
- remove_env_var(disable_env_var);
}
TEST(ImplicitLayers, PreInstanceVersion) {
@@ -210,6 +208,7 @@
const char* implicit_layer_name = "ImplicitTestLayer";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner disable_cleaner(disable_env_var);
env.add_implicit_layer(
ManifestLayer{}
@@ -239,8 +238,6 @@
ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceVersion(&version));
ASSERT_NE(version, 0U);
ASSERT_NE(version, layer_version);
-
- remove_env_var(disable_env_var);
}
// Run with a pre-Negotiate function version of the layer so that it has to query vkCreateInstance using the
@@ -254,6 +251,7 @@
const char* implicit_layer_name = "ImplicitTestLayer";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner disable_cleaner(disable_env_var);
env.add_implicit_layer(ManifestLayer{}
.set_file_format_version(ManifestVersion(1, 0, 0))
@@ -277,8 +275,697 @@
InstWrapper inst2{env.vulkan_functions};
inst2.CheckCreate();
}
+}
- remove_env_var(disable_env_var);
+// Force enable with filter env var
+TEST(ImplicitLayers, EnableWithFilter) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* implicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* implicit_json_name_1 = "First_layer.json";
+ const char* disable_layer_name_1 = "DISABLE_FIRST";
+ const char* enable_layer_name_1 = "ENABLE_FIRST";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_enable_environment(enable_layer_name_1)
+ .set_disable_environment(disable_layer_name_1)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_1);
+
+ const char* implicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* implicit_json_name_2 = "Second_layer.json";
+ const char* disable_layer_name_2 = "DISABLE_SECOND";
+ const char* enable_layer_name_2 = "ENABLE_SECOND";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_enable_environment(enable_layer_name_2)
+ .set_disable_environment(disable_layer_name_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_2);
+
+ const char* implicit_layer_name_3 = "VK_LAYER_LUNARG_Second_test_layer";
+ const char* implicit_json_name_3 = "Second_test_layer.json";
+ const char* disable_layer_name_3 = "DISABLE_THIRD";
+ const char* enable_layer_name_3 = "ENABLE_THIRD";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_3)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_enable_environment(enable_layer_name_3)
+ .set_disable_environment(disable_layer_name_3)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_3);
+
+ EnvVarCleaner layers_enable_cleaner("VK_LOADER_LAYERS_ENABLE");
+ EnvVarCleaner layer_1_enable_cleaner(enable_layer_name_1);
+
+ // First, test an instance/device without the layer forced on.
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Now force on one layer with its full name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", implicit_layer_name_1);
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match prefix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "VK_LAYER_LUNARG_*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match suffix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second_layer");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match substring
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ inst5.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with star '*'
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ inst6.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with special name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "~all~");
+
+ InstWrapper inst7{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst7.create_info, env.debug_log);
+ inst7.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match substring, but enable the other layer manually
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var(enable_layer_name_1, "1");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst8{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst8.create_info, env.debug_log);
+ inst8.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+}
+
+// Force disabled with new filter env var
+TEST(ImplicitLayers, DisableWithFilter) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* implicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* implicit_json_name_1 = "First_layer.json";
+ const char* disable_layer_name_1 = "DISABLE_FIRST";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_1)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_1);
+
+ const char* implicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* implicit_json_name_2 = "Second_layer.json";
+ const char* disable_layer_name_2 = "DISABLE_SECOND";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_2);
+
+ const char* implicit_layer_name_3 = "VK_LAYER_LUNARG_Second_test_layer";
+ const char* implicit_json_name_3 = "Second_test_layer.json";
+ const char* disable_layer_name_3 = "DISABLE_THIRD";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_3)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_3)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_3);
+
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+
+ // First, test an instance/device
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Now force off one layer with its full name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", implicit_layer_name_1);
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match prefix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "VK_LAYER_LUNARG_*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match suffix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*Second_layer");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match substring
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*Second*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ inst5.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with star '*'
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ inst6.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with special name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~all~");
+
+ InstWrapper inst7{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst7.create_info, env.debug_log);
+ inst7.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+}
+
+// Force disabled with new filter env var
+TEST(ImplicitLayers, DisableWithFilterWhenLayersEnableEnvVarIsActive) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* implicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* implicit_json_name_1 = "First_layer.json";
+ const char* disable_layer_name_1 = "DISABLE_FIRST";
+ const char* enable_layer_name_1 = "ENABLE_FIRST";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_1)
+ .set_enable_environment(enable_layer_name_1)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_1);
+
+ const char* implicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* implicit_json_name_2 = "Second_layer.json";
+ const char* disable_layer_name_2 = "DISABLE_SECOND";
+ const char* enable_layer_name_2 = "ENABLE_SECOND";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_2)
+ .set_enable_environment(enable_layer_name_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_2);
+
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+ EnvVarCleaner layer_1_enable_cleaner(enable_layer_name_1);
+ EnvVarCleaner layer_2_enable_cleaner(enable_layer_name_2);
+
+ // First, test an instance/device
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+
+ // Set the layers enable env-var
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var(enable_layer_name_1, "1");
+ set_env_var(enable_layer_name_2, "1");
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+
+ // Now force off one layer with its full name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", implicit_layer_name_1);
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+
+ // Now force off both layers
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~implicit~");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+}
+
+// Test interaction between both the enable and disable filter environment variables. The enable should always
+// override the disable.
+TEST(ImplicitLayers, EnableAndDisableWithFilter) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* implicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* implicit_json_name_1 = "First_layer.json";
+ const char* disable_layer_name_1 = "DISABLE_FIRST";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_1)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_1);
+
+ const char* implicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* implicit_json_name_2 = "Second_layer.json";
+ const char* disable_layer_name_2 = "DISABLE_SECOND";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_2);
+
+ const char* implicit_layer_name_3 = "VK_LAYER_LUNARG_Second_test_layer";
+ const char* implicit_json_name_3 = "Second_test_layer.json";
+ const char* disable_layer_name_3 = "DISABLE_THIRD";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name_3)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment(disable_layer_name_3)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ implicit_json_name_3);
+
+ EnvVarCleaner layers_enable_cleaner("VK_LOADER_LAYERS_ENABLE");
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+
+ // Disable 2 but enable 1
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*Second*");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*test_layer");
+
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable all but enable 2
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable all but enable 2
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~all~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable implicit but enable 2
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~implicit~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable explicit but enable 2 (should still be everything)
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~explicit~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ inst5.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable implicit but enable all
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~implicit~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ inst6.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", implicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", implicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(implicit_layer_name_3, "disabled because name matches filter of env var"));
}
// Meta layer which contains component layers that do not exist.
@@ -348,6 +1035,7 @@
ManifestLayer{}.add_layer(
ManifestLayer::LayerDescription{}.set_name(regular_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
"regular_test_layer.json");
+
{ // global functions
// should find 1, the 'regular' layer
uint32_t layer_count = 0;
@@ -580,6 +1268,7 @@
EXPECT_TRUE(string_eq(extensions[0].extensionName, device_ext_name));
}
}
+
// Override meta layer missing disable environment variable still enables the layer
TEST(OverrideMetaLayer, InvalidDisableEnvironment) {
FrameworkEnvironment env;
@@ -790,7 +1479,7 @@
inst.CheckCreate();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
// Newer component is allowed now
- EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + regular_layer_name));
env.debug_log.clear();
uint32_t count = 0;
env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
@@ -810,7 +1499,7 @@
inst.CheckCreate();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
// Newer component is allowed now
- EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + regular_layer_name));
env.debug_log.clear();
uint32_t count = 0;
env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
@@ -920,8 +1609,17 @@
.add_blacklisted_layer(manual_regular_layer_name)
.set_disable_environment("DisableMeIfYouCan")),
"meta_test_layer.json");
-
- { // enable the layer in the blacklist
+ { // Check that enumerating the layers returns only the non-blacklisted layers + override layer
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr);
+ ASSERT_EQ(count, 2U);
+ std::vector<VkLayerProperties> layer_props{2, VkLayerProperties{}};
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, layer_props.data());
+ ASSERT_EQ(count, 2U);
+ ASSERT_TRUE(check_permutation({automatic_regular_layer_name, lunarg_meta_layer_name}, layer_props));
+ }
+ {
+ // enable the layer in the blacklist
InstWrapper inst{env.vulkan_functions};
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.create_info.add_layer(manual_regular_layer_name);
@@ -979,7 +1677,7 @@
inst.create_info.set_api_version(1, 1, 0);
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.CheckCreate();
- ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + regular_layer_name));
+ ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + regular_layer_name));
env.layers.clear();
}
@@ -1022,7 +1720,7 @@
inst.create_info.add_layer(regular_layer_name);
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
- ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer ") + regular_layer_name));
+ ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer \"") + regular_layer_name));
env.layers.clear();
}
@@ -1067,7 +1765,7 @@
inst.create_info.add_layer(env_var_layer_name);
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
- ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer ") + env_var_layer_name));
+ ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer \"") + env_var_layer_name));
env.layers.clear();
remove_env_var("VK_LAYER_PATH");
@@ -1112,7 +1810,7 @@
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.create_info.set_api_version(1, 1, 0);
inst.CheckCreate();
- ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer ") + implicit_layer_name));
+ ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer \"") + implicit_layer_name));
ASSERT_TRUE(
env.debug_log.find("Removing meta-layer VK_LAYER_LUNARG_override from instance layer list since it appears invalid."));
env.layers.clear();
@@ -1147,7 +1845,7 @@
inst.create_info.set_api_version(1, 1, 0);
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.CheckCreate();
- ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + regular_layer_name));
+ ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + regular_layer_name));
ASSERT_TRUE(env.debug_log.find("Indicating meta-layer-specific override paths, but using older JSON file version."));
env.layers.clear();
}
@@ -1393,6 +2091,92 @@
}
}
+TEST(ExplicitLayers, VkLayerPathEnvVar) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+ env.get_test_icd().add_physical_device({});
+
+ {
+ // verify layer loads successfully when setting VK_LAYER_PATH to a full filepath
+ const char* regular_layer_name_1 = "RegularLayer1";
+ env.add_explicit_layer(
+ TestLayerDetails(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(regular_layer_name_1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "regular_layer_1.json").set_discovery_type(ManifestDiscoveryType::env_var).set_is_dir(false));
+
+ InstWrapper inst(env.vulkan_functions);
+ inst.create_info.add_layer(regular_layer_name_1);
+ inst.CheckCreate(VK_SUCCESS);
+ auto phys_dev = inst.GetPhysDev();
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
+ ASSERT_EQ(count, 1U);
+
+ VkLayerProperties layer_props;
+ env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, &layer_props);
+ EXPECT_TRUE(string_eq(layer_props.layerName, regular_layer_name_1));
+ }
+ {
+ // verify layers load successfully when setting VK_LAYER_PATH to multiple full filepaths
+ const char* regular_layer_name_1 = "RegularLayer1";
+ env.add_explicit_layer(
+ TestLayerDetails(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(regular_layer_name_1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "regular_layer_1.json").set_discovery_type(ManifestDiscoveryType::env_var).set_is_dir(false));
+
+ const char* regular_layer_name_2 = "RegularLayer2";
+ env.add_explicit_layer(
+ TestLayerDetails(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(regular_layer_name_2).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "regular_layer_2.json").set_discovery_type(ManifestDiscoveryType::env_var).set_is_dir(false));
+
+ InstWrapper inst(env.vulkan_functions);
+ inst.create_info.add_layer(regular_layer_name_1);
+ inst.create_info.add_layer(regular_layer_name_2);
+ inst.CheckCreate(VK_SUCCESS);
+ auto phys_dev = inst.GetPhysDev();
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
+ ASSERT_EQ(count, 2U);
+
+ std::array<VkLayerProperties, 2> layer_props;
+ env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, layer_props.data());
+ EXPECT_TRUE(check_permutation({regular_layer_name_1, regular_layer_name_2}, layer_props));
+ }
+ {
+ // verify layers load successfully when setting VK_LAYER_PATH to a directory
+ const char* regular_layer_name_1 = "RegularLayer1";
+ env.add_explicit_layer(
+ TestLayerDetails(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(regular_layer_name_1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "regular_layer_1.json").set_discovery_type(ManifestDiscoveryType::env_var));
+
+ const char* regular_layer_name_2 = "RegularLayer2";
+ env.add_explicit_layer(
+ TestLayerDetails(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(regular_layer_name_2).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "regular_layer_2.json").set_discovery_type(ManifestDiscoveryType::env_var));
+
+ InstWrapper inst(env.vulkan_functions);
+ inst.create_info.add_layer(regular_layer_name_1);
+ inst.create_info.add_layer(regular_layer_name_2);
+ inst.CheckCreate(VK_SUCCESS);
+ auto phys_dev = inst.GetPhysDev();
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
+ ASSERT_EQ(count, 2U);
+
+ std::array<VkLayerProperties, 2> layer_props;
+ env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, layer_props.data());
+ EXPECT_TRUE(check_permutation({regular_layer_name_1, regular_layer_name_2}, layer_props));
+ }
+}
+
TEST(LayerExtensions, ImplicitNoAdditionalInstanceExtension) {
FrameworkEnvironment env;
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -1405,6 +2189,7 @@
const char* implicit_layer_name = "VK_LAYER_LUNARG_wrap_objects";
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(implicit_layer_name)
@@ -1440,8 +2225,6 @@
// Make sure all the function pointers are NULL as well
handle_assert_null(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkReleaseDisplayEXT"));
handle_assert_null(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"));
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ImplicitDirDispModeInstanceExtension) {
@@ -1456,6 +2239,7 @@
const char* implicit_layer_name = "VK_LAYER_LUNARG_wrap_objects";
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
env.add_implicit_layer(
ManifestLayer{}.add_layer(
@@ -1495,8 +2279,6 @@
// Make sure only the appropriate function pointers are NULL as well
handle_assert_has_value(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkReleaseDisplayEXT"));
handle_assert_null(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"));
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ImplicitDispSurfCountInstanceExtension) {
@@ -1511,6 +2293,7 @@
const char* implicit_layer_name = "VK_LAYER_LUNARG_wrap_objects";
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(implicit_layer_name)
@@ -1550,8 +2333,6 @@
// Make sure only the appropriate function pointers are NULL as well
handle_assert_null(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkReleaseDisplayEXT"));
handle_assert_has_value(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"));
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ImplicitBothInstanceExtensions) {
@@ -1566,6 +2347,7 @@
const char* implicit_layer_name = "VK_LAYER_LUNARG_wrap_objects";
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
env.add_implicit_layer(
ManifestLayer{}.add_layer(
@@ -1608,8 +2390,6 @@
// Make sure only the appropriate function pointers are NULL as well
handle_assert_has_value(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkReleaseDisplayEXT"));
handle_assert_has_value(env.vulkan_functions.vkGetInstanceProcAddr(inst.inst, "vkGetPhysicalDeviceSurfaceCapabilities2EXT"));
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ExplicitNoAdditionalInstanceExtension) {
@@ -1929,6 +2709,7 @@
// // set enable env-var, layer should load
set_env_var(enable_env_var, "1");
+ EnvVarCleaner enable_cleaner(enable_env_var);
CheckLogForLayerString(env, implicit_layer_name, true);
InstWrapper inst{env.vulkan_functions};
@@ -1986,8 +2767,6 @@
ASSERT_DEATH(pfn_vkTrimCommandPool(dev.dev, VK_NULL_HANDLE, 0), "");
ASSERT_DEATH(pfn_vkGetSwapchainStatus(dev.dev, VK_NULL_HANDLE), "");
ASSERT_DEATH(pfn_vkSetDeviceMemoryPriority(dev.dev, VK_NULL_HANDLE, 0.f), "");
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ImplicitMaintenanceDeviceExtension) {
@@ -2002,6 +2781,7 @@
const char* implicit_layer_name = "VK_LAYER_LUNARG_wrap_objects";
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(implicit_layer_name)
@@ -2047,8 +2827,6 @@
// Make sure only the appropriate function pointers are NULL as well
handle_assert_has_value(dev->vkGetDeviceProcAddr(dev.dev, "vkTrimCommandPoolKHR"));
handle_assert_null(dev->vkGetDeviceProcAddr(dev.dev, "vkGetSwapchainStatusKHR"));
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ImplicitPresentImageDeviceExtension) {
@@ -2063,6 +2841,7 @@
const char* implicit_layer_name = "VK_LAYER_LUNARG_wrap_objects";
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(implicit_layer_name)
@@ -2109,8 +2888,6 @@
// Make sure only the appropriate function pointers are NULL as well
handle_assert_null(dev->vkGetDeviceProcAddr(dev.dev, "vkTrimCommandPoolKHR"));
handle_assert_has_value(dev->vkGetDeviceProcAddr(dev.dev, "vkGetSwapchainStatusKHR"));
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ImplicitBothDeviceExtensions) {
@@ -2125,6 +2902,7 @@
const char* implicit_layer_name = "VK_LAYER_LUNARG_wrap_objects";
const char* enable_env_var = "ENABLE_ME";
const char* disable_env_var = "DISABLE_ME";
+ EnvVarCleaner enable_cleaner(enable_env_var);
env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
.set_name(implicit_layer_name)
@@ -2176,8 +2954,6 @@
// Make sure only the appropriate function pointers are NULL as well
handle_assert_has_value(dev->vkGetDeviceProcAddr(dev.dev, "vkTrimCommandPoolKHR"));
handle_assert_has_value(dev->vkGetDeviceProcAddr(dev.dev, "vkGetSwapchainStatusKHR"));
-
- remove_env_var(enable_env_var);
}
TEST(LayerExtensions, ExplicitNoAdditionalDeviceExtension) {
@@ -2558,7 +3334,7 @@
inst.create_info.set_api_version(1, 1, 0);
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.CheckCreate();
- EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + regular_layer_name));
env.debug_log.clear();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
@@ -2575,7 +3351,7 @@
inst.create_info.set_api_version(1, 2, 0);
FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
inst.CheckCreate();
- EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + regular_layer_name));
env.debug_log.clear();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
@@ -2622,7 +3398,7 @@
inst.create_info.set_api_version(1, 0, 0);
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate();
- EXPECT_TRUE(log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(log.find(std::string("Insert instance layer \"") + regular_layer_name));
VkPhysicalDevice phys_dev = inst.GetPhysDev();
uint32_t count = 0;
@@ -2639,7 +3415,7 @@
inst.create_info.set_api_version(1, 1, 0);
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate();
- EXPECT_TRUE(log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(log.find(std::string("Insert instance layer \"") + regular_layer_name));
VkPhysicalDevice phys_dev = inst.GetPhysDev();
uint32_t count = 0;
env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
@@ -2656,7 +3432,7 @@
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate();
VkPhysicalDevice phys_dev = inst.GetPhysDev();
- EXPECT_TRUE(log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(log.find(std::string("Insert instance layer \"") + regular_layer_name));
uint32_t count = 0;
env.vulkan_functions.vkEnumerateDeviceLayerProperties(phys_dev, &count, nullptr);
EXPECT_EQ(1U, count);
@@ -2671,7 +3447,7 @@
inst.create_info.set_fill_in_application_info(false);
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate();
- EXPECT_TRUE(log.find(std::string("Insert instance layer ") + regular_layer_name));
+ EXPECT_TRUE(log.find(std::string("Insert instance layer \"") + regular_layer_name));
VkPhysicalDevice phys_dev = inst.GetPhysDev();
uint32_t count = 0;
@@ -2686,7 +3462,7 @@
// Verify that VK_INSTANCE_LAYERS work. To test this, make sure that an explicit layer does not affect an instance until
// it is set with VK_INSTANCE_LAYERS
-TEST(TestLayers, EnvironEnableExplicitLayer) {
+TEST(TestLayers, InstEnvironEnableExplicitLayer) {
FrameworkEnvironment env;
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
@@ -2735,6 +3511,7 @@
// Now setup the instance layer
set_env_var("VK_INSTANCE_LAYERS", explicit_layer_name);
+ EnvVarCleaner instance_layers_cleaner("VK_INSTANCE_LAYERS");
// Now, test an instance/device with the layer forced on. The extensions should be present and
// the function pointers should be valid.
@@ -2771,8 +3548,909 @@
handle_assert_has_value(pfn_GetSwapchainStatusAfter);
ASSERT_EQ(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR, pfn_GetSwapchainStatusAfter(dev2.dev, VK_NULL_HANDLE));
+}
- remove_env_var("VK_INSTANCE_LAYERS");
+// Verify that VK_LOADER_LAYERS_ENABLE work. To test this, make sure that an explicit layer does not affect an instance until
+// it is set with VK_LOADER_LAYERS_ENABLE
+TEST(TestLayers, EnvironLayerEnableExplicitLayer) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_1);
+
+ const char* explicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* explicit_json_name_2 = "Second_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_2);
+
+ const char* explicit_layer_name_3 = "VK_LAYER_LUNARG_second_test_layer";
+ const char* explicit_json_name_3 = "second_test_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_3)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_3);
+
+ EnvVarCleaner layers_enable_cleaner("VK_LOADER_LAYERS_ENABLE");
+
+ // First, test an instance/device without the layer forced on.
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Now force on one layer with its full name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", explicit_layer_name_1);
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match prefix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "VK_LAYER_LUNARG_*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match suffix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second_layer");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ inst4.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match substring
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ inst5.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with star '*'
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ inst6.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with special name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "~all~");
+
+ InstWrapper inst7{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst7.create_info, env.debug_log);
+ inst7.CheckCreate();
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+}
+
+// Verify that VK_LOADER_LAYERS_DISABLE work. To test this, make sure that an explicit layer does not affect an instance until
+// it is set with VK_LOADER_LAYERS_DISABLE
+TEST(TestLayers, EnvironLayerDisableExplicitLayer) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_1);
+
+ const char* explicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* explicit_json_name_2 = "Second_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_2);
+
+ const char* explicit_layer_name_3 = "VK_LAYER_LUNARG_Second_test_layer";
+ const char* explicit_json_name_3 = "Second_test_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_3)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_3);
+ EnvVarCleaner layers_enable_cleaner("VK_LOADER_LAYERS_ENABLE");
+
+ // First, test an instance/device without the layer forced on.
+ InstWrapper inst1{env.vulkan_functions};
+ inst1.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst1.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Now force on one layer with its full name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", explicit_layer_name_1);
+
+ InstWrapper inst2{env.vulkan_functions};
+ inst2.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst2.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match prefix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "VK_LAYER_LUNARG_*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ inst3.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst3.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match suffix
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*Second_layer");
+
+ InstWrapper inst4{env.vulkan_functions};
+ inst4.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst4.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match substring
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*Second*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ inst5.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst5.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with star '*'
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ inst6.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst6.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match all with special name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~all~");
+
+ InstWrapper inst7{env.vulkan_functions};
+ inst7.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst7.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst7.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Match explicit special name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~explicit~");
+
+ InstWrapper inst8{env.vulkan_functions};
+ inst8.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst8.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst8.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // No match implicit special name
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~implicit~");
+
+ InstWrapper inst9{env.vulkan_functions};
+ inst9.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst9.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst9.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+}
+
+// Verify that VK_LOADER_LAYERS_ENABLE + VK_LOADER_LAYERS_DISABLE work.(results in the layer still being
+// enabled)
+TEST(TestLayers, EnvironLayerEnableDisableExplicitLayer) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_1);
+
+ const char* explicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* explicit_json_name_2 = "Second_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_2);
+
+ const char* explicit_layer_name_3 = "VK_LAYER_LUNARG_Second_test_layer";
+ const char* explicit_json_name_3 = "Second_test_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_3)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_3);
+
+ EnvVarCleaner layers_enable_cleaner("VK_LOADER_LAYERS_ENABLE");
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+
+ // First, test an instance/device without the layer forced on.
+ InstWrapper inst1{env.vulkan_functions};
+ inst1.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst1.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable 2 but enable 1
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*Second*");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*test_layer");
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst2.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable all but enable 2
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst3.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable all but enable 2
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~all~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst4{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst4.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst4.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable explicit but enable 2
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~explicit~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst5{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst5.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst5.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable implicit but enable 2 (should still be everything)
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~implicit~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*Second*");
+
+ InstWrapper inst6{env.vulkan_functions};
+ inst6.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst6.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst6.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+
+ // Disable explicit but enable all
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "~explicit~");
+ set_env_var("VK_LOADER_LAYERS_ENABLE", "*");
+
+ InstWrapper inst7{env.vulkan_functions};
+ inst7.create_info.add_layer(explicit_layer_name_1).add_layer(explicit_layer_name_2).add_layer(explicit_layer_name_3);
+ FillDebugUtilsCreateDetails(inst7.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst7.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_3));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_3, "disabled because name matches filter of env var"));
+}
+
+// Verify that VK_INSTANCE_LAYERS + VK_LOADER_LAYERS_DISABLE work.(results in the layer still being
+// enabled)
+TEST(TestLayers, EnvironVkInstanceLayersAndDisableFilters) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_1);
+
+ const char* explicit_layer_name_2 = "VK_LAYER_LUNARG_Second_layer";
+ const char* explicit_json_name_2 = "Second_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_2);
+
+ EnvVarCleaner instance_layers_cleaner("VK_INSTANCE_LAYERS");
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+
+ // First, test an instance/device without the layer forced on.
+ InstWrapper inst1{env.vulkan_functions};
+ inst1.create_info.add_layer(explicit_layer_name_1);
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst1.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+
+ // Enable the non-default enabled layer with VK_INSTANCE_LAYERS
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_INSTANCE_LAYERS", explicit_layer_name_2);
+
+ InstWrapper inst2{env.vulkan_functions};
+ inst2.create_info.add_layer(explicit_layer_name_1);
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst2.CheckCreate());
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+
+ // Try to disable all
+ // ------------------------------------------
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", "*");
+
+ InstWrapper inst3{env.vulkan_functions};
+ inst3.create_info.add_layer(explicit_layer_name_1);
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst3.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer", explicit_layer_name_2));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_2, "disabled because name matches filter of env var"));
+}
+
+TEST(TestLayers, AppEnabledExplicitLayerFails) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0))),
+ explicit_json_name_1);
+
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", explicit_layer_name_1);
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr);
+ EXPECT_EQ(count, 0U);
+ std::vector<VkLayerProperties> layers;
+ layers.resize(1);
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, layers.data());
+ EXPECT_EQ(count, 0U);
+
+ InstWrapper inst3{env.vulkan_functions};
+ inst3.create_info.add_layer(explicit_layer_name_1);
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst3.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
+
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer ", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+}
+
+TEST(TestLayers, OverrideEnabledExplicitLayerWithDisableFilter) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))),
+ explicit_json_name_1);
+ env.add_implicit_layer(ManifestLayer{}
+ .set_file_format_version(ManifestVersion(1, 2, 0))
+ .add_layer(ManifestLayer::LayerDescription{}
+ .set_name(lunarg_meta_layer_name)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))
+ .add_component_layer(explicit_layer_name_1)
+ .set_disable_environment("DisableMeIfYouCan")),
+ "meta_test_layer.json");
+
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", explicit_layer_name_1);
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr);
+ EXPECT_EQ(count, 1U);
+ std::vector<VkLayerProperties> layers;
+ layers.resize(1);
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, layers.data());
+ EXPECT_EQ(count, 1U);
+ EXPECT_TRUE(string_eq(lunarg_meta_layer_name, &layers[0].layerName[0]));
+
+ { // both override layer and Disable env var
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer ", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(
+ env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ }
+ env.debug_log.clear();
+ { // Now try to enable the explicit layer as well
+ InstWrapper inst{env.vulkan_functions};
+ inst.create_info.add_layer(explicit_layer_name_1);
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer ", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(
+ env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ }
+}
+
+TEST(TestLayers, OverrideEnabledExplicitLayerWithDisableFilterForOverrideLayer) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))),
+ explicit_json_name_1);
+ env.add_implicit_layer(ManifestLayer{}
+ .set_file_format_version(ManifestVersion(1, 2, 0))
+ .add_layer(ManifestLayer::LayerDescription{}
+ .set_name(lunarg_meta_layer_name)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))
+ .add_component_layer(explicit_layer_name_1)
+ .set_disable_environment("DisableMeIfYouCan")),
+ "meta_test_layer.json");
+
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_DISABLE", lunarg_meta_layer_name);
+ EnvVarCleaner layers_disable_cleaner("VK_LOADER_LAYERS_DISABLE");
+
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr);
+ EXPECT_EQ(count, 1U);
+ std::vector<VkLayerProperties> layers;
+ layers.resize(1);
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, layers.data());
+ EXPECT_EQ(count, 1U);
+ EXPECT_TRUE(string_eq(explicit_layer_name_1, &layers[0].layerName[0]));
+
+ { // both override layer and Disable env var
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix("Insert instance layer ", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(
+ env.debug_log.find_prefix_then_postfix(lunarg_meta_layer_name, "disabled because name matches filter of env var"));
+ }
+ env.debug_log.clear();
+ { // Now try to enable the explicit layer as well
+ InstWrapper inst{env.vulkan_functions};
+ inst.create_info.add_layer(explicit_layer_name_1);
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer ", explicit_layer_name_1));
+ ASSERT_FALSE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_TRUE(
+ env.debug_log.find_prefix_then_postfix(lunarg_meta_layer_name, "disabled because name matches filter of env var"));
+ }
+}
+
+TEST(TestLayers, OverrideBlacklistedLayerWithEnableFilter) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA, VK_MAKE_API_VERSION(0, 1, 2, 0)));
+ env.get_test_icd().icd_api_version = VK_MAKE_API_VERSION(0, 1, 2, 0);
+
+ const char* explicit_layer_name_1 = "VK_LAYER_LUNARG_First_layer";
+ const char* explicit_json_name_1 = "First_layer.json";
+ env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(explicit_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))),
+ explicit_json_name_1);
+ env.add_implicit_layer(ManifestLayer{}
+ .set_file_format_version(ManifestVersion(1, 2, 0))
+ .add_layer(ManifestLayer::LayerDescription{}
+ .set_name(lunarg_meta_layer_name)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))
+ .add_blacklisted_layer(explicit_layer_name_1)
+ .set_disable_environment("DisableMeIfYouCan")),
+ "meta_test_layer.json");
+
+ env.debug_log.clear();
+ set_env_var("VK_LOADER_LAYERS_ENABLE", explicit_layer_name_1);
+ EnvVarCleaner layers_enable_cleaner("VK_LOADER_LAYERS_ENABLE");
+
+ uint32_t count = 0;
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr);
+ EXPECT_EQ(count, 1U);
+ std::vector<VkLayerProperties> layers;
+ layers.resize(1);
+ env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, layers.data());
+ EXPECT_EQ(count, 1U);
+ EXPECT_TRUE(string_eq(explicit_layer_name_1, &layers[0].layerName[0]));
+ {
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer ", explicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(
+ env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ }
+ env.debug_log.clear();
+ { // Try to enable a blacklisted layer
+ InstWrapper inst{env.vulkan_functions};
+ inst.create_info.add_layer(explicit_layer_name_1);
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Insert instance layer ", explicit_layer_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix("Found manifest file", explicit_json_name_1));
+ ASSERT_TRUE(env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "forced enabled due to env var"));
+ ASSERT_FALSE(
+ env.debug_log.find_prefix_then_postfix(explicit_layer_name_1, "disabled because name matches filter of env var"));
+ }
}
// Add a device layer, should not work
diff --git a/tests/loader_phys_dev_inst_ext_tests.cpp b/tests/loader_phys_dev_inst_ext_tests.cpp
index 14f4b57..f6bd061 100644
--- a/tests/loader_phys_dev_inst_ext_tests.cpp
+++ b/tests/loader_phys_dev_inst_ext_tests.cpp
@@ -122,6 +122,7 @@
// Test vkGetPhysicalDeviceProperties2 where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -130,32 +131,100 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
FillInRandomDeviceProps(env.get_test_icd(0).physical_devices.back().properties, VK_API_VERSION_1_1, 5, 123);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+ ASSERT_NE(GetPhysDevProps2, nullptr);
- auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
- ASSERT_NE(GetPhysDevProps2, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkPhysicalDeviceProperties props{};
+ instance->vkGetPhysicalDeviceProperties(physical_device, &props);
+ VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
+ GetPhysDevProps2(physical_device, &props2);
- VkPhysicalDeviceProperties props{};
- instance->vkGetPhysicalDeviceProperties(physical_device, &props);
- VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
- GetPhysDevProps2(physical_device, &props2);
+ // Both properties should match
+ ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
+ ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
+ ASSERT_EQ(props.vendorID, props2.properties.vendorID);
+ ASSERT_EQ(props.deviceID, props2.properties.deviceID);
+ ASSERT_EQ(props.deviceType, props2.properties.deviceType);
+ ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
+ }
- // Both properties should match
- ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
- ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
- ASSERT_EQ(props.vendorID, props2.properties.vendorID);
- ASSERT_EQ(props.deviceID, props2.properties.deviceID);
- ASSERT_EQ(props.deviceType, props2.properties.deviceType);
- ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
+ { // Do the same logic but have the application forget to use 1.1 and doesn't enable the extension - should emulate the call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+ ASSERT_NE(GetPhysDevProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceProperties props{};
+ instance->vkGetPhysicalDeviceProperties(physical_device, &props);
+ VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
+ GetPhysDevProps2(physical_device, &props2);
+
+ // Both properties should match
+ ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
+ ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
+ ASSERT_EQ(props.vendorID, props2.properties.vendorID);
+ ASSERT_EQ(props.deviceID, props2.properties.deviceID);
+ ASSERT_EQ(props.deviceType, props2.properties.deviceType);
+ ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+ ASSERT_NE(GetPhysDevProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceProperties props{};
+ instance->vkGetPhysicalDeviceProperties(physical_device, &props);
+ VkPhysicalDeviceProperties2KHR props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR};
+ GetPhysDevProps2(physical_device, &props2);
+
+ // Both properties should match
+ ASSERT_EQ(props.apiVersion, props2.properties.apiVersion);
+ ASSERT_EQ(props.driverVersion, props2.properties.driverVersion);
+ ASSERT_EQ(props.vendorID, props2.properties.vendorID);
+ ASSERT_EQ(props.deviceID, props2.properties.deviceID);
+ ASSERT_EQ(props.deviceType, props2.properties.deviceType);
+ ASSERT_EQ(0, memcmp(props.pipelineCacheUUID, props2.properties.pipelineCacheUUID, VK_UUID_SIZE));
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceProperties2 and vkGetPhysicalDeviceProperties2KHR where ICD is 1.0 and supports
@@ -463,6 +532,7 @@
// Test vkGetPhysicalDeviceFeatures2 where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevFeats2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -471,25 +541,80 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
FillInRandomFeatures(env.get_test_icd(0).physical_devices.back().features);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+ ASSERT_NE(GetPhysDevFeats2, nullptr);
- auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
- ASSERT_NE(GetPhysDevFeats2, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkPhysicalDeviceFeatures feats{};
+ instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
+ VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+ GetPhysDevFeats2(physical_device, &feats2);
+ ASSERT_TRUE(CompareFeatures(feats, feats2));
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- VkPhysicalDeviceFeatures feats{};
- instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
- VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
- GetPhysDevFeats2(physical_device, &feats2);
- ASSERT_TRUE(CompareFeatures(feats, feats2));
+ auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+ ASSERT_NE(GetPhysDevFeats2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceFeatures feats{};
+ instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
+ VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+ GetPhysDevFeats2(physical_device, &feats2);
+ ASSERT_TRUE(CompareFeatures(feats, feats2));
+
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevFeats2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+ ASSERT_NE(GetPhysDevFeats2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceFeatures feats{};
+ instance->vkGetPhysicalDeviceFeatures(physical_device, &feats);
+ VkPhysicalDeviceFeatures2 feats2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+ GetPhysDevFeats2(physical_device, &feats2);
+ ASSERT_TRUE(CompareFeatures(feats, feats2));
+
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceFeatures2 and vkGetPhysicalDeviceFeatures2KHR where ICD is 1.0 and supports
@@ -686,6 +811,7 @@
// Test vkGetPhysicalDeviceFormatProperties2 where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevFormatProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -694,30 +820,88 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
FillInRandomFormatProperties(env.get_test_icd(0).physical_devices.back().format_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2"));
+ ASSERT_NE(GetPhysDevFormatProps2, nullptr);
- auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2"));
- ASSERT_NE(GetPhysDevFormatProps2, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkFormatProperties props{};
+ instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
+ VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+ GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
- VkFormatProperties props{};
- instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
- VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
- GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
+ ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
+ ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
+ ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
+ }
+ { // Do the same logic but have the application forget to enable 1.1 and doesn't enable the extension
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
- ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
- ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
+ auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2"));
+ ASSERT_NE(GetPhysDevFormatProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkFormatProperties props{};
+ instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
+ VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+ GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
+
+ ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
+ ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
+ ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2"));
+ ASSERT_NE(GetPhysDevFormatProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkFormatProperties props{};
+ instance->vkGetPhysicalDeviceFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props);
+ VkFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+ GetPhysDevFormatProps2(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &props2);
+
+ ASSERT_EQ(props.bufferFeatures, props2.formatProperties.bufferFeatures);
+ ASSERT_EQ(props.linearTilingFeatures, props2.formatProperties.linearTilingFeatures);
+ ASSERT_EQ(props.optimalTilingFeatures, props2.formatProperties.optimalTilingFeatures);
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
-
// Test vkGetPhysicalDeviceFormatProperties2 and vkGetPhysicalDeviceFormatProperties2KHR where ICD is 1.0 and supports
// extension but the instance supports 1.1 and the extension
TEST(LoaderInstPhysDevExts, PhysDevFormatProps2KHRInstanceSupports11) {
@@ -934,6 +1118,7 @@
// Test vkGetPhysicalDeviceImageFormatProperties2 where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevImageFormatProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -942,45 +1127,138 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
FillInRandomImageFormatData(env.get_test_icd(0).physical_devices.back().image_format_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2"));
+ ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
- auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2"));
- ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkImageFormatProperties props{};
+ ASSERT_EQ(VK_SUCCESS,
+ instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
- VkImageFormatProperties props{};
- ASSERT_EQ(VK_SUCCESS,
- instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
- VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
+ VkPhysicalDeviceImageFormatInfo2 info2{
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType
+ nullptr, // pNext
+ VK_FORMAT_R4G4_UNORM_PACK8, // format
+ VK_IMAGE_TYPE_2D, // type
+ VK_IMAGE_TILING_OPTIMAL, // tiling
+ 0, // usage
+ 0, // flags
+ };
- VkPhysicalDeviceImageFormatInfo2 info2{
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType
- nullptr, // pNext
- VK_FORMAT_R4G4_UNORM_PACK8, // format
- VK_IMAGE_TYPE_2D, // type
- VK_IMAGE_TILING_OPTIMAL, // tiling
- 0, // usage
- 0, // flags
- };
+ VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+ ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
- VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
- ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
+ ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
+ ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
+ ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
+ ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
+ ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
+ ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
+ ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
- ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
- ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
- ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
- ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
- ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
- ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
+ auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2"));
+ ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkImageFormatProperties props{};
+ ASSERT_EQ(VK_SUCCESS,
+ instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
+
+ VkPhysicalDeviceImageFormatInfo2 info2{
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType
+ nullptr, // pNext
+ VK_FORMAT_R4G4_UNORM_PACK8, // format
+ VK_IMAGE_TYPE_2D, // type
+ VK_IMAGE_TILING_OPTIMAL, // tiling
+ 0, // usage
+ 0, // flags
+ };
+
+ VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+ ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
+
+ ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
+ ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
+ ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
+ ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
+ ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
+ ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
+ ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties2"));
+ ASSERT_NE(GetPhysDevImageFormatProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkImageFormatProperties props{};
+ ASSERT_EQ(VK_SUCCESS,
+ instance->vkGetPhysicalDeviceImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_IMAGE_TILING_OPTIMAL, 0, 0, &props));
+
+ VkPhysicalDeviceImageFormatInfo2 info2{
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType
+ nullptr, // pNext
+ VK_FORMAT_R4G4_UNORM_PACK8, // format
+ VK_IMAGE_TYPE_2D, // type
+ VK_IMAGE_TILING_OPTIMAL, // tiling
+ 0, // usage
+ 0, // flags
+ };
+
+ VkImageFormatProperties2 props2{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
+ ASSERT_EQ(VK_SUCCESS, GetPhysDevImageFormatProps2(physical_device, &info2, &props2));
+
+ ASSERT_EQ(props.maxExtent.width, props2.imageFormatProperties.maxExtent.width);
+ ASSERT_EQ(props.maxExtent.height, props2.imageFormatProperties.maxExtent.height);
+ ASSERT_EQ(props.maxExtent.depth, props2.imageFormatProperties.maxExtent.depth);
+ ASSERT_EQ(props.maxMipLevels, props2.imageFormatProperties.maxMipLevels);
+ ASSERT_EQ(props.maxArrayLayers, props2.imageFormatProperties.maxArrayLayers);
+ ASSERT_EQ(props.sampleCounts, props2.imageFormatProperties.sampleCounts);
+ ASSERT_EQ(props.maxResourceSize, props2.imageFormatProperties.maxResourceSize);
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceImageFormatProperties2 and vkGetPhysicalDeviceImageFormatProperties2KHR where instance supports, an ICD,
@@ -1237,6 +1515,7 @@
// Test vkGetPhysicalDeviceMemoryProperties2 where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevMemoryProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -1245,26 +1524,81 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
FillInRandomMemoryData(env.get_test_icd(0).physical_devices.back().memory_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2"));
+ ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
- auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2"));
- ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkPhysicalDeviceMemoryProperties props{};
+ instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
- VkPhysicalDeviceMemoryProperties props{};
- instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
+ VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
+ GetPhysDevMemoryProps2(physical_device, &props2);
+ ASSERT_TRUE(CompareMemoryData(props, props2));
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
- GetPhysDevMemoryProps2(physical_device, &props2);
- ASSERT_TRUE(CompareMemoryData(props, props2));
+ auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2"));
+ ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceMemoryProperties props{};
+ instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
+
+ VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
+ GetPhysDevMemoryProps2(physical_device, &props2);
+ ASSERT_TRUE(CompareMemoryData(props, props2));
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevMemoryProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2"));
+ ASSERT_NE(GetPhysDevMemoryProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceMemoryProperties props{};
+ instance->vkGetPhysicalDeviceMemoryProperties(physical_device, &props);
+
+ VkPhysicalDeviceMemoryProperties2 props2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
+ GetPhysDevMemoryProps2(physical_device, &props2);
+ ASSERT_TRUE(CompareMemoryData(props, props2));
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceMemoryProperties2 and vkGetPhysicalDeviceMemoryProperties2KHR where ICD is 1.0 and supports
@@ -1489,6 +1823,7 @@
// Test vkGetPhysicalDeviceQueueFamilyProperties2 where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevQueueFamilyProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -1497,35 +1832,108 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
uint32_t num_fam = FillInRandomQueueFamilyData(env.get_test_icd(0).physical_devices.back().queue_family_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2"));
+ ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
- auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2"));
- ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ uint32_t ret_fam_1 = 0;
+ std::vector<VkQueueFamilyProperties> props{};
+ instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
+ ASSERT_EQ(num_fam, ret_fam_1);
+ props.resize(ret_fam_1);
- uint32_t ret_fam_1 = 0;
- std::vector<VkQueueFamilyProperties> props{};
- instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
- ASSERT_EQ(num_fam, ret_fam_1);
- props.resize(ret_fam_1);
+ instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
- instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
+ std::vector<VkQueueFamilyProperties2> props2{};
+ uint32_t ret_fam_2 = 0;
+ GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
+ ASSERT_EQ(ret_fam_1, ret_fam_2);
+ props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
+ GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
+ ASSERT_TRUE(CompareQueueFamilyData(props, props2));
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- std::vector<VkQueueFamilyProperties2> props2{};
- uint32_t ret_fam_2 = 0;
- GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
- ASSERT_EQ(ret_fam_1, ret_fam_2);
- props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
- GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
- ASSERT_TRUE(CompareQueueFamilyData(props, props2));
+ auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2"));
+ ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ uint32_t ret_fam_1 = 0;
+ std::vector<VkQueueFamilyProperties> props{};
+ instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
+ ASSERT_EQ(num_fam, ret_fam_1);
+ props.resize(ret_fam_1);
+
+ instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
+
+ std::vector<VkQueueFamilyProperties2> props2{};
+ uint32_t ret_fam_2 = 0;
+ GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
+ ASSERT_EQ(ret_fam_1, ret_fam_2);
+ props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
+ GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
+ ASSERT_TRUE(CompareQueueFamilyData(props, props2));
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevQueueFamilyProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2"));
+ ASSERT_NE(GetPhysDevQueueFamilyProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ uint32_t ret_fam_1 = 0;
+ std::vector<VkQueueFamilyProperties> props{};
+ instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, nullptr);
+ ASSERT_EQ(num_fam, ret_fam_1);
+ props.resize(ret_fam_1);
+
+ instance->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &ret_fam_1, props.data());
+
+ std::vector<VkQueueFamilyProperties2> props2{};
+ uint32_t ret_fam_2 = 0;
+ GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, nullptr);
+ ASSERT_EQ(ret_fam_1, ret_fam_2);
+ props2.resize(ret_fam_2, VkQueueFamilyProperties2{VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2});
+ GetPhysDevQueueFamilyProps2(physical_device, &ret_fam_2, props2.data());
+ ASSERT_TRUE(CompareQueueFamilyData(props, props2));
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceQueueFamilyProperties2 and vkGetPhysicalDeviceQueueFamilyProperties2KHR where ICD is 1.0 and supports
@@ -1777,6 +2185,7 @@
// Test vkGetPhysicalDeviceSparseImageFormatProperties2 where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevSparseImageFormatProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -1785,49 +2194,150 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0});
FillInRandomSparseImageFormatData(env.get_test_icd(0).physical_devices.back().sparse_image_format_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2"));
+ ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
- auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2"));
- ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ std::vector<VkSparseImageFormatProperties> props{};
+ uint32_t sparse_count_1 = 0;
+ instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+ VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
+ ASSERT_NE(sparse_count_1, 0U);
+ props.resize(sparse_count_1);
+ instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+ VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
+ ASSERT_NE(sparse_count_1, 0U);
- std::vector<VkSparseImageFormatProperties> props{};
- uint32_t sparse_count_1 = 0;
- instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
- VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
- VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
- ASSERT_NE(sparse_count_1, 0U);
- props.resize(sparse_count_1);
- instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
- VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
- VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
- ASSERT_NE(sparse_count_1, 0U);
+ VkPhysicalDeviceSparseImageFormatInfo2 info2{
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, // sType
+ nullptr, // pNext
+ VK_FORMAT_R4G4_UNORM_PACK8, // format
+ VK_IMAGE_TYPE_2D, // type
+ VK_SAMPLE_COUNT_4_BIT, // samples
+ VK_IMAGE_USAGE_STORAGE_BIT, // usage
+ VK_IMAGE_TILING_OPTIMAL, // tiling
+ };
+ std::vector<VkSparseImageFormatProperties2> props2{};
+ uint32_t sparse_count_2 = 0;
+ GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
+ ASSERT_EQ(sparse_count_1, sparse_count_2);
+ props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
+ GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
+ ASSERT_EQ(sparse_count_1, sparse_count_2);
+ ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- VkPhysicalDeviceSparseImageFormatInfo2 info2{
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, // sType
- nullptr, // pNext
- VK_FORMAT_R4G4_UNORM_PACK8, // format
- VK_IMAGE_TYPE_2D, // type
- VK_SAMPLE_COUNT_4_BIT, // samples
- VK_IMAGE_USAGE_STORAGE_BIT, // usage
- VK_IMAGE_TILING_OPTIMAL, // tiling
- };
- std::vector<VkSparseImageFormatProperties2> props2{};
- uint32_t sparse_count_2 = 0;
- GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
- ASSERT_EQ(sparse_count_1, sparse_count_2);
- props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
- GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
- ASSERT_EQ(sparse_count_1, sparse_count_2);
- ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
+ auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2"));
+ ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ std::vector<VkSparseImageFormatProperties> props{};
+ uint32_t sparse_count_1 = 0;
+ instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+ VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
+ ASSERT_NE(sparse_count_1, 0U);
+ props.resize(sparse_count_1);
+ instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+ VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
+ ASSERT_NE(sparse_count_1, 0U);
+
+ VkPhysicalDeviceSparseImageFormatInfo2 info2{
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, // sType
+ nullptr, // pNext
+ VK_FORMAT_R4G4_UNORM_PACK8, // format
+ VK_IMAGE_TYPE_2D, // type
+ VK_SAMPLE_COUNT_4_BIT, // samples
+ VK_IMAGE_USAGE_STORAGE_BIT, // usage
+ VK_IMAGE_TILING_OPTIMAL, // tiling
+ };
+ std::vector<VkSparseImageFormatProperties2> props2{};
+ uint32_t sparse_count_2 = 0;
+ GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
+ ASSERT_EQ(sparse_count_1, sparse_count_2);
+ props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
+ GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
+ ASSERT_EQ(sparse_count_1, sparse_count_2);
+ ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysDevSparseImageFormatProps2 = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties2"));
+ ASSERT_NE(GetPhysDevSparseImageFormatProps2, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ std::vector<VkSparseImageFormatProperties> props{};
+ uint32_t sparse_count_1 = 0;
+ instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+ VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, nullptr);
+ ASSERT_NE(sparse_count_1, 0U);
+ props.resize(sparse_count_1);
+ instance->vkGetPhysicalDeviceSparseImageFormatProperties(physical_device, VK_FORMAT_R4G4_UNORM_PACK8, VK_IMAGE_TYPE_2D,
+ VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_USAGE_STORAGE_BIT,
+ VK_IMAGE_TILING_OPTIMAL, &sparse_count_1, props.data());
+ ASSERT_NE(sparse_count_1, 0U);
+
+ VkPhysicalDeviceSparseImageFormatInfo2 info2{
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, // sType
+ nullptr, // pNext
+ VK_FORMAT_R4G4_UNORM_PACK8, // format
+ VK_IMAGE_TYPE_2D, // type
+ VK_SAMPLE_COUNT_4_BIT, // samples
+ VK_IMAGE_USAGE_STORAGE_BIT, // usage
+ VK_IMAGE_TILING_OPTIMAL, // tiling
+ };
+ std::vector<VkSparseImageFormatProperties2> props2{};
+ uint32_t sparse_count_2 = 0;
+ GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, nullptr);
+ ASSERT_EQ(sparse_count_1, sparse_count_2);
+ props2.resize(sparse_count_2, VkSparseImageFormatProperties2{VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2});
+ GetPhysDevSparseImageFormatProps2(physical_device, &info2, &sparse_count_2, props2.data());
+ ASSERT_EQ(sparse_count_1, sparse_count_2);
+ ASSERT_TRUE(CompareSparseImageFormatData(props, props2));
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceSparseImageFormatProperties2 and vkGetPhysicalDeviceSparseImageFormatProperties2KHR where ICD is 1.0 and
@@ -2087,6 +2597,7 @@
// Test vkGetPhysicalDeviceExternalBufferProperties where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevExtBufProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -2095,25 +2606,78 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 0});
FillInRandomExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
- auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferProperties"));
- ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
+ VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
+ GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
+ ASSERT_TRUE(CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties,
+ props.externalMemoryProperties));
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
- VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
- GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
- ASSERT_TRUE(CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties,
- props.externalMemoryProperties));
+ auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
+ VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
+ GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
+ // Compare against 'zeroed' out VkExternalMemoryProperties
+ ASSERT_TRUE(CompareExtMemoryData(VkExternalMemoryProperties{}, props.externalMemoryProperties));
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+
+ auto GetPhysicalDeviceExternalBufferProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalBufferProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalBufferProperties, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceExternalBufferInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO};
+ VkExternalBufferProperties props{VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES};
+ GetPhysicalDeviceExternalBufferProperties(physical_device, &info, &props);
+ ASSERT_TRUE(CompareExtMemoryData(env.get_test_icd(0).physical_devices.back().external_memory_properties,
+ props.externalMemoryProperties));
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceExternalBufferProperties where instance supports it with some ICDs that both support
@@ -2299,6 +2863,7 @@
// Test vkGetPhysicalDeviceExternalSemaphoreProperties where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevExtSemProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -2307,24 +2872,74 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, 0});
FillInRandomExtSemData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
- auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
- ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
+ VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
+ GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
+ ASSERT_TRUE(CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props));
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+ auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
- VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
- VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
- GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
- ASSERT_TRUE(CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props));
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
+ VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
+ GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
+ // Compare against 'zeroed' out VkExternalSemaphoreProperties
+ ASSERT_TRUE(CompareExtSemaphoreData(VkExternalSemaphoreProperties{}, props));
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+ auto GetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalSemaphoreProperties, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceExternalSemaphoreInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO};
+ VkExternalSemaphoreProperties props{VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES};
+ GetPhysicalDeviceExternalSemaphoreProperties(physical_device, &info, &props);
+ ASSERT_TRUE(CompareExtSemaphoreData(env.get_test_icd(0).physical_devices.back().external_semaphore_properties, props));
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
// Test vkGetPhysicalDeviceExternalSemaphoreProperties where instance supports it with some ICDs that both support
@@ -2510,6 +3125,7 @@
// Test vkGetPhysicalDeviceExternalFenceProperties where instance supports, an ICD, and a device under that ICD
// also support, so everything should work and return properly.
+// Also check if the application didn't enable 1.1 and when a layer 'upgrades' the api version to 1.1
TEST(LoaderInstPhysDevExts, PhysDevExtFenceProps2Simple) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
@@ -2518,26 +3134,76 @@
env.get_test_icd(0).physical_devices.push_back({});
env.get_test_icd(0).physical_devices.back().extensions.push_back({VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, 0});
FillInRandomExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties);
+ {
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.set_api_version(VK_API_VERSION_1_1);
+ instance.CheckCreate();
- InstWrapper instance(env.vulkan_functions);
- instance.create_info.set_api_version(VK_API_VERSION_1_1);
- instance.CheckCreate();
+ auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFenceProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
- auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
- instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFenceProperties"));
- ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
- uint32_t driver_count = 1;
- VkPhysicalDevice physical_device;
- ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
- ASSERT_EQ(driver_count, 1U);
+ VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
+ VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
+ GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
+ ASSERT_TRUE(CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props));
+ }
+ { // Now do the same logic but the application didn't enable 1.0 or the extension so they get the emulated call
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
- VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
- VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
- GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
- ASSERT_TRUE(CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props));
+ auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFenceProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
+ VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
+ GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
+ // Compare against 'zeroed' out VkExternalFenceProperties
+ ASSERT_TRUE(CompareExtFenceData(VkExternalFenceProperties{}, props));
+ ASSERT_TRUE(log.find("Emulating call in ICD"));
+ }
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name("modify_api_version_layer")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DisableEnvVar")),
+ "modify_api_version_layer.json");
+ env.get_test_layer().set_alter_api_version(VK_API_VERSION_1_1);
+ { // Now do the same as above but with a layer that updates the version to 1.1 on behalf of the application
+ InstWrapper instance(env.vulkan_functions);
+ instance.create_info.add_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ instance.CheckCreate();
+ DebugUtilsWrapper log{instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ CreateDebugUtilsMessenger(log);
+ auto GetPhysicalDeviceExternalFenceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
+ instance.functions->vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceExternalFenceProperties"));
+ ASSERT_NE(GetPhysicalDeviceExternalFenceProperties, nullptr);
+
+ uint32_t driver_count = 1;
+ VkPhysicalDevice physical_device;
+ ASSERT_EQ(VK_SUCCESS, instance->vkEnumeratePhysicalDevices(instance, &driver_count, &physical_device));
+ ASSERT_EQ(driver_count, 1U);
+
+ VkPhysicalDeviceExternalFenceInfo info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO};
+ VkExternalFenceProperties props{VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES};
+ GetPhysicalDeviceExternalFenceProperties(physical_device, &info, &props);
+ ASSERT_TRUE(CompareExtFenceData(env.get_test_icd(0).physical_devices.back().external_fence_properties, props));
+ ASSERT_FALSE(log.find("Emulating call in ICD"));
+ }
}
-
// Test vkGetPhysicalDeviceExternalFenceProperties where instance supports it with some ICDs that both support
// and don't support it:
// ICD 0 supports
diff --git a/tests/loader_regression_tests.cpp b/tests/loader_regression_tests.cpp
index 32070e3..204a1c8 100644
--- a/tests/loader_regression_tests.cpp
+++ b/tests/loader_regression_tests.cpp
@@ -1069,10 +1069,10 @@
// Should get an error message for the explicit layer
#ifndef __APPLE__
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" was wrong bit-type!")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" was wrong bit-type!")));
#else // __APPLE__
// Apple only throws a wrong library type of error
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load!")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load!")));
#endif // __APPLE__
}
@@ -1106,10 +1106,10 @@
#ifndef __APPLE__
// Should get an info message for the bad implicit layer
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" was wrong bit-type.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" was wrong bit-type.")));
#else // __APPLE__
// Apple only throws a wrong library type of error
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load.")));
#endif // __APPLE__
}
@@ -1149,12 +1149,12 @@
#ifndef __APPLE__
// Should get error messages for both (the explicit is second and we don't want the implicit to return before the explicit
// triggers a failure during vkCreateInstance)
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" was wrong bit-type!")));
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" was wrong bit-type.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" was wrong bit-type!")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" was wrong bit-type.")));
#else // __APPLE__
// Apple only throws a wrong library type of error
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" failed to load!")));
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" failed to load.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" failed to load!")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" failed to load.")));
#endif // __APPLE__
}
@@ -1193,12 +1193,12 @@
#ifndef __APPLE__
// Should not get an error messages for either
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" was wrong bit-type!")));
- ASSERT_FALSE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" was wrong bit-type.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" was wrong bit-type!")));
+ ASSERT_FALSE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" was wrong bit-type.")));
#else // __APPLE__
// Apple only throws a wrong library type of error
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" failed to load!")));
- ASSERT_FALSE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" failed to load.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" failed to load!")));
+ ASSERT_FALSE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" failed to load.")));
#endif // __APPLE__
}
@@ -1230,7 +1230,7 @@
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
// Should get an error message for the bad explicit
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load!")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load!")));
}
TEST(TryLoadWrongBinaries, BadImplicit) {
@@ -1262,7 +1262,7 @@
inst.CheckCreate(VK_SUCCESS);
// Should get an info message for the bad implicit
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name) + std::string("\" failed to load.")));
}
TEST(TryLoadWrongBinaries, BadExplicitAndImplicit) {
@@ -1299,8 +1299,8 @@
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
// Apple only throws a wrong library type of error
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" failed to load!")));
- ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" failed to load.")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_0) + std::string("\" failed to load!")));
+ ASSERT_TRUE(log.find(std::string("Requested layer \"") + std::string(layer_name_1) + std::string("\" failed to load.")));
}
TEST(TryLoadWrongBinaries, WrongArchDriver) {
@@ -2815,6 +2815,7 @@
FrameworkEnvironment env{};
set_env_var("VK_LOADER_DISABLE_SELECT", "1");
+ EnvVarCleaner disable_select_cleaner("VK_LOADER_DISABLE_SELECT");
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2, VK_API_VERSION_1_0));
env.get_test_icd(0).add_instance_extension({VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME});
@@ -2917,8 +2918,6 @@
for (uint32_t dev = 0; dev < device_count; ++dev) {
ASSERT_EQ(physical_devices[dev], physical_devices_again[dev]);
}
-
- remove_env_var("VK_LOADER_DISABLE_SELECT");
}
TEST(SortedPhysicalDevices, DeviceGroupsSortedEnabled) {
@@ -3109,6 +3108,7 @@
FrameworkEnvironment env{};
set_env_var("VK_LOADER_DISABLE_SELECT", "1");
+ EnvVarCleaner disable_select_cleaner("VK_LOADER_DISABLE_SELECT");
// ICD 0: Vulkan 1.1
// PhysDev 0: pd0, Discrete, Vulkan 1.1, Bus 7
@@ -3277,16 +3277,14 @@
ASSERT_EQ(physical_device_groups[group].physicalDevices[dev], physical_device_groups_again[group].physicalDevices[dev]);
}
}
-
- remove_env_var("VK_LOADER_DISABLE_SELECT");
}
#endif // __linux__ || __FreeBSD__ || __OpenBSD__
const char* portability_driver_warning =
"vkCreateInstance: Found drivers that contain devices which support the portability subset, but the "
- "portability enumeration bit was not set!. Applications that wish to enumerate portability drivers must set the "
- "VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit in the VkInstanceCreateInfo flags and"
+ "portability enumeration bit was not set! Applications that wish to enumerate portability drivers must set the "
+ "VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR bit in the VkInstanceCreateInfo flags and "
"enable the VK_KHR_portability_enumeration instance extension.";
TEST(PortabilityICDConfiguration, PortabilityICDOnly) {
@@ -3527,4 +3525,121 @@
InstWrapper inst{env.vulkan_functions};
inst.CheckCreate();
}
+
+// Make sure that stale layer manifests (path to nonexistant file) which have the same name as real manifests don't cause the real
+// manifests to be skipped. Stale registry entries happen when a registry is written on layer/driver installation but not cleaned up
+// when the corresponding manifest is removed from the file system.
+TEST(DuplicateRegistryEntries, Layers) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(ManifestICD{}.set_lib_path(TEST_ICD_PATH_VERSION_2)));
+
+ auto null_path = env.get_folder(ManifestLocation::null).location() / "test_layer.json";
+
+ env.platform_shim->add_manifest(ManifestCategory::explicit_layer, null_path.str());
+
+ const char* layer_name = "TestLayer";
+ env.add_explicit_layer(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "test_layer.json");
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.create_info.add_layer(layer_name);
+ inst.CheckCreate();
+}
+
+// Check that the de-duplication of drivers found in both PnP and generic Khronos/Vulkan/Drivers doesn't result in the same thing
+// being added twice
+TEST(DuplicateRegistryEntries, Drivers) {
+ FrameworkEnvironment env{};
+ auto null_path = env.get_folder(ManifestLocation::null).location() / "test_icd_0.json";
+ env.platform_shim->add_manifest(ManifestCategory::icd, null_path.str());
+
+ env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA}.set_discovery_type(ManifestDiscoveryType::none));
+ auto& driver = env.get_test_icd();
+ driver.physical_devices.emplace_back("physical_device_0");
+ driver.adapterLUID = _LUID{10, 1000};
+ env.platform_shim->add_d3dkmt_adapter(D3DKMT_Adapter{0, _LUID{10, 1000}}.add_driver_manifest_path(env.get_icd_manifest_path()));
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find(
+ std::string("Skipping adding of json file \"") + null_path.str() +
+ "\" from registry \"HKEY_LOCAL_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\Drivers\" to the list due to duplication"));
+}
+#endif
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+// Check that valid symlinks do not cause the loader to crash when directly in an XDG env-var
+TEST(ManifestDiscovery, ValidSymlinkInXDGEnvVar) {
+ FrameworkEnvironment env{true, false};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA).set_discovery_type(ManifestDiscoveryType::none));
+ env.get_test_icd().physical_devices.push_back({});
+ auto driver_path = env.get_icd_manifest_path(0);
+ std::string symlink_name = "symlink_to_driver.json";
+ fs::path symlink_path = env.get_folder(ManifestLocation::driver_env_var).location() / symlink_name;
+ env.get_folder(ManifestLocation::driver_env_var).add_existing_file(symlink_name);
+ int res = symlink(driver_path.c_str(), symlink_path.c_str());
+ ASSERT_EQ(res, 0);
+ set_env_var("XDG_CONFIG_DIRS", symlink_path.str());
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+}
+
+// Check that valid symlinks do not cause the loader to crash
+TEST(ManifestDiscovery, ValidSymlink) {
+ FrameworkEnvironment env{true, false};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA).set_discovery_type(ManifestDiscoveryType::none));
+ env.get_test_icd().physical_devices.push_back({});
+
+ auto driver_path = env.get_icd_manifest_path(0);
+ std::string symlink_name = "symlink_to_driver.json";
+ fs::path symlink_path = env.get_folder(ManifestLocation::driver_env_var).location() / symlink_name;
+ env.get_folder(ManifestLocation::driver_env_var).add_existing_file(symlink_name);
+ int res = symlink(driver_path.c_str(), symlink_path.c_str());
+ ASSERT_EQ(res, 0);
+
+ env.platform_shim->set_path(ManifestCategory::icd, env.get_folder(ManifestLocation::driver_env_var).location());
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+}
+
+// Check that invalid symlinks do not cause the loader to crash when directly in an XDG env-var
+TEST(ManifestDiscovery, InvalidSymlinkXDGEnvVar) {
+ FrameworkEnvironment env{true, false};
+ std::string symlink_name = "symlink_to_nothing.json";
+ fs::path symlink_path = env.get_folder(ManifestLocation::driver_env_var).location() / symlink_name;
+ fs::path invalid_driver_path = env.get_folder(ManifestLocation::driver).location() / "nothing_here.json";
+ int res = symlink(invalid_driver_path.c_str(), symlink_path.c_str());
+ ASSERT_EQ(res, 0);
+ env.get_folder(ManifestLocation::driver_env_var).add_existing_file(symlink_name);
+
+ set_env_var("XDG_CONFIG_DIRS", symlink_path.str());
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
+}
+
+// Check that invalid symlinks do not cause the loader to crash
+TEST(ManifestDiscovery, InvalidSymlink) {
+ FrameworkEnvironment env{true, false};
+ std::string symlink_name = "symlink_to_nothing.json";
+ fs::path symlink_path = env.get_folder(ManifestLocation::driver).location() / symlink_name;
+ fs::path invalid_driver_path = env.get_folder(ManifestLocation::driver_env_var).location() / "nothing_here.json";
+ int res = symlink(invalid_driver_path.c_str(), symlink_path.c_str());
+ ASSERT_EQ(res, 0);
+ env.get_folder(ManifestLocation::driver).add_existing_file(symlink_name);
+
+ env.platform_shim->set_path(ManifestCategory::icd, env.get_folder(ManifestLocation::driver_env_var).location());
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
+}
#endif
diff --git a/tests/loader_testing_main.cpp b/tests/loader_testing_main.cpp
index eb2c8f8..6fe3f45 100644
--- a/tests/loader_testing_main.cpp
+++ b/tests/loader_testing_main.cpp
@@ -55,6 +55,10 @@
remove_env_var("VK_LAYER_PATH");
remove_env_var("VK_ADD_LAYER_PATH");
remove_env_var("VK_INSTANCE_LAYERS");
+ remove_env_var("VK_LOADER_DRIVERS_SELECT");
+ remove_env_var("VK_LOADER_DRIVERS_DISABLE");
+ remove_env_var("VK_LOADER_LAYERS_ENABLE");
+ remove_env_var("VK_LOADER_LAYERS_DISABLE");
remove_env_var("VK_LOADER_DEBUG");
remove_env_var("VK_LOADER_DISABLE_INST_EXT_FILTER");
@@ -67,7 +71,6 @@
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
set_env_var("HOME", "/home/fake_home");
#endif
-
::testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
diff --git a/tests/loader_threading_tests.cpp b/tests/loader_threading_tests.cpp
index 78999a0..83b17da 100644
--- a/tests/loader_threading_tests.cpp
+++ b/tests/loader_threading_tests.cpp
@@ -29,29 +29,52 @@
#include <mutex>
#include <thread>
+#include <atomic>
-void create_destroy_device_loop(uint32_t num_loops_create_destroy_device, uint32_t num_loops_try_get_proc_addr, InstWrapper* inst,
- VkPhysicalDevice phys_dev) {
+void create_destroy_instance_loop_with_function_queries(FrameworkEnvironment* env, uint32_t num_loops_create_destroy_instance,
+ uint32_t num_loops_try_get_instance_proc_addr,
+ uint32_t num_loops_try_get_device_proc_addr) {
+ for (uint32_t i = 0; i < num_loops_create_destroy_instance; i++) {
+ InstWrapper inst{env->vulkan_functions};
+ inst.CheckCreate();
+ PFN_vkEnumeratePhysicalDevices enum_pd = nullptr;
+ for (uint32_t j = 0; j < num_loops_try_get_instance_proc_addr; j++) {
+ enum_pd = inst.load("vkEnumeratePhysicalDevices");
+ ASSERT_NE(enum_pd, nullptr);
+ }
+ VkPhysicalDevice phys_dev = inst.GetPhysDev();
+
+ DeviceWrapper dev{inst};
+ dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(1.0));
+ dev.CheckCreate(phys_dev);
+ for (uint32_t j = 0; j < num_loops_try_get_device_proc_addr; j++) {
+ PFN_vkCmdBindPipeline p = dev.load("vkCmdBindPipeline");
+ p(VK_NULL_HANDLE, VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, VK_NULL_HANDLE);
+ }
+ }
+}
+
+void create_destroy_device_loop(FrameworkEnvironment* env, uint32_t num_loops_create_destroy_device,
+ uint32_t num_loops_try_get_proc_addr) {
+ InstWrapper inst{env->vulkan_functions};
+ inst.CheckCreate();
+ VkPhysicalDevice phys_dev = inst.GetPhysDev();
for (uint32_t i = 0; i < num_loops_create_destroy_device; i++) {
- DeviceWrapper dev{*inst};
+ DeviceWrapper dev{inst};
dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(1.0));
dev.CheckCreate(phys_dev);
for (uint32_t j = 0; j < num_loops_try_get_proc_addr; j++) {
- PFN_vkCmdBindPipeline p =
- reinterpret_cast<PFN_vkCmdBindPipeline>(dev->vkGetDeviceProcAddr(dev.dev, "vkCmdBindPipeline"));
- ASSERT_NE(p, nullptr);
- PFN_vkCmdBindDescriptorSets d =
- reinterpret_cast<PFN_vkCmdBindDescriptorSets>(dev->vkGetDeviceProcAddr(dev.dev, "vkCmdBindDescriptorSets"));
- ASSERT_NE(d, nullptr);
- PFN_vkCmdBindVertexBuffers vb =
- reinterpret_cast<PFN_vkCmdBindVertexBuffers>(dev->vkGetDeviceProcAddr(dev.dev, "vkCmdBindVertexBuffers"));
- ASSERT_NE(vb, nullptr);
- PFN_vkCmdBindIndexBuffer ib =
- reinterpret_cast<PFN_vkCmdBindIndexBuffer>(dev->vkGetDeviceProcAddr(dev.dev, "vkCmdBindIndexBuffer"));
- ASSERT_NE(ib, nullptr);
- PFN_vkCmdDraw c = reinterpret_cast<PFN_vkCmdDraw>(dev->vkGetDeviceProcAddr(dev.dev, "vkCmdDraw"));
- ASSERT_NE(c, nullptr);
+ PFN_vkCmdBindPipeline p = dev.load("vkCmdBindPipeline");
+ PFN_vkCmdBindDescriptorSets d = dev.load("vkCmdBindDescriptorSets");
+ PFN_vkCmdBindVertexBuffers vb = dev.load("vkCmdBindVertexBuffers");
+ PFN_vkCmdBindIndexBuffer ib = dev.load("vkCmdBindIndexBuffer");
+ PFN_vkCmdDraw c = dev.load("vkCmdDraw");
+ p(VK_NULL_HANDLE, VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, VK_NULL_HANDLE);
+ d(VK_NULL_HANDLE, VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, VK_NULL_HANDLE, 0, 0, nullptr, 0, nullptr);
+ vb(VK_NULL_HANDLE, 0, 0, nullptr, nullptr);
+ ib(VK_NULL_HANDLE, 0, 0, VkIndexType::VK_INDEX_TYPE_UINT16);
+ c(VK_NULL_HANDLE, 0, 0, 0, 0);
}
}
}
@@ -67,12 +90,40 @@
const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) {}
VKAPI_ATTR void VKAPI_CALL test_vkCmdDraw(VkCommandBuffer cmd_buf, uint32_t vertexCount, uint32_t instanceCount,
uint32_t firstVertex, uint32_t firstInstance) {}
-TEST(ThreadingTests, ConcurentGetDeviceProcAddr) {
- FrameworkEnvironment env{};
+TEST(Threading, InstanceCreateDestroyLoop) {
+ const auto processor_count = std::thread::hardware_concurrency();
+
+ FrameworkEnvironment env{false};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
- uint32_t num_threads = 100;
- uint32_t num_loops_create_destroy_device = 10;
- uint32_t num_loops_try_get_proc_addr = 100;
+ uint32_t num_loops_create_destroy_instance = 500;
+ uint32_t num_loops_try_get_instance_proc_addr = 5;
+ uint32_t num_loops_try_get_device_proc_addr = 100;
+ auto& driver = env.get_test_icd();
+
+ driver.physical_devices.emplace_back("physical_device_0");
+ driver.physical_devices.back().known_device_functions.push_back(
+ {"vkCmdBindPipeline", to_vkVoidFunction(test_vkCmdBindPipeline)});
+
+ std::vector<std::thread> instance_creation_threads;
+ std::vector<std::thread> function_query_threads;
+ for (uint32_t i = 0; i < processor_count; i++) {
+ instance_creation_threads.emplace_back(create_destroy_instance_loop_with_function_queries, &env,
+ num_loops_create_destroy_instance, num_loops_try_get_instance_proc_addr,
+ num_loops_try_get_device_proc_addr);
+ }
+ for (uint32_t i = 0; i < processor_count; i++) {
+ instance_creation_threads[i].join();
+ }
+}
+
+TEST(Threading, DeviceCreateDestroyLoop) {
+ const auto processor_count = std::thread::hardware_concurrency();
+
+ FrameworkEnvironment env{false};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+
+ uint32_t num_loops_create_destroy_device = 1000;
+ uint32_t num_loops_try_get_device_proc_addr = 5;
auto& driver = env.get_test_icd();
driver.physical_devices.emplace_back("physical_device_0");
@@ -86,21 +137,13 @@
{"vkCmdBindIndexBuffer", to_vkVoidFunction(test_vkCmdBindIndexBuffer)});
driver.physical_devices.back().known_device_functions.push_back({"vkCmdDraw", to_vkVoidFunction(test_vkCmdDraw)});
- InstWrapper inst{env.vulkan_functions};
- inst.CheckCreate();
+ std::vector<std::thread> device_creation_threads;
- VkPhysicalDevice phys_dev = inst.GetPhysDev();
-
- DeviceWrapper dev{inst};
- dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(1.0));
- dev.CheckCreate(phys_dev);
-
- std::vector<std::thread> threads;
- for (uint32_t i = 0; i < num_threads; i++) {
- threads.emplace_back(create_destroy_device_loop, num_loops_create_destroy_device, num_loops_try_get_proc_addr, &inst,
- phys_dev);
+ for (uint32_t i = 0; i < processor_count; i++) {
+ device_creation_threads.emplace_back(create_destroy_device_loop, &env, num_loops_create_destroy_device,
+ num_loops_try_get_device_proc_addr);
}
- for (uint32_t i = 0; i < num_threads; i++) {
- threads[i].join();
+ for (uint32_t i = 0; i < processor_count; i++) {
+ device_creation_threads[i].join();
}
}
diff --git a/tests/loader_unknown_ext_tests.cpp b/tests/loader_unknown_ext_tests.cpp
index 294251a..bdce9b6 100644
--- a/tests/loader_unknown_ext_tests.cpp
+++ b/tests/loader_unknown_ext_tests.cpp
@@ -445,7 +445,7 @@
decltype(custom_physical_device_functions::func_zero)* returned_func_i =
env.vulkan_functions.load(inst.inst, function_names.at(0).c_str());
ASSERT_NE(returned_func_i, nullptr);
- ASSERT_DEATH(returned_func_i(phys_dev_to_use, 0), "Extension vkNotIntRealFuncTEST_0 not supported for this physical device");
+ ASSERT_DEATH(returned_func_i(phys_dev_to_use, 0), "Function vkNotIntRealFuncTEST_0 not supported for this physical device");
}
TEST(UnknownFunction, PhysicalDeviceFunctionWithImplicitLayerImplementation) {
diff --git a/tests/loader_version_tests.cpp b/tests/loader_version_tests.cpp
index 04c22ac..815c7bb 100644
--- a/tests/loader_version_tests.cpp
+++ b/tests/loader_version_tests.cpp
@@ -516,7 +516,8 @@
env.vulkan_functions.vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, physical_device_handles.data()));
ASSERT_EQ(physical_count, returned_physical_count);
- VkSurfaceKHR surface = create_surface(inst);
+ VkSurfaceKHR surface{};
+ create_surface(inst, surface);
for (const auto& handle : physical_device_handles) {
handle_assert_has_value(handle);
@@ -854,8 +855,8 @@
inst.create_info.set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0));
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate();
- ASSERT_TRUE(log.find(std::string("Layer ") + implicit_layer_name +
- " has an \'api_version\' field which contains a non-zero variant value of 1. Skipping Layer."));
+ ASSERT_TRUE(log.find(std::string("Layer \"") + implicit_layer_name +
+ "\" has an \'api_version\' field which contains a non-zero variant value of 1. Skipping Layer."));
}
TEST(LayerManifest, ExplicitNonVulkanVariant) {
@@ -875,8 +876,8 @@
inst.create_info.set_api_version(VK_MAKE_API_VERSION(0, 1, 0, 0)).add_layer(explicit_layer_name);
FillDebugUtilsCreateDetails(inst.create_info, log);
inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
- ASSERT_TRUE(log.find(std::string("Layer ") + explicit_layer_name +
- " has an \'api_version\' field which contains a non-zero variant value of 1. Skipping Layer."));
+ ASSERT_TRUE(log.find(std::string("Layer \"") + explicit_layer_name +
+ "\" has an \'api_version\' field which contains a non-zero variant value of 1. Skipping Layer."));
}
TEST(DriverManifest, UnknownManifestVersion) {
diff --git a/tests/loader_wsi_tests.cpp b/tests/loader_wsi_tests.cpp
index 548e135..095aac9 100644
--- a/tests/loader_wsi_tests.cpp
+++ b/tests/loader_wsi_tests.cpp
@@ -138,7 +138,8 @@
cur_icd.enable_icd_wsi = false;
InstWrapper inst{env.vulkan_functions};
- inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME});
+ inst.create_info.add_extensions(
+ {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
inst.CheckCreate();
uint32_t driver_count = 1;
@@ -146,8 +147,11 @@
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
ASSERT_EQ(driver_count, 1U);
- ASSERT_DEATH(env.vulkan_functions.vkGetPhysicalDeviceWin32PresentationSupportKHR(physical_device, 0),
- "ICD for selected physical device does not export vkGetPhysicalDeviceWin32PresentationSupportKHR!");
+ DebugUtilsWrapper log{inst};
+ CreateDebugUtilsMessenger(log);
+ auto res = env.vulkan_functions.vkGetPhysicalDeviceWin32PresentationSupportKHR(physical_device, 0);
+ ASSERT_EQ(res, VK_FALSE);
+ ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceWin32PresentationSupportKHR!"));
}
TEST(WsiTests, GetPhysicalDeviceWin32PresentICDSupport) {
@@ -323,7 +327,8 @@
cur_icd.enable_icd_wsi = false;
InstWrapper inst{env.vulkan_functions};
- inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME});
+ inst.create_info.add_extensions(
+ {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
inst.CheckCreate();
uint32_t driver_count = 1;
@@ -331,8 +336,11 @@
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
ASSERT_EQ(driver_count, 1U);
- ASSERT_DEATH(env.vulkan_functions.vkGetPhysicalDeviceXcbPresentationSupportKHR(physical_device, 0, nullptr, 0),
- "ICD for selected physical device does not export vkGetPhysicalDeviceXcbPresentationSupportKHR!");
+ DebugUtilsWrapper log{inst};
+ CreateDebugUtilsMessenger(log);
+ auto res = env.vulkan_functions.vkGetPhysicalDeviceXcbPresentationSupportKHR(physical_device, 0, nullptr, 0);
+ ASSERT_EQ(res, VK_FALSE);
+ ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceXcbPresentationSupportKHR!"));
}
TEST(WsiTests, GetPhysicalDeviceXcbPresentICDSupport) {
@@ -508,7 +516,8 @@
cur_icd.enable_icd_wsi = false;
InstWrapper inst{env.vulkan_functions};
- inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME});
+ inst.create_info.add_extensions(
+ {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
inst.CheckCreate();
uint32_t driver_count = 1;
@@ -516,8 +525,11 @@
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
ASSERT_EQ(driver_count, 1U);
- ASSERT_DEATH(env.vulkan_functions.vkGetPhysicalDeviceXlibPresentationSupportKHR(physical_device, 0, nullptr, 0),
- "ICD for selected physical device does not export vkGetPhysicalDeviceXlibPresentationSupportKHR!");
+ DebugUtilsWrapper log{inst};
+ CreateDebugUtilsMessenger(log);
+ auto res = env.vulkan_functions.vkGetPhysicalDeviceXlibPresentationSupportKHR(physical_device, 0, nullptr, 0);
+ ASSERT_EQ(res, VK_FALSE);
+ ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceXlibPresentationSupportKHR!"));
}
TEST(WsiTests, GetPhysicalDeviceXlibPresentICDSupport) {
@@ -693,7 +705,8 @@
cur_icd.enable_icd_wsi = false;
InstWrapper inst{env.vulkan_functions};
- inst.create_info.add_extensions({VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME});
+ inst.create_info.add_extensions(
+ {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
inst.CheckCreate();
uint32_t driver_count = 1;
@@ -701,8 +714,11 @@
ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst, &driver_count, &physical_device));
ASSERT_EQ(driver_count, 1U);
- ASSERT_DEATH(env.vulkan_functions.vkGetPhysicalDeviceWaylandPresentationSupportKHR(physical_device, 0, nullptr),
- "ICD for selected physical device does not export vkGetPhysicalDeviceWaylandPresentationSupportKHR!");
+ DebugUtilsWrapper log{inst};
+ CreateDebugUtilsMessenger(log);
+ auto res = env.vulkan_functions.vkGetPhysicalDeviceWaylandPresentationSupportKHR(physical_device, 0, nullptr);
+ ASSERT_EQ(res, VK_FALSE);
+ ASSERT_TRUE(log.find("ICD for selected physical device does not export vkGetPhysicalDeviceWaylandPresentationSupportKHR!"));
}
TEST(WsiTests, GetPhysicalDeviceWaylandPresentICDSupport) {
@@ -768,3 +784,109 @@
env.vulkan_functions.vkDestroySurfaceKHR(instance.inst, surface, nullptr);
}
#endif
+
+TEST(WsiTests, ForgetEnableSurfaceExtensions) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+ auto& driver = env.get_test_icd();
+ setup_WSI_in_ICD(driver);
+ MockQueueFamilyProperties family_props{{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true};
+
+ driver.physical_devices.emplace_back("physical_device_0");
+ driver.physical_devices.back().queue_family_properties.push_back(family_props);
+ driver.physical_devices.back().add_extension("VK_KHR_swapchain");
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.create_info.add_extension("VK_KHR_surface");
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+
+ VkSurfaceKHR surface{};
+ ASSERT_FALSE(create_surface(inst, surface));
+}
+
+TEST(WsiTests, SwapchainFunctional) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+ auto& driver = env.get_test_icd();
+ setup_WSI_in_ICD(driver);
+ MockQueueFamilyProperties family_props{{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, true};
+
+ driver.physical_devices.emplace_back("physical_device_0");
+ driver.physical_devices.back().queue_family_properties.push_back(family_props);
+ driver.physical_devices.back().add_extension("VK_KHR_swapchain");
+
+ InstWrapper inst{env.vulkan_functions};
+ setup_WSI_in_create_instance(inst);
+ inst.CheckCreate();
+ VkSurfaceKHR surface{};
+ create_surface(inst, surface);
+ VkPhysicalDevice phys_dev = inst.GetPhysDev();
+
+ { // Use GDPA to get functions
+ DeviceWrapper dev{inst};
+ dev.create_info.add_extension("VK_KHR_swapchain");
+ dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+
+ ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+
+ VkSwapchainKHR swapchain{};
+ VkSwapchainCreateInfoKHR swap_create_info{};
+ swap_create_info.surface = surface;
+ DeviceFunctions funcs{*inst.functions, dev};
+ ASSERT_EQ(VK_SUCCESS, funcs.vkCreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain));
+ uint32_t count = 0;
+ ASSERT_EQ(VK_SUCCESS, funcs.vkGetSwapchainImagesKHR(dev, swapchain, &count, nullptr));
+ ASSERT_GT(count, 0U);
+ std::array<VkImage, 16> images;
+ ASSERT_EQ(VK_SUCCESS, funcs.vkGetSwapchainImagesKHR(dev, swapchain, &count, images.data()));
+ funcs.vkDestroySwapchainKHR(dev, swapchain, nullptr);
+ }
+ { // Use GIPA gotten functions
+ DeviceWrapper dev{inst};
+ dev.create_info.add_extension("VK_KHR_swapchain");
+ dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+
+ ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+
+ PFN_vkCreateSwapchainKHR inst_CreateSwapchainKHR = inst.load("vkCreateSwapchainKHR");
+ PFN_vkGetSwapchainImagesKHR inst_GetSwapchainImagesKHR = inst.load("vkGetSwapchainImagesKHR");
+ PFN_vkDestroySwapchainKHR inst_DestroySwapchainKHR = inst.load("vkDestroySwapchainKHR");
+ ASSERT_TRUE(nullptr != inst_CreateSwapchainKHR);
+ ASSERT_TRUE(nullptr != inst_GetSwapchainImagesKHR);
+ ASSERT_TRUE(nullptr != inst_DestroySwapchainKHR);
+
+ VkSwapchainKHR swapchain{};
+ VkSwapchainCreateInfoKHR swap_create_info{};
+ swap_create_info.surface = surface;
+
+ ASSERT_EQ(VK_SUCCESS, inst_CreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain));
+ uint32_t count = 0;
+ ASSERT_EQ(VK_SUCCESS, inst_GetSwapchainImagesKHR(dev, swapchain, &count, nullptr));
+ ASSERT_GT(count, 0U);
+ std::array<VkImage, 16> images;
+ ASSERT_EQ(VK_SUCCESS, inst_GetSwapchainImagesKHR(dev, swapchain, &count, images.data()));
+ inst_DestroySwapchainKHR(dev, swapchain, nullptr);
+ }
+ { // forget to enable the extension
+ DeviceWrapper dev{inst};
+ ASSERT_NO_FATAL_FAILURE(dev.CheckCreate(phys_dev));
+
+ DeviceFunctions funcs{*inst.functions, dev};
+ ASSERT_EQ(funcs.vkCreateSwapchainKHR, nullptr);
+ ASSERT_EQ(funcs.vkGetSwapchainImagesKHR, nullptr);
+ ASSERT_EQ(funcs.vkDestroySwapchainKHR, nullptr);
+ }
+ { // forget to set the surface
+ DeviceWrapper dev{inst};
+ dev.create_info.add_extension("VK_KHR_swapchain");
+ dev.create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
+
+ dev.CheckCreate(phys_dev);
+
+ VkSwapchainKHR swapchain{};
+ VkSwapchainCreateInfoKHR swap_create_info{};
+ DeviceFunctions funcs{*inst.functions, dev};
+ ASSERT_DEATH(funcs.vkCreateSwapchainKHR(dev, &swap_create_info, nullptr, &swapchain), "");
+ }
+ env.vulkan_functions.vkDestroySurfaceKHR(inst.inst, surface, nullptr);
+}