mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-19 20:08:28 +01:00
Switch code to SDL2.
Also simplify wasm html (now that it is suppported by all browsers). Change-Id: I352b08594b93d3dd7d44832d4328b3546ccc1b90
This commit is contained in:
parent
a429c0de64
commit
24d7f9cb6e
@ -638,13 +638,13 @@ if(WEBP_BUILD_EXTRAS)
|
|||||||
${CMAKE_CURRENT_BINARY_DIR})
|
${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
# vwebp_sdl
|
# vwebp_sdl
|
||||||
find_package(SDL)
|
find_package(SDL2 QUIET)
|
||||||
if(WEBP_BUILD_VWEBP AND SDL_FOUND)
|
if(WEBP_BUILD_VWEBP AND SDL2_FOUND)
|
||||||
add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
|
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(
|
target_include_directories(
|
||||||
vwebp_sdl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
|
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)
|
set(WEBP_HAVE_SDL 1)
|
||||||
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
|
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
|
||||||
endif()
|
endif()
|
||||||
@ -661,31 +661,43 @@ if(WEBP_BUILD_WEBP_JS)
|
|||||||
else()
|
else()
|
||||||
set(emscripten_stack_size "-sTOTAL_STACK=5MB")
|
set(emscripten_stack_size "-sTOTAL_STACK=5MB")
|
||||||
endif()
|
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.
|
# wasm2js does not support SIMD.
|
||||||
if(NOT WEBP_ENABLE_SIMD)
|
if(NOT WEBP_ENABLE_SIMD)
|
||||||
# JavaScript version
|
# JavaScript version
|
||||||
|
find_package(SDL2 QUIET)
|
||||||
add_executable(webp_js ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
|
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})
|
target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
set(WEBP_HAVE_SDL 1)
|
set(WEBP_HAVE_SDL 1)
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
webp_js
|
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_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)
|
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
|
||||||
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# WASM version
|
# WASM version
|
||||||
add_executable(webp_wasm ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
|
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})
|
target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
webp_wasm
|
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_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(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
|
||||||
|
|
||||||
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
|
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
|
||||||
|
@ -464,7 +464,7 @@ AC_ARG_ENABLE([sdl],
|
|||||||
@<:@default=auto@:>@]))
|
@<:@default=auto@:>@]))
|
||||||
AS_IF([test "x$enable_sdl" != "xno"], [
|
AS_IF([test "x$enable_sdl" != "xno"], [
|
||||||
CLEAR_LIBVARS([SDL])
|
CLEAR_LIBVARS([SDL])
|
||||||
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config])
|
AC_PATH_PROGS([LIBSDL_CONFIG], [sdl2-config])
|
||||||
if test -n "$LIBSDL_CONFIG"; then
|
if test -n "$LIBSDL_CONFIG"; then
|
||||||
SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
|
SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
|
||||||
SDL_LIBS="`$LIBSDL_CONFIG --libs`"
|
SDL_LIBS="`$LIBSDL_CONFIG --libs`"
|
||||||
@ -474,13 +474,12 @@ AS_IF([test "x$enable_sdl" != "xno"], [
|
|||||||
|
|
||||||
sdl_header="no"
|
sdl_header="no"
|
||||||
LIBCHECK_PROLOGUE([SDL])
|
LIBCHECK_PROLOGUE([SDL])
|
||||||
AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"],
|
AC_CHECK_HEADER([SDL2/SDL.h], [sdl_header="SDL2/SDL.h"],
|
||||||
[AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"],
|
[AC_MSG_WARN(SDL2 library not available - no SDL.h)])
|
||||||
[AC_MSG_WARN(SDL library not available - no sdl.h)])])
|
|
||||||
if test x"$sdl_header" != "xno"; then
|
if test x"$sdl_header" != "xno"; then
|
||||||
AC_LANG_PUSH(C)
|
AC_LANG_PUSH(C)
|
||||||
SDL_SAVED_LIBS="$LIBS"
|
SDL_SAVED_LIBS="$LIBS"
|
||||||
for lib in "" "-lSDL" "-lSDLmain -lSDL"; do
|
for lib in "" "-lSDL2" "-lSDL2main -lSDL2"; do
|
||||||
LIBS="$SDL_SAVED_LIBS $lib"
|
LIBS="$SDL_SAVED_LIBS $lib"
|
||||||
# Perform a full link to ensure SDL_main is resolved if needed.
|
# Perform a full link to ensure SDL_main is resolved if needed.
|
||||||
AC_LINK_IFELSE(
|
AC_LINK_IFELSE(
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#if defined(WEBP_HAVE_JUST_SDL_H)
|
#if defined(WEBP_HAVE_JUST_SDL_H)
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#else
|
#else
|
||||||
#include <SDL/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void ProcessEvents(void) {
|
static void ProcessEvents(void) {
|
||||||
|
@ -20,88 +20,75 @@
|
|||||||
#include "webp_to_sdl.h"
|
#include "webp_to_sdl.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "src/webp/decode.h"
|
#include "src/webp/decode.h"
|
||||||
|
|
||||||
#if defined(WEBP_HAVE_JUST_SDL_H)
|
#if defined(WEBP_HAVE_JUST_SDL_H)
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#else
|
#else
|
||||||
#include <SDL/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int init_ok = 0;
|
static int init_ok = 0;
|
||||||
int WebPToSDL(const char* data, unsigned int data_size) {
|
int WebPToSDL(const char* data, unsigned int data_size) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
VP8StatusCode status;
|
VP8StatusCode status;
|
||||||
WebPDecoderConfig config;
|
WebPBitstreamFeatures input;
|
||||||
WebPBitstreamFeatures* const input = &config.input;
|
uint8_t* output = NULL;
|
||||||
WebPDecBuffer* const output = &config.output;
|
SDL_Window* window = NULL;
|
||||||
SDL_Surface* screen = NULL;
|
SDL_Renderer* renderer = NULL;
|
||||||
SDL_Surface* surface = NULL;
|
SDL_Texture* texture = NULL;
|
||||||
|
int width, height;
|
||||||
if (!WebPInitDecoderConfig(&config)) {
|
|
||||||
fprintf(stderr, "Library version mismatch!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!init_ok) {
|
if (!init_ok) {
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
init_ok = 1;
|
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;
|
if (status != VP8_STATUS_OK) goto Error;
|
||||||
|
width = input.width;
|
||||||
|
height = input.height;
|
||||||
|
|
||||||
screen = SDL_SetVideoMode(input->width, input->height, 32, SDL_SWSURFACE);
|
SDL_CreateWindowAndRenderer(width, height, 0, &window, &renderer);
|
||||||
if (screen == NULL) {
|
if (window == NULL || renderer == NULL) {
|
||||||
fprintf(stderr, "Unable to set video mode (32bpp %dx%d)!\n",
|
fprintf(stderr, "Unable to create window or renderer!\n");
|
||||||
input->width, input->height);
|
|
||||||
goto Error;
|
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,
|
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
|
||||||
input->width, input->height, 32,
|
SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||||
0x000000ffu, // R mask
|
if (texture == NULL) {
|
||||||
0x0000ff00u, // G mask
|
fprintf(stderr, "Unable to create %dx%d RGBA texture!\n", width, height);
|
||||||
0x00ff0000u, // B mask
|
|
||||||
0xff000000u); // A mask
|
|
||||||
|
|
||||||
if (surface == NULL) {
|
|
||||||
fprintf(stderr, "Unable to create %dx%d RGBA surface!\n",
|
|
||||||
input->width, input->height);
|
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
|
|
||||||
|
|
||||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||||
output->colorspace = MODE_BGRA;
|
output = WebPDecodeBGRA((const uint8_t*)data, (size_t)data_size, &width,
|
||||||
|
&height);
|
||||||
#else
|
#else
|
||||||
output->colorspace = MODE_RGBA;
|
output = WebPDecodeRGBA((const uint8_t*)data, (size_t)data_size, &width,
|
||||||
|
&height);
|
||||||
#endif
|
#endif
|
||||||
output->width = surface->w;
|
if (output == NULL) {
|
||||||
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) {
|
|
||||||
fprintf(stderr, "Error decoding image (%d)\n", status);
|
fprintf(stderr, "Error decoding image (%d)\n", status);
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
|
SDL_UpdateTexture(texture, NULL, output, width * sizeof(uint32_t));
|
||||||
if (SDL_BlitSurface(surface, NULL, screen, NULL) ||
|
SDL_RenderClear(renderer);
|
||||||
SDL_Flip(screen)) {
|
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||||
goto Error;
|
SDL_RenderPresent(renderer);
|
||||||
}
|
|
||||||
|
|
||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
SDL_FreeSurface(surface);
|
// We should call SDL_DestroyWindow(window) but that makes .js fail.
|
||||||
SDL_FreeSurface(screen);
|
SDL_DestroyRenderer(renderer);
|
||||||
WebPFreeDecBuffer(output);
|
SDL_DestroyTexture(texture);
|
||||||
|
WebPFree(output);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,13 +37,13 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# SDL flags: use sdl-config if it exists
|
# 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),)
|
ifneq ($(SDL_CONFIG),)
|
||||||
SDL_LIBS = $(shell sdl-config --libs)
|
SDL_LIBS = $(shell sdl2-config --libs)
|
||||||
SDL_FLAGS = $(shell sdl-config --cflags)
|
SDL_FLAGS = $(shell sdl2-config --cflags)
|
||||||
else
|
else
|
||||||
# use best-guess
|
# use best-guess
|
||||||
SDL_LIBS = -lSDL
|
SDL_LIBS = -lSDL2
|
||||||
SDL_FLAGS =
|
SDL_FLAGS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -20,8 +20,7 @@ Emscripten and CMake.
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
cd webp_js && \
|
cd webp_js && \
|
||||||
emcmake cmake -DWEBP_BUILD_WEBP_JS=ON \
|
emcmake cmake -DWEBP_BUILD_WEBP_JS=ON ../
|
||||||
../
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- compile webp.js using 'emmake make'.
|
- 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
|
See webp_js/index_wasm.html for a simple demo page using the WASM version of the
|
||||||
library.
|
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
|
## Caveats
|
||||||
|
|
||||||
- First decoding using the library is usually slower, due to just-in-time
|
- First decoding using the library is usually slower, due to just-in-time
|
||||||
compilation.
|
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.
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
noInitialRun : true
|
noInitialRun : true
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<script src="./webp_wasm.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -16,40 +17,25 @@
|
|||||||
// main wrapper for the function decoding a WebP into a canvas object
|
// main wrapper for the function decoding a WebP into a canvas object
|
||||||
var WebpToCanvas;
|
var WebpToCanvas;
|
||||||
|
|
||||||
function init() {
|
Module.onRuntimeInitialized = async () => {
|
||||||
var xhr = new XMLHttpRequest();
|
// wrapper for the function decoding a WebP into a canvas object
|
||||||
xhr.open('GET', 'webp_wasm.wasm', true);
|
WebpToCanvas = Module.cwrap('WebPToSDL', 'number', ['array', 'number']);
|
||||||
xhr.responseType = 'arraybuffer';
|
};
|
||||||
xhr.onload = function() {
|
|
||||||
Module.wasmBinary = xhr.response;
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.src = "webp_wasm.js";
|
|
||||||
document.body.appendChild(script);
|
|
||||||
};
|
|
||||||
xhr.send(null);
|
|
||||||
}
|
|
||||||
window.onload = init;
|
|
||||||
|
|
||||||
function decode(webp_data, canvas_id) {
|
function decode(webp_data, canvas_id) {
|
||||||
var result;
|
var result;
|
||||||
if (Module["asm"] != undefined) {
|
// get the canvas to decode into
|
||||||
// wrapper for the function decoding a WebP into a canvas object
|
var canvas = document.getElementById(canvas_id);
|
||||||
WebpToCanvas = Module.cwrap('WebPToSDL', 'number', ['array', 'number']);
|
if (canvas == null) return;
|
||||||
// get the canvas to decode into
|
// clear previous picture (if any)
|
||||||
var canvas = document.getElementById(canvas_id);
|
Module.canvas = canvas;
|
||||||
if (canvas == null) return;
|
canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
|
||||||
// clear previous picture (if any)
|
// decode and measure timing
|
||||||
Module.canvas = canvas;
|
var start = new Date();
|
||||||
canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
|
var ret = WebpToCanvas(webp_data, webp_data.length);
|
||||||
// decode and measure timing
|
var end = new Date();
|
||||||
var start = new Date();
|
var decodeTime = end - start;
|
||||||
var ret = WebpToCanvas(webp_data, webp_data.length);
|
result = 'decoding time: ' + decodeTime +' ms.';
|
||||||
var end = new Date();
|
|
||||||
var decode_time = end - start;
|
|
||||||
result = 'decoding time: ' + decode_time +' ms.';
|
|
||||||
} else {
|
|
||||||
result = "WASM module not finished loading! Please retry";
|
|
||||||
}
|
|
||||||
// display timing result
|
// display timing result
|
||||||
var speed_result = document.getElementById('timing');
|
var speed_result = document.getElementById('timing');
|
||||||
if (speed_result != null) {
|
if (speed_result != null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user