From 9ddc65d4e5f60800d0afb77fe86355b56e36336e Mon Sep 17 00:00:00 2001 From: kalwalt Date: Thu, 21 Dec 2023 00:47:15 +0100 Subject: [PATCH 01/13] fix for issue https://github.com/webarkit/jsartoolkitNFT/issues/364 --- lib/SRC/ARUtil/log.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/SRC/ARUtil/log.c b/lib/SRC/ARUtil/log.c index 66e4337..9e58741 100644 --- a/lib/SRC/ARUtil/log.c +++ b/lib/SRC/ARUtil/log.c @@ -201,7 +201,16 @@ void arLogv(const char *tag, const int logLevel, const char *format, va_list ap) os_log_with_type(OS_LOG_DEFAULT, type, "%{public}s", buf); } #else + +#ifdef __EMSCRIPTEN__ + if(logLevel == AR_LOG_LEVEL_ERROR) + fprintf(stderr, "%s", buf); + else + fprintf(stdout, "%s", buf); +#else fprintf(stderr, "%s", buf); +#endif + #endif } free(buf); From 01108701762e832cca7290b5de7d466e3a46e5d6 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Fri, 22 Dec 2023 22:49:59 +0100 Subject: [PATCH 02/13] improved log with emscripten_log uilities - see https://github.com/webarkit/jsartoolkitNFT/issues/364 --- lib/SRC/ARUtil/log.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/SRC/ARUtil/log.c b/lib/SRC/ARUtil/log.c index 9e58741..26a8d54 100644 --- a/lib/SRC/ARUtil/log.c +++ b/lib/SRC/ARUtil/log.c @@ -47,6 +47,10 @@ # define snprintf _snprintf #endif +#ifdef __EMSCRIPTEN__ +#include +#endif + // // Global required for logging functions. // @@ -204,9 +208,9 @@ void arLogv(const char *tag, const int logLevel, const char *format, va_list ap) #ifdef __EMSCRIPTEN__ if(logLevel == AR_LOG_LEVEL_ERROR) - fprintf(stderr, "%s", buf); + emscripten_console_error(buf); else - fprintf(stdout, "%s", buf); + emscripten_console_warn(buf); #else fprintf(stderr, "%s", buf); #endif From a21f6591728415e2d4915cbc3d5a42c2317655f6 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Wed, 23 Oct 2024 23:52:42 +0200 Subject: [PATCH 03/13] fix for issue https://github.com/webarkit/jsartoolkitNFT/issues/363 - emcc version > 3.1.40 cause issue with isnan --- lib/SRC/KPM/FreakMatcher/framework/error.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/SRC/KPM/FreakMatcher/framework/error.h b/lib/SRC/KPM/FreakMatcher/framework/error.h index 5383c0c..e0237ab 100644 --- a/lib/SRC/KPM/FreakMatcher/framework/error.h +++ b/lib/SRC/KPM/FreakMatcher/framework/error.h @@ -63,7 +63,8 @@ # define DEBUG_BLOCK(X) #endif -#define isnan(x) ((x) != (x)) +/*#define isnan(x) ((x) != (x)) #define isinf(x) (!isnan(x) && isnan(x - x)) #define ASSERT_NAN(x) ASSERT(!isnan(x), "NaN") -#define ASSERT_INF(x) ASSERT(!isinf(x), "INF") \ No newline at end of file +#define ASSERT_INF(x) ASSERT(!isinf(x), "INF") +*/ \ No newline at end of file From 70537cd6c04c0165fd79bf5f01d0addadc04bce5 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Wed, 6 Nov 2024 12:10:53 +0100 Subject: [PATCH 04/13] check workspace to fix the issue --- lib/SRC/AR2/featureMap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/SRC/AR2/featureMap.c b/lib/SRC/AR2/featureMap.c index 61eb501..a9f1f22 100644 --- a/lib/SRC/AR2/featureMap.c +++ b/lib/SRC/AR2/featureMap.c @@ -200,7 +200,7 @@ AR2FeatureMapT *ar2GenFeatureMap( AR2ImageT *image, fp2++; } for( j = 1; j < ysize-1; j++ ) { - ARLOGi("\r%4d/%4d.", j+1, ysize); fflush(stdout); + ARLOGd("\r%4d/%4d.", j+1, ysize); fflush(stdout); *(fp++) = 1.0f; fp2++; for( i = 1; i < xsize-1; i++ ) { From 1bfc1b21edd59012c7fb74eb8bf2cc23ca52d19f Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Mon, 10 Mar 2025 17:37:17 +0100 Subject: [PATCH 05/13] add WebARKitVideoLuma module for luma conversion with SIMD support --- WebARKit/WebARKitVideoLuma.cpp | 120 +++++++++++++++++++++++++++ WebARKit/include/WebARKitVideoLuma.h | 42 ++++++++++ 2 files changed, 162 insertions(+) create mode 100644 WebARKit/WebARKitVideoLuma.cpp create mode 100644 WebARKit/include/WebARKitVideoLuma.h diff --git a/WebARKit/WebARKitVideoLuma.cpp b/WebARKit/WebARKitVideoLuma.cpp new file mode 100644 index 0000000..7038896 --- /dev/null +++ b/WebARKit/WebARKitVideoLuma.cpp @@ -0,0 +1,120 @@ +#include +#include // Include this header for printf + +ARVideoLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { + ARVideoLumaInfo *vli; + + vli = (ARVideoLumaInfo *)calloc(1, sizeof(ARVideoLumaInfo)); + if (!vli) { + printf("Out of memory!!\n"); + return (NULL); + } + vli->xsize = xsize; + vli->ysize = ysize; + vli->buffSize = xsize * ysize; + vli->simd128 = simd128; + vli->buff = (uint8_t *)valloc(vli->buffSize); + if (!vli->buff) { + printf("Out of memory!!\n"); + free(vli); + return (NULL); + } + + return (vli); +} + +uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, + const uint8_t *__restrict dataPtr) { + unsigned int p, q; + + if (vli->simd128 == true) { + printf("With simd128!!!\n"); +#ifdef __EMSCRIPTEN_SIMD128__ + arVideoLumaRGBAtoL_Emscripten_simd128( + vli->buff, (unsigned char *__restrict)dataPtr, vli->buffSize); + return (vli->buff); +#else + printf("SIMD128 not supported!!!\n"); + arVideoLuma_default(vli->buff, (unsigned char *__restrict)dataPtr, vli->buffSize); + return (vli->buff); +#endif + } else { + printf("Without simd128!!!\n"); + arVideoLuma_default(vli->buff, (unsigned char *__restrict)dataPtr, vli->buffSize); + return (vli->buff); + } +} + +int arVideoLumaFinal(ARVideoLumaInfo **vli_p) { + if (!vli_p) + return (-1); + if (!*vli_p) + return (0); + + free((*vli_p)->buff); + free(*vli_p); + *vli_p = NULL; + + return (0); +} + +static void arVideoLuma_default(uint8_t *__restrict dest, + uint8_t *__restrict src, int32_t numPixels) { + unsigned int p, q; + printf("default luma conversion!!!\n"); + q = 0; + for (p = 0; p < numPixels; p++) { + dest[p] = (R8_CCIR601 * src[q + 0] + G8_CCIR601 * src[q + 1] + + B8_CCIR601 * src[q + 2]) >> + 8; + q += 4; + } +} + +#ifdef __EMSCRIPTEN_SIMD128__ +static void arVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, + uint8_t *__restrict src, + int32_t numPixels) { + + printf("using arVideoLumaRGBAtoL_Emscripten_simd128_fast !!!\n"); + + v128_t *pin = (v128_t *)src; + int64_t *pout = (int64_t *)dest; + int numPixelsDiv8 = numPixels / 8; + + v128_t maskRedBlue = wasm_i32x4_splat(0x00FF00FF); + v128_t scaleRedBlue = + wasm_i32x4_splat((uint32_t)B8_CCIR601 << 16 | R8_CCIR601); + v128_t scaleGreen = wasm_i32x4_splat(G8_CCIR601); + do { + v128_t pixels1 = wasm_v128_load(pin); // Load 16 bytes (4 pixels) from src + v128_t pixels2 = wasm_v128_load(pin + 1); + pin += 2; + + v128_t g1 = wasm_u16x8_shr(pixels1, 8); + v128_t g2 = wasm_u16x8_shr(pixels2, 8); + + v128_t rb1 = wasm_v128_and(pixels1, maskRedBlue); + v128_t rb2 = wasm_v128_and(pixels2, maskRedBlue); + + g1 = wasm_i32x4_dot_i16x8(g1, scaleGreen); + g2 = wasm_i32x4_dot_i16x8(g2, scaleGreen); + rb1 = wasm_i32x4_dot_i16x8(rb1, scaleRedBlue); + rb2 = wasm_i32x4_dot_i16x8(rb2, scaleRedBlue); + + v128_t y1 = wasm_i32x4_add(g1, rb1); + v128_t y2 = wasm_i32x4_add(g2, rb2); + + y1 = wasm_u32x4_shr(y1, 8); + y2 = wasm_u32x4_shr(y2, 8); + + v128_t y = wasm_i16x8_narrow_i32x4(y1, y2); + y = wasm_u8x16_narrow_i16x8(y, y); + + *pout = wasm_i64x2_extract_lane(y, 0); + + pout++; + numPixelsDiv8--; + } while (numPixelsDiv8); +} +#endif \ No newline at end of file diff --git a/WebARKit/include/WebARKitVideoLuma.h b/WebARKit/include/WebARKitVideoLuma.h new file mode 100644 index 0000000..ea44754 --- /dev/null +++ b/WebARKit/include/WebARKitVideoLuma.h @@ -0,0 +1,42 @@ +#ifndef WEBARKITVIDEOLUMA_H +#define WEBARKITVIDEOLUMA_H + +#include // For standard integer types like uint8_t, int32_t +#include // For boolean type +#include // For memory allocation functions + +#ifdef __EMSCRIPTEN_SIMD128__ +#include // For SIMD operations +#endif + +// CCIR 601 recommended values. See +// http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC11 . +const uint8_t R8_CCIR601 = 77; +const uint8_t G8_CCIR601 = 150; +const uint8_t B8_CCIR601 = 29; + +struct ARVideoLumaInfo { + int xsize; + int ysize; + int buffSize; + bool simd128; + uint8_t *__restrict buff; +}; + +#ifdef __EMSCRIPTEN_SIMD128__ +static void arVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, + uint8_t *__restrict src, + int32_t numPixels); +#endif + +static void arVideoLuma_default(uint8_t *__restrict dest, uint8_t *__restrict src, + int32_t numPixels); + +ARVideoLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128); + +uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, + const uint8_t *__restrict dataPtr); + +int arVideoLumaFinal(ARVideoLumaInfo **vli_p); + +#endif // WEBARKITVIDEOLUMA_H \ No newline at end of file From 3fb79f915f13d33314abaac84c7f79e6fbf8a021 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Mon, 10 Mar 2025 17:47:36 +0100 Subject: [PATCH 06/13] refactor: encapsulate WebARKitVideoLuma functions within webarkit namespace --- WebARKit/WebARKitVideoLuma.cpp | 6 +++++- WebARKit/include/WebARKitVideoLuma.h | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/WebARKit/WebARKitVideoLuma.cpp b/WebARKit/WebARKitVideoLuma.cpp index 7038896..1cfb0d5 100644 --- a/WebARKit/WebARKitVideoLuma.cpp +++ b/WebARKit/WebARKitVideoLuma.cpp @@ -1,6 +1,8 @@ #include #include // Include this header for printf +namespace webarkit { + ARVideoLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { ARVideoLumaInfo *vli; @@ -117,4 +119,6 @@ static void arVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, numPixelsDiv8--; } while (numPixelsDiv8); } -#endif \ No newline at end of file +#endif + +} // namespace webarkit \ No newline at end of file diff --git a/WebARKit/include/WebARKitVideoLuma.h b/WebARKit/include/WebARKitVideoLuma.h index ea44754..dc1d7af 100644 --- a/WebARKit/include/WebARKitVideoLuma.h +++ b/WebARKit/include/WebARKitVideoLuma.h @@ -9,6 +9,8 @@ #include // For SIMD operations #endif +namespace webarkit { + // CCIR 601 recommended values. See // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC11 . const uint8_t R8_CCIR601 = 77; @@ -39,4 +41,6 @@ uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, int arVideoLumaFinal(ARVideoLumaInfo **vli_p); +} // namespace webarkit + #endif // WEBARKITVIDEOLUMA_H \ No newline at end of file From 597d1a0d3a9114a77fd11a80c2e6d8affbb56c68 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Mon, 10 Mar 2025 18:01:38 +0100 Subject: [PATCH 07/13] refactor: replace raw memory management with smart pointers in WebARKitVideoLuma --- WebARKit/WebARKitVideoLuma.cpp | 36 +++++++++++++--------------- WebARKit/include/WebARKitVideoLuma.h | 3 ++- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/WebARKit/WebARKitVideoLuma.cpp b/WebARKit/WebARKitVideoLuma.cpp index 1cfb0d5..d2f4c32 100644 --- a/WebARKit/WebARKitVideoLuma.cpp +++ b/WebARKit/WebARKitVideoLuma.cpp @@ -4,25 +4,24 @@ namespace webarkit { ARVideoLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { - ARVideoLumaInfo *vli; + ARVideoLumaInfo *vli = new ARVideoLumaInfo; - vli = (ARVideoLumaInfo *)calloc(1, sizeof(ARVideoLumaInfo)); if (!vli) { printf("Out of memory!!\n"); - return (NULL); + return nullptr; } vli->xsize = xsize; vli->ysize = ysize; vli->buffSize = xsize * ysize; vli->simd128 = simd128; - vli->buff = (uint8_t *)valloc(vli->buffSize); + vli->buff = std::make_unique(vli->buffSize); if (!vli->buff) { printf("Out of memory!!\n"); - free(vli); - return (NULL); + delete vli; + return nullptr; } - return (vli); + return vli; } uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, @@ -33,31 +32,30 @@ uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, printf("With simd128!!!\n"); #ifdef __EMSCRIPTEN_SIMD128__ arVideoLumaRGBAtoL_Emscripten_simd128( - vli->buff, (unsigned char *__restrict)dataPtr, vli->buffSize); - return (vli->buff); + vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); + return vli->buff.get(); #else printf("SIMD128 not supported!!!\n"); - arVideoLuma_default(vli->buff, (unsigned char *__restrict)dataPtr, vli->buffSize); - return (vli->buff); + arVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); + return vli->buff.get(); #endif } else { printf("Without simd128!!!\n"); - arVideoLuma_default(vli->buff, (unsigned char *__restrict)dataPtr, vli->buffSize); - return (vli->buff); + arVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); + return vli->buff.get(); } } int arVideoLumaFinal(ARVideoLumaInfo **vli_p) { if (!vli_p) - return (-1); + return -1; if (!*vli_p) - return (0); + return 0; - free((*vli_p)->buff); - free(*vli_p); - *vli_p = NULL; + delete *vli_p; + *vli_p = nullptr; - return (0); + return 0; } static void arVideoLuma_default(uint8_t *__restrict dest, diff --git a/WebARKit/include/WebARKitVideoLuma.h b/WebARKit/include/WebARKitVideoLuma.h index dc1d7af..e79d0a5 100644 --- a/WebARKit/include/WebARKitVideoLuma.h +++ b/WebARKit/include/WebARKitVideoLuma.h @@ -4,6 +4,7 @@ #include // For standard integer types like uint8_t, int32_t #include // For boolean type #include // For memory allocation functions +#include // For std::unique_ptr #ifdef __EMSCRIPTEN_SIMD128__ #include // For SIMD operations @@ -22,7 +23,7 @@ struct ARVideoLumaInfo { int ysize; int buffSize; bool simd128; - uint8_t *__restrict buff; + std::unique_ptr buff; }; #ifdef __EMSCRIPTEN_SIMD128__ From 59cad462131534aba23b51f72371cb671052ceda Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Mon, 10 Mar 2025 18:53:48 +0100 Subject: [PATCH 08/13] refactor: rename ARVideoLumaInfo to WebARKitLumaInfo and update related functions --- WebARKit/WebARKitVideoLuma.cpp | 8 ++++---- WebARKit/include/WebARKitVideoLuma.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/WebARKit/WebARKitVideoLuma.cpp b/WebARKit/WebARKitVideoLuma.cpp index d2f4c32..a3ba35c 100644 --- a/WebARKit/WebARKitVideoLuma.cpp +++ b/WebARKit/WebARKitVideoLuma.cpp @@ -3,8 +3,8 @@ namespace webarkit { -ARVideoLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { - ARVideoLumaInfo *vli = new ARVideoLumaInfo; +WebARKitLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { + WebARKitLumaInfo *vli = new WebARKitLumaInfo; if (!vli) { printf("Out of memory!!\n"); @@ -24,7 +24,7 @@ ARVideoLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { return vli; } -uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, +uint8_t *__restrict arVideoLuma(WebARKitLumaInfo *vli, const uint8_t *__restrict dataPtr) { unsigned int p, q; @@ -46,7 +46,7 @@ uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, } } -int arVideoLumaFinal(ARVideoLumaInfo **vli_p) { +int arVideoLumaFinal(WebARKitLumaInfo **vli_p) { if (!vli_p) return -1; if (!*vli_p) diff --git a/WebARKit/include/WebARKitVideoLuma.h b/WebARKit/include/WebARKitVideoLuma.h index e79d0a5..0405add 100644 --- a/WebARKit/include/WebARKitVideoLuma.h +++ b/WebARKit/include/WebARKitVideoLuma.h @@ -18,7 +18,7 @@ const uint8_t R8_CCIR601 = 77; const uint8_t G8_CCIR601 = 150; const uint8_t B8_CCIR601 = 29; -struct ARVideoLumaInfo { +struct WebARKitLumaInfo { int xsize; int ysize; int buffSize; @@ -35,12 +35,12 @@ static void arVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, static void arVideoLuma_default(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels); -ARVideoLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128); +WebARKitLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128); -uint8_t *__restrict arVideoLuma(ARVideoLumaInfo *vli, +uint8_t *__restrict arVideoLuma(WebARKitLumaInfo *vli, const uint8_t *__restrict dataPtr); -int arVideoLumaFinal(ARVideoLumaInfo **vli_p); +int arVideoLumaFinal(WebARKitLumaInfo **vli_p); } // namespace webarkit From b2dd75e573d4fa529a647d70751b530bb2471211 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Mon, 10 Mar 2025 19:18:09 +0100 Subject: [PATCH 09/13] refactor: rename functions in WebARKitVideoLuma for consistency and clarity --- WebARKit/WebARKitVideoLuma.cpp | 20 ++++++++++---------- WebARKit/include/WebARKitVideoLuma.h | 17 ++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/WebARKit/WebARKitVideoLuma.cpp b/WebARKit/WebARKitVideoLuma.cpp index a3ba35c..e3e84f2 100644 --- a/WebARKit/WebARKitVideoLuma.cpp +++ b/WebARKit/WebARKitVideoLuma.cpp @@ -1,9 +1,9 @@ #include -#include // Include this header for printf +#include namespace webarkit { -WebARKitLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { +WebARKitLumaInfo *webarkitVideoLumaInit(int xsize, int ysize, bool simd128) { WebARKitLumaInfo *vli = new WebARKitLumaInfo; if (!vli) { @@ -24,29 +24,29 @@ WebARKitLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128) { return vli; } -uint8_t *__restrict arVideoLuma(WebARKitLumaInfo *vli, +uint8_t *__restrict webarkitVideoLuma(WebARKitLumaInfo *vli, const uint8_t *__restrict dataPtr) { unsigned int p, q; if (vli->simd128 == true) { printf("With simd128!!!\n"); #ifdef __EMSCRIPTEN_SIMD128__ - arVideoLumaRGBAtoL_Emscripten_simd128( + webarkitVideoLumaRGBAtoL_Emscripten_simd128( vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); return vli->buff.get(); #else printf("SIMD128 not supported!!!\n"); - arVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); + webarkitVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); return vli->buff.get(); #endif } else { printf("Without simd128!!!\n"); - arVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); + webarkitVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); return vli->buff.get(); } } -int arVideoLumaFinal(WebARKitLumaInfo **vli_p) { +int webarkitVideoLumaFinal(WebARKitLumaInfo **vli_p) { if (!vli_p) return -1; if (!*vli_p) @@ -58,7 +58,7 @@ int arVideoLumaFinal(WebARKitLumaInfo **vli_p) { return 0; } -static void arVideoLuma_default(uint8_t *__restrict dest, +static void webarkitVideoLuma_default(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels) { unsigned int p, q; printf("default luma conversion!!!\n"); @@ -72,11 +72,11 @@ static void arVideoLuma_default(uint8_t *__restrict dest, } #ifdef __EMSCRIPTEN_SIMD128__ -static void arVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, +static void webarkitVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels) { - printf("using arVideoLumaRGBAtoL_Emscripten_simd128_fast !!!\n"); + printf("using webarkitVideoLumaRGBAtoL_Emscripten_simd128_fast !!!\n"); v128_t *pin = (v128_t *)src; int64_t *pout = (int64_t *)dest; diff --git a/WebARKit/include/WebARKitVideoLuma.h b/WebARKit/include/WebARKitVideoLuma.h index 0405add..c7f2059 100644 --- a/WebARKit/include/WebARKitVideoLuma.h +++ b/WebARKit/include/WebARKitVideoLuma.h @@ -1,10 +1,9 @@ #ifndef WEBARKITVIDEOLUMA_H #define WEBARKITVIDEOLUMA_H -#include // For standard integer types like uint8_t, int32_t -#include // For boolean type -#include // For memory allocation functions -#include // For std::unique_ptr +#include +#include +#include #ifdef __EMSCRIPTEN_SIMD128__ #include // For SIMD operations @@ -27,20 +26,20 @@ struct WebARKitLumaInfo { }; #ifdef __EMSCRIPTEN_SIMD128__ -static void arVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, +static void webarkitVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels); #endif -static void arVideoLuma_default(uint8_t *__restrict dest, uint8_t *__restrict src, +static void webarkitVideoLuma_default(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels); -WebARKitLumaInfo *arVideoLumaInit(int xsize, int ysize, bool simd128); +WebARKitLumaInfo *webarkitVideoLumaInit(int xsize, int ysize, bool simd128); -uint8_t *__restrict arVideoLuma(WebARKitLumaInfo *vli, +uint8_t *__restrict webarkitVideoLuma(WebARKitLumaInfo *vli, const uint8_t *__restrict dataPtr); -int arVideoLumaFinal(WebARKitLumaInfo **vli_p); +int webarkitVideoLumaFinal(WebARKitLumaInfo **vli_p); } // namespace webarkit From d60dd39a898c77206e157225ad5c139607f7270b Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Mon, 10 Mar 2025 20:57:39 +0100 Subject: [PATCH 10/13] refactor: update SIMD preprocessor directives from EMSCRIPTEN_SIMD128 to wasm_simd128 for consistency --- WebARKit/WebARKitVideoLuma.cpp | 4 ++-- WebARKit/include/WebARKitVideoLuma.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WebARKit/WebARKitVideoLuma.cpp b/WebARKit/WebARKitVideoLuma.cpp index e3e84f2..a323c3e 100644 --- a/WebARKit/WebARKitVideoLuma.cpp +++ b/WebARKit/WebARKitVideoLuma.cpp @@ -29,8 +29,8 @@ uint8_t *__restrict webarkitVideoLuma(WebARKitLumaInfo *vli, unsigned int p, q; if (vli->simd128 == true) { +#ifdef __wasm_simd128__ printf("With simd128!!!\n"); -#ifdef __EMSCRIPTEN_SIMD128__ webarkitVideoLumaRGBAtoL_Emscripten_simd128( vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); return vli->buff.get(); @@ -71,7 +71,7 @@ static void webarkitVideoLuma_default(uint8_t *__restrict dest, } } -#ifdef __EMSCRIPTEN_SIMD128__ +#ifdef __wasm_simd128__ static void webarkitVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels) { diff --git a/WebARKit/include/WebARKitVideoLuma.h b/WebARKit/include/WebARKitVideoLuma.h index c7f2059..96d1156 100644 --- a/WebARKit/include/WebARKitVideoLuma.h +++ b/WebARKit/include/WebARKitVideoLuma.h @@ -5,7 +5,7 @@ #include #include -#ifdef __EMSCRIPTEN_SIMD128__ +#ifdef __wasm_simd128__ #include // For SIMD operations #endif @@ -25,7 +25,7 @@ struct WebARKitLumaInfo { std::unique_ptr buff; }; -#ifdef __EMSCRIPTEN_SIMD128__ +#ifdef __wasm_simd128__ static void webarkitVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels); From 1dbeab59ed51fe3dc3f957e6f1df51ffb542f0ac Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Tue, 11 Mar 2025 13:36:55 +0100 Subject: [PATCH 11/13] refactor: replace printf statements with logging functions for better error handling --- WebARKit/WebARKitVideoLuma.cpp | 18 +++++++----------- WebARKit/include/WebARKitVideoLuma.h | 3 ++- include/WebARKit/WebARKitLog.h | 1 + lib/SRC/WebARKit/WebARKitLog.cpp | 27 ++++++++++++++++++++++++++- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/WebARKit/WebARKitVideoLuma.cpp b/WebARKit/WebARKitVideoLuma.cpp index a323c3e..12f0b6c 100644 --- a/WebARKit/WebARKitVideoLuma.cpp +++ b/WebARKit/WebARKitVideoLuma.cpp @@ -1,5 +1,4 @@ #include -#include namespace webarkit { @@ -7,7 +6,7 @@ WebARKitLumaInfo *webarkitVideoLumaInit(int xsize, int ysize, bool simd128) { WebARKitLumaInfo *vli = new WebARKitLumaInfo; if (!vli) { - printf("Out of memory!!\n"); + webarkitLOGe("Out of memory!!"); return nullptr; } vli->xsize = xsize; @@ -16,7 +15,7 @@ WebARKitLumaInfo *webarkitVideoLumaInit(int xsize, int ysize, bool simd128) { vli->simd128 = simd128; vli->buff = std::make_unique(vli->buffSize); if (!vli->buff) { - printf("Out of memory!!\n"); + webarkitLOGe("Out of memory!!\n"); delete vli; return nullptr; } @@ -26,21 +25,18 @@ WebARKitLumaInfo *webarkitVideoLumaInit(int xsize, int ysize, bool simd128) { uint8_t *__restrict webarkitVideoLuma(WebARKitLumaInfo *vli, const uint8_t *__restrict dataPtr) { - unsigned int p, q; + //unsigned int p, q; if (vli->simd128 == true) { #ifdef __wasm_simd128__ - printf("With simd128!!!\n"); - webarkitVideoLumaRGBAtoL_Emscripten_simd128( + webarkitVideoLumaRGBAtoLuma_Emscripten_simd128( vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); return vli->buff.get(); #else - printf("SIMD128 not supported!!!\n"); webarkitVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); return vli->buff.get(); #endif } else { - printf("Without simd128!!!\n"); webarkitVideoLuma_default(vli->buff.get(), (unsigned char *__restrict)dataPtr, vli->buffSize); return vli->buff.get(); } @@ -61,7 +57,7 @@ int webarkitVideoLumaFinal(WebARKitLumaInfo **vli_p) { static void webarkitVideoLuma_default(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels) { unsigned int p, q; - printf("default luma conversion!!!\n"); + webarkitLOGd("Using webarkitVideoLuma_default for luma conversion!!!"); q = 0; for (p = 0; p < numPixels; p++) { dest[p] = (R8_CCIR601 * src[q + 0] + G8_CCIR601 * src[q + 1] + @@ -72,11 +68,11 @@ static void webarkitVideoLuma_default(uint8_t *__restrict dest, } #ifdef __wasm_simd128__ -static void webarkitVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, +static void webarkitVideoLumaRGBAtoLuma_Emscripten_simd128(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels) { - printf("using webarkitVideoLumaRGBAtoL_Emscripten_simd128_fast !!!\n"); + webarkitLOGd("Using webarkitVideoLumaRGBAtoLuma_Emscripten_simd128 for Luma conversion !!!"); v128_t *pin = (v128_t *)src; int64_t *pout = (int64_t *)dest; diff --git a/WebARKit/include/WebARKitVideoLuma.h b/WebARKit/include/WebARKitVideoLuma.h index 96d1156..e33f03b 100644 --- a/WebARKit/include/WebARKitVideoLuma.h +++ b/WebARKit/include/WebARKitVideoLuma.h @@ -4,6 +4,7 @@ #include #include #include +#include #ifdef __wasm_simd128__ #include // For SIMD operations @@ -26,7 +27,7 @@ struct WebARKitLumaInfo { }; #ifdef __wasm_simd128__ -static void webarkitVideoLumaRGBAtoL_Emscripten_simd128(uint8_t *__restrict dest, +static void webarkitVideoLumaRGBAtoLuma_Emscripten_simd128(uint8_t *__restrict dest, uint8_t *__restrict src, int32_t numPixels); #endif diff --git a/include/WebARKit/WebARKitLog.h b/include/WebARKit/WebARKitLog.h index a42b6e5..938dc26 100644 --- a/include/WebARKit/WebARKitLog.h +++ b/include/WebARKit/WebARKitLog.h @@ -40,5 +40,6 @@ void webarkitLOGw(const std::string &message, const char * format); void webarkitLOGw(const std::string &message, int format); +void webarkitLOGd(const std::string &message); #endif // #ifndef WEBARKIT_LOG_H \ No newline at end of file diff --git a/lib/SRC/WebARKit/WebARKitLog.cpp b/lib/SRC/WebARKit/WebARKitLog.cpp index 9e9e61f..74c869c 100644 --- a/lib/SRC/WebARKit/WebARKitLog.cpp +++ b/lib/SRC/WebARKit/WebARKitLog.cpp @@ -6,6 +6,8 @@ const char * WARKTerror = "%c🚩[webarkit-error:]"; const char * WARKTerrorStyle = "color: #ffffff; background-color: #ff0101; border-radius: 4px; padding: 2px"; const char * WARKTwarn = "%c⚠️[webarkit-warn:]"; const char * WARKTwarnStyle = "color: #774400; background-color: #ffff99; border-radius: 4px; padding: 2px"; +const char * WARKTdebug = "%c🐞[webarkit-debug:]"; +const char * WARKTdebugStyle = "color: #000000; background-color: #ffcc00; border-radius: 4px; padding: 2px"; void webarkitLOGi(const std::string &message) { EM_ASM ({ @@ -266,4 +268,27 @@ void webarkitLOGw(const std::string &message, int format) { WARKTwarnStyle, format ); -} \ No newline at end of file +} + +#if defined WEBARKIT_DEBUG + +void webarkitLOGd(const std::string &message) { + EM_ASM ({ + var message = UTF8ToString($0); + var debugHead = UTF8ToString($1); + var style = UTF8ToString($2); + console.log(debugHead + message, style); + }, + message.c_str(), + WARKTdebug, + WARKTdebugStyle + ); +} + +#else + +void webarkitLOGd(const std::string &message) { + // do nothing +} + +#endif \ No newline at end of file From 656436e36bbebd9c269cf2a9f47fb4a962359f92 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Sun, 9 Nov 2025 19:03:43 +0100 Subject: [PATCH 12/13] version 1.7.6 --- include/AR/config.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/AR/config.h b/include/AR/config.h index c762675..33df05b 100644 --- a/include/AR/config.h +++ b/include/AR/config.h @@ -276,7 +276,7 @@ typedef enum { #undef ARVIDEO_INPUT_DEFAULT_1394 #undef ARVIDEO_INPUT_DEFAULT_GSTREAMER #undef ARVIDEO_INPUT_DEFAULT_IMAGE -#undef ARVIDEO_INPUT_DEFAULT_DUMMY +#define ARVIDEO_INPUT_DEFAULT_DUMMY // Other Linux-only configuration. #define HAVE_LIBJPEG 1 @@ -358,7 +358,7 @@ typedef enum { #undef ARVIDEO_INPUT_WINDOWS_MEDIA_CAPTURE // Default input module. This is edited by the configure script. -#undef ARVIDEO_INPUT_DEFAULT_DUMMY +#define ARVIDEO_INPUT_DEFAULT_DUMMY #undef ARVIDEO_INPUT_DEFAULT_IMAGE #undef ARVIDEO_INPUT_DEFAULT_WINDOWS_MEDIA_FOUNDATION #undef ARVIDEO_INPUT_DEFAULT_WINDOWS_MEDIA_CAPTURE @@ -408,7 +408,7 @@ typedef enum { #undef ARVIDEO_INPUT_DUMMY #define ARVIDEO_INPUT_ANDROID #undef ARVIDEO_INPUT_IMAGE -#undef ARVIDEO_INPUT_DEFAULT_DUMMY +#define ARVIDEO_INPUT_DEFAULT_DUMMY #define ARVIDEO_INPUT_DEFAULT_ANDROID #undef ARVIDEO_INPUT_DEFAULT_IMAGE @@ -459,7 +459,7 @@ typedef enum { #undef ARVIDEO_INPUT_DUMMY #define ARVIDEO_INPUT_IMAGE #define ARVIDEO_INPUT_DEFAULT_AVFOUNDATION -#undef ARVIDEO_INPUT_DEFAULT_DUMMY +#define ARVIDEO_INPUT_DEFAULT_DUMMY #undef ARVIDEO_INPUT_DEFAULT_IMAGE #define HAVE_LIBJPEG 1 #define USE_OPENGL_ES 1 @@ -476,7 +476,7 @@ typedef enum { #define ARVIDEO_INPUT_DUMMY #define ARVIDEO_INPUT_IMAGE #define ARVIDEO_INPUT_DEFAULT_AVFOUNDATION -#undef ARVIDEO_INPUT_DEFAULT_DUMMY +#define ARVIDEO_INPUT_DEFAULT_DUMMY #undef ARVIDEO_INPUT_DEFAULT_IMAGE #define HAVE_LIBJPEG 1 #define HAVE_INTEL_SIMD 1 From 2c9f6308ea82081d652f3ce691fe2414ce4bd042 Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Mon, 1 Jun 2026 21:21:54 +0200 Subject: [PATCH 13/13] fix(kpm/matcher): use std::map for deterministic iteration in vote tally, keyframes, and BHC clusters The matcher had three `std::unordered_map` typedefs whose iteration order depended on the STL implementation (libstdc++ on Linux, MSVC STL on Windows, libc++ on macOS / Emscripten). Code paths that iterate these maps and pick a winner-on-tie produced different results on different platforms, causing the matcher to be non-deterministic across builds. Concretely: 1. `HoughSimilarityVoting::hash_t` (vote tally) is consumed by `getMaximumNumberOfVotes`, which iterates and picks the bin with the highest count. Ties between Hough bins are common at borderline matches and were broken inconsistently per platform. 2. `VisualDatabase::keyframe_map_t` is iterated by `query()`. Ties on inlier count between keyframes are broken first-wins, so the winning keyframe at borderline ties depended on which iteration order the platform's STL chose. 3. `BinaryHierarchicalClustering::cluster_map_t` is iterated during BHC tree construction; ordering affects the resulting topology and therefore which features cluster together, which propagates into the eventual inlier set. All three typedefs become `std::map<...>`. `std::map`'s ascending- key iteration is consistent across STL implementations (and matches the BTreeMap fix on the pure-Rust port, webarkit/WebARKitLib-rs issue #170). API surface change: none. `std::map` and `std::unordered_map` share the operations used here (`operator[]`, `find`, `insert`, `erase`, `clear`, `iterator`). Performance: `O(log N)` lookup instead of `O(1) amortized`, but N is small for all three maps (number of keyframes ~1-10, number of Hough bins voted for in a query ~10s, number of BHC clusters per level ~1-100), so the difference is negligible. `VisualDatabaseImpl::point3d_map_t` in `facade/visual_database_facade.cpp` is left as `std::unordered_map` because it is used lookup-only (`map[image_id] = ...`, `return map[image_id]`); changing it has no functional benefit and would be cosmetic only. Motivation + measurements live in webarkit/WebARKitLib-rs issue #170, which has the cross-platform repro from CI. --- .../matchers/binary_hierarchical_clustering.h | 13 +++++++++++-- .../matchers/hough_similarity_voting.h | 16 ++++++++++++---- .../KPM/FreakMatcher/matchers/visual_database.h | 12 ++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/SRC/KPM/FreakMatcher/matchers/binary_hierarchical_clustering.h b/lib/SRC/KPM/FreakMatcher/matchers/binary_hierarchical_clustering.h index d0674bb..767620f 100644 --- a/lib/SRC/KPM/FreakMatcher/matchers/binary_hierarchical_clustering.h +++ b/lib/SRC/KPM/FreakMatcher/matchers/binary_hierarchical_clustering.h @@ -37,7 +37,7 @@ #include "kmedoids.h" -#include +#include #include namespace vision { @@ -214,7 +214,16 @@ namespace vision { typedef Node node_t; typedef std::unique_ptr node_ptr_t; typedef BinarykMedoids kmedoids_t; - typedef std::unordered_map > cluster_map_t; + // std::map (not std::unordered_map): BHC tree construction + // iterates this map to build the topology of clusters. With + // unordered_map, the resulting tree's child ordering varied + // across STL implementations and produced different BHC + // topologies on different platforms, which propagated into + // different inlier sets and homographies. std::map's + // ascending-key iteration makes BHC tree topology + // deterministic. Mirrors the BTreeMap fix on the Rust port + // (see freak/clustering.rs and issue #170). + typedef std::map > cluster_map_t; typedef PriorityQueueItem queue_item_t; typedef std::priority_queue queue_t; diff --git a/lib/SRC/KPM/FreakMatcher/matchers/hough_similarity_voting.h b/lib/SRC/KPM/FreakMatcher/matchers/hough_similarity_voting.h index 1c16198..62e4eaa 100644 --- a/lib/SRC/KPM/FreakMatcher/matchers/hough_similarity_voting.h +++ b/lib/SRC/KPM/FreakMatcher/matchers/hough_similarity_voting.h @@ -40,18 +40,26 @@ #include #include -#include +#include namespace vision { /** - * Hough voting for a similarity transformation based on a set of correspondences. + * Hough voting for a similarity transformation based on a set of correspondences. */ class HoughSimilarityVoting { public: - - typedef std::unordered_map hash_t; + + // std::map (not std::unordered_map): the vote-tally is consumed + // by getMaximumNumberOfVotes, which iterates and picks the bin + // with the highest count. unordered_map has implementation- + // defined iteration order (libstdc++ vs MSVC STL) so tied bins + // produced different winners across platforms, making the + // matcher non-deterministic across builds. std::map gives a + // stable ascending-key ordering that resolves ties consistently. + // Mirrors the BTreeMap fix on the Rust port (issue #170). + typedef std::map hash_t; typedef std::pair vote_t; typedef std::vector vote_vector_t; diff --git a/lib/SRC/KPM/FreakMatcher/matchers/visual_database.h b/lib/SRC/KPM/FreakMatcher/matchers/visual_database.h index 889f1b0..5d41ecc 100644 --- a/lib/SRC/KPM/FreakMatcher/matchers/visual_database.h +++ b/lib/SRC/KPM/FreakMatcher/matchers/visual_database.h @@ -48,7 +48,7 @@ #include #include -#include +#include #include "feature_point.h" @@ -69,7 +69,15 @@ namespace vision { typedef Keyframe<96> keyframe_t; typedef std::shared_ptr keyframe_ptr_t; - typedef std::unordered_map keyframe_map_t; + // std::map (not std::unordered_map): query() iterates this + // collection and breaks ties on inlier-count with a strict + // "first wins" comparison. unordered_map has implementation- + // defined iteration order, so the winning keyframe on + // borderline ties varied across libstdc++ vs MSVC STL builds. + // std::map's ascending-key order makes the tie-breaking + // platform-independent. Mirrors the BTreeMap fix on the Rust + // port (issue #170). + typedef std::map keyframe_map_t; typedef BinomialPyramid32f pyramid_t; typedef DoGScaleInvariantDetector detector_t;