Skip to content

Commit 562509c

Browse files
aqnuepMarkCallow
andauthored
Add JS bindings for full libktx (#874)
The PR makes the following minor API changes to libktx: * Adds `ktxTexture_GetLevelSize` function. * Makes the parameters to `ktxTexture[12]_Create` `const`. * Adds `ktxTexture2_{GetPrimaries_e, SetOETF and SetPrimaries}` functions. It adds the following functions to the JS binding while modernizing and greatly improving the binding code: * A constructor equivalent to `ktxTexture_Create`. * `createCopy` * `findKeyValue` * `getDataSize` * `getOETF` * `getPrimaries` * `getImage` for retrieving an image from the texture. Fixes #288. * `setImageFromMemory` * `compressAstc` * `compressBasis` * `deflateZstd` * `deflateZLIB` * `addKVPairString` and `addKVPairByte` * `deleteKVPair` * `setOETF` * `setPrimaries` * `writeToMemory` It makes available two bindings. First is a read-only binding, `libktx_read.js` which has the previously available functions plus `findKeyValue`, `getDataSize`, `getOETF`, `getPrimaries` and `getImage`. The second, using the original name `libktx.js`, has functions for creating new KTX texture objects and writing them to files. The JS `ktxTexture` class has been renamed `texture` as typical usage is with an Emscripten module instance name of `ktx` and `new ktx.ktxTexture()` looks weird. Newly added classes do not have `ktx` prefixes. Compared to the Phasmatic bindings it: * Removes `compressBasisU` which was bundling calls to `ktxTexture2_CompressBasisEx`, `ktxTexture2_DeflateZstd`, `ktxTexture2_WriteToMemory` and `ktxHashList_addKVPair`. Instead each function now has a binding and can be called by the JS client. * Removes `createFromBuffer` which was using parameters passed from Javascript to determine the VKFormat and size of the texture then creating it with `ktxTexture2_Create` and finally loading an image from a passed ArrayBufferView into the texture via `ktxTexture_SetImageFromMemory`. Instead a `ktxCreateInfo` can be initialized in the JS code which can call `new ktxTexture` to create the texture then call `setImageFromMemory` to put the image into the texture object. --------- Co-authored-by: Mark Callow <[email protected]>
1 parent 7fb646c commit 562509c

26 files changed

+3089
-321
lines changed

.reuse/dep5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ Files: tests/webgl/libktx-gltf/*
170170
Copyright: 2020 Don McCurdy, Austin Eng, Shrek Shao, and Mark Callow
171171
License: Apache-2.0
172172

173-
Files: tests/webgl/libktx-webgl/*
173+
Files: tests/webgl/libktx-webgl/* tests/webgl/libktx-read-webgl/*
174174
Copyright: 2020 Mark Callow
175175
License: Apache-2.0
176176

BUILDING.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,10 @@ cmake --build build-web
290290
291291
To include the load test application into the build add `-DKTX_FEATURE_LOADTEST_APPS=ON` to either of the above configuration steps.
292292
293-
Web builds create two additional targets:
293+
Web builds create three additional targets:
294294
295-
- `ktx_js`, (libktx javascript wrapper)
295+
- `ktx_js` (libktx javascript wrapper - with write support)
296+
- `ktx_js_read` (libktx_read javascript wrapper - read-only)
296297
- `msc_basis_transcoder_js` (transcoder wrapper)
297298
298299
> **Note:** The libktx wrapper does not use the transcoder wrapper. It directly uses the underlying c++ transcoder.
@@ -490,8 +491,10 @@ The following files related to the the VkFormat enum are generated from `vulkan_
490491
- lib/vkformat_typesize.c
491492
- lib/dfd/dfd2vk.inl
492493
- lib/dfd/vk2dfd.inl
493-
- interface/java_binding/src/main/java/org/khronos/ktxVkFormat.java
494+
- interface/java\_binding/src/main/java/org/khronos/ktxVkFormat.java
494495
- interface/python\_binding/pyktx/vk\_format.py
496+
- interface/js\_binding/vk\_format.inl
497+
495498
496499
The following files are generated from the mapping database in the KTX-Specification repo by `generate_format_switches.rb`:
497500

CMakeLists.txt

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -911,19 +911,38 @@ if(EMSCRIPTEN)
911911
set(
912912
KTX_EMC_LINK_FLAGS
913913
--bind
914+
--pre-js ${CMAKE_CURRENT_SOURCE_DIR}/interface/js_binding/class_compat.js
915+
--extern-post-js ${CMAKE_CURRENT_SOURCE_DIR}/interface/js_binding/module_create_compat.js
914916
"SHELL:-s MODULARIZE=1"
917+
"SHELL:-s EXPORTED_RUNTIME_METHODS=[\'GL\']"
918+
"SHELL:-s GL_PREINITIALIZED_CONTEXT=1"
919+
)
920+
921+
set(
922+
KTX_JS_COMMON_SOURCE
923+
interface/js_binding/ktx_wrapper.cpp
924+
interface/js_binding/class_compat.js
925+
interface/js_binding/module_create_compat.js
915926
)
916927

917-
add_executable( ktx_js interface/js_binding/ktx_wrapper.cpp )
918-
target_link_libraries( ktx_js ktx_read )
919-
target_include_directories( ktx_js PRIVATE $<TARGET_PROPERTY:ktx_read,INTERFACE_INCLUDE_DIRECTORIES> )
928+
add_executable( ktx_js
929+
${KTX_JS_COMMON_SOURCE}
930+
interface/js_binding/vk_format.inl
931+
)
932+
target_compile_definitions(ktx_js PUBLIC KTX_FEATURE_WRITE)
933+
target_link_libraries( ktx_js ktx )
934+
target_include_directories(
935+
ktx_js
936+
PRIVATE
937+
${CMAKE_CURRENT_SOURCE_DIR}/other_include
938+
${CMAKE_CURRENT_SOURCE_DIR}/lib
939+
$<TARGET_PROPERTY:ktx,INTERFACE_INCLUDE_DIRECTORIES>
940+
)
920941
target_link_options(
921942
ktx_js
922943
PUBLIC
923944
${KTX_EMC_LINK_FLAGS}
924-
"SHELL:-s EXPORT_NAME=LIBKTX"
925-
"SHELL:-s EXPORTED_RUNTIME_METHODS=[\'GL\']"
926-
"SHELL:-s GL_PREINITIALIZED_CONTEXT=1"
945+
"SHELL:-s EXPORT_NAME=createKtxModule"
927946
)
928947
set_target_properties( ktx_js PROPERTIES OUTPUT_NAME "libktx")
929948

@@ -945,6 +964,43 @@ if(EMSCRIPTEN)
945964
COMPONENT ktx_js
946965
)
947966

967+
add_executable( ktx_js_read
968+
${KTX_JS_COMMON_SOURCE}
969+
)
970+
target_link_libraries( ktx_js_read ktx_read )
971+
target_include_directories(
972+
ktx_js_read
973+
PRIVATE
974+
${CMAKE_CURRENT_SOURCE_DIR}/other_include
975+
${CMAKE_CURRENT_SOURCE_DIR}/lib
976+
$<TARGET_PROPERTY:ktx_read,INTERFACE_INCLUDE_DIRECTORIES>
977+
)
978+
target_link_options(
979+
ktx_js_read
980+
PUBLIC
981+
${KTX_EMC_LINK_FLAGS}
982+
"SHELL:-s EXPORT_NAME=createKtxReadModule"
983+
)
984+
set_target_properties( ktx_js_read PROPERTIES OUTPUT_NAME "libktx_read")
985+
986+
add_custom_command(
987+
TARGET ktx_js_read
988+
POST_BUILD
989+
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:ktx_js_read>/$<TARGET_FILE_PREFIX:ktx_js_read>$<TARGET_FILE_BASE_NAME:ktx_js_read>.js" "${PROJECT_SOURCE_DIR}/tests/webgl"
990+
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:ktx_js_read>/$<TARGET_FILE_PREFIX:ktx_js_read>$<TARGET_FILE_BASE_NAME:ktx_js_read>.wasm" "${PROJECT_SOURCE_DIR}/tests/webgl"
991+
COMMENT "Copy libktx_read.js and libktx_read.wasm to tests/webgl"
992+
)
993+
994+
install(TARGETS ktx_js_read
995+
RUNTIME
996+
DESTINATION .
997+
COMPONENT ktx_js_read
998+
)
999+
install(FILES ${CMAKE_BINARY_DIR}/libktx_read.wasm
1000+
DESTINATION .
1001+
COMPONENT ktx_js_read
1002+
)
1003+
9481004
add_executable( msc_basis_transcoder_js interface/js_binding/transcoder_wrapper.cpp )
9491005
target_link_libraries( msc_basis_transcoder_js ktx_read )
9501006
target_include_directories( msc_basis_transcoder_js
@@ -1354,6 +1410,7 @@ elseif(WIN32)
13541410
elseif(EMSCRIPTEN)
13551411
set(CPACK_GENERATOR ZIP)
13561412
set(CPACK_ARCHIVE_KTX_JS_FILE_NAME "${CMAKE_PROJECT_NAME}-${KTX_VERSION_FULL}-Web-libktx")
1413+
set(CPACK_ARCHIVE_KTX_JS_READ_FILE_NAME "${CMAKE_PROJECT_NAME}-${KTX_VERSION_FULL}-Web-libktx_read")
13571414
set(CPACK_ARCHIVE_MSC_BASIS_TRANSCODER_JS_FILE_NAME "${CMAKE_PROJECT_NAME}-${KTX_VERSION_FULL}-Web-msc_basis_transcoder")
13581415

13591416
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
@@ -1405,6 +1462,7 @@ cpack_add_component_group(LoadTestApps
14051462
if(EMSCRIPTEN)
14061463
set(CPACK_COMPONENTS_ALL
14071464
ktx_js
1465+
ktx_js_read
14081466
msc_basis_transcoder_js
14091467
)
14101468
else()

cmake/mkvk.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ list(APPEND mkvkformatfiles_input
8080
scripts/mkvkformatfiles)
8181
list(APPEND mkvkformatfiles_output
8282
"${PROJECT_SOURCE_DIR}/interface/java_binding/src/main/java/org/khronos/ktx/VkFormat.java"
83+
"${PROJECT_SOURCE_DIR}/interface/js_binding/vk_format.inl"
8384
"${PROJECT_SOURCE_DIR}/interface/python_binding/pyktx/vk_format.py"
8485
"${PROJECT_SOURCE_DIR}/lib/vkformat_enum.h"
8586
"${PROJECT_SOURCE_DIR}/lib/vkformat_typesize.c"

include/ktx.h

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ typedef ktx_size_t
455455
(KTX_APIENTRY* PFNKTEXGETDATASIZEUNCOMPRESSED)(ktxTexture* This);
456456
typedef ktx_size_t
457457
(KTX_APIENTRY* PFNKTEXGETIMAGESIZE)(ktxTexture* This, ktx_uint32_t level);
458+
typedef ktx_size_t
459+
(KTX_APIENTRY* PFNKTEXGETLEVELSIZE)(ktxTexture* This, ktx_uint32_t level);
458460
typedef KTX_error_code
459461
(KTX_APIENTRY* PFNKTEXITERATELEVELS)(ktxTexture* This, PFNKTXITERCB iterCb,
460462
void* userdata);
@@ -506,6 +508,7 @@ typedef KTX_error_code
506508
PFNKTEXGETIMAGEOFFSET GetImageOffset;
507509
PFNKTEXGETDATASIZEUNCOMPRESSED GetDataSizeUncompressed;
508510
PFNKTEXGETIMAGESIZE GetImageSize;
511+
PFNKTEXGETLEVELSIZE GetLevelSize;
509512
PFNKTEXITERATELEVELS IterateLevels;
510513
PFNKTEXITERATELOADLEVELFACES IterateLoadLevelFaces;
511514
PFNKTEXNEEDSTRANSCODING NeedsTranscoding;
@@ -557,6 +560,14 @@ typedef KTX_error_code
557560
#define ktxTexture_GetImageSize(This, level) \
558561
(This)->vtbl->GetImageSize(This, level)
559562

563+
/**
564+
* @~English
565+
* @brief Helper for calling the GetImageSize virtual method of a ktxTexture.
566+
* @copydoc ktxTexture2.ktxTexture2_GetImageSize
567+
*/
568+
#define ktxTexture_GetLevelSize(This, level) \
569+
(This)->vtbl->GetLevelSize(This, level)
570+
560571
/**
561572
* @~English
562573
* @brief Helper for calling the IterateLevels virtual method of a ktxTexture.
@@ -985,7 +996,7 @@ ktxTexture_IterateLevelFaces(ktxTexture* This, PFNKTXITERCB iterCb,
985996
* Create a new ktxTexture1.
986997
*/
987998
KTX_API KTX_error_code KTX_APIENTRY
988-
ktxTexture1_Create(ktxTextureCreateInfo* createInfo,
999+
ktxTexture1_Create(const ktxTextureCreateInfo* const createInfo,
9891000
ktxTextureCreateStorageEnum storageAllocation,
9901001
ktxTexture1** newTex);
9911002

@@ -1046,7 +1057,7 @@ ktxTexture1_WriteKTX2ToStream(ktxTexture1* This, ktxStream *dststr);
10461057
* Create a new ktxTexture2.
10471058
*/
10481059
KTX_API KTX_error_code KTX_APIENTRY
1049-
ktxTexture2_Create(ktxTextureCreateInfo* createInfo,
1060+
ktxTexture2_Create(const ktxTextureCreateInfo* const createInfo,
10501061
ktxTextureCreateStorageEnum storageAllocation,
10511062
ktxTexture2** newTex);
10521063

@@ -1111,9 +1122,18 @@ ktxTexture2_GetColorModel_e(ktxTexture2* This);
11111122
KTX_API ktx_bool_t KTX_APIENTRY
11121123
ktxTexture2_GetPremultipliedAlpha(ktxTexture2* This);
11131124

1125+
KTX_API khr_df_primaries_e KTX_APIENTRY
1126+
ktxTexture2_GetPrimaries_e(ktxTexture2* This);
1127+
11141128
KTX_API ktx_bool_t KTX_APIENTRY
11151129
ktxTexture2_NeedsTranscoding(ktxTexture2* This);
11161130

1131+
KTX_API ktx_error_code_e KTX_APIENTRY
1132+
ktxTexture2_SetOETF(ktxTexture2* This, khr_df_transfer_e oetf);
1133+
1134+
KTX_API ktx_error_code_e KTX_APIENTRY
1135+
ktxTexture2_SetPrimaries(ktxTexture2* This, khr_df_primaries_e primaries);
1136+
11171137
/**
11181138
* @~English
11191139
* @brief Flags specifiying UASTC encoding options.
@@ -1363,21 +1383,23 @@ typedef struct ktxBasisParams {
13631383
/*!< A swizzle to apply before encoding. It must match the regular
13641384
expression /^[rgba01]{4}$/. If both this and preSwizzle
13651385
are specified ktxTexture_CompressBasisEx will raise
1366-
KTX_INVALID_OPERATION.
1386+
KTX_INVALID_OPERATION. Usable with both ETC1S and UASTC.
13671387
*/
13681388
ktx_bool_t normalMap;
13691389
/*!< Tunes codec parameters for better quality on normal maps (no
13701390
selector RDO, no endpoint RDO) and sets the texture's DFD appropriately.
13711391
Only valid for linear textures.
13721392
*/
13731393
ktx_bool_t separateRGToRGB_A;
1374-
/*!< @deprecated. This was and is a no-op. 2-component inputs have always been
1375-
automatically separated using an "rrrg" inputSwizzle. @sa inputSwizzle and normalMode.
1394+
/*!< @deprecated. This was and is a no-op. 2-component inputs have
1395+
always been automatically separated using an "rrrg" inputSwizzle.
1396+
@sa inputSwizzle and normalMode.
13761397
*/
13771398
ktx_bool_t preSwizzle;
13781399
/*!< If the texture has @c KTXswizzle metadata, apply it before
13791400
compressing. Swizzling, like @c rabb may yield drastically
1380-
different error metrics if done after supercompression.
1401+
different error metrics if done after supercompression. Usable
1402+
for both ETC1S and UASTC.
13811403
*/
13821404
ktx_bool_t noEndpointRDO;
13831405
/*!< Disable endpoint rate distortion optimizations. Slightly faster,

interface/js_binding/class_compat.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// -*- tab-width: 4; -*-
2+
// vi: set sw=2 ts=4 expandtab textwidth=80:
3+
4+
//
5+
// Copyright 2024 Khronos Group, Inc.
6+
// SPDX-License-Identifier: Apache-2.0
7+
//
8+
9+
// Provide old name for backward compatibility.
10+
11+
Module.onRuntimeInitialized = function() {
12+
Module['ktxTexture'] = Module.texture;
13+
Module['ErrorCode'] = Module.error_code;
14+
Module['TranscodeTarget'] = Module.texture_transcode_fmt;
15+
Module['TranscodeFlags'] = Module.transcode_flag_bits;
16+
}
17+

0 commit comments

Comments
 (0)