From 24d7f9cb6ef1ef90a04d7b6c15d3477813f75ee0 Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Thu, 28 Sep 2023 10:18:23 +0200 Subject: [PATCH] Switch code to SDL2. Also simplify wasm html (now that it is suppported by all browsers). Change-Id: I352b08594b93d3dd7d44832d4328b3546ccc1b90 --- CMakeLists.txt | 32 +++++++++++----- configure.ac | 9 ++--- extras/vwebp_sdl.c | 2 +- extras/webp_to_sdl.c | 81 +++++++++++++++++------------------------ makefile.unix | 8 ++-- webp_js/README.md | 23 +----------- webp_js/index_wasm.html | 48 +++++++++--------------- 7 files changed, 83 insertions(+), 120 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad5e14c3..e4aaf88e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -638,13 +638,13 @@ if(WEBP_BUILD_EXTRAS) ${CMAKE_CURRENT_BINARY_DIR}) # vwebp_sdl - find_package(SDL) - if(WEBP_BUILD_VWEBP AND SDL_FOUND) + find_package(SDL2 QUIET) + if(WEBP_BUILD_VWEBP AND SDL2_FOUND) add_executable(vwebp_sdl ${VWEBP_SDL_SRCS}) - target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp) + target_link_libraries(vwebp_sdl ${SDL2_LIBRARIES} imageioutil webp) target_include_directories( vwebp_sdl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/src ${SDL_INCLUDE_DIR}) + ${CMAKE_CURRENT_BINARY_DIR}/src ${SDL2_INCLUDE_DIRS}) set(WEBP_HAVE_SDL 1) target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL) endif() @@ -661,31 +661,43 @@ if(WEBP_BUILD_WEBP_JS) else() set(emscripten_stack_size "-sTOTAL_STACK=5MB") endif() + # Set SDL2 flags so that ports are downloaded by emscripten. + set(EMSCRIPTEN_SDL2_FLAGS "-sUSE_SDL=2 -sUSE_SDL_IMAGE=2") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_SDL2_FLAGS}") # wasm2js does not support SIMD. if(NOT WEBP_ENABLE_SIMD) # JavaScript version + find_package(SDL2 QUIET) add_executable(webp_js ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c) - target_link_libraries(webp_js webpdecoder SDL) + target_link_libraries(webp_js webpdecoder SDL2) target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) set(WEBP_HAVE_SDL 1) set_target_properties( webp_js - PROPERTIES LINK_FLAGS "-sWASM=0 ${emscripten_stack_size} \ + PROPERTIES + LINK_FLAGS + "-sWASM=0 ${emscripten_stack_size} \ -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \ - -sEXPORTED_RUNTIME_METHODS=cwrap") + -sEXPORTED_RUNTIME_METHODS=cwrap ${EMSCRIPTEN_SDL2_FLAGS} \ + -sALLOW_MEMORY_GROWTH" + ) set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp) target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL) endif() # WASM version add_executable(webp_wasm ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c) - target_link_libraries(webp_wasm webpdecoder SDL) + target_link_libraries(webp_wasm webpdecoder SDL2) target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) set_target_properties( webp_wasm - PROPERTIES LINK_FLAGS "-sWASM=1 ${emscripten_stack_size} \ + PROPERTIES + LINK_FLAGS + "-sWASM=1 ${emscripten_stack_size} \ -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \ - -sEXPORTED_RUNTIME_METHODS=cwrap") + -sEXPORTED_RUNTIME_METHODS=cwrap ${EMSCRIPTEN_SDL2_FLAGS} \ + -sALLOW_MEMORY_GROWTH" + ) target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL) target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN) diff --git a/configure.ac b/configure.ac index 2216e4a8..3933a6f0 100644 --- a/configure.ac +++ b/configure.ac @@ -464,7 +464,7 @@ AC_ARG_ENABLE([sdl], @<:@default=auto@:>@])) AS_IF([test "x$enable_sdl" != "xno"], [ CLEAR_LIBVARS([SDL]) - AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config]) + AC_PATH_PROGS([LIBSDL_CONFIG], [sdl2-config]) if test -n "$LIBSDL_CONFIG"; then SDL_INCLUDES=`$LIBSDL_CONFIG --cflags` SDL_LIBS="`$LIBSDL_CONFIG --libs`" @@ -474,13 +474,12 @@ AS_IF([test "x$enable_sdl" != "xno"], [ sdl_header="no" LIBCHECK_PROLOGUE([SDL]) - AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"], - [AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"], - [AC_MSG_WARN(SDL library not available - no sdl.h)])]) + AC_CHECK_HEADER([SDL2/SDL.h], [sdl_header="SDL2/SDL.h"], + [AC_MSG_WARN(SDL2 library not available - no SDL.h)]) if test x"$sdl_header" != "xno"; then AC_LANG_PUSH(C) SDL_SAVED_LIBS="$LIBS" - for lib in "" "-lSDL" "-lSDLmain -lSDL"; do + for lib in "" "-lSDL2" "-lSDL2main -lSDL2"; do LIBS="$SDL_SAVED_LIBS $lib" # Perform a full link to ensure SDL_main is resolved if needed. AC_LINK_IFELSE( diff --git a/extras/vwebp_sdl.c b/extras/vwebp_sdl.c index e9554eb1..acf48909 100644 --- a/extras/vwebp_sdl.c +++ b/extras/vwebp_sdl.c @@ -30,7 +30,7 @@ #if defined(WEBP_HAVE_JUST_SDL_H) #include #else -#include +#include #endif static void ProcessEvents(void) { diff --git a/extras/webp_to_sdl.c b/extras/webp_to_sdl.c index 1e526811..971ffc88 100644 --- a/extras/webp_to_sdl.c +++ b/extras/webp_to_sdl.c @@ -20,88 +20,75 @@ #include "webp_to_sdl.h" #include + #include "src/webp/decode.h" #if defined(WEBP_HAVE_JUST_SDL_H) #include #else -#include +#include #endif static int init_ok = 0; int WebPToSDL(const char* data, unsigned int data_size) { int ok = 0; VP8StatusCode status; - WebPDecoderConfig config; - WebPBitstreamFeatures* const input = &config.input; - WebPDecBuffer* const output = &config.output; - SDL_Surface* screen = NULL; - SDL_Surface* surface = NULL; - - if (!WebPInitDecoderConfig(&config)) { - fprintf(stderr, "Library version mismatch!\n"); - return 0; - } + WebPBitstreamFeatures input; + uint8_t* output = NULL; + SDL_Window* window = NULL; + SDL_Renderer* renderer = NULL; + SDL_Texture* texture = NULL; + int width, height; if (!init_ok) { SDL_Init(SDL_INIT_VIDEO); init_ok = 1; } - status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &config.input); + status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &input); if (status != VP8_STATUS_OK) goto Error; + width = input.width; + height = input.height; - screen = SDL_SetVideoMode(input->width, input->height, 32, SDL_SWSURFACE); - if (screen == NULL) { - fprintf(stderr, "Unable to set video mode (32bpp %dx%d)!\n", - input->width, input->height); + SDL_CreateWindowAndRenderer(width, height, 0, &window, &renderer); + if (window == NULL || renderer == NULL) { + fprintf(stderr, "Unable to create window or renderer!\n"); goto Error; } + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, + "linear"); // make the scaled rendering look smoother. + SDL_RenderSetLogicalSize(renderer, width, height); - surface = SDL_CreateRGBSurface(SDL_SWSURFACE, - input->width, input->height, 32, - 0x000000ffu, // R mask - 0x0000ff00u, // G mask - 0x00ff0000u, // B mask - 0xff000000u); // A mask - - if (surface == NULL) { - fprintf(stderr, "Unable to create %dx%d RGBA surface!\n", - input->width, input->height); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, + SDL_TEXTUREACCESS_STREAMING, width, height); + if (texture == NULL) { + fprintf(stderr, "Unable to create %dx%d RGBA texture!\n", width, height); goto Error; } - if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface); #if SDL_BYTEORDER == SDL_BIG_ENDIAN - output->colorspace = MODE_BGRA; + output = WebPDecodeBGRA((const uint8_t*)data, (size_t)data_size, &width, + &height); #else - output->colorspace = MODE_RGBA; + output = WebPDecodeRGBA((const uint8_t*)data, (size_t)data_size, &width, + &height); #endif - output->width = surface->w; - output->height = surface->h; - output->u.RGBA.rgba = surface->pixels; - output->u.RGBA.stride = surface->pitch; - output->u.RGBA.size = surface->pitch * surface->h; - output->is_external_memory = 1; - - status = WebPDecode((const uint8_t*)data, (size_t)data_size, &config); - if (status != VP8_STATUS_OK) { + if (output == NULL) { fprintf(stderr, "Error decoding image (%d)\n", status); goto Error; } - if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface); - if (SDL_BlitSurface(surface, NULL, screen, NULL) || - SDL_Flip(screen)) { - goto Error; - } - + SDL_UpdateTexture(texture, NULL, output, width * sizeof(uint32_t)); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); ok = 1; Error: - SDL_FreeSurface(surface); - SDL_FreeSurface(screen); - WebPFreeDecBuffer(output); + // We should call SDL_DestroyWindow(window) but that makes .js fail. + SDL_DestroyRenderer(renderer); + SDL_DestroyTexture(texture); + WebPFree(output); return ok; } diff --git a/makefile.unix b/makefile.unix index 857ea988..428673a9 100644 --- a/makefile.unix +++ b/makefile.unix @@ -37,13 +37,13 @@ else endif # SDL flags: use sdl-config if it exists -SDL_CONFIG = $(shell sdl-config --version 2> /dev/null) +SDL_CONFIG = $(shell sdl2-config --version 2> /dev/null) ifneq ($(SDL_CONFIG),) - SDL_LIBS = $(shell sdl-config --libs) - SDL_FLAGS = $(shell sdl-config --cflags) + SDL_LIBS = $(shell sdl2-config --libs) + SDL_FLAGS = $(shell sdl2-config --cflags) else # use best-guess - SDL_LIBS = -lSDL + SDL_LIBS = -lSDL2 SDL_FLAGS = endif diff --git a/webp_js/README.md b/webp_js/README.md index 824afa0b..ae9ce8f0 100644 --- a/webp_js/README.md +++ b/webp_js/README.md @@ -20,8 +20,7 @@ Emscripten and CMake. ```shell cd webp_js && \ - emcmake cmake -DWEBP_BUILD_WEBP_JS=ON \ - ../ + emcmake cmake -DWEBP_BUILD_WEBP_JS=ON ../ ``` - compile webp.js using 'emmake make'. @@ -55,27 +54,7 @@ directory. See webp_js/index_wasm.html for a simple demo page using the WASM version of the library. -You will need a fairly recent version of Emscripten (at least 2.0.18, -latest-upstream is recommended) and of your WASM-enabled browser to run this -version. - ## Caveats - First decoding using the library is usually slower, due to just-in-time compilation. - -- Some versions of llvm produce the following compile error when SSE2 is - enabled. - - ``` - "Unsupported: %516 = bitcast <8 x i16> %481 to i128 - LLVM ERROR: BitCast Instruction not yet supported for integer types larger than 64 bits" - ``` - - The corresponding Emscripten bug is at: - https://github.com/kripken/emscripten/issues/3788 - - Therefore, SSE2 optimization is currently disabled in CMakeLists.txt. - -- If WEBP_ENABLE_SIMD is set to 1 the JavaScript version (webp.js) will be - disabled as wasm2js does not support SIMD. diff --git a/webp_js/index_wasm.html b/webp_js/index_wasm.html index 5d7c17e8..7a9b362a 100644 --- a/webp_js/index_wasm.html +++ b/webp_js/index_wasm.html @@ -9,6 +9,7 @@ noInitialRun : true }; +