diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c3c09359ed..7f5ceebbf0 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -31,6 +31,7 @@ jobs: os: [ windows-latest ] toolset: [v143, CLangCL] arch: [ x64 ] + check_mkvk: [ NO ] options: [ {config: 'Debug,Release', doc: ON, jni: ON, loadtests: OpenGL+Vulkan, py: ON, tests: ON, tools: ON, tools_cts: ON, @@ -50,6 +51,11 @@ jobs: sse: ON, opencl: ON} ] include: + - os: windows-latest + generator: 'Visual Studio 17 2022' + toolset: CLangCL + arch: x64 + check_mkvk: ONLY - os: windows-2019 generator: 'Visual Studio 16 2019' toolset: v142 @@ -82,6 +88,7 @@ jobs: CMAKE_TOOLSET: ${{ matrix.toolset }} ARCH: ${{ matrix.arch }} + CHECK_MKVK: ${{ matrix.check_mkvk }} CONFIGURATION: ${{ matrix.options.config }} FEATURE_DOC: ${{ matrix.options.doc }} FEATURE_JNI: ${{ matrix.options.jni }} @@ -122,6 +129,7 @@ jobs: fetch-depth: 0 - name: Install NSIS with large string support + if: matrix.check_mkvk != 'ONLY' shell: bash run: | retryCount=4 @@ -147,7 +155,7 @@ jobs: - name: Force fetch provoking tag's annotation. # Work around https://github.com/actions/checkout/issues/290. - if: github.ref_type == 'tag' + if: github.ref_type == 'tag' && matrix.check_mkvk != 'ONLY' run: git fetch -f origin ${{ github.ref }}:${{ github.ref }} # Need doxygen if docs are supposed to be built. @@ -178,6 +186,7 @@ jobs: } - name: Install AzureSignTool + if: matrix.check_mkvk != 'ONLY' id: install-ast run: | if ($env:PACKAGE -eq "YES" -and $env:AZURE_KEY_VAULT_URL) { @@ -196,18 +205,19 @@ jobs: echo "LOADTESTS_USE_LOCAL_DEPENDENCIES=ON" >> $env:GITHUB_ENV - name: Install Dependencies + if: matrix.check_mkvk != 'ONLY' # This script only installs what's needed by ON FEATUREs. run: ci_scripts/install_win.ps1 - name: Set up JDK 17. - if: matrix.options.jni == 'ON' + if: matrix.options.jni == 'ON' && matrix.check_mkvk != 'ONLY' uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' - name: Set up Python 3.11 - if: matrix.options.py == 'ON' + if: matrix.options.py == 'ON' && matrix.check_mkvk != 'ONLY' uses: actions/setup-python@v4 with: python-version: '3.11.4' @@ -219,6 +229,7 @@ jobs: ci_scripts/smudge_date.ps1 - name: Build Windows + if: matrix.check_mkvk != 'ONLY' # The installers run as part of "Install Dependencies" add # environment variables to the registry and augment $Path there. # Although each step gets a new Powershell instance, that instance @@ -239,6 +250,10 @@ jobs: $env:JAVA_HOME=$step_java_home ci_scripts/build_win.ps1 + - name: Test Generation of VkFormat-related files + if: matrix.check_mkvk == 'ONLY' + run: ci_scripts/check_mkvk.ps1 + - name: Test Windows build # Tests built for arm64 can't be run as the CI runners are all x64. if: matrix.arch == 'x64' && matrix.options.tests == 'ON' diff --git a/.travis.yml b/.travis.yml index 870c67442c..0c87f7f39d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,9 +25,11 @@ addons: env: global: - BUILD_DIR: build + - CHECK_MKVK: NO - CHECK_REUSE: NO - FEATURE_TESTS: ON - GIT_LFS_SKIP_SMUDGE: 1 + - HOMEBREW_NO_AUTO_UPDATE: 1 - PACKAGE: NO - REL_DESC_FILE: "$BUILD_DIR/rel_desc.md" - VULKAN_SDK_VER: "1.3.243.0" @@ -37,6 +39,7 @@ env: - WASM_BUILD: NO - WERROR: ON jobs: + # NOTE: As least 2 configurations must be present or no macOS job is run. # FEATURE_TESTS is off for arm64 macOS because we can't even build # them during CI. CI runs on x86_64 and there is a PostBuild command # that attempts to execute the compiled-for-m1 tests to have gtest @@ -45,6 +48,8 @@ env: # FEATURE_PY is off for arm64 macOS because we'd need a cross-compiled version # of Python for it to correctly build the Python extensions (the CI # runs on x86_64) + - CHECK_MKVK=ONLY + - CONFIGURATION=Debug,Release PLATFORM=macOS ARCHS=x86_64 FEATURE_DOC=ON FEATURE_JNI=ON FEATURE_PY=ON FEATURE_LOADTESTS=OpenGL+Vulkan FEATURE_TOOLS=ON FEATURE_TOOLS_CTS=ON LOADTESTS_USE_LOCAL_DEPENDENCIES=ON SUPPORT_SSE=ON SUPPORT_OPENCL=OFF DEPLOY_DOCS=YES PACKAGE=YES @@ -84,6 +89,10 @@ jobs: dist: jammy env: - CHECK_REUSE: ONLY + - os: linux + dist: jammy + env: + - CHECK_MKVK: ONLY - os: linux dist: jammy addons: @@ -201,7 +210,7 @@ before_install: # when the repo owner differs from the user. For details see # https://github.blog/2022-04-12-git-security-vulnerability-announced/ docker run -dit --name emscripten --user "$(id -u):$(id -g)" -v $(pwd):/src emscripten/emsdk bash - elif [ "$CHECK_REUSE" != "ONLY" ]; then + elif [ "$CHECK_REUSE" != "ONLY" -a "$CHECK_MKVK" != "ONLY" ]; then sudo apt-get update fi ;; @@ -216,7 +225,7 @@ install: pip3 install reuse set +e fi - if [ "$CHECK_REUSE" != "ONLY" -a "$WASM_BUILD" != "YES" ]; then + if [ "$CHECK_REUSE" != "ONLY" -a "$CHECK_MKVK" != "ONLY" -a "$WASM_BUILD" != "YES" ]; then if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then # JDK was not installed on arm64 runner. Kept for reference. #sudo apt-get -qq install openjdk-17-jdk @@ -235,11 +244,13 @@ install: fi ;; osx) - if [ "$LOADTESTS_USE_LOCAL_DEPENDENCIES" = "ON" ]; then - brew install sdl2 - brew install assimp + if [ "$CHECK_REUSE" != "ONLY" -a "$CHECK_MKVK" != "ONLY" ]; then + if [ "$LOADTESTS_USE_LOCAL_DEPENDENCIES" = "ON" ]; then + brew install sdl2 + brew install assimp + fi + ./ci_scripts/install_macos.sh fi - ./ci_scripts/install_macos.sh ;; esac @@ -259,15 +270,15 @@ before_script: script: - | + set -e # Instead of trying to chain everything together with && + # otherwise subsequent commands will swallow bad exit status. case "${TRAVIS_OS_NAME:-linux}" in linux) if [ "$CHECK_REUSE" = "YES" -o "$CHECK_REUSE" = "ONLY" ]; then echo "Calling reuse lint." - set -e # because the if below swallows a bad exit status. reuse --suppress-deprecation lint - set +e fi - if [ "$CHECK_REUSE" != "ONLY" ]; then + if [ "$CHECK_REUSE" != "ONLY" -a "$CHECK_MKVK" != "ONLY" ]; then if [ "$WASM_BUILD" = "YES" ]; then ./ci_scripts/build_wasm_docker.sh else @@ -276,19 +287,25 @@ script: fi ;; osx) - if [ "$PLATFORM" = "macOS" ]; then - ./ci_scripts/build_macos.sh - else - ./ci_scripts/build_ios.sh + if [ "$CHECK_REUSE" != "ONLY" -a "$CHECK_MKVK" != "ONLY" ]; then + if [ "$PLATFORM" = "macOS" ]; then + ./ci_scripts/build_macos.sh + else + ./ci_scripts/build_ios.sh + fi fi ;; esac + if [ "$CHECK_MKVK" = "ONLY" ]; then + ci_scripts/check_mkvk.sh + fi if [ "$DEPLOY_DOCS" = "YES" ]; then # Some files in the pyktx docs have an _ prefix so Jekyll will # not copy them from the gh-pages branch to the website. This # file says no Jekyll files here. Treat all as ordinary files. touch $BUILD_DIR/docs/html/.nojekyll fi + set +e # See if this helps with truncated logs. #after_script: diff --git a/CMakeLists.txt b/CMakeLists.txt index 65b1f85502..1813e88f2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,12 @@ else() set( KTX_LOADTEST_APPS_USE_LOCAL_DEPENDENCIES ON ) endif() +option( KTX_GENERATE_VK_FILES + "Include targets for generating VkFormat related files. For project developers only." + OFF +) +mark_as_advanced(FORCE KTX_GENERATE_VK_FILES) + # Platform specific settings if(APPLE) @@ -253,7 +259,9 @@ else() endif() # Depends on the settings, so it must be included after -include(cmake/mkvk.cmake) +if(KTX_GENERATE_VK_FILES) + include(cmake/mkvk.cmake) +endif() # Global compile & link options including optimization flags @@ -457,7 +465,7 @@ add_library( ktx_read ${LIB_TYPE} macro(common_libktx_settings target enable_write library_type) if(TARGET mkvk) - # Creating vulkan headers is only required when Vulkan SDK updates. + # Creating vulkan headers only required after Vulkan Spec/SDK updates. add_dependencies(${target} mkvk) endif() diff --git a/ci_scripts/check_mkvk.ps1 b/ci_scripts/check_mkvk.ps1 new file mode 100644 index 0000000000..4e7bdec834 --- /dev/null +++ b/ci_scripts/check_mkvk.ps1 @@ -0,0 +1,62 @@ +# Copyright 2024 The Khronos Group Inc. +# SPDX-License-Identifier: Apache-2.0 + +<# + .SYNOPSIS + Check generation of VkFormat related files. + + .DESCRIPTION + Regenerates all VkFormat related files and compares them with the + version in Git. Used to verify correct functioning of the generation + scripts in CI. + + .INPUTS + None + + .OUTPUTS + None +#> + +param ( + # Default of $null results in an empty string when not set, so be explicit. + [string] $BUILD_DIR = "" + # With positional parameters, BUILD_DIR will be $null if no parameter. +# [Parameter(Position=0)] [string[]]$BUILD_DIR +) + +function Get-ParamValue { + <# + .SYNOPSIS + Get a parameter value. + + .DESCRIPTION + Returns one of the following in this priority order: + + 1. Value set on command line, if any. + 2. Value from same-named environment variable, if any + 3. $DefaultValue param. + #> + param ( $ParamName, $DefaultValue ) + $res = get-variable $ParamName -ValueOnly -ErrorAction 'SilentlyContinue' + if ($res -eq "" -or $res -eq $null) { + $res = [Environment]::GetEnvironmentVariable($ParamName) + if ($res -eq $null) { + $res = $DefaultValue + } + } + return $res +} + +$BUILD_DIR = Get-ParamValue BUILD_DIR "build/checkmkvk" + +cmake . -B $BUILD_DIR -D KTX_FEATURE_TESTS=OFF -D KTX_FEATURE_TOOLS=OFF -D KTX_GENERATE_VK_FILES=ON +# Clean first is to ensure all files are generated so everything is tested. +cmake --build $BUILD_DIR --target mkvk --clean-first +rm $BUILD_DIR -Recurse -Confirm:$false +# Verify no files were modified. Exit with 1, if so. +git diff --quiet HEAD +if (!$?) { + git status + git diff + exit 1 +} diff --git a/ci_scripts/check_mkvk.sh b/ci_scripts/check_mkvk.sh new file mode 100755 index 0000000000..e290acac3f --- /dev/null +++ b/ci_scripts/check_mkvk.sh @@ -0,0 +1,22 @@ +#! /usr/bin/env bash +# Copyright 2024 The Khronos Group Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Check generation of VkFormat related files. +# +# Regenerates all VkFormat related files and compares them with the +# version in Git. Used to verify correct functioning of the generation +# scripts in CI. + +BUILD_DIR=${BUILD_DIR:-build/checkmkvk} + +cmake . -B $BUILD_DIR -D KTX_FEATURE_TESTS=OFF -D KTX_FEATURE_TOOLS=OFF -D KTX_GENERATE_VK_FILES=ON +# Clean first is to ensure all files are generated so everything is tested. +cmake --build $BUILD_DIR --target mkvk --clean-first +rm -rf $BUILD_DIR +# Verify no files were modified. Exit with 1, if so. +if ! git diff --quiet HEAD; then + git status + git diff + exit 1 +fi diff --git a/cmake/mkvk.cmake b/cmake/mkvk.cmake index dee06ec97c..c09589ac8d 100644 --- a/cmake/mkvk.cmake +++ b/cmake/mkvk.cmake @@ -3,136 +3,130 @@ # Code generation scripts that require a Vulkan SDK installation -#set(skip_mkvk_message "-> skipping mkvk target (this is harmless; only needed when re-generating of vulkan headers and dfdutils is required)") - -if (NOT IOS) +# TODO: Rewrite scripts to generate the files from the Vulkan +# registry, vk.xml, in the Vulkan-Docs repo. + +# NOTE: Since this must be explicitly included by setting an option, +# require sought packages. +# +# CAUTION: Outputs of custom commands are deleted during a clean +# operation so these targets result in clean deleting what are normally +# considered source files. There appears to be no easy way to avoid +# this. Since only project developers need to use these targets, and +# only occasionally, this misfeature can be tolerated. + +if (NOT IOS AND NOT ANDROID) # Not needed as local custom vulkan_core.h is used. Keeping # in case we go back to the standard one. # # find_package doesn't find the Vulkan SDK when building for IOS. # # I haven't investigated why. -# find_package(Vulkan) -# if(NOT Vulkan_FOUND) -# message(STATUS "Vulkan SDK not found ${skip_mkvk_message}") -# return() -# endif() +# find_package(Vulkan REQUIRED) + set(Vulkan_INCLUDE_DIR lib/dfdutils) else() - # Skip mkvk. We don't need to run it when building for iOS. + # Skip mkvk. There is no need to use iOS or Android to regenerate + # the files. return() endif() -if(CMAKE_HOST_WIN32 AND NOT CYGWIN_INSTALL_PATH) - # Git for Windows comes with Perl - # Trick FindPerl into considering default Git location - set(CYGWIN_INSTALL_PATH "C:\\Program Files\\Git\\usr") -endif() +set(vulkan_header "${Vulkan_INCLUDE_DIR}/vulkan/vulkan_core.h") -find_package(Perl) +# CAUTION: On Windows use a version of Perl built for Windows, i.e. not +# one found in Cygwin or MSYS (Git for Windows). This is needed so the +# generated files have the correct the correct CRLF line endings. The ones +# mentioned write LF line endings (possibly related to some Cygwin or MSYS +# installation setting for handling of text files). The Perl scripts, +# unlike the Awk scripts, have not been modified to always write CRLF +# on Windows. +# +# Strawberry Perl via Chocolatey is recommended. +# choco install strawberryperl -if(NOT PERL_FOUND) - message(STATUS "Perl not found ${skip_mkvk_message}") - return() -endif() +#if(CMAKE_HOST_WIN32 AND NOT CYGWIN_INSTALL_PATH) +# # Git for Windows comes with Perl +# # Trick FindPerl into considering default Git location +# set(CYGWIN_INSTALL_PATH "C:\\Program Files\\Git\\usr") +#endif() + +find_package(Perl REQUIRED) list(APPEND mkvkformatfiles_input - "lib/dfdutils/vulkan/vulkan_core.h" - "lib/mkvkformatfiles") + ${vulkan_header} + lib/mkvkformatfiles) list(APPEND mkvkformatfiles_output "${PROJECT_SOURCE_DIR}/lib/vkformat_enum.h" "${PROJECT_SOURCE_DIR}/lib/vkformat_check.c" "${PROJECT_SOURCE_DIR}/lib/vkformat_str.c") -# What a shame! We have to duplicate most of the build commands because -# if(CMAKE_HOST_WIN32) can't appear inside add_custom_command. -if(CMAKE_HOST_WIN32) - add_custom_command(OUTPUT ${mkvkformatfiles_output} - COMMAND ${CMAKE_COMMAND} -E make_directory lib - COMMAND "${BASH_EXECUTABLE}" -c "Vulkan_INCLUDE_DIR=\"${Vulkan_INCLUDE_DIR}\" lib/mkvkformatfiles lib" - COMMAND "${BASH_EXECUTABLE}" -c "unix2dos ${PROJECT_SOURCE_DIR}/lib/vkformat_enum.h" - COMMAND "${BASH_EXECUTABLE}" -c "unix2dos ${PROJECT_SOURCE_DIR}/lib/vkformat_check.c" - COMMAND "${BASH_EXECUTABLE}" -c "unix2dos ${PROJECT_SOURCE_DIR}/lib/vkformat_str.c" - DEPENDS ${mkvkformatfiles_input} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating VkFormat-related source files" - VERBATIM - ) -else() - add_custom_command(OUTPUT ${mkvkformatfiles_output} - COMMAND ${CMAKE_COMMAND} -E make_directory lib - COMMAND Vulkan_INCLUDE_DIR=\"${Vulkan_INCLUDE_DIR}\" lib/mkvkformatfiles lib - DEPENDS ${mkvkformatfiles_input} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating VkFormat-related source files" - VERBATIM - ) -endif() +# CAUTION: When a COMMAND contains VAR="Value" CMake messes up the escaping +# for Bash. With or without VERBATIM, if Value has no spaces CMake changes it +# to VAR=\"Value\". If it has spaces CMake changes it to "VAR=\"Value\"". +# The first causes the quotes to leak into the command that is reading VAR +# breaking, e.g. opening a file that has VAR's value as part of its name. +# The second causes Bash to look for the command 'VAR="Value"' causing it +# to exit with error. +# +# The only workaround I've found is to put the command in a string and invoke +# it with bash -c. This is what we'd have to do on Windows anyway as COMMAND +# defaults to cmd or powershell (not sure which). In this case CMake passes +# to bash a string of the form '"VAR=\"Value\" command arg ..."' which bash +# parses successfully. + +list(APPEND mvffc_as_list + Vulkan_INCLUDE_DIR="${Vulkan_INCLUDE_DIR}" lib/mkvkformatfiles lib) + list(JOIN mvffc_as_list " " mvffc_as_string) + set(mkvkformatfiles_command "${BASH_EXECUTABLE}" -c "${mvffc_as_string}") + +add_custom_command(OUTPUT ${mkvkformatfiles_output} + COMMAND ${CMAKE_COMMAND} -E make_directory lib + COMMAND ${mkvkformatfiles_command} + DEPENDS ${mkvkformatfiles_input} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Generating VkFormat-related source files" + VERBATIM +) add_custom_target(mkvkformatfiles DEPENDS ${mkvkformatfiles_output} SOURCES ${mkvkformatfiles_input} ) -list(APPEND makevkswitch_input - "lib/vkformat_enum.h" - "lib/dfdutils/makevk2dfd.pl") -set(makevkswitch_output +list(APPEND makevk2dfd_input + ${vulkan_header} + lib/dfdutils/makevk2dfd.pl) +set(makevk2dfd_output "${PROJECT_SOURCE_DIR}/lib/dfdutils/vk2dfd.inl") -if(CMAKE_HOST_WIN32) - add_custom_command( - OUTPUT ${makevkswitch_output} - COMMAND ${CMAKE_COMMAND} -E make_directory lib/dfdutils - COMMAND "${PERL_EXECUTABLE}" lib/dfdutils/makevk2dfd.pl lib/vkformat_enum.h lib/dfdutils/vk2dfd.inl - COMMAND "${BASH_EXECUTABLE}" -c "unix2dos ${PROJECT_SOURCE_DIR}/lib/dfdutils/vk2dfd.inl" - DEPENDS ${makevkswitch_input} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating VkFormat/DFD switch body" - VERBATIM - ) -else() - add_custom_command( - OUTPUT ${makevkswitch_output} - COMMAND ${CMAKE_COMMAND} -E make_directory lib/dfdutils - COMMAND "${PERL_EXECUTABLE}" lib/dfdutils/makevk2dfd.pl lib/vkformat_enum.h lib/dfdutils/vk2dfd.inl - DEPENDS ${makevkswitch_input} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating VkFormat/DFD switch body" - VERBATIM - ) -endif() + +add_custom_command( + OUTPUT ${makevk2dfd_output} + COMMAND ${CMAKE_COMMAND} -E make_directory lib/dfdutils + COMMAND "${PERL_EXECUTABLE}" lib/dfdutils/makevk2dfd.pl ${vulkan_header} lib/dfdutils/vk2dfd.inl + DEPENDS ${makevk2dfd_input} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Generating VkFormat/DFD switch body" + VERBATIM +) add_custom_target(makevk2dfd - DEPENDS ${makevkswitch_output} - SOURCES ${makevkswitch_input} + DEPENDS ${makevk2dfd_output} + SOURCES ${makevk2dfd_input} ) list(APPEND makedfd2vk_input - "lib/vkformat_enum.h" - "lib/dfdutils/makedfd2vk.pl") + ${vulkan_header} + lib/dfdutils/makedfd2vk.pl) list(APPEND makedfd2vk_output "${PROJECT_SOURCE_DIR}/lib/dfdutils/dfd2vk.inl") -if(CMAKE_HOST_WIN32) - add_custom_command( - OUTPUT ${makedfd2vk_output} - COMMAND ${CMAKE_COMMAND} -E make_directory lib/dfdutils - COMMAND "${PERL_EXECUTABLE}" lib/dfdutils/makedfd2vk.pl lib/vkformat_enum.h lib/dfdutils/dfd2vk.inl - COMMAND "${BASH_EXECUTABLE}" -c "unix2dos ${PROJECT_SOURCE_DIR}/lib/dfdutils/dfd2vk.inl" - DEPENDS ${makedfd2vk_input} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating DFD/VkFormat switch body" - VERBATIM - ) -else() - add_custom_command( - OUTPUT ${makedfd2vk_output} - COMMAND ${CMAKE_COMMAND} -E make_directory lib/dfdutils - COMMAND "${PERL_EXECUTABLE}" lib/dfdutils/makedfd2vk.pl lib/vkformat_enum.h lib/dfdutils/dfd2vk.inl - DEPENDS ${makedfd2vk_input} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating DFD/VkFormat switch body" - VERBATIM - ) -endif() +add_custom_command( + OUTPUT ${makedfd2vk_output} + COMMAND ${CMAKE_COMMAND} -E make_directory lib/dfdutils + COMMAND "${PERL_EXECUTABLE}" lib/dfdutils/makedfd2vk.pl ${vulkan_header} lib/dfdutils/dfd2vk.inl + DEPENDS ${makedfd2vk_input} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Generating DFD/VkFormat switch body" + VERBATIM +) add_custom_target(makedfd2vk DEPENDS ${makedfd2vk_output} diff --git a/lib/mkvkformatfiles b/lib/mkvkformatfiles index 165ad13df9..2f5f6a809d 100755 --- a/lib/mkvkformatfiles +++ b/lib/mkvkformatfiles @@ -1,5 +1,5 @@ #! /usr/bin/awk -f -# Copyright 2019-2020 Mark Callow +# Copyright 2019-2024 Mark Callow # SPDX-License-Identifier: Apache-2.0 # This script creates 3 files from vulkan/vulkan_core.h: @@ -13,64 +13,66 @@ # KTX2. BEGIN { + if (index(tolower(ENVIRON["OS"]), "windows") > 0) { + ORS = "\r\n"; + } vulkan_core = "vulkan_core.h" processing_core_formats = 0 processing_extension_formats = 0 # Range pattern matches 2nd line to avoid other comments so need # comment opening. - copyright = "/*\n" + copyright = "/*" ORS banner = "" format_decl = "" core_formats = "" extension_formats = "" end_range = "" max_std_format_enum = 0 - prohibited = "#include \n#include \n\n" - prohibited = prohibited "#include \"vkformat_enum.h\"\n\n" - prohibited = prohibited "bool\nisProhibitedFormat(VkFormat format)\n{\n" - prohibited = prohibited " switch (format) {\n"; - valid = "bool\nisValidFormat(VkFormat format)\n{\n" - valid = valid " // On MSVC VkFormat can be a signed integer\n" - valid = valid " if ((uint32_t) format <= VK_FORMAT_MAX_STANDARD_ENUM)\n" - valid = valid " return true;\n else switch(format) {\n" + prohibited = "#include " ORS "#include " ORS ORS + prohibited = prohibited "#include \"vkformat_enum.h\"" ORS ORS + prohibited = prohibited "bool" ORS "isProhibitedFormat(VkFormat format)" ORS "{" ORS + prohibited = prohibited " switch (format) {" ORS; + valid = "bool" ORS "isValidFormat(VkFormat format)" ORS "{" ORS + valid = valid " // On MSVC VkFormat can be a signed integer" ORS + valid = valid " if ((uint32_t) format <= VK_FORMAT_MAX_STANDARD_ENUM)" ORS + valid = valid " return true;" ORS " else switch(format) {" ORS if (ARGC == 2) { output_dir = ARGV[1] "/"; } format_hdr = output_dir "vkformat_enum.h" format_strings = output_dir "vkformat_str.c" format_check = output_dir "vkformat_check.c" + if (ENVIRON["Vulkan_INCLUDE_DIR"]) { + ARGV[1] = ENVIRON["Vulkan_INCLUDE_DIR"] "/vulkan/vulkan_core.h"; ARGC = 2 + } else { # Use local vulkan_core.h until ASTC 3D texture extension is released. -# if (ENVIRON["Vulkan_INCLUDE_DIR"]) { -# vulkan_include_dir = ENVIRON["Vulkan_INCLUDE_DIR"]; -# } else { -# vulkan_include_dir = "/usr/include"; -# } -# ARGV[1] = vulkan_include_dir"/vulkan/"vulkan_core; ARGC = 2 - ARGV[1] = "lib/dfdutils/vulkan/"vulkan_core; ARGC = 2 +# ARGV[1] = "/usr/include"; + ARGV[1] = "lib/dfdutils/vulkan/vulkan_core.h"; ARGC = 2 + } } # A range pattern to extract the copyright message. -/\*\* Copyright*/,/\*\// { copyright = copyright $0 "\n" } +/\*\* Copyright*/,/\*\// { copyright = copyright $0 ORS } $2 == "VK_HEADER_VERSION" { - banner = "\n" - banner = banner "/***************************** Do not edit. *****************************\n" - banner = banner " Automatically generated from " vulkan_core " version " $3 " by mkvkformatfiles.\n" - banner = banner " *************************************************************************/\n" + banner = ORS + banner = banner "/***************************** Do not edit. *****************************" ORS + banner = banner " Automatically generated from " vulkan_core " version " $3 " by mkvkformatfiles." ORS + banner = banner " *************************************************************************/" ORS } # Extract VkFlags definition. /typedef .* VkFlags/ { - format_decl = format_decl "#if defined(_MSC_VER) && _MSC_VER < 1900 // Older than VS 2015.\n" - format_decl = format_decl "typedef unsigned __int32 VkFlags;\n#else\n" - format_decl = format_decl "#include \n" - format_decl = format_decl $0 "\n#endif\n\n" + format_decl = format_decl "#if defined(_MSC_VER) && _MSC_VER < 1900 // Older than VS 2015." ORS + format_decl = format_decl "typedef unsigned __int32 VkFlags;" ORS "#else" ORS + format_decl = format_decl "#include " ORS + format_decl = format_decl $0 ORS "#endif" ORS ORS } # A range pattern to extract the VkFormat declaration. /^typedef enum VkFormat {/,/^} VkFormat;/ { if ($3 !~ /VK_FORMAT_.*/) { # Avoid values defined as existing values. - format_decl = format_decl $0 "\n" + format_decl = format_decl $0 ORS if ($1 ~ /VK_FORMAT/ && $1 !~ /.*MAX_ENUM/ && $3 !~ /1000....../) { # I don't understand why but if I apply the sub to $3 here, it # breaks extraction of VK_FORMAT token names below. It is like @@ -83,23 +85,23 @@ $2 == "VK_HEADER_VERSION" { } } if ($1 ~ /}/) { - end_range = "#define VK_FORMAT_MAX_STANDARD_ENUM " max_std_format_enum "\n"; + end_range = "#define VK_FORMAT_MAX_STANDARD_ENUM " max_std_format_enum ORS; } } -/.*SCALED|A8B8G8R8_.*_PACK32/ { prohibited = prohibited " case " $1 ":\n"; } -#/A8B8G8R8_.*_PACK32/ { prohibited = prohibited " case " $1 ":\n"; } +/.*SCALED|A8B8G8R8_.*_PACK32/ { prohibited = prohibited " case " $1 ":" ORS; } +#/A8B8G8R8_.*_PACK32/ { prohibited = prohibited " case " $1 ":" ORS; } # Multiplane formats. /VK_FORMAT_[^F]/ && (/PLANE/ || /420/) { # Avoid values defined as existing values and avoid the MAX_ENUM value. if ($3 !~ /VK_FORMAT_.*/ && $1 !~ /.*MAX_ENUM/) { - prohibited = prohibited " case " $1 ":\n"; + prohibited = prohibited " case " $1 ":" ORS; } } # Extract valid formats with values > VK_FORMAT_END_RANGE. /VK_FORMAT_[^F].* = 1000/ && ! /PLANE/ && !/420/ { - valid = valid " case " $1 ":\n"; + valid = valid " case " $1 ":" ORS; } function removePrefix(string, prefix) { @@ -112,13 +114,13 @@ function removePrefix(string, prefix) { switch_value = "" if ($1 !~ /.*MAX_ENUM/) { # Avoid the MAX_ENUM value. if ($3 !~ /VK_FORMAT_.*/) { # Avoid values defined as existing values. - switch_body_vk2str = switch_body_vk2str " case " $1 ":\n return \"" $1 "\";\n" + switch_body_vk2str = switch_body_vk2str " case " $1 ":" ORS " return \"" $1 "\";" ORS switch_value = $1 # Use symbolic not numeric value. } else { switch_value = $3 # Use symbol for existing value. sub(/,.*$/, "", switch_value) } - switch_body_str2vk = switch_body_str2vk " if (ktx_strcasecmp(str, \"" removePrefix($1, "VK_FORMAT_") "\") == 0)\n return " switch_value ";\n" + switch_body_str2vk = switch_body_str2vk " if (ktx_strcasecmp(str, \"" removePrefix($1, "VK_FORMAT_") "\") == 0)" ORS " return " switch_value ";" ORS } } @@ -143,65 +145,65 @@ function write_source_file(body, filename) { END { # vkformat_enum.h - write_header_file("_VKFORMAT_ENUM_H_", "VULKAN_CORE_H_", format_decl "\n" end_range, format_hdr); + write_header_file("_VKFORMAT_ENUM_H_", "VULKAN_CORE_H_", format_decl ORS end_range, format_hdr); # vkformat_prohibited.c - prohibited = prohibited " return true;\n" - prohibited = prohibited " default:\n return false;\n }\n}\n"; - valid = valid " return true;\n" - valid = valid " default:\n return false;\n }\n}\n"; - write_source_file(prohibited "\n" valid, format_check) + prohibited = prohibited " return true;" ORS + prohibited = prohibited " default:" ORS " return false;" ORS " }" ORS "}" ORS; + valid = valid " return true;" ORS + valid = valid " default:" ORS " return false;" ORS " }" ORS "}" ORS; + write_source_file(prohibited ORS valid, format_check) # vkformat_str.c - prelude = "\n"; - prelude = prelude "#include \n"; - prelude = prelude "#include \n"; - prelude = prelude "\n"; - prelude = prelude "#include \"vkformat_enum.h\"\n"; - prelude = prelude "\n"; - prelude = prelude "const char*\nvkFormatString(VkFormat format)\n{\n"; - prelude = prelude " switch (format) {\n"; - postscript = " default:\n return \"VK_UNKNOWN_FORMAT\";\n"; - postscript = postscript " }\n"; - postscript = postscript "}\n"; - begin_str2vk = "\n" - begin_str2vk = begin_str2vk "static int ktx_strcasecmp(const char* s1, const char* s2) {\n" - begin_str2vk = begin_str2vk " const unsigned char* us1 = (const unsigned char*) s1;\n" - begin_str2vk = begin_str2vk " const unsigned char* us2 = (const unsigned char*) s2;\n" - begin_str2vk = begin_str2vk "\n" - begin_str2vk = begin_str2vk " while (tolower(*us1) == tolower(*us2)) {\n" - begin_str2vk = begin_str2vk " if (*us1 == '\\0')\n" - begin_str2vk = begin_str2vk " return 0;\n" - begin_str2vk = begin_str2vk " ++us1;\n" - begin_str2vk = begin_str2vk " ++us2;\n" - begin_str2vk = begin_str2vk " }\n" - begin_str2vk = begin_str2vk " return tolower(*us1) - tolower(*us2);\n" - begin_str2vk = begin_str2vk "}\n" - begin_str2vk = begin_str2vk "\n" - begin_str2vk = begin_str2vk "static int ktx_strncasecmp(const char* s1, const char* s2, int length) {\n" - begin_str2vk = begin_str2vk " const unsigned char* us1 = (const unsigned char*) s1;\n" - begin_str2vk = begin_str2vk " const unsigned char* us2 = (const unsigned char*) s2;\n" - begin_str2vk = begin_str2vk "\n" - begin_str2vk = begin_str2vk " while (length > 0 && tolower(*us1) == tolower(*us2)) {\n" - begin_str2vk = begin_str2vk " if (*us1 == '\\0')\n" - begin_str2vk = begin_str2vk " return 0;\n" - begin_str2vk = begin_str2vk " ++us1;\n" - begin_str2vk = begin_str2vk " ++us2;\n" - begin_str2vk = begin_str2vk " --length;\n" - begin_str2vk = begin_str2vk " }\n" - begin_str2vk = begin_str2vk " if (length == 0)\n" - begin_str2vk = begin_str2vk " return 0;\n" - begin_str2vk = begin_str2vk " return tolower(*us1) - tolower(*us2);\n" - begin_str2vk = begin_str2vk "}\n" - begin_str2vk = begin_str2vk "\n" - begin_str2vk = begin_str2vk "/// Parses a VkFormat. VK_FORMAT_ prefix is optional. Case insensitive.\n" - begin_str2vk = begin_str2vk "VkFormat\n" - begin_str2vk = begin_str2vk "stringToVkFormat(const char* str)\n" - begin_str2vk = begin_str2vk "{\n" - begin_str2vk = begin_str2vk " if (ktx_strncasecmp(str, \"VK_FORMAT_\", sizeof(\"VK_FORMAT_\") - 1) == 0)\n" - begin_str2vk = begin_str2vk " str += sizeof(\"VK_FORMAT_\") - 1;\n" - begin_str2vk = begin_str2vk "\n" - end_str2vk = " return VK_FORMAT_UNDEFINED;\n"; + prelude = ORS; + prelude = prelude "#include " ORS; + prelude = prelude "#include " ORS; + prelude = prelude ORS; + prelude = prelude "#include \"vkformat_enum.h\"" ORS; + prelude = prelude ORS; + prelude = prelude "const char*" ORS "vkFormatString(VkFormat format)" ORS "{" ORS; + prelude = prelude " switch (format) {" ORS; + postscript = " default:" ORS " return \"VK_UNKNOWN_FORMAT\";" ORS; + postscript = postscript " }" ORS; + postscript = postscript "}" ORS; + begin_str2vk = ORS + begin_str2vk = begin_str2vk "static int ktx_strcasecmp(const char* s1, const char* s2) {" ORS + begin_str2vk = begin_str2vk " const unsigned char* us1 = (const unsigned char*) s1;" ORS + begin_str2vk = begin_str2vk " const unsigned char* us2 = (const unsigned char*) s2;" ORS + begin_str2vk = begin_str2vk ORS + begin_str2vk = begin_str2vk " while (tolower(*us1) == tolower(*us2)) {" ORS + begin_str2vk = begin_str2vk " if (*us1 == '\\0')" ORS + begin_str2vk = begin_str2vk " return 0;" ORS + begin_str2vk = begin_str2vk " ++us1;" ORS + begin_str2vk = begin_str2vk " ++us2;" ORS + begin_str2vk = begin_str2vk " }" ORS + begin_str2vk = begin_str2vk " return tolower(*us1) - tolower(*us2);" ORS + begin_str2vk = begin_str2vk "}" ORS + begin_str2vk = begin_str2vk ORS + begin_str2vk = begin_str2vk "static int ktx_strncasecmp(const char* s1, const char* s2, int length) {" ORS + begin_str2vk = begin_str2vk " const unsigned char* us1 = (const unsigned char*) s1;" ORS + begin_str2vk = begin_str2vk " const unsigned char* us2 = (const unsigned char*) s2;" ORS + begin_str2vk = begin_str2vk ORS + begin_str2vk = begin_str2vk " while (length > 0 && tolower(*us1) == tolower(*us2)) {" ORS + begin_str2vk = begin_str2vk " if (*us1 == '\\0')" ORS + begin_str2vk = begin_str2vk " return 0;" ORS + begin_str2vk = begin_str2vk " ++us1;" ORS + begin_str2vk = begin_str2vk " ++us2;" ORS + begin_str2vk = begin_str2vk " --length;" ORS + begin_str2vk = begin_str2vk " }" ORS + begin_str2vk = begin_str2vk " if (length == 0)" ORS + begin_str2vk = begin_str2vk " return 0;" ORS + begin_str2vk = begin_str2vk " return tolower(*us1) - tolower(*us2);" ORS + begin_str2vk = begin_str2vk "}" ORS + begin_str2vk = begin_str2vk ORS + begin_str2vk = begin_str2vk "/// Parses a VkFormat. VK_FORMAT_ prefix is optional. Case insensitive." ORS + begin_str2vk = begin_str2vk "VkFormat" ORS + begin_str2vk = begin_str2vk "stringToVkFormat(const char* str)" ORS + begin_str2vk = begin_str2vk "{" ORS + begin_str2vk = begin_str2vk " if (ktx_strncasecmp(str, \"VK_FORMAT_\", sizeof(\"VK_FORMAT_\") - 1) == 0)" ORS + begin_str2vk = begin_str2vk " str += sizeof(\"VK_FORMAT_\") - 1;" ORS + begin_str2vk = begin_str2vk ORS + end_str2vk = " return VK_FORMAT_UNDEFINED;" ORS; end_str2vk = end_str2vk "}" write_source_file(prelude switch_body_vk2str postscript begin_str2vk switch_body_str2vk end_str2vk, format_strings); }