diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index a3f0b561..dbbf347d 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -28,7 +28,7 @@ class GlRenderer : public RenderMethod { public: - Surface surface = {nullptr, 0, 0, 0}; + Surface surface = {nullptr, 0, 0, 0, ColorSpace::Unsupported, true}; RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) override; RenderData prepare(const Array& scene, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 49cf9deb..04b56ffd 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -358,7 +358,8 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id); bool rasterClear(SwSurface* surface); void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len); -void rasterUnpremultiply(SwSurface* surface); +void rasterUnpremultiply(Surface* surface); +void rasterPremultiply(Surface* surface); bool rasterConvertCS(Surface* surface, ColorSpace to); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index a4bf8c4d..610d89eb 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -1481,8 +1481,10 @@ bool rasterClear(SwSurface* surface) } -void rasterUnpremultiply(SwSurface* surface) +void rasterUnpremultiply(Surface* surface) { + TVGLOG("SW_ENGINE", "Unpremultiply [Size: %d x %d]", surface->w, surface->h); + //OPTIMIZE_ME: +SIMD for (uint32_t y = 0; y < surface->h; y++) { auto buffer = surface->buffer + surface->stride * y; @@ -1503,6 +1505,25 @@ void rasterUnpremultiply(SwSurface* surface) } } } + surface->premultiplied = false; +} + + +void rasterPremultiply(Surface* surface) +{ + TVGLOG("SW_ENGINE", "Premultiply [Size: %d x %d]", surface->w, surface->h); + + //OPTIMIZE_ME: +SIMD + auto buffer = surface->buffer; + for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) { + auto dst = buffer; + for (uint32_t x = 0; x < surface->w; ++x, ++dst) { + auto c = *dst; + auto a = (c >> 24); + *dst = (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); + } + } + surface->premultiplied = true; } diff --git a/src/lib/sw_engine/tvgSwRasterC.h b/src/lib/sw_engine/tvgSwRasterC.h index d45d68c6..fb19b1ee 100644 --- a/src/lib/sw_engine/tvgSwRasterC.h +++ b/src/lib/sw_engine/tvgSwRasterC.h @@ -65,7 +65,7 @@ static bool inline cRasterTranslucentRect(SwSurface* surface, const SwBBox& regi static bool inline cRasterABGRtoARGB(Surface* surface) { - TVGLOG("SW_ENGINE", "Convert ColorSpace ABGR - ARGB"); + TVGLOG("SW_ENGINE", "Convert ColorSpace ABGR - ARGB [Size: %d x %d]", surface->w, surface->h); auto buffer = surface->buffer; for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) { diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index a7bb0b13..74e5965e 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -278,7 +278,10 @@ struct SwImageTask : SwTask auto clipRegion = bbox; //Convert colorspace if it's not aligned. - if (surface->cs != source->cs) rasterConvertCS(source, surface->cs); + if (source->owner) { + if (source->cs != surface->cs) rasterConvertCS(source, surface->cs); + if (!source->premultiplied) rasterPremultiply(source); + } image.data = source->buffer; image.w = source->w; @@ -427,6 +430,8 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t surface->w = w; surface->h = h; surface->cs = cs; + surface->premultiplied = true; + surface->owner = true; vport.x = vport.y = 0; vport.w = surface->w; diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index a186633f..b4d28e70 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -72,7 +72,7 @@ struct Picture::Impl ~Impl() { if (paint) delete(paint); - free(surface); + delete(surface); } bool dispose(RenderMethod& renderer) @@ -275,13 +275,10 @@ struct Picture::Impl dup->loader = loader; if (surface) { - dup->surface = static_cast(malloc(sizeof(Surface))); + dup->surface = new Surface; *dup->surface = *surface; - //TODO: It needs a better design... - //Backend engines might try to align the colorspace. - //Since it shares the bitmap, duplications should not touch the data. - //Only the owner could manage it. - dup->surface->cs = ColorSpace::Unsupported; + //TODO: A dupilcation is not a proxy... it needs copy of the pixel data? + dup->surface->owner = false; } dup->w = w; dup->h = h; diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index a162d116..8f9e7ce0 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -46,11 +46,13 @@ enum ColorSpace struct Surface { - //TODO: Union for multiple types uint32_t* buffer; - uint32_t stride; - uint32_t w, h; + uint32_t stride; + uint32_t w, h; ColorSpace cs; + + bool premultiplied; //Alpha-premultiplied + bool owner; //Only owner could modify the buffer }; struct Compositor diff --git a/src/loaders/external_jpg/tvgJpgLoader.cpp b/src/loaders/external_jpg/tvgJpgLoader.cpp index f5e1073c..1c47b4f5 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.cpp +++ b/src/loaders/external_jpg/tvgJpgLoader.cpp @@ -158,12 +158,15 @@ unique_ptr JpgLoader::bitmap() { if (!image) return nullptr; - auto surface = static_cast(malloc(sizeof(Surface))); + //TODO: It's better to keep this surface instance in the loader side + auto surface = new Surface; surface->buffer = (uint32_t*)(image); surface->stride = w; surface->w = w; surface->h = h; surface->cs = cs; + surface->premultiplied = true; + surface->owner = true; return unique_ptr(surface); } diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index dacd60d7..1dc4905e 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -27,24 +27,6 @@ /* Internal Class Implementation */ /************************************************************************/ -static inline uint32_t PREMULTIPLY(uint32_t c) -{ - auto a = (c >> 24); - return (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); -} - - -static void _premultiply(uint32_t* data, uint32_t w, uint32_t h) -{ - auto buffer = data; - for (uint32_t y = 0; y < h; ++y, buffer += w) { - auto src = buffer; - for (uint32_t x = 0; x < w; ++x, ++src) { - *src = PREMULTIPLY(*src); - } - } -} - /************************************************************************/ /* External Class Implementation */ @@ -109,8 +91,6 @@ bool PngLoader::read() } content = reinterpret_cast(buffer); - _premultiply(reinterpret_cast(buffer), image->width, image->height); - return true; } @@ -124,12 +104,15 @@ unique_ptr PngLoader::bitmap() { if (!content) return nullptr; - auto surface = static_cast(malloc(sizeof(Surface))); + //TODO: It's better to keep this surface instance in the loader side + auto surface = new Surface; surface->buffer = content; surface->stride = w; surface->w = w; surface->h = h; surface->cs = cs; + surface->owner = true; + surface->premultiplied = false; return unique_ptr(surface); } diff --git a/src/loaders/jpg/tvgJpgLoader.cpp b/src/loaders/jpg/tvgJpgLoader.cpp index f0bd3cb0..15f4cc9b 100644 --- a/src/loaders/jpg/tvgJpgLoader.cpp +++ b/src/loaders/jpg/tvgJpgLoader.cpp @@ -118,12 +118,15 @@ unique_ptr JpgLoader::bitmap() if (!image) return nullptr; - auto surface = static_cast(malloc(sizeof(Surface))); + //TODO: It's better to keep this surface instance in the loader side + auto surface = new Surface; surface->buffer = reinterpret_cast(image); surface->stride = static_cast(w); surface->w = static_cast(w); surface->h = static_cast(h); surface->cs = cs; + surface->premultiplied = true; + surface->owner = true; return unique_ptr(surface); } diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index 40fb28da..b4364ec8 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -29,26 +29,6 @@ /* Internal Class Implementation */ /************************************************************************/ - -static inline uint32_t PREMULTIPLY(uint32_t c) -{ - auto a = (c >> 24); - return (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); -} - - -static void _premultiply(uint32_t* data, uint32_t w, uint32_t h) -{ - auto buffer = data; - for (uint32_t y = 0; y < h; ++y, buffer += w) { - auto src = buffer; - for (uint32_t x = 0; x < w; ++x, ++src) { - *src = PREMULTIPLY(*src); - } - } -} - - void PngLoader::clear() { lodepng_state_cleanup(&state); @@ -174,12 +154,15 @@ unique_ptr PngLoader::bitmap() { this->done(); - auto surface = static_cast(malloc(sizeof(Surface))); + //TODO: It's better to keep this surface instance in the loader side + auto surface = new Surface; surface->buffer = reinterpret_cast(image); surface->stride = static_cast(w); surface->w = static_cast(w); surface->h = static_cast(h); surface->cs = cs; + surface->premultiplied = false; + surface->owner = true; return unique_ptr(surface); } @@ -195,6 +178,4 @@ void PngLoader::run(unsigned tid) auto height = static_cast(h); lodepng_decode(&image, &width, &height, &state, data, size); - - _premultiply((uint32_t*)(image), width, height); } diff --git a/src/loaders/raw/tvgRawLoader.cpp b/src/loaders/raw/tvgRawLoader.cpp index 1130639c..d81de06c 100644 --- a/src/loaders/raw/tvgRawLoader.cpp +++ b/src/loaders/raw/tvgRawLoader.cpp @@ -80,12 +80,15 @@ unique_ptr RawLoader::bitmap() { if (!content) return nullptr; - auto surface = static_cast(malloc(sizeof(Surface))); + //TODO: It's better to keep this surface instance in the loader side + auto surface = new Surface; surface->buffer = content; surface->stride = static_cast(w); surface->w = static_cast(w); surface->h = static_cast(h); surface->cs = cs; + surface->premultiplied = true; + surface->owner = true; return unique_ptr(surface); }