diff --git a/.github/workflows/publish-pyktx.yml b/.github/workflows/publish-pyktx.yml new file mode 100644 index 0000000000..b928c11684 --- /dev/null +++ b/.github/workflows/publish-pyktx.yml @@ -0,0 +1,126 @@ +# Copyright 2023 Shukant Pal +# SPDX-License-Identifier: Apache-2.0 + +name: Publish Python 🐍 distribution 📦 to PyPI or TestPyPI + +# https://github.com/pypa/gh-action-pypi-publish strongly recommends a +# separate publishing job when building platform-specific distribution +# packages, hence this. +# +# This should not be run until the release artifacts have been deployed. +# The only way I can see to trigger this automatically is to have all +# platform builds in a single workflow file and use on: `workflow_run` +# so this is triggered when that workflow completes. Once all platform +# builds are moved to GitHub Actions we can try making each platform +# workflow reusable and making another workflow that calls each of +# them via `uses` and use `on: workflow_run` here. +# +# We also have to figure out how to determine if the workflow deployed +# to releases. Maybe can use the GitHub REST API to get an artifact +# from the triggering workflow that is set only when deploying +# releases. See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow. +# Alternatively maybe there is some way of querying what triggered +# the workflow that we can test in an `if:` in the job as noted below. + +on: + workflow_dispatch: + inputs: +# repository-url: +# description: 'destination repository' +# required: true +# default: 'https://pypi.org' +# type: choice +# options: +# - https://test.pypi.org +# - https://pypi.org + test-pypi: + type: boolean + description: 'Deploy to test pypi registry' + required: true + default: false + +# Example to try in future. +# workflow_run: +# workflows: [KTX-Software Build All] +# types: +# - completed +# An unknown is how to limit the trigger to when deploy is run in +# Windows CI which is happens when that workflow is triggered by +# a push with the tags below. +# push: +# # Trigger on push of release tags. There is no way to limit the trigger +# # to a specific branch. A later build step checks for the main branch. +# tags: +# - 'v[0-9]+\.[0-9]+\.[0-9]+' +# - 'v[0-9]+\.[0-9]+\.[0-9]+-*' + +jobs: + publish-to-pypi: + name: Publish Python 🐍 distribution 📦 to PyPI + if: test-pypi == false + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/pyktx + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + # When using workflow_run it is necessary to check for successful + # completion of the workflow with + #if: ${{ github.event.workflow_run.conclusion == 'success' }} + # Maybe it is possible to test for a release tag here too. + steps: + - name: Download latest release metadata + run: | + curl \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -o latest.json \ + https://api.github.com/repos/KhronosGroup/KTX-Software/releases/latest + - name: Filter out pyktx- assets + run: | + jq '.assets | map(select(.name | startswith("pyktx-"))) | map(.browser_download_url)' < latest.json > pyktx.json + - name: Create dist directory + run: | + mkdir dist + - name: Download assets + run: | + cd dist; jq -c '.[]' ../pyktx.json | xargs -L 1 curl -O -J; cd.. + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} + + publish-to-testpypi: + name: Publish Python 🐍 distribution 📦 to TestPyPI + if: test-pypi + runs-on: ubuntu-latest + environment: + name: testpypi + url: https://pypi.org/p/pyktx + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + # When using workflow_run it is necessary to check for successful + # completion of the workflow with + #if: ${{ github.event.workflow_run.conclusion == 'success' }} + # Maybe it is possible to test for a release tag here too. + steps: + - name: Download latest release metadata + run: | + curl \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -o latest.json \ + https://api.github.com/repos/KhronosGroup/KTX-Software/releases/latest + - name: Filter out pyktx- assets + run: | + jq '.assets | map(select(.name | startswith("pyktx-"))) | map(.browser_download_url)' < latest.json > pyktx.json + - name: Create dist directory + run: | + mkdir dist + - name: Download assets + run: | + cd dist; jq -c '.[]' ../pyktx.json | xargs -L 1 curl -O -J; cd.. + - name: Publish distribution 📦 to TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index dffb146955..0000000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2023 Shukant Pal -# SPDX-License-Identifier: Apache-2.0 -name: Publish to PyPI - -on: - workflow_dispatch: - push: - # Trigger on push of release tags. There is no way to limit the trigger - # to a specific branch. A later build step checks for the main branch. - tags: - - 'v[0-9]+\.[0-9]+\.[0-9]+' - - 'v[0-9]+\.[0-9]+\.[0-9]+-*' - -jobs: - pypi: - runs-on: ubuntu-latest - if: endsWith(github.event.base_ref, 'main') - steps: - - name: Download latest release metadata - run: | - curl \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - -o latest.json \ - https://api.github.com/repos/KhronosGroup/KTX-Software/releases/latest - - name: Filter out pyktx- assets - run: | - jq '.assets | map(select(.name | startswith("pyktx-"))) | map(.browser_download_url)' < latest.json > pyktx.json - - name: Create dist directory - run: | - mkdir dist - - name: Download assets - run: | - cd dist; jq -c '.[]' ../pyktx.json | xargs -L 1 curl -O -J; cd.. - - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c942ccb527..c3c09359ed 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -225,7 +225,7 @@ jobs: # is spawned from some parent Powershell so it does not pick up # the changes from the registry. Use Chocolatey's helper to # pull in the changes. - # After import `refreshenv` is an alias for + # After import, `refreshenv` is an alias for # Update-SessionEnvironment. Without the import refreshenv will end # up calling the cmd.exe version, which won't help Powershell, and # Update-SessionEnvironment will not exist. @@ -263,18 +263,20 @@ jobs: path: ${{env.BUILD_DIR}}/KTX-Software-*.exe* - name: Upload pyktx artifacts - if: matrix.options.package == 'YES' && matrix.options.py + if: matrix.options.package == 'YES' && matrix.options.py == 'ON' uses: kittaakos/upload-artifact-as-is@v0 with: path: ${{env.BUILD_DIR}}/interface/python_binding/dist/ - - name: Upload To Release + - name: Upload to Release uses: softprops/action-gh-release@v1 if: matrix.options.package == 'YES' && matrix.toolset == 'CLangCL' && github.event_name == 'push' && github.ref_type == 'tag' with: draft: true prerelease: true - files: ${{env.BUILD_DIR}}/KTX-Software-*.exe* + files: | + ${{env.BUILD_DIR}}/KTX-Software-*.exe* + ${{env.BUILD_DIR}}/interface/python_binding/dist/pyktx-* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index ff627cae65..e26a0c5b00 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ cmake-build-* # Temps used for Windows signing on CI appveyor-tools the_khronos_group_inc.p12 + +# Place for random developer test files. +/testground/ diff --git a/.travis.yml b/.travis.yml index 3f9ef3e425..04d5073d2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -396,11 +396,25 @@ deploy: - provider: script edge: true - script: ruby ci_scripts/github_release.rb -s ${GITHUB_TOKEN} -r ${TRAVIS_REPO_SLUG} -c $REL_DESC_FILE -t ${TRAVIS_TAG} --overwrite true --draft true --prerelease true $BUILD_DIR/KTX-Software-*-* $BUILD_DIR/interface/python_binding/dist/*.whl + # nullglob is to force a null string when there are no *.whl files. + script: ruby ci_scripts/github_release.rb -s ${GITHUB_TOKEN} -r ${TRAVIS_REPO_SLUG} -c $REL_DESC_FILE -t ${TRAVIS_TAG} --overwrite true --draft true --prerelease true $BUILD_DIR/KTX-Software-*-* on: tags: true #branch: master condition: $PACKAGE = "YES" && $TRAVIS_TAG =~ ^v[0-9].* + + # Separate deploy for pyktx because the linux runners use sh not bash + # for the "script" so `shopt -s nullglob; ci_scripts/github_release.rb ...` + # does not work to avoid passing `.../*.whl` to github_release when + # FEATURE_PY not ON. + - provider: script + edge: true + script: ruby ci_scripts/github_release.rb -s ${GITHUB_TOKEN} -r ${TRAVIS_REPO_SLUG} -c $REL_DESC_FILE -t ${TRAVIS_TAG} --overwrite true --draft true --prerelease true $BUILD_DIR/interface/python_binding/dist/*.whl + on: + tags: true + #branch: master + condition: $PACKAGE = "YES" && $TRAVIS_TAG =~ ^v[0-9].* && $FEATURE_PY = "ON" + # --------------------------------------------------------- # vim:ai:ts=4:sts=2:sw=2:expandtab diff --git a/CMakeLists.txt b/CMakeLists.txt index 454c0f04b3..4c17d9cb34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -877,6 +877,7 @@ if(EMSCRIPTEN) "SHELL:-s EXPORT_NAME=LIBKTX" "SHELL:-s EXPORTED_RUNTIME_METHODS=[\'GL\']" "SHELL:-s GL_PREINITIALIZED_CONTEXT=1" + "SHELL:-s GL_ENABLE_GET_PROC_ADDRESS=1" # For Emscripten 3.1.51+ ) set_target_properties( ktx_js PROPERTIES OUTPUT_NAME "libktx") diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f5183971c2..e78257b2db 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -2,8 +2,9 @@ Release Notes ============= -## Version 4.3.0-alpha3 -### New Features +## Version 4.3.0-beta1 +### New Features in Version 4.3.0 +#### Command Line Tools Suite v4.3.0 contains a new suite of command line tools accessed via an umbrella `ktx` command. @@ -11,20 +12,21 @@ v4.3.0 contains a new suite of command line tools accessed via an umbrella `ktx` | :--- | ----------- | ------------------- | | `ktx create` | Create a KTX2 file from various input files | `toktx` | | `ktx extract` | Export selected images from a KTX2 file | - | -| `ktx encode` | Encode a KTX2 file | `ktxsc` | +| `ktx encode` | Encode a KTX2 file to a Basis Universal format | `ktxsc` | | `ktx transcode` | Transcode a KTX2 file | - | | `ktx info` | Prints information about a KTX2 file | `ktxinfo` | | `ktx validate` | Validate a KTX2 file | `ktx2check` | | `ktx help` | Display help information about the ktx tools | - | -Equivalent old tools will be removed in the next release. +Equivalent old tools will be removed in a subsequent release soon. Some features of the old tools are not currently available in the new equivalent. | Old Tool | New Tool | Missing Features | | :------: | :------: | ---------------- | -| `toktx` | `create` | JPEG and NBPM input and scaling/resizing. | -| `ktxsc` | `encode` | ASTC encoding. This can be done in `create`. | +| `toktx` | `create` | JPEG and NBPM input and scaling/resizing of input images. | +| `ktxsc` | `encode` | ASTC encoding of a KTX2 file. This can be done in `create`.
Deflation of a KTX2 file with zlib or zstd.| + The command-line syntax and semantics differ from the old tools including, but not limited to: @@ -43,12 +45,17 @@ The command-line syntax and semantics differ from the old tools including, but n Please refer to the manual pages or use the `--help` command-line option for further details on the options available and associated semantics for each individual command. +#### Python Binding +A Python binding for `libktx` has been added. Applications written in Python can now use `libktx` functions. Huge thanks to @ShukantPal. Please download the appropriate `pyktx` package from Releases as publishing to PyPI is not yet established. + ### Changes * `libktx` has been made much more robust to errors KTX files. - * `libktx` now validates checksums when present in a Zstd data stream. * `libktx` has two new error codes it can return: `KTX_DECOMPRESS_LENGTH_ERROR` and `KTX_DECOMPRESS_CHECKSUM_ERROR`. +* All tools and `libktx` now correctly process on all platforms utf8 file names +with multi-byte code-points. Previously such names did not work on Windows. +* The Vulkan texture uploader can now optionally be used with an extenal memory allocator such as [VulkanMemoryAllocator](https://gpuopen.com/vulkan-memory-allocator/). ### Known Issues @@ -63,6 +70,89 @@ Please refer to the manual pages or use the `--help` command-line option for fur * Neither the Vulkan nor GL loaders support depth/stencil textures. +### Changes since v4.3.0-alpha3 (by part) +### libktx + +* git subrepo push lib/dfdutils (ab9c27707) (@MarkCallow) + +* Reenable build of loadtest apps on Windows arm64 CI (#802) (6c131f75f) (@MarkCallow) + +* Utf-8/unicode support in legacy tools and lib. (#800) (1c5dc9cf6) (@MarkCallow) + +* Do not redefine NOMINMAX (#801) (6dbb24643) (@corporateshark) + +* libktx: update ktxTexture2\_setImageFromStream to allow setting the entire level's data in one call (#794) (88fc7a6e9) (@AlexRouSg) + +* Update dfdutils-included vulkan\_core.h. (#783) (9c223d950) (@MarkCallow) + +* Support for A8 and A1B5G5R5 formats (#785) (eeac6206c) (@aqnuep) + +* Major non-content documentation fixes. (#773) (e6a6a3be9) (@MarkCallow) + +* Fix vendor-specific/tied memory property flag detection (#771) (a10021758) (@toomuchvoltage) + +* Return KTX\_NOT\_FOUND when a GPU proc is not found. (#770) (aeca5e695) (@MarkCallow) + +* Support for external allocators: (#748) (6856fdb0d) (@toomuchvoltage) + +* Fix ktx\_strncasecmp (#741) (1ae04f897) (@VaderY) + +* Use correct counter for indexing sample. (#739) (3153e94e8) (@MarkCallow) + +### Tools + +* Disallow ASTC options when format is not ASTC (#809) (d3ef5ed8b) (@aqnuep) + +* Remove unnecessary nullptr checks. (#807) (072a4eb25) (@MarkCallow) + +* Set tools and tests rpath on Linux. (#804) (928612a71) (@MarkCallow) + +* Utf-8/unicode support in legacy tools and lib. (#800) (1c5dc9cf6) (@MarkCallow) + +* Support building of loadtest apps with locally installed dependencies (#799) (84ee59dd2) (@MarkCallow) + +* Update dfdutils-included vulkan\_core.h. (#783) (9c223d950) (@MarkCallow) + +* Add UTF-8 filename support on Windows to ktxtools (#788) (7b6eab5dc) (@aqnuep) + +* Support for A8 and A1B5G5R5 formats (#785) (eeac6206c) (@aqnuep) + +* KTXwriterScParams support (#779) (f8691ff05) (@aqnuep) + +* Use \-- in doc. to get -- not n-dash in output. (#767) (724790094) (@MarkCallow) + +* Document convert\_primaries option in toktx. (#765) (3049f5b5e) (@MarkCallow) + +* Do target\_type changes only in toktx (#757) (2cf053c19) (@MarkCallow) + +* Add support for fewer components in input files (#755) (adcccf152) (@aqnuep) + +* Fix --convert-primaries (#753) (e437ec45f) (@aqnuep) + +* Fix legacy app input from pipes on Windows. (#749) (3e7fd0af6) (@MarkCallow) + +* Improve output determinism and add internal ktxdiff tool for comparing test outputs (#745) (7f67af7e0) (@VaderY) + +* Add KTX\_WERROR config option (#746) (dab32db90) (@MarkCallow) + +* Fix incorrect index calculations in image conversions (#735) (682f456de) (@VaderY) + +* Color-space and documentation related improvements for ktx create (#732) (8b12216f7) (@VaderY) + + + + + +### Java Wrapper + +* Update dfdutils-included vulkan\_core.h. (#783) (9c223d950) (@MarkCallow) + + + + +## Version 4.3.0-alpha3 + + ### Changes since v4.3.0-alpha2 (by part) ### libktx diff --git a/cmake/version.cmake b/cmake/version.cmake index f9f20015ed..859fd0e43d 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -197,7 +197,7 @@ function( create_version_header dest_path target ) endfunction() function( create_version_file ) - file(WRITE ${PROJECT_BINARY_DIR}/ktx.version "${KTX_VERSION}") + file(WRITE ${PROJECT_BINARY_DIR}/ktx.version "${KTX_VERSION_FULL}") endfunction() # vim:ai:ts=4:sts=4:sw=2:expandtab:textwidth=70 diff --git a/interface/python_binding/CMakeLists.txt b/interface/python_binding/CMakeLists.txt index 85d5edf110..b2c4051434 100644 --- a/interface/python_binding/CMakeLists.txt +++ b/interface/python_binding/CMakeLists.txt @@ -2,8 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 find_package (Python3 COMPONENTS Interpreter) -file(GLOB pyktx_py_src ${CMAKE_SOURCE_DIR}/interface/python_binding/pyktx/*.py) -list(TRANSFORM pyktx_py_src REPLACE "${CMAKE_SOURCE_DIR}/interface/python_binding/pyktx/" "${KTX_BUILD_DIR}/interface/python_binding/docs/pyktx." OUTPUT_VARIABLE pyktx_py_rst_filenames) +set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/interface/python_binding) +file(GLOB pyktx_py_src ${SOURCE_DIR}/pyktx/*.py) +list(TRANSFORM pyktx_py_src REPLACE "${SOURCE_DIR}/pyktx/" "${KTX_BUILD_DIR}/interface/python_binding/docs/pyktx." OUTPUT_VARIABLE pyktx_py_rst_filenames) list(TRANSFORM pyktx_py_rst_filenames REPLACE ".py$" ".rst" OUTPUT_VARIABLE pyktx_py_rst) set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) @@ -28,7 +29,7 @@ add_custom_target( pyktx-deps ALL add_custom_command( TARGET pyktx-deps COMMAND - ${PYTHON_EXECUTABLE} -m pip install --no-warn-script-location -r ${CMAKE_SOURCE_DIR}/interface/python_binding/requirements.txt + ${PYTHON_EXECUTABLE} -m pip install --no-warn-script-location -r ${SOURCE_DIR}/requirements.txt COMMENT "Install dependencies for pyktx build" ) @@ -37,7 +38,7 @@ add_custom_target( pyktx ALL DEPENDS ktx WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR}/interface/python_binding + ${SOURCE_DIR} COMMENT "Python distributions" ) @@ -51,15 +52,29 @@ add_custom_command( COMMENT "Clean up pyktx build artifacts" WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR}/interface/python_binding + ${SOURCE_DIR} ) +# Normalize version number as the python toolchain does. Tweaks are reduced +# to a, b or rc immediately following the patch number. We do because names +# of the BYPRODUCTS in the following custom_command need to match the +# names with normalized version numbers the python tools would produce. +function(normalize_version _var fullver) + string(REPLACE -alpha a normalized ${fullver}) + string(REPLACE -beta b normalized ${normalized}) + set(${_var} "${normalized}" PARENT_SCOPE) +endfunction() + +normalize_version(KTX_VERSION_NORMALIZED ${KTX_VERSION_FULL}) +set(DIST_DIR ${KTX_BUILD_DIR}/interface/python_binding/dist) +set(SOURCE_ARCHIVE_BASENAME ${DIST_DIR}/pyktx-${KTX_VERSION_NORMALIZED}) + add_custom_command( TARGET pyktx BYPRODUCTS - ${KTX_BUILD_DIR}/interface/python_binding/dist/pyktx-${KTX_VERSION}.tar.gz - ${KTX_BUILD_DIR}/interface/python_binding/dist/pyktx-${KTX_VERSION}.zip + ${SOURCE_ARCHIVE_BASENAME}.tar.gz + ${SOURCE_ARCHIVE_BASENAME}.zip DEPENDS ${pyktx_py_src} pyktx/ktx_texture.h @@ -72,10 +87,10 @@ add_custom_command( ${CMAKE_COMMAND} -E env LIBKTX_INCLUDE_DIR=${CMAKE_SOURCE_DIR}/include LIBKTX_LIB_DIR=${LIBKTX_LIB_DIR} - LIBKTX_VERSION=${PROJECT_VERSION} - ${PYTHON_EXECUTABLE} -m build --sdist --outdir ${KTX_BUILD_DIR}/interface/python_binding/dist + LIBKTX_VERSION=${KTX_VERSION_NORMALIZED} + ${PYTHON_EXECUTABLE} -m build --sdist --outdir ${DIST_DIR} WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR}/interface/python_binding + ${SOURCE_DIR} ) add_custom_command( @@ -87,18 +102,18 @@ add_custom_command( ${CMAKE_COMMAND} -E env LIBKTX_INCLUDE_DIR=${CMAKE_SOURCE_DIR}/include LIBKTX_LIB_DIR=${LIBKTX_LIB_DIR} - LIBKTX_VERSION=${PROJECT_VERSION} - ${PYTHON_EXECUTABLE} -m build --wheel --outdir ${KTX_BUILD_DIR}/interface/python_binding/dist + LIBKTX_VERSION=${KTX_VERSION_NORMALIZED} + ${PYTHON_EXECUTABLE} -m build --wheel --outdir ${DIST_DIR} WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR}/interface/python_binding + ${SOURCE_DIR} ) set(pyktx_egg_info - ${CMAKE_SOURCE_DIR}/interface/python_binding/pyktx.egg-info/dependency_links.txt - ${CMAKE_SOURCE_DIR}/interface/python_binding/pyktx.egg-info/PKG-INFO - ${CMAKE_SOURCE_DIR}/interface/python_binding/pyktx.egg-info/requires.txt - ${CMAKE_SOURCE_DIR}/interface/python_binding/pyktx.egg-info/SOURCES.txt - ${CMAKE_SOURCE_DIR}/interface/python_binding/pyktx.egg-info/top_level.txt) + ${SOURCE_DIR}/pyktx.egg-info/dependency_links.txt + ${SOURCE_DIR}/pyktx.egg-info/PKG-INFO + ${SOURCE_DIR}/pyktx.egg-info/requires.txt + ${SOURCE_DIR}/pyktx.egg-info/SOURCES.txt + ${SOURCE_DIR}/pyktx.egg-info/top_level.txt) add_test(NAME pyktx COMMAND @@ -110,7 +125,7 @@ add_test(NAME pyktx LD_LIBRARY_PATH=${LIBKTX_LIB_DIR}:$ENV{LD_LIBRARY_PATH} ${PYTHON_EXECUTABLE} buildscript.py WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR}/interface/python_binding + ${SOURCE_DIR} ) if(KTX_FEATURE_DOC) @@ -152,6 +167,6 @@ if(KTX_FEATURE_DOC) SPHINXBUILD=${PYTHON_PATH}\ -m\ sphinx make SOURCEDIR="${KTX_BUILD_DIR}/interface/python_binding" BUILDDIR="${KTX_BUILD_DIR}/interface/python_binding/docs/html/pyktx" html WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR}/interface/python_binding + ${SOURCE_DIR} ) -endif() \ No newline at end of file +endif() diff --git a/interface/python_binding/README.md b/interface/python_binding/README.md index a0b931b2ce..f3006142f7 100644 --- a/interface/python_binding/README.md +++ b/interface/python_binding/README.md @@ -31,5 +31,5 @@ If you are on a POSIX system (macOS or Linux), make sure libktx is on your `DYLD > ``` > ld: warning: ignoring file '/usr/local/lib/libktx.4.3.0.dylib': found architecture 'arm64', required architecture 'x86_64' > ``` -> -> 'arm64' and 'x86_64' may be reversed depending on the build machine architecture. This happens because libktx is not a universal binary so only supports the current platform architecture. The message can be ignored. \ No newline at end of file +> +> 'arm64' and 'x86_64' may be reversed depending on the build machine architecture. This happens because libktx is not a universal binary so only supports the current platform architecture. The message can be ignored. diff --git a/interface/python_binding/buildscript.py b/interface/python_binding/buildscript.py index 9b7c8e29e3..fb823a0952 100644 --- a/interface/python_binding/buildscript.py +++ b/interface/python_binding/buildscript.py @@ -34,7 +34,7 @@ ffibuilder.cdef( """ void free(void *ptr); - + typedef struct ktxTexture ktxTexture; typedef struct ktxTextureCreateInfo ktxTextureCreateInfo; typedef struct ktxTexture1 ktxTexture1; @@ -45,13 +45,13 @@ uint32_t error; ktxTexture* texture; } ktxTextureMixed; - + typedef struct { void *bytes; size_t size; int error; } ktxWriteToMemory; - + typedef struct { size_t offset; int error; @@ -80,7 +80,7 @@ int ktxHashList_AddKVPair(ktxHashList *, const char *key, unsigned int valueLen, const void *value); int ktxHashList_DeleteKVPair(ktxHashList *, const char *key); ktxHashListEntry *ktxHashList_Next(void *entry); - + // Glue code ktxTextureMixed PY_ktxTexture_CreateFromNamedFile(const char* const filename, uint32_t create_flags); diff --git a/interface/python_binding/pyktx/ktx_astc_params.py b/interface/python_binding/pyktx/ktx_astc_params.py index 46c760a2dd..fef0a98fb3 100644 --- a/interface/python_binding/pyktx/ktx_astc_params.py +++ b/interface/python_binding/pyktx/ktx_astc_params.py @@ -25,7 +25,7 @@ class KtxAstcParams: mode: KtxPackAstcEncoderMode = KtxPackAstcEncoderMode.DEFAULT """Can be {ldr/hdr} from astcenc""" - + quality_level: int = KtxPackAstcQualityLevels.FASTEST """astcenc supports -fastest, -fast, -medium, -thorough, -exhaustive""" @@ -41,16 +41,16 @@ class KtxAstcParams: perceptual: bool = False """ The codec should optimize for perceptual error, instead of direct RMS error. - + This aims to improves perceived image quality, but typically lowers the measured PSNR score. Perceptual methods are currently only available for normal maps and RGB color data. """ - + input_swizzle: bytes = bytes([0, 0, 0, 0]) """ A swizzle to provide as input to astcenc. - + It must match the regular expression /^[rgba01]{4}$/. """ diff --git a/interface/python_binding/pyktx/ktx_basis_params.py b/interface/python_binding/pyktx/ktx_basis_params.py index 64e1fe4f43..1a883f90c8 100644 --- a/interface/python_binding/pyktx/ktx_basis_params.py +++ b/interface/python_binding/pyktx/ktx_basis_params.py @@ -23,8 +23,8 @@ class KtxBasisParams: compression_level: int = 0 """ - Encoding speed vs. quality tradeoff. Range is [0,5]. - + Encoding speed vs. quality tradeoff. Range is [0,5]. + Higher values are slower, but give higher quality. There is no default. Callers must explicitly set this value. Callers can use KTX_ETC1S_DEFAULT_COMPRESSION_LEVEL as a default value. Currently this is 2. @@ -35,13 +35,13 @@ class KtxBasisParams: Compression quality. Range is [1,255]. Lower gives better compression/lower quality/faster. - Higher gives less compression/higher quality/slower. + Higher gives less compression/higher quality/slower. This automatically determines values for max_endpoints, max_selectors, endpoint_rdo_threshold, and selector_rdo_threshold for the target quality level. Setting these parameters overrides the values determined by quality_level which defaults to 128 if neither it nor both of max_endpoints and max_selectors have been set. - + Both of max_endpoints and max_selectors must be set for them to have any effect. quality_level will only determine values for endpoint_rdo_threshold and selector_rdo_threshold when its value exceeds 128, otherwise their defaults will be used. @@ -58,7 +58,7 @@ class KtxBasisParams: endpoint_rdo_threshold: int = 0 """ Set endpoint RDO quality threshold. The default is 1.25. - + Lower is higher quality but less quality per output bit (try [1.0,3.0]. This will override the value chosen by quality_level. """ @@ -66,15 +66,15 @@ class KtxBasisParams: max_selectors: int = 0 """ Manually set the max number of color selector clusters. Range is [1,16128]. - + Default is 0, unset. If this is set, max_endpoints must also be set, otherwise the value will be ignored. """ - + selector_rdo_threshold: int = 0 """ Set selector RDO quality threshold. The default is 1.5. - + Lower is higher quality but less quality per output bit (try [1.0,3.0]). This will override the value chosen by @c qualityLevel. """ @@ -82,7 +82,7 @@ class KtxBasisParams: input_swizzle: bytes = bytes(4) """ A swizzle to apply before encoding. - + It must match the regular expression /^[rgba01]{4}$/. If both this and pre_swizzle are specified KtxTexture2.compressBasis() will raise INVALID_OPERATION. """ @@ -98,7 +98,7 @@ class KtxBasisParams: pre_swizzle: bool = False """ If the texture has swizzle metadata, apply it before compressing. - + Swizzling, like rabb may yield drastically different error metrics if done after supercompression. """ @@ -106,7 +106,7 @@ class KtxBasisParams: separate_rg_to_rgb_a: bool = False """ This was and is a no-op. - + 2-component inputs have always been automatically separated using an "rrrg" input_swizzle. """ @@ -114,21 +114,21 @@ class KtxBasisParams: no_endpoint_rdo: bool = False """ Disable endpoint rate distortion optimizations. - + Slightly faster, less noisy output, but lower quality per output bit. """ no_selector_rdo: bool = False """ Disable selector rate distortion optimizations. - + Slightly faster, less noisy output, but lower quality per output bit. """ uastc_flags: int = KtxPackUastcFlagBits.FASTEST """ A set of KtxPackUastcFlagBits controlling UASTC encoding. - + The most important value is the level given in the least-significant 4 bits which selects a speed vs quality tradeoff. """ @@ -139,7 +139,7 @@ class KtxBasisParams: uastc_rdo_quality_scalar: float = 0. """ UASTC RDO quality scalar (lambda). - + Lower values yield higher quality/larger LZ compressed files, higher values yield lower quality/smaller LZ compressed files. A good range to try is [.2,4]. Full range is [.001,50.0]. Default is 1.0. @@ -169,4 +169,4 @@ class KtxBasisParams: """Do not favor simpler UASTC modes in RDO mode.""" uastc_rdo_no_multithreading: bool = False - """Disable RDO multithreading (slightly higher compression, deterministic).""" \ No newline at end of file + """Disable RDO multithreading (slightly higher compression, deterministic).""" diff --git a/interface/python_binding/pyktx/ktx_error_code.py b/interface/python_binding/pyktx/ktx_error_code.py index a9d340afce..d70c9fc54e 100644 --- a/interface/python_binding/pyktx/ktx_error_code.py +++ b/interface/python_binding/pyktx/ktx_error_code.py @@ -45,7 +45,7 @@ class KtxErrorCode(IntEnum): NOT_FOUND = 12 """Requested key was not found""" - + OUT_OF_MEMORY = 13 """Not enough memory to complete the operation.""" diff --git a/interface/python_binding/pyktx/ktx_pack_astc_encoder_mode.py b/interface/python_binding/pyktx/ktx_pack_astc_encoder_mode.py index c3435d6064..e306a6c154 100644 --- a/interface/python_binding/pyktx/ktx_pack_astc_encoder_mode.py +++ b/interface/python_binding/pyktx/ktx_pack_astc_encoder_mode.py @@ -7,7 +7,7 @@ class KtxPackAstcEncoderMode(IntEnum): """ Options specifying ASTC encoder profile mode. - + This and function is used later to derive the profile. """ diff --git a/interface/python_binding/pyktx/ktx_pack_uastc_flag_bits.py b/interface/python_binding/pyktx/ktx_pack_uastc_flag_bits.py index ceea6bea5f..971b8c14c9 100644 --- a/interface/python_binding/pyktx/ktx_pack_uastc_flag_bits.py +++ b/interface/python_binding/pyktx/ktx_pack_uastc_flag_bits.py @@ -30,7 +30,7 @@ class KtxPackUastcFlagBits(IntEnum): FAVOR_UASTC_ERROR = 8 """Optimize for lowest UASTC error.""" - + FAVOR_BC7_ERROR = 16 """Optimize for lowest BC7 error.""" diff --git a/interface/python_binding/pyktx/ktx_texture.py b/interface/python_binding/pyktx/ktx_texture.py index 8b531ae142..2da6b15c52 100644 --- a/interface/python_binding/pyktx/ktx_texture.py +++ b/interface/python_binding/pyktx/ktx_texture.py @@ -107,7 +107,7 @@ def element_size(self) -> int: def kv_data_raw(self) -> Optional[c_buffer]: """ The raw KV data buffer. - + This is available only if RAW_KVDATA_BIT was used in create-flag bits. """ @@ -150,7 +150,7 @@ def row_pitch(self, level: int) -> int: if necessary. For all currently known compressed formats padding will not be necessary. """ - + return lib.ktxTexture_GetRowPitch(self._ptr, level) def image_size(self, level: int) -> int: diff --git a/interface/python_binding/pyktx/ktx_texture1.py b/interface/python_binding/pyktx/ktx_texture1.py index e3182c918c..51f8de91e4 100644 --- a/interface/python_binding/pyktx/ktx_texture1.py +++ b/interface/python_binding/pyktx/ktx_texture1.py @@ -56,7 +56,7 @@ def create_from_named_file(filename: str, create_flags: int = KtxTextureCreateFl def gl_format(self) -> int: """ Format of the texture data, e.g. GL_RGB. - + You can find all OpenGL formats here: """ return lib.PY_ktxTexture1_get_glFormat(self._ptr) @@ -85,7 +85,7 @@ def gl_baseinternalformat(self) -> int: def gl_type(self) -> int: """ Type of the texture data, e.g, GL_UNSIGNED_BYTE. - + You can find all OpenGL data types here: """ return lib.PY_ktxTexture1_get_glType(self._ptr) diff --git a/interface/python_binding/pyktx/ktx_texture2.py b/interface/python_binding/pyktx/ktx_texture2.py index 2619d16a00..c2a6760c00 100644 --- a/interface/python_binding/pyktx/ktx_texture2.py +++ b/interface/python_binding/pyktx/ktx_texture2.py @@ -91,7 +91,7 @@ def needs_transcoding(self) -> bool: def compress_astc(self, params: Union[int, KtxAstcParams]) -> None: """ Encode and compress a ktx texture with uncompressed images to ASTC. - + The images are either encoded to ASTC block-compressed format. The encoded images replace the original images and the texture's fields including the dfd are modified to reflect the new state. @@ -197,7 +197,7 @@ def transcode_basis(self, output_format: KtxTranscodeFmt, transcode_flags: int = PVRTC2_4_RGB, PVRTC2_4_RGBA, ASTC_4x4_RGBA, ETC2_EAC_R11, ETC2_EAC_RG11, ETC and BC1_OR_3. ETC automatically selects between ETC1_RGB and ETC2_RGBA according to whether an alpha - channel is available. BC1_OR_3 does likewise between BC1_RGB and BC3_RGBA. Note that if + channel is available. BC1_OR_3 does likewise between BC1_RGB and BC3_RGBA. Note that if PVRTC1_4_RGBA or PVRTC2_4_RGBA is specified and there is no alpha channel PVRTC1_4_RGB or PVRTC2_4_RGB respectively will be selected. diff --git a/lib/libktx_mainpage.md b/lib/libktx_mainpage.md index 135104ad10..3e37f01597 100644 --- a/lib/libktx_mainpage.md +++ b/lib/libktx_mainpage.md @@ -86,7 +86,7 @@ result = ktxTexture_CreateFromNamedFile("mytex3d.ktx", &kTexture); glGenTextures(1, &texture); // Optional. GLUpload can generate a texture. result = ktxTexture_GLUpload(kTexture, &texture, &target, &glerror); -ktxTexture_Destroy(texture); +ktxTexture_Destroy(kTexture); // ... // GL rendering using the texture // ... diff --git a/tests/loadtests/CMakeLists.txt b/tests/loadtests/CMakeLists.txt index 28f85dd6b7..59188a0d87 100644 --- a/tests/loadtests/CMakeLists.txt +++ b/tests/loadtests/CMakeLists.txt @@ -18,6 +18,14 @@ if(NOT IOS) find_package(OpenGL REQUIRED) endif() if(KTX_LOADTEST_APPS_USE_LOCAL_DEPENDENCIES) + # When using a local SDL2 package installed by brew on macOS, at + # least, a mysterious .../lib/$ appears in the library + # search paths in the generated project. I've been unable to find + # this in the {INTERFACE,}_LINK_DIRECTORIES properties in any of + # the SDL2::SDL2 or {gl3,vk}loadtests targets. My guess is the Xcode + # generator is adding it. It leads to a harmless warning during + # build, harmless because the libraries are referenced by full paths + # and the .../lib directory is in the search path of SDL2::SDL2. find_package(SDL2 REQUIRED) if(NOT EMSCRIPTEN) # Tests that require assimp are omitted from loadtests diff --git a/tools/imageio/imageinput.cc b/tools/imageio/imageinput.cc index ae46e98893..2541c064e9 100644 --- a/tools/imageio/imageinput.cc +++ b/tools/imageio/imageinput.cc @@ -312,12 +312,16 @@ ImageInput::readImage(void* pBuffer, size_t bufferByteCount, uint32_t subimage, uint32_t miplevel, const FormatDescriptor& format) { + const auto& targetFormat = format.isUnknown() ? spec().format() : format; + size_t outScanlineByteCount + = targetFormat.basic.bytesPlane0 * spec().width(); + uint8_t* pDst = static_cast(pBuffer); for (uint32_t y = 0; y < spec().height(); y++) { readScanline(pDst, bufferByteCount, - y, 0, subimage, miplevel, format); - pDst += spec().scanlineByteCount(); - bufferByteCount -= spec().scanlineByteCount(); + y, 0, subimage, miplevel, targetFormat); + pDst += outScanlineByteCount; + bufferByteCount -= outScanlineByteCount; } } diff --git a/tools/imageio/jpg.imageio/jpginput.cc b/tools/imageio/jpg.imageio/jpginput.cc index c08ee04f90..eebb243f73 100644 --- a/tools/imageio/jpg.imageio/jpginput.cc +++ b/tools/imageio/jpg.imageio/jpginput.cc @@ -362,13 +362,16 @@ void JpegInput::readImage(void* bufferOut, size_t bufferByteCount, uint subimage, uint miplevel, const FormatDescriptor& format) { - if (bufferByteCount < spec().imageByteCount()) + const auto& targetFormat = format.isUnknown() ? spec().format() : format; + size_t outImageByteCount + = targetFormat.basic.bytesPlane0 * spec().width() * spec().height(); + if (bufferByteCount < outImageByteCount) throw buffer_too_small(); pJd->begin_decoding(); decodingBegun = true; ImageInput::readImage(bufferOut, bufferByteCount, subimage, miplevel, - format); + targetFormat); } diff --git a/tools/ktxtools_mainpage.md b/tools/ktxtools_mainpage.md index d21e8b3bcc..3a6a8588bc 100644 --- a/tools/ktxtools_mainpage.md +++ b/tools/ktxtools_mainpage.md @@ -23,14 +23,14 @@ ktx Overview | @ref ktx_validate | Validate a KTX2 file | `ktx2check` | | @ref ktx_help | Display help information about the ktx tools | - | -Equivalent old tools are deprecated and will be removed in the near future. +Equivalent old tools are deprecated and will be removed soon. -Some features of old tools are not currently available in their new equivalent. +Some features of old tools are not currently available in the new equivalent. | Old Tool | New Tool | Missing Features | | :------: | :------: | ---------------- | -| @ref toktx | @ref ktx_create "create" | JPEG and NBPM input and scaling/resizing. | -| @ref ktxsc | @ref ktx_encode "encode" | ASTC encoding. This can be done in `create`. | +| @ref toktx | @ref ktx_create "create" | JPEG and NBPM input and scaling/resizing of input images. | +| @ref ktxsc | @ref ktx_encode "encode" | ASTC encoding. This can be done in `create`.
Deflation of a KTX2 file with zlib or zstd.| The command-line syntax and semantics differ from the old tools including, but not limited to: