Skip to content

Commit

Permalink
Update to Basis1.16.3 (KhronosGroup#543)
Browse files Browse the repository at this point in the history
* git subrepo commit (merge) lib/basisu

subrepo:
  subdir:   "lib/basisu"
  merged:   "7e156388"
upstream:
  origin:   "https://github.com/BinomialLLC/basis_universal.git"
  branch:   "master"
  commit:   "1f4b564a"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/MarkCallow/git-subrepo.git"
  commit:   "c1f1132"

* Fix syntax errors in on_failure.ps1.
  • Loading branch information
MarkCallow authored Mar 4, 2022
1 parent c2c3eec commit 785fd31
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 31 deletions.
4 changes: 2 additions & 2 deletions lib/basisu/.gitrepo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/BinomialLLC/basis_universal.git
branch = master
commit = 44e1bcd3e145d18eb29d2915581ad4c61bb65cc7
parent = d98aa6807c67368de818aa4d128e47898666266a
commit = 1f4b564ae0b8ec1e67f21f058e53112d0405a25a
parent = cb45eadca7fed568d9f6f51477ca897d1ec2732a
method = merge
cmdver = 0.4.3
13 changes: 10 additions & 3 deletions lib/basisu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ project(basisu)

cmake_minimum_required(VERSION 3.0)
option(STATIC "static linking" FALSE)
option(SAN "sanitize" FALSE)

# For MSVC builds default to SSE enabled, and determine if it's a 64-bit (-A x64) vs. 32-bit (-A Win32) build.
if (MSVC)
Expand All @@ -24,6 +25,7 @@ message("Initial CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
message("Initial SSE=${SSE}")
message("Initial ZSTD=${ZSTD}")
message("Initial OPENCL=${OPENCL}")
message("Initial SAN=${SAN}")

if (NOT MSVC)
# With MSVC builds we use the Khronos lib/include files in the project's "OpenCL" directory, to completely avoid requiring fiddly to install vendor SDK's.
Expand Down Expand Up @@ -60,10 +62,15 @@ endif()

if (NOT MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")

set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")

if (SAN)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined")
endif()

set(CMAKE_CXX_FLAGS -std=c++11)
set(GCC_COMPILE_FLAGS "-fvisibility=hidden -fPIC -fno-strict-aliasing -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -Wall -Wextra -Wno-unused-local-typedefs -Wno-unused-value -Wno-unused-parameter -Wno-unused-variable")
Expand Down
6 changes: 3 additions & 3 deletions lib/basisu/basisu_tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
using namespace basisu;
using namespace buminiz;

#define BASISU_TOOL_VERSION "1.16"
#define BASISU_TOOL_VERSION "1.16.3"

enum tool_mode
{
Expand Down Expand Up @@ -2044,7 +2044,7 @@ static bool unpack_and_validate_basis_file(
// Fill the buffer with psuedo-random bytes, to help more visibly detect cases where the transcoder fails to write to part of the output.
fill_buffer_with_random_bytes(gi.get_ptr(), gi.get_size_in_bytes());

uint32_t decode_flags = 0;
//uint32_t decode_flags = 0;

tm.start();

Expand Down Expand Up @@ -2741,7 +2741,7 @@ static bool compare_mode(command_line_params &opts)
{
for (uint32_t x = 0; x < a.get_width(); x++)
{
color_rgba& d = delta_img(x, y);
//color_rgba& d = delta_img(x, y);

for (int c = 0; c < 4; c++)
{
Expand Down
14 changes: 7 additions & 7 deletions lib/basisu/contrib/single_file_transcoder/README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
# Single File Basis Universal Transcoder

The script `combine.sh` creates an _amalgamated_ C++ source file that can be used with or without `basisu_transcoder.h`. This _isn't_ a header-only file but it does offer a similar level of simplicity when integrating into a project.
The script `combine.py` creates an _amalgamated_ C++ source file that can be used with or without `basisu_transcoder.h`. This _isn't_ a header-only file but it does offer a similar level of simplicity when integrating into a project.

Create `basisu_transcoder.cpp` from the transcoder sources using:
```
cd basis_universal/contrib/single_file_transcoder
./combine.sh -r ../../transcoder -o basisu_transcoder.cpp basisu_transcoder-in.cpp
python3 combine.py -r ../../transcoder -o basisu_transcoder.cpp basisu_transcoder-in.cpp
```
Then add the resulting file to your project (see the [example files](examples)).

If certain features will _never__ be enabled, e.g. `BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY`, then `combine.sh` can be told to exclude files with the `-x` option:
If certain features will _never__ be enabled, e.g. `BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY`, then `combine.py` can be told to exclude files with the `-x` option:
```
./combine.sh -r ../../transcoder -x basisu_transcoder_tables_bc7_m6.inc -o basisu_transcoder.cpp basisu_transcoder-in.cpp
python3 combine.py -r ../../transcoder -x basisu_transcoder_tables_bc7_m6.inc -o basisu_transcoder.cpp basisu_transcoder-in.cpp
```
Excluding the BC7 mode 6 support reduces the generated source by 1.2MB, which is the choice taken in `basisu_transcoder-in.cpp` and used in the examples, with `create_transcoder.sh` running the above script, creating the final `basisu_transcoder.cpp`.

The combiner script can also generate separate amalgamated header and source files, using the `-k` option to keep the specified inline directive, and `-p` to keep the `#pragma once` directives in the header:
```
./combine.sh -r ../../transcoder -o basisu_transcoder.h -p ../../transcoder/basisu_transcoder.h
python3 combine.py -r ../../transcoder -o basisu_transcoder.h -p ../../transcoder/basisu_transcoder.h
./combine.sh -r ../../transcoder -x basisu_transcoder_tables_bc7_m6.inc -k basisu_transcoder.h -o basisu_transcoder.cpp basisu_transcoder-in.cpp
python3 combine.py -r ../../transcoder -x basisu_transcoder_tables_bc7_m6.inc -k basisu_transcoder.h -o basisu_transcoder.cpp basisu_transcoder-in.cpp
```

Note: the amalgamation script will run on pretty much anything but is _extremely_ slow on Windows with the `bash` included with Git.
Note: the amalgamation script was tested on Windows and Mac, requiring Python 3.8, with a fallback implementation as a shell script that will run on pretty much anything.

Why?
----
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Basis Universal single file library. Generated using:
* \code
* ./combine.sh -r ../../transcoder -o basisu_transcoder.cpp basisu_transcoder-in.cpp
* ./combine.py -r ../../transcoder -o basisu_transcoder.cpp basisu_transcoder-in.cpp
* \endcode
*/

Expand Down
234 changes: 234 additions & 0 deletions lib/basisu/contrib/single_file_transcoder/combine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#!/usr/bin/env python3

# Tool to bundle multiple C/C++ source files, inlining any includes.
#
# Note: there are two types of exclusion options: the '-x' flag, which besides
# excluding a file also adds an #error directive in place of the #include, and
# the '-k' flag, which keeps the #include and doesn't inline the file. The
# intended use cases are: '-x' for files that would normally be #if'd out, so
# features that 100% won't be used in the amalgamated file, for which every
# occurrence adds the error, and '-k' for headers that we wish to manually
# include, such as a project's public API, for which occurrences after the first
# are removed.
#
# Todo: the error handling could be better, which currently throws and halts
# (which is functional just not very friendly).
#
# Author: Carl Woffenden, Numfum GmbH (this script is released under a CC0 license/Public Domain)

import argparse, re, sys

from pathlib import Path
from typing import Any, List, Optional, Pattern, Set, TextIO

# Set of file roots when searching (equivalent to -I paths for the compiler).
roots: Set[Path] = set()

# Set of (canonical) file Path objects to exclude from inlining (and not only
# exclude but to add a compiler error directive when they're encountered).
excludes: Set[Path] = set()

# Set of (canonical) file Path objects to keep as include directives.
keeps: Set[Path] = set()

# Whether to keep the #pragma once directives (unlikely, since this will result
# in a warning, but the option is there).
keep_pragma: bool = False

# Destination file object (or stdout if no output file was supplied).
destn:TextIO = sys.stdout

# Set of file Path objects previously inlined (and to ignore if reencountering).
found: Set[Path] = set()

# Compiled regex Patern to handle the following type of file includes:
#
# #include "file"
# #include "file"
# # include "file"
# #include "file"
# #include "file" // comment
# #include "file" // comment with quote "
#
# And all combinations of, as well as ignoring the following:
#
# #include <file>
# //#include "file"
# /*#include "file"*/
#
# We don't try to catch errors since the compiler will do this (and the code is
# expected to be valid before processing) and we don't care what follows the
# file (whether it's a valid comment or not, since anything after the quoted
# string is ignored)
#
include_regex: Pattern = re.compile(r'^\s*#\s*include\s*"(.+?)"')

# Simple tests to prove include_regex's cases.
#
def test_match_include() -> bool:
if (include_regex.match('#include "file"') and
include_regex.match(' #include "file"') and
include_regex.match('# include "file"') and
include_regex.match('#include "file"') and
include_regex.match('#include "file" // comment')):
if (not include_regex.match('#include <file>') and
not include_regex.match('//#include "file"') and
not include_regex.match('/*#include "file"*/')):
found = include_regex.match('#include "file" // "')
if (found and found.group(1) == 'file'):
print('#include match valid')
return True
return False

# Compiled regex Patern to handle "#pragma once" in various formats:
#
# #pragma once
# #pragma once
# # pragma once
# #pragma once
# #pragma once // comment
#
# Ignoring commented versions, same as include_regex.
#
pragma_regex: Pattern = re.compile(r'^\s*#\s*pragma\s*once\s*')

# Simple tests to prove pragma_regex's cases.
#
def text_match_pragma() -> bool:
if (pragma_regex.match('#pragma once') and
pragma_regex.match(' #pragma once') and
pragma_regex.match('# pragma once') and
pragma_regex.match('#pragma once') and
pragma_regex.match('#pragma once // comment')):
if (not pragma_regex.match('//#pragma once') and
not pragma_regex.match('/*#pragma once*/')):
print('#pragma once match valid')
return True
return False

# Finds 'file'. First the list of 'root' paths are searched, followed by the
# the currently processing file's 'parent' path, returning a valid Path in
# canonical form. If no match is found None is returned.
#
def resolve_include(file: str, parent: Optional[Path] = None) -> Optional[Path]:
for root in roots:
found = root.joinpath(file).resolve()
if (found.is_file()):
return found
if (parent):
found = parent.joinpath(file).resolve();
else:
found = Path(file)
if (found.is_file()):
return found
return None

# Helper to resolve lists of files. 'file_list' is passed in from the arguments
# and each entry resolved to its canonical path (like any include entry, either
# from the list of root paths or the owning file's 'parent', which in this case
# is case is the input file). The results are stored in 'resolved'.
#
def resolve_excluded_files(file_list: Optional[List[str]], resolved: Set[Path], parent: Optional[Path] = None) -> None:
if (file_list):
for filename in file_list:
found = resolve_include(filename, parent)
if (found):
resolved.add(found)
else:
error_line(f'Warning: excluded file not found: {filename}')

# Writes 'line' to the open 'destn' (or stdout).
#
def write_line(line: str) -> None:
print(line, file=destn)

# Logs 'line' to stderr. This is also used for general notifications that we
# don't want to go to stdout (so the source can be piped).
#
def error_line(line: Any) -> None:
print(line, file=sys.stderr)

# Inline the contents of 'file' (with any of its includes also inlined, etc.).
#
# Note: text encoding errors are ignored and replaced with ? when reading the
# input files. This isn't ideal, but it's more than likely in the comments than
# code and a) the text editor has probably also failed to read the same content,
# and b) the compiler probably did too.
#
def add_file(file: Path, file_name: str = None) -> None:
if (file.is_file()):
if (not file_name):
file_name = file.name
error_line(f'Processing: {file_name}')
with file.open('r', errors='replace') as opened:
for line in opened:
line = line.rstrip('\n')
match_include = include_regex.match(line);
if (match_include):
# We have a quoted include directive so grab the file
inc_name = match_include.group(1)
resolved = resolve_include(inc_name, file.parent)
if (resolved):
if (resolved in excludes):
# The file was excluded so error if the compiler uses it
write_line(f'#error Using excluded file: {inc_name}')
error_line(f'Excluding: {inc_name}')
else:
if (resolved not in found):
# The file was not previously encountered
found.add(resolved)
if (resolved in keeps):
# But the include was flagged to keep as included
write_line(f'/**** *NOT* inlining {inc_name} ****/')
write_line(line)
error_line(f'Not inlining: {inc_name}')
else:
# The file was neither excluded nor seen before so inline it
write_line(f'/**** start inlining {inc_name} ****/')
add_file(resolved, inc_name)
write_line(f'/**** ended inlining {inc_name} ****/')
else:
write_line(f'/**** skipping file: {inc_name} ****/')
else:
# The include file didn't resolve to a file
write_line(f'#error Unable to find: {inc_name}')
error_line(f'Error: Unable to find: {inc_name}')
else:
# Skip any 'pragma once' directives, otherwise write the source line
if (keep_pragma or not pragma_regex.match(line)):
write_line(line)
else:
error_line(f'Error: Invalid file: {file}')

# Start here
parser = argparse.ArgumentParser(description='Amalgamate Tool', epilog=f'example: {sys.argv[0]} -r ../my/path -r ../other/path -o out.c in.c')
parser.add_argument('-r', '--root', action='append', type=Path, help='file root search path')
parser.add_argument('-x', '--exclude', action='append', help='file to completely exclude from inlining')
parser.add_argument('-k', '--keep', action='append', help='file to exclude from inlining but keep the include directive')
parser.add_argument('-p', '--pragma', action='store_true', default=False, help='keep any "#pragma once" directives (removed by default)')
parser.add_argument('-o', '--output', type=argparse.FileType('w'), help='output file (otherwise stdout)')
parser.add_argument('input', type=Path, help='input file')
args = parser.parse_args()

# Fail early on an invalid input (and store it so we don't recurse)
args.input = args.input.resolve(strict=True)
found.add(args.input)

# Resolve all of the root paths upfront (we'll halt here on invalid roots)
if (args.root):
for path in args.root:
roots.add(path.resolve(strict=True))

# The remaining params: so resolve the excluded files and #pragma once directive
resolve_excluded_files(args.exclude, excludes, args.input.parent)
resolve_excluded_files(args.keep, keeps, args.input.parent)
keep_pragma = args.pragma;

# Then recursively process the input file
try:
if (args.output):
destn = args.output
add_file(args.input)
finally:
if (not destn):
destn.close()
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
OUT_FILE="tempbin"

echo "Amalgamating files... this can take a while"
./combine.sh -r ../../transcoder -o basisu_transcoder.cpp basisu_transcoder-in.cpp
# Use the faster Python script if we have 3.8 or higher
if python3 -c 'import sys; assert sys.version_info >= (3,8)' 2>/dev/null; then
./combine.py -r ../../transcoder -o basisu_transcoder.cpp basisu_transcoder-in.cpp
else
./combine.sh -r ../../transcoder -o basisu_transcoder.cpp basisu_transcoder-in.cpp
fi
# Did combining work?
if [ $? -ne 0 ]; then
echo "Combine script: FAILED"
Expand Down
13 changes: 12 additions & 1 deletion lib/basisu/encoder/basisu_enc.h
Original file line number Diff line number Diff line change
Expand Up @@ -990,17 +990,28 @@ namespace basisu
int dg = e1.g - e2.g;
int db = e1.b - e2.b;

#if 0
int delta_l = dr * 27 + dg * 92 + db * 9;
int delta_cr = dr * 128 - delta_l;
int delta_cb = db * 128 - delta_l;

uint32_t id = ((uint32_t)(delta_l * delta_l) >> 7U) +
((((uint32_t)(delta_cr * delta_cr) >> 7U) * 26U) >> 7U) +
((((uint32_t)(delta_cb * delta_cb) >> 7U) * 3U) >> 7U);
#else
int64_t delta_l = dr * 27 + dg * 92 + db * 9;
int64_t delta_cr = dr * 128 - delta_l;
int64_t delta_cb = db * 128 - delta_l;

uint32_t id = ((uint32_t)((delta_l * delta_l) >> 7U)) +
((((uint32_t)((delta_cr * delta_cr) >> 7U)) * 26U) >> 7U) +
((((uint32_t)((delta_cb * delta_cb) >> 7U)) * 3U) >> 7U);
#endif

if (alpha)
{
int da = (e1.a - e2.a) << 7;
// This shouldn't overflow if da is 255 or -255: 29.99 bits after squaring.
id += ((uint32_t)(da * da) >> 7U);
}

Expand Down
Loading

0 comments on commit 785fd31

Please sign in to comment.