364 lines
14 KiB
Awk
Executable File
364 lines
14 KiB
Awk
Executable File
#! /usr/bin/env -S awk -f
|
|
# Copyright 2019-2024 Mark Callow
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# Usage: mkvkformatfiles [output-dir path/to/vulkan_core]
|
|
#
|
|
# output_dir defaults to the current directory.
|
|
# path/to/vulkan_core defaults to ENVIRON["Vulkan_INCLUDE_DIR"]. If not
|
|
# set, default is external/dfdutils/vulkan/vulkan_core.h.
|
|
#
|
|
# When specifying path/to/vulkan_core, output-dir must also be
|
|
# specified.
|
|
|
|
# This script creates 6 files from vulkan/vulkan_core.h:
|
|
#
|
|
# - lib/vkformat_enum.h: the VkFormat enum declaration for those who don't
|
|
# want to include vulkan_core.h. extension token names for
|
|
# extensions that have been moved to core are omitted.
|
|
#
|
|
# - lib/vkformat_str.c: a switch statement for converting VkFormat enums to
|
|
# to strings corresponding to the format names.
|
|
# - lib/vkformat_typesize.c, function to return the type-size for each
|
|
# format.
|
|
#
|
|
# - lib/vkformat_check.c: 3 functions: 1 to check if a format is prohibited in
|
|
# KTX2, one to see if a format is a valid Vulkan format and one to see
|
|
# if it is an sRGB format.
|
|
#
|
|
# - interface/java_binding/src/main/java/org/khronos/ktx/VkFormat.java,
|
|
# VkFormat enumerators for Java.
|
|
#
|
|
# - interface/js_binding/vk_format.inl,
|
|
# VkFormat enumeration body for ktx_wrapper.cpp.
|
|
#
|
|
# - interface/python_binding/pyktx/vk_format.py, VkFormat enumerators for
|
|
# Python.
|
|
#
|
|
# - tests/unittests/vkformat_list.inl, a list of VkFormat enum names for use in
|
|
# initializing tables, etc.
|
|
#
|
|
# KTX v2 prohibited formats are excluded from the last three files.
|
|
|
|
BEGIN {
|
|
if (index(tolower(ENVIRON["OS"]), "windows") > 0) {
|
|
ORS = "\r\n";
|
|
}
|
|
# ARGV[0] is "awk".
|
|
if (ARGC > 1) {
|
|
output_dir = ARGV[1] "/";
|
|
delete ARGV[1];
|
|
} else {
|
|
output_dir = "./";
|
|
}
|
|
# awk reads files whose names are found in the positional parameters,
|
|
# hence setting ARGV[1] here and deleting a possible ARGV[1] above.
|
|
if (ARGC == 1) {
|
|
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.
|
|
# ARGV[1] = "/usr/include";
|
|
ARGV[1] = "external/dfdutils/vulkan/vulkan_core.h"; ARGC = 2
|
|
}
|
|
}
|
|
|
|
# Hard-coded paths are somewhat unfortunate but major changes in
|
|
# the source code organization are unlikely.
|
|
format_hdr = output_dir "lib/vkformat_enum.h"
|
|
format_typesize = output_dir "lib/vkformat_typesize.c"
|
|
format_inl = output_dir "tests/unittests/vkformat_list.inl"
|
|
format_strings = output_dir "lib/vkformat_str.c"
|
|
format_check = output_dir "lib/vkformat_check.c"
|
|
format_java = output_dir "interface/java_binding/src/main/java/org/khronos/ktx/VkFormat.java"
|
|
format_js = output_dir "interface/js_binding/vk_format.inl"
|
|
format_python = output_dir "interface/python_binding/pyktx/vk_format.py"
|
|
|
|
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 = "/*" ORS
|
|
banner = ""
|
|
format_decl = ""
|
|
format_name_list = ""
|
|
core_formats = ""
|
|
extension_formats = ""
|
|
end_range = ""
|
|
max_std_format_enum = 0
|
|
java = "package org.khronos.ktx;" ORS "public class VkFormat {" ORS
|
|
prohibited = "#include <stdint.h>" ORS "#include <stdbool.h>" ORS ORS
|
|
prohibited = prohibited "#include \"vkformat_enum.h\"" ORS ORS
|
|
prohibited = prohibited "bool" ORS "isProhibitedFormat(VkFormat format)" ORS "{" ORS
|
|
prohibited = prohibited " switch (format) {" ORS;
|
|
python = "from enum import IntEnum" ORS ORS "class VkFormat(IntEnum):" ORS
|
|
python = python " \"\"\"Vulkan texture format constants.\"\"\"" ORS ORS
|
|
srgb = "bool" ORS "isSrgbFormat(VkFormat format)" ORS "{" ORS
|
|
srgb = srgb " 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
|
|
}
|
|
|
|
# A range pattern to extract the copyright message.
|
|
/\*\* Copyright*/,/\*\// { copyright = copyright $0 ORS; }
|
|
|
|
$2 == "VK_HEADER_VERSION" {
|
|
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." ORS
|
|
format_decl = format_decl "typedef unsigned __int32 VkFlags;" ORS "#else" ORS
|
|
format_decl = format_decl "#include <stdint.h>" 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 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
|
|
# this $3 becomes the $3 seen down there.
|
|
enum_val = $3;
|
|
sub(/,$/, "", enum_val);
|
|
if (enum_val+0 > max_std_format_enum) {
|
|
max_std_format_enum = enum_val+0;
|
|
}
|
|
if ($1 !~ /UNDEFINED/) {
|
|
format_name_list = format_name_list $1 "," ORS
|
|
}
|
|
if ($1 !~ /SCALED/ && $1) {
|
|
java = java " public static final int " $1 " = " enum_val ";" ORS
|
|
js = js " .value(\"" removePrefix($1, "VK_FORMAT_") "\", " $1 ")" ORS
|
|
python = python " " $1 " = " enum_val ORS
|
|
}
|
|
}
|
|
}
|
|
if ($1 ~ /}/) {
|
|
end_range = "#define VK_FORMAT_MAX_STANDARD_ENUM " max_std_format_enum ORS;
|
|
}
|
|
}
|
|
|
|
/.*SCALED/ { 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 ":" ORS;
|
|
}
|
|
}
|
|
|
|
# Extract srgb formats
|
|
/VK_FORMAT_.*SRGB/ && !/PLANE/ && !/420/ {
|
|
srgb = srgb " case " $1 ":" ORS;
|
|
}
|
|
|
|
# Extract valid formats with values > VK_FORMAT_END_RANGE.
|
|
/VK_FORMAT_[^F].* = 1000/ && !/PLANE/ && !/420/ {
|
|
valid = valid " case " $1 ":" ORS;
|
|
format_name_list = format_name_list $1 "," ORS
|
|
enum_val = $3;
|
|
sub(/,$/, "", enum_val);
|
|
java = java " public static final int " $1 " = " enum_val ";" ORS
|
|
js = js " .value(\"" removePrefix($1, "VK_FORMAT_") "\", " $1 ")" ORS
|
|
python = python " " $1 " = " enum_val ORS
|
|
}
|
|
|
|
function removePrefix(string, prefix) {
|
|
sub("^" prefix, "", string)
|
|
return string
|
|
}
|
|
|
|
function genTypeSize(format) {
|
|
size = format
|
|
if (format ~ /^VK_FORMAT_UNDEFINED$/) {
|
|
size = 1
|
|
} else if (format ~ /.*PACK[0-9]+($|_)/) {
|
|
sub("^.*PACK", "", size)
|
|
sub("_.*$", "", size)
|
|
size = size / 8
|
|
} else if (format ~ /.*BLOCK/) {
|
|
size = 1
|
|
} else if (format ~ /D16_UNORM_S8_UINT/) {
|
|
size = 2
|
|
} else if (format ~ /D24_UNORM_S8_UINT/) {
|
|
size = 4
|
|
} else {
|
|
sub("^[^0-9]+", "", size)
|
|
sub("[^0-9].*$", "", size)
|
|
size = size / 8
|
|
}
|
|
return " case " format ":" ORS " return " size ";" ORS
|
|
}
|
|
|
|
# Extract VK_FORMAT token names. [^F] avoids the VK_FORMAT_FEATURE* tokens.
|
|
/ VK_FORMAT_[^F]/ {
|
|
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 ":" ORS " return \"" $1 "\";" ORS
|
|
switch_value = $1 # Use symbolic not numeric value.
|
|
switch_body_vktypesize = switch_body_vktypesize genTypeSize($1)
|
|
} 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)" ORS " return " switch_value ";" ORS
|
|
}
|
|
}
|
|
|
|
function write_header_file(guard1, guard2, body, filename) {
|
|
print "// clang-format off: CI is complicated if formatting checks on generated files are enforced." > filename
|
|
if (guard2) {
|
|
print "#if !defined("guard1") && !defined("guard2")" > filename
|
|
} else {
|
|
print "#ifndef "guard1 > filename
|
|
}
|
|
print "#define "guard1 > filename
|
|
print banner > filename
|
|
print copyright > filename
|
|
print body > filename
|
|
print "#endif /* "guard1" */" > filename
|
|
print "// clang-format on" > filename
|
|
}
|
|
|
|
function write_source_file(body, filename) {
|
|
print banner > filename
|
|
print copyright > filename
|
|
# write_source_file used for both java and c sources
|
|
if (filename ~ /\.(h|c)$/) {
|
|
print "// clang-format off: CI is complicated if formatting checks on generated files are enforced." > filename
|
|
}
|
|
print body > filename
|
|
if (filename ~ /\.(h|c)$/) {
|
|
print "// clang-format on" > filename
|
|
}
|
|
}
|
|
|
|
function write_python_source_file(body, filename) {
|
|
pybanner = banner;
|
|
sub(/\/\*/, "#***", pybanner);
|
|
sub(/\*\//, "****", pybanner);
|
|
sub(/ Auto/, "# Auto", pybanner);
|
|
regexp = ORS " \\*";
|
|
sub(regexp, ORS "#", pybanner);
|
|
|
|
pycopyright = copyright;
|
|
regexp = "/\\*" ORS;
|
|
sub(regexp, "", pycopyright);
|
|
gsub(/\*\*/, "#", pycopyright);
|
|
regexp = "\\*/" ORS;
|
|
sub(regexp, "", pycopyright);
|
|
|
|
print pybanner > filename
|
|
print pycopyright > filename
|
|
print body > filename
|
|
}
|
|
|
|
END {
|
|
# vkformat_enum.h
|
|
write_header_file("_VKFORMAT_ENUM_H_", "VULKAN_CORE_H_", format_decl ORS end_range, format_hdr);
|
|
|
|
# vkformat_list.inl
|
|
write_source_file(format_name_list ORS, format_inl)
|
|
|
|
# vkformat_typesize.c
|
|
begin_vktypesize = ORS
|
|
begin_vktypesize = begin_vktypesize "#include <stdint.h>" ORS;
|
|
begin_vktypesize = begin_vktypesize ORS;
|
|
begin_vktypesize = begin_vktypesize "#include \"vkformat_enum.h\"" ORS;
|
|
begin_vktypesize = begin_vktypesize ORS;
|
|
begin_vktypesize = begin_vktypesize "uint32_t" ORS "vkFormatTypeSize(VkFormat format)" ORS "{" ORS;
|
|
begin_vktypesize = begin_vktypesize " switch (format) {" ORS;
|
|
end_vktypesize = " default:" ORS
|
|
end_vktypesize = end_vktypesize " return 0;" ORS;
|
|
end_vktypesize = end_vktypesize " }" ORS
|
|
end_vktypesize = end_vktypesize "}"
|
|
write_source_file(begin_vktypesize switch_body_vktypesize end_vktypesize, format_typesize);
|
|
|
|
# vkformat_check.c
|
|
prohibited = prohibited " return true;" ORS
|
|
prohibited = prohibited " default:" ORS " return false;" ORS " }" ORS "}" ORS;
|
|
srgb = srgb " return true;" ORS
|
|
srgb = srgb " 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 srgb ORS valid, format_check)
|
|
|
|
# vkformat_str.c
|
|
prelude = ORS;
|
|
prelude = prelude "#include <stdint.h>" ORS;
|
|
prelude = prelude "#include <ctype.h>" 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);
|
|
|
|
# VkFormat.java
|
|
end_java = "}" ORS
|
|
write_source_file(java end_java, format_java);
|
|
|
|
# vk_format.inl (js)
|
|
write_source_file(js, format_js);
|
|
|
|
# vk_format.py
|
|
write_python_source_file(python, format_python);
|
|
}
|
|
|
|
# vim:ai:ts=4:sts=4:sw=2:expandtab:textwidth=70
|
|
|