From 5fe9b432ec106d76d9383c26da99420ff7d94074 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 7 Feb 2024 15:02:48 +0900 Subject: [PATCH] loaders: enhance decoding efficiency enhance decoding efficiency by determining the desired canvas format during image loading. This allows loaders to preemptively decode the image in the specified format, to not convert the format again. --- src/loaders/external_jpg/tvgJpgLoader.cpp | 17 ++++++++++++----- src/loaders/external_png/tvgPngLoader.cpp | 16 ++++++++-------- src/loaders/png/tvgPngLoader.cpp | 8 +++----- src/loaders/webp/dec/webp.cpp | 4 ++++ src/loaders/webp/tvgWebpLoader.cpp | 13 ++++++++++--- src/renderer/tvgLoadModule.h | 2 ++ src/renderer/tvgLoader.cpp | 2 ++ src/renderer/tvgSwCanvas.cpp | 4 ++++ 8 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/loaders/external_jpg/tvgJpgLoader.cpp b/src/loaders/external_jpg/tvgJpgLoader.cpp index 58338da4..5b7d240b 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.cpp +++ b/src/loaders/external_jpg/tvgJpgLoader.cpp @@ -126,13 +126,21 @@ bool JpgLoader::read() if (w == 0 || h == 0) return false; - /* OPTIMIZE: We assume the desired colorspace is ColorSpace::ARGB - How could we notice the renderer colorspace at this time? */ - auto image = (unsigned char *)tjAlloc(static_cast(w) * static_cast(h) * tjPixelSize[TJPF_BGRX]); + //determine the image format + TJPF format; + if (cs == ColorSpace::ARGB8888 || cs == ColorSpace::ARGB8888S) { + format = TJPF_BGRX; + surface.cs = ColorSpace::ARGB8888; + } else { + format = TJPF_RGBX; + surface.cs = ColorSpace::ABGR8888; + } + + auto image = (unsigned char *)tjAlloc(static_cast(w) * static_cast(h) * tjPixelSize[format]); if (!image) return false; //decompress jpg image - if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), TJPF_BGRX, 0) < 0) { + if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), format, 0) < 0) { TVGERR("JPG LOADER", "%s", tjGetErrorStr()); tjFree(image); image = nullptr; @@ -145,7 +153,6 @@ bool JpgLoader::read() surface.w = w; surface.h = h; surface.channelSize = sizeof(uint32_t); - surface.cs = ColorSpace::ARGB8888; surface.premultiplied = true; clear(); diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index a1b672c8..fcc29844 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -84,14 +84,15 @@ bool PngLoader::read() if (w == 0 || h == 0) return false; - png_bytep buffer; - image->format = PNG_FORMAT_BGRA; - buffer = static_cast(malloc(PNG_IMAGE_SIZE((*image)))); - if (!buffer) { - //out of memory, only time when libpng doesnt free its data - png_image_free(image); - return false; + if (cs == ColorSpace::ARGB8888 || cs == ColorSpace::ARGB8888S) { + image->format = PNG_FORMAT_BGRA; + surface.cs = ColorSpace::ARGB8888; + } else { + image->format = PNG_FORMAT_RGBA; + surface.cs = ColorSpace::ABGR8888; } + + auto buffer = static_cast(malloc(PNG_IMAGE_SIZE((*image)))); if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) { free(buffer); return false; @@ -103,7 +104,6 @@ bool PngLoader::read() surface.w = (uint32_t)w; surface.h = (uint32_t)h; surface.channelSize = sizeof(uint32_t); - surface.cs = ColorSpace::ARGB8888; //TODO: we can acquire a pre-multiplied image. See "png_structrp" surface.premultiplied = false; diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index 2e042771..e71f3c13 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -35,6 +35,8 @@ void PngLoader::run(unsigned tid) auto width = static_cast(w); auto height = static_cast(h); + state.info_raw.colortype = LCT_RGBA; //request this image format + if (lodepng_decode(&surface.buf8, &width, &height, &state, data, size)) { TVGERR("PNG", "Failed to decode image"); } @@ -43,6 +45,7 @@ void PngLoader::run(unsigned tid) surface.stride = width; surface.w = width; surface.h = height; + surface.cs = ColorSpace::ABGR8888; surface.channelSize = sizeof(uint32_t); if (state.info_png.color.colortype == LCT_RGBA) surface.premultiplied = false; @@ -95,9 +98,6 @@ bool PngLoader::open(const string& path) w = static_cast(width); h = static_cast(height); - if (state.info_png.color.colortype == LCT_RGBA) surface.cs = ColorSpace::ABGR8888; - else surface.cs = ColorSpace::ARGB8888; - ret = true; goto finalize; @@ -127,8 +127,6 @@ bool PngLoader::open(const char* data, uint32_t size, TVG_UNUSED const string& r h = static_cast(height); this->size = size; - surface.cs = ColorSpace::ABGR8888; - return true; } diff --git a/src/loaders/webp/dec/webp.cpp b/src/loaders/webp/dec/webp.cpp index df0d61f7..dd21736d 100644 --- a/src/loaders/webp/dec/webp.cpp +++ b/src/loaders/webp/dec/webp.cpp @@ -654,6 +654,10 @@ uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, return Decode(MODE_bgrA, data, data_size, width, height, NULL); } +uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_rgbA, data, data_size, width, height, NULL); +} int WebPGetInfo(const uint8_t* data, size_t data_size, int* width, int* height) { diff --git a/src/loaders/webp/tvgWebpLoader.cpp b/src/loaders/webp/tvgWebpLoader.cpp index 72de6e7a..cc8a690b 100644 --- a/src/loaders/webp/tvgWebpLoader.cpp +++ b/src/loaders/webp/tvgWebpLoader.cpp @@ -35,12 +35,17 @@ void WebpLoader::clear() void WebpLoader::run(unsigned tid) { - //TODO: we can figure out the requested image format in advance. - surface.buf8 = WebPDecodeBGRA(data, size, nullptr, nullptr); + if (surface.cs == ColorSpace::ARGB8888 || surface.cs == ColorSpace::ARGB8888S) { + surface.buf8 = WebPDecodeBGRA(data, size, nullptr, nullptr); + surface.cs = ColorSpace::ARGB8888; + } else { + surface.buf8 = WebPDecodeRGBA(data, size, nullptr, nullptr); + surface.cs = ColorSpace::ABGR8888; + } + surface.stride = static_cast(w); surface.w = static_cast(w); surface.h = static_cast(h); - surface.cs = ColorSpace::ARGB8888; surface.channelSize = sizeof(uint32_t); surface.premultiplied = true; @@ -128,6 +133,8 @@ bool WebpLoader::read() if (!data || w == 0 || h == 0) return false; + surface.cs = this->cs; + TaskScheduler::request(this); return true; diff --git a/src/renderer/tvgLoadModule.h b/src/renderer/tvgLoadModule.h index d50aa5f6..1f7ea63e 100644 --- a/src/renderer/tvgLoadModule.h +++ b/src/renderer/tvgLoadModule.h @@ -68,6 +68,8 @@ struct LoadModule struct ImageLoader : LoadModule { + static ColorSpace cs; //desired value + float w = 0, h = 0; //default image size Surface surface; diff --git a/src/renderer/tvgLoader.cpp b/src/renderer/tvgLoader.cpp index 99fb2987..bde4bbd3 100644 --- a/src/renderer/tvgLoader.cpp +++ b/src/renderer/tvgLoader.cpp @@ -66,6 +66,8 @@ uint64_t HASH_KEY(const char* data, uint64_t size) /* Internal Class Implementation */ /************************************************************************/ +ColorSpace ImageLoader::cs = ColorSpace::ARGB8888; + static Key key; static Inlist _activeLoaders; diff --git a/src/renderer/tvgSwCanvas.cpp b/src/renderer/tvgSwCanvas.cpp index 44040570..d154a600 100644 --- a/src/renderer/tvgSwCanvas.cpp +++ b/src/renderer/tvgSwCanvas.cpp @@ -21,6 +21,7 @@ */ #include "tvgCanvas.h" +#include "tvgLoadModule.h" #ifdef THORVG_SW_RASTER_SUPPORT #include "tvgSwRenderer.h" @@ -90,6 +91,9 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t //Paints must be updated again with this new target. Canvas::pImpl->needRefresh(); + //FIXME: The value must be associated with an individual canvas instance. + ImageLoader::cs = static_cast(cs); + return Result::Success; #endif return Result::NonSupport;